complete new audit system

This commit is contained in:
2026-03-21 18:23:54 +01:00
parent 4f359df161
commit 219e1930f7
159 changed files with 2841 additions and 736 deletions
+50 -50
View File
@@ -37,10 +37,10 @@ exports.addRepresentative = addRepresentative;
exports.removeRepresentative = removeRepresentative;
exports.searchCustomersForRepresentative = searchCustomersForRepresentative;
const client_1 = require("@prisma/client");
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const helpers_js_1 = require("../utils/helpers.js");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const prisma = new client_1.PrismaClient();
// Helper zum Löschen von Dateien
function deleteFileIfExists(filePath) {
if (!filePath)
@@ -72,7 +72,7 @@ async function getAllCustomers(filters) {
];
}
const [customers, total] = await Promise.all([
prisma.customer.findMany({
prisma_js_1.default.customer.findMany({
where,
skip,
take,
@@ -84,7 +84,7 @@ async function getAllCustomers(filters) {
},
},
}),
prisma.customer.count({ where }),
prisma_js_1.default.customer.count({ where }),
]);
return {
customers,
@@ -92,7 +92,7 @@ async function getAllCustomers(filters) {
};
}
async function getCustomerById(id) {
return prisma.customer.findUnique({
return prisma_js_1.default.customer.findUnique({
where: { id },
include: {
addresses: true,
@@ -122,7 +122,7 @@ async function getCustomerById(id) {
});
}
async function getCustomersByIds(ids) {
return prisma.customer.findMany({
return prisma_js_1.default.customer.findMany({
where: { id: { in: ids } },
select: {
id: true,
@@ -131,7 +131,7 @@ async function getCustomersByIds(ids) {
});
}
async function createCustomer(data) {
return prisma.customer.create({
return prisma_js_1.default.customer.create({
data: {
...data,
customerNumber: (0, helpers_js_1.generateCustomerNumber)(),
@@ -139,22 +139,22 @@ async function createCustomer(data) {
});
}
async function updateCustomer(id, data) {
return prisma.customer.update({
return prisma_js_1.default.customer.update({
where: { id },
data,
});
}
async function deleteCustomer(id) {
// Vor dem Löschen: Alle Dokumente (Dateien) des Kunden löschen
const customer = await prisma.customer.findUnique({
const customer = await prisma_js_1.default.customer.findUnique({
where: { id },
select: { businessRegistrationPath: true, commercialRegisterPath: true, privacyPolicyPath: true },
});
const bankCards = await prisma.bankCard.findMany({
const bankCards = await prisma_js_1.default.bankCard.findMany({
where: { customerId: id },
select: { documentPath: true },
});
const identityDocs = await prisma.identityDocument.findMany({
const identityDocs = await prisma_js_1.default.identityDocument.findMany({
where: { customerId: id },
select: { documentPath: true },
});
@@ -172,13 +172,13 @@ async function deleteCustomer(id) {
deleteFileIfExists(doc.documentPath);
}
// Jetzt DB-Eintrag löschen (Cascade löscht die verknüpften Einträge)
return prisma.customer.delete({
return prisma_js_1.default.customer.delete({
where: { id },
});
}
// Address operations
async function getCustomerAddresses(customerId) {
return prisma.address.findMany({
return prisma_js_1.default.address.findMany({
where: { customerId },
orderBy: [{ isDefault: 'desc' }, { createdAt: 'desc' }],
});
@@ -186,12 +186,12 @@ async function getCustomerAddresses(customerId) {
async function createAddress(customerId, data) {
// If this is set as default, unset other defaults of same type
if (data.isDefault) {
await prisma.address.updateMany({
await prisma_js_1.default.address.updateMany({
where: { customerId, type: data.type },
data: { isDefault: false },
});
}
return prisma.address.create({
return prisma_js_1.default.address.create({
data: {
customerId,
...data,
@@ -199,11 +199,11 @@ async function createAddress(customerId, data) {
});
}
async function updateAddress(id, data) {
const address = await prisma.address.findUnique({ where: { id } });
const address = await prisma_js_1.default.address.findUnique({ where: { id } });
if (!address)
throw new Error('Adresse nicht gefunden');
if (data.isDefault) {
await prisma.address.updateMany({
await prisma_js_1.default.address.updateMany({
where: {
customerId: address.customerId,
type: data.type || address.type,
@@ -212,13 +212,13 @@ async function updateAddress(id, data) {
data: { isDefault: false },
});
}
return prisma.address.update({
return prisma_js_1.default.address.update({
where: { id },
data,
});
}
async function deleteAddress(id) {
return prisma.address.delete({ where: { id } });
return prisma_js_1.default.address.delete({ where: { id } });
}
// Bank card operations
async function getCustomerBankCards(customerId, showInactive = false) {
@@ -226,13 +226,13 @@ async function getCustomerBankCards(customerId, showInactive = false) {
if (!showInactive) {
where.isActive = true;
}
return prisma.bankCard.findMany({
return prisma_js_1.default.bankCard.findMany({
where,
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
});
}
async function createBankCard(customerId, data) {
return prisma.bankCard.create({
return prisma_js_1.default.bankCard.create({
data: {
customerId,
...data,
@@ -241,18 +241,18 @@ async function createBankCard(customerId, data) {
});
}
async function updateBankCard(id, data) {
return prisma.bankCard.update({
return prisma_js_1.default.bankCard.update({
where: { id },
data,
});
}
async function deleteBankCard(id) {
// Erst Datei-Pfad holen, dann Datei löschen, dann DB-Eintrag löschen
const bankCard = await prisma.bankCard.findUnique({ where: { id } });
const bankCard = await prisma_js_1.default.bankCard.findUnique({ where: { id } });
if (bankCard?.documentPath) {
deleteFileIfExists(bankCard.documentPath);
}
return prisma.bankCard.delete({ where: { id } });
return prisma_js_1.default.bankCard.delete({ where: { id } });
}
// Identity document operations
async function getCustomerDocuments(customerId, showInactive = false) {
@@ -260,13 +260,13 @@ async function getCustomerDocuments(customerId, showInactive = false) {
if (!showInactive) {
where.isActive = true;
}
return prisma.identityDocument.findMany({
return prisma_js_1.default.identityDocument.findMany({
where,
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
});
}
async function createDocument(customerId, data) {
return prisma.identityDocument.create({
return prisma_js_1.default.identityDocument.create({
data: {
customerId,
...data,
@@ -275,18 +275,18 @@ async function createDocument(customerId, data) {
});
}
async function updateDocument(id, data) {
return prisma.identityDocument.update({
return prisma_js_1.default.identityDocument.update({
where: { id },
data,
});
}
async function deleteDocument(id) {
// Erst Datei-Pfad holen, dann Datei löschen, dann DB-Eintrag löschen
const document = await prisma.identityDocument.findUnique({ where: { id } });
const document = await prisma_js_1.default.identityDocument.findUnique({ where: { id } });
if (document?.documentPath) {
deleteFileIfExists(document.documentPath);
}
return prisma.identityDocument.delete({ where: { id } });
return prisma_js_1.default.identityDocument.delete({ where: { id } });
}
// Meter operations
async function getCustomerMeters(customerId, showInactive = false) {
@@ -294,7 +294,7 @@ async function getCustomerMeters(customerId, showInactive = false) {
if (!showInactive) {
where.isActive = true;
}
return prisma.meter.findMany({
return prisma_js_1.default.meter.findMany({
where,
include: {
readings: {
@@ -306,7 +306,7 @@ async function getCustomerMeters(customerId, showInactive = false) {
});
}
async function createMeter(customerId, data) {
return prisma.meter.create({
return prisma_js_1.default.meter.create({
data: {
customerId,
...data,
@@ -315,14 +315,14 @@ async function createMeter(customerId, data) {
});
}
async function updateMeter(id, data) {
return prisma.meter.update({
return prisma_js_1.default.meter.update({
where: { id },
data,
});
}
async function deleteMeter(id) {
// Prüfen ob der Zähler noch an Verträgen hängt
const linkedContracts = await prisma.contractMeter.findMany({
const linkedContracts = await prisma_js_1.default.contractMeter.findMany({
where: { meterId: id },
include: { energyContractDetails: { include: { contract: { select: { contractNumber: true } } } } },
});
@@ -333,7 +333,7 @@ async function deleteMeter(id) {
throw new Error(`Zähler kann nicht gelöscht werden noch an Vertrag/Verträgen zugeordnet: ${contractNumbers}`);
}
// Auch direkte meterId-Referenz auf EnergyContractDetails prüfen
const directLinks = await prisma.energyContractDetails.findMany({
const directLinks = await prisma_js_1.default.energyContractDetails.findMany({
where: { meterId: id },
include: { contract: { select: { contractNumber: true } } },
});
@@ -341,7 +341,7 @@ async function deleteMeter(id) {
const contractNumbers = directLinks.map(d => d.contract.contractNumber).join(', ');
throw new Error(`Zähler kann nicht gelöscht werden noch an Vertrag/Verträgen zugeordnet: ${contractNumbers}`);
}
return prisma.meter.delete({ where: { id } });
return prisma_js_1.default.meter.delete({ where: { id } });
}
async function addMeterReading(meterId, data) {
// Validierung: Zählerstand muss monoton steigend sein
@@ -349,7 +349,7 @@ async function addMeterReading(meterId, data) {
if (data.valueNt !== undefined) {
await validateReadingValue(meterId, data.readingDate, data.valueNt, undefined, 'NT');
}
return prisma.meterReading.create({
return prisma_js_1.default.meterReading.create({
data: {
meterId,
readingDate: data.readingDate,
@@ -361,14 +361,14 @@ async function addMeterReading(meterId, data) {
});
}
async function getMeterReadings(meterId) {
return prisma.meterReading.findMany({
return prisma_js_1.default.meterReading.findMany({
where: { meterId },
orderBy: { readingDate: 'desc' },
});
}
async function updateMeterReading(meterId, readingId, data) {
// Verify the reading belongs to the meter
const reading = await prisma.meterReading.findFirst({
const reading = await prisma_js_1.default.meterReading.findFirst({
where: { id: readingId, meterId },
});
if (!reading) {
@@ -384,7 +384,7 @@ async function updateMeterReading(meterId, readingId, data) {
await validateReadingValue(meterId, data.readingDate || reading.readingDate, ntVal, readingId, 'NT');
}
}
return prisma.meterReading.update({
return prisma_js_1.default.meterReading.update({
where: { id: readingId },
data,
});
@@ -394,7 +394,7 @@ async function updateMeterReading(meterId, readingId, data) {
* tariffLabel: 'HT' für Hochtarif/Eintarif, 'NT' für Niedertarif
*/
async function validateReadingValue(meterId, readingDate, value, excludeReadingId, tariffLabel = 'HT') {
const existing = await prisma.meterReading.findMany({
const existing = await prisma_js_1.default.meterReading.findMany({
where: { meterId, ...(excludeReadingId ? { id: { not: excludeReadingId } } : {}) },
orderBy: { readingDate: 'asc' },
});
@@ -416,20 +416,20 @@ async function validateReadingValue(meterId, readingDate, value, excludeReadingI
}
async function deleteMeterReading(meterId, readingId) {
// Verify the reading belongs to the meter
const reading = await prisma.meterReading.findFirst({
const reading = await prisma_js_1.default.meterReading.findFirst({
where: { id: readingId, meterId },
});
if (!reading) {
throw new Error('Zählerstand nicht gefunden');
}
return prisma.meterReading.delete({
return prisma_js_1.default.meterReading.delete({
where: { id: readingId },
});
}
// ==================== PORTAL SETTINGS ====================
async function updatePortalSettings(customerId, data) {
// Wenn Portal deaktiviert wird, Passwort-Hash nicht löschen (für spätere Reaktivierung)
return prisma.customer.update({
return prisma_js_1.default.customer.update({
where: { id: customerId },
data: {
portalEnabled: data.portalEnabled,
@@ -444,7 +444,7 @@ async function updatePortalSettings(customerId, data) {
});
}
async function getPortalSettings(customerId) {
return prisma.customer.findUnique({
return prisma_js_1.default.customer.findUnique({
where: { id: customerId },
select: {
id: true,
@@ -458,7 +458,7 @@ async function getPortalSettings(customerId) {
// ==================== REPRESENTATIVE MANAGEMENT ====================
async function getCustomerRepresentatives(customerId) {
// Holt alle Kunden, die der angegebene Kunde vertreten kann (dieser ist der Vertreter)
return prisma.customerRepresentative.findMany({
return prisma_js_1.default.customerRepresentative.findMany({
where: { representativeId: customerId, isActive: true },
include: {
customer: {
@@ -477,7 +477,7 @@ async function getCustomerRepresentatives(customerId) {
}
async function getRepresentedByList(customerId) {
// Holt alle Kunden, die den angegebenen Kunden vertreten können
return prisma.customerRepresentative.findMany({
return prisma_js_1.default.customerRepresentative.findMany({
where: { customerId: customerId, isActive: true },
include: {
representative: {
@@ -499,8 +499,8 @@ representativeId, // Der Kunde, der einsehen darf
notes) {
// Prüfen, ob beide Kunden existieren
const [customer, representative] = await Promise.all([
prisma.customer.findUnique({ where: { id: customerId } }),
prisma.customer.findUnique({ where: { id: representativeId } }),
prisma_js_1.default.customer.findUnique({ where: { id: customerId } }),
prisma_js_1.default.customer.findUnique({ where: { id: representativeId } }),
]);
if (!customer) {
throw new Error('Kunde nicht gefunden');
@@ -515,7 +515,7 @@ notes) {
if (!representative.portalEnabled) {
throw new Error('Der Vertreter-Kunde muss ein aktiviertes Portal-Konto haben');
}
return prisma.customerRepresentative.upsert({
return prisma_js_1.default.customerRepresentative.upsert({
where: {
customerId_representativeId: { customerId, representativeId },
},
@@ -545,7 +545,7 @@ notes) {
}
async function removeRepresentative(customerId, representativeId) {
// Anstatt zu löschen, setzen wir isActive auf false
return prisma.customerRepresentative.update({
return prisma_js_1.default.customerRepresentative.update({
where: {
customerId_representativeId: { customerId, representativeId },
},
@@ -555,7 +555,7 @@ async function removeRepresentative(customerId, representativeId) {
async function searchCustomersForRepresentative(search, excludeCustomerId) {
// Sucht Kunden, die als Vertreter hinzugefügt werden können
// Nur Kunden mit aktiviertem Portal
return prisma.customer.findMany({
return prisma_js_1.default.customer.findMany({
where: {
id: { not: excludeCustomerId },
portalEnabled: true,