feat(inventory): display all warehouse items on selection and track withdrawal recipient

- Show all available inventory items immediately when selecting a warehouse in withdrawal form
- Add vertical scrolling container with max height to prevent layout overflow for large item lists
- Add Material column to the inventory rows table for clear item identification
- Add required 'delivered_to' recipient field in withdrawal form with frontend validation
- Track delivered_to in database, models, schemas, and API
- Display recipient badge on withdrawal cards in daily control page
- Group daily control withdrawals by inventory ID and recipient
This commit is contained in:
2026-09-28 22:54:02 +03:30
parent 253c922280
commit d85ede7d11
10 changed files with 140 additions and 50 deletions
+4
View File
@@ -247,6 +247,7 @@ _V26_DDL = [
physical_qty NUMERIC(18,6),
transfer_pair_id UUID,
performed_by TEXT,
delivered_to TEXT,
transaction_date TIMESTAMPTZ NOT NULL DEFAULT now(),
note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
@@ -258,6 +259,9 @@ _V26_DDL = [
"""
CREATE INDEX IF NOT EXISTS idx_inventory_tx_warehouse_date ON inventory_transactions (warehouse_id, transaction_date)
""",
"""
ALTER TABLE inventory_transactions ADD COLUMN IF NOT EXISTS delivered_to TEXT
""",
# suppliers.categories JSONB (v2.4 runtime) is replaced by suppliers.category_id — drop it.
"""
ALTER TABLE suppliers DROP COLUMN IF EXISTS categories
+1
View File
@@ -156,6 +156,7 @@ class InventoryTransaction(Base):
# NULL for a standalone entry; links TRANSFER_OUT to its TRANSFER_IN row.
transfer_pair_id: Mapped[uuid.UUID | None] = mapped_column(Uuid(as_uuid=True))
performed_by: Mapped[str | None] = mapped_column(Text) # user display name (dev placeholder)
delivered_to: Mapped[str | None] = mapped_column(Text)
transaction_date: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)
+1
View File
@@ -197,6 +197,7 @@ def transaction_to_dict(tx: InventoryTransaction, wh: Warehouse | None = None) -
"physical_qty": float(tx.physical_qty) if tx.physical_qty is not None else None,
"transfer_pair_id": str(tx.transfer_pair_id) if tx.transfer_pair_id else None,
"performed_by": tx.performed_by,
"delivered_to": tx.delivered_to,
"transaction_date": to_iso(tx.transaction_date),
"note": tx.note,
}
+1
View File
@@ -64,6 +64,7 @@ class InventoryTransactionCreate(APIModel):
unit_id: int | None = None
specs: dict | None = None
note: str | None = None
delivered_to: str | None = None
transaction_date: datetime | None = None
@model_validator(mode="after")
@@ -290,6 +290,7 @@ async def apply_transaction(
transaction_type=t,
quantity=quantity,
performed_by=performed_by,
delivered_to=payload.delivered_to,
transaction_date=payload.transaction_date,
note=payload.note,
)
@@ -319,6 +320,7 @@ async def apply_transaction(
transaction_type=t,
quantity=-quantity,
performed_by=performed_by,
delivered_to=payload.delivered_to,
transaction_date=payload.transaction_date,
note=payload.note,
)