Files
reseller-platform/backend/app/engines/inventory.py

73 lines
2.7 KiB
Python

"""Inventory sync engine.
Refreshes supplier_products inventory from each adapter, writes inventory_history,
and flags zero/unavailable stock (pauses published products + audit log alert).
"""
from datetime import datetime, timezone
from app.engines.suppliers.base import build_adapter
from app.models import AuditLog, InventoryHistory, Supplier, SupplierProduct
def sync_inventory(db, supplier=None):
if supplier is not None:
suppliers = [supplier]
else:
suppliers = db.query(Supplier).filter(Supplier.status == "active").all()
stats = {"suppliers": len(suppliers), "checked": 0, "changed": 0, "zeroed": 0}
for s in suppliers:
try:
adapter = build_adapter(s)
current = {r["supplier_sku"]: int(r["inventory"]) for r in adapter.get_inventory()}
except Exception as exc: # noqa: BLE001 — log and continue to next supplier
db.add(
AuditLog(
actor="inventory",
action="sync_failed",
entity="supplier",
entity_id=str(s.id),
detail={"supplier": s.name, "error": str(exc)},
)
)
continue
for sp in db.query(SupplierProduct).filter(SupplierProduct.supplier_id == s.id).all():
stats["checked"] += 1
new_value = current.get(sp.supplier_sku)
if new_value is None:
continue
if sp.supplier_inventory != new_value:
stats["changed"] += 1
sp.supplier_inventory = new_value
sp.last_updated = datetime.now(timezone.utc)
db.add(InventoryHistory(supplier_product_id=sp.id, inventory=new_value))
if new_value <= 0:
stats["zeroed"] += 1
db.add(
AuditLog(
actor="inventory",
action="inventory_zero",
entity="supplier_product",
entity_id=str(sp.id),
detail={"supplier_sku": sp.supplier_sku, "inventory": 0},
)
)
if sp.product is not None and sp.product.status == "published":
sp.product.status = "paused"
db.add(
AuditLog(
actor="inventory",
action="product_paused_zero_inventory",
entity="product",
entity_id=str(sp.product.id),
detail={"sku": sp.product.sku},
)
)
db.commit()
return stats