# Order Replacement and Weight Change Actions

This document describes all order-level actions related to **product replacement**, **weight changes**, **capture**, and **additional payment handling**.

Each action includes endpoint definitions, request/response structures, validation rules, business constraints, audit behavior, and configuration dependencies.

## <mark style="color:red;">1. Capture Order</mark>

This action is executed **only once per order**.

It captures the order’s previously authorized transaction. This operation converts the prior authorization obtained from the customer into an actual payment.

#### Endpoint

```
POST /api/v1/orders/{order_id}/capture_order/
```

#### Request Example

```http
POST /api/v1/orders/12345/capture_order/
Authorization: Token your_token_here
Content-Type: application/json

{
  "force_refund": false
}
```

#### Request Parameters

* `force_refund` (boolean, optional, default: `false`)
  * If the order already has a **purchase transaction**, setting this value to `true` triggers a refund for the excess amount and applies a capture-like behavior.

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

(Empty response body)
```

#### Business Rules

1. This action **must be executed only once** per order.
2. If the order has an **authorized transaction**, the order status **cannot** be `waiting_for_substitute`.
   * Otherwise, `FinalizeCaptureWaitingPaymentException` is raised.
3. Concurrent capture attempts are blocked.
   * A cache lock prevents multiple captures on the same order for **60 seconds**.
4. The order total amount is validated via:

   ```
   order.validate_total_amount()
   ```
5. The order must have either:
   * an **authorize transaction**, or
   * a **purchase transaction**
   * Otherwise, `OrderCaptureException` is raised.
6. If `force_refund = true` and the order already has a purchase transaction:
   * The excess amount of the purchase transaction is refunded.
7. If the order status is `confirmation_waiting`, it is updated to `approved`.
8. An audit log entry is created with action:

   ```
   order_capture
   ```

#### ENV & Dynamic Settings

* **ENV**: None
* **Dynamic Settings**: None

***

## <mark style="color:red;">2. Bulk Replace Products</mark>

It bulk replaces the products of multiple order items in an order.

The existing order items are canceled, and new order items are created with the new products.

#### Endpoint

```
POST /api/v1/orders/{order_id}/bulk_replace_products/
```

#### Request Example

```http
POST /api/v1/orders/12345/bulk_replace_products/
Authorization: Token your_token_here
Content-Type: application/json

[
  {
    "order_item": 100,
    "new_product_sku": "NEW_PRODUCT_SKU_123"
  },
  {
    "order_item": 101,
    "new_product_sku": "NEW_PRODUCT_SKU_456"
  }
]
```

#### Request Parameters

* `order_item` (integer, optional): ID of the order item to be replaced.
* `new_product_sku` (string, optional): SKU of the replacement product.

**Validation Note**

* At least one of `order_item` or `new_product_sku` **must** be provided.
* If both are missing, serializer validation fails.

#### Response Example

```json
{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "approved",
  "amount": "1500.00",
  "currency": "TRY",
  "orderitem_set": [
    {
      "pk": 200,
      "price": "1500.00",
      "status": "approved"
    }
  ]
}
```

#### Business Rules

1. Each request item must include at least one of the `order_item` or `new_product_sku` parameters. If neither is provided, a serializer validation error is raised.
2. The order status must be one of the following:
   * `confirmation_waiting`
   * `approved`
   * `preparing`\
     Otherwise, `OrderItemChangeOrderNotAllowedException` is raised.
3. The order’s channel type must be `web`. Otherwise, `OrderItemChangeOrderNotAllowedException` is raised.
4. The order transaction is validated (`validate_transaction()`).
5. The order must not have been sent to the ERP system (`is_send=False`). Otherwise, `OrderItemReplacementOrderIsSendException` is raised.
6. For each order item:
   * The order item must not have an active cancellation plan.
   * The order item status must be one of: `waiting`, `payment_waiting`, `confirmation_waiting`, `approved`, `preparing`.
   * The new product must belong to the same catalog.
   * The new product must be in the same stock list.
   * The stock quantity of the new product must not be less than the order item’s quantity.
   * The stock unit type must be `quantity`.
   * The price of the new product must be greater than the order item’s total benefit share amount.
7. If the new order amount is greater than the previous amount:
   * The `ORDER_ITEM_UPPER_PRICE_ENABLE` dynamic setting must be enabled. Otherwise, `OrderItemPriceExceedsCurrentPriceException` is raised.
   * The order status is updated to `waiting_for_substitute`.
   * A `create_replacement_order` event is sent to Commerce.
8. The existing order items are canceled (`status=cancelled`, `price=0`).
9. New order items are created.
10. The order amount is recalculated.
11. An audit log entry is created with the action:

    ```
    order_change_product
    ```

#### ENV & Dynamic Settings

* **ENV**: None
* **Dynamic Settings**
  * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` (boolean, default: `false`): Determines whether order item product updates are enabled.
  * `ORDER_ITEM_UPPER_PRICE_ENABLE` (boolean, default: `false`): Allows the new product price to be higher than the existing price.

***

## <mark style="color:red;">3. Bulk Reduce Weights</mark>

It bulk reduces the weights of multiple order items in an order. This operation is used for products sold by kilogram.

This action **does not allow weight increase**.

#### Endpoint

```
POST /api/v1/orders/{order_id}/bulk_reduce_weights/
```

#### Request Example

```http
POST /api/v1/orders/12345/bulk_reduce_weights/
Authorization: Token your_token_here
Content-Type: application/json

[
  {
    "order_item": 100,
    "new_weight": 2.5
  },
  {
    "order_item": 101,
    "new_weight": 1.8
  }
]
```

#### Request Parameters

* `order_item` (integer, required): The ID of the order item whose weight will be changed.
* `new_weight` (decimal, required): The new weight value (in kilograms).

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "approved",
  "amount": "1200.00",
  "currency": "TRY",
  "orderitem_set": [
    {
      "pk": 100,
      "price": "1200.00",
      "attributes": {
        "unit_weight": "2.5",
        "old_unit_weight": "3.0"
      },
      ...
    }
  ],
  ...
}
```

#### Business Rules

1. The `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` dynamic setting must be enabled **OR** the `ORDER_ITEM_WEIGHT_KEY` setting must be defined.\
   Otherwise, `OrderItemReplacementNotEnabledException` is raised.
2. The order transaction is validated by calling `validate_transaction()`.
3. For each order item:
   * The order item must not have an active cancellation plan.
   * The order item status must be one of the following:\
     `waiting`, `payment_waiting`, `confirmation_waiting`, `approved`, `preparing`.
   * The stock unit type must be `kilogram`.
   * The `ORDER_ITEM_WEIGHT_KEY` key must exist in the order item’s `attributes` field.
   * The new weight must be different from the previous weight.
4. The price is recalculated based on the weight change ratio:
   * `new_price = old_price * (new_weight / old_weight)`
   * If `new_weight = 0`, the order item price is set to `0`, and all benefit applicants are cancelled.
5. The order item’s `attributes` field is updated as follows:
   * `old_{ORDER_ITEM_WEIGHT_KEY}`: stores the previous weight
   * `{ORDER_ITEM_WEIGHT_KEY}`: stores the new weight
6. If the new order total amount is greater than the previous total:
   * The `ORDER_ITEM_UPPER_PRICE_ENABLE` dynamic setting must be enabled.\
     Otherwise, `OrderItemPriceExceedsCurrentPriceException` is raised.
   * The order status is updated to `waiting_for_substitute`.
   * A `create_replacement_order` event is sent to Commerce.
7. The order total amount is recalculated.
8. An audit log entry is created with the action:

   ```
   bulk_order_item_change_weight
   ```

#### ENV & Dynamic Settings

* **ENV**
  * `ORDER_ITEM_WEIGHT_KEY` (string, default: `None`): The key name used to store weight information in the order item’s `attributes` field (e.g. `"unit_weight"`).
* **Dynamic Settings**
  * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` (boolean, default: `False`): Determines whether order item updates are enabled.
  * `ORDER_ITEM_UPPER_PRICE_ENABLE` (boolean, default: `False`): Allows the price calculated from the new weight to be higher than the previous price.

***

## <mark style="color:red;">4. Bulk Replace Product and Reduce Weight</mark>

Replaces the products of multiple order items in an order and/or reduces their weights.\
This action allows **both product replacement and weight reduction** to be performed within the same request.

#### Endpoint

```
POST /api/v1/orders/{order_id}/bulk_replace_product_and_reduce_weight/
```

#### Request Example

```http
POST /api/v1/orders/12345/bulk_replace_product_and_reduce_weight/
Authorization: Token your_token_here
Content-Type: application/json

[
  {
    "order_item": 100,
    "new_product_sku": "NEW_PRODUCT_SKU_123"
  },
  {
    "order_item": 101,
    "new_weight": 2.5
  }
]
```

#### Request Parameters

* `order_item` (integer, optional): The ID of the order item to be updated.
* `new_product_sku` (string, optional): The SKU of the new product (for product replacement).
* `new_weight` (decimal, optional): The new weight value (for weight reduction).

**Notes**:

* `new_product_sku` and `new_weight` cannot be provided at the same time.\
  If both are provided, a validation error is raised.
* At least one of `new_product_sku`, `new_weight`, or `order_item` must be provided.\
  If none are provided, a validation error is raised.

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "approved",
  "amount": "1500.00",
  "currency": "TRY",
  "orderitem_set": [...],
  ...
}
```

#### Business Rules

1. Each request item must include at least one of the following parameters:\
   `new_product_sku`, `new_weight`, or `order_item`.\
   If none are provided, a serializer validation error is raised.
2. `new_product_sku` and `new_weight` cannot be provided together in the same request item.\
   If both are provided, a serializer validation error is raised.
3. The `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` dynamic setting must be enabled **OR** the `ORDER_ITEM_WEIGHT_KEY` setting must be defined.\
   Otherwise, `OrderItemReplacementNotEnabledException` is raised.
4. The order transaction is validated by calling `validate_transaction()`.
5. For each order item:
   * If `new_product_sku` is provided, **all business rules of the `bulk_replace_products` action apply**.
   * If `new_weight` is provided, **all business rules of the `bulk_reduce_weights` action apply**.
6. Product replacement and weight reduction can both be applied to the **same order item**, executed sequentially.
7. If the new order total amount is greater than the previous total:
   * The `ORDER_ITEM_UPPER_PRICE_ENABLE` dynamic setting must be enabled.\
     Otherwise, `OrderItemPriceExceedsCurrentPriceException` is raised.
   * The order status is updated to `waiting_for_substitute`.
   * A `create_replacement_order` event is sent to Commerce.
8. The order total amount is recalculated.
9. An audit log entry is created with the action:

   ```
   order_bulk_replace_product_and_change_weight
   ```

#### ENV and Dynamic Settings

* **ENV**
  * `ORDER_ITEM_WEIGHT_KEY` (string, default: `None`): The key name used to store weight information in the order item’s `attributes` field.
* **Dynamic Settings**
  * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` (boolean, default: `False`): Determines whether order item updates are enabled.
  * `ORDER_ITEM_UPPER_PRICE_ENABLE` (boolean, default: `False`): Allows the new price to be higher than the previous price.

***

## <mark style="color:red;">5. Bulk Change Weight</mark>

Updates the weights of multiple order items within an order in bulk (the weight can be **increased or decreased**).

The difference from the `bulk_reduce_weights` action is that this action **also allows weight increases**.

#### Endpoint

```
POST /api/v1/orders/{order_id}/bulk_change_weight/
```

#### Request Example

```http
POST /api/v1/orders/12345/bulk_change_weight/
Authorization: Token your_token_here
Content-Type: application/json

[
  {
    "order_item": 100,
    "new_weight": 3.5
  },
  {
    "order_item": 101,
    "new_weight": 2.0
  }
]
```

#### Request Parameters

* `order_item` (integer, required): The ID of the order item whose weight will be changed.
* `new_weight` (decimal, required): The new weight value (in kilograms).

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "waiting_for_substitute",
  "amount": "1800.00",
  "currency": "TRY",
  "orderitem_set": [
    {
      "pk": 100,
      "price": "1800.00",
      "attributes": {
        "unit_weight": "3.5",
        "old_unit_weight": "2.5"
      },
      ...
    }
  ],
  ...
}
```

#### Business Rules

1. The `ORDER_ITEM_UPPER_PRICE_ENABLE` dynamic setting **must be enabled**.\
   Otherwise, `OrderItemPriceExceedsCurrentPriceException` is raised.
2. The `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` dynamic setting must be enabled **OR** the `ORDER_ITEM_WEIGHT_KEY` setting must be defined.\
   Otherwise, `OrderItemReplacementNotEnabledException` is raised.
3. The order transaction is validated by calling `validate_transaction()`.
4. **All business rules of the `bulk_reduce_weights` action apply**.
5. The weight may be increased or decreased, but it **must be different from the previous weight**.
6. If the new order total amount is greater than the previous total:
   * The order status is updated to `waiting_for_substitute`.
   * A `create_replacement_order` event is sent to Commerce.
7. The order total amount is recalculated.
8. An audit log entry is created with the action:

   ```
   bulk_order_item_change_weight
   ```

#### ENV and Dynamic Settings

* **ENV**
  * `ORDER_ITEM_WEIGHT_KEY` (string, default: `None`): The key name used to store weight information in the order item’s `attributes` field.
* **Dynamic Settings**
  * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` (boolean, default: `False`): Determines whether order item updates are enabled.
  * `ORDER_ITEM_UPPER_PRICE_ENABLE` (boolean, default: `False`): **MANDATORY** – must be enabled for this action.

***

## <mark style="color:red;">6. Bulk Replace Product and Change Weight</mark>

Allows replacing products and/or changing the weight of **multiple order items** within an order.\
Unlike the `bulk_replace_product_and_reduce_weight` action, this endpoint **allows both increasing and decreasing the weight**.

#### Endpoint

```http
POST /api/v1/orders/{order_id}/bulk_replace_product_and_change_weight/
```

#### Request Example

```http
POST /api/v1/orders/12345/bulk_replace_product_and_change_weight/
Authorization: Token your_token_here
Content-Type: application/json

[
  {
    "order_item": 100,
    "new_product_sku": "NEW_PRODUCT_SKU_123"
  },
  {
    "order_item": 101,
    "new_weight": 3.5
  }
]
```

#### Request Parameters

* `order_item` (integer, **required**): ID of the order item to be updated
* `new_product_sku` (string, optional): SKU of the new product to replace the existing one
* `new_weight` (decimal, optional): New weight value for the order item

**Validation Rules**

* `order_item` is **required** for each request item.
* At least **one of** `new_product_sku` or `new_weight` must be provided.
* `new_product_sku` and `new_weight` **cannot be provided together** in the same request item.
  * If both are provided, a serializer validation error is raised.
* `new_weight` must be **different from the current weight** (both increase and decrease are allowed).

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "waiting_for_substitute",
  "amount": "2000.00",
  "currency": "TRY",
  "orderitem_set": [...],
  ...
}
```

#### Business Rules

1. The `ORDER_ITEM_UPPER_PRICE_ENABLE` dynamic setting **must be enabled**.
   * Otherwise, `OrderItemPriceExceedsCurrentPriceException` is raised.
2. At least **one** of the following conditions must be met:
   * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` dynamic setting is enabled
   * `ORDER_ITEM_WEIGHT_KEY` ENV setting is defined
   * Otherwise, `OrderItemReplacementNotEnabledException` is raised.
3. The order transaction is validated (`validate_transaction()`).
4. All business rules defined for the `bulk_replace_product_and_reduce_weight` action **also apply**.
5. The order total amount is recalculated.
6. If the new order amount is **greater than** the previous amount:
   * Order status is updated to `waiting_for_substitute`.
   * A `create_replacement_order` event is sent to Commerce.
7. An audit log is created after the operation
   * Action name: `order_bulk_replace_product_and_change_weight`

#### ENV and Dynamic Settings

* **ENV**
  * `ORDER_ITEM_WEIGHT_KEY` (string, default: `None`): Key name used to store weight information in the order item’s `attributes` field
* **Dynamic Settings**
  * `ORDER_ITEM_PRODUCT_UPDATE_AVAILABLE` (boolean, default: `False`): Determines whether order item updates are enabled
  * `ORDER_ITEM_UPPER_PRICE_ENABLE` (boolean, default: `False`): **MANDATORY** – Must be enabled for this action

***

## <mark style="color:red;">7. Waive Additional Payment</mark>

Cancels a pending **additional payment (pay later)** request for an order and updates the order status to `preparing`.

This action is used when an order is waiting for an additional payment from the customer, but the payment request is waived.

#### Endpoint

```http
POST /api/v1/orders/{order_id}/waive_additional_payment/
```

#### Request Example

```http
POST /api/v1/orders/12345/waive_additional_payment/
Authorization: Token your_token_here
Content-Type: application/json

(Empty request body)
```

#### Request Parameters

This action does **not** require a request body.

#### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "pk": 12345,
  "number": "ORD-2024-001",
  "status": "preparing",
  "amount": "1500.00",
  "currency": "TRY",
  "channel": {...},
  "customer": {...},
  "orderitem_set": [...],
  ...
}
```

#### Business Rules

* The order status **must be** `waiting_for_substitute`.
  * Otherwise, `PayLaterInfoInvalidOrderStatusException` is raised.
* The order must have an **active `PayLaterInfo` record** with `status=payment_waiting`.
  * If not found, `PayLaterInfoNotFoundFromOrderException` is raised.
* The order status is updated to `preparing`.
* The related `PayLaterInfo` record is updated to `waived`.
* The operation is executed within an **atomic transaction**.

#### ENV and Dynamic Settings

* **ENV**: None
* **Dynamic Settings**: None

***

## <mark style="color:red;">General Notes</mark>

### <mark style="color:red;">Error Handling</mark>

All actions may raise the following exceptions under relevant conditions:

* `OrderItemHasActiveCancellationPlanException`
  * The order item has an active cancellation plan.
* `OrderItemReplacementNotAllowedException`
  * Order item replacement is not allowed.
* `OrderItemReplacementOrderIsSendException`
  * The order has already been sent.
* `OrderItemPriceExceedsCurrentPriceException`
  * The new price exceeds the current price and `ORDER_ITEM_UPPER_PRICE_ENABLE` is disabled.
* `OrderCaptureException`
  * The order transaction cannot be captured.
* `PayLaterInfoNotFoundFromOrderException`
  * No pay later information exists for the order.

### <mark style="color:red;">Audit Logs</mark>

All actions create an **audit log** entry. These logs are used to track and audit order-related operations.

### <mark style="color:red;">Channel Integration</mark>

Some actions (product replacement, weight change) send events to Commerce:

* `order_item_create` – When a new order item is created
* `order_item_update` – When an order item is updated
* `order_update` – When the order is updated
* `create_replacement_order` – When an additional payment is required

### <mark style="color:red;">Transaction Validation</mark>

All replacement-related actions validate the order transaction:

* The order must **not** be captured
* The transaction must be in **authorize** or **purchase** state


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akinon.com/technical-guides/omnitron/order-replacement-and-weight-change-actions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
