Referrals: 4 neue Beziehungen + Bearbeiten-Stift pro Eintrag
Beziehungs-Dropdown erweitert um Schwiegertochter/Schwiegersohn, Schwiegermutter/Schwiegervater, Oma/Opa, Uroma/Uropa (Whitelist front- und backend synchron). Bearbeiten-Stift pro Zeile (vor der Muelltonne): Beziehung und/oder Gegen-Kunde aenderbar. Neuer PUT /:customerId/referrals/:referralId mit Whitelist-Pruefung, Doppel-Werber-409 (Self-Ausschluss), Portal-Block und UPDATE-Auditeintrag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,10 @@ export const REFERRAL_RELATIONSHIPS = [
|
||||
'Freund/Kumpel',
|
||||
'Eltern',
|
||||
'Bruder/Schwester',
|
||||
'Schwiegertochter/Schwiegersohn',
|
||||
'Schwiegermutter/Schwiegervater',
|
||||
'Oma/Opa',
|
||||
'Uroma/Uropa',
|
||||
'Bekannte',
|
||||
'sonstige',
|
||||
] as const;
|
||||
@@ -108,6 +112,60 @@ export async function createReferral(params: {
|
||||
return created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ändert eine bestehende Werbe-Beziehung (Beziehungsart und/oder den
|
||||
* beteiligten Gegen-Kunden). recruiter/recruited werden vom Controller aus
|
||||
* der Richtung + aktueller Kundenakte bestimmt.
|
||||
*/
|
||||
export async function updateReferral(params: {
|
||||
id: number;
|
||||
recruiterId: number;
|
||||
recruitedId: number;
|
||||
relationship: string;
|
||||
}) {
|
||||
const { id, recruiterId, recruitedId, relationship } = params;
|
||||
|
||||
if (!Number.isInteger(id)) {
|
||||
throw new ReferralError('Ungültige ID');
|
||||
}
|
||||
if (!Number.isInteger(recruiterId) || !Number.isInteger(recruitedId)) {
|
||||
throw new ReferralError('Ungültige Kunden-ID');
|
||||
}
|
||||
if (recruiterId === recruitedId) {
|
||||
throw new ReferralError('Ein Kunde kann sich nicht selbst werben');
|
||||
}
|
||||
if (!REFERRAL_RELATIONSHIPS.includes(relationship as typeof REFERRAL_RELATIONSHIPS[number])) {
|
||||
throw new ReferralError('Ungültige Beziehungsart');
|
||||
}
|
||||
|
||||
const existing = await prisma.customerReferral.findUnique({ where: { id } });
|
||||
if (!existing) {
|
||||
throw new ReferralError('Eintrag nicht gefunden', 404);
|
||||
}
|
||||
|
||||
// Beide Kunden müssen existieren
|
||||
const count = await prisma.customer.count({ where: { id: { in: [recruiterId, recruitedId] } } });
|
||||
if (count !== 2) {
|
||||
throw new ReferralError('Kunde nicht gefunden', 404);
|
||||
}
|
||||
|
||||
// recruitedId ist @unique → falls der Geworbene auf einen anderen Kunden
|
||||
// geändert wird, der bereits einen Werber hat, klare Meldung statt DB-Fehler.
|
||||
if (recruitedId !== existing.recruitedId) {
|
||||
const clash = await prisma.customerReferral.findUnique({ where: { recruitedId } });
|
||||
if (clash && clash.id !== id) {
|
||||
throw new ReferralError('Dieser Kunde wurde bereits als angeworben markiert. Bitte zuerst den bestehenden Eintrag entfernen.', 409);
|
||||
}
|
||||
}
|
||||
|
||||
const updated = await prisma.customerReferral.update({
|
||||
where: { id },
|
||||
data: { recruiterId, recruitedId, relationship },
|
||||
include: { recruiter: { select: CUSTOMER_SELECT }, recruited: { select: CUSTOMER_SELECT } },
|
||||
});
|
||||
return updated;
|
||||
}
|
||||
|
||||
export async function deleteReferral(id: number): Promise<boolean> {
|
||||
if (!Number.isInteger(id)) return false;
|
||||
const existing = await prisma.customerReferral.findUnique({ where: { id } });
|
||||
|
||||
Reference in New Issue
Block a user