-
{{ formatAmount(data.amount) }} LEI
-
+
+ {{ formatAmount(data.amount) }} LEI
+
+
+
+
+
+
{{ data.items_count }} articole
@@ -75,25 +87,6 @@
TVA
@@ -299,30 +292,40 @@ const formatProcessingTime = (ms) => {
padding: 0.75rem 1rem;
}
-/* Section-based layout (bon fiscal style) */
+/* Section-based layout (bon fiscal style) - clearer separation */
.ocr-section {
- padding: 0.6rem 0;
- border-bottom: 1px solid #d1fae5;
+ padding: 0.75rem;
+ margin-bottom: 0.5rem;
+ background: rgba(255, 255, 255, 0.5);
+ border-radius: 8px;
+ border: 1px solid #bbf7d0;
}
.ocr-section:last-of-type {
- border-bottom: none;
+ margin-bottom: 0;
}
.ocr-section-title {
font-size: 0.7rem;
- font-weight: 600;
+ font-weight: 700;
color: #166534;
text-transform: uppercase;
- letter-spacing: 0.05em;
- margin-bottom: 0.35rem;
- opacity: 0.8;
+ letter-spacing: 0.08em;
+ margin-bottom: 0.5rem;
+ padding-bottom: 0.35rem;
+ border-bottom: 1px dashed #86efac;
}
.ocr-section-content {
color: #1e293b;
}
+/* TOTAL section - prominent styling */
+.ocr-section-total {
+ background: linear-gradient(135deg, rgba(220, 252, 231, 0.8) 0%, rgba(187, 247, 208, 0.6) 100%);
+ border: 2px solid #86efac;
+}
+
/* FURNIZOR section */
.vendor-name {
font-weight: 600;
@@ -376,6 +379,13 @@ const formatProcessingTime = (ms) => {
border: 2px solid #86efac;
border-radius: 8px;
padding: 0.75rem 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.total-main {
display: flex;
align-items: center;
justify-content: center;
@@ -388,6 +398,21 @@ const formatProcessingTime = (ms) => {
color: #166534;
}
+/* Payment methods inside total box */
+.payment-methods-inline {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 0.5rem;
+ padding-top: 0.5rem;
+ border-top: 1px dashed #86efac;
+ width: 100%;
+}
+
+.payment-tag {
+ font-size: 0.8rem;
+}
+
.items-count {
text-align: center;
font-size: 0.8rem;
@@ -395,29 +420,6 @@ const formatProcessingTime = (ms) => {
margin-top: 0.35rem;
}
-/* PLATA section */
-.ocr-payment-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 0.5rem;
-}
-
-.suggested-payment-mode {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- margin-top: 0.5rem;
- padding: 0.4rem 0.6rem;
- background: #fef3c7;
- border-radius: 6px;
- font-size: 0.8rem;
- color: #92400e;
-}
-
-.suggested-payment-mode .pi-lightbulb {
- color: #f59e0b;
-}
-
/* TVA section */
.ocr-tva-table {
display: flex;
diff --git a/data-entry-app/frontend/src/components/ocr/OCRUploadZone.vue b/data-entry-app/frontend/src/components/ocr/OCRUploadZone.vue
index 3ee5401..e027932 100644
--- a/data-entry-app/frontend/src/components/ocr/OCRUploadZone.vue
+++ b/data-entry-app/frontend/src/components/ocr/OCRUploadZone.vue
@@ -26,19 +26,19 @@
-
+
{{ selectedFile.name }}
{{ formatFileSize(selectedFile.size) }}
@@ -187,8 +183,8 @@ defineExpose({ reset, processOCR })
.upload-dropzone {
border: 2px dashed #cbd5e1;
- border-radius: 12px;
- padding: 2rem;
+ border-radius: 10px;
+ padding: 1rem 1.25rem;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
@@ -215,63 +211,52 @@ defineExpose({ reset, processOCR })
display: none;
}
-/* Empty state */
+/* Empty state - compact */
.empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 0.5rem;
-}
-
-.main-text {
- font-size: 1rem;
- color: #475569;
- margin: 0.5rem 0;
-}
-
-.sub-text {
- font-size: 0.85rem;
- color: #94a3b8;
- margin: 0;
-}
-
-.ocr-hint {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-size: 0.85rem;
- color: #667eea;
- margin-top: 0.5rem;
- padding: 0.5rem 1rem;
- background: #eef2ff;
- border-radius: 20px;
-}
-
-/* File selected state */
-.file-selected-state {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
}
+.main-text {
+ font-size: 0.9rem;
+ color: #475569;
+ margin: 0.25rem 0;
+}
+
+.sub-text {
+ font-size: 0.8rem;
+ color: #94a3b8;
+ margin: 0;
+}
+
+/* File selected state - compact */
+.file-selected-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.15rem;
+}
+
.file-name {
font-weight: 600;
+ font-size: 0.9rem;
color: #1e293b;
- margin: 0.5rem 0 0 0;
+ margin: 0.25rem 0 0 0;
word-break: break-all;
}
.file-size {
- font-size: 0.85rem;
+ font-size: 0.8rem;
color: #64748b;
margin: 0;
}
.file-actions {
display: flex;
- gap: 0.75rem;
- margin-top: 1rem;
+ gap: 0.5rem;
+ margin-top: 0.5rem;
}
/* Processing state */
diff --git a/data-entry-app/frontend/src/router/index.js b/data-entry-app/frontend/src/router/index.js
index 462f666..8b69abf 100644
--- a/data-entry-app/frontend/src/router/index.js
+++ b/data-entry-app/frontend/src/router/index.js
@@ -23,7 +23,7 @@ const routes = [
{
path: '/receipt/:id',
name: 'ReceiptDetail',
- component: () => import('../views/receipts/ReceiptDetailView.vue'),
+ component: () => import('../views/receipts/ReceiptCreateView.vue'),
meta: { title: 'Detalii Bon', requiresAuth: true }
},
{
diff --git a/data-entry-app/frontend/src/stores/receiptsStore.js b/data-entry-app/frontend/src/stores/receiptsStore.js
index 00b90a7..21b71e8 100644
--- a/data-entry-app/frontend/src/stores/receiptsStore.js
+++ b/data-entry-app/frontend/src/stores/receiptsStore.js
@@ -238,6 +238,39 @@ export const useReceiptsStore = defineStore('receipts', {
return `/api/receipts/attachments/${attachmentId}/download`
},
+ async fetchAttachmentBlob(attachmentId) {
+ try {
+ const response = await apiService.get(`/receipts/attachments/${attachmentId}/download`, {
+ responseType: 'blob',
+ })
+ return URL.createObjectURL(response.data)
+ } catch (error) {
+ console.error('Failed to fetch attachment:', error)
+ return null
+ }
+ },
+
+ async downloadAttachment(attachmentId, filename) {
+ try {
+ const response = await apiService.get(`/receipts/attachments/${attachmentId}/download`, {
+ responseType: 'blob',
+ })
+ // Create download link
+ const url = URL.createObjectURL(response.data)
+ const link = document.createElement('a')
+ link.href = url
+ link.download = filename || 'attachment'
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ URL.revokeObjectURL(url)
+ return true
+ } catch (error) {
+ console.error('Failed to download attachment:', error)
+ throw new Error(error.response?.data?.detail || 'Failed to download attachment')
+ }
+ },
+
// ============ Accounting Entries ============
async fetchEntries(receiptId) {
diff --git a/data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue b/data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue
index 13ef0f3..566936d 100644
--- a/data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue
+++ b/data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue
@@ -2,23 +2,90 @@
+
+
+
+
+
+
Motiv respingere:
+
{{ receipt.rejection_reason }}
+
Respins de {{ receipt.reviewed_by }} la {{ formatDateTime(receipt.reviewed_at) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -189,6 +335,7 @@
v-model="form.receipt_type"
value="bon_fiscal"
inputId="type_bon"
+ :disabled="isReadOnly"
/>
@@ -197,6 +344,7 @@
v-model="form.receipt_type"
value="chitanta"
inputId="type_chitanta"
+ :disabled="isReadOnly"
/>