Merge branch 'beta'

# Conflicts:
#	components/DocumentDisplay.vue
#	components/MainNav.vue
#	composables/useRole.js
#	composables/useSupabase.js
#	pages/createDocument/edit/[[id]].vue
#	pages/files/index.vue
#	pages/inventoryitems/index.vue
#	pages/services/[mode]/[[id]].vue
#	pages/vendors/[mode]/[[id]].vue
#	stores/data.js
This commit is contained in:
2025-01-20 11:05:22 +01:00
135 changed files with 7403 additions and 11455 deletions

View File

@@ -0,0 +1,3 @@
export const useCurrency = (value,currencyString = " €") => {
return `${Number(value).toFixed(2).replace(".",",")} ${currencyString}`
}

25
composables/useError.js Normal file
View File

@@ -0,0 +1,25 @@
export const useError = (resourceType) => {
const supabase = useSupabaseClient()
const toast = useToast()
const profileStore = useProfileStore()
const logError = async (error) => {
let errorData = {
message: error,
tenant: profileStore.currentTenant,
profile: profileStore.activeProfile.id
}
const {data:supabaseData,error:supabaseError} = await supabase.from("errors").insert(errorData).select().single()
if(supabaseError) {
console.error(supabaseError)
} else if(supabaseData) {
return supabaseData.id
}
}
return { logError}
}

214
composables/useFiles.js Normal file
View File

@@ -0,0 +1,214 @@
import index from "v-calendar";
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
}
})
}
//console.log(data)
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(*)), 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}
}

View File

@@ -0,0 +1,42 @@
import axios from "axios";
import dayjs from "dayjs";
const baseURL = "https://functions.fedeo.io"
export const useFunctions = () => {
const supabase = useSupabaseClient()
const getWorkingTimesEvaluationData = async (profileId, startDate, endDate) => {
const {data:{session:{access_token}}} = await supabase.auth.getSession()
return (await axios({
method: "POST",
url: `${baseURL}/functions/workingtimeevaluation`,
data: {
profile: profileId,
startDate: dayjs(startDate).format("YYYY-MM-DD"),
endDate: dayjs(endDate).format("YYYY-MM-DD"),
},
headers: {
Authorization: `Bearer ${access_token}`
}
})).data
}
const useNextNumber = async (numberRange) => {
const {data:{session:{access_token}}} = await supabase.auth.getSession()
return (await axios({
method: "POST",
url: `${baseURL}/functions/usenextnumber`,
data: {
numberRange: numberRange,
},
headers: {
Authorization: `Bearer ${access_token}`
}
})).data.usedNumber
}
return {getWorkingTimesEvaluationData, useNextNumber}
}

View File

@@ -3,8 +3,9 @@ export const useNumberRange = (resourceType) => {
const supabase = useSupabaseClient()
const dataStore = useDataStore()
const profileStore = useProfileStore()
const numberRanges = dataStore.ownTenant.numberRanges
const numberRanges = profileStore.ownTenant.numberRanges
const numberRange = numberRanges[resourceType]
@@ -19,13 +20,12 @@ export const useNumberRange = (resourceType) => {
const {data,error} = await supabase
.from("tenants")
.update({numberRanges: newNumberRanges})
.eq('id',dataStore.currentTenant)
.eq('id',profileStore.currentTenant)
dataStore.fetchOwnTenant()
await profileStore.fetchOwnTenant()
return (numberRange.prefix ? numberRange.prefix : "") + nextNumber + (numberRange.suffix ? numberRange.suffix : "")
}
return { useNextNumber}

View File

@@ -4,9 +4,10 @@ import Handlebars from "handlebars";
export const usePrintLabel = async (printServerId,printerName , rawZPL ) => {
const supabase = useSupabaseClient()
const dataStore = useDataStore()
const profileStore = useProfileStore()
await supabase.from("printJobs").insert({
tenant: dataStore.currentTenant,
tenant: profileStore.currentTenant,
rawContent: rawZPL,
printerName: printerName,
printServer: printServerId

250
composables/useRole.js Normal file
View File

@@ -0,0 +1,250 @@
export const useRole = () => {
const profileStore = useProfileStore()
console.log(profileStore.currentTenant)
const generalAvailableRights = ref({
projects: {
label: "Projekte",
showToAllUsers: false
},
"projects-viewAll": {
label: "Alle Projekte einsehen",
parent: "projects"
},
"projects-create": {
label: "Projekte erstellen",
parent: "projects"
},
contracts: {
label: "Verträge",
showToAllUsers: false
},
"contracts-viewAll": {
label: "Alle Verträge einsehen",
parent: "contracts"
},
"contracts-create": {
label: "Verträge erstellen",
parent: "contracts"
},
plants: {
label: "Objekte",
showToAllUsers: false
},
"plants-viewAll": {
label: "Alle Objekte einsehen",
parent: "plants"
},
"plants-create": {
label: "Objekte erstellen",
parent: "plants"
},
products: {
label: "Artikel",
showToAllUsers: true
},
"products-create": {
label: "Artikel erstellen",
parent: "products"
},
productcategories: {
label: "Artikelkategorie",
showToAllUsers: true
},
"productcategories-create": {
label: "Artikelkategorie erstellen",
parent: "productcategories"
},
services: {
label: "Leistungen",
showToAllUsers: true
},
"services-create": {
label: "Leistungen erstellen",
parent: "services"
},
servicecategories: {
label: "Leistungskategorien",
showToAllUsers: true
},
"servicecategories-create": {
label: "Leistungskategorien erstellen",
parent: "servicecategories"
},
customers: {
label: "Kunden",
showToAllUsers: false
},
"customers-viewAll": {
label: "Alle Kunden einsehen",
parent: "customers"
},
"customers-create": {
label: "Kunden erstellen",
parent: "customers"
},
contacts: {
label: "Kontakte",
showToAllUsers: false
},
"contacts-viewAll": {
label: "Alle Kontakte einsehen",
parent: "contacts"
},
"contacts-create": {
label: "Kontakte erstellen",
parent: "contacts"
},
vendors: {
label: "Lieferanten",
showToAllUsers: false
},
"vendors-viewAll": {
label: "Alle Lieferanten einsehen",
parent: "vendors"
},
"vendors-create": {
label: "Lieferanten erstellen",
parent: "vendors"
},
checks: {
label: "Überprüfungen",
showToAllUsers: false
},
"checks-viewAll": {
label: "Alle Überprüfungen einsehen",
parent: "checks"
},
"checks-create": {
label: "Überprüfungen erstellen",
parent: "checks"
},
vehicles: {
label: "Fahrzeuge",
showToAllUsers: false
},
"vehicles-viewAll": {
label: "Alle Fahrzeuge einsehen",
parent: "vehicles"
},
"vehicles-create": {
label: "Fahrzeuge erstellen",
parent: "vehicles"
},
inventoryitems: {
label: "Inventarartikel",
showToAllUsers: false
},
"inventoryitems-viewAll": {
label: "Alle Inventarartikel einsehen",
parent: "inventoryitems"
},
"inventoryitems-create": {
label: "Inventarartikel erstellen",
parent: "inventoryitems"
},
absencerequests: {
label: "Abwesenheiten",
showToAllUsers: false
},
"absencerequests-viewAll": {
label: "Alle Abwesenheiten einsehen",
parent: "absencerequests"
},
"absencerequests-create": {
label: "Abwesenheiten erstellen",
parent: "absencerequests"
},
events: {
label: "Termine",
showToAllUsers: false
},
"events-viewAll": {
label: "Alle Termine einsehen",
parent: "events"
},
"events-create": {
label: "Termine erstellen",
parent: "events"
},
spaces: {
label: "Lagerplätze",
showToAllUsers: false
},
"spaces-viewAll": {
label: "Alle Lagerplätze einsehen",
parent: "spaces"
},
"spaces-create": {
label: "Lagerplätze erstellen",
parent: "spaces"
},
roles: {
label: "Rollen",
showToAllUsers: false
},
"roles-viewAll": {
label: "Alle Rollen einsehen",
parent: "roles"
},
"roles-create": {
label: "Rollen erstellen",
parent: "roles"
},
tasks: {
label: "Aufgaben",
showToAllUsers: false
},
"tasks-viewAll": {
label: "Alle Aufgaben einsehen",
parent: "tasks"
},
"tasks-create": {
label: "Aufgaben erstellen",
parent: "tasks"
},
"inventory": {
label: "Lager",
},
})
let role = profileStore.activeProfile.role
const checkRight = (right) => {
let rightsToCheck = [right]
//console.log(right.split("-"))
if(right.split("-").length > 1) {
rightsToCheck.push(right.split("-")[0])
}
//console.log(rightsToCheck)
let hasAllNeccessaryRights = true
//console.log(role.rights)
rightsToCheck.forEach(i => {
if(!role.rights.includes(i)){
hasAllNeccessaryRights = false
}
})
return hasAllNeccessaryRights
}
return {
role,
generalAvailableRights,
checkRight
}
}

View File

@@ -2,7 +2,7 @@
export const useSupabaseSelect = async (relation,select = '*', sortColumn = null, ascending = true) => {
const supabase = useSupabaseClient()
const dataStore = useDataStore()
const profileStore = useProfileStore()
let data = null
@@ -10,67 +10,21 @@ export const useSupabaseSelect = async (relation,select = '*', sortColumn = null
data = (await supabase
.from(relation)
.select(select)
.eq("tenant", dataStore.currentTenant)
.eq("tenant", profileStore.currentTenant)
.order(sortColumn, {ascending: ascending})).data
} else {
data = (await supabase
.from(relation)
.select(select)
.eq("tenant", dataStore.currentTenant)).data
.eq("tenant", profileStore.currentTenant)).data
}
return data
}
export const useSupabaseSelectDocuments = async (select = '*', sortColumn = null, folderPath = "_") => {
const supabase = useSupabaseClient()
const dataStore = useDataStore()
let data = null
if(sortColumn !== null ) {
data = (await supabase
.from("documents")
.select(select)
.eq("tenant", dataStore.currentTenant)
.eq("folderPath", folderPath)
.order(sortColumn, {ascending: true})).data
} else {
data = (await supabase
.from("documents")
.select(select)
.eq("tenant", dataStore.currentTenant)
.eq("folderPath",folderPath)).data
}
if(data.length > 0){
let paths = []
data.forEach(doc => {
paths.push(doc.path)
})
const {data: supabaseData,error} = await supabase.storage.from('files').createSignedUrls(paths,3600)
data = data.map((doc,index) => {
return {
...doc,
url: supabaseData[index].signedUrl
}
})
}
//console.log(data)
return data
}
export const useSupabaseSelectSingle = async (relation,idToEq,select = '*' ) => {
const supabase = useSupabaseClient()
const dataStore = useDataStore()
const profileStore = useProfileStore()
let data = null
@@ -78,14 +32,14 @@ export const useSupabaseSelectSingle = async (relation,idToEq,select = '*' ) =>
data = (await supabase
.from(relation)
.select(select)
.eq("tenant", dataStore.currentTenant)
.eq("tenant", profileStore.currentTenant)
.eq("id",idToEq)
.single()).data
} else {
data = (await supabase
.from(relation)
.select(select)
.eq("tenant", dataStore.currentTenant)
.eq("tenant", profileStore.currentTenant)
.single()).data
}

View File

@@ -1,10 +1,7 @@
export const useZipCheck = async (zip) => {
const supabase = useSupabaseClient()
console.log((await supabase.from("citys").select().eq("zip",Number(zip)).maybeSingle()).data)
const result = (await supabase.from("citys").select().eq("zip",Number(zip)).maybeSingle()).data
return result ? result.short : null