# Order Management

Order completion, cancellation, and modification endpoints

## Get Completed Order Details (Authenticated)

> Retrieves the details of a completed order for the authenticated user.\
> \
> \*\*Business Logic:\*\*\
> \- Requires authentication. The order must belong to the logged-in user.\
> \- Validates the signed order number.\
> \- The signature is time-limited for security.\
> \
> \*\*Response Format:\*\*\
> \- Default: HTML page rendering order confirmation.\
> \- JSON: Add \`?format=json\` query parameter.

```json
{"openapi":"3.1.0","info":{"title":"Orders API","version":"1.0.0"},"tags":[{"name":"Order Management","description":"Order completion, cancellation, and modification endpoints"}],"servers":[{"description":"Server base URL","url":"https://{commerce_url}","variables":{"commerce_url":{"default":"sandbox.akinon.com","description":"Commerce server URL"}}}],"security":[{"cookieAuth":[]}],"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"sessionid"}},"parameters":{"CookieHeader":{"name":"Cookie","in":"header","description":"Session ID and CSRF token cookies.\nFormat: `sessionid=<id>; osessionid=<id>; csrftoken=<token>`","required":true,"schema":{"type":"string"}}},"schemas":{"CompletedOrderResponse":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/OrderDetail"},"campaigns":{"type":"array","items":{"type":"object"},"description":"Applied campaigns on the order."}}},"OrderDetail":{"type":"object","properties":{"pk":{"type":"integer"},"number":{"type":"string","description":"Order number."},"status":{"$ref":"#/components/schemas/EnumValue"},"currency":{"$ref":"#/components/schemas/EnumValue"},"amount":{"type":"string","format":"decimal"},"discount_amount":{"type":"string","format":"decimal"},"shipping_amount":{"type":"string","format":"decimal"},"shipping_tax_rate":{"type":"string","format":"decimal"},"created_date":{"type":"string","format":"date-time"},"orderitem_set":{"type":"array","items":{"$ref":"#/components/schemas/OrderItemSummary"}},"shipping_address":{"$ref":"#/components/schemas/AddressSummary"},"billing_address":{"$ref":"#/components/schemas/AddressSummary"}}},"EnumValue":{"type":"object","properties":{"value":{"type":"string","description":"The internal value of the enum choice."},"label":{"type":"string","description":"The human-readable label of the enum choice."}}},"OrderItemSummary":{"type":"object","properties":{"pk":{"type":"integer"},"product":{"$ref":"#/components/schemas/ProductSummary"},"status":{"$ref":"#/components/schemas/EnumValue"},"price":{"type":"string","format":"decimal"},"quantity":{"type":"integer","default":1},"discount_amount":{"type":"string","format":"decimal"},"tracking_number":{"type":["string","null"]},"shipping_company":{"$ref":"#/components/schemas/EnumValue"}}},"ProductSummary":{"type":"object","properties":{"pk":{"type":"integer"},"sku":{"type":"string"},"name":{"type":"string"},"image":{"type":["string","null"],"format":"uri"}}},"AddressSummary":{"type":"object","properties":{"pk":{"type":"integer"},"title":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"line":{"type":"string"},"city":{"type":"object","properties":{"pk":{"type":"integer"},"name":{"type":"string"}}},"country":{"type":"object","properties":{"pk":{"type":"integer"},"name":{"type":"string"}}}}},"ValidationErrorResponse":{"type":"object","description":"Standard DRF validation error response","additionalProperties":{"type":"array","items":{"type":"string"}}}}},"paths":{"/orders/completed/{order_number}/":{"get":{"tags":["Order Management"],"summary":"Get Completed Order Details (Authenticated)","description":"Retrieves the details of a completed order for the authenticated user.\n\n**Business Logic:**\n- Requires authentication. The order must belong to the logged-in user.\n- Validates the signed order number.\n- The signature is time-limited for security.\n\n**Response Format:**\n- Default: HTML page rendering order confirmation.\n- JSON: Add `?format=json` query parameter.","operationId":"getCompletedOrder","parameters":[{"$ref":"#/components/parameters/CookieHeader"},{"name":"order_number","in":"path","required":true,"schema":{"type":"string"},"description":"Signed order number (time-limited signature for security)."},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json"]},"description":"Response format. Use `json` for JSON response."}],"responses":{"200":{"description":"Order details","content":{"text/html":{"schema":{"type":"string","description":"HTML page with order confirmation."}},"application/json":{"schema":{"$ref":"#/components/schemas/CompletedOrderResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"404":{"description":"Order not found, signature expired, or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}}}}}}}
```

## Cancel Order Items Directly

> Directly cancels selected order items and sends the cancellation to the order management system (Omnitron).\
> \
> \*\*How It Works:\*\*\
> \
> This endpoint attempts \*\*direct cancellation\*\* without creating CancellationRequest records. \
> The selected order items are immediately cancelled and reported to Omnitron.\
> \
> 1\. Validates that the order belongs to the authenticated user.\
> 2\. Checks all cancellation rules (status, time limits, invoice status, etc.).\
> 3\. Retrieves the order details from Omnitron.\
> 4\. Sends the cancellation request directly to Omnitron API.\
> 5\. Updates the order item statuses to \`cancellation\_waiting\`.\
> \
> \*\*Fallback Behavior:\*\*\
> \
> If direct cancellation fails for any reason (validation error, Omnitron API error, etc.), \
> the system automatically creates \*\*CancellationRequest\*\* records instead. \
> In this case, the response will be \`200 OK\` with the created CancellationRequest list.\
> \
> \*\*Cancellation Validation Rules:\*\*\
> \
> The following conditions are checked before allowing cancellation:\
> \
> \| Validation | Error |\
> \|------------|-------|\
> \| Order is already cancelled | "Order already cancelled!" |\
> \| Cancellation already in progress | "Order cancellation already in progress." |\
> \| Order status doesn't allow cancellation | "Order can't be cancelled in this status." |\
> \| Order has invoice (if configured) | "Invoiced orders can not cancel" |\
> \| Time limit exceeded (if configured) | "Order cancellation expired." |\
> \| Item status doesn't allow cancellation | "Order Item ({name}) can't be cancelled in this status." |\
> \
> \*\*Cancellable Order Statuses (Default):\*\*\
> \- \`payment\_waiting\`\
> \- \`confirmation\_waiting\`\
> \- \`approved\`\
> \
> Additional statuses can be configured via \`EXTRA\_CANCEL\_RULES\` setting.\
> \
> \*\*Configuration (Dynamic Settings):\*\*\
> \
> \| Setting | Description |\
> \|---------|-------------|\
> \| \`EXTRA\_CANCEL\_RULES.extra\_direct\_cancellable\_statuses\` | Additional order statuses that allow direct cancellation |\
> \| \`EXTRA\_CANCEL\_RULES.has\_invoice\` | If \`true\`, orders with invoice cannot be cancelled |\
> \| \`EXTRA\_CANCEL\_RULES.hour\_gap.is\_active\` | If \`true\`, enables time-based cancellation limit |\
> \| \`EXTRA\_CANCEL\_RULES.hour\_gap.time\` | Time limit in minutes after order creation (default: 60) |\
> \
> \*\*Response:\*\*\
> \- \`204\`: Direct cancellation successful - order items cancelled and sent to Omnitron.\
> \- \`200\`: Direct cancellation failed - CancellationRequest records created as fallback.\
> \- \`400\`: Validation error - cancellation not allowed.

```json
{"openapi":"3.1.0","info":{"title":"Orders API","version":"1.0.0"},"tags":[{"name":"Order Management","description":"Order completion, cancellation, and modification endpoints"}],"servers":[{"description":"Server base URL","url":"https://{commerce_url}","variables":{"commerce_url":{"default":"sandbox.akinon.com","description":"Commerce server URL"}}}],"security":[{"cookieAuth":[]}],"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"sessionid"}},"parameters":{"CSRFTokenHeader":{"name":"X-CSRFToken","in":"header","description":"CSRF token for write operations (POST, PUT, PATCH, DELETE).\nRequired for security when using session authentication.\nObtain token from cookie 'csrftoken' or meta tag in HTML.","required":true,"schema":{"type":"string"}},"CookieHeader":{"name":"Cookie","in":"header","description":"Session ID and CSRF token cookies.\nFormat: `sessionid=<id>; osessionid=<id>; csrftoken=<token>`","required":true,"schema":{"type":"string"}}},"schemas":{"OrderCancellationRequest":{"type":"object","description":"Request payload for cancelling order items.\nContains a list of items to cancel with their individual cancellation details.","required":["cancel_order_items"],"properties":{"cancel_order_items":{"type":"array","description":"List of order items to cancel with their cancellation details.","items":{"$ref":"#/components/schemas/OrderItemCancellationInput"}},"pickup_address":{"type":["integer","null"],"description":"Address ID for product pickup (for easy return / refund requests).\nMust be a valid address belonging to the authenticated user.\nOnly required for refund-type cancellations with easy return enabled."},"fully_refund_as_loyalty_money":{"type":"boolean","default":false,"description":"If `true`, the refund amount will be credited as loyalty points\ninstead of being refunded to the original payment method."}}},"OrderItemCancellationInput":{"type":"object","description":"Individual order item cancellation details.","required":["order_item","cancellation_type","reason"],"properties":{"order_item":{"type":"integer","description":"The ID of the order item to cancel."},"cancellation_type":{"type":"string","enum":["cancel","refund"],"description":"Type of cancellation request:\n- `cancel`: Cancel before shipment (no product return needed)\n- `refund`: Return product after delivery (requires easy return process)"},"reason":{"type":"integer","description":"Cancellation reason ID.\nObtain available reasons from the cancellation reasons endpoint."},"description":{"type":["string","null"],"description":"Additional description or notes for the cancellation."},"shipping_company":{"type":["integer","null"],"description":"Easy return shipping company ID.\nRequired only for `refund` type cancellations.\nObtain available companies from the easy return shipping companies endpoint."},"pickup_date":{"oneOf":[{"$ref":"#/components/schemas/PickupDateInput"},{"type":"null"}],"description":"Scheduled pickup date and time range for easy return.\nRequired only for `refund` type cancellations when pickup is needed."},"quantity":{"type":["integer","null"],"minimum":1,"description":"Quantity to cancel (for mergeable/quantity-based order items).\nIf not provided, the entire order item quantity is cancelled.\nCannot exceed the original order item quantity."},"cancellation_request_image_set":{"type":"array","description":"Images related to the cancellation request (e.g., product damage photos).\nLimited by `CANCELLATION_REQUEST_MAX_IMAGE_COUNT_PER_ORDER_ITEM` setting.","items":{"$ref":"#/components/schemas/CancellationRequestImageInput"}}}},"PickupDateInput":{"type":"object","description":"Scheduled pickup date and time range for easy return.","required":["date","hour_range"],"properties":{"date":{"type":"string","format":"date","description":"Pickup date (YYYY-MM-DD format)."},"hour_range":{"type":"object","required":["start","end"],"properties":{"start":{"type":"string","description":"Start time of pickup window."},"end":{"type":"string","description":"End time of pickup window."}}}}},"CancellationRequestImageInput":{"type":"object","description":"Image attachment for cancellation request.","required":["image"],"properties":{"image":{"type":"string","format":"byte","description":"Base64 encoded image data."}}},"CancellationRequestResponse":{"type":"object","properties":{"pk":{"type":"integer","description":"Cancellation request ID."},"uuid":{"type":"string","format":"uuid","description":"Unique identifier for the cancellation request."},"order_item":{"type":"integer","description":"Order item ID that is being cancelled."},"status":{"type":"object","description":"Cancellation request status.\n\n**Possible values:**\n- `open`: Request is open and waiting to be processed\n- `waiting`: Waiting for processing\n- `confirmation_waiting`: Waiting for confirmation\n- `confirmed`: Confirmed by the system\n- `waiting_approval`: Waiting for back-office approval\n- `approved`: Approved by the back-office\n- `rejected`: Rejected by the back-office\n- `waiting_for_payment`: Waiting for refund payment\n- `manuel_refund_need`: Requires manual refund processing\n- `completed`: Cancellation completed","properties":{"value":{"type":"string","enum":["open","waiting","confirmation_waiting","confirmed","waiting_approval","approved","rejected","waiting_for_payment","manuel_refund_need","completed"]},"label":{"type":"string","description":"Human-readable status label."}}},"cancellation_type":{"type":"object","description":"Type of cancellation request.\n\n**Possible values:**\n- `cancel`: Order item cancellation (before shipment)\n- `refund`: Refund request (after delivery)","properties":{"value":{"type":"string","enum":["cancel","refund"]},"label":{"type":"string","description":"Human-readable type label."}}},"reason":{"type":"integer","description":"Cancellation reason ID (from CancellationReason model)."},"description":{"type":"string","description":"Additional notes or explanation provided by the customer."},"created_date":{"type":"string","format":"date-time","description":"Date and time when the cancellation request was created."}}},"ValidationErrorResponse":{"type":"object","description":"Standard DRF validation error response","additionalProperties":{"type":"array","items":{"type":"string"}}}}},"paths":{"/orders/{order_number}/cancel/":{"post":{"tags":["Order Management"],"summary":"Cancel Order Items Directly","description":"Directly cancels selected order items and sends the cancellation to the order management system (Omnitron).\n\n**How It Works:**\n\nThis endpoint attempts **direct cancellation** without creating CancellationRequest records. \nThe selected order items are immediately cancelled and reported to Omnitron.\n\n1. Validates that the order belongs to the authenticated user.\n2. Checks all cancellation rules (status, time limits, invoice status, etc.).\n3. Retrieves the order details from Omnitron.\n4. Sends the cancellation request directly to Omnitron API.\n5. Updates the order item statuses to `cancellation_waiting`.\n\n**Fallback Behavior:**\n\nIf direct cancellation fails for any reason (validation error, Omnitron API error, etc.), \nthe system automatically creates **CancellationRequest** records instead. \nIn this case, the response will be `200 OK` with the created CancellationRequest list.\n\n**Cancellation Validation Rules:**\n\nThe following conditions are checked before allowing cancellation:\n\n| Validation | Error |\n|------------|-------|\n| Order is already cancelled | \"Order already cancelled!\" |\n| Cancellation already in progress | \"Order cancellation already in progress.\" |\n| Order status doesn't allow cancellation | \"Order can't be cancelled in this status.\" |\n| Order has invoice (if configured) | \"Invoiced orders can not cancel\" |\n| Time limit exceeded (if configured) | \"Order cancellation expired.\" |\n| Item status doesn't allow cancellation | \"Order Item ({name}) can't be cancelled in this status.\" |\n\n**Cancellable Order Statuses (Default):**\n- `payment_waiting`\n- `confirmation_waiting`\n- `approved`\n\nAdditional statuses can be configured via `EXTRA_CANCEL_RULES` setting.\n\n**Configuration (Dynamic Settings):**\n\n| Setting | Description |\n|---------|-------------|\n| `EXTRA_CANCEL_RULES.extra_direct_cancellable_statuses` | Additional order statuses that allow direct cancellation |\n| `EXTRA_CANCEL_RULES.has_invoice` | If `true`, orders with invoice cannot be cancelled |\n| `EXTRA_CANCEL_RULES.hour_gap.is_active` | If `true`, enables time-based cancellation limit |\n| `EXTRA_CANCEL_RULES.hour_gap.time` | Time limit in minutes after order creation (default: 60) |\n\n**Response:**\n- `204`: Direct cancellation successful - order items cancelled and sent to Omnitron.\n- `200`: Direct cancellation failed - CancellationRequest records created as fallback.\n- `400`: Validation error - cancellation not allowed.","operationId":"cancelOrder","parameters":[{"$ref":"#/components/parameters/CSRFTokenHeader"},{"$ref":"#/components/parameters/CookieHeader"},{"name":"order_number","in":"path","required":true,"schema":{"type":"string"},"description":"The order number to cancel."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCancellationRequest"}}}},"responses":{"200":{"description":"Direct cancellation failed - CancellationRequest records created as fallback.\nReturns the list of created CancellationRequest records that will be processed by the back-office.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CancellationRequestResponse"}}}}},"204":{"description":"Direct cancellation successful.\nThe cancellation has been sent to Omnitron and order item statuses are updated to `cancellation_waiting`."},"400":{"description":"Validation error - cancellation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"404":{"description":"Order not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}}}}}}}
```

## Request Order Address Change

> Submits a request to change the delivery address for an existing order.\
> \
> \*\*Business Logic:\*\*\
> \- Validates that the order and address belong to the authenticated user.\
> \- Sends the address change request to the order management system (Omnitron).\
> \- The request may be subject to approval based on order status.\
> \
> \*\*Restrictions:\*\*\
> \- Cannot change address for orders that have already been shipped.\
> \- The new address must be a valid address from the user's address book.\
> \
> \*\*Error Code:\*\* \`order\_100\_3\` - Old order address cannot be changed (order already shipped).

```json
{"openapi":"3.1.0","info":{"title":"Orders API","version":"1.0.0"},"tags":[{"name":"Order Management","description":"Order completion, cancellation, and modification endpoints"}],"servers":[{"description":"Server base URL","url":"https://{commerce_url}","variables":{"commerce_url":{"default":"sandbox.akinon.com","description":"Commerce server URL"}}}],"security":[{"cookieAuth":[]}],"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"sessionid"}},"parameters":{"CSRFTokenHeader":{"name":"X-CSRFToken","in":"header","description":"CSRF token for write operations (POST, PUT, PATCH, DELETE).\nRequired for security when using session authentication.\nObtain token from cookie 'csrftoken' or meta tag in HTML.","required":true,"schema":{"type":"string"}},"CookieHeader":{"name":"Cookie","in":"header","description":"Session ID and CSRF token cookies.\nFormat: `sessionid=<id>; osessionid=<id>; csrftoken=<token>`","required":true,"schema":{"type":"string"}}},"schemas":{"OrderAddressChangeRequest":{"type":"object","required":["order","address","order_address_types"],"properties":{"order":{"type":"integer","description":"The ID of the order to update."},"address":{"type":"integer","description":"The ID of the new address from the user's address book."},"order_address_types":{"type":"array","items":{"type":"string","enum":["shipping","billing"]},"description":"Which address types to update (shipping, billing, or both)."},"channel_id":{"type":["integer","null"],"description":"Channel ID (optional, populated automatically)."}}},"OrderAddressChangeResponse":{"type":"object","description":"Response from Omnitron after address change request.","properties":{"status":{"type":"integer","description":"HTTP status code from Omnitron API."}}},"ValidationErrorResponse":{"type":"object","description":"Standard DRF validation error response","additionalProperties":{"type":"array","items":{"type":"string"}}}}},"paths":{"/orders/address_change/":{"post":{"tags":["Order Management"],"summary":"Request Order Address Change","description":"Submits a request to change the delivery address for an existing order.\n\n**Business Logic:**\n- Validates that the order and address belong to the authenticated user.\n- Sends the address change request to the order management system (Omnitron).\n- The request may be subject to approval based on order status.\n\n**Restrictions:**\n- Cannot change address for orders that have already been shipped.\n- The new address must be a valid address from the user's address book.\n\n**Error Code:** `order_100_3` - Old order address cannot be changed (order already shipped).","operationId":"requestOrderAddressChange","parameters":[{"$ref":"#/components/parameters/CSRFTokenHeader"},{"$ref":"#/components/parameters/CookieHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderAddressChangeRequest"}}}},"responses":{"200":{"description":"Address change request submitted successfully to Omnitron.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderAddressChangeResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}}}}}}}
```
