Files
ERP-core/Backend/PROGRESS.md
T
ImanThiyanga 4e84a15db7 feat: Implement procurement services and number sequence management
- Added INumberSequenceService interface for generating document numbers.
- Created NumberSequenceService to handle atomic document number issuance.
- Introduced IPurchaseOrderService interface and implemented PurchaseOrderService for managing purchase orders.
- Added IRequisitionService interface and implemented RequisitionService for handling requisitions.
- Created IRfqService interface and implemented RfqService for managing RFQs and vendor quotations.
- Defined necessary DTOs and domain entities for procurement processes.
- Ensured proper validation and error handling across services.
2026-07-13 10:28:58 +05:30

91 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backend — PROGRESS (Phase 1: Inventory & Supply Chain)
Legend: `[ ]` not started · `[~]` in progress · `[x]` done
Spec: `docs/10-BACKEND-PHASE1.md` (model + rules) · `docs/11-BACKEND-PHASE1.md` (API)
Convention: `docs/01-DOC-GUIDE.md §6`. Update this file in the **same commit** as the code. When ticking `[x]`, append a short note + any deviation.
## 0. Bootstrap
- [x] Solution + Web API project (`net10.0`), packages restored (00-CORE §5.4)
- [x] Folder structure per 00-CORE §5.3
- [x] `ErpDbContext` + Npgsql wired; `InitialCreate` migration **created and applied** (2026-07-10, 8 master-data tables). `/health``Healthy`.
- [x] Serilog, JWT, Swagger, HealthChecks, ProblemDetails in `Program.cs` (JWT bearer *validated*; endpoints not yet `[Authorize]`-gated — see §6 auth note)
- [x] `IUnitOfWork` + `UnitOfWork` (transaction boundary)
- [x] Generic repository base + interfaces
- [x] `ICurrentUser` (audit stamp from token `sub`)
- [x] ProblemDetails middleware + domain exception → `code` mapping (System/Errors; full §7 catalog added to `ErrorCodes`)
## 1. Master Data
> Code complete for all items below (2026-07-09). **Live smoke test PASSED against Postgres (2026-07-10):** create/get/list/update/status/reorder/uom-conversions across all 5 controllers; ETag round-trip 200 / stale→412 / missing→428; SKU_DUPLICATE→400; bad reference→422; missing-field→400 ValidationProblemDetails; category `?tree=true` nesting; `pageSize=9999` clamped to 200; deactivate via PATCH status→204. Still `[~]` (not `[x]`) for **one** reason: the **security gate** (00-CORE §8) — the foundational auth control (02-SECURITY B.1) and the audit trail (B.3, the AR-01 compensating control) land in §6. Flip to `[x]` once §6 auth+audit are wired.
- [x] Item: entity + config + enums (ItemType, TrackingMode; EntityStatus added) — `xmin`/RowVersion concurrency token (Npgsql), unique SKU
- [~] Item: repository (generic) + service + controller (CRUD, narrow DTOs, ETag/If-Match→412, SKU_DUPLICATE, reference validation) — server-controlled fields excluded (02-SECURITY C.1)
- [~] UOM + UOM conversions (`GET/POST /uoms`, `PUT /items/{id}/uom-conversions` full-replace upsert)
- [~] Category (hierarchy, `GET /categories?tree=true` nested build, parent-exists validation)
- [~] Vendor (CRUD, ETag/If-Match, unique code, deactivate via `PATCH /vendors/{id}/status`)
- [~] Warehouse + Bin (`/warehouses`, nested `/warehouses/{id}/bins`, bin code unique per warehouse)
- [~] Item reorder settings (`PUT /items/{id}/reorder` full-replace upsert, warehouse-exists validation)
## 2. Procurement
> Requisition/RFQ/PO implemented 2026-07-10. **Live smoke test PASSED** (docNo `PR/RFQ/PO-2026-#####` gap-controlled + incrementing, requestedBy/createdBy = seeded system user, RFQ comparison matrix, duplicate quotation→409, PO auto-approve + server-computed totals matching the spec example `112100/20178/132278`, edit-while-open with recomputed totals + ETag 200/412, PO_NOT_EDITABLE→409 on cancelled, cancel→200, bad reference→422). Same `[~]` reason as §1: the §6 security gate (auth + audit) is not yet wired.
- [~] Requisition (+ lines) + submit (`POST /requisitions`, `/{id}/submit`, list, get)
- [~] RFQ + quotations + comparison (`POST /rfqs`, `/{id}/quotations` [one per vendor], `GET /{id}/comparison` matrix)
- [~] Purchase Order: create (auto-approve, `approvalRequired` flag), edit-while-open (If-Match), approve (no-op), cancel
- [ ] Purchase Return (outbound movement, reason code) — **deferred**: needs GRN lines + stock ledger/FIFO (§3/§4). Build with those.
> **Deviation (recorded):** `VendorQuotation` is modelled as header + `VendorQuotationLine` (per-item pricing) to satisfy the API contract (docs/11 §3.2); docs/10 Part C.2's scalar `VENDOR_QUOTATION(unit_price, lead_days)` with no item ref cannot represent it. Update the ER model doc to match.
> **RFQ `vendorIds`** are validated for existence but not persisted (no RFQ↔vendor link in the model); quotations reference vendors directly.
## 3. Goods Receipt
- [ ] GRN create (against PO / direct), over-receipt tolerance
- [ ] GRN confirm → FIFO layer + ledger + PO `qtyReceived` (single UoW txn, Idempotency-Key)
- [ ] Inspection hold release / reject
## 4. Stock Core
- [ ] StockLayer + StockLedger entities/config (ledger append-only)
- [ ] `FifoCostingService` (consume oldest-first with row lock; valuation)
- [ ] Stock enquiry (onHand / available / onHold / inTransit)
- [ ] Ledger query · Valuation query
## 5. Stock Transactions
- [ ] Transfer: create → dispatch (consume, In-Transit) → receive (dest layer, cost-preserving)
- [ ] Adjustment (auto-post, mandatory reason code)
- [ ] Count (cycle/full → enter counts → variance → post)
- [ ] Reorder alerts (query) + suggest requisition
## 6. Cross-cutting
> **Auth-enforcement gap (open):** JWT bearer *validation* is wired, but no token issuer exists yet and controllers are **not** `[Authorize]`-gated, so §1 endpoints are currently open. This is the AR-01/NFR-03 control surface — gate all v1 endpoints (fallback authorization policy) in the same change as `POST /auth/login`, then re-run the 02-SECURITY B.1 checklist and flip §1 items to `[x]`.
- [ ] Audit log on every mutation (who/when/old→new)
- [x] Document numbering sequences (per type, per year) — `NumberSequence` + `NumberSequenceService` (atomic `INSERT … ON CONFLICT … RETURNING` inside the doc's UoW txn; gap-controlled). Verified issuing + incrementing PR/RFQ/PO.
- [~] Auth: simple in-app login → JWT (`POST /auth/login`) — foundation only: `User` table + seeded `system` user (id 1) exist and `ICurrentUser.AuditUserId` stamps docs; login endpoint + `[Authorize]` still pending.
- [ ] JournalEntryStub emitted per stock movement (data only)
- [ ] Negative-stock policy enforcement (default block)
- [ ] FEFO picking for perishables; block expired / on-hold issue
## Deferred (Phase 2+ — do NOT build now, hooks only)
- [ ] Vendor invoice + three-way match
- [ ] Reservation/allocation fulfilment
- [ ] RBAC policy enforcement + approval workflow activation
## Done
<!-- move [x] items here with date + note if the active list grows long -->
### 2026-07-09 — Bootstrap verified + Master Data (§1) implemented
- Bootstrap scaffolding confirmed against 00-CORE §5 (solution, packages, `Program.cs` wiring, UoW, generic repo, `ICurrentUser`, ProblemDetails handler). Added enum-as-string JSON (`JsonStringEnumConverter`) and registered the 5 master-data services.
- Domain: 3 enums (`ItemType`, `TrackingMode`, `EntityStatus`) + 8 entities (Category, Uom, UomConversion, Item, ItemReorder, Vendor, Warehouse, Bin) with one `IEntityTypeConfiguration` each; FKs `Restrict` (masters deactivate, not cascade-delete), unique indexes (SKU, vendor/warehouse code, uom name, bin code per-warehouse), decimal precision, `xmin` concurrency token on Item/Vendor.
- API: 5 controllers, lowercase routes matching `docs/11 §2` exactly (verified via generated `swagger.json`). ETag/If-Match (428 if missing, 412 on mismatch), narrow request DTOs (no over-posting), `PagedResponse<T>` list envelope (§1.4), `PageQuery` with pageSize clamp ≤200 (B.6).
- Migration `InitialCreate` generated (`xmin` correctly produces no DDL — uses the PG system column).
- **Verified:** `dotnet build` clean (0 warn/0 err); app boots (`Now listening… Application started`); `/api/meta` 200; `swagger.json` 200 with all 13 master-data paths; DI resolves controller→service→repo→DbContext (a DB-backed call reaches Npgsql, failing only on creds).
- **Blocked / follow-ups:** (1) auth enforcement + audit trail — §6 (the remaining security gate for `[x]`); (2) no `DELETE` master endpoints — `MASTER_IN_USE` code reserved until transaction tables exist (deactivate-only per FR-MD-08); (3) minor: bad-enum bind error leaks the CLR type name in `detail` (02-SECURITY B.5) — fine in Dev, tidy before prod.
### 2026-07-10 — Migration applied + live smoke test PASSED
- `dotnet ef database update` applied `InitialCreate` to local Postgres; `/health``Healthy`.
- End-to-end curl smoke across all 5 controllers — all green: warehouse/bin create+list; uom create; category + child + `?tree=true` nesting; vendor create + PUT (If-Match 200 / stale 412 / missing 428); item create (201, referencing category/uom/vendor) + GET (ETag header) + list/filter `q` + `pageSize=9999`→clamped 200; reorder PUT; uom-conversions PUT; full item PUT with fresh ETag→200; PATCH status Inactive→204; duplicate SKU→400 `SKU_DUPLICATE`; bad reference→422; missing required→400 ValidationProblemDetails; bad enum→400. Concurrency token (`xmin`) confirmed incrementing per mutation.
- Note: local dev DB now holds smoke-test rows (warehouse/bin/uom×2/category×2/vendor/item, item left Inactive). Reset any time with `dotnet ef database drop -f && dotnet ef database update`.
### 2026-07-10 — Procurement (§2, minus returns) + cross-cutting foundations
- Cross-cutting: `User` entity (+ seeded `system` user via `HasData`), `ICurrentUser.AuditUserId` (numeric actor, system fallback), `NumberSequence` + `NumberSequenceService` (atomic per-type/per-year doc numbers issued inside the UoW txn).
- Procurement: enums (RequisitionStatus, RfqStatus, PurchaseOrderStatus); 8 entities (Requisition/Line, Rfq/Line, VendorQuotation/Line, PurchaseOrder/Line) + configs; DTOs; 3 services; 3 controllers (`/requisitions`, `/rfqs`, `/purchase-orders`). PO carries the `xmin` ETag token; totals computed server-side; create/edit wrapped in `IUnitOfWork.ExecuteInTransactionAsync` so the reserved doc number rolls back with the doc.
- Migration `AddProcurement` generated + applied (10 tables incl. users/number_sequences; system-user seed; PO `xmin` emits no DDL).
- **Verified:** build clean; app boots; full procurement smoke green (see §2 note) — requisition→submit, RFQ→quotation→comparison, PO create/get/edit/approve/cancel, numbering increment, error paths 409/412/422.
- **Deferred/next:** Purchase Return (needs GRN+stock), then §3 GRN, §4 Stock Core (FIFO/ledger), §5 stock transactions. Auth/audit (§6) still the gate for flipping §1/§2 to `[x]`.
- Housekeeping: an empty user-created migration `20260709124415_initial` sits between InitialCreate and AddProcurement (applied, harmless no-op; emits a cosmetic CS8981 lowercase-name warning).