516 lines
16 KiB
JavaScript
516 lines
16 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.getAllCustomers = getAllCustomers;
|
|
exports.getCustomerById = getCustomerById;
|
|
exports.getCustomersByIds = getCustomersByIds;
|
|
exports.createCustomer = createCustomer;
|
|
exports.updateCustomer = updateCustomer;
|
|
exports.deleteCustomer = deleteCustomer;
|
|
exports.getCustomerAddresses = getCustomerAddresses;
|
|
exports.createAddress = createAddress;
|
|
exports.updateAddress = updateAddress;
|
|
exports.deleteAddress = deleteAddress;
|
|
exports.getCustomerBankCards = getCustomerBankCards;
|
|
exports.createBankCard = createBankCard;
|
|
exports.updateBankCard = updateBankCard;
|
|
exports.deleteBankCard = deleteBankCard;
|
|
exports.getCustomerDocuments = getCustomerDocuments;
|
|
exports.createDocument = createDocument;
|
|
exports.updateDocument = updateDocument;
|
|
exports.deleteDocument = deleteDocument;
|
|
exports.getCustomerMeters = getCustomerMeters;
|
|
exports.createMeter = createMeter;
|
|
exports.updateMeter = updateMeter;
|
|
exports.deleteMeter = deleteMeter;
|
|
exports.addMeterReading = addMeterReading;
|
|
exports.getMeterReadings = getMeterReadings;
|
|
exports.updateMeterReading = updateMeterReading;
|
|
exports.deleteMeterReading = deleteMeterReading;
|
|
exports.updatePortalSettings = updatePortalSettings;
|
|
exports.getPortalSettings = getPortalSettings;
|
|
exports.getCustomerRepresentatives = getCustomerRepresentatives;
|
|
exports.getRepresentedByList = getRepresentedByList;
|
|
exports.addRepresentative = addRepresentative;
|
|
exports.removeRepresentative = removeRepresentative;
|
|
exports.searchCustomersForRepresentative = searchCustomersForRepresentative;
|
|
const client_1 = require("@prisma/client");
|
|
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)
|
|
return;
|
|
const absolutePath = path_1.default.join(process.cwd(), filePath);
|
|
if (fs_1.default.existsSync(absolutePath)) {
|
|
try {
|
|
fs_1.default.unlinkSync(absolutePath);
|
|
}
|
|
catch (error) {
|
|
console.error('Fehler beim Löschen der Datei:', absolutePath, error);
|
|
}
|
|
}
|
|
}
|
|
async function getAllCustomers(filters) {
|
|
const { search, type, page = 1, limit = 20 } = filters;
|
|
const { skip, take } = (0, helpers_js_1.paginate)(page, limit);
|
|
const where = {};
|
|
if (type) {
|
|
where.type = type;
|
|
}
|
|
if (search) {
|
|
where.OR = [
|
|
{ firstName: { contains: search } },
|
|
{ lastName: { contains: search } },
|
|
{ companyName: { contains: search } },
|
|
{ email: { contains: search } },
|
|
{ customerNumber: { contains: search } },
|
|
];
|
|
}
|
|
const [customers, total] = await Promise.all([
|
|
prisma.customer.findMany({
|
|
where,
|
|
skip,
|
|
take,
|
|
orderBy: { createdAt: 'desc' },
|
|
include: {
|
|
addresses: { where: { isDefault: true }, take: 1 },
|
|
_count: {
|
|
select: { contracts: true },
|
|
},
|
|
},
|
|
}),
|
|
prisma.customer.count({ where }),
|
|
]);
|
|
return {
|
|
customers,
|
|
pagination: (0, helpers_js_1.buildPaginationResponse)(page, limit, total),
|
|
};
|
|
}
|
|
async function getCustomerById(id) {
|
|
return prisma.customer.findUnique({
|
|
where: { id },
|
|
include: {
|
|
addresses: true,
|
|
bankCards: { orderBy: { isActive: 'desc' } },
|
|
identityDocuments: { orderBy: { isActive: 'desc' } },
|
|
meters: {
|
|
orderBy: { isActive: 'desc' },
|
|
include: {
|
|
readings: {
|
|
orderBy: { readingDate: 'desc' },
|
|
},
|
|
},
|
|
},
|
|
stressfreiEmails: { orderBy: { isActive: 'desc' } },
|
|
contracts: {
|
|
where: {
|
|
// Deaktivierte Verträge ausblenden
|
|
status: { not: client_1.ContractStatus.DEACTIVATED },
|
|
},
|
|
orderBy: [{ startDate: 'desc' }, { createdAt: 'desc' }],
|
|
include: {
|
|
address: true,
|
|
salesPlatform: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
async function getCustomersByIds(ids) {
|
|
return prisma.customer.findMany({
|
|
where: { id: { in: ids } },
|
|
select: {
|
|
id: true,
|
|
portalEmail: true,
|
|
},
|
|
});
|
|
}
|
|
async function createCustomer(data) {
|
|
return prisma.customer.create({
|
|
data: {
|
|
...data,
|
|
customerNumber: (0, helpers_js_1.generateCustomerNumber)(),
|
|
},
|
|
});
|
|
}
|
|
async function updateCustomer(id, data) {
|
|
return prisma.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({
|
|
where: { id },
|
|
select: { businessRegistrationPath: true, commercialRegisterPath: true, privacyPolicyPath: true },
|
|
});
|
|
const bankCards = await prisma.bankCard.findMany({
|
|
where: { customerId: id },
|
|
select: { documentPath: true },
|
|
});
|
|
const identityDocs = await prisma.identityDocument.findMany({
|
|
where: { customerId: id },
|
|
select: { documentPath: true },
|
|
});
|
|
// Kundendokumente löschen
|
|
if (customer) {
|
|
deleteFileIfExists(customer.businessRegistrationPath);
|
|
deleteFileIfExists(customer.commercialRegisterPath);
|
|
deleteFileIfExists(customer.privacyPolicyPath);
|
|
}
|
|
// Bankkarten- und Ausweisdokumente löschen
|
|
for (const card of bankCards) {
|
|
deleteFileIfExists(card.documentPath);
|
|
}
|
|
for (const doc of identityDocs) {
|
|
deleteFileIfExists(doc.documentPath);
|
|
}
|
|
// Jetzt DB-Eintrag löschen (Cascade löscht die verknüpften Einträge)
|
|
return prisma.customer.delete({
|
|
where: { id },
|
|
});
|
|
}
|
|
// Address operations
|
|
async function getCustomerAddresses(customerId) {
|
|
return prisma.address.findMany({
|
|
where: { customerId },
|
|
orderBy: [{ isDefault: 'desc' }, { createdAt: 'desc' }],
|
|
});
|
|
}
|
|
async function createAddress(customerId, data) {
|
|
// If this is set as default, unset other defaults of same type
|
|
if (data.isDefault) {
|
|
await prisma.address.updateMany({
|
|
where: { customerId, type: data.type },
|
|
data: { isDefault: false },
|
|
});
|
|
}
|
|
return prisma.address.create({
|
|
data: {
|
|
customerId,
|
|
...data,
|
|
},
|
|
});
|
|
}
|
|
async function updateAddress(id, data) {
|
|
const address = await prisma.address.findUnique({ where: { id } });
|
|
if (!address)
|
|
throw new Error('Adresse nicht gefunden');
|
|
if (data.isDefault) {
|
|
await prisma.address.updateMany({
|
|
where: {
|
|
customerId: address.customerId,
|
|
type: data.type || address.type,
|
|
id: { not: id },
|
|
},
|
|
data: { isDefault: false },
|
|
});
|
|
}
|
|
return prisma.address.update({
|
|
where: { id },
|
|
data,
|
|
});
|
|
}
|
|
async function deleteAddress(id) {
|
|
return prisma.address.delete({ where: { id } });
|
|
}
|
|
// Bank card operations
|
|
async function getCustomerBankCards(customerId, showInactive = false) {
|
|
const where = { customerId };
|
|
if (!showInactive) {
|
|
where.isActive = true;
|
|
}
|
|
return prisma.bankCard.findMany({
|
|
where,
|
|
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
|
});
|
|
}
|
|
async function createBankCard(customerId, data) {
|
|
return prisma.bankCard.create({
|
|
data: {
|
|
customerId,
|
|
...data,
|
|
isActive: true,
|
|
},
|
|
});
|
|
}
|
|
async function updateBankCard(id, data) {
|
|
return prisma.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 } });
|
|
if (bankCard?.documentPath) {
|
|
deleteFileIfExists(bankCard.documentPath);
|
|
}
|
|
return prisma.bankCard.delete({ where: { id } });
|
|
}
|
|
// Identity document operations
|
|
async function getCustomerDocuments(customerId, showInactive = false) {
|
|
const where = { customerId };
|
|
if (!showInactive) {
|
|
where.isActive = true;
|
|
}
|
|
return prisma.identityDocument.findMany({
|
|
where,
|
|
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
|
});
|
|
}
|
|
async function createDocument(customerId, data) {
|
|
return prisma.identityDocument.create({
|
|
data: {
|
|
customerId,
|
|
...data,
|
|
isActive: true,
|
|
},
|
|
});
|
|
}
|
|
async function updateDocument(id, data) {
|
|
return prisma.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 } });
|
|
if (document?.documentPath) {
|
|
deleteFileIfExists(document.documentPath);
|
|
}
|
|
return prisma.identityDocument.delete({ where: { id } });
|
|
}
|
|
// Meter operations
|
|
async function getCustomerMeters(customerId, showInactive = false) {
|
|
const where = { customerId };
|
|
if (!showInactive) {
|
|
where.isActive = true;
|
|
}
|
|
return prisma.meter.findMany({
|
|
where,
|
|
include: {
|
|
readings: {
|
|
orderBy: { readingDate: 'desc' },
|
|
take: 5,
|
|
},
|
|
},
|
|
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
|
});
|
|
}
|
|
async function createMeter(customerId, data) {
|
|
return prisma.meter.create({
|
|
data: {
|
|
customerId,
|
|
...data,
|
|
isActive: true,
|
|
},
|
|
});
|
|
}
|
|
async function updateMeter(id, data) {
|
|
return prisma.meter.update({
|
|
where: { id },
|
|
data,
|
|
});
|
|
}
|
|
async function deleteMeter(id) {
|
|
return prisma.meter.delete({ where: { id } });
|
|
}
|
|
async function addMeterReading(meterId, data) {
|
|
return prisma.meterReading.create({
|
|
data: {
|
|
meterId,
|
|
...data,
|
|
},
|
|
});
|
|
}
|
|
async function getMeterReadings(meterId) {
|
|
return prisma.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({
|
|
where: { id: readingId, meterId },
|
|
});
|
|
if (!reading) {
|
|
throw new Error('Zählerstand nicht gefunden');
|
|
}
|
|
return prisma.meterReading.update({
|
|
where: { id: readingId },
|
|
data,
|
|
});
|
|
}
|
|
async function deleteMeterReading(meterId, readingId) {
|
|
// Verify the reading belongs to the meter
|
|
const reading = await prisma.meterReading.findFirst({
|
|
where: { id: readingId, meterId },
|
|
});
|
|
if (!reading) {
|
|
throw new Error('Zählerstand nicht gefunden');
|
|
}
|
|
return prisma.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({
|
|
where: { id: customerId },
|
|
data: {
|
|
portalEnabled: data.portalEnabled,
|
|
portalEmail: data.portalEmail,
|
|
},
|
|
select: {
|
|
id: true,
|
|
portalEnabled: true,
|
|
portalEmail: true,
|
|
portalLastLogin: true,
|
|
},
|
|
});
|
|
}
|
|
async function getPortalSettings(customerId) {
|
|
return prisma.customer.findUnique({
|
|
where: { id: customerId },
|
|
select: {
|
|
id: true,
|
|
portalEnabled: true,
|
|
portalEmail: true,
|
|
portalLastLogin: true,
|
|
portalPasswordHash: true, // Nur um zu prüfen ob Passwort gesetzt (wird als boolean zurückgegeben)
|
|
},
|
|
});
|
|
}
|
|
// ==================== REPRESENTATIVE MANAGEMENT ====================
|
|
async function getCustomerRepresentatives(customerId) {
|
|
// Holt alle Kunden, die der angegebene Kunde vertreten kann (dieser ist der Vertreter)
|
|
return prisma.customerRepresentative.findMany({
|
|
where: { representativeId: customerId, isActive: true },
|
|
include: {
|
|
customer: {
|
|
select: {
|
|
id: true,
|
|
customerNumber: true,
|
|
firstName: true,
|
|
lastName: true,
|
|
companyName: true,
|
|
type: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: 'desc' },
|
|
});
|
|
}
|
|
async function getRepresentedByList(customerId) {
|
|
// Holt alle Kunden, die den angegebenen Kunden vertreten können
|
|
return prisma.customerRepresentative.findMany({
|
|
where: { customerId: customerId, isActive: true },
|
|
include: {
|
|
representative: {
|
|
select: {
|
|
id: true,
|
|
customerNumber: true,
|
|
firstName: true,
|
|
lastName: true,
|
|
companyName: true,
|
|
type: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: 'desc' },
|
|
});
|
|
}
|
|
async function addRepresentative(customerId, // Der Kunde, dessen Verträge eingesehen werden dürfen
|
|
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 } }),
|
|
]);
|
|
if (!customer) {
|
|
throw new Error('Kunde nicht gefunden');
|
|
}
|
|
if (!representative) {
|
|
throw new Error('Vertreter-Kunde nicht gefunden');
|
|
}
|
|
if (customerId === representativeId) {
|
|
throw new Error('Ein Kunde kann sich nicht selbst vertreten');
|
|
}
|
|
// Prüfen ob der Vertreter ein Portal-Konto hat
|
|
if (!representative.portalEnabled) {
|
|
throw new Error('Der Vertreter-Kunde muss ein aktiviertes Portal-Konto haben');
|
|
}
|
|
return prisma.customerRepresentative.upsert({
|
|
where: {
|
|
customerId_representativeId: { customerId, representativeId },
|
|
},
|
|
create: {
|
|
customerId,
|
|
representativeId,
|
|
notes,
|
|
isActive: true,
|
|
},
|
|
update: {
|
|
isActive: true,
|
|
notes,
|
|
},
|
|
include: {
|
|
representative: {
|
|
select: {
|
|
id: true,
|
|
customerNumber: true,
|
|
firstName: true,
|
|
lastName: true,
|
|
companyName: true,
|
|
type: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
async function removeRepresentative(customerId, representativeId) {
|
|
// Anstatt zu löschen, setzen wir isActive auf false
|
|
return prisma.customerRepresentative.update({
|
|
where: {
|
|
customerId_representativeId: { customerId, representativeId },
|
|
},
|
|
data: { isActive: false },
|
|
});
|
|
}
|
|
async function searchCustomersForRepresentative(search, excludeCustomerId) {
|
|
// Sucht Kunden, die als Vertreter hinzugefügt werden können
|
|
// Nur Kunden mit aktiviertem Portal
|
|
return prisma.customer.findMany({
|
|
where: {
|
|
id: { not: excludeCustomerId },
|
|
portalEnabled: true,
|
|
OR: [
|
|
{ firstName: { contains: search } },
|
|
{ lastName: { contains: search } },
|
|
{ companyName: { contains: search } },
|
|
{ customerNumber: { contains: search } },
|
|
],
|
|
},
|
|
select: {
|
|
id: true,
|
|
customerNumber: true,
|
|
firstName: true,
|
|
lastName: true,
|
|
companyName: true,
|
|
type: true,
|
|
},
|
|
take: 10,
|
|
});
|
|
}
|
|
//# sourceMappingURL=customer.service.js.map
|