|
|
|
@@ -193,12 +193,16 @@ async def save_orders_batch(orders_data: list[dict]):
|
|
|
|
VALUES (?, ?, ?)
|
|
|
|
VALUES (?, ?, ?)
|
|
|
|
""", [(d["sync_run_id"], d["order_number"], d["status_at_run"]) for d in orders_data])
|
|
|
|
""", [(d["sync_run_id"], d["order_number"], d["status_at_run"]) for d in orders_data])
|
|
|
|
|
|
|
|
|
|
|
|
# 3. Order items — replace semantics (GoMag source of truth)
|
|
|
|
# 3. Order items — replace semantics (GoMag source of truth).
|
|
|
|
|
|
|
|
# Dedup per-order by SKU (GoMag sometimes returns same SKU twice).
|
|
|
|
all_items = []
|
|
|
|
all_items = []
|
|
|
|
order_numbers_with_items = set()
|
|
|
|
order_numbers_with_items = set()
|
|
|
|
for d in orders_data:
|
|
|
|
for d in orders_data:
|
|
|
|
for item in d.get("items", []):
|
|
|
|
raw_items = d.get("items", [])
|
|
|
|
order_numbers_with_items.add(d["order_number"])
|
|
|
|
if not raw_items:
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
order_numbers_with_items.add(d["order_number"])
|
|
|
|
|
|
|
|
for item in _dedup_items_by_sku(raw_items):
|
|
|
|
all_items.append((
|
|
|
|
all_items.append((
|
|
|
|
d["order_number"],
|
|
|
|
d["order_number"],
|
|
|
|
item.get("sku"), item.get("product_name"),
|
|
|
|
item.get("sku"), item.get("product_name"),
|
|
|
|
@@ -535,14 +539,40 @@ async def get_web_products_batch(skus: list) -> dict:
|
|
|
|
|
|
|
|
|
|
|
|
# ── order_items ──────────────────────────────────
|
|
|
|
# ── order_items ──────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _dedup_items_by_sku(items: list) -> list:
|
|
|
|
|
|
|
|
"""Deduplicate items by SKU within a single order. Sums quantities on collision.
|
|
|
|
|
|
|
|
GoMag occasionally returns the same SKU on multiple lines (configurable products,
|
|
|
|
|
|
|
|
promo splits). The order_items primary key is (order_number, sku) so the raw rows
|
|
|
|
|
|
|
|
would violate UNIQUE. Keeps first price/vat/name; sums quantity + baseprice*qty.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not items:
|
|
|
|
|
|
|
|
return items
|
|
|
|
|
|
|
|
merged: dict = {}
|
|
|
|
|
|
|
|
order: list = []
|
|
|
|
|
|
|
|
for item in items:
|
|
|
|
|
|
|
|
sku = item.get("sku")
|
|
|
|
|
|
|
|
if sku is None:
|
|
|
|
|
|
|
|
order.append(item)
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
if sku in merged:
|
|
|
|
|
|
|
|
prev = merged[sku]
|
|
|
|
|
|
|
|
prev["quantity"] = (prev.get("quantity") or 0) + (item.get("quantity") or 0)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
merged[sku] = dict(item)
|
|
|
|
|
|
|
|
order.append(merged[sku])
|
|
|
|
|
|
|
|
return order
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def add_order_items(order_number: str, items: list):
|
|
|
|
async def add_order_items(order_number: str, items: list):
|
|
|
|
"""Replace order items — delete any existing rows, then insert fresh batch.
|
|
|
|
"""Replace order items — delete any existing rows, then insert fresh batch.
|
|
|
|
|
|
|
|
|
|
|
|
GoMag is source of truth: re-import must reflect quantity changes.
|
|
|
|
GoMag is source of truth: re-import must reflect quantity changes.
|
|
|
|
Atomic (DELETE + INSERT in one transaction).
|
|
|
|
Atomic (DELETE + INSERT in one transaction). Items with the same SKU are
|
|
|
|
|
|
|
|
merged (quantities summed) to satisfy the (order_number, sku) PK.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if not items:
|
|
|
|
if not items:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
items = _dedup_items_by_sku(items)
|
|
|
|
db = await get_sqlite()
|
|
|
|
db = await get_sqlite()
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
await db.execute("DELETE FROM order_items WHERE order_number = ?", (order_number,))
|
|
|
|
await db.execute("DELETE FROM order_items WHERE order_number = ?", (order_number,))
|
|
|
|
|