File manager - Edit - /home2/zetasolve/crm.shayantraders.com/scripts/returns.js
Back
let allSkus = []; let returnCart = []; let allReturns = []; document.addEventListener('DOMContentLoaded', async () => { document.getElementById('returnDate').valueAsDate = new Date(); await loadSkus(); await loadReturns(); }); async function loadSkus() { try { allSkus = await app.apiGet('/skus'); const skuSelect = document.getElementById('returnSkuSelect'); skuSelect.innerHTML = '<option value="">Select a product...</option>' + allSkus.map(sku => ` <option value="${sku.id}"> ${sku.sku_code} - ${sku.product_name} ${sku.flavour} (${sku.weight}) </option> `).join(''); } catch (error) { console.error('Error loading SKUs:', error); app.showNotification('Failed to load products', 'error'); } } function addReturnItem() { const skuSelect = document.getElementById('returnSkuSelect'); const quantity = parseInt(document.getElementById('returnQuantity').value); if (!skuSelect.value) { app.showNotification('Please select a product', 'error'); return; } if (quantity < 1) { app.showNotification('Quantity must be at least 1', 'error'); return; } const skuId = parseInt(skuSelect.value); const sku = allSkus.find(s => s.id === skuId); // Check if already in cart const existingItem = returnCart.find(item => item.sku_id === skuId); if (existingItem) { existingItem.quantity += quantity; } else { returnCart.push({ sku_id: skuId, sku_code: sku.sku_code, product_name: sku.product_name, flavour: sku.flavour, weight: sku.weight, quantity: quantity }); } // Reset selection skuSelect.value = ''; document.getElementById('returnQuantity').value = 1; updateReturnItemsDisplay(); } function removeReturnItem(index) { returnCart.splice(index, 1); updateReturnItemsDisplay(); } function updateReturnItemsDisplay() { const container = document.getElementById('returnItems'); const submitBtn = document.getElementById('submitReturnBtn'); if (returnCart.length === 0) { container.innerHTML = '<p class="text-muted" style="text-align: center; padding: 2rem;">No items added yet</p>'; submitBtn.disabled = true; return; } submitBtn.disabled = false; container.innerHTML = ` <div style="background: var(--bg-tertiary); border-radius: var(--radius-md); padding: 1rem;"> ${returnCart.map((item, index) => ` <div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; ${index < returnCart.length - 1 ? 'border-bottom: 1px solid var(--glass-border);' : ''}"> <div style="flex: 1;"> <div style="font-weight: 600; color: var(--text-primary);">${item.sku_code}</div> <div style="font-size: 0.875rem; color: var(--text-muted);">${item.product_name} ${item.flavour} (${item.weight})</div> </div> <div style="display: flex; align-items: center; gap: 1rem;"> <div style="font-weight: 600; color: var(--text-primary);">Qty: ${item.quantity}</div> <button type="button" class="btn btn-danger" onclick="removeReturnItem(${index})" style="padding: 0.5rem 0.75rem; font-size: 0.75rem;"> Remove </button> </div> </div> `).join('')} </div> `; } async function processReturn(event) { event.preventDefault(); if (returnCart.length === 0) { app.showNotification('Please add items to return', 'error'); return; } const returnData = { return_date: document.getElementById('returnDate').value, customer_name: document.getElementById('customerName').value || null, reason: document.getElementById('returnReason').value || null, return_type: document.getElementById('returnType').value, original_transaction_id: null, items: returnCart }; try { await app.apiPost('/returns', returnData); app.showNotification('Return processed successfully! Inventory updated.', 'success'); // Reset form returnCart = []; document.getElementById('returnForm').reset(); document.getElementById('returnDate').valueAsDate = new Date(); updateReturnItemsDisplay(); // Reload returns history await loadReturns(); } catch (error) { console.error('Error processing return:', error); app.showNotification('Failed to process return', 'error'); } } async function loadReturns(filters = {}) { try { let url = '/returns'; const params = new URLSearchParams(); if (filters.start_date) params.append('start_date', filters.start_date); if (filters.end_date) params.append('end_date', filters.end_date); if (params.toString()) url += '?' + params.toString(); allReturns = await app.apiGet(url); const container = document.getElementById('returnHistoryList'); if (allReturns.length === 0) { container.innerHTML = '<p class="loading">No returns found</p>'; return; } container.innerHTML = allReturns.map(ret => { const itemDescription = ret.items && ret.items.length > 0 ? `${ret.items[0].product_name} (${ret.items[0].quantity}x)` + (ret.items.length > 1 ? ` +${ret.items.length - 1} more` : '') : 'No items'; return ` <div class="activity-item fade-in" style="border-bottom: 1px solid var(--glass-border); padding: 1rem 0;"> <div style="display: flex; justify-content: space-between; align-items: flex-start;"> <div style="flex: 1;"> <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.5rem;"> <strong style="color: var(--text-primary);">${app.formatDate(ret.return_date)}</strong> ${ret.customer_name ? `<span style="color: var(--text-muted); margin-left: 0.5rem;">• ${ret.customer_name}</span>` : ''} </div> <div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.25rem;"> <span style="font-size: 0.75rem; padding: 0.25rem 0.5rem; border-radius: 4px; background: ${ret.return_type === 'Damaged' ? 'rgba(239, 68, 68, 0.2)' : 'rgba(16, 185, 129, 0.2)'}; color: ${ret.return_type === 'Damaged' ? '#ef4444' : '#10b981'};"> ${ret.return_type || 'Normal'} </span> <span style="font-size: 0.875rem;">${itemDescription}</span> </div> ${ret.reason ? `<p style="font-size: 0.875rem; color: var(--text-muted); margin: 0.25rem 0;">Reason: ${ret.reason}</p>` : ''} </div> <button class="btn btn-secondary" onclick="openEditReturnModal(${ret.id})" style="padding: 0.25rem 0.5rem; font-size: 0.75rem; margin-left: 0.5rem;"> Edit </button> <button class="btn btn-danger" onclick="deleteReturn(${ret.id})" style="padding: 0.25rem 0.5rem; font-size: 0.75rem; margin-left: 0.5rem;"> Delete </button> </div> </div> `}).join(''); } catch (error) { console.error('Error loading returns:', error); document.getElementById('returnHistoryList').innerHTML = '<p class="loading">Failed to load returns</p>'; } } async function deleteReturn(returnId) { if (confirm('Are you sure you want to delete this return? If it was a Normal return, stock will be reversed.')) { try { await app.apiDelete(`/returns/${returnId}`); app.showNotification('Return deleted successfully', 'success'); await loadReturns(); await loadSkus(); // Refresh products stock } catch (error) { console.error('Error deleting return:', error); app.showNotification('Failed to delete return', 'error'); } } } function filterReturns() { const filters = { start_date: document.getElementById('filterStartDate').value, end_date: document.getElementById('filterEndDate').value }; loadReturns(filters); } function openEditReturnModal(returnId) { // Flatten returns to find specific return record const ret = allReturns.find(r => r.id === returnId); if (!ret) return; // For simplicity, we only edit the first item if there are multiple, // or handle multi-item edits properly. // Given the UI, let's assume single-item edits or just editing the main fields + quantity of first item // Ideally, we'd need a more complex UI for multi-item returns. // For now, let's pre-fill with the first item's data. const firstItem = ret.items && ret.items.length > 0 ? ret.items[0] : null; document.getElementById('editReturnId').value = ret.id; document.getElementById('editSkuId').value = firstItem ? firstItem.sku_id : ''; document.getElementById('editReturnDate').value = ret.return_date; document.getElementById('editCustomerName').value = ret.customer_name || ''; document.getElementById('editReturnType').value = ret.return_type; document.getElementById('editReturnReason').value = ret.reason || ''; if (firstItem) { document.getElementById('editProductDetails').value = `${firstItem.product_name} - ${firstItem.flavour}`; document.getElementById('editReturnQuantity').value = firstItem.quantity; } else { document.getElementById('editProductDetails').value = 'No items found'; document.getElementById('editReturnQuantity').value = 0; } document.getElementById('editReturnModal').classList.add('active'); } function closeEditReturnModal() { document.getElementById('editReturnModal').classList.remove('active'); document.getElementById('editReturnForm').reset(); } async function updateReturnRecord(event) { event.preventDefault(); const returnId = document.getElementById('editReturnId').value; const skuId = document.getElementById('editSkuId').value; if (!skuId) { app.showNotification('Cannot update return with no items', 'error'); return; } const payload = { return_date: document.getElementById('editReturnDate').value, customer_name: document.getElementById('editCustomerName').value, reason: document.getElementById('editReturnReason').value, return_type: document.getElementById('editReturnType').value, items: [{ sku_id: parseInt(skuId), quantity: parseInt(document.getElementById('editReturnQuantity').value) }] }; try { await app.apiPut(`/returns/${returnId}`, payload); app.showNotification('Return updated successfully', 'success'); closeEditReturnModal(); await loadReturns(); // Refresh products to show updated stock await loadSkus(); } catch (error) { console.error('Error updating return:', error); app.showNotification('Failed to update return', 'error'); } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.31 | Generation time: 0.21 |
proxy
|
phpinfo
|
Settings