feat: complete unified order model integration for Letzshop API

Update API endpoints and schemas to use the unified Order model:
- Update Letzshop order schemas with OrderItem support
- Update API responses to use new field names (external_*, status, etc.)
- Update confirm/reject endpoints to use OrderItem.external_item_id
- Update Letzshop order service for unified Order model queries
- Update documentation to reflect completed implementation

🤖 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-19 21:27:24 +01:00
parent 6a10fbba10
commit c49b80ce41
4 changed files with 530 additions and 533 deletions

View File

@@ -39,8 +39,10 @@ from models.schema.letzshop import (
LetzshopJobItem,
LetzshopJobsListResponse,
LetzshopOrderDetailResponse,
LetzshopOrderItemResponse,
LetzshopOrderListResponse,
LetzshopOrderResponse,
LetzshopOrderStats,
LetzshopSuccessResponse,
LetzshopSyncTriggerRequest,
LetzshopSyncTriggerResponse,
@@ -348,7 +350,7 @@ def list_vendor_letzshop_orders(
vendor_id: int = Path(..., description="Vendor ID"),
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=200),
sync_status: str | None = Query(None, description="Filter by sync status"),
status: str | None = Query(None, description="Filter by order status"),
has_declined_items: bool | None = Query(
None, description="Filter orders with declined/unavailable items"
),
@@ -370,7 +372,7 @@ def list_vendor_letzshop_orders(
vendor_id=vendor_id,
skip=skip,
limit=limit,
sync_status=sync_status,
status=status,
has_declined_items=has_declined_items,
search=search,
)
@@ -383,37 +385,50 @@ def list_vendor_letzshop_orders(
LetzshopOrderResponse(
id=order.id,
vendor_id=order.vendor_id,
letzshop_order_id=order.letzshop_order_id,
letzshop_shipment_id=order.letzshop_shipment_id,
letzshop_order_number=order.letzshop_order_number,
letzshop_state=order.letzshop_state,
order_number=order.order_number,
external_order_id=order.external_order_id,
external_shipment_id=order.external_shipment_id,
external_order_number=order.external_order_number,
status=order.status,
customer_email=order.customer_email,
customer_name=order.customer_name,
customer_name=order.customer_full_name,
customer_locale=order.customer_locale,
shipping_country_iso=order.shipping_country_iso,
billing_country_iso=order.billing_country_iso,
ship_country_iso=order.ship_country_iso,
bill_country_iso=order.bill_country_iso,
total_amount=order.total_amount,
currency=order.currency,
local_order_id=order.local_order_id,
sync_status=order.sync_status,
last_synced_at=order.last_synced_at,
sync_error=order.sync_error,
confirmed_at=order.confirmed_at,
rejected_at=order.rejected_at,
tracking_set_at=order.tracking_set_at,
tracking_number=order.tracking_number,
tracking_carrier=order.tracking_carrier,
inventory_units=order.inventory_units,
tracking_provider=order.tracking_provider,
order_date=order.order_date,
confirmed_at=order.confirmed_at,
shipped_at=order.shipped_at,
cancelled_at=order.cancelled_at,
created_at=order.created_at,
updated_at=order.updated_at,
items=[
LetzshopOrderItemResponse(
id=item.id,
product_id=item.product_id,
product_name=item.product_name,
product_sku=item.product_sku,
gtin=item.gtin,
gtin_type=item.gtin_type,
quantity=item.quantity,
unit_price=item.unit_price,
total_price=item.total_price,
external_item_id=item.external_item_id,
external_variant_id=item.external_variant_id,
item_state=item.item_state,
)
for item in order.items
],
)
for order in orders
],
total=total,
skip=skip,
limit=limit,
stats=stats,
stats=LetzshopOrderStats(**stats),
)
@@ -436,31 +451,63 @@ def get_letzshop_order_detail(
return LetzshopOrderDetailResponse(
id=order.id,
vendor_id=order.vendor_id,
letzshop_order_id=order.letzshop_order_id,
letzshop_shipment_id=order.letzshop_shipment_id,
letzshop_order_number=order.letzshop_order_number,
letzshop_state=order.letzshop_state,
order_number=order.order_number,
external_order_id=order.external_order_id,
external_shipment_id=order.external_shipment_id,
external_order_number=order.external_order_number,
status=order.status,
customer_email=order.customer_email,
customer_name=order.customer_name,
customer_name=order.customer_full_name,
customer_locale=order.customer_locale,
shipping_country_iso=order.shipping_country_iso,
billing_country_iso=order.billing_country_iso,
customer_first_name=order.customer_first_name,
customer_last_name=order.customer_last_name,
customer_phone=order.customer_phone,
ship_country_iso=order.ship_country_iso,
ship_first_name=order.ship_first_name,
ship_last_name=order.ship_last_name,
ship_company=order.ship_company,
ship_address_line_1=order.ship_address_line_1,
ship_address_line_2=order.ship_address_line_2,
ship_city=order.ship_city,
ship_postal_code=order.ship_postal_code,
bill_country_iso=order.bill_country_iso,
bill_first_name=order.bill_first_name,
bill_last_name=order.bill_last_name,
bill_company=order.bill_company,
bill_address_line_1=order.bill_address_line_1,
bill_address_line_2=order.bill_address_line_2,
bill_city=order.bill_city,
bill_postal_code=order.bill_postal_code,
total_amount=order.total_amount,
currency=order.currency,
local_order_id=order.local_order_id,
sync_status=order.sync_status,
last_synced_at=order.last_synced_at,
sync_error=order.sync_error,
confirmed_at=order.confirmed_at,
rejected_at=order.rejected_at,
tracking_set_at=order.tracking_set_at,
tracking_number=order.tracking_number,
tracking_carrier=order.tracking_carrier,
inventory_units=order.inventory_units,
tracking_provider=order.tracking_provider,
order_date=order.order_date,
confirmed_at=order.confirmed_at,
shipped_at=order.shipped_at,
cancelled_at=order.cancelled_at,
created_at=order.created_at,
updated_at=order.updated_at,
raw_order_data=order.raw_order_data,
external_data=order.external_data,
customer_notes=order.customer_notes,
internal_notes=order.internal_notes,
items=[
LetzshopOrderItemResponse(
id=item.id,
product_id=item.product_id,
product_name=item.product_name,
product_sku=item.product_sku,
gtin=item.gtin,
gtin_type=item.gtin_type,
quantity=item.quantity,
unit_price=item.unit_price,
total_price=item.total_price,
external_item_id=item.external_item_id,
external_variant_id=item.external_variant_id,
item_state=item.item_state,
)
for item in order.items
],
)
@@ -743,21 +790,24 @@ def confirm_order(
try:
order = order_service.get_order_or_raise(vendor_id, order_id)
except OrderNotFoundError:
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
raise ResourceNotFoundException("Order", str(order_id))
# Get inventory unit IDs from order
if not order.inventory_units:
# Get inventory unit IDs from order items
items = order_service.get_order_items(order)
if not items:
return FulfillmentOperationResponse(
success=False,
message="No inventory units found in order",
message="No items found in order",
)
inventory_unit_ids = [u.get("id") for u in order.inventory_units if u.get("id")]
inventory_unit_ids = [
item.external_item_id for item in items if item.external_item_id
]
if not inventory_unit_ids:
return FulfillmentOperationResponse(
success=False,
message="No inventory unit IDs found in order",
message="No inventory unit IDs found in order items",
)
try:
@@ -775,7 +825,12 @@ def confirm_order(
errors=error_messages,
)
# Update order status
# Update order status and item states
for item in items:
if item.external_item_id:
order_service.update_inventory_unit_state(
order, item.external_item_id, "confirmed_available"
)
order_service.mark_order_confirmed(order)
db.commit()
@@ -810,21 +865,24 @@ def reject_order(
try:
order = order_service.get_order_or_raise(vendor_id, order_id)
except OrderNotFoundError:
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
raise ResourceNotFoundException("Order", str(order_id))
# Get inventory unit IDs from order
if not order.inventory_units:
# Get inventory unit IDs from order items
items = order_service.get_order_items(order)
if not items:
return FulfillmentOperationResponse(
success=False,
message="No inventory units found in order",
message="No items found in order",
)
inventory_unit_ids = [u.get("id") for u in order.inventory_units if u.get("id")]
inventory_unit_ids = [
item.external_item_id for item in items if item.external_item_id
]
if not inventory_unit_ids:
return FulfillmentOperationResponse(
success=False,
message="No inventory unit IDs found in order",
message="No inventory unit IDs found in order items",
)
try:
@@ -842,7 +900,12 @@ def reject_order(
errors=error_messages,
)
# Update order status
# Update item states and order status
for item in items:
if item.external_item_id:
order_service.update_inventory_unit_state(
order, item.external_item_id, "confirmed_unavailable"
)
order_service.mark_order_rejected(order)
db.commit()
@@ -862,7 +925,7 @@ def reject_order(
def confirm_single_item(
vendor_id: int = Path(..., description="Vendor ID"),
order_id: int = Path(..., description="Order ID"),
item_id: str = Path(..., description="Inventory Unit ID"),
item_id: str = Path(..., description="External Item ID (Letzshop inventory unit ID)"),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
@@ -877,7 +940,7 @@ def confirm_single_item(
try:
order = order_service.get_order_or_raise(vendor_id, order_id)
except OrderNotFoundError:
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
raise ResourceNotFoundException("Order", str(order_id))
try:
with creds_service.create_client(vendor_id) as client:
@@ -894,7 +957,7 @@ def confirm_single_item(
errors=error_messages,
)
# Update local inventory unit state
# Update local order item state
order_service.update_inventory_unit_state(order, item_id, "confirmed_available")
db.commit()
@@ -915,7 +978,7 @@ def confirm_single_item(
def decline_single_item(
vendor_id: int = Path(..., description="Vendor ID"),
order_id: int = Path(..., description="Order ID"),
item_id: str = Path(..., description="Inventory Unit ID"),
item_id: str = Path(..., description="External Item ID (Letzshop inventory unit ID)"),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_api),
):
@@ -930,7 +993,7 @@ def decline_single_item(
try:
order = order_service.get_order_or_raise(vendor_id, order_id)
except OrderNotFoundError:
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
raise ResourceNotFoundException("Order", str(order_id))
try:
with creds_service.create_client(vendor_id) as client:
@@ -947,7 +1010,7 @@ def decline_single_item(
errors=error_messages,
)
# Update local inventory unit state
# Update local order item state
order_service.update_inventory_unit_state(order, item_id, "confirmed_unavailable")
db.commit()