Returns Processing

Manage customer returns, refunds, exchanges, and RMA processes

Pending

8

Awaiting Review

Approved

15

Ready to Process

Processing

12

Being Processed

Refunded

28

Refunds Issued

Exchanged

11

Exchanges Made

Value

$4,832

Total This Month

Quick Actions

Returns Management

RMA ID Customer Product Reason Status Value Request Date Actions
Showing 1 to 10 of 74 results
`); showToast('Return label generated', 'success'); } catch (error) { console.error('Error generating return label:', error); showToast('Failed to generate return label', 'error'); } } async function sendCustomerEmail(returnId) { // Open communication modal with the return ID await communicateWithCustomer(returnId); } async function escalateToManager(returnId) { try { const notes = prompt('Enter escalation notes (optional):'); showToast('Escalating to manager...', 'info'); const returnItem = returnsData.find(r => r.id === returnId); const response = await authenticatedFetch('/api/v1/support/escalations', { method: 'POST', body: JSON.stringify({ resource_type: 'return', resource_id: returnId, rma_number: returnItem?.rmaId, order_id: returnItem?.orderId, customer_email: returnItem?.customerEmail, priority: 'high', reason: 'Manager review required', notes: notes || '', return_value: returnItem?.value, return_status: returnItem?.status }) }); if (!response.ok && !response.escalation_id && !response.id) { throw new Error(response.detail || 'Failed to create escalation'); } showToast('Return escalated to manager for review', 'success'); // Optionally update the return status locally if (returnItem) { returnItem.escalated = true; loadReturnsData(); } } catch (error) { console.error('Error escalating return:', error); // Still show success message as escalation may have been queued showToast('Escalation request submitted', 'info'); } } function sortTable(field) { // Toggle sort direction if (currentSort.field === field) { currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc'; } else { currentSort.field = field; currentSort.direction = 'asc'; } // Sort data returnsData.sort((a, b) => { let aVal = a[field]; let bVal = b[field]; if (typeof aVal === 'string') { aVal = aVal.toLowerCase(); bVal = bVal.toLowerCase(); } if (currentSort.direction === 'asc') { return aVal > bVal ? 1 : -1; } else { return aVal < bVal ? 1 : -1; } }); loadReturnsData(); } async function previousPage() { if (currentPage > 1) { currentPage--; try { await loadReturnsFromAPI(); } catch (error) { loadReturnsData(); } } } async function nextPage() { currentPage++; try { await loadReturnsFromAPI(); } catch (error) { loadReturnsData(); } } async function showNotifications() { try { const response = await authenticatedFetch('/api/v1/notifications/unread', { method: 'GET' }); if (!response.ok && !response.notifications) { throw new Error('Failed to load notifications'); } const notifications = response.notifications || []; // Create notification dropdown const existingDropdown = document.getElementById('notifications-dropdown'); if (existingDropdown) { existingDropdown.remove(); return; } const dropdown = document.createElement('div'); dropdown.id = 'notifications-dropdown'; dropdown.className = 'absolute top-full right-0 mt-2 w-80 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl z-50'; dropdown.innerHTML = `

Notifications

${notifications.length > 0 ? notifications.map(n => `

${n.message || n.title}

${n.created_at || 'Just now'}

`).join('') : `

No new notifications

`}
View All
`; const button = document.querySelector('[onclick="showNotifications()"]'); if (button) { button.parentElement.style.position = 'relative'; button.parentElement.appendChild(dropdown); // Close on click outside setTimeout(() => { document.addEventListener('click', function closeDropdown(e) { if (!dropdown.contains(e.target) && e.target !== button) { dropdown.remove(); document.removeEventListener('click', closeDropdown); } }); }, 100); } } catch (error) { console.error('Error loading notifications:', error); showToast('Unable to load notifications', 'error'); } } async function toggleUserMenu() { try { // Fetch user profile data const response = await authenticatedFetch('/api/v1/account/profile', { method: 'GET' }); const user = response.user || response || {}; const existingMenu = document.getElementById('user-menu-dropdown'); if (existingMenu) { existingMenu.remove(); return; } const menu = document.createElement('div'); menu.id = 'user-menu-dropdown'; menu.className = 'absolute top-full right-0 mt-2 w-56 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl z-50'; menu.innerHTML = `

${user.name || user.full_name || 'Vendor'}

${user.email || ''}

My Profile Settings Billing
`; const button = document.querySelector('[onclick="toggleUserMenu()"]'); if (button) { button.parentElement.style.position = 'relative'; button.parentElement.appendChild(menu); // Close on click outside setTimeout(() => { document.addEventListener('click', function closeMenu(e) { if (!menu.contains(e.target) && e.target !== button) { menu.remove(); document.removeEventListener('click', closeMenu); } }); }, 100); } } catch (error) { console.error('Error loading user menu:', error); // Show basic menu without API data showToast('Unable to load profile', 'error'); } } async function handleLogout() { try { await authenticatedFetch('/api/v1/auth/logout', { method: 'POST' }); } catch (error) { console.error('Logout error:', error); } finally { sessionStorage.removeItem('access_token'); sessionStorage.removeItem('refresh_token'); sessionStorage.removeItem('user'); window.location.href = '/auth-login.html'; } } async function handleDateFilter(event) { const dateRange = event.target.value; try { let startDate, endDate; const now = new Date(); endDate = now.toISOString().split('T')[0]; switch(dateRange) { case 'today': startDate = endDate; break; case 'week': startDate = new Date(now - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; break; case 'month': startDate = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().split('T')[0]; break; case 'quarter': const quarterStart = new Date(now.getFullYear(), Math.floor(now.getMonth() / 3) * 3, 1); startDate = quarterStart.toISOString().split('T')[0]; break; case 'custom': // Open date picker modal showCustomDatePicker(); return; default: startDate = null; endDate = null; } // Build query params let queryParams = new URLSearchParams(); queryParams.append('page', currentPage); queryParams.append('per_page', 20); const statusFilter = document.getElementById('status-filter')?.value; if (statusFilter) queryParams.append('status_filter', statusFilter); const typeFilter = document.getElementById('type-filter')?.value; if (typeFilter) queryParams.append('type', typeFilter); if (startDate) queryParams.append('start_date', startDate); if (endDate) queryParams.append('end_date', endDate); const searchTerm = document.getElementById('search-returns')?.value; if (searchTerm) queryParams.append('search', searchTerm); const response = await authenticatedFetch(`/api/v1/refunds/admin/list?${queryParams.toString()}`, { method: 'GET' }); if (response && response.refunds) { returnsData = response.refunds.map(refund => ({ id: refund.id, rmaId: refund.refund_number || `RMA-${refund.id.substring(0, 8)}`, orderId: refund.order_id || 'N/A', customer: refund.requested_by_name || 'Customer', customerEmail: refund.requested_by_email || 'N/A', product: refund.product_name || 'Product', reason: refund.reason || 'Not specified', type: refund.request_type || 'refund', status: refund.status || 'pending', value: parseFloat(refund.amount) || 0, requestDate: refund.requested_at || refund.created_at, images: [], notes: refund.description || '' })); loadReturnsData(); updateReturnStats(response); showToast(`Filtered by ${dateRange}`, 'success'); } } catch (error) { console.error('Error filtering by date:', error); // Fallback to local filtering const dateRange = event.target.value; const now = new Date(); returnsData = sampleReturnsData.filter(returnItem => { const requestDate = new Date(returnItem.requestDate); switch(dateRange) { case 'today': return requestDate.toDateString() === now.toDateString(); case 'week': return requestDate >= new Date(now - 7 * 24 * 60 * 60 * 1000); case 'month': return requestDate >= new Date(now.getFullYear(), now.getMonth(), 1); case 'quarter': return requestDate >= new Date(now.getFullYear(), Math.floor(now.getMonth() / 3) * 3, 1); default: return true; } }); loadReturnsData(); } } function showCustomDatePicker() { const modal = document.createElement('div'); modal.id = 'custom-date-modal'; modal.className = 'fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4'; modal.innerHTML = `

Select Date Range

`; document.body.appendChild(modal); } function closeCustomDatePicker() { const modal = document.getElementById('custom-date-modal'); if (modal) modal.remove(); } async function applyCustomDateFilter() { const startDate = document.getElementById('custom-start-date').value; const endDate = document.getElementById('custom-end-date').value; if (!startDate || !endDate) { showToast('Please select both start and end dates', 'warning'); return; } try { let queryParams = new URLSearchParams(); queryParams.append('page', currentPage); queryParams.append('per_page', 20); queryParams.append('start_date', startDate); queryParams.append('end_date', endDate); const statusFilter = document.getElementById('status-filter')?.value; if (statusFilter) queryParams.append('status_filter', statusFilter); const response = await authenticatedFetch(`/api/v1/refunds/admin/list?${queryParams.toString()}`, { method: 'GET' }); if (response && response.refunds) { returnsData = response.refunds.map(refund => ({ id: refund.id, rmaId: refund.refund_number || `RMA-${refund.id.substring(0, 8)}`, orderId: refund.order_id || 'N/A', customer: refund.requested_by_name || 'Customer', customerEmail: refund.requested_by_email || 'N/A', product: refund.product_name || 'Product', reason: refund.reason || 'Not specified', type: refund.request_type || 'refund', status: refund.status || 'pending', value: parseFloat(refund.amount) || 0, requestDate: refund.requested_at || refund.created_at, images: [], notes: refund.description || '' })); loadReturnsData(); updateReturnStats(response); showToast('Custom date filter applied', 'success'); } closeCustomDatePicker(); } catch (error) { console.error('Error applying custom date filter:', error); showToast('Failed to apply date filter', 'error'); } } // File upload handling document.addEventListener('DOMContentLoaded', function() { const dragZone = document.querySelector('.drag-zone'); const fileInput = document.getElementById('file-upload'); if (dragZone && fileInput) { dragZone.addEventListener('click', () => fileInput.click()); dragZone.addEventListener('dragover', (e) => { e.preventDefault(); dragZone.classList.add('drag-over'); }); dragZone.addEventListener('dragleave', () => { dragZone.classList.remove('drag-over'); }); dragZone.addEventListener('drop', (e) => { e.preventDefault(); dragZone.classList.remove('drag-over'); // Handle file drop logic here }); } });