Skip to content

Commit 2031241

Browse files
committed
Fixes from call including streamlining cancellation
1 parent b059bf0 commit 2031241

File tree

4 files changed

+202
-112
lines changed

4 files changed

+202
-112
lines changed

EditorsDraft/customercancelled.png

609 Bytes
Loading

EditorsDraft/edit.html

+56-34
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@
589589

590590
- The <a>Broker</a> MUST update the `Order` in with an internal status of `https://schema.org/OrderDelivered` after invoices have been created and notifications successfully sent.
591591

592-
x) **Refunds an Cancellation** - The <a>Broker</a> subscribes to updates from the <a>Booking System</a> to process cancellations and refunds.
592+
x) **Refunds and Cancellation** - The <a>Broker</a> subscribes to updates from the <a>Booking System</a> to process cancellations and refunds.
593593
- A secure <a>Orders feed</a> of `Order`s MUST be provided by the <a>Booking System</a>, with the contents of the feed specific to the authentication credentials. This allows the <a>Broker</a> to maintain an updated state of all their bookings across a number of <a>Booking Systems</a>, even when changes are made outside of the <a>Broker</a>. This also allows the <a>Broker</a> to handle refunds to cancellations, and process notifications to <a>Customers</a> in a consistent way.
594594
- The <a>Booking System</a> must ensure that the `Order`s in the <a>Orders feed</a> represent the current state of `OrderItem`s within the system, for the properties included in the feed.
595595
- The <a>Broker</a> uses these `Order`s to process refunds and send update notifications to the <a>Customer</a>.
@@ -860,7 +860,7 @@
860860

861861
- The <a>Broker</a> has machine readable permission to access the relevant instance of a compliant Open Booking API provided by the <a>Booking System</a> via an API key or similar token.
862862

863-
The <a>Broker</a> MUST NOT attempt to book an opportunity that is not <a>bookable</a> by the above criteria. The <a>Booking System</a> MUST return an error if an `Order` is submitted that contains activities that are not <a>bookable</a>, and include an `error` against each `OrderItem` in the `OrderQuote` that is not <a>bookable</a>.
863+
The <a>Broker</a> MUST NOT attempt to book an opportunity that is not <a>bookable</a> by the above criteria. The <a>Booking System</a> MUST include an `error` of value `UnavailableOpportunityError` against each `OrderItem` in the `OrderQuote` that is not <a>bookable</a>.
864864

865865
Note that although the <a>Customer</a> may be ineligible to attend a <a>bookable</a> opportunity based on the `genderRestriction` or `ageRange`, this specification encourages the <a>Broker</a> NOT to capture gender and age data from the <a>Customer</a> and NOT to enforce validation of these restrictions, but instead to prominently display any restrictions in the booking process to ensure that the <a>Customer</a> is aware of these.
866866

@@ -880,6 +880,10 @@
880880
5. The <a>Broker</a> MAY additionally filter based on the `Offer`s that apply to the customer, for example based on `ageRange` if specified in the `Offer`. This specification provides no guidance as to how the filtering should be performed, however it recommends against gathering additional personal data about the <a>Customer</a> in order to restrict `Offer`s presented, and instead advocates clear messaging regarding the restrictions of each `Offer` to allow the <a>Customer</a> to make an informed decision.
881881

882882

883+
884+
<div class="issue" data-number="103"></div>
885+
886+
883887
## Amending the OrderQuote before **B**
884888

885889
The <a>Broker</a> MAY call **C1** and MUST call **C2** when the <a>Customer</a> updates their basket to add and remove items.
@@ -905,22 +909,25 @@
905909

906910
To cancel an existing OrderItem, the <a>Broker</a> MUST:
907911

908-
1. Use the latest state of the `Order` from the <a>Orders feed</a> to determine which `OrderItem`s may be cancelled. If `allowSimpleCancellation` is `true` and `latestCancellationBeforeStartDate` subtracted from the opportunity `startDate` is in the future, a PATCH against the `OrderItem` `id` with a body of `{ "orderItemStatus": "https://openactive.io/CustomerCancelled" }` MUST succeed.
912+
1. Use the latest state of the `Order` stored during the booking flow and updated via the <a>Orders feed</a> to determine which `OrderItem`s may be cancelled. If `allowSimpleCancellation` is `true` and `latestCancellationBeforeStartDate` subtracted from the opportunity `startDate` is in the future, a PATCH against the `Order` including the `OrderItem` with `"orderItemStatus": "https://openactive.io/CustomerCancelled"` MUST succeed.
909913

910914
2. Inform the <a>Customer</a> of the expected refund before they commit to cancellation, where the value of the refund for each `OrderItem` MUST be equal to:
911-
- For `taxMode` of `https://openactive/TaxNet`: the sum of the `price` in the `acceptedOffer` and all the prices in `unitTaxSpecification`.
912-
- For `taxMode` of `https://openactive/TaxGross`: the `price` in the `acceptedOffer`.
915+
(i) for `taxMode` of `https://openactive/TaxNet`, the sum of the `price` in the `acceptedOffer` and all the prices in `unitTaxSpecification`;
916+
(ii) for `taxMode` of `https://openactive/TaxGross`, the `price` in the `acceptedOffer`.
913917

914-
3. Submit a PATCH for each `OrderItem` to be cancelled using the URL `id` of the `OrderItem` from the feed with a body of `{ "orderItemStatus": "https://openactive.io/CustomerCancelled" }`. On success, a 204 response will be received, without any body. On failure a 5xx response will be received with an error message.
918+
3. Submit a PATCH for the `Order` including only the `id` for each of the `OrderItem`s to be cancelled, with an `"orderItemStatus": "https://openactive.io/CustomerCancelled"` set on each. On success, a 204 response will be received, without any body. On failure a 5xx response will be received with an error message.
915919

916920
4. Process any refunds based on the resulting updates to the <a>Orders feed</a>. Successfully cancelled `OrderItems` will have `orderItemStatus` set to `https://openactive.io/CustomerCancelled`. Note refunds MUST NOT be processed except in response to updates in the <a>Orders feed</a>.
917921

918-
To cancel an entire `Order`, a PATCH request must be made to each `OrderItem` within it individually. To minimise the number of updates in the <a>Orders feed</a>, it is recommended that multiple DELETEs are sent in quick succession.
922+
To cancel an entire `Order`, a single PATCH request MUST be made including `"orderItemStatus": "https://openactive.io/CustomerCancelled"` for each `OrderItem` within it.
919923

920-
Note that there is no provision for a <a>Customer</a> to cancel an `Order` after the cancellation window specified by `latestCancellationBeforeStartDate`, yet they may wish to do this out of politeness even though no refund is possible, with the benefit that their place may be taken by another participant.
924+
Note that there is no provision for a <a>Customer</a> to cancel an `Order` after the cancellation window specified by `latestCancellationBeforeStartDate. They may wish to do this out of politeness even though no refund is possible, with the benefit that their place may be taken by another participant, which can be included in future versions of this specification.
921925

922926
<div class="issue" data-number="92"></div>
923927

928+
<div class="issue" data-number="102"></div>
929+
930+
924931
### Seller requested cancellation
925932

926933
<figure>
@@ -1097,13 +1104,13 @@
10971104

10981105
A summary of endpoints defined by this specification is provided below:
10991106

1100-
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1101-
|------------------------|-------------|------------------|-----------|--------------------------------------------------|
1102-
| Order Creation | REQUIRED | Order | PUT | `/orders/{uuid}` |
1103-
| Order Deletion | REQUIRED | Order | DELETE | `/orders/{uuid}` |
1104-
| Orders RPDE Feed | REQUIRED | Orders feed | GET | `/orders-rpde` |
1105-
| OrderItem Cancellation | REQUIRED | OrderItem | PATCH | `/orders/{uuid}/order-items/{order-item-id}` |
1106-
| Order Status | OPTIONAL | Order | GET | `/orders/{uuid}` |
1107+
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1108+
|-------------------------|-------------|------------------|-----------|-------------------|
1109+
| Order Creation | REQUIRED | Order | PUT | `/orders/{uuid}` |
1110+
| Order Deletion | REQUIRED | Order | DELETE | `/orders/{uuid}` |
1111+
| OrderItem Cancellation | REQUIRED | Order | PATCH | `/orders/{uuid}` |
1112+
| Orders RPDE Feed | REQUIRED | Orders feed | GET | `/orders-rpde` |
1113+
| Order Status | OPTIONAL | Order | GET | `/orders/{uuid}` |
11071114

11081115

11091116
<div class="issue" data-number="98"></div>
@@ -1194,9 +1201,9 @@
11941201

11951202
### Order Deletion
11961203

1197-
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1198-
|------------------------|-------------|------------------|-----------|--------------------------------------------------|
1199-
| Order Deletion | REQUIRED | Order | DELETE | `/orders/{uuid}` |
1204+
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1205+
|------------------------|-------------|------------------|-----------|----------------------|
1206+
| Order Deletion | REQUIRED | Order | DELETE | `/orders/{uuid}` |
12001207

12011208
Deleting an `Order` allows for the whole Booking Flow to be reversed for fatal error and testing scenarios.
12021209

@@ -1214,38 +1221,49 @@
12141221
</pre>
12151222

12161223

1217-
### Orders RPDE Feed
1224+
### OrderItem Cancellation
12181225

1219-
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1220-
|------------------------|-------------|------------------|-----------|--------------------------------------------------|
1221-
| Orders RPDE Feed | REQUIRED | Orders feed | GET | `/orders-rpde` |
1226+
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1227+
|------------------------|-------------|------------------|-----------|----------------------|
1228+
| OrderItem Cancellation | REQUIRED | Order | PATCH | `/orders/{uuid}` |
12221229

1223-
<pre class="example" title="Order RPDE Feed: example request" data-transform="dataExampleOrderFeedRequest">
1230+
All other properties except the `id` and `orderItemStatus` inside the `OrderItem` MUST be ignored. `OrderItem`s omitted from the PATCH request MUST also be ignored.
1231+
1232+
<pre class="example" title="OrderItem Cancellation: example request" data-transform="dataExampleOrderItemCancellationRequest">
12241233
</pre>
12251234

1226-
<pre class="example" title="Order RPDE Feed: example response" data-transform="dataExampleOrderFeedResponse">
1235+
The cancellation request succeeds and fails atomically.
1236+
1237+
<pre class="example" title="OrderItem Cancellation: example success response" data-transform="dataExampleOrderItemCancellationSuccessResponse">
12271238
</pre>
12281239

1240+
<!--
1241+
<pre class="example" title="OrderItem Cancellation: example error response" data-transform="dataExampleOrderItemCancellationErrorResponse">
1242+
</pre>
1243+
-->
12291244

1230-
### OrderItem Cancellation
12311245

1232-
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1233-
|------------------------|-------------|------------------|-----------|--------------------------------------------------|
1234-
| OrderItem Cancellation | REQUIRED | OrderItem | PATCH | `/orders/{uuid}/order-items/{order-item-id}` |
12351246

1236-
<pre class="example" title="OrderItem Cancellation: example request" data-transform="dataExampleOrderItemCancellationRequest">
1247+
### Orders RPDE Feed
1248+
1249+
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1250+
|------------------------|-------------|------------------|-----------|----------------------|
1251+
| Orders RPDE Feed | REQUIRED | Orders feed | GET | `/orders-rpde` |
1252+
1253+
<pre class="example" title="Order RPDE Feed: example request" data-transform="dataExampleOrderFeedRequest">
12371254
</pre>
12381255

1239-
<pre class="example" title="OrderItem Cancellation: example response" data-transform="dataExampleOrderItemCancellationResponse">
1256+
<pre class="example" title="Order RPDE Feed: example response" data-transform="dataExampleOrderFeedResponse">
12401257
</pre>
12411258

1259+
12421260
### Order Status
12431261

12441262
A <a>Booking System</a> MAY provide an endpoint to allow a <a>Broker</a> to retrieve complete `Order`s. In future versions of the specification, endpoints may be provided which permit a <a>Broker</a> to see all `Order`s created by a <a>Customer</a>. In this current implementation, the <a>Broker</a> MUST keep its own record of `Order`s as described elsewhere in this specification, and not rely on this OPTIONAL Order Status endpoint.
12451263

1246-
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1247-
|------------------------|-------------|------------------|-----------|--------------------------------------------------|
1248-
| Order Status | OPTIONAL | Order | GET | `/orders/{uuid}` |
1264+
| Endpoint Name | Status | Resource | HTTP Verb | Example Path |
1265+
|------------------------|-------------|------------------|-----------|-----------------------|
1266+
| Order Status | OPTIONAL | Order | GET | `/orders/{uuid}` |
12491267

12501268
<pre class="example" title="Order Status: example request" data-transform="dataExampleOrderStatusRequest">
12511269
</pre>
@@ -1608,6 +1626,10 @@
16081626
| `OrderAlreadyExistsError` | 400 | If the UUID used for an `OrderQuote` already represents a completed Order. |
16091627

16101628

1629+
<!--| `CancellationNotPermittedError` | 400 | If the cancellation is not permitted due to internal rules of the booking system not otherwise exposed to the `Broker`. The `description` property of the object SHOULD include a <a>Customer</a>-facing description of the reason that cancellation is not permitted. |-->
1630+
1631+
1632+
16111633
#### Order Creation - `OrderItem` errors
16121634

16131635
Note that all `OrderItem` errors for an `OrderQuote` request result in a `409 Conflict` response, as the error is expected to be resolved, and the request resubmitted, as per [[RFC2616]] section 10.4.10.
@@ -1618,7 +1640,7 @@
16181640
| `UnacceptableOfferError` | 409 | If the `acceptedOffer` is not a URL which corresponds to an <a>Applicable `Offer`</a> for the opportunity. |
16191641
| `UnknownOfferError` | 409 | If the `acceptedOffer` is not a URL which corresponds to an `Offer` within the <a>Booking System</a>. |
16201642
| `UnknownOpportunityDetailsError` | 409 | If the `orderedItem` is not a URL which corresponds to an opportunity on the <a>Booking System</a>. |
1621-
| `UnavailableOpportunityError` | 409 | If the `Offer` contained in the `acceptedOffer` property is not bookable |
1643+
| `UnavailableOpportunityError` | 409 | If the `Offer` contained in the `acceptedOffer` property is not <a>bookable</a>. |
16221644
| `OpportunityIsFullError` | 409 | If there are no available spaces for the opportunity contained in the `orderedItem` property |
16231645
| `OpportunityHasInsufficientCapacityError` | 409 | If there are not enough available spaces in the opportunity contained in the `orderedItem` property to fulfil the number requested by the `orderQuantity` property. |
16241646

EditorsDraft/examples.js

+45-5
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,36 @@ function dataExampleRateLimitResponse(utils, content) {
7070
});
7171
}
7272

73+
// Create issue around race conditions:
74+
//There is a race condition between the Orders feed and completion of ** B **
75+
// for new Orders.
76+
77+
//If the completion of ** B ** from the Order creation call takes longer than the time
78+
//for the Orders feed update to be processed an unrecognised Order would be present in the feed.
79+
80+
//This same situation would occur as a result of a fatal error during payment authorization.
81+
82+
// Remove last 4 from diagram!
83+
84+
// Add to spec intro: "The commercial relationship will govern what is possible, the spec does not recommend or include ACLs that specifically disable functionality."
85+
86+
// Make OfferOverride clearer
87+
88+
// Specific error code for "not bookable"
89+
90+
// Offer override to disable/exclude an offer.
91+
92+
// Line at top of Customer cancellation diagram isn't RPDE, as it's now coming from the store based on Order response and not RPDE - it should just be "store"
93+
94+
// Create a GitHub issue for 49:00 which includes pros and cons of latestCancellationBeforeStartDate vs better errors on cancellation noting "allowSimpleCancellation"
95+
96+
97+
// Make issue about minimal personal data capture
7398

7499
// Switch to including only new orders in the feed, not existing Orders - include issue on this.
75100

101+
// Raise issue around minimal contact details captured (is this an issue already?)
102+
76103

77104
//TODO: Include rate limiting scheme!! [DONE]
78105

@@ -222,15 +249,25 @@ function dataExampleOrderFeedResponse(utils, content) {
222249
}
223250

224251
function dataExampleOrderItemCancellationRequest(utils, content) {
225-
return generateRequest("PATCH", API_PATH + "/orders/" + UUID + "/order-items/1234", OPERATIONS_MEDIA_TYPE, {
226-
"orderItemStatus": "https://openactive.io/CustomerCancelled"
252+
return generateRequest("PATCH", API_PATH + "/orders/" + UUID, OPERATIONS_MEDIA_TYPE, {
253+
"@context": CONTEXT,
254+
"type": "Order",
255+
"orderedItem": [responseCancelledOrderItem]
227256
});
228257
}
229258

230-
function dataExampleOrderItemCancellationResponse(utils, content) {
259+
function dataExampleOrderItemCancellationSuccessResponse(utils, content) {
231260
return generateResponse("204 No Content", null, OPERATIONS_MEDIA_TYPE);
232261
}
233262

263+
function dataExampleOrderItemCancellationErrorResponse(utils, content) {
264+
return generateResponse("400 Bad Request", null, OPERATIONS_MEDIA_TYPE, {
265+
"@context": CONTEXT,
266+
"type": "CancellationNotPermittedError",
267+
"description": "The horse has already been fed, and cannot be put back in the box."
268+
});
269+
}
270+
234271
function dataExampleOrderStatusRequest(utils, content) {
235272
return generateRequest("GET", API_PATH + "/orders/" + UUID, OPERATIONS_MEDIA_TYPE);
236273
}
@@ -660,8 +697,11 @@ var responseOrderItem = {
660697
"accessToken": fullOrderItemExampleContent.accessToken
661698
}
662699

663-
664-
700+
var responseCancelledOrderItem = {
701+
"type": "OrderItem",
702+
"id": fullOrderItemExampleContent.id,
703+
"orderItemStatus": fullOrderItemExampleContent.orderItemStatus.CustomerCancelled
704+
}
665705

666706
/***** Helper Functions *****/
667707

0 commit comments

Comments
 (0)