diff --git a/scripts/ralph/prd.json b/scripts/ralph/prd.json index ea07db6..c8d0058 100644 --- a/scripts/ralph/prd.json +++ b/scripts/ralph/prd.json @@ -81,8 +81,8 @@ "npm run build passes", "Verify in browser: butoanele au același aspect ca pe pagina Facturi" ], - "passes": false, - "notes": "" + "passes": true, + "notes": "Completed in iteration 2" }, { "id": "US-503", diff --git a/scripts/ralph/progress.txt b/scripts/ralph/progress.txt index a44f3ac..c50b180 100644 --- a/scripts/ralph/progress.txt +++ b/scripts/ralph/progress.txt @@ -76,3 +76,9 @@ Design Reference: src/modules/reports/views/InvoicesView.vue [2026-01-12 22:09:40] Working on story: US-501 [2026-01-12 22:09:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-501.log) [2026-01-12 22:16:53] SUCCESS: Story US-501 passed! +[2026-01-12 22:16:53] Changes committed +[2026-01-12 22:16:53] Progress: 1/19 stories completed +[2026-01-12 22:16:55] === Iteration 2/100 === +[2026-01-12 22:16:55] Working on story: US-502 +[2026-01-12 22:16:55] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-502.log) +[2026-01-12 22:20:46] SUCCESS: Story US-502 passed! diff --git a/src/modules/data-entry/views/receipts/ReceiptsListView.vue b/src/modules/data-entry/views/receipts/ReceiptsListView.vue index 92b913c..909579f 100644 --- a/src/modules/data-entry/views/receipts/ReceiptsListView.vue +++ b/src/modules/data-entry/views/receipts/ReceiptsListView.vue @@ -315,24 +315,41 @@ @date-select="onFilterChange" /> - -
+ +
@@ -1005,7 +1022,7 @@ import DragDropOverlay from '@data-entry/components/bulk/DragDropOverlay.vue' import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue' import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue' import MobileSelectionFooter from '@shared/components/mobile/MobileSelectionFooter.vue' -import { exportToExcel } from '@reports/utils/exportUtils' +import { exportToExcel, exportToPDF } from '@reports/utils/exportUtils' import BatchGroupHeader from '@data-entry/components/bulk/BatchGroupHeader.vue' import ProcessingStatusCell from '@data-entry/components/bulk/ProcessingStatusCell.vue' import Paginator from 'primevue/paginator' @@ -1079,6 +1096,9 @@ const showDrawer = ref(false) const moreMenuRef = ref(null) const fabVisible = ref(true) +// US-502: Export Menu ref and items for desktop header actions +const exportMenuRef = ref(null) + // US-303: FAB Menu State const fabMenuRef = ref(null) const fabMenuOpen = ref(false) @@ -1119,6 +1139,25 @@ const moreMenuItems = computed(() => [ } ]) +// US-502: Toggle export menu +const toggleExportMenu = (event) => { + exportMenuRef.value?.toggle(event) +} + +// US-502: Export menu items (PDF and XLSX) +const exportMenuItems = computed(() => [ + { + label: 'Export PDF', + icon: 'pi pi-file-pdf', + command: () => exportAllReceiptsPDF() + }, + { + label: 'Export XLSX', + icon: 'pi pi-file-excel', + command: () => exportAllReceipts() + } +]) + // US-303: FAB Menu Items (Bon Nou | Upload Bulk) const fabMenuItems = [ { @@ -1171,8 +1210,13 @@ const handleTopBarAction = (action) => { showFilters.value = !showFilters.value break case 'export': - // US-306: Export all current receipts - exportAllReceipts() + // US-502: Show export menu (PDF/XLSX dropdown) on mobile too + if (exportMenuRef.value) { + const btn = document.querySelector('.mobile-top-bar .top-bar-btn:nth-child(2)') + if (btn) { + exportMenuRef.value.toggle({ currentTarget: btn }) + } + } break case 'more': // The more menu needs to be toggled with the event, but we don't have the event here @@ -2508,6 +2552,78 @@ const exportAllReceipts = () => { } } +/** + * US-502: Export all currently visible receipts to PDF. + * Exports all receipts from the current filtered list (excludes job items). + */ +const exportAllReceiptsPDF = () => { + // Filter out job items - only export actual receipts + const receiptsList = unifiedItems.value.filter(item => !isJobItem(item)) + + if (receiptsList.length === 0) { + toast.add({ + severity: 'warn', + summary: 'Atenție', + detail: 'Nu există bonuri de exportat', + life: 3000, + }) + return + } + + // Map receipt data to export format for PDF + const exportData = receiptsList.map(r => ({ + store_name: r.store_name || r.partner_name || '-', + cui: r.cui || '-', + receipt_date: r.receipt_date ? formatDate(r.receipt_date) : '-', + receipt_number: r.receipt_number || '-', + receipt_type: r.receipt_type === 'receipt' ? 'Bon' : r.receipt_type === 'invoice' ? 'Factură' : r.receipt_type || '-', + direction: r.direction === 'expense' ? 'Cheltuială' : r.direction === 'income' ? 'Venit' : r.direction || '-', + amount: r.amount || 0, + tva_total: r.tva_total || 0, + status: getStatusLabel(r.status) || '-', + })) + + // Define columns for PDF with proportional widths + const columns = [ + { field: 'store_name', header: 'Magazin', type: 'text', width: 0.22 }, + { field: 'cui', header: 'CUI', type: 'text', width: 0.10 }, + { field: 'receipt_date', header: 'Data', type: 'text', width: 0.10 }, + { field: 'receipt_number', header: 'Nr. Bon', type: 'text', width: 0.10 }, + { field: 'receipt_type', header: 'Tip', type: 'text', width: 0.08 }, + { field: 'direction', header: 'Direcție', type: 'text', width: 0.10 }, + { field: 'amount', header: 'Suma', type: 'number', width: 0.10 }, + { field: 'tva_total', header: 'TVA', type: 'number', width: 0.10 }, + { field: 'status', header: 'Status', type: 'text', width: 0.10 }, + ] + + const result = exportToPDF( + exportData, + columns, + `bonuri_export_${receiptsList.length}`, + { + companyName: companyStore.selectedCompany?.name || '', + title: 'Lista Bonuri Fiscale', + period: '', + } + ) + + if (result.success) { + toast.add({ + severity: 'success', + summary: 'Export reușit', + detail: `${receiptsList.length} bonuri exportate cu succes (PDF)`, + life: 3000, + }) + } else { + toast.add({ + severity: 'error', + summary: 'Eroare', + detail: 'Nu s-a putut exporta lista de bonuri în format PDF', + life: 5000, + }) + } +} + /** * US-026: Confirmation dialog for bulk delete. * Uses PrimeVue ConfirmDialog to ask user before deleting multiple receipts. @@ -3359,6 +3475,30 @@ const cleanupCompletedBatches = (storedBatchIds) => { margin-left: auto; } +/* US-502: Header actions bar for unified Filter/Reset/Export buttons */ +.header-actions-bar { + display: flex; + gap: var(--space-xs); + margin-left: auto; + align-items: center; +} + +.header-actions-bar .p-button { + min-width: auto; + padding: var(--space-sm); +} + +.header-actions-bar .filter-active { + background: var(--color-primary); + border-color: var(--color-primary); + color: var(--surface-ground); +} + +.header-actions-bar .filter-active:hover { + background: var(--color-primary-dark); + border-color: var(--color-primary-dark); +} + /* Compact DataTable - styles moved to vendor/primevue-overrides.css */ /* Action buttons - always on same line */