# Cancelling a seller order — what to change in the app (2026-10-22)

**For:** the mobile app developer. The website changed how a customer cancels a **seller order**; this file lists
what the app must change to match. It builds on the order screens of `docs/api/combined-orders-mobile.md` (order
list, order page, edit screen).

**Server:** nothing to wait for. The cancel endpoint keeps its URL, fields and answers (§4); current app builds keep
working.

---

## 1. Terms

| Term | What it is | In the API |
|---|---|---|
| **Combined order** (checkout) | everything bought in one checkout | one item of `purchase-history/grouped` |
| **Seller order** | one seller's share of the checkout (e.g. الأوائل), with its own code, status and **Cancel** / **Edit** | `orders[]` inside the item |
| **Product line** | one product of a seller order | `orders[].lines[]` |

---

## 2. What to change

1. **Cancel form: remove the image upload.** The form is now reason (required) + notes (optional) only.
2. **Edit screen: removing the last remaining product opens the cancel form.** Removing some products while others of
   the same seller order stay is still a normal edit. As soon as every product of the seller order is removed, close
   the edit screen and open the cancel form for that seller order (do not save it as an edit).

Everything else about cancelling stays as it is: the Cancel button on each seller order, the reason list, the
endpoint.

---

## 3. The rule

| What the customer does | What happens |
|---|---|
| Cancels **some** products of a seller order, others of that seller order stay | an edit: those products are cancelled, **no cancel form** |
| Removes the **last remaining** product of a seller order, or all its products at once | the **cancel form** opens |
| Taps **Cancel** on a seller order | the **cancel form** opens |

It does **not** matter whether the checkout's other seller orders go on, or whether this is the last seller order
left: a whole seller order is always cancelled through the form, with a reason.

Example: a customer orders 2 products from الأوائل and 1 from another seller.

- Removes 1 الأوائل product in the edit screen → only that product is cancelled, no form.
- Removes both الأوائل products, or taps Cancel on the الأوائل order → the cancel form; the other seller's order goes on.
- Later cancels the other seller's order too → the cancel form again.

---

## 4. Screens

### 4.1 The cancel form

Show the **Cancel** button on a seller order when `orders[].can_cancel` is true (unchanged).

- Title: **إلغاء الطلب** + the seller order's `code`.
- **السبب** (Reason), **required**: a picker filled from `GET /api/v2/cancel-reason` (`[{key, title}]`). First,
  empty option: **اختر سبب الإلغاء**. Send the `key`. Do not send until a reason is picked.
- **ملاحظات** (Notes), **optional**: a multi-line text box.
- **No image upload.**
- Buttons: **إغلاق** (close, does nothing) and **تأكيد الإلغاء** (red, sends the cancel, §5).

After a successful cancel, refresh the order page (the website reloads it and shows
"Order has been canceled successfully").

### 4.2 Edit screen (one seller order)

Quantity / variant changes, preview and save are unchanged (`docs/api/combined-orders.md` §3.3–3.5).

- Removing a product while **other products of this seller order stay**: the product gets the removed / undo state
  and Save cancels it (as today).
- Removing the **last remaining product**: close the edit screen and open the **cancel form of §4.1** for this seller
  order, right away (the website does it on the tap, before any save).
- If the preview or save answers `code: "remove_all"` (every product would be removed): open the cancel form the
  same way.

---

## 5. API call (unchanged)

```
POST /api/v2/order/cancel2/{id}          (auth: Bearer token; id = the seller order's id)
```

| Field | |
|---|---|
| `cancel_reason` | **required**: the `key` from `cancel-reason` |
| `cancel_note` | optional text, max 1000 characters |
| `cancel_image` | do not send any more (still accepted, so old builds keep working) |

| Situation | HTTP | Body |
|---|---|---|
| cancelled | 200 | `{"result": true, "message": "..."}` |
| the order can no longer be cancelled (not pending / already paid) or is not the user's | 200 | `{"result": false, "message": "..."}`: show `message`, refresh the order |
| no `cancel_reason` | 422 | `{"result": false, "message": "...", "errors": {"cancel_reason": ["..."]}}` |

---

## 6. Texts

| Where | Arabic | English |
|---|---|---|
| Form title | إلغاء الطلب | Cancel Order |
| Reason label | السبب | Reason |
| Reason placeholder | اختر سبب الإلغاء | Select the cancellation reason |
| Note label | ملاحظات | Notes |
| Buttons | إغلاق · تأكيد الإلغاء | Close · Confirm cancellation |

---

## 7. Checklist

- [ ] Cancel form: image field removed; reason (required) + notes (optional).
- [ ] Cancel on any seller order (order list card and order page) opens the form, whatever the other seller orders.
- [ ] Edit screen: removing the last remaining product opens the cancel form; removing some products stays an edit.
- [ ] `remove_all` from preview / save opens the cancel form.
- [ ] Refresh the order page after a cancel.

> If you read an earlier version of this file (with "case A / case B"): case B (cancel one store with no reason) was
> dropped. Every cancel of a whole seller order asks for a reason; remove case B, its two texts and the
> "last seller order left" check.
