diff --git a/components/DocumentUploadModal.vue b/components/DocumentUploadModal.vue
index b3d24b2..482db80 100644
--- a/components/DocumentUploadModal.vue
+++ b/components/DocumentUploadModal.vue
@@ -1,4 +1,6 @@
-
-
-
-
-
- Datei hochladen
-
-
-
-
+
-
-
-
-
-
+ Dateien hier ablegen
+
+
+
+
+
+
+
+ Datei hochladen
+
+
+
+
+
+
-
- {{availableFiletypes.find(x => x.id === props.fileData.type).name}}
- Keine Typ ausgewählt
-
-
-
+
-
- Hochladen
-
-
+
+ Ausgewählt: {{ fileNames }}
+
+
+
+
+
+
+ {{availableFiletypes.find(x => x.id === props.fileData.type).name}}
+ Kein Typ ausgewählt
+
+
+
+
+
+ Hochladen
+
+
+
\ No newline at end of file
diff --git a/components/EntityShowSubCreatedDocuments.vue b/components/EntityShowSubCreatedDocuments.vue
index 4aba719..3c5d26f 100644
--- a/components/EntityShowSubCreatedDocuments.vue
+++ b/components/EntityShowSubCreatedDocuments.vue
@@ -107,7 +107,6 @@ const getAvailableQueryStringData = (keys) => {
returnString += `${key}=${value}`
} else {
returnString += `&${key}=${value}`
-
}
}
diff --git a/components/StaffTimeEntryModal.vue b/components/StaffTimeEntryModal.vue
index e08ff26..dcf370f 100644
--- a/components/StaffTimeEntryModal.vue
+++ b/components/StaffTimeEntryModal.vue
@@ -1,206 +1,170 @@
-
-
-
+
+
-
- {{ local.id ? "Zeit bearbeiten" : "Neue Zeit erfassen" }}
+
+
+ {{ entry ? 'Eintrag bearbeiten' : 'Neue Zeit erfassen' }}
+
+
-
+
-
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Leer lassen, wenn die Zeit noch läuft.
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
\ No newline at end of file
diff --git a/components/columnRenderings/address.vue b/components/columnRenderings/address.vue
index d4528c7..4747bcd 100644
--- a/components/columnRenderings/address.vue
+++ b/components/columnRenderings/address.vue
@@ -9,6 +9,7 @@ const props = defineProps({
+ {{props.row.infoData.streetNumber}},
{{props.row.infoData.street}},
{{props.row.infoData.special}},
{{props.row.infoData.zip}},
diff --git a/components/columnRenderings/purchasePrice.vue b/components/columnRenderings/purchasePrice.vue
index dfb1916..8b81b61 100644
--- a/components/columnRenderings/purchasePrice.vue
+++ b/components/columnRenderings/purchasePrice.vue
@@ -9,5 +9,5 @@ const props = defineProps({
- {{props.row.purchasePrice ? useCurrency(props.row.purchasePrice) : ''}}
+ {{props.row.purchase_price ? useCurrency(props.row.purchase_price) : ''}}
diff --git a/components/columnRenderings/sellingPrice.vue b/components/columnRenderings/sellingPrice.vue
index 6bfeeb1..a11b050 100644
--- a/components/columnRenderings/sellingPrice.vue
+++ b/components/columnRenderings/sellingPrice.vue
@@ -9,5 +9,5 @@ const props = defineProps({
- {{props.row.sellingPrice ? useCurrency(props.row.sellingPrice) : ''}}
+ {{props.row.selling_price ? useCurrency(props.row.selling_price) : ''}}
diff --git a/components/copyCreatedDocumentModal.vue b/components/copyCreatedDocumentModal.vue
index 1c3038b..56fe961 100644
--- a/components/copyCreatedDocumentModal.vue
+++ b/components/copyCreatedDocumentModal.vue
@@ -60,7 +60,7 @@ const mappings = ref({
})
const startImport = () => {
- router.push(`/createDocument/edit/?linkedDocument=${props.id}&type=${documentTypeToUse.value}&optionsToImport=${encodeURIComponent(JSON.stringify(optionsToImport.value))}`)
+ router.push(`/createDocument/edit/?createddocument=${props.id}&type=${documentTypeToUse.value}&optionsToImport=${encodeURIComponent(JSON.stringify(optionsToImport.value))}`)
modal.close()
}
diff --git a/components/displayOpenBalances.vue b/components/displayOpenBalances.vue
index e0e6a11..c19dfdf 100644
--- a/components/displayOpenBalances.vue
+++ b/components/displayOpenBalances.vue
@@ -22,7 +22,7 @@ const setupPage = async () => {
finalizedDocuments = finalizedDocuments.filter(i => i.statementallocations.reduce((n,{amount}) => n + amount, 0).toFixed(2) !== useSum().getCreatedDocumentSum(i, documents).toFixed(2))
- finalizedDocuments = finalizedDocuments.filter(x => (x.type === 'invoices' || x.type === 'advanceInvoices') && x.state === 'Gebucht' && !items.find(i => i.linkedDocument && i.linkedDocument.id === x.id))
+ finalizedDocuments = finalizedDocuments.filter(x => (x.type === 'invoices' || x.type === 'advanceInvoices') && x.state === 'Gebucht' && !items.find(i => i.createddocument && i.createddocument.id === x.id))
diff --git a/components/materialComposing.vue b/components/materialComposing.vue
index b3c802a..201f3ce 100644
--- a/components/materialComposing.vue
+++ b/components/materialComposing.vue
@@ -53,7 +53,7 @@ const setRowData = (row) => {
let product = products.value.find(i => i.id === row.product)
row.unit = product.unit
- row.price = product.sellingPrice
+ row.price = product.selling_price
calculateTotalMaterialPrice()
}
diff --git a/composables/useEntities.ts b/composables/useEntities.ts
index fbf0459..edbca08 100644
--- a/composables/useEntities.ts
+++ b/composables/useEntities.ts
@@ -134,11 +134,11 @@ export const useEntities = (
const selectSingle = async (
idToEq: string | number,
select: string = "*",
- withInformation: boolean = false
+ withInformation: boolean = true
) => {
if (!idToEq) return null
- const res = await useNuxtApp().$api(withInformation ? `/api/resource/${relation}/${idToEq}` : `/api/resource/${relation}/${idToEq}`, {
+ const res = await useNuxtApp().$api(withInformation ? `/api/resource/${relation}/${idToEq}` : `/api/resource/${relation}/${idToEq}/true`, {
method: "GET",
params: { select }
})
diff --git a/composables/useFunctions.js b/composables/useFunctions.js
index a56ac3c..e475b50 100644
--- a/composables/useFunctions.js
+++ b/composables/useFunctions.js
@@ -7,7 +7,20 @@ export const useFunctions = () => {
const supabase = useSupabaseClient()
const getWorkingTimesEvaluationData = async (user_id, startDate, endDate) => {
- return (await useNuxtApp().$api(`/api/functions/timeevaluation/${user_id}?start_date=${startDate}&end_date=${endDate}`))
+ // Der neue Endpunkt ist /staff/time/evaluation und erwartet die Benutzer-ID als targetUserId Query-Parameter.
+
+ // Wir bauen den Query-String zusammen.
+ const queryParams = new URLSearchParams({
+ from: startDate,
+ to: endDate,
+ targetUserId: user_id, // Die ID wird als targetUserId übergeben
+ });
+
+ // Der neue API-Pfad verwendet nur noch den Basis-Endpunkt.
+ const url = `/api/staff/time/evaluation?${queryParams.toString()}`;
+
+ // Annahme: useNuxtApp().$api führt den GET-Request aus und liefert die Daten zurück.
+ return (await useNuxtApp().$api(url));
}
const useNextNumber = async (numberRange) => {
diff --git a/composables/useStaffTime.ts b/composables/useStaffTime.ts
index 4db7d36..791c0a0 100644
--- a/composables/useStaffTime.ts
+++ b/composables/useStaffTime.ts
@@ -1,77 +1,119 @@
-interface StaffTimeEntry {
- id: string
- started_at: string
- stopped_at?: string | null
- duration_minutes?: number | null
- type: string
- description?: string | null
- created_at?: string
-}
+import { defineStore } from 'pinia'
+import { useAuthStore } from '~/stores/auth'
-export function useStaffTime() {
- const { $api } = useNuxtApp()
+export const useStaffTime = () => {
+ const { $api, $dayjs } = useNuxtApp()
const auth = useAuthStore()
-
-
- async function list(params?: { user_id?: string }) {
- const query = new URLSearchParams()
- if (params?.user_id) query.append("user_id", params.user_id)
-
- return await $api(`/api/staff/time${query.toString() ? `?${query}` : ''}`, { method: 'GET' })
+ // ... (list Funktion bleibt gleich) ...
+ const list = async (filter?: { user_id?: string, from?: string, to?: string }) => {
+ // ... (Code wie zuvor)
+ const from = filter?.from || $dayjs().startOf('month').format('YYYY-MM-DD')
+ const to = filter?.to || $dayjs().endOf('month').format('YYYY-MM-DD')
+ const targetUserId = filter?.user_id || auth.user.id
+ const params = new URLSearchParams({ from, to, targetUserId })
+ try {
+ const spans = await $api(`/api/staff/time/spans?${params.toString()}`)
+ return (spans || []).map((span: any) => {
+ const start = $dayjs(span.startedAt)
+ const end = span.endedAt ? $dayjs(span.endedAt) : $dayjs()
+ return {
+ id: span.sourceEventIds && span.sourceEventIds.length > 0 ? span.sourceEventIds[0] : null,
+ eventIds: span.sourceEventIds || [],
+ state: span.status,
+ started_at: span.startedAt,
+ stopped_at: span.endedAt,
+ duration_minutes: end.diff(start, 'minute'),
+ user_id: targetUserId,
+ type: span.type,
+ description: span.payload?.description || ''
+ }
+ }).sort((a: any, b: any) => $dayjs(b.started_at).valueOf() - $dayjs(a.started_at).valueOf())
+ } catch (error) {
+ console.error("Fehler beim Laden:", error)
+ return []
+ }
}
- async function start(description?: string) {
- return await $api('/api/staff/time', {
+ /**
+ * Startet "jetzt" (Live-Modus).
+ * Kann optional eine Zeit empfangen (für manuelle Korrekturen),
+ * aber wir nutzen dafür besser die createEntry Funktion unten.
+ */
+ const start = async (description = "Arbeitszeit", time?: string) => {
+ await $api('/api/staff/time/event', {
method: 'POST',
body: {
- started_at: new Date().toISOString(),
- type: 'work',
- description,
- },
+ eventtype: 'work_start',
+ eventtime: time || new Date().toISOString(), // 💡 Fix: Zeit akzeptieren
+ payload: { description }
+ }
})
}
- async function stop(id: string) {
- return await $api(`/api/staff/time/${id}/stop`, {
- method: 'PUT',
- body: { stopped_at: new Date().toISOString() },
- })
+ const stop = async () => {
+ await $api('/api/staff/time/event', { method: 'POST', body: { eventtype: 'work_end', eventtime: new Date().toISOString() } })
}
- async function submit(id: string) {
- return await $api(`/api/staff/time/${id}`, {
- method: 'PUT',
- body: { state: 'submitted' },
- })
+ const submit = async (entry: any) => {
+ const ids = entry.eventIds || (entry.id ? [entry.id] : [entry]);
+ if (!ids || ids.length === 0) return
+ await $api('/api/staff/time/submit', { method: 'POST', body: { eventIds: ids } })
}
- async function approve(id: string) {
- const auth = useAuthStore()
- const now = useNuxtApp().$dayjs().toISOString()
+ const approve = async (entry: any) => {
+ if (!entry?.user_id) return
+ const ids = entry.eventIds || [entry.id];
+ await $api('/api/staff/time/approve', { method: 'POST', body: { eventIds: ids, employeeUserId: entry.user_id } })
+ }
- return await $api(`/api/staff/time/${id}`, {
- method: 'PUT',
+ const reject = async (entry: any, reason = "Abgelehnt") => {
+ if (!entry?.user_id) return
+ const ids = entry.eventIds || [entry.id];
+ await $api('/api/staff/time/reject', { method: 'POST', body: { eventIds: ids, employeeUserId: entry.user_id, reason } })
+ }
+
+ const update = async (entry: any, newData: { start: string, end: string | null, type: string, description: string }) => {
+ if (!entry || !entry.eventIds || entry.eventIds.length === 0) {
+ throw new Error("Bearbeiten fehlgeschlagen: Keine IDs.")
+ }
+ await $api('/api/staff/time/edit', {
+ method: 'POST',
body: {
- state: 'approved',
- //@ts-ignore
- approved_by: auth.user.id,
- approved_at: now,
- },
+ originalEventIds: entry.eventIds,
+ newStart: newData.start,
+ newEnd: newData.end,
+ newType: newData.type,
+ description: newData.description,
+ reason: "Manuelle Bearbeitung"
+ }
})
}
- async function get(id: string) {
- return await $api(`/api/staff/time/${id}`, { method: 'GET' })
+ // 🆕 NEU: Manuellen Eintrag erstellen (Vergangenheit oder Zeitraum)
+ const createEntry = async (data: { start: string, end: string | null, type: string, description: string }) => {
+ // 1. Start Event senden
+ // Wir nutzen den dynamischen Typ (work_start, vacation_start etc.)
+ await $api('/api/staff/time/event', {
+ method: 'POST',
+ body: {
+ eventtype: `${data.type}_start`,
+ eventtime: data.start,
+ payload: { description: data.description }
+ }
+ })
+
+ // 2. End Event senden (falls vorhanden)
+ if (data.end) {
+ await $api('/api/staff/time/event', {
+ method: 'POST',
+ body: {
+ eventtype: `${data.type}_end`,
+ eventtime: data.end
+ }
+ })
+ }
}
- async function create(data: Record) {
- return await $api('/api/staff/time', { method: 'POST', body: data })
- }
-
- async function update(id: string, data: Record) {
- return await $api(`/api/staff/time/${id}`, { method: 'PUT', body: data })
- }
-
- return { list, start, stop,submit,approve, get, create, update }
-}
+ return { list, start, stop, submit, approve, reject, update, createEntry }
+}
\ No newline at end of file
diff --git a/nuxt.config.ts b/nuxt.config.ts
index ad3b05c..5e9547f 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -7,7 +7,7 @@ export default defineNuxtConfig({
}
},
- modules: ['@pinia/nuxt', '@nuxt/ui', '@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', '@vueuse/nuxt'],
ssr: false,
diff --git a/package.json b/package.json
index cc0dc96..5ea1bbd 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
"@capacitor/cli": "^7.0.0",
"@nuxtjs/leaflet": "^1.2.3",
"@nuxtjs/supabase": "^1.1.4",
+ "@vueuse/core": "^14.1.0",
+ "@vueuse/nuxt": "^14.1.0",
"nuxt": "^3.14.1592",
"nuxt-tiptap-editor": "^1.2.0",
"vue": "^3.5.13",
@@ -35,6 +37,7 @@
"@fullcalendar/timegrid": "^6.1.10",
"@fullcalendar/vue3": "^6.1.10",
"@iconify/json": "^2.2.171",
+ "@mmote/niimbluelib": "^0.0.1-alpha.29",
"@nuxt/ui-pro": "^1.6.0",
"@nuxtjs/fontaine": "^0.4.1",
"@nuxtjs/google-fonts": "^3.1.0",
@@ -63,7 +66,9 @@
"dayjs": "^1.11.10",
"fast-sort": "^3.4.1",
"handlebars": "^4.7.8",
+ "image-js": "^1.1.0",
"leaflet": "^1.9.4",
+ "license-checker": "^25.0.1",
"maplibre-gl": "^4.7.0",
"nuxt-editorjs": "^1.0.4",
"nuxt-viewport": "^2.0.6",
@@ -80,6 +85,8 @@
"vue-chartjs": "^5.3.1",
"vuedraggable": "^4.1.0",
"vuetify": "^3.4.0-beta.1",
- "zebra-browser-print-wrapper": "^0.1.4"
+ "zebra-browser-print-wrapper": "^0.1.4",
+ "zod": "^3.25.76",
+ "zpl-renderer-js": "^2.0.2"
}
-}
\ No newline at end of file
+}
diff --git a/pages/banking/index.vue b/pages/banking/index.vue
index 67af524..6b7cd38 100644
--- a/pages/banking/index.vue
+++ b/pages/banking/index.vue
@@ -58,7 +58,7 @@ const clearSearchString = () => {
searchString.value = ''
}
-const filterAccount = ref(bankaccounts || [])
+const filterAccount = ref(bankaccounts.value || [])
const displayCurrency = (value, currency = "€") => {
return `${Number(value).toFixed(2).replace(".",",")} ${currency}`
@@ -150,7 +150,7 @@ setupPage()
-
Spalten
-
+ -->
{
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 useEntities("incominginvoices").select("*, statementallocations(*), vendor(id,name)")).filter(i => i.state === "Gebucht")
+ incominginvoices.value = (await useEntities("incominginvoices").select("*, statementallocations(*), vendor(id,name)")).filter(i => i.state === "Gebucht")
accounts.value = (await useEntities("accounts").selectSpecial("*","number",true))
ownaccounts.value = (await useEntities("ownaccounts").select())
@@ -66,7 +66,7 @@ const setup = async () => {
console.log(openDocuments.value)
allocatedDocuments.value = documents.filter(i => i.statementallocations.find(x => x.bankstatement === itemInfo.value.id))
- allocatedIncomingInvoices.value = incominginvoices.filter(i => i.statementallocations.find(x => x.bankstatement === itemInfo.value.id))
+ allocatedIncomingInvoices.value = incominginvoices.value.filter(i => i.statementallocations.find(x => x.bankstatement === itemInfo.value.id))
console.log(allocatedDocuments.value)
console.log(allocatedIncomingInvoices.value)
openIncomingInvoices.value = (await useEntities("incominginvoices").select("*, statementallocations(*), vendor(*)")).filter(i => !i.archived && i.statementallocations.reduce((n,{amount}) => n + amount, 0).toFixed(2) !== getInvoiceSum(i,false))
@@ -177,7 +177,14 @@ const removeAllocation = async (allocationId) => {
await setup()
}
-const searchString = ref("")
+const searchString = ref(tempStore.searchStrings["bankstatementsedit"] ||'')
+
+const clearSearchString = () => {
+ searchString.value = ''
+ tempStore.clearSearchString("bankstatementsedit")
+
+}
+
const filteredDocuments = computed(() => {
@@ -509,11 +516,11 @@ const archiveStatement = async () => {
- {{item.ii_id.reference}} - {{vendors.find(i => i.id === item.ii_id.vendor).name}}
+ {{incominginvoices.find(i => i.id === item.incominginvoice).reference}} - {{incominginvoices.find(i => i.id === item.incominginvoice).vendor?.name}}
{{displayCurrency(item.amount)}}
@@ -529,11 +536,11 @@ const archiveStatement = async () => {
- {{item.cd_id.documentNumber}} - {{customers.find(i => i.id === item.cd_id.customer).name}}
+ {{createddocuments.find(i => i.id === item.createddocument).documentNumber}} - {{createddocuments.find(i => i.id === item.createddocument).customer?.name}}
{{displayCurrency(item.amount)}}
@@ -546,7 +553,15 @@ const archiveStatement = async () => {
class="mr-3 mt-3"
@click="removeAllocation(item.id)"
/>
+
+
@@ -780,6 +795,7 @@ const archiveStatement = async () => {
placeholder="Suche..."
class="hidden lg:block w-full mr-1"
@keydown.esc="$event.target.blur()"
+ @change="tempStore.modifySearchString('bankstatementsedit',searchString)"
>
@@ -789,7 +805,7 @@ const archiveStatement = async () => {
variant="outline"
icon="i-heroicons-x-mark"
color="rose"
- @click="searchString = ''"
+ @click="clearSearchString"
/>
@@ -810,8 +826,8 @@ const archiveStatement = async () => {
icon="i-heroicons-check"
variant="outline"
class="mr-3"
- v-if="!itemInfo.statementallocations.find(i => i.cd_id === document.id)"
- @click="saveAllocation({cd_id: document.id, bankstatement: itemInfo.id, amount: Number(Number(document.openSum) < manualAllocationSum ? document.openSum : manualAllocationSum), description: allocationDescription})"
+ v-if="!itemInfo.statementallocations.find(i => i.createddocument === document.id)"
+ @click="saveAllocation({createddocument: document.id, bankstatement: itemInfo.id, amount: Number(Number(document.openSum) < manualAllocationSum ? document.openSum : manualAllocationSum), description: allocationDescription})"
/>
{
icon="i-heroicons-check"
variant="outline"
class="mr-3"
- v-if="!itemInfo.statementallocations.find(i => i.ii_id === item.id)"
- @click="saveAllocation({ii_id: item.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(item,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(item,true)), description: allocationDescription})"
+ v-if="!itemInfo.statementallocations.find(i => i.incominginvoice === item.id)"
+ @click="saveAllocation({incominginvoice: item.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(item,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(item,true)), description: allocationDescription})"
/>
{
if (route.params) {
if (route.params.id) {
console.log(route.params)
- itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id)
+ itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id,'',false)
await setContactPersonData()
checkCompatibilityWithInputPrice()
}
@@ -141,9 +141,9 @@ const setupPage = async () => {
//TODO: Implement Checking for Same Customer, Contact and Project
- itemInfo.value.customer = linkedDocuments[0].customer
- itemInfo.value.project = linkedDocuments[0].project
- itemInfo.value.contact = linkedDocuments[0].contact
+ itemInfo.value.customer = linkedDocuments[0].customer ? linkedDocuments[0].customer.id : null
+ itemInfo.value.project = linkedDocuments[0].project ? linkedDocuments[0].project.id : null
+ itemInfo.value.contact = linkedDocuments[0].contact ? linkedDocuments[0].contact.id : null
setCustomerData()
@@ -276,9 +276,9 @@ const setupPage = async () => {
}
- if (route.query.linkedDocument) {
- itemInfo.value.linkedDocument = route.query.linkedDocument
- let linkedDocument = await useEntities("createddocuments").selectSingle(itemInfo.value.linkedDocument)
+ if (route.query.createddocument) {
+ itemInfo.value.createddocument = route.query.createddocument
+ let linkedDocument = await useEntities("createddocuments").selectSingle(itemInfo.value.createddocument,'',false)
if (route.query.optionsToImport) {
//Import only true
@@ -1428,7 +1428,8 @@ const closeDocument = async () => {
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
+ console.log(tags)
+ fileData.type = tags.find(i => i.createdDocumentType === mappedType).id
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(","),
@@ -1506,7 +1507,20 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
}
if (row.service) {
- row.unit = service.unit ? service.unit : services.value.find(i => i.id === row.service).unit
+ console.log(service)
+ if(service.unit) {
+ row.unit = service.unit
+ } else {
+ let selectedService = services.value.find(i => i.id === row.service)
+ console.log(selectedService)
+ if(selectedService.unit?.id) {
+ row.unit = selectedService.unit.id
+ } else {
+ row.unit = selectedService.unit
+ }
+ }
+
+ //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 : "")
@@ -1520,14 +1534,14 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, 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.inputPrice = (product.selling_price ? product.selling_price : products.value.find(i => i.id === row.product).selling_price)
//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)) {
row.taxPercent = 0
} else {
- row.taxPercent = product.taxPercentage ? product.taxPercentage : products.value.find(i => i.id === row.product).taxPercentage
+ row.taxPercent = product.tax_percentage ? product.tax_percentage : products.value.find(i => i.id === row.product).tax_percentage
}
}
@@ -1584,7 +1598,6 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
-
-
+
-
+
-
Spalten
-
+ -->
Filter
@@ -63,36 +63,36 @@
- {{item.label}}
+ {{ item.label }}
- {{filteredRows.filter(i => item.key === 'invoices' ? ['invoices','advanceInvoices','cancellationInvoices'].includes(i.type) : item.key === i.type).length}}
+ {{ filteredRows.filter(i => item.key === 'invoices' ? ['invoices', 'advanceInvoices', 'cancellationInvoices'].includes(i.type) : item.key === i.type).length }}
- {{dataStore.documentTypesForCreation[row.type].labelSingle}}
-
+ {{ dataStore.documentTypesForCreation[row.type].labelSingle }}
+
- {{row.state}}
+ {{ row.state }}
- {{row.state}}
+ {{ row.state }}
- Storniert mit {{items.find(i => i.linkedDocument && i.linkedDocument.id === row.id).documentNumber}}
+ Storniert mit {{ items.find(i => i.createddocument && i.createddocument.id === row.id).documentNumber }}
- {{row.state}}
+ {{ row.state }}
- {{row.customer ? row.customer.name : ""}}
+ {{ row.customer ? row.customer.name : "" }}
- {{row.customer.name.substring(0,20)}}...
+ {{ row.customer.name.substring(0, 20) }}...
- {{row.documentNumber}}
- {{row.documentNumber}}
+ {{ row.documentNumber }}
+ {{ row.documentNumber }}
- {{row.date ? dayjs(row.date).format("DD.MM.YY") : ''}}
- {{row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : ''}}
+ {{ row.date ? dayjs(row.date).format("DD.MM.YY") : '' }}
+ {{ row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : '' }}
-
+ {{ row.documentDate ? dayjs(row.documentDate).add(row.paymentDays, 'day').format("DD.MM.YY") : '' }}
-
+
-
+ {{ displayCurrency(useSum().getCreatedDocumentSum(row, items)) }}
-
+ {{ displayCurrency(useSum().getCreatedDocumentSum(row, items) - row.statementallocations.reduce((n, {amount}) => n + amount, 0)) }}
@@ -181,14 +182,14 @@ defineShortcuts({
}
},
'arrowdown': () => {
- if(selectedItem.value < filteredRows.value.length - 1) {
+ if (selectedItem.value < filteredRows.value.length - 1) {
selectedItem.value += 1
} else {
selectedItem.value = 0
}
},
'arrowup': () => {
- if(selectedItem.value === 0) {
+ if (selectedItem.value === 0) {
selectedItem.value = filteredRows.value.length - 1
} else {
selectedItem.value -= 1
@@ -208,7 +209,7 @@ const selectedItem = ref(0)
const setupPage = async () => {
- items.value = (await useEntities("createddocuments").select("*, customer(id,name), statementallocations(id,amount),linkedDocument(*)","documentNumber",true, true))
+ items.value = (await useEntities("createddocuments").select("*, customer(id,name), statementallocations(id,amount),linkedDocument(*)", "documentNumber", true, true))
}
setupPage()
@@ -315,7 +316,7 @@ const filteredRows = computed(() => {
}
})
- if(selectedFilters.value.length > 0) {
+ if (selectedFilters.value.length > 0) {
selectedFilters.value.forEach(filterName => {
let filter = dataType.filters.find(i => i.name === filterName)
tempItems = tempItems.filter(filter.filterFunction)
@@ -323,7 +324,6 @@ const filteredRows = computed(() => {
}
-
tempItems = useSearch(searchString.value, tempItems)
diff --git a/pages/createDocument/serialInvoice.vue b/pages/createDocument/serialInvoice.vue
index 8436158..8900d36 100644
--- a/pages/createDocument/serialInvoice.vue
+++ b/pages/createDocument/serialInvoice.vue
@@ -1,5 +1,3 @@
-
-
@@ -25,7 +23,7 @@
-
Spalten
-
+ -->
{{dataStore.documentTypesForCreation[row.type].labelSingle}}
-
-
- {{row.state}}
-
-
- {{row.state}}
-
-
- {{row.state}}
-
-
{{row.customer ? row.customer.name : ""}}
@@ -116,6 +94,10 @@
{{row.contract.contractNumber}} - {{row.contract.name}}
+
+ Monatlich
+ Quartalsweise
+
@@ -161,13 +143,9 @@ const filteredRows = computed(() => {
const templateColumns = [
{
- key: 'type',
- label: "Typ"
+ key: 'serialConfig.active',
+ label: "Aktiv"
},{
- key: 'state',
- label: "Status"
- },
- {
key: "amount",
label: "Betrag"
},
@@ -180,8 +158,8 @@ const templateColumns = [
label: "Vertrag"
},
{
- key: 'serialConfig.active',
- label: "Aktiv"
+ key: 'serialConfig.intervall',
+ label: "Rhythmus"
}
]
const selectedColumns = ref(templateColumns)
diff --git a/pages/createDocument/show/[id].vue b/pages/createDocument/show/[id].vue
index 81ae4dc..3d91df4 100644
--- a/pages/createDocument/show/[id].vue
+++ b/pages/createDocument/show/[id].vue
@@ -39,9 +39,9 @@ const openEmail = () => {
const openBankstatements = () => {
if(itemInfo.value.statementallocations.length > 1) {
- navigateTo(`/banking/?filter=${JSON.stringify(itemInfo.value.statementallocations.map(i => i.bs_id))}`)
+ navigateTo(`/banking/?filter=${JSON.stringify(itemInfo.value.statementallocations.map(i => i.bankstatement))}`)
} else {
- navigateTo(`/banking/statements/edit/${itemInfo.value.statementallocations[0].bs_id}`)
+ navigateTo(`/banking/statements/edit/${itemInfo.value.statementallocations[0].bankstatement}`)
}
}
@@ -105,12 +105,21 @@ const openBankstatements = () => {
Kunde
- {{dataStore.documentTypesForCreation[itemInfo.linkedDocument.type].labelSingle}} - {{itemInfo.linkedDocument.documentNumber}}
+ {{dataStore.documentTypesForCreation[itemInfo.createddocument.type].labelSingle}} - {{itemInfo.createddocument.documentNumber}}
+
+
+ {{dataStore.documentTypesForCreation[item.type].labelSingle}} - {{item.documentNumber}}
{
if(data) loadedDocuments.value = data
+ loadedDocuments.value = await Promise.all(loadedDocuments.value.map(async doc => {
+
+ const document = await useEntities("createddocuments").selectSingle(doc.createddocument)
+ console.log(document)
+ return {
+ ...doc,
+ createddocument: document
+ }}))
+
//console.log(loadedDocuments.value)
if(loadedDocuments.value.length > 0) {
diff --git a/pages/files/index.vue b/pages/files/index.vue
index 89ffec4..fd8313e 100644
--- a/pages/files/index.vue
+++ b/pages/files/index.vue
@@ -364,33 +364,67 @@ const clearSearchString = () => {
variant="outline"
v-if="Object.keys(selectedFiles).find(i => selectedFiles[i] === true)"
>Herunterladen
-
-
+
+
- Ordner Erstellen
-
+
+
+ Ordner Erstellen
+
+
+
+
+
+
+
-
-
+
-
+
+ {{ filetags.find(t => t.id === createFolderData.standardFiletype)?.name }}
+
+ Kein Typ ausgewählt
+
+
+
+
+
+
-
+
-
- Erstellen
-
+
+
+ Abbrechen
+
+
+ Erstellen
+
+
-
@@ -429,8 +463,8 @@ const clearSearchString = () => {
- {{dayjs(documents.find(i => i.id === entry.id).created_at).format("DD.MM.YY HH:mm")}}
- {{dayjs(currentFolders.find(i => i.id === entry.id).created_at).format("DD.MM.YY HH:mm")}}
+ {{dayjs(documents.find(i => i.id === entry.id).createdAt).format("DD.MM.YY HH:mm")}}
+ {{dayjs(currentFolders.find(i => i.id === entry.id).createdAt).format("DD.MM.YY HH:mm")}}
|
diff --git a/pages/staff/time/[id]/evaluate.vue b/pages/staff/time/[id]/evaluate.vue
index 38ced35..8f75226 100644
--- a/pages/staff/time/[id]/evaluate.vue
+++ b/pages/staff/time/[id]/evaluate.vue
@@ -4,10 +4,25 @@ const router = useRouter()
const route = useRoute()
const auth = useAuthStore()
const toast = useToast()
+
// 🔹 State
-const workingtimes = ref([])
-const absencerequests = ref([])
-const workingTimeInfo = ref(null)
+const workingTimeInfo = ref<{
+ userId: string;
+ spans: any[]; // Neue Struktur für die Detailansicht/Tabelle
+ summary: {
+ sumWorkingMinutesSubmitted: number;
+ sumWorkingMinutesApproved: number;
+ sumWorkingMinutesRecreationDays: number;
+ sumRecreationDays: number;
+ sumWorkingMinutesVacationDays: number;
+ sumVacationDays: number;
+ sumWorkingMinutesSickDays: number;
+ sumSickDays: number;
+ timeSpanWorkingMinutes: number;
+ saldoApproved: number;
+ saldoSubmitted: number;
+ } | null; // Neue Struktur für die Zusammenfassung
+} | null>(null)
const platformIsNative = ref(useCapacitor().getIsNative())
@@ -20,12 +35,38 @@ const showDocument = ref(false)
const uri = ref("")
const itemInfo = ref({})
+const profile = ref(null)
+
+// 💡 Die ID des Benutzers, dessen Daten wir abrufen (aus der Route)
+const evaluatedUserId = computed(() => route.params.id as string)
+
+/**
+ * Konvertiert Minuten in das Format HH:MM h
+ */
function formatMinutesToHHMM(minutes = 0) {
const h = Math.floor(minutes / 60)
const m = Math.floor(minutes % 60)
return `${h}:${String(m).padStart(2, "0")} h`
}
+/**
+ * Berechnet die Dauer zwischen startedAt und endedAt in Minuten.
+ */
+function calculateDurationMinutes(start: string, end: string): number {
+ const startTime = $dayjs(start);
+ const endTime = $dayjs(end);
+ return endTime.diff(startTime, 'minute');
+}
+
+/**
+ * Formatiert die Dauer (in Minuten) in HH:MM h
+ */
+function formatSpanDuration(start: string, end: string): string {
+ const minutes = calculateDurationMinutes(start, end);
+ return formatMinutesToHHMM(minutes);
+}
+
+
// 📅 Zeitraumumschaltung
function changeRange() {
const rangeMap = {
@@ -56,41 +97,67 @@ function changeRange() {
loadWorkingTimeInfo()
}
-const profile = ref(null)
-
-// 📊 Daten laden
+// 📊 Daten laden (Initialisierung)
async function setupPage() {
await changeRange()
- profile.value = (await useNuxtApp().$api("/api/tenant/profiles")).data.find(i => i.user_id === route.params.id)
+ // Lade das Profil des Benutzers, der ausgewertet wird (route.params.id)
+ try {
+ const response = await useNuxtApp().$api(`/api/tenant/profiles`);
+ // Findet das Profil des Benutzers, dessen ID in der Route steht
+ profile.value = response.data.find(i => i.user_id === evaluatedUserId.value);
+ } catch (error) {
+ console.error("Fehler beim Laden des Profils:", error);
+ }
console.log(profile.value)
setPageLayout(platformIsNative.value ? 'mobile' : 'default')
-
}
+// 💡 ANGEPASST: Ruft den neuen Endpunkt ab und speichert das gesamte Payload-Objekt
async function loadWorkingTimeInfo() {
- workingTimeInfo.value = await useFunctions().getWorkingTimesEvaluationData(
- route.params.id,
- selectedStartDay.value,
- selectedEndDay.value
- )
+
+ // Erstellt Query-Parameter für den neuen Backend-Endpunkt
+ const queryParams = new URLSearchParams({
+ from: selectedStartDay.value,
+ to: selectedEndDay.value,
+ targetUserId: evaluatedUserId.value,
+ });
+
+ const url = `/api/staff/time/evaluation?${queryParams.toString()}`;
+
+ // Führt den GET-Request zum neuen Endpunkt aus und speichert das gesamte Payload-Objekt { userId, spans, summary }
+ const data = await useNuxtApp().$api(url);
+
+ workingTimeInfo.value = data;
+
openTab.value = 0
}
// 📄 PDF generieren
+// Frontend (index.vue)
async function generateDocument() {
- const path = (await useEntities("letterheads").select("*"))[0].path // TODO SELECT
+ if (!workingTimeInfo.value || !workingTimeInfo.value.summary) return;
+
+ const path = (await useEntities("letterheads").select("*"))[0].path
uri.value = await useFunctions().useCreatePDF({
full_name: profile.value.full_name,
- employee_number: profile.value.employee_number ? profile.value.employee_number : "-",
- ...workingTimeInfo.value}, path, "timesheet")
+ employee_number: profile.value.employee_number || "-",
+ // Wir übergeben das summary-Objekt flach (für Header-Daten)
+ ...workingTimeInfo.value.summary,
+
+ // UND wir müssen die Spans explizit übergeben, damit die Tabelle generiert werden kann
+ spans: workingTimeInfo.value.spans
+ }, path, "timesheet")
showDocument.value = true
}
+
const fileSaved = ref(false)
+
+// 💾 Datei speichern
async function saveFile() {
try {
let fileData = {
@@ -107,9 +174,6 @@ async function saveFile() {
} catch (error) {
toast.add({title:"Fehler beim Speichern der Auswertung", color: "rose"})
}
-
-
-
}
async function onTabChange(index: number) {
@@ -118,7 +182,6 @@ async function onTabChange(index: number) {
// Initialisierung
await setupPage()
-changeRange()
@@ -206,22 +269,24 @@ changeRange()
>
-
+
+
Zusammenfassung
-
Eingereicht: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesEingereicht) }}
-
Genehmigt: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesApproved) }}
-
Feiertagsausgleich: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesRecreationDays) }} / {{ workingTimeInfo.sumRecreationDays }} Tage
-
Urlaubs-/Berufsschulausgleich: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesVacationDays) }} / {{ workingTimeInfo.sumVacationDays }} Tage
-
Krankheitsausgleich: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesSickDays) }} / {{ workingTimeInfo.sumSickDays }} Tage
-
Soll-Stunden: {{ formatMinutesToHHMM(workingTimeInfo.timeSpanWorkingMinutes) }}
+
Eingereicht: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesSubmitted) }}
+
Genehmigt: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesApproved) }}
+
Feiertagsausgleich: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesRecreationDays) }} / {{ workingTimeInfo.summary.sumRecreationDays }} Tage
+
Urlaubs-/Berufsschulausgleich: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesVacationDays) }} / {{ workingTimeInfo.summary.sumVacationDays }} Tage
+
Krankheitsausgleich: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesSickDays) }} / {{ workingTimeInfo.summary.sumSickDays }} Tage
+
Soll-Stunden: {{ formatMinutesToHHMM(workingTimeInfo.summary.timeSpanWorkingMinutes) }}
+
- Inoffizielles Saldo: {{ (workingTimeInfo.saldoInOfficial >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.saldoInOfficial)) }}
+ Inoffizielles Saldo: {{ (workingTimeInfo.summary.saldoSubmitted >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.summary.saldoSubmitted)) }}
- Saldo: {{ (workingTimeInfo.saldo >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.saldo)) }}
+ Saldo: {{ (workingTimeInfo.summary.saldoApproved >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.summary.saldoApproved)) }}
@@ -229,33 +294,39 @@ changeRange()
router.push(`/workingtimes/edit/${row.id}`)"
+ @select="(row) => router.push(`/workingtimes/edit/${row.sourceEventIds[0]}`)"
>
-
- Genehmigt
- Eingereicht
- Entwurf
+
+ Genehmigt
+ Eingereicht
+ Faktisch
+ Entwurf
+ {{ row.status }}
-
- {{ $dayjs(row.started_at).format('HH:mm DD.MM.YY') }} Uhr
+
+ {{ $dayjs(row.startedAt).format('HH:mm DD.MM.YY') }} Uhr
-
- {{ $dayjs(row.stopped_at).format('HH:mm DD.MM.YY') }} Uhr
+
+ {{ $dayjs(row.endedAt).format('HH:mm DD.MM.YY') }} Uhr
- {{ useFormatDuration(row.duration_minutes) }}
+ {{ formatSpanDuration(row.startedAt, row.endedAt) }}
+
+
+
+ {{ row.type.charAt(0).toUpperCase() + row.type.slice(1).replace('_', ' ') }}
@@ -273,12 +344,8 @@ changeRange()
-
-
-
-
@@ -290,9 +357,7 @@ changeRange()
-
-
-
Start
@@ -341,7 +405,6 @@ changeRange()
-
-
-
-
-
-
+
Zusammenfassung
-
Eingereicht: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesEingereicht) }}
-
Genehmigt: {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesApproved) }}
+
Eingereicht: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesSubmitted) }}
+
Genehmigt: {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesApproved) }}
Feiertagsausgleich:
- {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesRecreationDays) }}
- / {{ workingTimeInfo.sumRecreationDays }} Tage
+ {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesRecreationDays) }}
+ / {{ workingTimeInfo.summary.sumRecreationDays }} Tage
Urlaubs-/Berufsschule:
- {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesVacationDays) }}
- / {{ workingTimeInfo.sumVacationDays }} Tage
+ {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesVacationDays) }}
+ / {{ workingTimeInfo.summary.sumVacationDays }} Tage
Krankheitsausgleich:
- {{ formatMinutesToHHMM(workingTimeInfo.sumWorkingMinutesSickDays) }}
- / {{ workingTimeInfo.sumSickDays }} Tage
+ {{ formatMinutesToHHMM(workingTimeInfo.summary.sumWorkingMinutesSickDays) }}
+ / {{ workingTimeInfo.summary.sumSickDays }} Tage
-
Soll: {{ formatMinutesToHHMM(workingTimeInfo.timeSpanWorkingMinutes) }}
+
Soll: {{ formatMinutesToHHMM(workingTimeInfo.summary.timeSpanWorkingMinutes) }}
Inoffizielles Saldo:
- {{ (workingTimeInfo.saldoInOfficial >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.saldoInOfficial)) }}
+ {{ (workingTimeInfo.summary.saldoSubmitted >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.summary.saldoSubmitted)) }}
Saldo:
- {{ (workingTimeInfo.saldo >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.saldo)) }}
+ {{ (workingTimeInfo.summary.saldoApproved >= 0 ? '+' : '-') + formatMinutesToHHMM(Math.abs(workingTimeInfo.summary.saldoApproved)) }}
-
-
-
-
-
+
\ No newline at end of file
diff --git a/pages/staff/time/index.vue b/pages/staff/time/index.vue
index ac4a1e3..a546533 100644
--- a/pages/staff/time/index.vue
+++ b/pages/staff/time/index.vue
@@ -1,4 +1,4 @@
-
-
-
-
-
-
-
- Läuft seit {{ useNuxtApp().$dayjs(active.started_at).format('HH:mm') }}
-
-
Keine aktive Zeit
+
+
+
+
+ Status
+
+ Läuft seit {{ useNuxtApp().$dayjs(active.started_at).format('HH:mm') }}
+
+ Nicht aktiv
+
+
+
+
+
+
+
+
+
-
-
- { editEntry = null; showModal = true }"
- />
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
{ entryToEdit = null; showEditModal = true }" />
+
-
-
-
- Genehmigt
- Eingereicht
- Entwurf
-
-
-
- {{ typeLabel[row.type] || row.type }}
-
-
-
-
-
-
-
- {{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY") }}
-
-
-
-
- {{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY HH:mm") }}
-
-
-
-
-
-
-
- läuft...
-
-
-
-
- {{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY") }}
-
-
-
-
- {{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY HH:mm") }}
-
-
-
-
-
-
-
---
-
-
-
-
+
+
+
+ Genehmigt
+ Eingereicht
+ Abgelehnt
+ Entwurf
+
+
+ {{ typeLabel[row.type] || row.type }}
+
+
+ {{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY") }}
+ {{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY HH:mm") }}
+
+
+ läuft...
+ {{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY") }}
+ {{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY HH:mm") }}
+
+
{{ row.duration_minutes ? useFormatDuration(row.duration_minutes) : "-" }}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{row.vacation_reason}}
+ {{row.sick_reason}}
+ {{row.description}}
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
- {{users.find(i => i.user_id === row.user_id) ? users.find(i => i.user_id === row.user_id).full_name : ""}}
-
-
- {{row.vacation_reason}}
- {{row.sick_reason}}
- {{row.description}}
-
-
+
+
+
+
+
+ {{ useNuxtApp().$dayjs(date).format('dddd, DD. MMMM') }}
+
+
+ {{ group.length }} Einträge
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ useNuxtApp().$dayjs(entry.started_at).format('HH:mm') }}
+ bis
+ {{ useNuxtApp().$dayjs(entry.stopped_at).format('HH:mm') }}
+ Läuft
+
+
+
{{ typeLabel[entry.type] }}
+
+
+
+
+ {{ useFormatDuration(entry.duration_minutes) }}
+
+
+ Genehmigt
+ Eingereicht
+ Abgelehnt
+ Entwurf
+
+
+
+
+
+ {{ entry.description || 'Keine Beschreibung angegeben.' }}
+
+
+ Grund: {{ entry.vacation_reason }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Keine Einträge im gewählten Zeitraum.
+
+
+
-
-
-
-
-
-
-
+
-
Aktive Zeit
-
-
+
Läuft seit {{ useNuxtApp().$dayjs(active.started_at).format('HH:mm') }}
Keine aktive Zeit
-
-
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
+
- {{ row.description || 'Keine Beschreibung' }}
-
-
- {{ typeLabel[row.type] }}
-
+ {{ row.description || 'Keine Beschreibung' }}
+ {{ typeLabel[row.type] }}
-
-
- {{
- {
- approved: 'Genehmigt',
- submitted: 'Eingereicht',
- draft: 'Entwurf'
- }[row.state] || row.state
- }}
-
-
+
Genehmigt
+
Eingereicht
+
Abgelehnt
+
Entwurf
-
-
- Start: {{ useNuxtApp().$dayjs(row.started_at).format('DD.MM.YY HH:mm') }}
-
-
-
- Ende:
-
- {{ useNuxtApp().$dayjs(row.stopped_at).format('DD.MM.YY HH:mm') }}
-
- läuft...
-
-
-
- Dauer:
- {{ row.duration_minutes ? useFormatDuration(row.duration_minutes) : '-' }}
-
-
-
-
-
-
-
+
Start: {{ useNuxtApp().$dayjs(row.started_at).format('DD.MM.YY HH:mm') }}
+
Ende: {{ useNuxtApp().$dayjs(row.stopped_at).format('DD.MM.YY HH:mm') }}
+
+
+
-
-
-
-
{ editEntry = null; showModal = true }"
- />
-
+ { entryToEdit = null; showEditModal = true }" />
-
-
+
+
+
+
+
+
+ Zeiteintrag ablehnen
+
+
+
+
+
+
+ Der Eintrag wird als "Rejected" markiert und nicht mehr zur Arbeitszeit gezählt.
+
+
+
+
+
+
+
+ Abbrechen
+ Bestätigen
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/standardEntity/[type]/[mode]/[[id]].vue b/pages/standardEntity/[type]/[mode]/[[id]].vue
index 450b5cd..0bf2688 100644
--- a/pages/standardEntity/[type]/[mode]/[[id]].vue
+++ b/pages/standardEntity/[type]/[mode]/[[id]].vue
@@ -33,7 +33,7 @@ const setupPage = async (sort_column = null, sort_direction = null) => {
item.value = await useEntities(type).selectSingle(route.params.id, "*", true)
} else if (mode.value === "edit") {
//Load Data for Edit
- item.value = JSON.stringify(await useEntities(type).selectSingle(route.params.id))
+ item.value = JSON.stringify(await useEntities(type).selectSingle(route.params.id,"*",false))
console.log(item.value)
diff --git a/stores/data.js b/stores/data.js
index adb5f5e..dd805a7 100644
--- a/stores/data.js
+++ b/stores/data.js
@@ -956,10 +956,10 @@ export const useDataStore = defineStore('data', () => {
inputType: "number",
inputTrailing: "EUR",
inputChangeFunction: function (row) {
- if(row.markupPercentage) {
- row.sellingPrice = (row.purchasePrice * (1+row.markupPercentage/100)).toFixed(4)
+ if(row.markup_percentage) {
+ row.seling_price = (row.purchase_price * (1+row.markup_percentage/100)).toFixed(4)
} else {
- row.sellingPrice = row.purchasePrice.toFixed(4)
+ row.seling_price = row.purchase_price.toFixed(4)
}
}
},{
@@ -968,12 +968,12 @@ export const useDataStore = defineStore('data', () => {
inputType: "number",
inputTrailing: "%",
inputChangeFunction: function (row) {
- if(row.purchasePrice && ! row.sellingPrice) {
- row.sellingPrice = (row.purchasePrice * (1+row.markupPercentage/100)).toFixed(4)
- } else if(row.sellingPrice && !row.purchasePrice) {
- row.purchasePrice = (row.sellingPrice / (1+row.markupPercentage/100)).toFixed(4)
+ if(row.purchase_price && ! row.seling_price) {
+ row.seling_price = (row.purchase_price * (1+row.markup_percentage/100)).toFixed(4)
+ } else if(row.seling_price && !row.purchase_price) {
+ row.purchase_price = (row.seling_price / (1+row.markup_percentage/100)).toFixed(4)
} else {
- row.sellingPrice = (row.purchasePrice * (1+row.markupPercentage/100)).toFixed(4)
+ row.seling_price = (row.purchase_price * (1+row.markup_percentage/100)).toFixed(4)
}
}
},{
@@ -984,10 +984,10 @@ export const useDataStore = defineStore('data', () => {
inputType: "number",
inputTrailing: "EUR",
inputChangeFunction: function (row) {
- if(row.purchasePrice ) {
- row.markupPercentage = ((row.sellingPrice / row.purchasePrice - 1) * 100 ).toFixed(2)
+ if(row.purchase_price ) {
+ row.markup_percentage = ((row.selling_price / row.purchase_price - 1) * 100 ).toFixed(2)
} else{
- row.purchasePrice = (row.sellingPrice / (1+row.markupPercentage/100)).toFixed(4)
+ row.purchase_price = (row.selling_price / (1+row.markup_percentage/100)).toFixed(4)
}
}
},{
@@ -1766,7 +1766,7 @@ export const useDataStore = defineStore('data', () => {
sortable: true
},
{
- key: "purchasePrice",
+ key: "purchase_price",
label: "Kaufpreis",
inputType: "number",
inputStepSize: "0.01",
@@ -2108,7 +2108,7 @@ export const useDataStore = defineStore('data', () => {
sortable: true
},
{
- key: "purchasePrice",
+ key: "purchase_price",
label: "Einkauspreis",
inputType: "number",
component: purchasePrice,