complete new audit system
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import * as contractService from '../services/contract.service.js';
|
||||
import * as contractCockpitService from '../services/contractCockpit.service.js';
|
||||
import * as contractHistoryService from '../services/contractHistory.service.js';
|
||||
import * as authorizationService from '../services/authorization.service.js';
|
||||
import { ApiResponse, AuthRequest } from '../types/index.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import { logChange } from '../services/audit.service.js';
|
||||
|
||||
export async function getContracts(req: AuthRequest, res: Response): Promise<void> {
|
||||
try {
|
||||
@@ -100,6 +99,12 @@ export async function getContract(req: AuthRequest, res: Response): Promise<void
|
||||
export async function createContract(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const contract = await contractService.createContract(req.body);
|
||||
await logChange({
|
||||
req, action: 'CREATE', resourceType: 'Contract',
|
||||
resourceId: contract.id.toString(),
|
||||
label: `Vertrag ${contract.contractNumber} angelegt`,
|
||||
customerId: contract.customerId,
|
||||
});
|
||||
res.status(201).json({ success: true, data: contract } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -109,9 +114,69 @@ export async function createContract(req: Request, res: Response): Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateContract(req: Request, res: Response): Promise<void> {
|
||||
export async function updateContract(req: AuthRequest, res: Response): Promise<void> {
|
||||
try {
|
||||
const contract = await contractService.updateContract(parseInt(req.params.id), req.body);
|
||||
const contractId = parseInt(req.params.id);
|
||||
// Vorherigen Stand laden für Audit-Vergleich
|
||||
const before = await prisma.contract.findUnique({
|
||||
where: { id: contractId },
|
||||
include: { energyDetails: true, internetDetails: true, mobileDetails: true, tvDetails: true, carInsuranceDetails: true },
|
||||
});
|
||||
|
||||
const contract = await contractService.updateContract(contractId, req.body);
|
||||
|
||||
// Geänderte Felder ermitteln
|
||||
const changes: Record<string, { von: unknown; nach: unknown }> = {};
|
||||
const fieldLabels: Record<string, string> = {
|
||||
status: 'Status', startDate: 'Vertragsbeginn', endDate: 'Vertragsende',
|
||||
portalUsername: 'Portal-Benutzername', customerNumberAtProvider: 'Kundennummer beim Anbieter',
|
||||
providerId: 'Anbieter', tariffId: 'Tarif', cancellationPeriodId: 'Kündigungsfrist',
|
||||
contractDurationId: 'Vertragslaufzeit', platformId: 'Vertriebsplattform',
|
||||
cancellationDate: 'Kündigungsdatum', cancellationSentDate: 'Kündigung gesendet am',
|
||||
identityDocumentId: 'Ausweis', bankCardId: 'Bankverbindung', addressId: 'Adresse',
|
||||
commission: 'Provision', notes: 'Notizen',
|
||||
};
|
||||
const energyLabels: Record<string, string> = {
|
||||
meterId: 'Zähler', maloId: 'MaLo-ID', annualConsumption: 'Jahresverbrauch',
|
||||
basePrice: 'Grundpreis', unitPrice: 'Arbeitspreis', unitPriceNt: 'NT-Arbeitspreis', bonus: 'Bonus',
|
||||
};
|
||||
|
||||
// Hauptfelder vergleichen
|
||||
const body = req.body;
|
||||
if (before) {
|
||||
for (const [key, newVal] of Object.entries(body)) {
|
||||
if (['energyDetails', 'internetDetails', 'mobileDetails', 'tvDetails', 'carInsuranceDetails', 'password'].includes(key)) continue;
|
||||
const oldVal = (before as any)[key];
|
||||
const norm = (v: unknown) => (v === null || v === undefined || v === '' ? null : v);
|
||||
if (JSON.stringify(norm(oldVal)) !== JSON.stringify(norm(newVal))) {
|
||||
const label = fieldLabels[key] || key;
|
||||
changes[label] = { von: oldVal ?? '-', nach: newVal ?? '-' };
|
||||
}
|
||||
}
|
||||
// Energie-Details vergleichen
|
||||
if (body.energyDetails && before.energyDetails) {
|
||||
for (const [key, newVal] of Object.entries(body.energyDetails)) {
|
||||
const oldVal = (before.energyDetails as any)[key];
|
||||
const norm = (v: unknown) => (v === null || v === undefined || v === '' ? null : v);
|
||||
if (JSON.stringify(norm(oldVal)) !== JSON.stringify(norm(newVal))) {
|
||||
const label = energyLabels[key] || key;
|
||||
changes[label] = { von: oldVal ?? '-', nach: newVal ?? '-' };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const changeList = Object.entries(changes).map(([f, c]) => `${f}: ${c.von} → ${c.nach}`).join(', ');
|
||||
await logChange({
|
||||
req, action: 'UPDATE', resourceType: 'Contract',
|
||||
resourceId: contractId.toString(),
|
||||
label: changeList
|
||||
? `Vertrag ${before?.contractNumber || contractId} aktualisiert: ${changeList}`
|
||||
: `Vertrag ${before?.contractNumber || contractId} aktualisiert`,
|
||||
details: Object.keys(changes).length > 0 ? changes : undefined,
|
||||
customerId: before?.customerId,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: contract } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -123,7 +188,15 @@ export async function updateContract(req: Request, res: Response): Promise<void>
|
||||
|
||||
export async function deleteContract(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
await contractService.deleteContract(parseInt(req.params.id));
|
||||
const contractId = parseInt(req.params.id);
|
||||
const contract = await prisma.contract.findUnique({ where: { id: contractId }, select: { contractNumber: true, customerId: true } });
|
||||
await contractService.deleteContract(contractId);
|
||||
await logChange({
|
||||
req, action: 'DELETE', resourceType: 'Contract',
|
||||
resourceId: contractId.toString(),
|
||||
label: `Vertrag ${contract?.contractNumber} gelöscht`,
|
||||
customerId: contract?.customerId,
|
||||
});
|
||||
res.json({ success: true, message: 'Vertrag gelöscht' } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -165,6 +238,13 @@ export async function createFollowUp(req: AuthRequest, res: Response): Promise<v
|
||||
createdBy
|
||||
);
|
||||
|
||||
await logChange({
|
||||
req, action: 'CREATE', resourceType: 'Contract',
|
||||
resourceId: contract.id.toString(),
|
||||
label: `Folgevertrag erstellt für ${previousContract.contractNumber}`,
|
||||
customerId: contract.customerId,
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: contract } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -295,6 +375,13 @@ export async function addSuccessorMeter(req: AuthRequest, res: Response): Promis
|
||||
data: { meterId: parseInt(meterId) },
|
||||
});
|
||||
|
||||
await logChange({
|
||||
req, action: 'CREATE', resourceType: 'ContractMeter',
|
||||
resourceId: contractMeter.id.toString(),
|
||||
label: `Folgezähler hinzugefügt zu Vertrag #${contractId}`,
|
||||
customerId: contract.customerId,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: contractMeter } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -307,7 +394,13 @@ export async function addSuccessorMeter(req: AuthRequest, res: Response): Promis
|
||||
export async function removeContractMeter(req: AuthRequest, res: Response): Promise<void> {
|
||||
try {
|
||||
const contractMeterId = parseInt(req.params.contractMeterId);
|
||||
const contractId = parseInt(req.params.id);
|
||||
await prisma.contractMeter.delete({ where: { id: contractMeterId } });
|
||||
await logChange({
|
||||
req, action: 'DELETE', resourceType: 'ContractMeter',
|
||||
resourceId: contractMeterId.toString(),
|
||||
label: `Folgezähler entfernt von Vertrag #${contractId}`,
|
||||
});
|
||||
res.json({ success: true, data: null } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
@@ -346,6 +439,12 @@ export async function snoozeContract(req: Request, res: Response): Promise<void>
|
||||
},
|
||||
});
|
||||
|
||||
await logChange({
|
||||
req, action: 'UPDATE', resourceType: 'Contract',
|
||||
resourceId: id.toString(),
|
||||
label: `Vertrag ${updated.contractNumber} zurückgestellt`,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: updated,
|
||||
|
||||
Reference in New Issue
Block a user