# WP5b — Stock balances: the customer column and filter (UI)

**Repo:** FE (`/home/moonui2/public_html/moon-erp`) · **Branch:** `hazemdev2` · **Depends on WP4 + WP5a** · **BE change:** none

## Goal

Show «عميل التصنيع» on `/core/stock-balances`, let the search box match it, and add a filter for it.

## ⚠️ The whole point of this WP is that it must NOT be confused with the existing owner lens

The screen already has an owner picker and an owner-aware quantity column — but that owner is the
**consignment custody owner** (`inventory_lot_balances.owner_partner_id`): who owns the physical
quantity. What you are adding is **who owns the catalogue definition** (`products.toll_customer_id`).
They can differ on the same row, and the existing picker only lists partners with live consignment lots.

**Owner decision (§9 Q1, settled): two columns, two filters, explicitly labelled.** Suggested labels —
«المالك (أمانة)» for the existing one, «عميل التصنيع» for the new one. If the existing control has a
vaguer label today, **relabel it** so the pair reads unambiguously; that relabel is in scope precisely
because adding the second one is what creates the ambiguity.

## Read first

- `../tasks/WP5a-report.md` — the **exact** filter parameter name and resource field names. Build
  against those, not a guess. If it and the live API disagree, the API wins and you say so.
- `src/app/features/stock-balances/stock-balances.component.{ts,html}` — the screen. Filter bar at
  `html:8-47`; the table at `html:126`; `loadPage()` at `ts:184-218`; the owner lens at `ts:77-81`
  and `ts:263-267` (it URL-syncs `owner` — follow that precedent for the new filter).
- `src/app/core/services/stock-balance.service.ts` — `listPage()` at line 116. Note it uses `!= null`
  (line 125) deliberately so `owner=0` survives; keep that discipline for the new param.
- `src/app/core/models/inventory.model.ts` — `StockBalance` (line ~335) needs the new fields typed.

## What to build

1. Type the two new fields on the `StockBalance` interface, matching WP5a exactly.
2. **A new column** showing the customer name, «—» when there is none. Place it near the item
   identity (after the name) — it identifies the item, it is not a quantity.
3. **A new filter control** — a customer picker plus the "our own items only" option that WP5a's
   `'own'` sentinel provides. URL-sync it the way `owner` already is, so a filtered view is shareable.
4. Make sure the existing **search box** benefits: WP5a extends the server-side `search` to match the
   customer's name, so no FE change may be needed — **verify and say so** rather than assuming.
5. Include the new filter in `hasActiveFilters()` and in the clear-filters button.
6. Bilingual labels; any new key goes into **both** `ar.json` and `en.json`.

## Watch out

- **Where does the customer list come from?** Do **not** reuse `getLotOwners()` — it returns only
  partners with live consignment lots, which is the wrong population. Use the same source the products
  screen uses for its toll-customer picker, and say which you chose.
- The screen filters the returned page client-side for branch-restricted users (`ts:201-204`) **without
  adjusting `totalRecords`**, so the paginator already over-counts for those users. That is
  pre-existing — **do not fix it here**, but do not make it worse, and mention it in your report.
- `base_unit_symbol` is rendered (`html:177`) but is not declared on the `StockBalance` interface.
  Pre-existing; note it, don't chase it.

## Acceptance criteria

1. The customer column shows the name for items that have one and «—» for those that don't.
2. The new filter narrows the list, and «our own items» returns only items with no toll customer.
3. **The two filters are visibly distinct** and cannot be mistaken for each other — state the final
   labels in your report.
4. Typing a customer's name into the search box returns that customer's items.
5. A filtered view survives a refresh and is shareable as a URL.
6. The existing owner lens, warehouse, category, hide-zero and clear-filters all still behave exactly
   as before.
7. RTL intact; the table may scroll horizontally but must not break its container.
8. `npx ng build --base-href /app/` green; `npx tsc --noEmit` no new errors.

## Environment / rules

- ⛔ **NEVER** `git checkout` / `restore` / `stash` on `src/assets/i18n/ar.json` or `en.json`.
  Additive edits only; a new key goes in BOTH files.
- Builds are pre-authorized. **Do NOT deploy to `/app`** — the orchestrator deploys.
- `chown moonui2:moonui2` every edited file. Commit on `hazemdev2`, conventional. **No push, no merge.**
- moonui2 ONLY — never `/home/moonui`. Never print a git remote URL.

## Out of scope

Column reorder/resize on this screen (owner decision §9 Q5) · the branch-restriction paginator bug ·
the stock card (WP4/WP6) · any backend change.

## Reality check for your own testing

On `moonui2_dev_be` only **2 products out of 17,166** have a `toll_customer_id`, and the owner's
example item (17139) is **not** one of them. The column will look empty on almost every row here —
that is the data, not a bug. Find one of the two and verify against it.
