# WP6 — the screen

**Flags:** no migration · FE only. **Repo:** `/home/moonui2/public_html/moon-erp`, `hazemdev2`.
**Depends on:** WP3 (endpoint contract + the two new per-line fields).

## Goal

Let the buyer pick which lines — and how much of each — to convert, see what is left on the
request, and convert again later. The owner has already approved the visual design; it is in
the analysis under «معاينة الواجهة». Build that, not a variation of it.

## The contract you consume (from WP3)

- `POST /api/purchases/requests/{id}/convert-to-order` with
  `{ supplier_id, warehouse_id?, expected_delivery_date?, items?: [{ purchase_request_item_id, quantity }] }`.
  Omitting `items` = convert everything (the old behaviour).
- Each request item now carries `converted_quantity` and `remaining_convert_qty`.
- The request status can now be `partially_converted`.

**Verify these against the actual WP3 code before building** — read the FormRequest and the
resource, don't trust this brief if they disagree.

## The pattern to copy — do not invent one

The create-GRN and create-bill dialogs on the purchase-orders screen already solve exactly
this interaction, and the user knows them:

- `src/app/features/purchases/orders/orders.component.ts` — `openCreateGrn()` `:691-713`,
  `saveGrn()` `:715-753`; template `orders.component.html:692-753`.

Their pattern: re-fetch the full document on open (the list row has no items) → filter to
lines with remaining > 0 so fully-consumed lines **don't appear at all** → pre-fill each
quantity to its remaining → a three-column table (Product / Remaining read-only / Quantity
`p-inputNumber [min]="0" [max]="item.remaining"`) → **no checkboxes**; excluding a line means
zeroing it → filter `quantity > 0` before submitting.

Follow it exactly.

## Exact changes

### 1. `src/app/core/services/purchase-request.service.ts:103`

Widen `convertToOrder` to accept the optional `items` array.

### 2. The convert dialog — `src/app/features/purchases/requests/requests.component.html:423-472`

Today it is a 450px dialog containing **one** field, the supplier select. Replace with the
approved design: supplier select on top, then the lines table beneath. Widen to ~650px.
Handlers are at `requests.component.ts:565-592` (`openConvertDialog`, `confirmConvertToOrder`).

`openConvertDialog` must now fetch the request's items (the list row doesn't carry them —
same as the GRN dialog) and build the view-model.

**Gate on the setting.** When `purchases.allow_partial_request_conversion` is off, the dialog
must stay exactly as it is today — supplier only, no table, no `items` in the payload. Read
the setting the way this FE already reads other purchases settings; find an existing example
rather than inventing a fetch.

### 3. The view-dialog lines table — `requests.component.html:336-368`

This is a **hand-written** table (the create/edit dialog uses the shared
`TransactionLineItemsComponent`, but the view dialog does not — put the new columns here).
Add «المحوَّل» and «المتبقي» after Quantity, per the approved mockup: a green «مكتمل» badge
when nothing remains, the remaining figure in amber otherwise.

### 4. The new status — **five places**

1. `src/app/core/models/purchase-request.model.ts:57` — add `'partially_converted'` to the union.
2. `requests.component.ts:171-178` — the filter dropdown. ⚠ Labels here are **hardcoded
   Arabic strings, not i18n keys**. Follow the existing (wrong) local convention rather than
   half-migrating the list; record it as tech debt in the ledger.
3. `requests.component.ts:717-736` — `getStatusSeverity()`. Use `warn` (amber), matching how
   partial states read elsewhere.
4. `requests.component.html:102` — the convert button's visibility condition. Today
   `pr.status === 'approved'`; it must also allow `partially_converted`, or the second
   conversion is unreachable. **This is the single most important line in this package.**
5. `requests.component.html:113` — the cancel button's condition.

`getStatusLabel()` at `:738-742` builds `'PURCHASES.' + status.toUpperCase()`, so the label
resolves automatically once the i18n key exists.

### 5. i18n — `src/assets/i18n/ar.json` and `en.json`

Add `PURCHASES.PARTIALLY_CONVERTED` beside the existing `PARTIALLY_RECEIVED` (~line 5500)
and `PARTIALLY_BILLED` (~5502) — those are the naming precedent. Add any new dialog strings
too (e.g. a hint that zeroing a line excludes it).

⛔ **NEVER** run `git checkout` / `restore` / `stash` on either i18n file — they were
destroyed that way once. Additive edits only, and every key goes in **both** files.

### 6. Put the setting on the right settings sub-tab

`src/app/features/settings/settings.component.ts` maps each purchases setting key to a
sub-tab (`general` / `features` / `pricing`). An unmapped key falls back to **general**, so
`purchases.allow_partial_request_conversion` *will* render — but under «عام» instead of
beside `enable_purchase_requests` under «الميزات», which is where the owner will look for it.

Add `'purchases.allow_partial_request_conversion': 'features'` to that map. (Found during
WP2; the setting itself already exists and works.)

### 7. The dead NgRx path

`requests.effects.ts:167-183` + `requests.actions.ts:31` model this action, but the component
calls the service directly (`ts:576`) and never dispatches it. Update the action/effect
signature too so the two paths don't contradict each other, and note in the commit that the
store path is currently unused by this screen.

## Acceptance criteria

1. **Setting off ⇒ the screen is exactly as today.** Same dialog, same payload, no new
   columns visible. Verify this first.
2. Setting on: the dialog lists only lines with remaining > 0, quantities pre-filled to
   remaining, each capped at its remaining.
3. Zeroing a line excludes it; the submitted payload contains only lines with quantity > 0.
4. After a partial convert the list row shows «محوَّل جزئيًا» and **the convert button is
   still there**.
5. The view dialog shows converted and remaining per line.
6. After the final conversion the row shows «محوَّل» and the convert button is gone.
7. `npx ng build` green, `npx tsc --noEmit -p tsconfig.app.json` clean.

## Out of scope

Any backend change. The create/edit dialog's shared line grid. Migrating the hardcoded
Arabic filter labels to i18n (record as debt, don't do it here).

## Finish

`chown moonui2:moonui2` every touched file · conventional commit on `hazemdev2` ·
**do not push, do not merge, do not deploy to `/app`** — the owner runs `/fullpush`.
Commit as soon as the build is green.
