feat: add item-level order confirmation/decline support

Per Letzshop API, each inventory unit must be confirmed/declined individually.
This enables partial confirmation (some items confirmed, others declined).

Admin API endpoints:
- POST /vendors/{id}/orders/{id}/confirm - confirm all items
- POST /vendors/{id}/orders/{id}/reject - decline all items
- POST /vendors/{id}/orders/{id}/items/{id}/confirm - confirm single item
- POST /vendors/{id}/orders/{id}/items/{id}/decline - decline single item

Order detail modal now shows:
- Product name, EAN, SKU, MPN, price per item
- Per-item state badge (unconfirmed/confirmed/declined)
- Per-item confirm/decline buttons for pending items
- Bulk confirm/decline all buttons

Order status logic:
- If all items declined -> order is "declined"
- If any item confirmed -> order is "confirmed"
- Partial confirmation supported

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-18 21:27:56 +01:00
parent 12018fc088
commit 3f1f6ad852
4 changed files with 450 additions and 11 deletions

View File

@@ -403,6 +403,56 @@ class LetzshopOrderService:
order.sync_status = "rejected"
return order
def update_inventory_unit_state(
self, order: LetzshopOrder, item_id: str, state: str
) -> LetzshopOrder:
"""
Update the state of a single inventory unit in an order.
Args:
order: The order containing the inventory unit.
item_id: The inventory unit ID to update.
state: The new state (confirmed_available, confirmed_unavailable).
Returns:
The updated order.
"""
if not order.inventory_units:
return order
# Update the specific item's state
updated_units = []
for unit in order.inventory_units:
if unit.get("id") == item_id:
unit["state"] = state
updated_units.append(unit)
order.inventory_units = updated_units
# Check if all items are now processed and update order status accordingly
all_confirmed = all(
u.get("state") in ("confirmed_available", "confirmed_unavailable", "returned")
for u in updated_units
)
if all_confirmed:
# Determine order status based on item states
has_available = any(
u.get("state") == "confirmed_available" for u in updated_units
)
all_unavailable = all(
u.get("state") == "confirmed_unavailable" for u in updated_units
)
if all_unavailable:
order.sync_status = "rejected"
order.rejected_at = datetime.now(UTC)
elif has_available:
order.sync_status = "confirmed"
order.confirmed_at = datetime.now(UTC)
return order
def set_order_tracking(
self,
order: LetzshopOrder,