Skip to content

fix: use basketItemsUpdate and checkoutConfirmOrderV4 for REOPENED fulfillment orders#19

Open
tapnl wants to merge 1 commit into
gwillem:mainfrom
tapnl:main
Open

fix: use basketItemsUpdate and checkoutConfirmOrderV4 for REOPENED fulfillment orders#19
tapnl wants to merge 1 commit into
gwillem:mainfrom
tapnl:main

Conversation

@tapnl

@tapnl tapnl commented May 11, 2026

Copy link
Copy Markdown

Problem

Calling AddToOrder (PUT /mobile-services/order/v1/items) after ReopenOrder
silently succeeds (HTTP 200) but does not actually modify the fulfillment order.
The order remains empty in the AH app.

Three root causes were identified via mitmproxy traffic analysis of the official
AH iOS app:

1. Wrong endpoint

AddToOrder uses the REST endpoint /mobile-services/order/v1/items.
The AH app never uses this endpoint for modifying orders.
It exclusively uses GraphQL.

2. Missing basketItemsUpdate mutation

The correct way to add/update items in a REOPENED order is the GraphQL mutation:

mutation UpdateMyListBasket($items: [BasketMutation!]!, $input: BasketInput) {
basketItemsUpdate(items: $items, input: $input) {
__typename
status
}
}

With variables:
{
"input": null,
"items": [
{
"id": <product_id>,
"isStrikethrough": false,
"newPosition": 0,
"quantity":
}
]
}

3. Wrong resubmit method

RevertOrder (orderRevert mutation) does not correctly close a REOPENED order
after item changes. The AH app uses checkoutConfirmOrderV4 instead:

mutation CheckoutConfirmOrder($orderId: Int!, $orderInfo: CheckoutConfirmOrderPayloadV4!) {
checkoutConfirmOrderV4(orderId: $orderId, orderInfo: $orderInfo) {
__typename
status
}
}

With variables:
{
"orderId": <order_id>,
"orderInfo": {
"channel": "IOS",
"orderLastModified": "",
"paymentMethod": "PAY_AT_DELIVERY",
"purchaseStampsBookletsApplied": 0
}
}

The orderLastModified timestamp must be fetched from the basket summary
immediately after basketItemsUpdate:

query FetchBasketSummary {
basket {
summary {
lastUserChangeDateTime
}
}
}

Fix

Three new functions are needed:

  1. AddToBasket(ctx, items) — uses basketItemsUpdate GraphQL mutation
  2. GetBasketLastModified(ctx) — fetches lastUserChangeDateTime from basket summary
  3. ConfirmOrder(ctx, orderID, lastModified) — uses checkoutConfirmOrderV4 mutation

The correct flow for modifying a fulfillment order is:

  1. ReopenOrder(ctx, orderID)
  2. AddToBasket(ctx, items)
  3. GetBasketLastModified(ctx) → get timestamp
  4. ConfirmOrder(ctx, orderID, timestamp)

Additional finding: /summaries/active returns no hash for REOPENED orders

GetOrder on a REOPENED order returns hash: "". The appie-current-order-hash
header is therefore never sent for fulfillment order modifications. This is not
the root cause of the issue (the real problem is the wrong endpoint) but worth
noting.

Environment

  • appie-go v0.0.12
  • AH iOS app 9.36
  • Tested on a DELIVERY fulfillment order

@gwillem

gwillem commented May 19, 2026

Copy link
Copy Markdown
Owner

Thanks for debugging this nasty issue!

Some requests:

  1. Raw stderr logging, please use c.logger.Printf instead
  2. Update AddToOrder/RevertOrder to dispatch internally (so the appie cli keeps working)
  3. Add httptest based unit tests for the graphql methods
  4. Support non-PAY_AT_DELIVERY payment methods (eg ideal)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants