New CustomerInventory,
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 32s
Build and Push Docker Images / build-frontend (push) Successful in 1m10s

New Mitgliederverwaltung für Vereine
New Bank Auto Complete
This commit is contained in:
2026-02-17 12:38:39 +01:00
parent f26d6bd4f3
commit 6fded3993a
39 changed files with 4837 additions and 158 deletions

View File

@@ -5,10 +5,12 @@ import dayjs from "dayjs"
import projecttype from "~/components/columnRenderings/projecttype.vue"
import contracttype from "~/components/columnRenderings/contracttype.vue"
import memberrelation from "~/components/columnRenderings/memberrelation.vue"
import customer from "~/components/columnRenderings/customer.vue"
import contact from "~/components/columnRenderings/contact.vue"
import plant from "~/components/columnRenderings/plant.vue"
import vendor from "~/components/columnRenderings/vendor.vue"
import product from "~/components/columnRenderings/product.vue"
import active from "~/components/columnRenderings/active.vue"
import sellingPrice from "~/components/columnRenderings/sellingPrice.vue";
import unit from "~/components/columnRenderings/unit.vue";
@@ -32,6 +34,7 @@ import endDate from "~/components/columnRenderings/endDate.vue"
import startDateTime from "~/components/columnRenderings/startDateTime.vue"
import endDateTime from "~/components/columnRenderings/endDateTime.vue"
import serviceCategories from "~/components/columnRenderings/serviceCategories.vue"
import productcategoriesWithLoad from "~/components/columnRenderings/productcategoriesWithLoad.vue"
import phase from "~/components/columnRenderings/phase.vue"
import vehiclesWithLoad from "~/components/columnRenderings/vehiclesWithLoad.vue"
import inventoryitemsWithLoad from "~/components/columnRenderings/inventoryitemsWithLoad.vue"
@@ -167,7 +170,7 @@ export const useDataStore = defineStore('data', () => {
numberRangeHolder: "customerNumber",
historyItemHolder: "customer",
sortColumn: "customerNumber",
selectWithInformation: "*, projects(*), plants(*), contracts(*), contacts(*), createddocuments(*, statementallocations(*)), files(*), events(*)",
selectWithInformation: "*, projects(*), plants(*), contracts(*), contacts(*), createddocuments(*, statementallocations(*)), files(*), events(*), customerinventoryitems(*), customerspaces(*)",
filters: [{
name: "Archivierte ausblenden",
default: true,
@@ -443,7 +446,7 @@ export const useDataStore = defineStore('data', () => {
inputColumn: "Allgemeines"
},*/
],
showTabs: [{label: 'Informationen'},{label: 'Ansprechpartner'},{label: 'Dateien'},{label: 'Ausgangsbelege'},{label: 'Projekte'},{label: 'Objekte'},{label: 'Termine'},{label: 'Verträge'},{label: 'Wiki'}]
showTabs: [{label: 'Informationen'},{label: 'Ansprechpartner'},{label: 'Dateien'},{label: 'Ausgangsbelege'},{label: 'Projekte'},{label: 'Objekte'},{label: 'Termine'},{label: 'Verträge'},{label: 'Kundeninventar', key: 'customerinventoryitems'},{label: 'Kundenlagerplätze', key: 'customerspaces'},{label: 'Wiki'}]
},
members: {
isArchivable: true,
@@ -524,6 +527,24 @@ export const useDataStore = defineStore('data', () => {
inputColumn: "Allgemeines",
sortable: true
},
{
key: "infoData.birthdate",
label: "Geburtsdatum",
inputType: "date",
inputColumn: "Allgemeines",
disabledInTable: true
},
{
key: "infoData.memberrelation",
label: "Mitgliedsverhältnis",
component: memberrelation,
inputType: "select",
selectDataType: "memberrelations",
selectOptionAttribute: "type",
selectSearchAttributes: ['type', 'billingInterval'],
inputColumn: "Allgemeines",
sortable: true
},
{
key: "active",
label: "Aktiv",
@@ -1035,6 +1056,57 @@ export const useDataStore = defineStore('data', () => {
],
showTabs: [{ label: "Informationen" }]
},
memberrelations: {
isArchivable: true,
label: "Mitgliedsverhältnisse",
labelSingle: "Mitgliedsverhältnis",
isStandardEntity: true,
historyItemHolder: "memberrelation",
redirect: true,
sortColumn: "type",
selectWithInformation: "*",
filters: [{
name: "Archivierte ausblenden",
default: true,
"filterFunction": function (row) {
return !row.archived
}
}],
templateColumns: [
{
key: "type",
label: "Typ",
required: true,
title: true,
inputType: "text",
sortable: true
},
{
key: "billingInterval",
label: "Abrechnungsintervall",
required: true,
inputType: "select",
selectValueAttribute: "label",
selectOptionAttribute: "label",
selectManualOptions: [
{ label: "Monatlich" },
{ label: "Quartalsweise" },
{ label: "Halbjährlich" },
{ label: "Jährlich" }
],
sortable: true
},
{
key: "billingAmount",
label: "Abrechnungshöhe",
required: true,
inputType: "number",
inputTrailing: "€",
sortable: true
}
],
showTabs: [{ label: "Informationen" }]
},
absencerequests: {
isArchivable: true,
label: "Abwesenheiten",
@@ -1293,7 +1365,8 @@ export const useDataStore = defineStore('data', () => {
selectDataType: "productcategories",
selectOptionAttribute: "name",
selectSearchAttributes: ['name'],
selectMultiple: true
selectMultiple: true,
component: productcategoriesWithLoad
},
{
key: "description",
@@ -1773,6 +1846,7 @@ export const useDataStore = defineStore('data', () => {
selectValueAttribute: "label",
selectManualOptions: [
{label:"Standort"},
{label:"Raum"},
{label:"Regalplatz"},
{label:"Kiste"},
{label:"Palettenplatz"},
@@ -1856,6 +1930,149 @@ export const useDataStore = defineStore('data', () => {
},{label: 'Inventarartikel'},{label: 'Wiki'}
]
},
customerspaces: {
isArchivable: true,
label: "Kundenlagerplätze",
labelSingle: "Kundenlagerplatz",
isStandardEntity: true,
selectWithInformation: "*, customer(id,name), files(*)",
sortColumn: "space_number",
redirect: true,
numberRangeHolder: "space_number",
historyItemHolder: "customerspace",
filters:[{
name: "Archivierte ausblenden",
default: true,
"filterFunction": function (row) {
return !row.archived
}
}],
inputColumns: [
"Allgemeines",
"Ort"
],
templateColumns: [
{
key: "name",
label: "Name",
inputType: "text",
required: true,
title: true,
inputColumn: "Allgemeines",
sortable: true
},
{
key: "customer",
label: "Kunde",
inputType: "select",
required: true,
selectDataType: "customers",
selectOptionAttribute: "name",
selectSearchAttributes: ["name"],
component: customer,
inputColumn: "Allgemeines",
sortable: true
},
{
key: "space_number",
label: "Kundenlagerplatznr.",
inputType: "text",
inputIsNumberRange: true,
inputColumn: "Allgemeines",
sortable: true
},
{
key: "type",
label: "Typ",
inputType: "select",
required: true,
selectValueAttribute: "label",
selectManualOptions: [
{label:"Standort"},
{label:"Raum"},
{label:"Regalplatz"},
{label:"Kiste"},
{label:"Palettenplatz"},
{label:"Sonstiges"}
],
inputColumn: "Allgemeines",
sortable: true
},
{
key: "parentSpace",
label: "Übergeordneter Kundenlagerplatz",
inputType: "select",
selectDataType: "customerspaces",
selectOptionAttribute: "space_number",
selectValueAttribute: "id",
inputColumn: "Allgemeines"
},
{
key: "info_data.streetNumber",
label: "Straße + Hausnummer",
inputType: "text",
disabledInTable: true,
inputColumn: "Ort"
},
{
key: "info_data.special",
label: "Adresszusatz",
inputType: "text",
disabledInTable: true,
inputColumn: "Ort"
},
{
key: "info_data.zip",
label: "Postleitzahl",
inputType: "text",
disabledInTable: true,
inputColumn: "Ort",
inputChangeFunction: async function (row) {
const zip = String(row.info_data.zip || "").replace(/\D/g, "")
row.info_data.zip = zip
if ([4, 5].includes(zip.length)) {
const zipData = await useFunctions().useZipCheck(zip)
row.info_data.zip = zipData?.zip || row.info_data.zip
row.info_data.city = zipData?.short || row.info_data.city
}
},
},
{
key: "info_data.city",
label: "Stadt",
inputType: "text",
disabledInTable: true,
inputColumn: "Ort"
},
{
key: "info_data.country",
label: "Land",
inputType: "select",
selectDataType: "countrys",
selectOptionAttribute: "name",
selectValueAttribute: "name",
disabledInTable: true,
inputColumn: "Ort"
},
{
key: "address",
label: "Adresse",
component: address
},
{
key: "description",
label: "Beschreibung",
inputType: "textarea",
}
],
showTabs: [
{
label: 'Informationen',
}, {
label: 'Dateien',
},{label: 'Kundeninventar', key: 'customerinventoryitems'},{label: 'Wiki'}
]
},
users: {
label: "Benutzer",
labelSingle: "Benutzer"
@@ -1968,6 +2185,179 @@ export const useDataStore = defineStore('data', () => {
}
]
},
customerinventoryitems: {
isArchivable: true,
label: "Kundeninventar",
labelSingle: "Kundeninventarartikel",
isStandardEntity: true,
selectWithInformation: "*, files(*), customer(id,name), customerspace(id,name,space_number), product(id,name,article_number,description,manufacturer,manufacturer_number,purchase_price,vendorAllocation), vendor(id,name)",
redirect: true,
numberRangeHolder: "customerInventoryId",
historyItemHolder: "customerinventoryitem",
inputColumns: [
"Allgemeines",
"Anschaffung"
],
filters:[{
name: "Archivierte ausblenden",
default: true,
"filterFunction": function (row) {
return !row.archived
}
}],
templateColumns: [
{
key: "name",
label: "Name",
title: true,
required: true,
inputType: "text",
inputColumn: "Allgemeines",
sortable: true
},
{
key: "customer",
label: "Kunde",
inputType: "select",
required: true,
selectDataType: "customers",
selectOptionAttribute: "name",
selectSearchAttributes: ["name"],
component: customer,
inputColumn: "Allgemeines",
sortable: true
},
{
key: "customerInventoryId",
label: "Kundeninventar-ID",
inputType: "text",
inputIsNumberRange: true,
inputColumn: "Allgemeines",
sortable: true
},
{
key: "product",
label: "Ableitung von Artikel",
inputType: "select",
selectDataType: "products",
selectOptionAttribute: "name",
selectSearchAttributes: ["name", "article_number"],
inputColumn: "Allgemeines",
component: product,
inputChangeFunction: function (row, loadedOptions) {
const products = loadedOptions?.products || []
const selected = products.find((p) => p.id === row.product)
if (!selected) return
row.name = selected.name || null
row.description = selected.description || null
row.manufacturer = selected.manufacturer || null
row.manufacturerNumber = selected.manufacturer_number || null
row.purchasePrice = typeof selected.purchase_price === "number" ? selected.purchase_price : row.purchasePrice
row.currentValue = row.currentValue ?? row.purchasePrice
const allocations = Array.isArray(selected.vendor_allocation)
? selected.vendor_allocation
: (Array.isArray(selected.vendorAllocation) ? selected.vendorAllocation : [])
const firstAllocation = allocations[0]
if (typeof firstAllocation === "number") {
row.vendor = firstAllocation
} else if (firstAllocation && typeof firstAllocation === "object") {
row.vendor = firstAllocation.vendor || firstAllocation.vendor_id || firstAllocation.id || row.vendor
}
}
},
{
key: "description",
label: "Beschreibung",
inputType: "textarea",
inputColumn: "Allgemeines",
sortable: true
},
{
key: "customerspace",
label: "Aktueller Kundenlagerplatz",
inputType: "select",
selectDataType: "customerspaces",
selectOptionAttribute: "name",
selectSearchAttributes: ["name", "space_number"],
inputColumn: "Allgemeines",
component: space
},
{
key: "serialNumber",
label: "Seriennummer",
inputType: "text",
inputColumn: "Allgemeines"
},
{
key: "quantity",
label: "Menge",
inputType: "number",
inputColumn: "Allgemeines",
disabledFunction: function (item) {
return item.serialNumber
},
helpComponent: quantity,
sortable: true
},
{
key: "purchaseDate",
label: "Kaufdatum",
inputType: "date",
inputColumn: "Anschaffung",
sortable: true
},
{
key: "vendor",
label: "Lieferant",
inputType: "select",
selectDataType: "vendors",
selectOptionAttribute: "name",
selectSearchAttributes: ["name"],
inputColumn: "Anschaffung",
component: vendor
},
{
key: "purchasePrice",
label: "Kaufpreis",
inputType: "number",
inputStepSize: "0.01",
inputColumn: "Anschaffung",
component: purchasePrice,
sortable: true
},
{
key: "manufacturer",
label: "Hersteller",
inputType: "text",
inputColumn: "Anschaffung"
},
{
key: "manufacturerNumber",
label: "Herstellernummer",
inputType: "text",
inputColumn: "Anschaffung"
},
{
key: "currentValue",
label: "Aktueller Wert",
inputType: "number",
inputStepSize: "0.01",
inputColumn: "Anschaffung",
sortable: true
},
],
showTabs: [
{
label: 'Informationen',
}, {
label: 'Dateien',
}, {
label: 'Wiki',
}
]
},
inventoryitems: {
isArchivable: true,
label: "Inventarartikel",