diff --git a/app.vue b/app.vue index b987c6b..f2f0d80 100644 --- a/app.vue +++ b/app.vue @@ -1,12 +1,7 @@ + + + + \ No newline at end of file diff --git a/components/ButtonWithConfirm.vue b/components/ButtonWithConfirm.vue index fe10c44..24da92c 100644 --- a/components/ButtonWithConfirm.vue +++ b/components/ButtonWithConfirm.vue @@ -41,7 +41,6 @@ const emitConfirm = () => {
@@ -50,8 +49,9 @@ const emitConfirm = () => { - Bestätigen + Archivieren diff --git a/components/DocumentDisplay.vue b/components/DocumentDisplay.vue index 7e4715b..6db5d5a 100644 --- a/components/DocumentDisplay.vue +++ b/components/DocumentDisplay.vue @@ -3,7 +3,6 @@ import DocumentDisplayModal from "~/components/DocumentDisplayModal.vue"; const toast = useToast() -const supabase = useSupabaseClient() const dataStore = useDataStore() const modal = useModal() const profileStore = useProfileStore() @@ -66,18 +65,18 @@ const showFile = (file) => { diff --git a/components/ProfileDropdown.vue b/components/ProfileDropdown.vue deleted file mode 100644 index a5c7281..0000000 --- a/components/ProfileDropdown.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - \ No newline at end of file diff --git a/components/StandardEntityModal.vue b/components/StandardEntityModal.vue index f405e2f..98850ac 100644 --- a/components/StandardEntityModal.vue +++ b/components/StandardEntityModal.vue @@ -35,10 +35,10 @@ const item = ref({}) const setupPage = async () => { if(props.mode === "show") { //Load Data for Show - item.value = await useSupabaseSelectSingle(props.type, props.id, dataType.supabaseSelectWithInformation || "*") + item.value = await useEntities(props.type).selectSingle(props.id, dataType.supabaseSelectWithInformation || "*") } else if(props.mode === "edit") { //Load Data for Edit - const data = JSON.stringify((await supabase.from(props.type).select().eq("id", props.id).single()).data) + const data = JSON.stringify(await useEntities(props.type).selectSingle(props.id)/*(await supabase.from(props.type).select().eq("id", props.id).single()).data*/) //await useSupabaseSelectSingle(type, route.params.id) item.value = data @@ -48,7 +48,7 @@ const setupPage = async () => { } else if(props.mode === "list") { //Load Data for List - items.value = await useSupabaseSelect(props.type, dataType.supabaseSelectWithInformation || "*", dataType.supabaseSortColumn,dataType.supabaseSortAscending || false) + items.value = await useEntities(props.type).select(dataType.supabaseSelectWithInformation || "*", dataType.supabaseSortColumn,dataType.supabaseSortAscending || false) } loaded.value = true diff --git a/components/TenantDropdown.vue b/components/TenantDropdown.vue new file mode 100644 index 0000000..fa5eb6f --- /dev/null +++ b/components/TenantDropdown.vue @@ -0,0 +1,27 @@ + + + \ No newline at end of file diff --git a/components/UserDropdown.vue b/components/UserDropdown.vue index b0b57f0..7d15569 100644 --- a/components/UserDropdown.vue +++ b/components/UserDropdown.vue @@ -1,4 +1,5 @@ diff --git a/components/costcentreDisplay.vue b/components/costcentreDisplay.vue index 5d5215b..8b3a97b 100644 --- a/components/costcentreDisplay.vue +++ b/components/costcentreDisplay.vue @@ -13,7 +13,7 @@ const props = defineProps({ const incomingInvoices = ref({}) const setupPage = async () => { - incomingInvoices.value = (await supabase.from("incominginvoices").select().eq("tenant", profileStore.currentTenant)).data.filter(i => i.accounts.find(x => x.costCentre === props.item.id)) + incomingInvoices.value = (await useEntities("incominginvoices").select()).filter(i => i.accounts.find(x => x.costCentre === props.item.id)) } setupPage() diff --git a/components/displayBankaccounts.vue b/components/displayBankaccounts.vue index 147bd71..cb4ac08 100644 --- a/components/displayBankaccounts.vue +++ b/components/displayBankaccounts.vue @@ -1,15 +1,14 @@ diff --git a/composables/useCapacitor.js b/composables/useCapacitor.js index 26e7288..64ec2be 100644 --- a/composables/useCapacitor.js +++ b/composables/useCapacitor.js @@ -17,10 +17,14 @@ export const useCapacitor = () => { return deviceInfo.model.toLowerCase().includes('iphone') } + const getIsNative = () => { + return Capacitor.isNativePlatform() + } + const getNetworkStatus = async () => { return await Network.getStatus() } - return {getPlatform, getDeviceInfo, getNetworkStatus, getIsPhone} + return {getPlatform, getDeviceInfo, getNetworkStatus, getIsPhone, getIsNative} } \ No newline at end of file diff --git a/composables/useEntities.ts b/composables/useEntities.ts new file mode 100644 index 0000000..9975b02 --- /dev/null +++ b/composables/useEntities.ts @@ -0,0 +1,143 @@ + +import { useDataStore } from "~/stores/data" + +export const useEntities = ( + relation: string, +) => { + + const dataStore = useDataStore() + const toast = useToast() + const router = useRouter() + + const dataType = dataStore.dataTypes[relation] + + const select = async ( + select: string = "*", + sortColumn: string | null = null, + ascending: boolean = false, + noArchivedFiltering: boolean = false + ) => { + + const res = await useNuxtApp().$api(`/api/resource/${relation}`, { + method: "GET", + params: { + select, + sort: sortColumn || undefined, + asc: ascending + } + }) + + let data = res || [] + + if (dataType && dataType.isArchivable && !noArchivedFiltering) { + data = data.filter((i: any) => !i.archived) + } + + return data + } + + const selectSpecial = async ( + select: string = "*", + sortColumn: string | null = null, + ascending: boolean = false, + ) => { + + const res = await useNuxtApp().$api(`/api/resource-special/${relation}`, { + method: "GET", + params: { + select, + sort: sortColumn || undefined, + asc: ascending + } + }) + + return res || [] + } + + const selectSingle = async ( + idToEq: string | number, + select: string = "*", + withInformation: boolean = false + ) => { + if (!idToEq) return null + + const res = await useNuxtApp().$api(withInformation ? `/api/resource/${relation}/${idToEq}/${withInformation}` : `/api/resource/${relation}/${idToEq}`, { + method: "GET", + params: { select } + }) + + return res + } + + const create = async ( + payload: Record, + noRedirect: boolean = false + ) => { + + + const res = await useNuxtApp().$api(`/api/resource/${relation}`, { + method: "POST", + body: payload + }) + + toast.add({title: `${dataType.labelSingle} hinzugefügt`}) + if(dataType.redirect && !noRedirect) { + if(dataType.isStandardEntity) { + await router.push(dataType.redirectToList ? `/standardEntity/${relation}` : `/standardEntity/${relation}/show/${res.id}`) + } else { + await router.push(dataType.redirectToList ? `/${relation}` : `/${relation}/show/${res.id}`) + } + } + //modal.close() TODO: Modal Close wenn in Modal + + + return res + } + + const update = async ( + id: string | number, + payload: Record, + noRedirect: boolean = false + ) => { + const res = await useNuxtApp().$api(`/api/resource/${relation}/${id}`, { + method: "PUT", + body: payload + }) + + toast.add({title: `${dataType.labelSingle} geändert`}) + if(dataType.redirect && !noRedirect) { + if(dataType.isStandardEntity) { + await router.push(dataType.redirectToList ? `/standardEntity/${relation}` : `/standardEntity/${relation}/show/${res.id}`) + } else { + await router.push(dataType.redirectToList ? `/${relation}` : `/${relation}/show/${res.id}`) + } + } + //modal.close() TODO: Modal Close wenn in Modal + + + return res + } + + /** + * Soft Delete = archived = true + */ + const archive = async ( + id: string | number + ) => { + const res = await useNuxtApp().$api(`/api/resource/${relation}/${id}`, { + method: "PUT", + body: { archived: true } + }) + navigateTo(dataType.isStandardEntity ? `/standardEntity/${relation}` : `/${relation}`) + + return res + + } + + return {select, create, update, archive, selectSingle, selectSpecial} +} + + + + + diff --git a/composables/useError.js b/composables/useErrorLogging.js similarity index 92% rename from composables/useError.js rename to composables/useErrorLogging.js index 1c2e742..298ccd0 100644 --- a/composables/useError.js +++ b/composables/useErrorLogging.js @@ -1,5 +1,5 @@ -export const useError = (resourceType) => { +export const useErrorLogging = (resourceType) => { const supabase = useSupabaseClient() const toast = useToast() const profileStore = useProfileStore() diff --git a/composables/useFiles.js b/composables/useFiles.js deleted file mode 100644 index 52c4875..0000000 --- a/composables/useFiles.js +++ /dev/null @@ -1,211 +0,0 @@ - -export const useFiles = () => { - const supabase = useSupabaseClient() - const toast = useToast() - - let bucket = "filesdev" - - const profileStore = useProfileStore() - - const uploadFiles = async (formData, files,tags, upsert) => { - const uploadSingleFile = async (file) => { - //Create File Entry to Get ID for Folder - const {data:createdFileData,error:createdFileError} = await supabase - .from("files") - .insert({ - tenant: profileStore.currentTenant, - }) - .select() - .single() - - if(createdFileError){ - console.log(createdFileError) - toast.add({title: "Hochladen fehlgeschlagen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000}) - } else if(createdFileData) { - //Upload File to ID Folder - const {data:uploadData, error: uploadError} = await supabase - .storage - .from(bucket) - .upload(`${profileStore.currentTenant}/filesbyid/${createdFileData.id}/${file.name}`, file, {upsert: upsert}) - - if(uploadError) { - console.log(uploadError) - console.log(uploadError.statusCode) - - if(uploadError.statusCode === '400') { - console.log("is 400") - toast.add({title: "Hochladen fehlgeschlagen", description: "Die Datei enthält ungültige Zeichen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000}) - } else if(uploadError.statusCode === '409') { - console.log("is 409") - toast.add({title: "Hochladen fehlgeschlagen", description: "Es existiert bereits eine Datei mit diesem Namen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000}) - } else { - toast.add({title: "Hochladen fehlgeschlagen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000}) - - } - } else if(uploadData) { - //Update File with Corresponding Path - const {data:updateFileData, error:updateFileError} = await supabase - .from("files") - .update({ - ...formData, - path: uploadData.path, - }) - .eq("id", createdFileData.id) - - if(updateFileError) { - console.log(updateFileError) - toast.add({title: "Hochladen fehlgeschlagen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000}) - } else { - const {data:tagData, error:tagError} = await supabase - .from("filetagmembers") - .insert(tags.map(tag => { - return { - file_id: createdFileData.id, - tag_id: tag - } - })) - - - - toast.add({title: "Hochladen erfolgreich"}) - - } - } - } - } - - if(files.length === 1) { - await uploadSingleFile(files[0]) - } else if( files.length > 1) { - - for(let i = 0; i < files.length; i++){ - await uploadSingleFile(files[i]) - } - - } - } - - const selectDocuments = async (sortColumn = null, folder = null) => { - let data = [] - - if(sortColumn !== null ) { - data = (await supabase - .from("files") - .select('*, incominginvoice(*), project(*), vendor(*), customer(*), contract(*), plant(*), createddocument(*), vehicle(*), product(*), profile(*), check(*), inventoryitem(*)') - .eq("tenant", profileStore.currentTenant) - .not("path","is",null) - .not("archived","is",true) - .order(sortColumn, {ascending: true})).data - } else { - data = (await supabase - .from("files") - .select('*, incominginvoice(*), project(*), vendor(*), customer(*), contract(*), plant(*), createddocument(*), vehicle(*), product(*), profile(*), check(*), inventoryitem(*)') - .eq("tenant", profileStore.currentTenant) - .not("path","is",null) - .not("archived","is",true)).data - - } - - if(data.length > 0){ - let paths = [] - data.forEach(doc => { - paths.push(doc.path) - }) - - const {data: supabaseData,error} = await supabase.storage.from(bucket).createSignedUrls(paths,3600) - - data = data.map((doc,index) => { - - return { - ...doc, - url: supabaseData[index].signedUrl - } - }) - } - - return data - } - - const selectSomeDocuments = async (documentIds, sortColumn = null, folder = null) => { - let data = null - - if(sortColumn !== null ) { - data = (await supabase - .from("files") - .select('*, incominginvoice(*), project(*), vendor(*), customer(*), contract(*), plant(*), createddocument(*), vehicle(*), product(*), profile(*), check(*), inventoryitem(*)') - .in("id",documentIds) - .eq("tenant", profileStore.currentTenant) - .not("path","is",null) - .not("archived","is",true) - .order(sortColumn, {ascending: true})).data - } else { - data = (await supabase - .from("files") - .select('*, incominginvoice(*), project(*), vendor(*), customer(*), contract(*), plant(*), createddocument(*, customer(*), contact(*)), vehicle(*), product(*), profile(*), check(*), inventoryitem(*)') - .in("id",documentIds) - .not("path","is",null) - .not("archived","is",true) - .eq("tenant", profileStore.currentTenant)).data - - } - - if(data.length > 0){ - let paths = [] - data.forEach(doc => { - paths.push(doc.path) - }) - - const {data: supabaseData,error} = await supabase.storage.from(bucket).createSignedUrls(paths,3600) - - data = data.map((doc,index) => { - - return { - ...doc, - url: supabaseData[index].signedUrl - } - }) - } - - //console.log(data) - - return data - } - - const selectDocument = async (id) => { - const {data,error} = await supabase - .from("files") - .select('*') - .eq("id",id) - .single() - - const {data: supabaseData,error:supabaseError} = await supabase.storage.from(bucket).createSignedUrl(data.path,3600) - - return { - ...data, - url: supabaseData.signedUrl - } -/* - if(data.length > 0){ - let paths = [] - data.forEach(doc => { - paths.push(doc.path) - }) - - const {data: supabaseData,error} = await supabase.storage.from(bucket).createSignedUrls(paths,3600) - - data = data.map((doc,index) => { - - return { - ...doc, - url: supabaseData[index].signedUrl - } - }) - } - - //console.log(data) - - return data[0]*/ - } - - return {uploadFiles, selectDocuments, selectSomeDocuments, selectDocument} -} \ No newline at end of file diff --git a/composables/useFiles.ts b/composables/useFiles.ts new file mode 100644 index 0000000..657824d --- /dev/null +++ b/composables/useFiles.ts @@ -0,0 +1,129 @@ + +export const useFiles = () => { + const supabase = useSupabaseClient() + const toast = useToast() + + const auth = useAuthStore() + + let bucket = "filesdev" + + const uploadFiles = async (fileData, files,tags, upsert) => { + const uploadSingleFile = async (file) => { + //Create File Entry to Get ID for Folder + + const formData = new FormData() + + formData.append("file", file) + formData.append("meta", JSON.stringify(fileData)) + + const {fileReturn} = await useNuxtApp().$api("/api/files/upload",{ + method: "POST", + body: formData + }) + } + + if(files.length === 1) { + await uploadSingleFile(files[0]) + } else if( files.length > 1) { + + for(let i = 0; i < files.length; i++){ + await uploadSingleFile(files[i]) + } + + } + } + + const selectDocuments = async (sortColumn = null, folder = null) => { + let data = [] + data = await useEntities("files").select("*, incominginvoice(*), project(*), vendor(*), customer(*), contract(*), plant(*), createddocument(*), vehicle(*), product(*), profile(*), check(*), inventoryitem(*)") + + + + const res = await useNuxtApp().$api("/api/files/presigned",{ + method: "POST", + body: { + ids: data.map(i => i.id) + } + }) + + console.log(res) + + return res.files + } + + const selectSomeDocuments = async (documentIds, sortColumn = null, folder = null) => { + + if(documentIds.length === 0) return [] + const res = await useNuxtApp().$api("/api/files/presigned",{ + method: "POST", + body: { + ids: documentIds + } + }) + + console.log(res) + + return res.files + + + } + + const selectDocument = async (id) => { + let documentIds = [id] + if(documentIds.length === 0) return [] + const res = await useNuxtApp().$api("/api/files/presigned",{ + method: "POST", + body: { + ids: documentIds + } + }) + + console.log(res) + + return res.files[0] + } + + const downloadFile = async (id?: string, ids?: string[], returnAsBlob: Boolean = false) => { + const url = id ? `/api/files/download/${id}` : `/api/files/download` + const body = ids ? { ids } : undefined + + const res:any = await useNuxtApp().$api.raw(url, { + method: "POST", + body, + responseType: "blob", // wichtig! + }) + + // Dateiname bestimmen + let filename = "download" + + if (id) { + // Einzeldatei → nimm den letzten Teil des Pfads aus Content-Disposition + const contentDisposition = res.headers?.get("content-disposition") + if (contentDisposition) { + const match = contentDisposition.match(/filename="?([^"]+)"?/) + if (match) filename = match[1] + } + } else { + filename = "dateien.zip" + } + + // Direkt speichern + const blob = res._data as Blob + + if(returnAsBlob) { + return blob + } else { + const link = document.createElement("a") + link.href = URL.createObjectURL(blob) + link.download = filename + link.click() + URL.revokeObjectURL(link.href) + } + + + + } + + + return {uploadFiles, selectDocuments, selectSomeDocuments, selectDocument, downloadFile} +} \ No newline at end of file diff --git a/composables/useFunctions.js b/composables/useFunctions.js index 44d27ee..42e7506 100644 --- a/composables/useFunctions.js +++ b/composables/useFunctions.js @@ -24,7 +24,7 @@ export const useFunctions = () => { } const useNextNumber = async (numberRange) => { - const {data:{session:{access_token}}} = await supabase.auth.getSession() + /*const {data:{session:{access_token}}} = await supabase.auth.getSession() return (await axios({ method: "POST", @@ -35,7 +35,11 @@ export const useFunctions = () => { headers: { Authorization: `Bearer ${access_token}` } - })).data.usedNumber + })).data.usedNumber*/ + + return (await useNuxtApp().$api(`/api/functions/usenextnumber/${numberRange}`,)).usedNumber + + } const useCreateTicket = async (subject,message,url,source) => { @@ -80,9 +84,17 @@ export const useFunctions = () => { } const useCreatePDF = async (invoiceData,path) => { - const {data:{session:{access_token}}} = await supabase.auth.getSession() + //const {data:{session:{access_token}}} = await supabase.auth.getSession() - const {data} = await axios({ + const data = await useNuxtApp().$api(`/api/functions/createinvoicepdf`, { + method: "POST", + body: { + invoiceData: invoiceData, + backgroundPath: path, + } + }) + + /*const {data} = await axios({ method: "POST", url: `${baseURL}/functions/createpdf`, data: { @@ -93,7 +105,7 @@ export const useFunctions = () => { headers: { Authorization: `Bearer ${access_token}` } - }) + })*/ console.log(data) diff --git a/composables/usePermission.ts b/composables/usePermission.ts new file mode 100644 index 0000000..54376e7 --- /dev/null +++ b/composables/usePermission.ts @@ -0,0 +1,9 @@ +export function usePermission() { + const auth = useAuthStore() + + const has = (key: string) => { + return auth.hasPermission(key) + } + + return { has } +} diff --git a/composables/useSum.js b/composables/useSum.js index 752a9d4..4c11915 100644 --- a/composables/useSum.js +++ b/composables/useSum.js @@ -6,7 +6,6 @@ export const useSum = () => { const getIncomingInvoiceSum = (invoice) => { let sum = 0 invoice.accounts.forEach(account => { - console.log(account) sum += account.amountTax @@ -23,21 +22,9 @@ export const useSum = () => { let total19 = 0 let total7 = 0 - /*let usedadvanceinvoices = [] - if(createddocument.usedAdvanceInvoices.length > 0) { - console.log(createddocument) - console.log(createddocument.usedAdvanceInvoices) - console.log((await supabase.from("createddocuments").select().in("id", createddocument.usedAdvanceInvoices))) - - usedadvanceinvoices = (await supabase.from("createddocuments").select().in("id", createddocument.usedAdvanceInvoices)).data - console.log(usedadvanceinvoices) - - }*/ - - createddocument.rows.forEach(row => { if(!['pagebreak','title','text'].includes(row.mode)){ let rowPrice = Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(3) diff --git a/composables/useSupabase.js b/composables/useSupabase.js deleted file mode 100644 index 4618aa1..0000000 --- a/composables/useSupabase.js +++ /dev/null @@ -1,54 +0,0 @@ -import {useDataStore} from "~/stores/data.js"; - - -export const useSupabaseSelect = async (relation,select = '*', sortColumn = null, ascending = true,noArchivedFiltering = false) => { - const supabase = useSupabaseClient() - const profileStore = useProfileStore() - let data = null - const dataStore = useDataStore() - - const dataType = dataStore.dataTypes[relation] - - if(sortColumn !== null ) { - data = (await supabase - .from(relation) - .select(select) - .eq("tenant", profileStore.currentTenant) - .order(sortColumn, {ascending: ascending})).data - } else { - data = (await supabase - .from(relation) - .select(select) - .eq("tenant", profileStore.currentTenant)).data - } - - if(dataType && dataType.isArchivable && !noArchivedFiltering) { - data = data.filter(i => !i.archived) - } - - return data -} - -export const useSupabaseSelectSingle = async (relation,idToEq,select = '*' ) => { - const supabase = useSupabaseClient() - const profileStore = useProfileStore() - let data = null - - - if(idToEq !== null) { - data = (await supabase - .from(relation) - .select(select) - .eq("tenant", profileStore.currentTenant) - .eq("id",idToEq) - .single()).data - } else { - data = (await supabase - .from(relation) - .select(select) - .eq("tenant", profileStore.currentTenant) - .single()).data - } - - return data -} \ No newline at end of file diff --git a/composables/useUsers.ts b/composables/useUsers.ts new file mode 100644 index 0000000..ba68874 --- /dev/null +++ b/composables/useUsers.ts @@ -0,0 +1,28 @@ + +import { useDataStore } from "~/stores/data" + +export const useUsers = ( + id: string | number, +) => { + + const dataStore = useDataStore() + const toast = useToast() + const router = useRouter() + + const getProfile = async () => { + + + const res = await useNuxtApp().$api(`/api/profiles/${id}`, { + method: "GET" + }) + + return res + } + + return {getProfile} +} + + + + + diff --git a/docker-compose.yml b/docker-compose.yml index 00ef6c5..55aab3b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,8 @@ services: # networks: # - traefik environment: - SUPABASE_URL: "https://uwppvcxflrcsibuzsbil.supabase.co" - SUPABASE_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InV3cHB2Y3hmbHJjc2lidXpzYmlsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDA5MzgxOTQsImV4cCI6MjAxNjUxNDE5NH0.CkxYSQH0uLfwx9GVUlO6AYMU2FMLAxGMrwEKvyPv7Oo" -# labels: + NUXT_PUBLIC_API_BASE: "https://backend.fedeo.io" + # labels: # - "traefik.enable=true" # - "traefik.docker.network=traefik" # - "traefik.port=3000" diff --git a/error.vue b/error.vue index fbeac53..814280f 100644 --- a/error.vue +++ b/error.vue @@ -7,11 +7,29 @@ const props = defineProps({ \ No newline at end of file diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 529ce3c..31a573e 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -485,7 +485,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = GMCGQ8KK2P; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; @@ -493,7 +493,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.8; + MARKETING_VERSION = 2.0; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = software.federspiel.fedeo; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -510,7 +510,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = GMCGQ8KK2P; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; @@ -518,7 +518,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.8; + MARKETING_VERSION = 2.0; PRODUCT_BUNDLE_IDENTIFIER = software.federspiel.fedeo; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; diff --git a/ios/App/Podfile b/ios/App/Podfile index 05c9cc3..6006b02 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -13,6 +13,7 @@ def capacitor_pods pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device' pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network' + pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences' pod 'CapacitorPluginSafeArea', :path => '../../node_modules/capacitor-plugin-safe-area' pod 'CordovaPluginsStatic', :path => '../capacitor-cordova-ios-plugins' end diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index 5510ba5..3d267bf 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -8,6 +8,8 @@ PODS: - Capacitor - CapacitorPluginSafeArea (4.0.0): - Capacitor + - CapacitorPreferences (6.0.3): + - Capacitor - CordovaPluginsStatic (7.1.0): - CapacitorCordova - OneSignalXCFramework (= 5.2.10) @@ -64,6 +66,7 @@ DEPENDENCIES: - "CapacitorDevice (from `../../node_modules/@capacitor/device`)" - "CapacitorNetwork (from `../../node_modules/@capacitor/network`)" - CapacitorPluginSafeArea (from `../../node_modules/capacitor-plugin-safe-area`) + - "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)" - CordovaPluginsStatic (from `../capacitor-cordova-ios-plugins`) - OneSignalXCFramework (< 6.0, >= 5.0) @@ -82,6 +85,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor/network" CapacitorPluginSafeArea: :path: "../../node_modules/capacitor-plugin-safe-area" + CapacitorPreferences: + :path: "../../node_modules/@capacitor/preferences" CordovaPluginsStatic: :path: "../capacitor-cordova-ios-plugins" @@ -91,9 +96,10 @@ SPEC CHECKSUMS: CapacitorDevice: 069faf433b3a99c3d5f0e500fbe634f60a8c6a84 CapacitorNetwork: 30c2e78a0ed32530656cb426c8ee6c2caec10dbf CapacitorPluginSafeArea: 22031c3436269ca80fac90ec2c94bc7c1e59a81d + CapacitorPreferences: f3eadae2369ac3ab8e21743a2959145b0d1286a3 CordovaPluginsStatic: f722d4ff434f50099581e690d579b7c108f490e6 OneSignalXCFramework: 1a3b28dfbff23aabce585796d23c1bef37772774 -PODFILE CHECKSUM: ccfbce7f13cfefd953204fe26b280d6431731aa5 +PODFILE CHECKSUM: d76fcd3d35c3f8c3708303de70ef45a76cc6e2b5 COCOAPODS: 1.16.2 diff --git a/layouts/default.vue b/layouts/default.vue index ecbbae7..e994ab7 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -3,19 +3,18 @@ import MainNav from "~/components/MainNav.vue"; import dayjs from "dayjs"; -import {useProfileStore} from "~/stores/profile.js"; import {useCapacitor} from "../composables/useCapacitor.js"; import GlobalMessages from "~/components/GlobalMessages.vue"; +import TenantDropdown from "~/components/TenantDropdown.vue"; const dataStore = useDataStore() -const profileStore = useProfileStore() const colorMode = useColorMode() const { isHelpSlideoverOpen } = useDashboard() -const supabase = useSupabaseClient() const router = useRouter() const route = useRoute() -profileStore.initializeData((await supabase.auth.getUser()).data.user.id) +const auth = useAuthStore() + const month = dayjs().format("MM") @@ -65,8 +64,8 @@ const actions = [ ] -const groups = computed(() => - [{ +const groups = computed(() => [ + { key: 'actions', commands: actions },{ @@ -99,7 +98,8 @@ const groups = computed(() => commands: dataStore.projects.map(item => { return {id: item.id, label: item.name, to: `/projects/show/${item.id}`}}) } ].filter(Boolean)) -const footerLinks = [/*{ +const footerLinks = [ + /*{ label: 'Invite people', icon: 'i-heroicons-plus', to: '/settings/members' @@ -112,56 +112,163 @@ const footerLinks = [/*{ \ No newline at end of file diff --git a/layouts/mobile.vue b/layouts/mobile.vue index 314708f..543a637 100644 --- a/layouts/mobile.vue +++ b/layouts/mobile.vue @@ -13,8 +13,9 @@ const { isHelpSlideoverOpen } = useDashboard() const supabase = useSupabaseClient() const router = useRouter() const route = useRoute() +const auth = useAuthStore() -profileStore.initializeData((await supabase.auth.getUser()).data.user.id) +//profileStore.initializeData((await supabase.auth.getUser()).data.user.id) const month = dayjs().format("MM") @@ -64,40 +65,6 @@ const actions = [ ] -const groups = computed(() => - [{ - key: 'actions', - commands: actions - },{ - key: "customers", - label: "Kunden", - commands: dataStore.customers.map(item => { return {id: item.id, label: item.name, to: `/customers/show/${item.id}`}}) - },{ - key: "vendors", - label: "Lieferanten", - commands: dataStore.vendors.map(item => { return {id: item.id, label: item.name, to: `/vendors/show/${item.id}`}}) - },{ - key: "contacts", - label: "Ansprechpartner", - commands: dataStore.contacts.map(item => { return {id: item.id, label: item.fullName, to: `/contacts/show/${item.id}`}}) - },{ - key: "products", - label: "Artikel", - commands: dataStore.products.map(item => { return {id: item.id, label: item.name, to: `/products/show/${item.id}`}}) - },{ - key: "tasks", - label: "Aufgaben", - commands: dataStore.tasks.map(item => { return {id: item.id, label: item.name, to: `/tasks/show/${item.id}`}}) - },{ - key: "plants", - label: "Objekte", - commands: dataStore.plants.map(item => { return {id: item.id, label: item.name, to: `/plants/show/${item.id}`}}) - },{ - key: "projects", - label: "Projekte", - commands: dataStore.projects.map(item => { return {id: item.id, label: item.name, to: `/projects/show/${item.id}`}}) - } - ].filter(Boolean)) const footerLinks = [/*{ label: 'Invite people', icon: 'i-heroicons-plus', @@ -111,87 +78,163 @@ const footerLinks = [/*{ diff --git a/middleware/auth.global.ts b/middleware/auth.global.ts new file mode 100644 index 0000000..8d0d033 --- /dev/null +++ b/middleware/auth.global.ts @@ -0,0 +1,17 @@ +export default defineNuxtRouteMiddleware(async (to, from) => { + const auth = useAuthStore() + + + + // Wenn nicht eingeloggt → auf /login (außer er will schon dahin) + if (!auth.user && !["/login", "/password-reset"].includes(to.path)) { + return navigateTo("/login") + } + + // Wenn eingeloggt → von /login auf /dashboard umleiten + if (auth.user && !auth.user?.must_change_password && to.path === "/login") { + return navigateTo("/") + } else if(auth.user && auth.user.must_change_password && to.path !== "/password-change") { + return navigateTo("/password-change") + } +}) \ No newline at end of file diff --git a/middleware/auth.ts b/middleware/auth.ts deleted file mode 100644 index 0bdf3b3..0000000 --- a/middleware/auth.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default defineNuxtRouteMiddleware((to, _from) => { - const user = useSupabaseUser() - const router = useRouter() - if (!user.value) { - //useCookie('redirect', { path: '/' }).value = to.fullPath - return router.push("/login") - } -}) \ No newline at end of file diff --git a/middleware/redirectToMobileIndex.ts b/middleware/redirectToMobileIndex.ts index 6c4b111..2ccfddc 100644 --- a/middleware/redirectToMobileIndex.ts +++ b/middleware/redirectToMobileIndex.ts @@ -3,7 +3,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => { console.log(await useCapacitor().getIsPhone()) - if(await useCapacitor().getIsPhone()) { + if(await useCapacitor().getIsPhone() && _from.path !== '/mobile') { return router.push('/mobile') } -}) \ No newline at end of file +}) diff --git a/nuxt.config.ts b/nuxt.config.ts index 9f690eb..0b7f3a5 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -25,7 +25,7 @@ export default defineNuxtConfig({ transpile: ['@vuepic/vue-datepicker'] }, - modules: ['@pinia/nuxt', '@nuxt/ui', '@nuxt/content', '@nuxtjs/supabase', "nuxt-editorjs", '@nuxtjs/fontaine', 'nuxt-viewport', 'nuxt-tiptap-editor', '@nuxtjs/leaflet'], + modules: ['@pinia/nuxt', '@nuxt/ui', '@nuxtjs/supabase', "nuxt-editorjs", '@nuxtjs/fontaine', 'nuxt-viewport', 'nuxt-tiptap-editor', '@nuxtjs/leaflet'], routeRules: { '/printing': {ssr: false} @@ -34,7 +34,8 @@ export default defineNuxtConfig({ supabase: { key: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InV3cHB2Y3hmbHJjc2lidXpzYmlsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDA5MzgxOTQsImV4cCI6MjAxNjUxNDE5NH0.CkxYSQH0uLfwx9GVUlO6AYMU2FMLAxGMrwEKvyPv7Oo", - url: "https://uwppvcxflrcsibuzsbil.supabase.co" + url: "https://uwppvcxflrcsibuzsbil.supabase.co", + redirect:false }, vite: { @@ -56,5 +57,13 @@ export default defineNuxtConfig({ prefix: "Tiptap" }, + runtimeConfig: { + + public: { + apiBase: '', + pdfLicense: '' + } + }, + compatibilityDate: '2024-12-18' }) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index 15c0d5d..0103f48 100644 --- a/package.json +++ b/package.json @@ -10,21 +10,21 @@ "postinstall": "nuxt prepare" }, "devDependencies": { + "@capacitor/cli": "^7.0.0", "@nuxtjs/leaflet": "^1.2.3", "@nuxtjs/supabase": "^1.1.4", "nuxt": "^3.14.1592", "nuxt-tiptap-editor": "^1.2.0", - "vite-plugin-pwa": "^0.17.3", "vue": "^3.5.13", "vue-router": "^4.2.5" }, "dependencies": { - "@capacitor/android": "^7.1.0", - "@capacitor/cli": "^7.1.0", - "@capacitor/core": "^7.1.0", + "@capacitor/android": "^7.0.0", + "@capacitor/core": "^7.0.0", "@capacitor/device": "^7.0.0", - "@capacitor/ios": "^7.1.0", + "@capacitor/ios": "^7.0.0", "@capacitor/network": "^7.0.0", + "@capacitor/preferences": "^7.0.0", "@fullcalendar/core": "^6.1.10", "@fullcalendar/daygrid": "^6.1.10", "@fullcalendar/interaction": "^6.1.10", @@ -34,7 +34,6 @@ "@fullcalendar/timegrid": "^6.1.10", "@fullcalendar/vue3": "^6.1.10", "@iconify/json": "^2.2.171", - "@nuxt/content": "^2.9.0", "@nuxt/ui-pro": "^1.6.0", "@nuxtjs/fontaine": "^0.4.1", "@nuxtjs/google-fonts": "^3.1.0", @@ -49,6 +48,7 @@ "@tiptap/vue-3": "^2.1.15", "@vicons/ionicons5": "^0.12.0", "@vue-leaflet/vue-leaflet": "^0.10.1", + "@vue-pdf-viewer/viewer": "^3.0.1", "@vuepic/vue-datepicker": "^7.4.0", "@zip.js/zip.js": "^2.7.32", "array-sort": "^1.0.0", @@ -81,4 +81,4 @@ "vuetify": "^3.4.0-beta.1", "zebra-browser-print-wrapper": "^0.1.4" } -} +} \ No newline at end of file diff --git a/pages/accounts/index.vue b/pages/accounts/index.vue index 30038a6..e955732 100644 --- a/pages/accounts/index.vue +++ b/pages/accounts/index.vue @@ -1,11 +1,6 @@ - - - - \ No newline at end of file diff --git a/pages/banking/index.vue b/pages/banking/index.vue index ae54624..a2ebb1f 100644 --- a/pages/banking/index.vue +++ b/pages/banking/index.vue @@ -2,10 +2,6 @@ import dayjs from "dayjs"; -definePageMeta({ - middleware: "auth" -}) - defineShortcuts({ '/': () => { //console.log(searchinput) @@ -14,17 +10,15 @@ defineShortcuts({ } }) -const profileStore = useProfileStore() const tempStore = useTempStore() const router = useRouter() -const supabase = useSupabaseClient() const bankstatements = ref([]) const bankaccounts = ref([]) const setupPage = async () => { - bankstatements.value = (await supabase.from("bankstatements").select("*, statementallocations(*)").is("archived",false).eq('tenant', profileStore.currentTenant).order("date", {ascending:false})).data - bankaccounts.value = await useSupabaseSelect("bankaccounts") + bankstatements.value = (await useEntities("bankstatements").select("*, statementallocations(*)", "date", false)) + bankaccounts.value = await useEntities("bankaccounts").select() } const templateColumns = [ diff --git a/pages/banking/statements/[mode]/[[id]].vue b/pages/banking/statements/[mode]/[[id]].vue index de40f5a..b23655f 100644 --- a/pages/banking/statements/[mode]/[[id]].vue +++ b/pages/banking/statements/[mode]/[[id]].vue @@ -3,9 +3,7 @@ import dayjs from "dayjs"; import {filter} from "vuedraggable/dist/vuedraggable.common.js"; -definePageMeta({ - middleware: "auth" -}) + defineShortcuts({ 'backspace': () => { @@ -18,7 +16,6 @@ const profileStore = useProfileStore() const route = useRoute() const router = useRouter() const mode = ref(route.params.mode || "show") -const supabase = useSupabaseClient() const itemInfo = ref({statementallocations:[]}) const oldItemInfo = ref({}) @@ -38,21 +35,22 @@ const ownaccounts = ref([]) const loading = ref(true) const setup = async () => { + loading.value = true if(route.params.id) { - itemInfo.value = (await supabase.from("bankstatements").select("*, statementallocations(*, cd_id(*), ii_id(*))").eq("id",route.params.id).single()).data //dataStore.bankstatements.find(i => i.id === Number(route.params.id)) + itemInfo.value = await useEntities("bankstatements").selectSingle(route.params.id,"*, statementallocations(*, cd_id(*), ii_id(*))", undefined, undefined, true) } if(itemInfo.value) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value)) manualAllocationSum.value = calculateOpenSum.value - createddocuments.value = (await useSupabaseSelect("createddocuments","*, statementallocations(*), customer(id,name)")) + createddocuments.value = (await useEntities("createddocuments").select("*, statementallocations(*), customer(id,name)")) const documents = createddocuments.value.filter(i => i.type === "invoices" ||i.type === "advanceInvoices") - const incominginvoices = (await useSupabaseSelect("incominginvoices","*, statementallocations(*), vendor(id,name)")).filter(i => i.state === "Gebucht") + const incominginvoices = (await useEntities("incominginvoices").select("*, statementallocations(*), vendor(id,name)")).filter(i => i.state === "Gebucht") - accounts.value = (await supabase.from("accounts").select().order("number",{ascending: true})).data - ownaccounts.value = (await supabase.from("ownaccounts").select()).data - customers.value = (await supabase.from("customers").select()).data - vendors.value = (await supabase.from("vendors").select()).data + accounts.value = (await useEntities("accounts").selectSpecial("*","number",true)) + ownaccounts.value = (await useEntities("ownaccounts").select()) + customers.value = (await useEntities("customers").select()) + vendors.value = (await useEntities("vendors").select()) openDocuments.value = documents.filter(i => i.statementallocations.reduce((n,{amount}) => n + amount, 0).toFixed(2) !== useSum().getCreatedDocumentSum(i,createddocuments.value).toFixed(2)) openDocuments.value = openDocuments.value.map(i => { @@ -71,15 +69,12 @@ const setup = async () => { allocatedIncomingInvoices.value = incominginvoices.filter(i => i.statementallocations.find(x => x.bs_id === itemInfo.value.id)) console.log(allocatedDocuments.value) console.log(allocatedIncomingInvoices.value) - //openIncomingInvoices.value = (await useSupabaseSelect("incominginvoices","*, statementallocations(*), vendor(*)")).filter(i => i.statementallocations.length === 0 ) - openIncomingInvoices.value = (await useSupabaseSelect("incominginvoices","*, statementallocations(*), vendor(*)")).filter(i => i.statementallocations.reduce((n,{amount}) => n + amount, 0).toFixed(2) !== getInvoiceSum(i,false)) + openIncomingInvoices.value = (await useEntities("incominginvoices").select("*, statementallocations(*), vendor(*)")).filter(i => i.statementallocations.reduce((n,{amount}) => n + amount, 0).toFixed(2) !== getInvoiceSum(i,false)) //console.log(openIncomingInvoices.value) // return incominginvoices.value.filter(i => bankstatements.value.filter(x => x.assignments.find(y => y.type === 'incomingInvoice' && y.id === i.id)).length === 0) - let allocations = (await supabase.from("createddocuments").select(`*, statementallocations(*)`).eq("id",50)).data - loading.value = false } @@ -151,15 +146,17 @@ const showMoreWithoutRecipe = ref(false) const showMoreText = ref(false) const saveAllocation = async (allocation) => { - + //TODO: BACKEND CHANGE SAVE/REMOVE console.log(allocation) - const {data,error} = await supabase.from("statementallocations").insert({ - ...allocation, - tenant: profileStore.currentTenant - }).select() + const res = await useNuxtApp().$api("/api/banking/statements",{ + method: "POST", + body: { + data: allocation + } + }) - if(data) { + if(res) { await setup() accountToSave.value = null vendorAccountToSave.value = null @@ -173,7 +170,9 @@ const saveAllocation = async (allocation) => { } const removeAllocation = async (allocationId) => { - const {data,error} = await supabase.from("statementallocations").delete().eq("id",allocationId) + const res = await useNuxtApp().$api(`/api/banking/statements/${allocationId}`,{ + method: "DELETE" + }) await setup() } @@ -202,15 +201,7 @@ const archiveStatement = async () => { let temp = itemInfo.value delete temp.statementallocations - await dataStore.updateItem("bankstatements", {...temp,archived:true}) - - - const {data,error} = await supabase.from("historyitems").insert({ - createdBy: useProfileStore().activeProfile.id, - tenant: useProfileStore().currentTenant, - text: "Bankbuchung archiviert", - bankStatement: itemInfo.value.id - }) + await useEntities("bankstatements").archive(temp.id) } @@ -254,19 +245,12 @@ const archiveStatement = async () => { @@ -356,7 +340,9 @@ const archiveStatement = async () => { Konto: + - - - - -
-
-
- -
-
-
- {{message.text}} -
- -
-
- -
- {{message.text}} -
-
-
-
- - - -
- - - - Senden - - - - -
-
- - - - - - \ No newline at end of file diff --git a/pages/chats/create.vue b/pages/chats/create.vue deleted file mode 100644 index 659260b..0000000 --- a/pages/chats/create.vue +++ /dev/null @@ -1,119 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/chats/index.vue b/pages/chats/index.vue deleted file mode 100644 index 9b38686..0000000 --- a/pages/chats/index.vue +++ /dev/null @@ -1,125 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/chats/show/[id].vue b/pages/chats/show/[id].vue deleted file mode 100644 index 2b480d6..0000000 --- a/pages/chats/show/[id].vue +++ /dev/null @@ -1,122 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/communication/historyItems/index.vue b/pages/communication/historyItems/index.vue deleted file mode 100644 index 8c81f86..0000000 --- a/pages/communication/historyItems/index.vue +++ /dev/null @@ -1,84 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/contacts/[mode]/[[id]].vue b/pages/contacts/[mode]/[[id]].vue deleted file mode 100644 index 65f491f..0000000 --- a/pages/contacts/[mode]/[[id]].vue +++ /dev/null @@ -1,340 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/contacts/index.vue b/pages/contacts/index.vue deleted file mode 100644 index a1cf1aa..0000000 --- a/pages/contacts/index.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/createDocument/edit/[[id]].vue b/pages/createDocument/edit/[[id]].vue index 2f8b5b4..4975eba 100644 --- a/pages/createDocument/edit/[[id]].vue +++ b/pages/createDocument/edit/[[id]].vue @@ -9,13 +9,11 @@ const dataStore = useDataStore() const profileStore = useProfileStore() const route = useRoute() const router = useRouter() -const supabase = useSupabaseClient() const modal = useModal() +const auth = useAuthStore() + -definePageMeta({ - middleware: "auth" -}) const itemInfo = ref({ @@ -37,17 +35,15 @@ const itemInfo = ref({ deliveryDateEnd: null, deliveryDateType: "Lieferdatum", dateOfPerformance: null, - paymentDays: profileStore.ownTenant.standardPaymentDays, + paymentDays: auth.activeTenantData.standardPaymentDays, customSurchargePercentage: 0, - createdBy: profileStore.activeProfile.id, + createdBy: auth.user.id, title: null, description: null, startText: null, endText: null, - rows: [ - - ], - contactPerson: profileStore.activeProfile.id, + rows: [], + contactPerson: auth.user.id, contactPersonName: null, contactTel: null, contactEMail: null, @@ -63,7 +59,7 @@ const itemInfo = ref({ usedAdvanceInvoices: [] }) -console.log(profileStore.ownTenant) +console.log(auth.activeTenantData) const letterheads = ref([]) const createddocuments = ref([]) @@ -78,61 +74,69 @@ const selectedServicecategorie = ref(null) const customers = ref([]) const contacts = ref([]) const texttemplates = ref([]) +const units = ref([]) +const tenantUsers = ref([]) +const setupData = async () => { + letterheads.value = (await useEntities("letterheads").select("*")).filter(i => i.documentTypes.length === 0 || i.documentTypes.includes(itemInfo.value.type)) + createddocuments.value = await useEntities("createddocuments").select("*") + projects.value = await useEntities("projects").select("*") + plants.value = await useEntities("plants").select("*") + services.value = await useEntities("services").select("*") + servicecategories.value = await useEntities("servicecategories").select("*") + products.value = await useEntities("products").select("*") + productcategories.value = await useEntities("productcategories").select("*") + customers.value = await useEntities("customers").select("*", "customerNumber") + contacts.value = await useEntities("contacts").select("*") + texttemplates.value = await useEntities("texttemplates").select("*") + units.value = await useEntities("units").selectSpecial("*") + tenantUsers.value = (await useNuxtApp().$api(`/api/tenant/users`, { + method: "GET" + })).users +} const loaded = ref(false) const setupPage = async () => { + await setupData() - letterheads.value = (await useSupabaseSelect("letterheads","*")).filter(i => i.documentTypes.length === 0 || i.documentTypes.includes(itemInfo.value.type)) - createddocuments.value = (await useSupabaseSelect("createddocuments","*")) - projects.value = (await useSupabaseSelect("projects","*")) - plants.value = (await useSupabaseSelect("plants","*")) - services.value = (await useSupabaseSelect("services","*")) - servicecategories.value = (await useSupabaseSelect("servicecategories","*")) - products.value = (await useSupabaseSelect("products","*")) - productcategories.value = (await useSupabaseSelect("productcategories","*")) - customers.value = (await useSupabaseSelect("customers","*","customerNumber")) - contacts.value = (await useSupabaseSelect("contacts","*")) - texttemplates.value = (await useSupabaseSelect("texttemplates","*")) - if(productcategories.value.length > 0) selectedProductcategorie.value = productcategories.value[0].id - if(servicecategories.value.length > 0) selectedServicecategorie.value = servicecategories.value[0].id + if (productcategories.value.length > 0) selectedProductcategorie.value = productcategories.value[0].id + if (servicecategories.value.length > 0) selectedServicecategorie.value = servicecategories.value[0].id - if(route.params) { - if(route.params.id) { - itemInfo.value = await useSupabaseSelectSingle("createddocuments", route.params.id) + if (route.params) { + if (route.params.id) { + console.log(route.params) + itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id) checkCompatibilityWithInputPrice() } - if(itemInfo.value.project) await checkForOpenAdvanceInvoices() - if(!itemInfo.value.deliveryDateType) itemInfo.value.deliveryDateType = "Lieferdatum" + if (!itemInfo.value.deliveryDateType) itemInfo.value.deliveryDateType = "Lieferdatum" - if(itemInfo.value.rows.find(i => i.agriculture)) { + if (itemInfo.value.rows.find(i => i.agriculture)) { processDieselPosition() } } - if(route.query) { - if(route.query.type) itemInfo.value.type = route.query.type + if (route.query) { + if (route.query.type) itemInfo.value.type = route.query.type - if(!itemInfo.value.startText && !itemInfo.value.endText) { + if (!itemInfo.value.startText && !itemInfo.value.endText) { setDocumentTypeConfig(true) } else { setDocumentTypeConfig(false) } - setContactPersonData() - if(route.query.linkedDocuments) { + if (route.query.linkedDocuments) { console.log(route.query.loadMode) - if(route.query.loadMode === "deliveryNotes") { - let linkedDocuments = (await supabase.from("createddocuments").select().in("id",JSON.parse(route.query.linkedDocuments))).data + if (route.query.loadMode === "deliveryNotes") { + let linkedDocuments = (await useEntities("createddocuments").select()).filter(i => JSON.parse(route.query.linkedDocuments).includes(i.id)) //TODO: Implement Checking for Same Customer, Contact and Project @@ -148,15 +152,15 @@ const setupPage = async () => { linkedDocuments.forEach(doc => { let lastId = 0 itemInfo.value.rows.forEach(row => { - if(row.id > lastId) lastId = row.id + if (row.id > lastId) lastId = row.id }) - if(dayjs(doc.documentDate).isBefore(firstDate) || !firstDate) firstDate = doc.documentDate - if(dayjs(doc.documentDate).isAfter(lastDate) || !lastDate) lastDate = doc.documentDate + if (dayjs(doc.documentDate).isBefore(firstDate) || !firstDate) firstDate = doc.documentDate + if (dayjs(doc.documentDate).isAfter(lastDate) || !lastDate) lastDate = doc.documentDate itemInfo.value.rows.push(...[ { - id:uuidv4(), + id: uuidv4(), mode: "title", text: `${doc.title} vom ${dayjs(doc.documentDate).format("DD.MM.YYYY")}` }, @@ -181,7 +185,7 @@ const setupPage = async () => { console.log(linkedDocuments) - if(linkedDocuments.find(i => i.rows.find( x => x.agriculture.dieselUsage))){ + if (linkedDocuments.find(i => i.rows.find(x => x.agriculture.dieselUsage))) { console.log("has diesel") //Remove Existing Total Diesel Pos @@ -191,7 +195,7 @@ const setupPage = async () => { //Add Total Title itemInfo.value.rows.push({ - id:uuidv4(), + id: uuidv4(), mode: "title", text: "Allgemein" }) @@ -199,8 +203,8 @@ const setupPage = async () => { processDieselPosition() } - } else if(route.query.loadMode === "finalInvoice") { - let linkedDocuments = (await supabase.from("createddocuments").select().in("id",JSON.parse(route.query.linkedDocuments))).data + } else if (route.query.loadMode === "finalInvoice") { + let linkedDocuments = (await useEntities("createddocuments").select()).filter(i => JSON.parse(route.query.linkedDocuments).includes(i.id)) //TODO: Implement Checking for Same Customer, Contact and Project @@ -213,7 +217,7 @@ const setupPage = async () => { setCustomerData() for await (const doc of linkedDocuments.filter(i => i.type === "confirmationOrders")) { - let linkedDocument = await useSupabaseSelectSingle("createddocuments",doc.id) + let linkedDocument = await useEntities("createddocuments").selectSingle(doc.id) itemInfo.value.rows.push({ mode: "title", @@ -224,7 +228,7 @@ const setupPage = async () => { } for await (const doc of linkedDocuments.filter(i => i.type === "quotes")) { - let linkedDocument = await useSupabaseSelectSingle("createddocuments",doc.id) + let linkedDocument = await useEntities("createddocuments").selectSingle(doc.id) itemInfo.value.rows.push({ mode: "title", @@ -247,7 +251,7 @@ const setupPage = async () => { taxPercent: 19, // TODO TAX PERCENTAGE discountPercent: 0, unit: 10, - inputPrice: useSum().getCreatedDocumentSumDetailed(doc).totalNet *-1, + inputPrice: useSum().getCreatedDocumentSumDetailed(doc).totalNet * -1, linkedEntitys: [ { type: "createddocuments", @@ -266,54 +270,49 @@ const setupPage = async () => { setPosNumbers() - - } - - } - if(route.query.linkedDocument) { + if (route.query.linkedDocument) { itemInfo.value.linkedDocument = route.query.linkedDocument - let linkedDocument = await useSupabaseSelectSingle("createddocuments",itemInfo.value.linkedDocument) + let linkedDocument = await useEntities("createddocuments").selectSingle(itemInfo.value.linkedDocument) - - if(route.query.optionsToImport) { + if (route.query.optionsToImport) { //Import only true let optionsToImport = JSON.parse(route.query.optionsToImport) console.log(optionsToImport) console.log(linkedDocument) - if(optionsToImport.taxType) itemInfo.value.taxType = linkedDocument.taxType - if(optionsToImport.customer) itemInfo.value.customer = linkedDocument.customer - if(optionsToImport.letterhead) itemInfo.value.letterhead = linkedDocument.letterhead - if(optionsToImport.contact) itemInfo.value.contact = linkedDocument.contact - if(optionsToImport.deliveryDateType) itemInfo.value.deliveryDateType = linkedDocument.deliveryDateType - if(optionsToImport.deliveryDate) itemInfo.value.deliveryDate = linkedDocument.deliveryDate - if(optionsToImport.deliveryDateEnd) itemInfo.value.deliveryDateEnd = linkedDocument.deliveryDateEnd - if(optionsToImport.documentDate) itemInfo.value.documentDate = linkedDocument.documentDate - if(optionsToImport.paymentDays) itemInfo.value.paymentDays = linkedDocument.paymentDays - if(optionsToImport.customSurchargePercentage) itemInfo.value.customSurchargePercentage = linkedDocument.customSurchargePercentage - if(optionsToImport.contactPerson) itemInfo.value.contactPerson = linkedDocument.contactPerson - if(optionsToImport.plant) itemInfo.value.plant = linkedDocument.plant - if(optionsToImport.project) itemInfo.value.project = linkedDocument.project - if(optionsToImport.title) itemInfo.value.title = linkedDocument.title - if(optionsToImport.description) itemInfo.value.description = linkedDocument.description - if(optionsToImport.startText) itemInfo.value.startText = linkedDocument.startText - if(optionsToImport.rows) itemInfo.value.rows = linkedDocument.rows - if(optionsToImport.endText) itemInfo.value.endText = linkedDocument.endText + if (optionsToImport.taxType) itemInfo.value.taxType = linkedDocument.taxType + if (optionsToImport.customer) itemInfo.value.customer = linkedDocument.customer + if (optionsToImport.letterhead) itemInfo.value.letterhead = linkedDocument.letterhead + if (optionsToImport.contact) itemInfo.value.contact = linkedDocument.contact + if (optionsToImport.deliveryDateType) itemInfo.value.deliveryDateType = linkedDocument.deliveryDateType + if (optionsToImport.deliveryDate) itemInfo.value.deliveryDate = linkedDocument.deliveryDate + if (optionsToImport.deliveryDateEnd) itemInfo.value.deliveryDateEnd = linkedDocument.deliveryDateEnd + if (optionsToImport.documentDate) itemInfo.value.documentDate = linkedDocument.documentDate + if (optionsToImport.paymentDays) itemInfo.value.paymentDays = linkedDocument.paymentDays + if (optionsToImport.customSurchargePercentage) itemInfo.value.customSurchargePercentage = linkedDocument.customSurchargePercentage + if (optionsToImport.contactPerson) itemInfo.value.contactPerson = linkedDocument.contactPerson + if (optionsToImport.plant) itemInfo.value.plant = linkedDocument.plant + if (optionsToImport.project) itemInfo.value.project = linkedDocument.project + if (optionsToImport.title) itemInfo.value.title = linkedDocument.title + if (optionsToImport.description) itemInfo.value.description = linkedDocument.description + if (optionsToImport.startText) itemInfo.value.startText = linkedDocument.startText + if (optionsToImport.rows) itemInfo.value.rows = linkedDocument.rows + if (optionsToImport.endText) itemInfo.value.endText = linkedDocument.endText } else { // Import all - if(process.dev) console.log(linkedDocument) + if (process.dev) console.log(linkedDocument) itemInfo.value.taxType = linkedDocument.taxType itemInfo.value.customer = linkedDocument.customer - await setCustomerData(null,true) + await setCustomerData(null, true) itemInfo.value.letterhead = linkedDocument.letterhead itemInfo.value.contact = linkedDocument.contact itemInfo.value.deliveryDateType = linkedDocument.deliveryDateType @@ -333,10 +332,9 @@ const setupPage = async () => { } - checkCompatibilityWithInputPrice() - if(route.query.loadMode === "storno") { + if (route.query.loadMode === "storno") { itemInfo.value.rows.forEach(row => { row.price = row.price * -1 }) @@ -345,7 +343,6 @@ const setupPage = async () => { itemInfo.value.usedAdvanceInvoices = linkedDocument.usedAdvanceInvoices - checkForOpenAdvanceInvoices() itemInfo.value.description = `Stornorechnung zu Rechnung ${linkedDocument.documentNumber} vom ${dayjs(linkedDocument.documentDate).format('DD.MM.YYYY')}` @@ -358,69 +355,52 @@ const setupPage = async () => { } - if(route.query.project) { + if (route.query.project) { itemInfo.value.project = Number(route.query.project) - let project = await useSupabaseSelectSingle("projects",itemInfo.value.project) + let project = await useEntities("projects").selectSingle(itemInfo.value.project) - if(!itemInfo.value.description){ + if (!itemInfo.value.description) { itemInfo.value.description = project.customerRef } - checkForOpenAdvanceInvoices() } - if(route.query.plant) { + if (route.query.plant) { itemInfo.value.plant = Number(route.query.plant) } - if(route.query.contact) itemInfo.value.contact = Number(route.query.contact) - if(route.query.customer) { + if (route.query.contact) itemInfo.value.contact = Number(route.query.contact) + if (route.query.customer) { itemInfo.value.customer = Number(route.query.customer) setCustomerData() } } - //if(itemInfo.value.project) checkForOpenAdvanceInvoices() loaded.value = true } setupPage() -const openAdvanceInvoices = ref([]) -const checkForOpenAdvanceInvoices = async () => { - console.log("Check for Open Advance Invoices") - const {data} = await supabase.from("createddocuments").select().eq("project", itemInfo.value.project).eq("advanceInvoiceResolved", false).eq("type","advanceInvoices") - const {data: usedAdvanceInvoices} = await supabase.from("createddocuments").select().in("id", itemInfo.value.usedAdvanceInvoices) - - console.log(data) - - openAdvanceInvoices.value = [...data, ...usedAdvanceInvoices.filter(i => !data.find(x => x.id === i.id))] - -} - -const addAdvanceInvoiceToInvoice = (advanceInvoice) => { - itemInfo.value.usedAdvanceInvoices.push(advanceInvoice) -} const setDocumentTypeConfig = (withTexts = false) => { - if(itemInfo.value.type === "invoices" ||itemInfo.value.type === "advanceInvoices" || itemInfo.value.type === "serialInvoices"|| itemInfo.value.type === "cancellationInvoices") { + if (itemInfo.value.type === "invoices" || itemInfo.value.type === "advanceInvoices" || itemInfo.value.type === "serialInvoices" || itemInfo.value.type === "cancellationInvoices") { itemInfo.value.documentNumberTitle = "Rechnungsnummer" itemInfo.value.title = `Rechnung-Nr. ${itemInfo.value.documentNumber ? itemInfo.value.documentNumber : "XXXX"}` - } else if(itemInfo.value.type === "quotes") { + } else if (itemInfo.value.type === "quotes") { itemInfo.value.documentNumberTitle = "Angebotsnummer" itemInfo.value.title = `Angebot-Nr. ${itemInfo.value.documentNumber ? itemInfo.value.documentNumber : "XXXX"}` - } else if(itemInfo.value.type === "deliveryNotes") { + } else if (itemInfo.value.type === "deliveryNotes") { itemInfo.value.documentNumberTitle = "Lieferscheinnummer" itemInfo.value.title = `Lieferschein-Nr. ${itemInfo.value.documentNumber ? itemInfo.value.documentNumber : "XXXX"}` - } else if(itemInfo.value.type === "confirmationOrders") { + } else if (itemInfo.value.type === "confirmationOrders") { itemInfo.value.documentNumberTitle = "Auftragsbestätigungsnr." itemInfo.value.title = `Auftragsbestätigung-Nr. ${itemInfo.value.documentNumber ? itemInfo.value.documentNumber : "XXXX"}` } - if(withTexts) { + if (withTexts) { itemInfo.value.startText = getTextTemplateByType(itemInfo.value.type).find(i => i.default && i.pos === "startText").text itemInfo.value.endText = getTextTemplateByType(itemInfo.value.type).find(i => i.default && i.pos === "endText").text //itemInfo.value.startText = texttemplates.value.find(i => i.documentType === itemInfo.value.type && i.default && i.pos === "startText").text @@ -429,7 +409,7 @@ const setDocumentTypeConfig = (withTexts = false) => { itemInfo.value.letterhead = letterheads.value[0].id - if(itemInfo.value.type === "advanceInvoices" && !itemInfo.value.rows.find(i => i.text === "Abschlagszahlung")) { + if (itemInfo.value.type === "advanceInvoices" && !itemInfo.value.rows.find(i => i.text === "Abschlagszahlung")) { itemInfo.value.rows.push({ @@ -450,11 +430,11 @@ const setDocumentTypeConfig = (withTexts = false) => { } const setTaxType = () => { - if(itemInfo.value.taxType === "19 UStG") { + if (itemInfo.value.taxType === "19 UStG") { itemInfo.value.rows.forEach(row => { row.taxPercent = 0 }) - } else if(itemInfo.value.taxType === "12.3 UStG") { + } else if (itemInfo.value.taxType === "12.3 UStG") { itemInfo.value.rows.forEach(row => { row.taxPercent = 0 }) @@ -463,30 +443,30 @@ const setTaxType = () => { const setCustomerData = async (customerId, loadOnlyAdress = false) => { - if(customerId){ + if (customerId) { itemInfo.value.customer = customerId } - customers.value = await useSupabaseSelect("customers") + customers.value = await useEntities("customers").select() let customer = customers.value.find(i => i.id === itemInfo.value.customer) console.log(customer) itemInfo.value.contact = null - if(customer) { + if (customer) { itemInfo.value.address.street = customer.infoData.street itemInfo.value.address.zip = customer.infoData.zip itemInfo.value.address.city = customer.infoData.city itemInfo.value.address.special = customer.infoData.special - if(!loadOnlyAdress && customer.customPaymentDays) itemInfo.value.paymentDays = customer.customPaymentDays + if (!loadOnlyAdress && customer.customPaymentDays) itemInfo.value.paymentDays = customer.customPaymentDays - if(!loadOnlyAdress && customer.customSurchargePercentage) { + if (!loadOnlyAdress && customer.customSurchargePercentage) { itemInfo.value.customSurchargePercentage = customer.customSurchargePercentage updateCustomSurcharge() } - if(!loadOnlyAdress && contacts.value.filter(i => i.customer === itemInfo.value.customer).length === 1) { + if (!loadOnlyAdress && contacts.value.filter(i => i.customer === itemInfo.value.customer).length === 1) { itemInfo.value.contact = contacts.value.filter(i => i.customer === itemInfo.value.customer)[0].id } @@ -496,10 +476,12 @@ const setCustomerData = async (customerId, loadOnlyAdress = false) => { } const setContactPersonData = async () => { - //console.log(itemInfo.value.contactPerson) - let profile = await useSupabaseSelectSingle("profiles",itemInfo.value.contactPerson, '*') + //console.log(itemInfo.value.contactPerson) //TODO: BACKEND CHANGE Set Profile + let profile = (await useNuxtApp().$api(`/api/user/${itemInfo.value.created_by}`, { + method: "GET" + })).profile - itemInfo.value.contactPersonName = profile.fullName + itemInfo.value.contactPersonName = auth.profile.full_name itemInfo.value.contactTel = profile.mobileTel || profile.fixedTel || "" itemInfo.value.contactEMail = profile.email @@ -512,17 +494,17 @@ const advanceInvoiceData = ref({ part: 0 }) const importPositions = () => { - if(itemInfo.value.type === 'advanceInvoices') { - if(advanceInvoiceData.value.totalSumNet !== 0 && advanceInvoiceData.value.partPerPecentage !== 0 && advanceInvoiceData.value.part !== 0) { + if (itemInfo.value.type === 'advanceInvoices') { + if (advanceInvoiceData.value.totalSumNet !== 0 && advanceInvoiceData.value.partPerPecentage !== 0 && advanceInvoiceData.value.part !== 0) { showAdvanceInvoiceCalcModal.value = false let lastId = 0 itemInfo.value.rows.forEach(row => { - if(row.id > lastId) lastId = row.id + if (row.id > lastId) lastId = row.id }) itemInfo.value.rows.push({ - id: lastId +1, + id: lastId + 1, mode: "free", text: "Abschlagszahlung", quantity: 1, @@ -540,27 +522,27 @@ const importPositions = () => { } const getRowAmount = (row) => { - return String(Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(2)).replace('.',',') + return String(Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) / 100)).toFixed(2)).replace('.', ',') } const getRowAmountUndiscounted = (row) => { - return String(Number(Number(row.quantity) * Number(row.price)).toFixed(2)).replace('.',',') + return String(Number(Number(row.quantity) * Number(row.price)).toFixed(2)).replace('.', ',') } const addPosition = (mode) => { let lastId = 0 itemInfo.value.rows.forEach(row => { - if(row.id > lastId) lastId = row.id + if (row.id > lastId) lastId = row.id }) let taxPercentage = 19 - if(['13b UStG','19 UStG','12.3 UStG'].includes(itemInfo.value.taxType)) { + if (['13b UStG', '19 UStG', '12.3 UStG'].includes(itemInfo.value.taxType)) { taxPercentage = 0 } - if(mode === 'free'){ + if (mode === 'free') { let rowData = { id: uuidv4(), mode: "free", @@ -574,9 +556,9 @@ const addPosition = (mode) => { linkedEntitys: [] } - itemInfo.value.rows.push({...rowData, ...profileStore.ownTenant.extraModules.includes("agriculture") ? {agriculture: {}}: {}}) + itemInfo.value.rows.push({...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}}) - } else if(mode === 'normal'){ + } else if (mode === 'normal') { itemInfo.value.rows.push({ id: uuidv4(), mode: "normal", @@ -588,7 +570,7 @@ const addPosition = (mode) => { unit: 1, linkedEntitys: [] }) - } else if(mode === 'service'){ + } else if (mode === 'service') { let rowData = { id: uuidv4(), mode: "service", @@ -602,20 +584,20 @@ const addPosition = (mode) => { } //Push Agriculture Holder only if Module is activated - itemInfo.value.rows.push({...rowData, ...profileStore.ownTenant.extraModules.includes("agriculture") ? {agriculture: {}}: {}}) - } else if(mode === "pagebreak") { + itemInfo.value.rows.push({...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}}) + } else if (mode === "pagebreak") { itemInfo.value.rows.push({ id: uuidv4(), mode: "pagebreak", linkedEntitys: [] }) - } else if(mode === "title") { + } else if (mode === "title") { itemInfo.value.rows.push({ id: uuidv4(), mode: "title", linkedEntitys: [] }) - } else if(mode === "text") { + } else if (mode === "text") { itemInfo.value.rows.push({ id: uuidv4(), mode: "text", @@ -636,69 +618,116 @@ const removePosition = (id) => { } const findDocumentErrors = computed(() => { - let errors = [] + let errors = [] - if(itemInfo.value.customer === null) errors.push({message: "Es ist kein Kunde ausgewählt", type: "breaking"}) - if(itemInfo.value.contact === null) errors.push({message: "Es ist kein Kontakt ausgewählt", type: "info"}) - if(itemInfo.value.letterhead === null) errors.push({message: "Es ist kein Briefpapier ausgewählt", type: "breaking"}) - if(itemInfo.value.address.street === null) errors.push({message: "Es ist keine Straße im Adressat angegeben", type: "breaking"}) - if(itemInfo.value.address.zip === null) errors.push({message: "Es ist keine Postleitzahl im Adressat angegeben", type: "breaking"}) - if(itemInfo.value.address.city === null) errors.push({message: "Es ist keine Stadt im Adressat angegeben", type: "breaking"}) + if (itemInfo.value.customer === null) errors.push({message: "Es ist kein Kunde ausgewählt", type: "breaking"}) + if (itemInfo.value.contact === null) errors.push({message: "Es ist kein Kontakt ausgewählt", type: "info"}) + if (itemInfo.value.letterhead === null) errors.push({message: "Es ist kein Briefpapier ausgewählt", type: "breaking"}) + if (itemInfo.value.created_by === null || !itemInfo.value.created_by) errors.push({message: "Es ist kein Ansprechpartner ausgewählt", type: "breaking"}) + if (itemInfo.value.address.street === null) errors.push({ + message: "Es ist keine Straße im Adressat angegeben", + type: "breaking" + }) + if (itemInfo.value.address.zip === null) errors.push({ + message: "Es ist keine Postleitzahl im Adressat angegeben", + type: "breaking" + }) + if (itemInfo.value.address.city === null) errors.push({ + message: "Es ist keine Stadt im Adressat angegeben", + type: "breaking" + }) - if(itemInfo.value.project === null) errors.push({message: "Es ist kein Projekt ausgewählt", type: "info"}) + if (itemInfo.value.project === null) errors.push({message: "Es ist kein Projekt ausgewählt", type: "info"}) - if(['Lieferzeitraum','Leistungszeitraum'].includes(itemInfo.value.deliveryDateType) && itemInfo.value.type !== "serialInvoices") { - if(itemInfo.value.deliveryDateEnd === null) errors.push({message: `Es ist kein Enddatum für den ${itemInfo.value.deliveryDateType} angegeben`, type: "breaking"}) - } + if (['Lieferzeitraum', 'Leistungszeitraum'].includes(itemInfo.value.deliveryDateType) && itemInfo.value.type !== "serialInvoices") { + if (itemInfo.value.deliveryDateEnd === null) errors.push({ + message: `Es ist kein Enddatum für den ${itemInfo.value.deliveryDateType} angegeben`, + type: "breaking" + }) + } - if(itemInfo.value.rows.length === 0) { - errors.push({message: "Es sind keine Positionen angegeben", type: "breaking"}) - } else { - itemInfo.value.rows.forEach(row => { + if (itemInfo.value.rows.length === 0) { + errors.push({message: "Es sind keine Positionen angegeben", type: "breaking"}) + } else { + itemInfo.value.rows.forEach(row => { - if(itemInfo.value.type !== "quotes" && row.optional) { - errors.push({message: `Position ${row.pos} ist als Optional markiert. Dies wird nur in Angeboten unterstützt.`, type: "breaking"}) - } + if (itemInfo.value.type !== "quotes" && row.optional) { + errors.push({ + message: `Position ${row.pos} ist als Optional markiert. Dies wird nur in Angeboten unterstützt.`, + type: "breaking" + }) + } - if(itemInfo.value.type !== "quotes" && row.alternative) { - errors.push({message: `Position ${row.pos} ist als Alternativ markiert. Dies wird nur in Angeboten unterstützt.`, type: "breaking"}) - } - - if(row.mode === "normal" && !row.product) errors.push({message: `In Position ${row.pos} ist kein Artikel ausgewählt`, type: "breaking"}) - if(row.mode === "service" && !row.service) errors.push({message: `In Position ${row.pos} ist keine Leistung ausgewählt`, type: "breaking"}) - if(row.mode === "title" && !row.text) errors.push({message: `In Position ${row.pos} ist kein Titel hinterlegt`, type: "breaking"}) - //if(row.mode === "text" && !row.text) errors.push({message: `In einer Freitext Position ist kein Titel hinterlegt`, type: "breaking"}) - if(row.mode === "free" && !row.text) errors.push({message: `In einer freien Position ist kein Titel hinterlegt`, type: "breaking"}) - - if(["normal","service","free"].includes(row.mode)){ - - if(!row.taxPercent && typeof row.taxPercent !== "number") errors.push({message: `In Position ${row.pos} ist kein Steuersatz hinterlegt`, type: "breaking"}) - if(!row.price && typeof row.price !== "number") errors.push({message: `In Position ${row.pos} ist kein Preis hinterlegt`, type: "breaking"}) - if(!row.unit) errors.push({message: `In Position ${row.pos} ist keine Einheit hinterlegt`, type: "breaking"}) - - } - - if(row.agriculture){ - if(row.agriculture.dieselUsage && (!row.agriculture.dieselPrice && typeof row.agriculture.dieselPrice !== "number")) { - errors.push({message: `In Position ${row.pos} ist kein Dieselpreis hinterlegt`, type: "breaking"}) - } else if(row.agriculture.dieselUsage && row.agriculture.dieselPrice === 0) { - errors.push({message: `In Position ${row.pos} ist 0,00 € als Dieselpreis hinterlegt`, type: "info"}) - } - } + if (itemInfo.value.type !== "quotes" && row.alternative) { + errors.push({ + message: `Position ${row.pos} ist als Alternativ markiert. Dies wird nur in Angeboten unterstützt.`, + type: "breaking" + }) + } + if (row.mode === "normal" && !row.product) errors.push({ + message: `In Position ${row.pos} ist kein Artikel ausgewählt`, + type: "breaking" }) - } + if (row.mode === "service" && !row.service) errors.push({ + message: `In Position ${row.pos} ist keine Leistung ausgewählt`, + type: "breaking" + }) + if (row.mode === "title" && !row.text) errors.push({ + message: `In Position ${row.pos} ist kein Titel hinterlegt`, + type: "breaking" + }) + //if(row.mode === "text" && !row.text) errors.push({message: `In einer Freitext Position ist kein Titel hinterlegt`, type: "breaking"}) + if (row.mode === "free" && !row.text) errors.push({ + message: `In einer freien Position ist kein Titel hinterlegt`, + type: "breaking" + }) + + if (["normal", "service", "free"].includes(row.mode)) { + + if (!row.taxPercent && typeof row.taxPercent !== "number") errors.push({ + message: `In Position ${row.pos} ist kein Steuersatz hinterlegt`, + type: "breaking" + }) + if (!row.price && typeof row.price !== "number") errors.push({ + message: `In Position ${row.pos} ist kein Preis hinterlegt`, + type: "breaking" + }) + if (!row.unit) errors.push({message: `In Position ${row.pos} ist keine Einheit hinterlegt`, type: "breaking"}) + + } + + if (row.agriculture) { + if (row.agriculture.dieselUsage && (!row.agriculture.dieselPrice && typeof row.agriculture.dieselPrice !== "number")) { + errors.push({message: `In Position ${row.pos} ist kein Dieselpreis hinterlegt`, type: "breaking"}) + } else if (row.agriculture.dieselUsage && row.agriculture.dieselPrice === 0) { + errors.push({message: `In Position ${row.pos} ist 0,00 € als Dieselpreis hinterlegt`, type: "info"}) + } + } + + }) + } - - - if(itemInfo.value.type === "serialInvoices") { - if(!itemInfo.value.serialConfig.intervall) errors.push({message: `Kein Intervall für die Ausführung festgelegt`, type: "breaking"}) - if(!itemInfo.value.serialConfig.dateDirection) errors.push({message: `Kein Richtung für die Datierung festgelegt`, type: "breaking"}) - if(!itemInfo.value.serialConfig.firstExecution) errors.push({message: `Kein Datum für die erste Ausführung festgelegt`, type: "breaking"}) - if(!itemInfo.value.serialConfig.executionUntil) errors.push({message: `Kein Datum für die letzte Ausführung festgelegt`, type: "info"}) - } + if (itemInfo.value.type === "serialInvoices") { + if (!itemInfo.value.serialConfig.intervall) errors.push({ + message: `Kein Intervall für die Ausführung festgelegt`, + type: "breaking" + }) + if (!itemInfo.value.serialConfig.dateDirection) errors.push({ + message: `Kein Richtung für die Datierung festgelegt`, + type: "breaking" + }) + if (!itemInfo.value.serialConfig.firstExecution) errors.push({ + message: `Kein Datum für die erste Ausführung festgelegt`, + type: "breaking" + }) + if (!itemInfo.value.serialConfig.executionUntil) errors.push({ + message: `Kein Datum für die letzte Ausführung festgelegt`, + type: "info" + }) + } return errors.sort((a) => (a.type === "breaking") ? -1 : 1) @@ -731,17 +760,17 @@ const documentTotal = computed(() => { let totalNet0 = 0 itemInfo.value.rows.filter(i => !i.optional && !i.alternative).forEach(row => { - if(!['pagebreak','title','text'].includes(row.mode)){ - let rowPrice = Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(3) + if (!['pagebreak', 'title', 'text'].includes(row.mode)) { + let rowPrice = Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) / 100)).toFixed(3) totalNet = totalNet + Number(rowPrice) - if(row.taxPercent === 19) { + if (row.taxPercent === 19) { total19 = total19 + Number(rowPrice * 0.19) totalNet19 += Number(rowPrice) - } else if(row.taxPercent === 7) { + } else if (row.taxPercent === 7) { total7 = total7 + Number(rowPrice * 0.07) totalNet7 += Number(rowPrice) - } else if(row.taxPercent === 0) { + } else if (row.taxPercent === 0) { totalNet0 += Number(rowPrice) } } @@ -755,18 +784,18 @@ const documentTotal = computed(() => { let transferCounter = 0 itemInfo.value.rows.forEach(row => { - if(row.mode === 'title'){ + if (row.mode === 'title') { let title = `${row.pos} - ${row.text}` titleSums[title] = 0 lastTitle = title //Übertrag berechnen - titleSumsTransfer[Object.keys(titleSums)[row.pos-2]] = transferCounter + titleSumsTransfer[Object.keys(titleSums)[row.pos - 2]] = transferCounter - } else if(!['pagebreak','text'].includes(row.mode) && lastTitle !== "" && !row.optional && !row.alternative){ - titleSums[lastTitle] = Number(titleSums[lastTitle]) + Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ) - transferCounter += Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ) + } else if (!['pagebreak', 'text'].includes(row.mode) && lastTitle !== "" && !row.optional && !row.alternative) { + titleSums[lastTitle] = Number(titleSums[lastTitle]) + Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) / 100)) + transferCounter += Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) / 100)) console.log(transferCounter) } }) @@ -774,8 +803,6 @@ const documentTotal = computed(() => { console.log(titleSumsTransfer) - - let totalGross = Number(totalNet.toFixed(2)) + Number(total19.toFixed(2)) + Number(total7.toFixed(2)) let totalGrossAlreadyPaid = 0 @@ -794,21 +821,14 @@ const documentTotal = computed(() => { let sumToPay = 0 - if(itemInfo.value.type === "invoices") { + if (itemInfo.value.type === "invoices") { sumToPay = totalGross - totalGrossAlreadyPaid - } else if(itemInfo.value.type === "cancellationInvoices") { + } else if (itemInfo.value.type === "cancellationInvoices") { sumToPay = totalGross + totalGrossAlreadyPaid } - - - - - - - return { titleSums: titleSums, titleSumsTransfer: titleSumsTransfer, @@ -838,15 +858,15 @@ const documentReport = computed(() => { itemInfo.value.rows.filter(i => !i.optional && !i.alternative).forEach(row => { - if(row.product) { + if (row.product) { let product = products.value.find(i => i.id === row.product) totalProductsPurchasePrice += product.purchasePrice * row.quantity - } else if(row.service) { + } else if (row.service) { let service = services.value.find(i => i.id === row.service) - if(service.materialComposition) { + if (service.materialComposition) { service.materialComposition.forEach(entry => { let productData = products.value.find(i => i.id === entry.product) @@ -854,21 +874,20 @@ const documentReport = computed(() => { }) } - if(service.personalComposition) { + if (service.personalComposition) { service.personalComposition.forEach(entry => { totalHoursFromServices.total += entry.quantity * row.quantity totalHoursFromServices.totalPurchasePrice += entry.quantity * entry.purchasePrice * row.quantity totalHoursSellingPrice += entry.quantity * entry.price * row.quantity - if(totalHoursFromServices.byName[entry.name]) { + if (totalHoursFromServices.byName[entry.name]) { totalHoursFromServices.byName[entry.name] += entry.quantity * row.quantity } else { totalHoursFromServices.byName[entry.name] = entry.quantity * row.quantity } - }) } else { //totalHoursSellingPrice += service.sellingPriceComposed.totalWorker * row.quantity @@ -901,7 +920,7 @@ const processDieselPosition = () => { } itemInfo.value.rows.forEach(row => { - if(row.agriculture && row.agriculture.dieselUsage) { + if (row.agriculture && row.agriculture.dieselUsage) { console.log(row.agriculture) agricultureData.dieselUsageTotal += Number(row.agriculture.dieselUsage) agricultureData.dieselPriceTotal += Number(row.agriculture.dieselPrice || 0) * Number(row.agriculture.dieselUsage) @@ -912,9 +931,9 @@ const processDieselPosition = () => { }) console.log(agricultureData) - if(agricultureData.dieselUsageTotal !== 0) { + if (agricultureData.dieselUsageTotal !== 0) { - if(itemInfo.value.rows.find(i => i.key === "dieselPos")){ + if (itemInfo.value.rows.find(i => i.key === "dieselPos")) { let existingIndex = itemInfo.value.rows.findIndex(i => i.key === "dieselPos") itemInfo.value.rows[existingIndex] = { @@ -934,7 +953,7 @@ const processDieselPosition = () => { } else { itemInfo.value.rows.push({ mode: "free", - text: `${(agricultureData.dieselUsageTotal).toFixed(2).replace(".",",")} L Diesel`, + text: `${(agricultureData.dieselUsageTotal).toFixed(2).replace(".", ",")} L Diesel`, quantity: 1, unit: 10, price: agricultureData.dieselPriceTotal, @@ -945,7 +964,7 @@ const processDieselPosition = () => { itemInfo.value.rows.push({ mode: "free", - text: `${(agricultureData.adblueUsageTotal).toFixed(2).replace(".",",")} L AdBlue`, + text: `${(agricultureData.adblueUsageTotal).toFixed(2).replace(".", ",")} L AdBlue`, quantity: 1, unit: 10, price: agricultureData.adbluePriceTotal, @@ -961,15 +980,15 @@ const processDieselPosition = () => { itemInfo.value.agriculture = {...itemInfo.value.agriculture, ...agricultureData} } -const getDocumentData = () => { +const getDocumentData = async () => { let customerData = customers.value.find(i => i.id === itemInfo.value.customer) - let contactData = dataStore.getContactById(itemInfo.value.contact) - let businessInfo = profileStore.ownTenant.businessInfo + let contactData = contacts.value.find(i => i.id === itemInfo.value.contact) + let businessInfo = auth.activeTenantData.businessInfo - if(profileStore.ownTenant.extraModules.includes("agriculture")) { + if (auth.activeTenantData.extraModules.includes("agriculture")) { itemInfo.value.rows.forEach(row => { - if(row.agriculture && row.agriculture.dieselUsage) { + if (row.agriculture && row.agriculture.dieselUsage) { row.agriculture.description = `${row.agriculture.dieselUsage} L Diesel zu ${renderCurrency(row.agriculture.dieselPrice)}/L verbraucht ${row.description ? "\n" + row.description : ""}` } }) @@ -977,25 +996,25 @@ const getDocumentData = () => { let rows = itemInfo.value.rows - if(itemInfo.value.taxType === "13b UStG" || itemInfo.value.taxType === "19 UStG") { - rows = rows.map(row => { - return { - ...row, - taxPercent: 0 - } - }) + if (itemInfo.value.taxType === "13b UStG" || itemInfo.value.taxType === "19 UStG") { + rows = rows.map(row => { + return { + ...row, + taxPercent: 0 + } + }) } rows = itemInfo.value.rows.map(row => { - let unit = dataStore.units.find(i => i.id === row.unit) + let unit = units.value.find(i => i.id === row.unit) - if(!['pagebreak','title'].includes(row.mode)){ - if(row.agriculture && row.agriculture.description) { + if (!['pagebreak', 'title'].includes(row.mode)) { + if (row.agriculture && row.agriculture.description) { console.log("Row has Agri") row.descriptionText = row.agriculture.description - } else if(row.description) { + } else if (row.description) { console.log("Row has no Agri") row.descriptionText = row.description } else { @@ -1003,18 +1022,18 @@ const getDocumentData = () => { } } - if(!['pagebreak','title','text'].includes(row.mode)) { - if(row.mode === 'normal') row.text = products.value.find(i => i.id === row.product).name - if(row.mode === 'service') row.text = services.value.find(i => i.id === row.service).name + if (!['pagebreak', 'title', 'text'].includes(row.mode)) { + if (row.mode === 'normal') row.text = products.value.find(i => i.id === row.product).name + if (row.mode === 'service') row.text = services.value.find(i => i.id === row.service).name return { ...row, rowAmount: `${getRowAmount(row)} €`, - quantity: String(row.quantity).replace(".",","), + quantity: String(row.quantity).replace(".", ","), unit: unit.short, pos: String(row.pos), - price: `${String(row.price.toFixed(2)).replace(".",",")} €`, + price: `${String(row.price.toFixed(2)).replace(".", ",")} €`, discountText: `(Rabatt: ${row.discountPercent} %)` } } else { @@ -1029,27 +1048,29 @@ const getDocumentData = () => { const generateContext = (itemInfo, contactData) => { return { lohnkosten: documentReport.value.totalHoursSellingPrice ? useCurrency(documentReport.value.totalHoursSellingPrice) : null, - anrede:(contactData && contactData.salutation) || (customerData && customerData.salutation), - titel:(contactData && contactData.title) || (customerData && customerData.title), - vorname:(contactData && contactData.firstName) || (customerData && customerData.firstname), + anrede: (contactData && contactData.salutation) || (customerData && customerData.salutation), + titel: (contactData && contactData.title) || (customerData && customerData.title), + vorname: (contactData && contactData.firstName) || (customerData && customerData.firstname), nachname: (contactData && contactData.lastName) || (customerData && customerData.lastname), kundenname: customerData && customerData.name, - zahlungsziel_in_tagen:itemInfo.paymentDays, + zahlungsziel_in_tagen: itemInfo.paymentDays, diesel_gesamtverbrauch: (itemInfo.agriculture && itemInfo.agriculture.dieselUsageTotal) && itemInfo.agriculture.dieselUsageTotal } } - let contactPerson = profileStore.getProfileById(itemInfo.value.contactPerson) + let contactPerson = (await useNuxtApp().$api(`/api/user/${itemInfo.value.created_by}`, { + method: "GET" + })).profile let returnTitleSums = {} - if(Object.keys(documentTotal.value.titleSums).length > 0) { + if (Object.keys(documentTotal.value.titleSums).length > 0) { Object.keys(documentTotal.value.titleSums).forEach(key => { returnTitleSums[key] = renderCurrency(documentTotal.value.titleSums[key]) }) } let returnTitleSumsTransfer = {} - if(Object.keys(documentTotal.value.titleSumsTransfer).length > 0) { + if (Object.keys(documentTotal.value.titleSumsTransfer).length > 0) { Object.keys(documentTotal.value.titleSumsTransfer).forEach(key => { returnTitleSumsTransfer[key] = renderCurrency(documentTotal.value.titleSumsTransfer[key]) }) @@ -1072,12 +1093,12 @@ const getDocumentData = () => { zip: itemInfo.value.address.zip || customerData.infoData.zip },*/ recipient: [ - customerData.name, - ... customerData.nameAddition ? [customerData.nameAddition] : [], - ... contactData ? [`${contactData.firstName} ${contactData.lastName}`] : [], - itemInfo.value.address.street, - ... itemInfo.value.address.special ? [itemInfo.value.address.special] : [], - `${itemInfo.value.address.zip} ${itemInfo.value.address.city}`, + customerData.name, + ...customerData.nameAddition ? [customerData.nameAddition] : [], + ...contactData ? [`${contactData.firstName} ${contactData.lastName}`] : [], + itemInfo.value.address.street, + ...itemInfo.value.address.special ? [itemInfo.value.address.special] : [], + `${itemInfo.value.address.zip} ${itemInfo.value.address.city}`, ], /*info: { @@ -1098,16 +1119,16 @@ const getDocumentData = () => { { label: itemInfo.value.documentNumberTitle, content: itemInfo.value.documentNumber || "XXXX", - },{ + }, { label: "Kundennummer", content: customerData.customerNumber, - },{ + }, { label: "Belegdatum", content: itemInfo.value.documentDate ? dayjs(itemInfo.value.documentDate).format("DD.MM.YYYY") : "XXXX", }, - ... itemInfo.value.deliveryDateType !== "Kein Lieferdatum anzeigen" ? [{ - label: itemInfo.value.deliveryDateType, - content: !['Lieferzeitraum','Leistungszeitraum'].includes(itemInfo.value.deliveryDateType) ? (itemInfo.value.deliveryDate ? dayjs(itemInfo.value.deliveryDate).format("DD.MM.YYYY") : "XXXX") : `${itemInfo.value.deliveryDate ? dayjs(itemInfo.value.deliveryDate).format("DD.MM.YYYY") : "XXXX"} - ${itemInfo.value.deliveryDateEnd ? dayjs(itemInfo.value.deliveryDateEnd).format("DD.MM.YYYY") : "XXXX"}`, + ...itemInfo.value.deliveryDateType !== "Kein Lieferdatum anzeigen" ? [{ + label: itemInfo.value.deliveryDateType, + content: !['Lieferzeitraum', 'Leistungszeitraum'].includes(itemInfo.value.deliveryDateType) ? (itemInfo.value.deliveryDate ? dayjs(itemInfo.value.deliveryDate).format("DD.MM.YYYY") : "XXXX") : `${itemInfo.value.deliveryDate ? dayjs(itemInfo.value.deliveryDate).format("DD.MM.YYYY") : "XXXX"} - ${itemInfo.value.deliveryDateEnd ? dayjs(itemInfo.value.deliveryDateEnd).format("DD.MM.YYYY") : "XXXX"}`, }] : [], /*{ label: itemInfo.value.deliveryDateType, @@ -1115,24 +1136,24 @@ const getDocumentData = () => { },*/ { label: "Ansprechpartner", - content: contactPerson.fullName, + content: contactPerson.full_name, }, - ... contactPerson.fixedTel || contactPerson.mobileTel ? [{ + ...contactPerson.fixedTel || contactPerson.mobileTel ? [{ label: "Telefon", content: contactPerson.fixedTel || contactPerson.mobileTel, }] : [], - ... contactPerson.email ? [{ + ...contactPerson.email ? [{ label: "E-Mail", content: contactPerson.email, - }]: [], - ... itemInfo.value.plant ? [{ + }] : [], + ...itemInfo.value.plant ? [{ label: "Objekt", content: plants.value.find(i => i.id === itemInfo.value.plant).name, - }] : [], - ... itemInfo.value.project ? [{ + }] : [], + ...itemInfo.value.project ? [{ label: "Projekt", content: projects.value.find(i => i.id === itemInfo.value.project).name - }]: [] + }] : [] ], title: itemInfo.value.title, description: itemInfo.value.description, @@ -1144,18 +1165,18 @@ const getDocumentData = () => { label: "Nettobetrag", content: renderCurrency(documentTotal.value.totalNet), }, - ... rows.find(i => i.taxPercent === 19) ? [{ + ...rows.find(i => i.taxPercent === 19) && !["13b UStG"].includes(itemInfo.value.taxType) ? [{ label: `zzgl. 19% USt auf ${renderCurrency(documentTotal.value.totalNet19)}`, content: renderCurrency(documentTotal.value.total19), }] : [], - ... rows.find(i => i.taxPercent === 7) ? [{ + ...rows.find(i => i.taxPercent === 7) && !["13b UStG"].includes(itemInfo.value.taxType) ? [{ label: `zzgl. 7% USt auf ${renderCurrency(documentTotal.value.totalNet7)}`, content: renderCurrency(documentTotal.value.total7), - }]: [], - ...rows.find(i => i.taxPercent === 0) ? [{ + }] : [], + ...rows.find(i => i.taxPercent === 0) && !["13b UStG"].includes(itemInfo.value.taxType) ? [{ label: `zzgl. 0% USt auf ${renderCurrency(documentTotal.value.totalNet0)}`, content: renderCurrency(documentTotal.value.total0), - }] : [], + }] : [], { label: "Gesamtbetrag", content: renderCurrency(documentTotal.value.totalGross), @@ -1185,38 +1206,23 @@ const getDocumentData = () => { const showDocument = ref(false) const uri = ref("") const generateDocument = async () => { + showDocument.value = false const path = letterheads.value.find(i => i.id === itemInfo.value.letterhead).path - /*const {data,error} = await supabase.functions.invoke('create_pdf',{ + uri.value = await useFunctions().useCreatePDF(await getDocumentData(), path) + /*uri.value = await useNuxtApp().$api("/api/functions/createinvoicepdf",{ + method: "POST", body: { - invoiceData: getDocumentData(), - backgroundPath: path, - returnMode: "base64" + invoiceData: await getDocumentData(), + backgroundPath: path } })*/ - uri.value = await useFunctions().useCreatePDF(getDocumentData(), path) - - - - - //const {data,error} = await supabase.storage.from("files").download(path) - - //console.log(data) - //console.log(error) - - //console.log(JSON.stringify(getDocumentData())) - - //uri.value = `data:${data.mimeType};base64,${data.base64}` - - //uri.value = await useCreatePdf(getDocumentData(), await data.arrayBuffer()) - //alert(uri.value) showDocument.value = true - //console.log(uri.value) } const onChangeTab = (index) => { - if(index === 1) { + if (index === 1) { generateDocument() } } @@ -1225,16 +1231,16 @@ const setPosNumbers = () => { let mainIndex = 1 let subIndex = 1 let rows = itemInfo.value.rows.map(row => { - if(row.mode === 'title') { + if (row.mode === 'title') { row.pos = mainIndex mainIndex += 1 subIndex = 1 - } else if(!['pagebreak','title','text'].includes(row.mode)) { - row.pos = itemInfo.value.rows.filter(i => i.mode === "title").length === 0 ? `${subIndex}` :`${ mainIndex - 1}.${subIndex}` + } else if (!['pagebreak', 'title', 'text'].includes(row.mode)) { + row.pos = itemInfo.value.rows.filter(i => i.mode === "title").length === 0 ? `${subIndex}` : `${mainIndex - 1}.${subIndex}` subIndex += 1 } - if(!row.id) { + if (!row.id) { row.id = uuidv4() } @@ -1265,24 +1271,24 @@ const saveSerialInvoice = async () => { let data = null - if(route.params.id) { - data = await dataStore.updateItem("createddocuments", {...createData, id: itemInfo.value.id}) + if (route.params.id) { + data = await useEntities("createddocuments").update(route.params.id, createData) } else { - data = await dataStore.createNewItem("createddocuments", createData) + data = await useEntities("createddocuments").create(createData) } await router.push(`/createDocument/edit/${data.id}`) } -const saveDocument = async (state,resetup = false) => { +const saveDocument = async (state, resetup = false) => { itemInfo.value.state = state - if(state !== "Entwurf") { + if (state !== "Entwurf") { console.log("???") let type = "" - if(itemInfo.value.type === "advanceInvoices" || itemInfo.value.type === "cancellationInvoices"){ + if (itemInfo.value.type === "advanceInvoices" || itemInfo.value.type === "cancellationInvoices") { type = "invoices" } else { type = itemInfo.value.type @@ -1297,13 +1303,11 @@ const saveDocument = async (state,resetup = false) => { } - - } - if(profileStore.ownTenant.extraModules.includes("agriculture")) { + if (auth.activeTenantData.extraModules.includes("agriculture")) { itemInfo.value.rows.forEach(row => { - if(row.agriculture && row.agriculture.dieselUsage) { + if (row.agriculture && row.agriculture.dieselUsage) { row.agriculture.description = `${row.agriculture.dieselUsage} L Diesel zu ${renderCurrency(row.agriculture.dieselPrice)}/L verbraucht ${row.description ? "\n" + row.description : ""}` } }) @@ -1314,7 +1318,7 @@ const saveDocument = async (state,resetup = false) => { let descriptionText = "" - if(row.agriculture && row.agriculture.description) { + if (row.agriculture && row.agriculture.description) { descriptionText = row.agriculture.description } else { descriptionText = row.description ? row.description : null @@ -1328,7 +1332,7 @@ const saveDocument = async (state,resetup = false) => { let createData = { type: itemInfo.value.type, - taxType: ['invoices','cancellationInvoices','advanceInvoices','qoutes','confirmationOrders'].includes(itemInfo.value.type) ? itemInfo.value.taxType : null, + taxType: ['invoices', 'cancellationInvoices', 'advanceInvoices', 'qoutes', 'confirmationOrders'].includes(itemInfo.value.type) ? itemInfo.value.taxType : null, state: itemInfo.value.state || "Entwurf", customer: itemInfo.value.customer, contact: itemInfo.value.contact, @@ -1343,6 +1347,7 @@ const saveDocument = async (state,resetup = false) => { deliveryDateType: itemInfo.value.deliveryDateType, info: {}, createdBy: itemInfo.value.createdBy, + created_by: itemInfo.value.created_by, title: itemInfo.value.title, description: itemInfo.value.description, startText: itemInfo.value.startText, @@ -1357,57 +1362,71 @@ const saveDocument = async (state,resetup = false) => { report: documentReport.value } - if(route.params.id) { - await dataStore.updateItem("createddocuments", {...createData, id: itemInfo.value.id}) + if (route.params.id) { + //await dataStore.updateItem("createddocuments", {...createData, id: itemInfo.value.id}) + await useEntities("createddocuments").update(itemInfo.value.id, {...createData, id: itemInfo.value.id}) } else { - const data = await dataStore.createNewItem("createddocuments", createData) + const data = await useEntities("createddocuments").create(createData) console.log(data) await router.push(`/createDocument/edit/${data.id}`) } - if(resetup) await setupPage() + if (resetup) await setupPage() } +const selectedTab = ref(0) + const closeDocument = async () => { - loaded.value = false + if(selectedTab.value === 0) { + await generateDocument() + selectedTab.value = 1 + } else { + loaded.value = false - await saveDocument("Gebucht") + await saveDocument("Gebucht") - await generateDocument() + await generateDocument() - let fileData = {} + let fileData = {} - fileData.project = itemInfo.value.project - fileData.createddocument = itemInfo.value.id + fileData.project = itemInfo.value.project + fileData.createddocument = itemInfo.value.id - let mappedType = itemInfo.value.type + let mappedType = itemInfo.value.type - if(mappedType === "advanceInvoices" || mappedType === "cancellationInvoices"){ - mappedType = "invoices" - } - - fileData.folder = (await supabase.from("folders").select("id").eq("tenant", profileStore.currentTenant).eq("function", mappedType).eq("year",dayjs().format("YYYY")).single()).data.id - - let tag = (await supabase.from("filetags").select("id").eq("tenant", profileStore.currentTenant).eq("createddocumenttype", mappedType).single()).data - - function dataURLtoFile(dataurl, filename) { - var arr = dataurl.split(","), - mime = arr[0].match(/:(.*?);/)[1], - bstr = atob(arr[arr.length - 1]), - n = bstr.length, - u8arr = new Uint8Array(n); - while (n--) { - u8arr[n] = bstr.charCodeAt(n); + if (mappedType === "advanceInvoices" || mappedType === "cancellationInvoices") { + mappedType = "invoices" } - return new File([u8arr], filename, { type: mime }); + + const folders = await useEntities("folders").select() + console.log(folders) + fileData.folder = folders.find(i => i.function === mappedType && i.year === Number(dayjs().format("YYYY"))).id + + const tags = await useEntities("filetags").select() + fileData.type = tags.find(i => i.createddocumenttype === mappedType).id + + function dataURLtoFile(dataurl, filename) { + var arr = dataurl.split(","), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[arr.length - 1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], filename, {type: mime}); + } + + let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`) + + await useFiles().uploadFiles(fileData, [file]) + + await router.push(`/createDocument/show/${itemInfo.value.id}`) } - let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`) - await dataStore.uploadFiles(fileData, [file],[tag.id], true) - await router.push(`/createDocument/show/${itemInfo.value.id}`) } @@ -1415,11 +1434,11 @@ const getTextTemplateByType = (type, pos) => { let finalType = type - if(type === "serialInvoices") { + if (type === "serialInvoices") { finalType = "invoices" } - if(pos) { + if (pos) { return texttemplates.value.filter(i => i.documentType === finalType && i.pos === pos) } else { return texttemplates.value.filter(i => i.documentType === finalType) @@ -1430,7 +1449,7 @@ const getTextTemplateByType = (type, pos) => { const checkCompatibilityWithInputPrice = () => { itemInfo.value.rows.forEach(row => { - if(!row.inputPrice) { + if (!row.inputPrice) { row.inputPrice = row.price } }) @@ -1438,10 +1457,10 @@ const checkCompatibilityWithInputPrice = () => { const updateCustomSurcharge = () => { itemInfo.value.rows.forEach(row => { - if(!["pagebreak","title","text"].includes(row.mode) /*&& !row.linkedEntitys.find(i => i.type === "createddocuments" && i.subtype === "advanceInvoices")*/) { + if (!["pagebreak", "title", "text"].includes(row.mode) /*&& !row.linkedEntitys.find(i => i.type === "createddocuments" && i.subtype === "advanceInvoices")*/) { //setRowData(row) - row.price = Number((row.inputPrice * (1 + itemInfo.value.customSurchargePercentage /100)).toFixed(2)) + row.price = Number((row.inputPrice * (1 + itemInfo.value.customSurchargePercentage / 100)).toFixed(2)) }/* else if(!["pagebreak","title","text"].includes(row.mode) /!*&& row.linkedEntitys.find(i => i.type === "createddocuments" && i.subtype === "advanceInvoices")*!/) { @@ -1452,36 +1471,36 @@ const updateCustomSurcharge = () => { const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {}) => { console.log("Set Row Data") - if(service && service.id) { + if (service && service.id) { row.service = service.id - services.value = await useSupabaseSelect("services","*") + services.value = await useEntities("services").select("*") } - if(product && product.id) { + if (product && product.id) { row.product = product.id - product.value = await useSupabaseSelect("products","*") + products.value = await useEntities("products").select("*") } - if(row.service) { + if (row.service) { row.unit = service.unit ? service.unit : services.value.find(i => i.id === row.service).unit row.inputPrice = ((service.sellingPriceComposed.total || service.sellingPrice) ? (service.sellingPriceComposed.total || service.sellingPrice) : (services.value.find(i => i.id === row.service).sellingPriceComposed.total || services.value.find(i => i.id === row.service).sellingPrice)) row.description = service.description ? service.description : (services.value.find(i => i.id === row.service) ? services.value.find(i => i.id === row.service).description : "") - if(['13b UStG','19 UStG'].includes(itemInfo.value.taxType)) { + if (['13b UStG', '19 UStG'].includes(itemInfo.value.taxType)) { row.taxPercent = 0 } else { row.taxPercent = service.taxPercentage ? service.taxPercentage : services.value.find(i => i.id === row.service).taxPercentage } } - if(row.product) { + if (row.product) { console.log("Product Detected") row.unit = product.unit ? product.unit : products.value.find(i => i.id === row.product).unit row.inputPrice = (product.sellingPrice ? product.sellingPrice : products.value.find(i => i.id === row.product).sellingPrice) //row.price = Number((row.originalPrice * (1 + itemInfo.value.customSurchargePercentage /100)).toFixed(2)) row.description = product.description ? product.description : (products.value.find(i => i.id === row.product) ? products.value.find(i => i.id === row.product).description : "") - if(['13b UStG','19 UStG'].includes(itemInfo.value.taxType)) { + if (['13b UStG', '19 UStG'].includes(itemInfo.value.taxType)) { row.taxPercent = 0 } else { row.taxPercent = product.taxPercentage ? product.taxPercentage : products.value.find(i => i.id === row.product).taxPercentage @@ -1506,21 +1525,14 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = { - +