diff --git a/frontend/pages/incomingInvoices/[mode]/[id].vue b/frontend/pages/incomingInvoices/[mode]/[id].vue index 6851d05..bf4c50b 100644 --- a/frontend/pages/incomingInvoices/[mode]/[id].vue +++ b/frontend/pages/incomingInvoices/[mode]/[id].vue @@ -7,6 +7,7 @@ import { useDraggable } from '@vueuse/core' const dataStore = useDataStore() const route = useRoute() const mode = ref(route.params.mode) +const toast = useToast() // --- Page Leave Logic --- const isModified = ref(false) // Speichert, ob Änderungen vorgenommen wurden @@ -119,6 +120,7 @@ const totalCalculated = computed(() => { }) const hasAmount = (value) => value !== null && value !== undefined && value !== "" +const hasValidNumber = (value) => hasAmount(value) && Number.isFinite(Number(value)) const recalculateItem = (item, source) => { const taxRate = Number(taxOptions.value.find(i => i.key === item.taxType)?.percentage || 0); @@ -151,6 +153,15 @@ const moveGrossToNet = (item) => { // --- Saving --- const updateIncomingInvoice = async (setBooked = false) => { + if (setBooked && hasBlockingIncomingInvoiceErrors.value) { + toast.add({ + title: "Buchen nicht möglich", + description: "Bitte beheben Sie zuerst die rot markierten Pflichtfehler.", + color: "rose" + }) + return + } + let item = { ...itemInfo.value } delete item.files item.state = setBooked ? "Gebucht" : "Entwurf" @@ -162,20 +173,32 @@ const updateIncomingInvoice = async (setBooked = false) => { } const findIncomingInvoiceErrors = computed(() => { - let errors = [] + const errors = [] const i = itemInfo.value if(!i.vendor) errors.push({message: "Es ist kein Lieferant ausgewählt", type: "breaking"}) - if(!i.reference) errors.push({message: "Es ist keine Referenz angegeben", type: "breaking"}) + if(!i.reference || !String(i.reference).trim()) errors.push({message: "Es ist keine Referenz angegeben", type: "breaking"}) if(!i.date) errors.push({message: "Es ist kein Datum ausgewählt", type: "breaking"}) + if(!i.accounts || i.accounts.length === 0) errors.push({message: "Es ist keine Position vorhanden", type: "breaking"}) i.accounts.forEach((account, idx) => { if(!account.account) errors.push({message: `Pos ${idx+1}: Keine Kategorie`, type: "breaking"}) - if(account.amountNet === null) errors.push({message: `Pos ${idx+1}: Kein Betrag`, type: "breaking"}) + if(!hasValidNumber(account.amountNet) && !hasValidNumber(account.amountGross)) { + errors.push({message: `Pos ${idx+1}: Kein gültiger Betrag`, type: "breaking"}) + } + if(!account.taxType) errors.push({message: `Pos ${idx+1}: Kein Steuerschlüssel`, type: "breaking"}) + if(hasValidNumber(account.amountNet) && !hasValidNumber(account.amountTax)) { + errors.push({message: `Pos ${idx+1}: Steuerbetrag fehlt, bitte Steuer neu berechnen`, type: "warning"}) + } }) - return errors.sort((a,b) => (a.type === "breaking") ? -1 : 1) + const order = { breaking: 0, warning: 1 } + return errors.sort((a,b) => order[a.type] - order[b.type]) }) + +const blockingIncomingInvoiceErrors = computed(() => findIncomingInvoiceErrors.value.filter(i => i.type === "breaking")) +const warningIncomingInvoiceErrors = computed(() => findIncomingInvoiceErrors.value.filter(i => i.type === "warning")) +const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceErrors.value.length > 0)