Two gaps found while auditing the order/stock flow: - Receiving stock via an approved stock request only updated products.productstatus (a global per-product flag). A location flagged outofstock by CreateOrder never got reactivated, since nothing touched productlocations.status on the way back in. CreateProductStock now reactivates the specific (tenant, location, product) row to "available" for every "in" entry, the counterpart to how it gets flagged out. - getproductbyvariant returned no stock info at all, so the app could only find out a product was unavailable from the 409 at order time. It now accepts an optional locationid and, when passed, returns live productstock (same SUM(in)-SUM(out) formula the order check uses) and locationstatus per product. Omitting locationid keeps the old response shape. Added MOBILE_ORDER_VERIFICATION.md as a handoff doc for the mobile team covering the expected request/response shapes and how to verify their integration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.9 KiB
Order Creation — Mobile Developer Verification Guide
Why this exists
We found that orders placed through the app were being saved with zero line
items — the order header (tenant, location, customer) saved fine, but the
items array was silently getting dropped somewhere between the app and the
database. Because the stock check only runs over whatever's in items, an
order with no items also skipped stock validation entirely.
The backend now tolerates a few different request shapes and has a stock check in place, but the app's actual request needs to be verified against what's below to confirm it lines up.
Endpoint
POST https://fiesta.nearle.app/live/api/v1/mob/orders/createorder
Content-Type: application/json
Request shape — items MUST be inside orders, not a sibling of it
Correct:
{
"orders": {
"tenantid": 1135,
"locationid": 1166,
"customerid": 42,
"items": [
{ "productid": 7060, "orderqty": 2, "price": 45.0 }
]
}
}
Also accepted (flat, no wrapper):
{
"tenantid": 1135,
"locationid": 1166,
"customerid": 42,
"items": [
{ "productid": 7060, "orderqty": 2, "price": 45.0 }
]
}
This shape used to silently lose the items — avoid it:
{
"orders": { "tenantid": 1135, "locationid": 1166 },
"items": [ { "productid": 7060, "orderqty": 2 } ]
}
items as a sibling of orders (not nested inside it) is now handled as a
fallback server-side too, but don't rely on the fallback — put items inside
orders to match the primary/documented shape.
Required fields per item
| field | type | required | notes |
|---|---|---|---|
productid |
int | yes | must be a real product for the tenant |
orderqty |
number | yes | quantity being ordered |
price |
number | recommended | unit price at time of order |
locationid |
int | no | defaults to the order's own locationid if omitted |
Expected responses — verify your app handles all of these
| Scenario | HTTP code | Body (key fields) |
|---|---|---|
| Order succeeds | 200 |
"status": true, "details": { "orderheaderid": ..., "items": [...] } |
No tenantid at all |
409 |
"status": false, "message": "Tenant ID is required" |
items missing/empty |
400 |
"status": false, "message": "Order must contain at least one item" |
| Requested qty > available stock | 409 |
"status": false, "message": "insufficient stock for product '<name>': requested X, available Y" |
Important: a 409 with "insufficient stock" is not a network/server
error — it's the correct, expected response when a customer tries to order
more than what's in stock at that store. The app should catch this
specifically (check the message text, or treat any 409 from this endpoint
as a stock problem) and show the customer a clear "not enough stock" message
rather than a generic error screen.
How to verify end-to-end yourselves
- Pick a real
tenantid+locationid+productidcombo you know has stock (ask backend/ops for current numbers, or check via the merchant web app's inventory view). - Place a normal order for 1 unit through the app. Confirm it returns
200and the response'sdetails.itemsarray is non-empty. - Place an order for a quantity larger than what's currently in stock for
that product/location. Confirm you get a
409with an "insufficient stock" message, and that the app surfaces this to the user instead of silently failing or showing a generic error. - Cancel a successful order and confirm a follow-up stock check reflects the restored quantity (ask backend to check, or place the same over-quantity order again afterward — it should now succeed if cancellation restored enough stock).
Checking stock before the customer even taps "order"
GET /live/api/v1/mob/products/getproductbyvariant now accepts an optional
locationid query param:
GET /live/api/v1/mob/products/getproductbyvariant?tenantid=1135&variantid=44&locationid=1166
When locationid is passed, each returned product now carries two extra
live fields:
| field | meaning |
|---|---|
productstock |
live available quantity at that store — same SUM(in)-SUM(out) formula the order stock check uses |
locationstatus |
that store's status for this product, e.g. "outofstock" or "available"/"Active" |
If locationid is omitted, both fields come back empty/zero — this is
the old behavior preserved for backward compatibility, not new stock data.
Start passing locationid (the store the customer is browsing) to get real
numbers, and use it to show "out of stock" / gray out the add-to-cart button
before the customer tries to order, instead of only finding out from the
409 response above.