Add POI feature and imporve the overall backend implementation
This commit is contained in:
@@ -22,6 +22,13 @@ The **Inventory Service** is the operational backbone of Bakery-IA, managing ing
|
||||
- **Historical Analysis** - Analyze consumption patterns over time
|
||||
- **Waste Tracking** - Monitor and categorize waste (expired, damaged, etc.)
|
||||
|
||||
### Automatic Stock Updates from Deliveries (🆕)
|
||||
- **Event-Driven Stock Updates** - Automatically updates stock when deliveries are received from procurement
|
||||
- **Batch & Expiry Tracking** - Records batch/lot numbers and expiration dates from delivery receipts
|
||||
- **Audit Trail** - Creates complete stock entry records for each delivery
|
||||
- **Zero Manual Entry** - Eliminates manual stock entry after deliveries
|
||||
- **Real-Time Synchronization** - Stock levels update immediately when deliveries are recorded
|
||||
|
||||
### Food Safety Compliance (HACCP)
|
||||
- **Temperature Monitoring** - Critical control point temperature logs
|
||||
- **Food Safety Alerts** - Automated safety notifications
|
||||
@@ -336,7 +343,15 @@ CREATE TABLE food_safety_alerts (
|
||||
```
|
||||
|
||||
### Consumed Events
|
||||
- **From Procurement**: Stock received from suppliers
|
||||
|
||||
**From Procurement Service (🆕)**
|
||||
- **Delivery Received** (`delivery.received`) - Automatically updates stock levels when deliveries are recorded
|
||||
- Creates/updates Stock records for each inventory product
|
||||
- Creates StockEntry audit records with batch/lot numbers and expiry dates
|
||||
- Handles accepted quantities from delivery receipts
|
||||
- Links stock movements to delivery reference IDs for full traceability
|
||||
|
||||
**From Other Services**
|
||||
- **From Production**: Ingredient consumption in production
|
||||
- **From Sales**: Finished product sales (for inventory valuation)
|
||||
|
||||
@@ -467,13 +482,13 @@ pytest --cov=app tests/ --cov-report=html
|
||||
## Integration Points
|
||||
|
||||
### Dependencies
|
||||
- **Procurement Service** - Receive stock from purchase orders
|
||||
- **Procurement Service** - Receive stock from purchase orders via delivery events (🆕)
|
||||
- **Production Service** - Consume ingredients in production
|
||||
- **Forecasting Service** - Provide consumption data for forecasts
|
||||
- **Suppliers Service** - Supplier information for stock items
|
||||
- **PostgreSQL** - Inventory data storage
|
||||
- **Redis** - Dashboard KPI cache
|
||||
- **RabbitMQ** - Alert publishing
|
||||
- **RabbitMQ** - Alert publishing and delivery event consumption (🆕)
|
||||
|
||||
### Dependents
|
||||
- **Production Service** - Check ingredient availability
|
||||
@@ -482,6 +497,133 @@ pytest --cov=app tests/ --cov-report=html
|
||||
- **Frontend Dashboard** - Display inventory status
|
||||
- **Notification Service** - Send inventory alerts
|
||||
|
||||
## Delivery Event Processing (🆕)
|
||||
|
||||
### Automatic Stock Updates from Deliveries
|
||||
|
||||
The inventory service automatically updates stock levels when deliveries are recorded in the procurement service through event-driven architecture.
|
||||
|
||||
**How It Works:**
|
||||
1. User records delivery receipt in procurement service (frontend `DeliveryReceiptModal`)
|
||||
2. Procurement service publishes `delivery.received` event to RabbitMQ
|
||||
3. Inventory service's `DeliveryEventConsumer` listens for and processes the event
|
||||
4. For each delivered item:
|
||||
- Gets or creates Stock record for the inventory product
|
||||
- Updates `quantity_available` by adding accepted quantity
|
||||
- Creates StockEntry audit record with:
|
||||
- Transaction type: `RESTOCK`
|
||||
- Reference type: `DELIVERY`
|
||||
- Batch/lot number from delivery
|
||||
- Expiration date from delivery
|
||||
- Quantity change and new balance
|
||||
|
||||
**Benefits:**
|
||||
- **Zero Manual Entry** - Eliminates duplicate data entry in inventory after recording deliveries
|
||||
- **Real-Time Updates** - Stock levels update within seconds of delivery recording
|
||||
- **Complete Traceability** - Every stock change linked to source delivery
|
||||
- **Batch Tracking** - Automatic batch/lot number recording for food safety compliance
|
||||
- **Expiry Management** - Expiration dates automatically captured from delivery receipts
|
||||
|
||||
### Delivery Event Consumer Implementation
|
||||
|
||||
```python
|
||||
async def process_delivery_stock_update(self, event_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Process delivery event and update stock levels.
|
||||
|
||||
Listens to: procurement.events exchange, routing key: delivery.received
|
||||
Creates: Stock records and StockEntry audit records
|
||||
"""
|
||||
data = event_data.get('data', {})
|
||||
tenant_id = uuid.UUID(data.get('tenant_id'))
|
||||
delivery_id = uuid.UUID(data.get('delivery_id'))
|
||||
items = data.get('items', [])
|
||||
|
||||
async with database_manager.get_session() as session:
|
||||
stock_repo = StockRepository(session)
|
||||
entry_repo = StockEntryRepository(session)
|
||||
|
||||
for item in items:
|
||||
inventory_product_id = uuid.UUID(item.get('inventory_product_id'))
|
||||
accepted_quantity = Decimal(str(item.get('accepted_quantity', 0)))
|
||||
|
||||
if accepted_quantity <= 0:
|
||||
continue # Skip rejected items
|
||||
|
||||
# Get or create stock record
|
||||
stock = await stock_repo.get_stock_by_product(
|
||||
tenant_id=tenant_id,
|
||||
inventory_product_id=inventory_product_id
|
||||
)
|
||||
|
||||
if not stock:
|
||||
# Create new stock record
|
||||
stock = await stock_repo.create_stock({
|
||||
'tenant_id': tenant_id,
|
||||
'inventory_product_id': inventory_product_id,
|
||||
'quantity_available': Decimal('0'),
|
||||
# ... other fields
|
||||
})
|
||||
|
||||
# Update stock quantity
|
||||
new_quantity = stock.quantity_available + accepted_quantity
|
||||
await stock_repo.update_stock(
|
||||
stock_id=stock.id,
|
||||
tenant_id=tenant_id,
|
||||
update_data={
|
||||
'quantity_available': new_quantity,
|
||||
'last_restocked_at': datetime.now(timezone.utc)
|
||||
}
|
||||
)
|
||||
|
||||
# Create stock entry for audit trail
|
||||
entry = await entry_repo.create_entry({
|
||||
'tenant_id': tenant_id,
|
||||
'stock_id': stock.id,
|
||||
'transaction_type': 'RESTOCK',
|
||||
'quantity_change': accepted_quantity,
|
||||
'quantity_after': new_quantity,
|
||||
'reference_type': 'DELIVERY',
|
||||
'reference_id': delivery_id,
|
||||
'batch_number': item.get('batch_lot_number'),
|
||||
'expiry_date': item.get('expiry_date'),
|
||||
'notes': f"Delivery received from PO. Batch: {item.get('batch_lot_number', 'N/A')}"
|
||||
})
|
||||
|
||||
await session.commit()
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
**Event Schema:**
|
||||
```json
|
||||
{
|
||||
"event_id": "uuid",
|
||||
"event_type": "delivery.received",
|
||||
"service_name": "procurement",
|
||||
"timestamp": "2025-11-12T10:30:00Z",
|
||||
"data": {
|
||||
"tenant_id": "uuid",
|
||||
"delivery_id": "uuid",
|
||||
"po_id": "uuid",
|
||||
"received_by": "uuid",
|
||||
"received_at": "2025-11-12T10:30:00Z",
|
||||
"items": [
|
||||
{
|
||||
"inventory_product_id": "uuid",
|
||||
"ordered_quantity": 100.0,
|
||||
"delivered_quantity": 98.0,
|
||||
"accepted_quantity": 95.0,
|
||||
"rejected_quantity": 3.0,
|
||||
"batch_lot_number": "LOT-2025-1112",
|
||||
"expiry_date": "2025-12-12",
|
||||
"rejection_reason": "3 damaged units"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## FIFO Implementation
|
||||
|
||||
### FIFO Consumption Logic
|
||||
|
||||
Reference in New Issue
Block a user