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:
@@ -22,10 +22,12 @@ from app.services.letzshop import (
|
|||||||
LetzshopClientError,
|
LetzshopClientError,
|
||||||
LetzshopCredentialsService,
|
LetzshopCredentialsService,
|
||||||
LetzshopOrderService,
|
LetzshopOrderService,
|
||||||
|
OrderNotFoundError,
|
||||||
VendorNotFoundError,
|
VendorNotFoundError,
|
||||||
)
|
)
|
||||||
from models.database.user import User
|
from models.database.user import User
|
||||||
from models.schema.letzshop import (
|
from models.schema.letzshop import (
|
||||||
|
FulfillmentOperationResponse,
|
||||||
LetzshopConnectionTestRequest,
|
LetzshopConnectionTestRequest,
|
||||||
LetzshopConnectionTestResponse,
|
LetzshopConnectionTestResponse,
|
||||||
LetzshopCredentialsCreate,
|
LetzshopCredentialsCreate,
|
||||||
@@ -647,3 +649,246 @@ def get_import_summary(
|
|||||||
"success": True,
|
"success": True,
|
||||||
"summary": summary,
|
"summary": summary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Fulfillment Operations (Admin)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/vendors/{vendor_id}/orders/{order_id}/confirm",
|
||||||
|
response_model=FulfillmentOperationResponse,
|
||||||
|
)
|
||||||
|
def confirm_order(
|
||||||
|
vendor_id: int = Path(..., description="Vendor ID"),
|
||||||
|
order_id: int = Path(..., description="Order ID"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_admin: User = Depends(get_current_admin_api),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Confirm all inventory units for a Letzshop order.
|
||||||
|
|
||||||
|
Sends confirmInventoryUnits mutation with isAvailable=true for all items.
|
||||||
|
"""
|
||||||
|
order_service = get_order_service(db)
|
||||||
|
creds_service = get_credentials_service(db)
|
||||||
|
|
||||||
|
try:
|
||||||
|
order = order_service.get_order_or_raise(vendor_id, order_id)
|
||||||
|
except OrderNotFoundError:
|
||||||
|
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
|
||||||
|
|
||||||
|
# Get inventory unit IDs from order
|
||||||
|
if not order.inventory_units:
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="No inventory units found in order",
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_unit_ids = [u.get("id") for u in order.inventory_units if u.get("id")]
|
||||||
|
|
||||||
|
if not inventory_unit_ids:
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="No inventory unit IDs found in order",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with creds_service.create_client(vendor_id) as client:
|
||||||
|
result = client.confirm_inventory_units(inventory_unit_ids)
|
||||||
|
|
||||||
|
if not result.get("inventoryUnits"):
|
||||||
|
error_messages = [
|
||||||
|
e.get("message", "Unknown error")
|
||||||
|
for e in result.get("errors", [])
|
||||||
|
]
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="Some inventory units could not be confirmed",
|
||||||
|
errors=error_messages,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update order status
|
||||||
|
order_service.mark_order_confirmed(order)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=True,
|
||||||
|
message=f"Confirmed {len(inventory_unit_ids)} inventory units",
|
||||||
|
confirmed_units=[u.get("id") for u in result.get("inventoryUnits", [])],
|
||||||
|
)
|
||||||
|
|
||||||
|
except LetzshopClientError as e:
|
||||||
|
return FulfillmentOperationResponse(success=False, message=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/vendors/{vendor_id}/orders/{order_id}/reject",
|
||||||
|
response_model=FulfillmentOperationResponse,
|
||||||
|
)
|
||||||
|
def reject_order(
|
||||||
|
vendor_id: int = Path(..., description="Vendor ID"),
|
||||||
|
order_id: int = Path(..., description="Order ID"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_admin: User = Depends(get_current_admin_api),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Decline all inventory units for a Letzshop order.
|
||||||
|
|
||||||
|
Sends confirmInventoryUnits mutation with isAvailable=false for all items.
|
||||||
|
"""
|
||||||
|
order_service = get_order_service(db)
|
||||||
|
creds_service = get_credentials_service(db)
|
||||||
|
|
||||||
|
try:
|
||||||
|
order = order_service.get_order_or_raise(vendor_id, order_id)
|
||||||
|
except OrderNotFoundError:
|
||||||
|
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
|
||||||
|
|
||||||
|
# Get inventory unit IDs from order
|
||||||
|
if not order.inventory_units:
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="No inventory units found in order",
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_unit_ids = [u.get("id") for u in order.inventory_units if u.get("id")]
|
||||||
|
|
||||||
|
if not inventory_unit_ids:
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="No inventory unit IDs found in order",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with creds_service.create_client(vendor_id) as client:
|
||||||
|
result = client.reject_inventory_units(inventory_unit_ids)
|
||||||
|
|
||||||
|
if not result.get("inventoryUnits"):
|
||||||
|
error_messages = [
|
||||||
|
e.get("message", "Unknown error")
|
||||||
|
for e in result.get("errors", [])
|
||||||
|
]
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="Some inventory units could not be declined",
|
||||||
|
errors=error_messages,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update order status
|
||||||
|
order_service.mark_order_rejected(order)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=True,
|
||||||
|
message=f"Declined {len(inventory_unit_ids)} inventory units",
|
||||||
|
)
|
||||||
|
|
||||||
|
except LetzshopClientError as e:
|
||||||
|
return FulfillmentOperationResponse(success=False, message=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/vendors/{vendor_id}/orders/{order_id}/items/{item_id}/confirm",
|
||||||
|
response_model=FulfillmentOperationResponse,
|
||||||
|
)
|
||||||
|
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"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_admin: User = Depends(get_current_admin_api),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Confirm a single inventory unit in an order.
|
||||||
|
|
||||||
|
Sends confirmInventoryUnits mutation with isAvailable=true for one item.
|
||||||
|
"""
|
||||||
|
order_service = get_order_service(db)
|
||||||
|
creds_service = get_credentials_service(db)
|
||||||
|
|
||||||
|
try:
|
||||||
|
order = order_service.get_order_or_raise(vendor_id, order_id)
|
||||||
|
except OrderNotFoundError:
|
||||||
|
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with creds_service.create_client(vendor_id) as client:
|
||||||
|
result = client.confirm_inventory_units([item_id])
|
||||||
|
|
||||||
|
if not result.get("inventoryUnits"):
|
||||||
|
error_messages = [
|
||||||
|
e.get("message", "Unknown error")
|
||||||
|
for e in result.get("errors", [])
|
||||||
|
]
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="Failed to confirm item",
|
||||||
|
errors=error_messages,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update local inventory unit state
|
||||||
|
order_service.update_inventory_unit_state(order, item_id, "confirmed_available")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=True,
|
||||||
|
message="Item confirmed",
|
||||||
|
confirmed_units=[item_id],
|
||||||
|
)
|
||||||
|
|
||||||
|
except LetzshopClientError as e:
|
||||||
|
return FulfillmentOperationResponse(success=False, message=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/vendors/{vendor_id}/orders/{order_id}/items/{item_id}/decline",
|
||||||
|
response_model=FulfillmentOperationResponse,
|
||||||
|
)
|
||||||
|
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"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_admin: User = Depends(get_current_admin_api),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Decline a single inventory unit in an order.
|
||||||
|
|
||||||
|
Sends confirmInventoryUnits mutation with isAvailable=false for one item.
|
||||||
|
"""
|
||||||
|
order_service = get_order_service(db)
|
||||||
|
creds_service = get_credentials_service(db)
|
||||||
|
|
||||||
|
try:
|
||||||
|
order = order_service.get_order_or_raise(vendor_id, order_id)
|
||||||
|
except OrderNotFoundError:
|
||||||
|
raise ResourceNotFoundException("LetzshopOrder", str(order_id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with creds_service.create_client(vendor_id) as client:
|
||||||
|
result = client.reject_inventory_units([item_id])
|
||||||
|
|
||||||
|
if not result.get("inventoryUnits"):
|
||||||
|
error_messages = [
|
||||||
|
e.get("message", "Unknown error")
|
||||||
|
for e in result.get("errors", [])
|
||||||
|
]
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=False,
|
||||||
|
message="Failed to decline item",
|
||||||
|
errors=error_messages,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update local inventory unit state
|
||||||
|
order_service.update_inventory_unit_state(order, item_id, "confirmed_unavailable")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return FulfillmentOperationResponse(
|
||||||
|
success=True,
|
||||||
|
message="Item declined",
|
||||||
|
)
|
||||||
|
|
||||||
|
except LetzshopClientError as e:
|
||||||
|
return FulfillmentOperationResponse(success=False, message=str(e))
|
||||||
|
|||||||
@@ -403,6 +403,56 @@ class LetzshopOrderService:
|
|||||||
order.sync_status = "rejected"
|
order.sync_status = "rejected"
|
||||||
return order
|
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(
|
def set_order_tracking(
|
||||||
self,
|
self,
|
||||||
order: LetzshopOrder,
|
order: LetzshopOrder,
|
||||||
|
|||||||
@@ -274,7 +274,7 @@
|
|||||||
'bg-red-100 text-red-700': selectedOrder?.sync_status === 'rejected',
|
'bg-red-100 text-red-700': selectedOrder?.sync_status === 'rejected',
|
||||||
'bg-blue-100 text-blue-700': selectedOrder?.sync_status === 'shipped'
|
'bg-blue-100 text-blue-700': selectedOrder?.sync_status === 'shipped'
|
||||||
}"
|
}"
|
||||||
x-text="selectedOrder?.sync_status?.toUpperCase()"
|
x-text="selectedOrder?.sync_status === 'rejected' ? 'DECLINED' : selectedOrder?.sync_status?.toUpperCase()"
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -296,19 +296,79 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div x-show="selectedOrder?.inventory_units?.length > 0">
|
<div x-show="selectedOrder?.inventory_units?.length > 0">
|
||||||
<h4 class="font-medium text-gray-700 dark:text-gray-300 mb-2">Items</h4>
|
<h4 class="font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
|
Items
|
||||||
<template x-for="unit in selectedOrder?.inventory_units || []" :key="unit.id">
|
<span class="text-xs font-normal text-gray-500">
|
||||||
<div class="flex justify-between text-sm py-1 border-b border-gray-200 dark:border-gray-600 last:border-0">
|
(Each item must be confirmed or declined individually)
|
||||||
<span class="text-gray-600 dark:text-gray-400" x-text="unit.id"></span>
|
</span>
|
||||||
<span
|
</h4>
|
||||||
class="px-2 py-0.5 text-xs rounded-full"
|
<div class="space-y-2">
|
||||||
:class="unit.state === 'confirmed' ? 'bg-green-100 text-green-700' : 'bg-orange-100 text-orange-700'"
|
<template x-for="(unit, index) in selectedOrder?.inventory_units || []" :key="unit.id">
|
||||||
x-text="unit.state"
|
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
|
||||||
></span>
|
<div class="flex justify-between items-start">
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="font-medium text-gray-700 dark:text-gray-200 text-sm" x-text="unit.product_name || 'Unknown Product'"></p>
|
||||||
|
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1 space-y-0.5">
|
||||||
|
<p x-show="unit.ean">
|
||||||
|
<span class="font-medium">EAN:</span> <span x-text="unit.ean"></span>
|
||||||
|
<span x-show="unit.ean_type" class="text-gray-400" x-text="'(' + unit.ean_type + ')'"></span>
|
||||||
|
</p>
|
||||||
|
<p x-show="unit.sku"><span class="font-medium">SKU:</span> <span x-text="unit.sku"></span></p>
|
||||||
|
<p x-show="unit.mpn"><span class="font-medium">MPN:</span> <span x-text="unit.mpn"></span></p>
|
||||||
|
<p x-show="unit.price"><span class="font-medium">Price:</span> <span x-text="unit.price + ' EUR'"></span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 ml-4">
|
||||||
|
<!-- Item State Badge -->
|
||||||
|
<span
|
||||||
|
class="px-2 py-0.5 text-xs rounded-full whitespace-nowrap"
|
||||||
|
:class="{
|
||||||
|
'bg-orange-100 text-orange-700': unit.state === 'unconfirmed',
|
||||||
|
'bg-green-100 text-green-700': unit.state === 'confirmed_available' || unit.state === 'confirmed',
|
||||||
|
'bg-red-100 text-red-700': unit.state === 'confirmed_unavailable',
|
||||||
|
'bg-gray-100 text-gray-700': unit.state === 'returned'
|
||||||
|
}"
|
||||||
|
x-text="unit.state === 'confirmed_unavailable' ? 'DECLINED' : (unit.state === 'confirmed_available' ? 'CONFIRMED' : unit.state?.toUpperCase())"
|
||||||
|
></span>
|
||||||
|
<!-- Item Actions (only for unconfirmed items) -->
|
||||||
|
<template x-if="unit.state === 'unconfirmed' && selectedOrder?.sync_status === 'pending'">
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<button
|
||||||
|
@click="confirmInventoryUnit(selectedOrder, unit, index)"
|
||||||
|
class="p-1 text-green-600 hover:bg-green-100 rounded"
|
||||||
|
title="Confirm this item"
|
||||||
|
>
|
||||||
|
<span x-html="$icon('check', 'w-4 h-4')"></span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="declineInventoryUnit(selectedOrder, unit, index)"
|
||||||
|
class="p-1 text-red-600 hover:bg-red-100 rounded"
|
||||||
|
title="Decline this item"
|
||||||
|
>
|
||||||
|
<span x-html="$icon('x', 'w-4 h-4')"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Bulk Actions -->
|
||||||
|
<div x-show="selectedOrder?.sync_status === 'pending'" class="mt-4 flex gap-2 justify-end">
|
||||||
|
<button
|
||||||
|
@click="confirmAllItems(selectedOrder)"
|
||||||
|
class="px-3 py-1.5 text-sm text-white bg-green-600 hover:bg-green-700 rounded-lg"
|
||||||
|
>
|
||||||
|
Confirm All Items
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="declineAllItems(selectedOrder)"
|
||||||
|
class="px-3 py-1.5 text-sm text-white bg-red-600 hover:bg-red-700 rounded-lg"
|
||||||
|
>
|
||||||
|
Decline All Items
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -579,6 +579,90 @@ function adminMarketplaceLetzshop() {
|
|||||||
this.showOrderModal = true;
|
this.showOrderModal = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm a single inventory unit
|
||||||
|
*/
|
||||||
|
async confirmInventoryUnit(order, unit, index) {
|
||||||
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/items/${unit.id}/confirm`
|
||||||
|
);
|
||||||
|
// Update local state
|
||||||
|
this.selectedOrder.inventory_units[index].state = 'confirmed_available';
|
||||||
|
this.successMessage = 'Item confirmed';
|
||||||
|
// Reload orders to get updated status
|
||||||
|
await this.loadOrders();
|
||||||
|
} catch (error) {
|
||||||
|
marketplaceLetzshopLog.error('Failed to confirm item:', error);
|
||||||
|
this.error = error.message || 'Failed to confirm item';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decline a single inventory unit
|
||||||
|
*/
|
||||||
|
async declineInventoryUnit(order, unit, index) {
|
||||||
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/items/${unit.id}/decline`
|
||||||
|
);
|
||||||
|
// Update local state
|
||||||
|
this.selectedOrder.inventory_units[index].state = 'confirmed_unavailable';
|
||||||
|
this.successMessage = 'Item declined';
|
||||||
|
// Reload orders to get updated status
|
||||||
|
await this.loadOrders();
|
||||||
|
} catch (error) {
|
||||||
|
marketplaceLetzshopLog.error('Failed to decline item:', error);
|
||||||
|
this.error = error.message || 'Failed to decline item';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm all items in an order
|
||||||
|
*/
|
||||||
|
async confirmAllItems(order) {
|
||||||
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
|
if (!confirm('Are you sure you want to confirm all items in this order?')) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/confirm`
|
||||||
|
);
|
||||||
|
this.successMessage = 'All items confirmed';
|
||||||
|
this.showOrderModal = false;
|
||||||
|
await this.loadOrders();
|
||||||
|
} catch (error) {
|
||||||
|
marketplaceLetzshopLog.error('Failed to confirm all items:', error);
|
||||||
|
this.error = error.message || 'Failed to confirm all items';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decline all items in an order
|
||||||
|
*/
|
||||||
|
async declineAllItems(order) {
|
||||||
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
|
if (!confirm('Are you sure you want to decline all items in this order?')) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/reject`
|
||||||
|
);
|
||||||
|
this.successMessage = 'All items declined';
|
||||||
|
this.showOrderModal = false;
|
||||||
|
await this.loadOrders();
|
||||||
|
} catch (error) {
|
||||||
|
marketplaceLetzshopLog.error('Failed to decline all items:', error);
|
||||||
|
this.error = error.message || 'Failed to decline all items';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
// SETTINGS TAB
|
// SETTINGS TAB
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
|
|||||||
Reference in New Issue
Block a user