# 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:**
```json
{
  "orders": {
    "tenantid": 1135,
    "locationid": 1166,
    "customerid": 42,
    "items": [
      { "productid": 7060, "orderqty": 2, "price": 45.0 }
    ]
  }
}
```

**Also accepted (flat, no wrapper):**
```json
{
  "tenantid": 1135,
  "locationid": 1166,
  "customerid": 42,
  "items": [
    { "productid": 7060, "orderqty": 2, "price": 45.0 }
  ]
}
```

**This shape used to silently lose the items — avoid it:**
```json
{
  "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

1. Pick a real `tenantid` + `locationid` + `productid` combo you know has
   stock (ask backend/ops for current numbers, or check via the merchant
   web app's inventory view).
2. Place a normal order for 1 unit through the app. Confirm it returns `200`
   and the response's `details.items` array is non-empty.
3. Place an order for a quantity larger than what's currently in stock for
   that product/location. Confirm you get a `409` with an "insufficient
   stock" message, and that the app surfaces this to the user instead of
   silently failing or showing a generic error.
4. 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.
