Vertragstypen für Änderungsanfragen pflegen
This commit is contained in:
1
backend/db/migrations/0036_allowed_contracttypes.sql
Normal file
1
backend/db/migrations/0036_allowed_contracttypes.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "contracts" ADD COLUMN "allowedContracttypes" jsonb DEFAULT '[]'::jsonb NOT NULL;
|
||||||
@@ -246,6 +246,13 @@
|
|||||||
"when": 1778191200000,
|
"when": 1778191200000,
|
||||||
"tag": "0035_contract_history",
|
"tag": "0035_contract_history",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 35,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1778194800000,
|
||||||
|
"tag": "0036_allowed_contracttypes",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export const contracts = pgTable(
|
|||||||
contracttype: bigint("contracttype", { mode: "number" }).references(
|
contracttype: bigint("contracttype", { mode: "number" }).references(
|
||||||
() => contracttypes.id
|
() => contracttypes.id
|
||||||
),
|
),
|
||||||
|
allowedContracttypes: jsonb("allowedContracttypes").notNull().default([]),
|
||||||
|
|
||||||
bankingIban: text("bankingIban"),
|
bankingIban: text("bankingIban"),
|
||||||
bankingBIC: text("bankingBIC"),
|
bankingBIC: text("bankingBIC"),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ async function getPortalContract(server: FastifyInstance, req: any, contractId:
|
|||||||
tenant: contracts.tenant,
|
tenant: contracts.tenant,
|
||||||
customer: contracts.customer,
|
customer: contracts.customer,
|
||||||
contracttype: contracts.contracttype,
|
contracttype: contracts.contracttype,
|
||||||
|
allowedContracttypes: contracts.allowedContracttypes,
|
||||||
archived: contracts.archived,
|
archived: contracts.archived,
|
||||||
})
|
})
|
||||||
.from(contracts)
|
.from(contracts)
|
||||||
@@ -121,6 +122,14 @@ export default async function portalContractRoutes(server: FastifyInstance) {
|
|||||||
return reply.code(400).send({ error: "Ungültiger Vertragstyp" })
|
return reply.code(400).send({ error: "Ungültiger Vertragstyp" })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allowedContracttypes = Array.isArray(contract.allowedContracttypes)
|
||||||
|
? contract.allowedContracttypes.map((id) => Number(id)).filter((id) => Number.isInteger(id))
|
||||||
|
: []
|
||||||
|
|
||||||
|
if (!allowedContracttypes.includes(requestedContracttype.id)) {
|
||||||
|
return reply.code(400).send({ error: "Dieser Vertragstyp steht für diesen Vertrag nicht zur Auswahl" })
|
||||||
|
}
|
||||||
|
|
||||||
const [currentContracttype] = contract.contracttype
|
const [currentContracttype] = contract.contracttype
|
||||||
? await server.db
|
? await server.db
|
||||||
.select({
|
.select({
|
||||||
|
|||||||
@@ -165,9 +165,27 @@ function getContactLabel(contact: any) {
|
|||||||
return contact.fullName || [contact.firstName, contact.lastName].filter(Boolean).join(" ") || contact.email || contact.id || "-"
|
return contact.fullName || [contact.firstName, contact.lastName].filter(Boolean).join(" ") || contact.email || contact.id || "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAllowedContracttypeIds(contract: any) {
|
||||||
|
if (!Array.isArray(contract?.allowedContracttypes)) return []
|
||||||
|
return contract.allowedContracttypes.map((id: any) => Number(id)).filter((id: number) => Number.isInteger(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllowedContracttypes(contract: any) {
|
||||||
|
const allowedIds = getAllowedContracttypeIds(contract)
|
||||||
|
return contracttypes.value.filter((item: any) => allowedIds.includes(Number(item.id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedContractAllowedContracttypes = computed(() => {
|
||||||
|
if (!selectedContract.value) return []
|
||||||
|
return getAllowedContracttypes(selectedContract.value)
|
||||||
|
})
|
||||||
|
|
||||||
function openContractChangeRequest(contract: any) {
|
function openContractChangeRequest(contract: any) {
|
||||||
|
const allowedTypes = getAllowedContracttypes(contract)
|
||||||
selectedContract.value = contract
|
selectedContract.value = contract
|
||||||
contractChangeForm.contracttype = contract.contracttype?.id || null
|
contractChangeForm.contracttype = allowedTypes.some((item: any) => item.id === contract.contracttype?.id)
|
||||||
|
? contract.contracttype.id
|
||||||
|
: allowedTypes[0]?.id || null
|
||||||
contractChangeForm.message = ""
|
contractChangeForm.message = ""
|
||||||
contractChangeModalOpen.value = true
|
contractChangeModalOpen.value = true
|
||||||
}
|
}
|
||||||
@@ -589,6 +607,7 @@ onMounted(async () => {
|
|||||||
variant="soft"
|
variant="soft"
|
||||||
icon="i-heroicons-pencil-square"
|
icon="i-heroicons-pencil-square"
|
||||||
class="justify-center"
|
class="justify-center"
|
||||||
|
:disabled="getAllowedContracttypes(contract).length === 0"
|
||||||
@click="openContractChangeRequest(contract)"
|
@click="openContractChangeRequest(contract)"
|
||||||
>
|
>
|
||||||
Änderung anfragen
|
Änderung anfragen
|
||||||
@@ -611,6 +630,22 @@ onMounted(async () => {
|
|||||||
{{ contract.contracttype?.name || "Nicht hinterlegt" }}
|
{{ contract.contracttype?.name || "Nicht hinterlegt" }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="rounded-xl bg-white p-3">
|
||||||
|
<p class="text-xs uppercase tracking-wide text-neutral-400">Änderung möglich zu</p>
|
||||||
|
<div v-if="getAllowedContracttypes(contract).length" class="mt-2 flex flex-wrap gap-2">
|
||||||
|
<UBadge
|
||||||
|
v-for="type in getAllowedContracttypes(contract)"
|
||||||
|
:key="type.id"
|
||||||
|
color="primary"
|
||||||
|
variant="soft"
|
||||||
|
>
|
||||||
|
{{ type.name }}
|
||||||
|
</UBadge>
|
||||||
|
</div>
|
||||||
|
<p v-else class="mt-1 text-sm font-medium text-neutral-900">
|
||||||
|
Keine Änderungstypen freigegeben
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div class="rounded-xl bg-white p-3">
|
<div class="rounded-xl bg-white p-3">
|
||||||
<p class="text-xs uppercase tracking-wide text-neutral-400">Ansprechpartner</p>
|
<p class="text-xs uppercase tracking-wide text-neutral-400">Ansprechpartner</p>
|
||||||
<p class="mt-1 text-sm font-medium text-neutral-900">
|
<p class="mt-1 text-sm font-medium text-neutral-900">
|
||||||
@@ -751,12 +786,15 @@ onMounted(async () => {
|
|||||||
<label class="mb-1 block text-sm font-medium text-neutral-700">Gewünschter Vertragstyp</label>
|
<label class="mb-1 block text-sm font-medium text-neutral-700">Gewünschter Vertragstyp</label>
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
v-model="contractChangeForm.contracttype"
|
v-model="contractChangeForm.contracttype"
|
||||||
:items="contracttypes"
|
:items="selectedContractAllowedContracttypes"
|
||||||
value-key="id"
|
value-key="id"
|
||||||
label-key="name"
|
label-key="name"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
placeholder="Vertragstyp auswählen"
|
placeholder="Vertragstyp auswählen"
|
||||||
/>
|
/>
|
||||||
|
<p v-if="!selectedContractAllowedContracttypes.length" class="mt-2 text-sm text-neutral-500">
|
||||||
|
Für diesen Vertrag sind aktuell keine Änderungstypen freigegeben.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 block text-sm font-medium text-neutral-700">Nachricht optional</label>
|
<label class="mb-1 block text-sm font-medium text-neutral-700">Nachricht optional</label>
|
||||||
|
|||||||
@@ -853,6 +853,15 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
item.billingInterval = selectedContractType.billingInterval || null
|
item.billingInterval = selectedContractType.billingInterval || null
|
||||||
},
|
},
|
||||||
inputColumn: "Allgemeines"
|
inputColumn: "Allgemeines"
|
||||||
|
},{
|
||||||
|
key: "allowedContracttypes",
|
||||||
|
label: "Vertragstypen für Änderungsanfragen",
|
||||||
|
inputType: "select",
|
||||||
|
selectDataType: "contracttypes",
|
||||||
|
selectOptionAttribute: "name",
|
||||||
|
selectSearchAttributes: ["name"],
|
||||||
|
selectMultiple: true,
|
||||||
|
inputColumn: "Allgemeines"
|
||||||
},{
|
},{
|
||||||
key: "active",
|
key: "active",
|
||||||
label: "Aktiv",
|
label: "Aktiv",
|
||||||
|
|||||||
Reference in New Issue
Block a user