# Order Lifecycle

This document covers the full journey of a cross-border order from cart retrieval through to refund. All transitions are driven by inbound JSON webhooks from Global-e's back-end. The plugin never initiates outbound calls for order management; it only reacts.

---

## Phase 1 — Cart retrieval (`pro-cart-info`)

1. Shopper lands on the merchant store. Global-e JS (`pro.js` or `gem.js`) detects an international visitor via the `GlobalE_Data` cookie.
2. Global-e's overlay calls `/?wc-api=pro-cart-info&hash={cartId}`.
3. `Helper\Session` reads the cookie, injects country and currency into the WooCommerce session.
4. `Api\Cart::info()` instantiates `Model\Cart`, builds `ProductsList`, `DiscountsList`, free-shipping state, and customer address details.
5. The JSON response is consumed by Global-e's checkout UI to render localised pricing.

See [cart-integration.md](cart-integration.md) for session bootstrap details.

---

## Phase 2 — Order creation (`pro-order-create-update`)

**Endpoint:** `POST /?wc-api=pro-order-create-update`

`Api\Order::create()` delegates to `Model\Order`:

1. **`createOrderFromRequest($req)`** — creates a new `WC_Order`, sets customer, billing, and shipping addresses from `$req->CustomerDetails`. Sets the Global-e order ID as order meta (`globale_OrderId`).
2. **`prepareOrderFromRequest($req)`** — adds line items from `$req->ProductsInformation`:
   - Resolves each product by SKU or product ID (controlled by `PRODUCT_IDENTIFIER` config).
   - The `woocommerce_globale_pro_load_product_by_transformed_sku` filter allows custom SKU-to-product resolution.
   - Applies product meta via the `woocommerce_globale_pro_product_meta_attributes` filter.
   - Fires `woocommerce_globale_pro_action_add_order_item_after` per item.
   - Handles extra virtual products from the `woocommerce_globale_pro_extra_virtual_products_to_metadata` filter.
   - Sets totals, taxes, shipping, and discount lines.
   - Stores the merchant cart hash as `_globale_merchant_cart_hash`.
3. Saves the order with status `pending`.

**Response:** `InternalOrderId` (WC post/HPOS ID), `OrderId` (WC order number), `GlobalEOrderId`.

---

## Phase 3 — Payment notification (`pro-order-payment`)

**Endpoint:** `POST /?wc-api=pro-order-payment`

1. `initOrderFromRequest($req)` loads the `WC_Order` by looking up `globale_OrderId` via `Helper\Data::get_order_id()`.
2. Raw request is stored as `_globale_request_{ts}_order-payment` order meta (audit trail).
3. `doPayment($req)` updates payment-related meta, marks the order as paid, and transitions the WooCommerce order status accordingly.

---

## Phase 4 — Status updates (`pro-order-status`)

**Endpoint:** `POST /?wc-api=pro-order-status`

`Model\Order\Status::convertOrderStatus()` maps Global-e status codes to WooCommerce statuses:

| Global-e status | WooCommerce status |
|---|---|
| `canceled` | `cancelled` |
| `N/A` | `pending` |
| `N\/A` | `pending` |
| `complete` | `completed` |
| Any other value | Passed through as-is (validated against registered WC statuses) |

If the mapped status is not a registered WooCommerce status, the endpoint returns `Success: false` with an invalid status message.

---

## Phase 5 — Shipping / tracking update (`pro-order-shipping`)

**Endpoint:** `POST /?wc-api=pro-order-shipping`

1. Order is loaded by Global-e order ID.
2. Raw request logged as `_globale_request_{ts}_order-shipping-info-update`.
3. `updateTracking($req)` reads `$req->InternationalDetails` and stores carrier, tracking number, and tracking URL as order meta.

---

## Phase 6 — Refund (`pro-order-refund`)

**Endpoint:** `POST /?wc-api=pro-order-refund`

1. `Model\Order\Refund` is instantiated with the loaded `Model\Order`.
2. `initRefund($req)` parses refunded products and amounts.
3. `create()` calls WooCommerce's `wc_create_refund()`:
   - If `RESTOCK_REFUNDED_PRODUCTS` is enabled, inventory is restocked.
   - Refund reason defaults to `"Refunded"` (`Refund::DEFAULT_REFUND_REASON`).
4. On exception: the error is logged via `GCBWC::log()` with full stack trace and returned as `Success: false`.

---

## Order meta written by the plugin

| Meta key | Set by | Content |
|---|---|---|
| `globale_OrderId` | Order creation | Global-e order ID string |
| `_globale_merchant_cart_hash` | Order creation | Hash of the cart at the time of order creation |
| `_globale_Customer_SendConfirmation` | Payment / order creation | Boolean flag; when `false`, WooCommerce order emails are suppressed |
| `_globale_request_{ts}_{method}` | payment, status, shipping, refund | Raw JSON request body (audit trail) |
| `_globale_is_add_shipping_to_totals` | Order creation | Mirrors `ADD_SHIPPING_TO_TOTALS` config at time of order creation |

---

## Email suppression

`GlobalePro::doSendEmail()` is applied to all standard WooCommerce transactional email filters. If an order has a `globale_OrderId` meta value **and** `_globale_Customer_SendConfirmation` is explicitly `false`, all emails are suppressed for that order. Emails are sent normally when the meta key is absent.

---

## Sequential order number integration

When the **Sequential Order Numbers for WooCommerce** (`Wt_Advanced_Order_Number`) plugin is active, `GlobalePro::append_ge_order_number()` appends the Global-e order ID in brackets to the displayed sequential number (admin view only), provided `APPEND_GE_ORDER_NUMBER_TO_SEQ` is enabled.
