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 */