diff --git a/app.vue b/app.vue index 32adab3..b987c6b 100644 --- a/app.vue +++ b/app.vue @@ -18,10 +18,13 @@ const setup = async () => { if(await useCapacitor().getIsPhone()) { platform.value = "mobile" } + + const dev = process.dev + console.log(dev) } setup() -const dev = process.dev + Sentry.init({ dsn: "https://62e62ff08e1a438591fe5eb4dd9de244@glitchtip.federspiel.software/3", diff --git a/components/EntityList.vue b/components/EntityList.vue index 7eb08d2..a76b031 100644 --- a/components/EntityList.vue +++ b/components/EntityList.vue @@ -2,6 +2,7 @@ import {useTempStore} from "~/stores/temp.js"; import FloatingActionButton from "~/components/mobile/FloatingActionButton.vue"; import EntityTable from "~/components/EntityTable.vue"; +import EntityListMobile from "~/components/EntityListMobile.vue"; const props = defineProps({ type: { @@ -181,7 +182,14 @@ const filteredRows = computed(() => { + + /*defineShortcuts({ + /!*'/': () => { + //console.log(searchinput) + //searchinput.value.focus() + document.getElementById("searchinput").focus() + },*!/ + 'Enter': { + usingInput: true, + handler: () => { + router.push(`/standardEntity/${props.type}/show/${props.rows.value[selectedItem.value].id}`) + } + }, + 'arrowdown': () => { + if(selectedItem.value < props.rows.length - 1) { + selectedItem.value += 1 + } else { + selectedItem.value = 0 + } + }, + 'arrowup': () => { + if(selectedItem.value === 0) { + selectedItem.value = props.rows.length - 1 + } else { + selectedItem.value -= 1 + } + } + })*/ + + const props = defineProps({ + rows: { + type: Array, + required: true, + default: [] + }, + columns: { + type: Array, + required: true, + }, + type: { + type: String, + required: true, + } + }) + + const dataStore = useDataStore() + + const router = useRouter() + + const dataType = dataStore.dataTypes[props.type] + + const selectedItem = ref(0) + + + + + + + \ No newline at end of file diff --git a/components/EntityShowSub.vue b/components/EntityShowSub.vue index 041e15d..75ecb8f 100644 --- a/components/EntityShowSub.vue +++ b/components/EntityShowSub.vue @@ -115,6 +115,7 @@ setup() :type="type" :columns="columns" :rows="props.item[type]" + style /> diff --git a/components/EntityShowSubCreatedDocuments.vue b/components/EntityShowSubCreatedDocuments.vue index 7f57b80..3956695 100644 --- a/components/EntityShowSubCreatedDocuments.vue +++ b/components/EntityShowSubCreatedDocuments.vue @@ -68,27 +68,30 @@ setup() const templateColumns = [ { key: "reference", - label: "Referenz", - sortable: true + label: "Referenz" + + }, { key: 'type', - label: "Typ", - sortable: true + label: "Typ" },{ key: 'state', - label: "Status", - sortable: true + label: "Status" + },{ + key: 'paid', + label: "Bezahlt" + },{ + key: 'amount', + label: "Betrag" }, { key: "date", - label: "Datum", - sortable: true + label: "Datum" }, { key: "dueDate", - label: "Fällig", - sortable: true + label: "Fällig" } ] const selectedColumns = ref(tempStore.columns["createddocuments"] ? tempStore.columns["createddocuments"] : templateColumns) @@ -119,7 +122,14 @@ const getAvailableQueryStringData = (keys) => { } const invoiceDeliveryNotes = () => { - router.push(`/createDocument/edit?type=invoices&linkedDocuments=[${props.item.createddocuments.filter(i => i.type === "deliveryNotes").map(i => i.id)}]`) + router.push(`/createDocument/edit?type=invoices&loadMode=deliveryNotes&linkedDocuments=[${props.item.createddocuments.filter(i => i.type === "deliveryNotes").map(i => i.id)}]`) +} + +const showFinalInvoiceConfig = ref(false) +const referenceDocument = ref(null) +const advanceInvoicesToAdd = ref([]) +const invoiceAdvanceInvoices = () => { + router.push(`/createDocument/edit?type=invoices&loadMode=finalInvoice&linkedDocuments=[${[referenceDocument.value, ... advanceInvoicesToAdd.value]}]`) } const selectItem = (item) => { @@ -166,6 +176,59 @@ const selectItem = (item) => { > + Abschlagsrechnung + + + Schlussrechnung + + + + + + + + + + + + + + + + @@ -195,6 +258,7 @@ const selectItem = (item) => { :ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }" @select="selectItem" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }" + style="height: 70vh" > + + diff --git a/components/GlobalMessages.vue b/components/GlobalMessages.vue index d8f212c..5c9251a 100644 --- a/components/GlobalMessages.vue +++ b/components/GlobalMessages.vue @@ -11,7 +11,16 @@ const setup = async () => { data = data.filter((message) => message.profiles.length === 0) globalMessages.value = data + + if(data.length > 0) { + messageToShow.value = data[0] + showMessageModal.value = true + } + + } + + const showMessageModal = ref(false) const messageToShow = ref(null) @@ -24,15 +33,32 @@ const markMessageAsRead = async () => { profile: profileStore.activeProfile.id, message: messageToShow.value.id, }) - setup() showMessageModal.value = false + setup() + } + + + setup() \ No newline at end of file diff --git a/pages/incomingInvoices/create.vue b/pages/incomingInvoices/create.vue index a40d90d..3f5c566 100644 --- a/pages/incomingInvoices/create.vue +++ b/pages/incomingInvoices/create.vue @@ -132,12 +132,12 @@ const totalCalculated = computed(() => { }) const createIncomingInvoice = async () => { - const data = await dataStore.createNewItem('incominginvoices',itemInfo.value) - - console.log(data) + const data = await dataStore.createNewItem('incominginvoices',itemInfo.value,true) const {error} = await supabase.from("files").update({incominginvoice: data.id}).eq("id",loadedFile.value.id) + router.push(`/incominginvoices/show/${data.id}`) + } const setCostCentre = async (item,data) => { @@ -145,6 +145,127 @@ const setCostCentre = async (item,data) => { item.costCentre = data.id } +const gptLoading = ref(false) + +const getInvoiceData = async () => { + gptLoading.value = true + console.log(loadedFile.value) + + + //loadedFile.value.url + + + /*let data = { + "invoice_number": "3423478673", + "invoice_date": "2025-05-30", + "invoice_type": "incoming", + "delivery_type": "null", + "delivery_note_number": "null", + "reference": "null", + "issuer": { + "name": "Boels Rental Germany GmbH", + "address": "Emeranstraße 49-51, 85622 Feldkirchen, Deutschland", + "phone": "+49-(0)1801663225", + "email": "fakturierung@boels.de", + "bank": "ABN AMRO Bank N.V.", + "bic": "ABNANL2A", + "iban": "NL09 ABNA 0520 5585 61" + }, + "recipient": { + "name": "Federspiel Technology UG", + "address": "Am Schwarzen Brack 14, 26452 Sande, Deutschland", + "phone": "null", + "email": "null" + }, + "invoice_items": [ + { + "description": "Bautrockner 50 ltr.", + "unit": "piece", + "quantity": 1, + "total": 395.22 + }, + { + "description": "Servicepauschale Kat. A", + "unit": "piece", + "quantity": 1, + "total": 32.1 + }, + { + "description": "Haftungsbegrenzung A: (Schäden, exkl. Feuer/Diebstahl/Einbruch)", + "unit": "piece", + "quantity": 1, + "total": 3.2 + }, + { + "description": "Haftungsbegrenzung B: (Feuer/Diebstahl/Einbruch)", + "unit": "piece", + "quantity": 1, + "total": 16.93 + } + ], + "subtotal": 89.1, + "tax_rate": 19, + "tax": 16.93, + "total": 106.03, + "terms": "Dieser Betrag wird automatisch mittels Lastschrift von ihrem Konto eingezogen" + } + + console.log(data) + console.log(data.subtotal)*/ + + + + let data = await useFunctions().useGetInvoiceData(loadedFile.value) + + + + + if(data.invoice_number) itemInfo.value.reference = data.invoice_number + if(data.invoice_date) itemInfo.value.date = dayjs(data.invoice_date) + if(data.issuer.id) itemInfo.value.vendor = data.issuer.id + if(data.invoice_duedate) itemInfo.value.dueDate = dayjs(data.invoice_duedate) + if(data.terms) itemInfo.value.paymentType = data.terms + if(data.subtotal) { + itemInfo.value.accounts = [ + { + account: null, + amountNet: data.subtotal, + amountTax: data.tax, + taxType: String(data.tax_rate), + costCentre: null, + amountGross: Number(data.subtotal) + Number(data.tax) + } + ] + } + + if(data.terms === "Direct Debit") { + itemInfo.value.paymentType = "Einzug" + } else if(data.terms === "Transfer") { + itemInfo.value.paymentType = "Überweisung" + } else if(data.terms === "Credit Card") { + itemInfo.value.paymentType = "Kreditkarte" + } else if(data.terms === "Other") { + itemInfo.value.paymentType = "Sonstiges" + } + + let description = "" + + if(data.delivery_note_number) description += `Lieferschein: ${data.delivery_note_number} \n` + if(data.reference) description += `Referenz: ${data.reference} \n` + if(data.invoice_items) { + data.invoice_items.forEach(item => { + description += `${item.description} - ${item.quantity} ${item.unit} - ${item.total}\n` + }) + } + itemInfo.value.description = description + + + + + gptLoading.value = false + + +} @@ -204,6 +325,17 @@ const setCostCentre = async (item,data) => {
+ + KI - Vorschlag + + + { :color="!item.amountNet ? 'rose' : 'primary'" :disabled="item.taxType === null" @keyup="item.amountTax = Number((item.amountNet * (Number(taxOptions.find(i => i.key === item.taxType).percentage)/100)).toFixed(2)), - item.amountGross = Number(item.amountNet) + NUmber(item.amountTax)" + item.amountGross = Number(item.amountNet) + Number(item.amountTax)" > + - + Lieferant - + icon="i-heroicons-x-mark" + variant="outline" + color="rose" + @click="itemInfo.vendor = null" + /> @@ -304,7 +364,6 @@ const updateIncomingInvoice = async () => { class="my-3" v-for="(item,index) in itemInfo.accounts" > - { /> + + + + + + @@ -470,7 +547,7 @@ const updateIncomingInvoice = async () => { overflow-y: scroll; padding-left: 1em; padding-right: 1em; - height: 75vh; + height: 70vh; -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } diff --git a/pages/incomingInvoices/index.vue b/pages/incomingInvoices/index.vue index d25e2ea..4911831 100644 --- a/pages/incomingInvoices/index.vue +++ b/pages/incomingInvoices/index.vue @@ -37,6 +37,7 @@ defineShortcuts({ }) const dataStore = useDataStore() +const tempStore = useTempStore() const router = useRouter() const sum = useSum() @@ -45,7 +46,7 @@ const items = ref([]) const selectedItem = ref(0) const setupPage = async () => { - items.value = await useSupabaseSelect("incominginvoices","*, vendor(id,name), statementallocations(id,amount)") + items.value = await useSupabaseSelect("incominginvoices","*, vendor(id,name), statementallocations(id,amount)","created_at",false) } setupPage() @@ -91,9 +92,17 @@ const selectedColumns = ref(templateColumns) const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column))) -const searchString = ref('') +const searchString = ref(tempStore.searchStrings['incominginvoices'] ||'') + +const clearSearchString = () => { + tempStore.clearSearchString('incominginvoices') + searchString.value = '' +} const filteredRows = computed(() => { - return useSearch(searchString.value, items.value) + let filteredItems = useSearch(searchString.value, items.value) + + return [...filteredItems.filter(i => i.state === "Vorbereitet"), ...filteredItems.filter(i => i.state !== "Vorbereitet")] + }) @@ -115,6 +124,16 @@ const isPaid = (item) => { return Math.abs(amountPaid) === Math.abs(Number(getInvoiceSum(item))) } +const selectIncomingInvoice = (invoice) => { + if(invoice.state === "Vorbereitet") { + router.push(`/incomingInvoices/edit/${invoice.id}`) + } else { + router.push(`/incomingInvoices/show/${invoice.id}`) + } + + +} + @@ -130,13 +149,21 @@ const isPaid = (item) => { placeholder="Suche..." class="hidden lg:block" @keydown.esc="$event.target.blur()" + @change="tempStore.modifySearchString('incominginvoices',searchString)" > + - + Beleg + @@ -162,13 +189,18 @@ const isPaid = (item) => { :columns="columns" class="w-full" :ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }" - @select="(i) => router.push(`/incomingInvoices/show/${i.id}`) " + @select="(i) => selectIncomingInvoice(i) " :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }" > + @@ -179,7 +211,7 @@ const isPaid = (item) => { {{displayCurrency(sum.getIncomingInvoiceSum(row))}}