// static/vendor/js/letzshop.js /** * Vendor Letzshop orders management page logic */ console.log('[VENDOR LETZSHOP] Loading...'); function vendorLetzshop() { console.log('[VENDOR LETZSHOP] vendorLetzshop() called'); return { // Inherit base layout state ...data(), // Set page identifier currentPage: 'letzshop', // Tab state activeTab: 'orders', // Loading states loading: false, importing: false, saving: false, testing: false, submittingTracking: false, // Messages error: '', successMessage: '', // Integration status status: { is_configured: false, is_connected: false, auto_sync_enabled: false, last_sync_at: null, last_sync_status: null }, // Credentials credentials: null, credentialsForm: { api_key: '', auto_sync_enabled: false, sync_interval_minutes: 15 }, showApiKey: false, // Orders orders: [], totalOrders: 0, page: 1, limit: 20, filters: { sync_status: '' }, // Order stats orderStats: { pending: 0, confirmed: 0, rejected: 0, shipped: 0 }, // Modals showTrackingModal: false, showOrderModal: false, selectedOrder: null, trackingForm: { tracking_number: '', tracking_carrier: '' }, // Export exportLanguage: 'fr', exportIncludeInactive: false, exporting: false, async init() { // Guard against multiple initialization if (window._vendorLetzshopInitialized) { return; } window._vendorLetzshopInitialized = true; // Call parent init first to set vendorCode from URL const parentInit = data().init; if (parentInit) { await parentInit.call(this); } await this.loadStatus(); await this.loadOrders(); }, /** * Load integration status */ async loadStatus() { try { const response = await apiClient.get('/vendor/letzshop/status'); this.status = response; if (this.status.is_configured) { await this.loadCredentials(); } } catch (error) { console.error('[VENDOR LETZSHOP] Failed to load status:', error); } }, /** * Load credentials (masked) */ async loadCredentials() { try { const response = await apiClient.get('/vendor/letzshop/credentials'); this.credentials = response; this.credentialsForm.auto_sync_enabled = response.auto_sync_enabled; this.credentialsForm.sync_interval_minutes = response.sync_interval_minutes; } catch (error) { // 404 means not configured, which is fine if (error.status !== 404) { console.error('[VENDOR LETZSHOP] Failed to load credentials:', error); } } }, /** * Load orders */ async loadOrders() { this.loading = true; this.error = ''; try { const params = new URLSearchParams({ skip: ((this.page - 1) * this.limit).toString(), limit: this.limit.toString() }); if (this.filters.sync_status) { params.append('sync_status', this.filters.sync_status); } const response = await apiClient.get(`/vendor/letzshop/orders?${params}`); this.orders = response.orders; this.totalOrders = response.total; // Calculate stats await this.loadOrderStats(); } catch (error) { console.error('[VENDOR LETZSHOP] Failed to load orders:', error); this.error = error.message || 'Failed to load orders'; } finally { this.loading = false; } }, /** * Load order stats by fetching counts for each status */ async loadOrderStats() { try { // Get all orders without filter to calculate stats const allResponse = await apiClient.get('/vendor/letzshop/orders?limit=1000'); const allOrders = allResponse.orders || []; this.orderStats = { pending: allOrders.filter(o => o.sync_status === 'pending').length, confirmed: allOrders.filter(o => o.sync_status === 'confirmed').length, rejected: allOrders.filter(o => o.sync_status === 'rejected').length, shipped: allOrders.filter(o => o.sync_status === 'shipped').length }; } catch (error) { console.error('[VENDOR LETZSHOP] Failed to load order stats:', error); } }, /** * Refresh all data */ async refreshData() { await this.loadStatus(); await this.loadOrders(); this.successMessage = 'Data refreshed'; setTimeout(() => this.successMessage = '', 3000); }, /** * Import orders from Letzshop */ async importOrders() { if (!this.status.is_configured) { this.error = 'Please configure your API key first'; this.activeTab = 'settings'; return; } this.importing = true; this.error = ''; try { const response = await apiClient.post('/vendor/letzshop/orders/import', { operation: 'order_import' }); if (response.success) { this.successMessage = response.message; await this.loadOrders(); } else { this.error = response.message || 'Import failed'; } } catch (error) { console.error('[VENDOR LETZSHOP] Import failed:', error); this.error = error.message || 'Failed to import orders'; } finally { this.importing = false; setTimeout(() => this.successMessage = '', 5000); } }, /** * Save credentials */ async saveCredentials() { if (!this.credentialsForm.api_key && !this.credentials) { this.error = 'Please enter an API key'; return; } this.saving = true; this.error = ''; try { const payload = { auto_sync_enabled: this.credentialsForm.auto_sync_enabled, sync_interval_minutes: parseInt(this.credentialsForm.sync_interval_minutes) }; if (this.credentialsForm.api_key) { payload.api_key = this.credentialsForm.api_key; } const response = await apiClient.post('/vendor/letzshop/credentials', payload); this.credentials = response; this.credentialsForm.api_key = ''; this.status.is_configured = true; this.successMessage = 'Credentials saved successfully'; } catch (error) { console.error('[VENDOR LETZSHOP] Failed to save credentials:', error); this.error = error.message || 'Failed to save credentials'; } finally { this.saving = false; setTimeout(() => this.successMessage = '', 5000); } }, /** * Test connection */ async testConnection() { this.testing = true; this.error = ''; try { const response = await apiClient.post('/vendor/letzshop/test'); if (response.success) { this.successMessage = `Connection successful (${response.response_time_ms?.toFixed(0)}ms)`; } else { this.error = response.error_details || 'Connection failed'; } } catch (error) { console.error('[VENDOR LETZSHOP] Connection test failed:', error); this.error = error.message || 'Connection test failed'; } finally { this.testing = false; setTimeout(() => this.successMessage = '', 5000); } }, /** * Delete credentials */ async deleteCredentials() { if (!confirm('Are you sure you want to remove your Letzshop credentials?')) { return; } try { await apiClient.delete('/vendor/letzshop/credentials'); this.credentials = null; this.status.is_configured = false; this.credentialsForm = { api_key: '', auto_sync_enabled: false, sync_interval_minutes: 15 }; this.successMessage = 'Credentials removed'; } catch (error) { console.error('[VENDOR LETZSHOP] Failed to delete credentials:', error); this.error = error.message || 'Failed to remove credentials'; } setTimeout(() => this.successMessage = '', 5000); }, /** * Confirm order */ async confirmOrder(order) { if (!confirm('Confirm this order?')) { return; } try { const response = await apiClient.post(`/vendor/letzshop/orders/${order.id}/confirm`); if (response.success) { this.successMessage = 'Order confirmed'; await this.loadOrders(); } else { this.error = response.message || 'Failed to confirm order'; } } catch (error) { console.error('[VENDOR LETZSHOP] Failed to confirm order:', error); this.error = error.message || 'Failed to confirm order'; } setTimeout(() => this.successMessage = '', 5000); }, /** * Reject order */ async rejectOrder(order) { if (!confirm('Reject this order? This action cannot be undone.')) { return; } try { const response = await apiClient.post(`/vendor/letzshop/orders/${order.id}/reject`); if (response.success) { this.successMessage = 'Order rejected'; await this.loadOrders(); } else { this.error = response.message || 'Failed to reject order'; } } catch (error) { console.error('[VENDOR LETZSHOP] Failed to reject order:', error); this.error = error.message || 'Failed to reject order'; } setTimeout(() => this.successMessage = '', 5000); }, /** * Open tracking modal */ openTrackingModal(order) { this.selectedOrder = order; this.trackingForm = { tracking_number: order.tracking_number || '', tracking_carrier: order.tracking_carrier || '' }; this.showTrackingModal = true; }, /** * Submit tracking */ async submitTracking() { if (!this.trackingForm.tracking_number || !this.trackingForm.tracking_carrier) { this.error = 'Please fill in all fields'; return; } this.submittingTracking = true; try { const response = await apiClient.post( `/vendor/letzshop/orders/${this.selectedOrder.id}/tracking`, this.trackingForm ); if (response.success) { this.showTrackingModal = false; this.successMessage = 'Tracking information saved'; await this.loadOrders(); } else { this.error = response.message || 'Failed to save tracking'; } } catch (error) { console.error('[VENDOR LETZSHOP] Failed to set tracking:', error); this.error = error.message || 'Failed to save tracking'; } finally { this.submittingTracking = false; } setTimeout(() => this.successMessage = '', 5000); }, /** * View order details */ viewOrderDetails(order) { this.selectedOrder = order; this.showOrderModal = true; }, /** * Format date for display */ formatDate(dateStr) { if (!dateStr) return 'N/A'; const date = new Date(dateStr); return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }, /** * Download product export CSV */ async downloadExport() { this.exporting = true; this.error = ''; try { const params = new URLSearchParams({ language: this.exportLanguage, include_inactive: this.exportIncludeInactive.toString() }); // Get the token for authentication const token = localStorage.getItem('wizamart_token'); if (!token) { throw new Error('Not authenticated'); } const response = await fetch(`/api/v1/vendor/letzshop/export?${params}`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || 'Export failed'); } // Get filename from Content-Disposition header const contentDisposition = response.headers.get('Content-Disposition'); let filename = `letzshop_export_${this.exportLanguage}.csv`; if (contentDisposition) { const match = contentDisposition.match(/filename="(.+)"/); if (match) { filename = match[1]; } } // Download the file const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); this.successMessage = `Export downloaded: ${filename}`; } catch (error) { console.error('[VENDOR LETZSHOP] Export failed:', error); this.error = error.message || 'Failed to export products'; } finally { this.exporting = false; setTimeout(() => this.successMessage = '', 5000); } } }; }