Procurement - Celery Tasks
Location: api/nextango/apps/procurement/tasks.py
Last Updated: 2026-07-09
Overview
Background tasks for the procurement domain. Currently one periodic task runs daily to scan all active inventory levels and surface items that have fallen at or below their configured reorder points, logging warnings to alert operations staff before a stockout occurs.
Task Summary
| Task | Schedule | Purpose | Key Service Call |
|---|---|---|---|
check_reorder_levels | Daily at 6 AM | Scan inventory for items at/below reorder point | InventoryLevel ORM query |
Task Reference
check_reorder_levels
Source: tasks.py:11-46
Schedule: Daily at 6:00 AM (configured in Celery beat schedule)
Purpose: Scans all active InventoryLevel records whose reorder_point > 0, stock_on_hand is at or below that reorder point, and whose product variant has custom_inventory_management enabled. For each matching item, emits a WARNING log containing the SKU, store name, current on-hand quantity, reorder point, and suggested order quantity. Items with reorder_point=0 are skipped (threshold not configured), as are variants without custom inventory management.
Signature:
@shared_task(name='procurement.check_reorder_levels')
def check_reorder_levels():
...
Returns:
{'needs_reorder': <int>} # Count of SKUs at or below reorder point
Retry Policy: None configured: if the task fails it will not retry automatically.
Why Daily:
- Reorder levels are a daily operational concern, not real-time
- Alerts are surfaced to warehouse staff at the start of the business day
- Receiving a PO updates inventory automatically:
stock_on_handandstock_lifetime_receivedincrement when line items are received (see Signals)
Celery Beat Configuration
from celery.schedules import crontab
CELERY_BEAT_SCHEDULE = {
'check-reorder-levels': {
'task': 'procurement.check_reorder_levels',
'schedule': crontab(hour=6, minute=0), # Daily at 6 AM
},
}
Manual Execution
from nextango.apps.procurement.tasks import check_reorder_levels
# Synchronous
result = check_reorder_levels()
print(f"{result['needs_reorder']} SKUs need reordering")
# Asynchronous
check_reorder_levels.delay()