wip: update frontend templates for Letzshop order management
- Add Letzshop order detail page template - Update orders list template - Update Letzshop orders tab with improved UI - Add JavaScript for order confirmation flow Note: Frontend needs alignment with new unified order schema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,8 +35,11 @@ function adminMarketplaceLetzshop() {
|
||||
testingConnection: false,
|
||||
submittingTracking: false,
|
||||
|
||||
// Historical import result
|
||||
// Historical import state
|
||||
historicalImportResult: null,
|
||||
historicalImportJobId: null,
|
||||
historicalImportProgress: null,
|
||||
historicalImportPollInterval: null,
|
||||
|
||||
// Messages
|
||||
error: '',
|
||||
@@ -87,7 +90,9 @@ function adminMarketplaceLetzshop() {
|
||||
ordersPage: 1,
|
||||
ordersLimit: 20,
|
||||
ordersFilter: '',
|
||||
orderStats: { pending: 0, confirmed: 0, rejected: 0, shipped: 0 },
|
||||
ordersSearch: '',
|
||||
ordersHasDeclinedItems: false,
|
||||
orderStats: { pending: 0, confirmed: 0, rejected: 0, shipped: 0, has_declined_items: 0 },
|
||||
|
||||
// Jobs
|
||||
jobs: [],
|
||||
@@ -226,6 +231,9 @@ function adminMarketplaceLetzshop() {
|
||||
this.letzshopStatus = { is_configured: false };
|
||||
this.credentials = null;
|
||||
this.orders = [];
|
||||
this.ordersFilter = '';
|
||||
this.ordersSearch = '';
|
||||
this.ordersHasDeclinedItems = false;
|
||||
this.jobs = [];
|
||||
this.settingsForm = {
|
||||
api_key: '',
|
||||
@@ -394,6 +402,14 @@ function adminMarketplaceLetzshop() {
|
||||
params.append('sync_status', this.ordersFilter);
|
||||
}
|
||||
|
||||
if (this.ordersHasDeclinedItems) {
|
||||
params.append('has_declined_items', 'true');
|
||||
}
|
||||
|
||||
if (this.ordersSearch) {
|
||||
params.append('search', this.ordersSearch);
|
||||
}
|
||||
|
||||
const response = await apiClient.get(`/admin/letzshop/vendors/${this.selectedVendor.id}/orders?${params}`);
|
||||
this.orders = response.orders || [];
|
||||
this.totalOrders = response.total || 0;
|
||||
@@ -421,7 +437,7 @@ function adminMarketplaceLetzshop() {
|
||||
*/
|
||||
updateOrderStats() {
|
||||
// Reset stats
|
||||
this.orderStats = { pending: 0, confirmed: 0, rejected: 0, shipped: 0 };
|
||||
this.orderStats = { pending: 0, confirmed: 0, rejected: 0, shipped: 0, has_declined_items: 0 };
|
||||
|
||||
// Count from orders list (only visible page - not accurate for totals)
|
||||
for (const order of this.orders) {
|
||||
@@ -455,6 +471,7 @@ function adminMarketplaceLetzshop() {
|
||||
|
||||
/**
|
||||
* Import historical orders from Letzshop (confirmed and declined orders)
|
||||
* Uses background job with polling for progress tracking
|
||||
*/
|
||||
async importHistoricalOrders() {
|
||||
if (!this.selectedVendor || !this.letzshopStatus.is_configured) return;
|
||||
@@ -463,44 +480,154 @@ function adminMarketplaceLetzshop() {
|
||||
this.error = '';
|
||||
this.successMessage = '';
|
||||
this.historicalImportResult = null;
|
||||
this.historicalImportProgress = {
|
||||
status: 'starting',
|
||||
message: 'Starting historical import...',
|
||||
current_phase: null,
|
||||
current_page: 0,
|
||||
shipments_fetched: 0,
|
||||
orders_processed: 0,
|
||||
};
|
||||
|
||||
try {
|
||||
// Import confirmed orders
|
||||
const confirmedResponse = await apiClient.post(
|
||||
`/admin/letzshop/vendors/${this.selectedVendor.id}/import-history?state=confirmed`
|
||||
// Start the import job
|
||||
const response = await apiClient.post(
|
||||
`/admin/letzshop/vendors/${this.selectedVendor.id}/import-history`
|
||||
);
|
||||
const confirmedStats = confirmedResponse.statistics || confirmedResponse;
|
||||
|
||||
// Import declined (rejected) orders
|
||||
const declinedResponse = await apiClient.post(
|
||||
`/admin/letzshop/vendors/${this.selectedVendor.id}/import-history?state=declined`
|
||||
);
|
||||
const declinedStats = declinedResponse.statistics || declinedResponse;
|
||||
this.historicalImportJobId = response.job_id;
|
||||
marketplaceLetzshopLog.info('Historical import job started:', response);
|
||||
|
||||
// Combine stats
|
||||
this.historicalImportResult = {
|
||||
imported: (confirmedStats.imported || 0) + (declinedStats.imported || 0),
|
||||
updated: (confirmedStats.updated || 0) + (declinedStats.updated || 0),
|
||||
skipped: (confirmedStats.skipped || 0) + (declinedStats.skipped || 0),
|
||||
products_matched: (confirmedStats.products_matched || 0) + (declinedStats.products_matched || 0),
|
||||
products_not_found: (confirmedStats.products_not_found || 0) + (declinedStats.products_not_found || 0),
|
||||
};
|
||||
const stats = this.historicalImportResult;
|
||||
this.successMessage = `Historical import complete: ${stats.imported} imported, ${stats.updated} updated`;
|
||||
// Start polling for progress
|
||||
this.startHistoricalImportPolling();
|
||||
|
||||
marketplaceLetzshopLog.info('Historical import result (confirmed):', confirmedResponse);
|
||||
marketplaceLetzshopLog.info('Historical import result (declined):', declinedResponse);
|
||||
|
||||
// Reload orders to show new data
|
||||
await this.loadOrders();
|
||||
} catch (error) {
|
||||
marketplaceLetzshopLog.error('Failed to import historical orders:', error);
|
||||
this.error = error.message || 'Failed to import historical orders';
|
||||
} finally {
|
||||
marketplaceLetzshopLog.error('Failed to start historical import:', error);
|
||||
this.error = error.message || 'Failed to start historical import';
|
||||
this.importingHistorical = false;
|
||||
this.historicalImportProgress = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Start polling for historical import progress
|
||||
*/
|
||||
startHistoricalImportPolling() {
|
||||
// Poll every 2 seconds
|
||||
this.historicalImportPollInterval = setInterval(async () => {
|
||||
await this.pollHistoricalImportStatus();
|
||||
}, 2000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Poll historical import status
|
||||
*/
|
||||
async pollHistoricalImportStatus() {
|
||||
if (!this.historicalImportJobId || !this.selectedVendor) {
|
||||
this.stopHistoricalImportPolling();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const status = await apiClient.get(
|
||||
`/admin/letzshop/vendors/${this.selectedVendor.id}/import-history/${this.historicalImportJobId}/status`
|
||||
);
|
||||
|
||||
// Update progress display
|
||||
this.historicalImportProgress = {
|
||||
status: status.status,
|
||||
message: this.formatProgressMessage(status),
|
||||
current_phase: status.current_phase,
|
||||
current_page: status.current_page,
|
||||
total_pages: status.total_pages,
|
||||
shipments_fetched: status.shipments_fetched,
|
||||
orders_processed: status.orders_processed,
|
||||
};
|
||||
|
||||
// Check if complete or failed
|
||||
if (status.status === 'completed' || status.status === 'failed') {
|
||||
this.stopHistoricalImportPolling();
|
||||
this.importingHistorical = false;
|
||||
|
||||
if (status.status === 'completed') {
|
||||
// Combine stats from both phases
|
||||
const confirmed = status.confirmed_stats || {};
|
||||
const pending = status.declined_stats || {}; // Actually unconfirmed/pending
|
||||
|
||||
this.historicalImportResult = {
|
||||
imported: (confirmed.imported || 0) + (pending.imported || 0),
|
||||
updated: (confirmed.updated || 0) + (pending.updated || 0),
|
||||
skipped: (confirmed.skipped || 0) + (pending.skipped || 0),
|
||||
products_matched: (confirmed.products_matched || 0) + (pending.products_matched || 0),
|
||||
products_not_found: (confirmed.products_not_found || 0) + (pending.products_not_found || 0),
|
||||
};
|
||||
const stats = this.historicalImportResult;
|
||||
|
||||
// Build a meaningful summary message
|
||||
const parts = [];
|
||||
if (stats.imported > 0) parts.push(`${stats.imported} imported`);
|
||||
if (stats.updated > 0) parts.push(`${stats.updated} updated`);
|
||||
if (stats.skipped > 0) parts.push(`${stats.skipped} already synced`);
|
||||
|
||||
this.successMessage = parts.length > 0
|
||||
? `Historical import complete: ${parts.join(', ')}`
|
||||
: 'Historical import complete: no orders found';
|
||||
marketplaceLetzshopLog.info('Historical import completed:', status);
|
||||
|
||||
// Reload orders to show new data
|
||||
await this.loadOrders();
|
||||
} else {
|
||||
this.error = status.error_message || 'Historical import failed';
|
||||
marketplaceLetzshopLog.error('Historical import failed:', status);
|
||||
}
|
||||
|
||||
this.historicalImportProgress = null;
|
||||
this.historicalImportJobId = null;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
marketplaceLetzshopLog.error('Failed to poll import status:', error);
|
||||
// Don't stop polling on transient errors
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop polling for historical import progress
|
||||
*/
|
||||
stopHistoricalImportPolling() {
|
||||
if (this.historicalImportPollInterval) {
|
||||
clearInterval(this.historicalImportPollInterval);
|
||||
this.historicalImportPollInterval = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Format progress message for display
|
||||
*/
|
||||
formatProgressMessage(status) {
|
||||
// Map phase to display name
|
||||
const phaseNames = {
|
||||
'confirmed': 'confirmed',
|
||||
'unconfirmed': 'pending',
|
||||
'declined': 'declined', // Legacy support
|
||||
};
|
||||
const phase = phaseNames[status.current_phase] || status.current_phase || 'orders';
|
||||
|
||||
if (status.status === 'fetching') {
|
||||
if (status.total_pages) {
|
||||
return `Fetching ${phase} orders: page ${status.current_page} of ${status.total_pages} (${status.shipments_fetched} fetched)`;
|
||||
}
|
||||
return `Fetching ${phase} orders: page ${status.current_page}... (${status.shipments_fetched} fetched)`;
|
||||
}
|
||||
if (status.status === 'processing') {
|
||||
return `Processing ${phase} orders: ${status.orders_processed} processed...`;
|
||||
}
|
||||
if (status.status === 'pending') {
|
||||
return 'Starting historical import...';
|
||||
}
|
||||
return status.status.charAt(0).toUpperCase() + status.status.slice(1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm an order
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user