From ec1114b1cd8b5b430ad742a33cacbd0b155ac231 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Tue, 3 Feb 2026 12:34:19 +0100 Subject: [PATCH] Add comparison endpoint and mass comparison feature for collected invoices with E-conomic in `openapi.yaml` and `CollectedOrderInvoicesListPagination.vue`. --- openapi.yaml | 95 +++++++++++++++++++ .../CollectedOrderInvoicesListPagination.vue | 92 +++++++++++++++++- 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 089d685e..09ec8f0d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3140,6 +3140,41 @@ paths: '200': description: Ready invoices retrieved successfully + /collected-invoices/economic/compare: + get: + tags: + - Invoices + summary: Compare collected invoice totals with E-conomic + description: | + Compares a collected invoice in the system with its corresponding invoice in E-conomic. + Returns totals from both sources, their difference, and any warnings detected during comparison. + operationId: compareCollectedInvoiceEconomic + parameters: + - name: collected_invoice_id + in: query + required: true + description: The internal collected invoice ID to compare + schema: + type: integer + minimum: 1 + responses: + '200': + description: Comparison completed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/CollectedInvoiceEconomicCompareResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + /superuser/invoicing/period: get: tags: @@ -5516,6 +5551,7 @@ components: cashier_id: type: integer description: Cashier user ID + cashier_name: type: string description: Cashier name @@ -5544,6 +5580,65 @@ components: type: string format: date-time + CollectedInvoiceEconomicCompareResponse: + type: object + description: Result of comparing a collected invoice with its E-conomic counterpart + properties: + collected_invoice_id: + type: integer + description: The internal collected invoice ID + example: 123 + draft_id: + type: integer + nullable: true + description: E-conomic draft invoice ID, if present + example: 456 + booked_id: + type: integer + nullable: true + description: E-conomic booked invoice ID, if present + example: 28368 + warnings: + type: array + description: List of warnings detected during comparison + items: + type: string + example: + - "Total amount mismatch for draft invoice ID 456: E-Conomic total is 867.5, internal total is 694" + draft_total: + type: number + format: float + nullable: true + description: Total amount from the E-conomic draft (gross) + example: 867.5 + booked_total: + type: number + format: float + nullable: true + description: Total amount from the E-conomic booked invoice (gross minus VAT if applicable) + example: 694 + difference: + type: number + format: float + nullable: true + description: draft_total minus booked_total when both are available + example: 0 + internal_total: + type: number + format: float + description: Internal total amount for the collected invoice + example: 694 + order_ids: + type: array + description: List of order IDs included in the collected invoice + items: + type: integer + example: [38679, 39210] + required: + - collected_invoice_id + - internal_total + - order_ids + SelfServeLaneStatus: type: object properties: diff --git a/src/components/displays/pagination/models/SuperUserDashboard/CollectedOrderInvoicesListPagination.vue b/src/components/displays/pagination/models/SuperUserDashboard/CollectedOrderInvoicesListPagination.vue index 6d002e31..9a74e3c3 100644 --- a/src/components/displays/pagination/models/SuperUserDashboard/CollectedOrderInvoicesListPagination.vue +++ b/src/components/displays/pagination/models/SuperUserDashboard/CollectedOrderInvoicesListPagination.vue @@ -31,7 +31,7 @@ const props = defineProps({ default: true }, }); -import { defineProps } from "vue"; +import { defineProps, ref } from "vue"; import { useRouter } from "vue-router"; import { isLoaded, @@ -58,6 +58,88 @@ import LoadButtonWhileAwait from "@/components/request/LoadButtonWhileAwait.vue" import PaginationDisplay from "@/components/displays/pagination/PaginationDisplay.vue"; import OrdersTable from "@/components/displays/department/pos/orders/ordersTable.vue"; import CategoriesTable from "@/components/displays/superuser/tables/categoriesTable.vue"; +import Swal from "sweetalert2"; + +// Mass compare functionality +const isMassComparing = ref(false); +const massCompareResults = ref([]); + +const massCompareToEconomic = async () => { + if (!list.value || list.value.length === 0) { + Swal.fire({ + icon: 'warning', + title: 'Ingen fakturaer', + text: 'Der er ingen fakturaer at sammenligne.', + timer: 2000, + }); + return; + } + + isMassComparing.value = true; + massCompareResults.value = []; + + const totalItems = list.value.length; + let processed = 0; + + // Show progress dialog + Swal.fire({ + title: 'Sammenligner fakturaer med E-conomic...', + html: `Behandler 0 af ${totalItems} fakturaer...`, + allowOutsideClick: false, + allowEscapeKey: false, + showConfirmButton: false, + didOpen: () => { + Swal.showLoading(); + } + }); + + for (const invoice of list.value) { + try { + const result = await SessionUser.objects.collectedOrderInvoices.functions.economic.compareToEconomic(invoice.id); + massCompareResults.value.push({ + id: invoice.id, + success: true, + data: result.data?.data || result.data, + }); + } catch (error) { + massCompareResults.value.push({ + id: invoice.id, + success: false, + error: error.message || 'Ukendt fejl', + }); + } + + processed++; + Swal.update({ + html: `Behandler ${processed} af ${totalItems} fakturaer...`, + }); + } + + isMassComparing.value = false; + + // Show results summary + const successCount = massCompareResults.value.filter(r => r.success).length; + const failCount = massCompareResults.value.filter(r => !r.success).length; + const withDifference = massCompareResults.value.filter(r => r.success && r.data?.difference !== null && r.data?.difference !== 0); + + let resultsHtml = `

Succes: ${successCount}

`; + resultsHtml += `

Fejl: ${failCount}

`; + resultsHtml += `

Med difference: ${withDifference.length}

`; + + if (withDifference.length > 0) { + resultsHtml += '

Fakturaer med difference:

'; + } + + Swal.fire({ + icon: failCount > 0 ? 'warning' : 'success', + title: 'Sammenligning færdig', + html: resultsHtml, + }); +}; const router = useRouter(); if (!props.onlyReadyToInvoice || props.onlyReadyToInvoice === false) { setEndpoint("/collected-invoices", false); @@ -91,7 +173,13 @@ if (props.autoLoad) { - Reload +
+ Reload + +