complete new audit system

This commit is contained in:
2026-03-21 18:23:54 +01:00
parent 38b3b7da73
commit fd55742c57
159 changed files with 2841 additions and 736 deletions
+107 -11
View File
@@ -32,6 +32,9 @@ var __importStar = (this && this.__importStar) || (function () {
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContracts = getContracts;
exports.getContract = getContract;
@@ -47,12 +50,12 @@ exports.getCockpit = getCockpit;
exports.addSuccessorMeter = addSuccessorMeter;
exports.removeContractMeter = removeContractMeter;
exports.snoozeContract = snoozeContract;
const client_1 = require("@prisma/client");
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const contractService = __importStar(require("../services/contract.service.js"));
const contractCockpitService = __importStar(require("../services/contractCockpit.service.js"));
const contractHistoryService = __importStar(require("../services/contractHistory.service.js"));
const authorizationService = __importStar(require("../services/authorization.service.js"));
const prisma = new client_1.PrismaClient();
const audit_service_js_1 = require("../services/audit.service.js");
async function getContracts(req, res) {
try {
const { customerId, type, status, search, page, limit, tree } = req.query;
@@ -138,6 +141,12 @@ async function getContract(req, res) {
async function createContract(req, res) {
try {
const contract = await contractService.createContract(req.body);
await (0, audit_service_js_1.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 });
}
catch (error) {
@@ -149,7 +158,63 @@ async function createContract(req, res) {
}
async function updateContract(req, res) {
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_js_1.default.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 = {};
const fieldLabels = {
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 = {
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[key];
const norm = (v) => (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[key];
const norm = (v) => (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 (0, audit_service_js_1.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 });
}
catch (error) {
@@ -161,7 +226,15 @@ async function updateContract(req, res) {
}
async function deleteContract(req, res) {
try {
await contractService.deleteContract(parseInt(req.params.id));
const contractId = parseInt(req.params.id);
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId }, select: { contractNumber: true, customerId: true } });
await contractService.deleteContract(contractId);
await (0, audit_service_js_1.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' });
}
catch (error) {
@@ -175,7 +248,7 @@ async function createFollowUp(req, res) {
try {
const previousContractId = parseInt(req.params.id);
// Vorgängervertrag laden für Vertragsnummer
const previousContract = await prisma.contract.findUnique({
const previousContract = await prisma_js_1.default.contract.findUnique({
where: { id: previousContractId },
select: { contractNumber: true },
});
@@ -189,6 +262,12 @@ async function createFollowUp(req, res) {
await contractHistoryService.createFollowUpHistoryEntry(previousContractId, contract.contractNumber, createdBy);
// Historie-Eintrag für den neuen Folgevertrag erstellen
await contractHistoryService.createNewContractFromPredecessorEntry(contract.id, previousContract.contractNumber, createdBy);
await (0, audit_service_js_1.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 });
}
catch (error) {
@@ -272,7 +351,7 @@ async function addSuccessorMeter(req, res) {
try {
const contractId = parseInt(req.params.id);
const { meterId, installedAt, finalReadingPrevious } = req.body;
const contract = await prisma.contract.findUnique({
const contract = await prisma_js_1.default.contract.findUnique({
where: { id: contractId },
include: { energyDetails: { include: { contractMeters: { orderBy: { position: 'asc' } } } } },
});
@@ -288,7 +367,7 @@ async function addSuccessorMeter(req, res) {
// Vorherigen Zähler als gewechselt markieren
if (existingMeters.length > 0 && finalReadingPrevious !== undefined) {
const prevMeter = existingMeters[existingMeters.length - 1];
await prisma.contractMeter.update({
await prisma_js_1.default.contractMeter.update({
where: { id: prevMeter.id },
data: {
removedAt: installedAt ? new Date(installedAt) : new Date(),
@@ -296,7 +375,7 @@ async function addSuccessorMeter(req, res) {
},
});
}
const contractMeter = await prisma.contractMeter.create({
const contractMeter = await prisma_js_1.default.contractMeter.create({
data: {
energyContractDetailsId: ecdId,
meterId: parseInt(meterId),
@@ -306,10 +385,16 @@ async function addSuccessorMeter(req, res) {
include: { meter: { include: { readings: true } } },
});
// Aktuellen Zähler am Vertrag aktualisieren
await prisma.energyContractDetails.update({
await prisma_js_1.default.energyContractDetails.update({
where: { id: ecdId },
data: { meterId: parseInt(meterId) },
});
await (0, audit_service_js_1.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 });
}
catch (error) {
@@ -322,7 +407,13 @@ async function addSuccessorMeter(req, res) {
async function removeContractMeter(req, res) {
try {
const contractMeterId = parseInt(req.params.contractMeterId);
await prisma.contractMeter.delete({ where: { id: contractMeterId } });
const contractId = parseInt(req.params.id);
await prisma_js_1.default.contractMeter.delete({ where: { id: contractMeterId } });
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractMeter',
resourceId: contractMeterId.toString(),
label: `Folgezähler entfernt von Vertrag #${contractId}`,
});
res.json({ success: true, data: null });
}
catch (error) {
@@ -348,7 +439,7 @@ async function snoozeContract(req, res) {
reviewDate.setMonth(reviewDate.getMonth() + months);
}
// Wenn beides leer → nextReviewDate wird auf null gesetzt (Snooze aufheben)
const updated = await prisma.contract.update({
const updated = await prisma_js_1.default.contract.update({
where: { id },
data: { nextReviewDate: reviewDate },
select: {
@@ -357,6 +448,11 @@ async function snoozeContract(req, res) {
nextReviewDate: true,
},
});
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Contract',
resourceId: id.toString(),
label: `Vertrag ${updated.contractNumber} zurückgestellt`,
});
res.json({
success: true,
data: updated,