"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAllContracts = getAllContracts; exports.getContractById = getContractById; exports.createContract = createContract; exports.updateContract = updateContract; exports.deleteContract = deleteContract; exports.createFollowUpContract = createFollowUpContract; exports.getContractPassword = getContractPassword; exports.getSimCardCredentials = getSimCardCredentials; exports.getInternetCredentials = getInternetCredentials; exports.getSipCredentials = getSipCredentials; const client_1 = require("@prisma/client"); const helpers_js_1 = require("../utils/helpers.js"); const encryption_js_1 = require("../utils/encryption.js"); const prisma = new client_1.PrismaClient(); async function getAllContracts(filters) { const { customerId, customerIds, type, status, search, page = 1, limit = 20 } = filters; const { skip, take } = (0, helpers_js_1.paginate)(page, limit); const where = {}; // Entweder einzelne customerId ODER Liste von customerIds (für Kundenportal) if (customerIds && customerIds.length > 0) { where.customerId = { in: customerIds }; } else if (customerId) { where.customerId = customerId; } if (type) where.type = type; // Status-Filter: Deaktivierte Verträge standardmäßig ausblenden if (status) { where.status = status; } else { // Wenn kein Status-Filter gesetzt, alle außer DEACTIVATED anzeigen where.status = { not: client_1.ContractStatus.DEACTIVATED }; } if (search) { where.OR = [ // Basis-Vertragsfelder { contractNumber: { contains: search } }, { providerName: { contains: search } }, { tariffName: { contains: search } }, { customerNumberAtProvider: { contains: search } }, { provider: { name: { contains: search } } }, { tariff: { name: { contains: search } } }, // Kundenname { customer: { firstName: { contains: search } } }, { customer: { lastName: { contains: search } } }, { customer: { companyName: { contains: search } } }, { customer: { customerNumber: { contains: search } } }, // Internet-Vertragsdetails { internetDetails: { routerSerialNumber: { contains: search } } }, { internetDetails: { homeId: { contains: search } } }, { internetDetails: { activationCode: { contains: search } } }, { internetDetails: { phoneNumbers: { some: { phoneNumber: { contains: search } } } } }, // Mobilfunk-Vertragsdetails { mobileDetails: { phoneNumber: { contains: search } } }, { mobileDetails: { simCardNumber: { contains: search } } }, { mobileDetails: { deviceImei: { contains: search } } }, { mobileDetails: { simCards: { some: { phoneNumber: { contains: search } } } } }, { mobileDetails: { simCards: { some: { simCardNumber: { contains: search } } } } }, // Energie-Vertragsdetails (Zählernummer) { energyDetails: { meter: { meterNumber: { contains: search } } } }, // TV-Vertragsdetails { tvDetails: { smartcardNumber: { contains: search } } }, // KFZ-Versicherung { carInsuranceDetails: { licensePlate: { contains: search } } }, { carInsuranceDetails: { vin: { contains: search } } }, { carInsuranceDetails: { policyNumber: { contains: search } } }, ]; } const [contracts, total] = await Promise.all([ prisma.contract.findMany({ where, skip, take, orderBy: [{ startDate: 'desc' }, { createdAt: 'desc' }], include: { customer: { select: { id: true, customerNumber: true, firstName: true, lastName: true, companyName: true, }, }, address: true, salesPlatform: true, cancellationPeriod: true, contractDuration: true, provider: true, tariff: true, contractCategory: true, }, }), prisma.contract.count({ where }), ]); return { contracts, pagination: (0, helpers_js_1.buildPaginationResponse)(page, limit, total), }; } async function getContractById(id, decryptPassword = false) { const contract = await prisma.contract.findUnique({ where: { id }, include: { customer: true, address: true, bankCard: true, identityDocument: true, salesPlatform: true, cancellationPeriod: true, contractDuration: true, provider: true, tariff: true, contractCategory: true, previousContract: { include: { energyDetails: { include: { meter: { include: { readings: true } } } }, internetDetails: { include: { phoneNumbers: true } }, mobileDetails: { include: { simCards: true } }, tvDetails: true, carInsuranceDetails: true, }, }, energyDetails: { include: { meter: { include: { readings: true } } } }, internetDetails: { include: { phoneNumbers: true } }, mobileDetails: { include: { simCards: true } }, tvDetails: true, carInsuranceDetails: true, stressfreiEmail: true, followUpContract: { select: { id: true, contractNumber: true, status: true }, }, }, }); if (!contract) return null; // Decrypt password if requested and exists if (decryptPassword && contract.portalPasswordEncrypted) { try { contract.portalPasswordDecrypted = (0, encryption_js_1.decrypt)(contract.portalPasswordEncrypted); } catch { // Password decryption failed, leave as is } } return contract; } async function createContract(data) { const { energyDetails, internetDetails, mobileDetails, tvDetails, carInsuranceDetails, portalPassword, ...contractData } = data; // Encrypt password if provided const portalPasswordEncrypted = portalPassword ? (0, encryption_js_1.encrypt)(portalPassword) : undefined; const contract = await prisma.contract.create({ data: { ...contractData, contractNumber: (0, helpers_js_1.generateContractNumber)(data.type), portalPasswordEncrypted, ...(energyDetails && ['ELECTRICITY', 'GAS'].includes(data.type) ? { energyDetails: { create: energyDetails } } : {}), ...(internetDetails && ['DSL', 'CABLE', 'FIBER'].includes(data.type) ? { internetDetails: { create: { downloadSpeed: internetDetails.downloadSpeed, uploadSpeed: internetDetails.uploadSpeed, routerModel: internetDetails.routerModel, routerSerialNumber: internetDetails.routerSerialNumber, installationDate: internetDetails.installationDate, internetUsername: internetDetails.internetUsername, internetPasswordEncrypted: internetDetails.internetPassword ? (0, encryption_js_1.encrypt)(internetDetails.internetPassword) : undefined, homeId: internetDetails.homeId, activationCode: internetDetails.activationCode, phoneNumbers: internetDetails.phoneNumbers && internetDetails.phoneNumbers.length > 0 ? { create: internetDetails.phoneNumbers.map((pn) => ({ phoneNumber: pn.phoneNumber, isMain: pn.isMain ?? false, sipUsername: pn.sipUsername, sipPasswordEncrypted: pn.sipPassword ? (0, encryption_js_1.encrypt)(pn.sipPassword) : undefined, sipServer: pn.sipServer, })), } : undefined, }, }, } : {}), ...(mobileDetails && data.type === 'MOBILE' ? { mobileDetails: { create: { requiresMultisim: mobileDetails.requiresMultisim, dataVolume: mobileDetails.dataVolume, includedMinutes: mobileDetails.includedMinutes, includedSMS: mobileDetails.includedSMS, deviceModel: mobileDetails.deviceModel, deviceImei: mobileDetails.deviceImei, phoneNumber: mobileDetails.phoneNumber, simCardNumber: mobileDetails.simCardNumber, simCards: mobileDetails.simCards ? { create: mobileDetails.simCards.map((sc) => ({ phoneNumber: sc.phoneNumber, simCardNumber: sc.simCardNumber, pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : undefined, puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : undefined, isMultisim: sc.isMultisim ?? false, isMain: sc.isMain ?? false, })), } : undefined, }, }, } : {}), ...(tvDetails && data.type === 'TV' ? { tvDetails: { create: tvDetails } } : {}), ...(carInsuranceDetails && data.type === 'CAR_INSURANCE' ? { carInsuranceDetails: { create: carInsuranceDetails } } : {}), }, include: { customer: true, address: true, salesPlatform: true, energyDetails: true, internetDetails: { include: { phoneNumbers: true } }, mobileDetails: { include: { simCards: true } }, tvDetails: true, carInsuranceDetails: true, }, }); return contract; } async function updateContract(id, data) { const { energyDetails, internetDetails, mobileDetails, tvDetails, carInsuranceDetails, portalPassword, ...contractData } = data; // Encrypt password if provided const portalPasswordEncrypted = portalPassword ? (0, encryption_js_1.encrypt)(portalPassword) : undefined; // Update main contract await prisma.contract.update({ where: { id }, data: { ...contractData, ...(portalPasswordEncrypted ? { portalPasswordEncrypted } : {}), }, }); // Update type-specific details if (energyDetails) { await prisma.energyContractDetails.upsert({ where: { contractId: id }, update: energyDetails, create: { contractId: id, ...energyDetails }, }); } if (internetDetails) { const { phoneNumbers, internetPassword, ...internetData } = internetDetails; const existing = await prisma.internetContractDetails.findUnique({ where: { contractId: id }, include: { phoneNumbers: true }, }); // Prepare internet data with encryption const preparedInternetData = { downloadSpeed: internetData.downloadSpeed, uploadSpeed: internetData.uploadSpeed, routerModel: internetData.routerModel, routerSerialNumber: internetData.routerSerialNumber, installationDate: internetData.installationDate, internetUsername: internetData.internetUsername, // Only update password if new value provided, otherwise keep existing ...(internetPassword ? { internetPasswordEncrypted: (0, encryption_js_1.encrypt)(internetPassword) } : {}), homeId: internetData.homeId, activationCode: internetData.activationCode, }; if (existing) { await prisma.internetContractDetails.update({ where: { contractId: id }, data: preparedInternetData, }); if (phoneNumbers) { // Get existing phone numbers for preserving encrypted passwords const existingPhoneNumbers = existing.phoneNumbers || []; // Delete all existing phone numbers await prisma.phoneNumber.deleteMany({ where: { internetContractDetailsId: existing.id }, }); // Create new phone numbers with encryption await prisma.phoneNumber.createMany({ data: phoneNumbers.map((pn) => { // Find existing entry to preserve sipPassword if not changed const existingPn = pn.id ? existingPhoneNumbers.find((e) => e.id === pn.id) : undefined; return { internetContractDetailsId: existing.id, phoneNumber: pn.phoneNumber, isMain: pn.isMain ?? false, sipUsername: pn.sipUsername, // Preserve existing sipPassword if no new value provided sipPasswordEncrypted: pn.sipPassword ? (0, encryption_js_1.encrypt)(pn.sipPassword) : existingPn?.sipPasswordEncrypted ?? undefined, sipServer: pn.sipServer, }; }), }); } } else { await prisma.internetContractDetails.create({ data: { contractId: id, ...preparedInternetData, ...(internetPassword ? { internetPasswordEncrypted: (0, encryption_js_1.encrypt)(internetPassword) } : {}), phoneNumbers: phoneNumbers ? { create: phoneNumbers.map((pn) => ({ phoneNumber: pn.phoneNumber, isMain: pn.isMain ?? false, sipUsername: pn.sipUsername, sipPasswordEncrypted: pn.sipPassword ? (0, encryption_js_1.encrypt)(pn.sipPassword) : undefined, sipServer: pn.sipServer, })), } : undefined, }, }); } } if (mobileDetails) { const { simCards, ...mobileData } = mobileDetails; const existing = await prisma.mobileContractDetails.findUnique({ where: { contractId: id }, }); if (existing) { await prisma.mobileContractDetails.update({ where: { contractId: id }, data: mobileData, }); if (simCards) { // Get existing sim cards to preserve PIN/PUK if not provided const existingSimCards = await prisma.simCard.findMany({ where: { mobileDetailsId: existing.id }, }); const existingSimCardMap = new Map(existingSimCards.map(sc => [sc.id, sc])); // Delete existing sim cards await prisma.simCard.deleteMany({ where: { mobileDetailsId: existing.id }, }); // Create new sim cards, preserving PIN/PUK if not provided await prisma.simCard.createMany({ data: simCards.map((sc) => { const existingSc = sc.id ? existingSimCardMap.get(sc.id) : undefined; return { mobileDetailsId: existing.id, phoneNumber: sc.phoneNumber, simCardNumber: sc.simCardNumber, // Preserve existing PIN/PUK if no new value provided pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : (existingSc?.pin ?? undefined), puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : (existingSc?.puk ?? undefined), isMultisim: sc.isMultisim ?? false, isMain: sc.isMain ?? false, }; }), }); } } else { await prisma.mobileContractDetails.create({ data: { contractId: id, ...mobileData, simCards: simCards ? { create: simCards.map((sc) => ({ phoneNumber: sc.phoneNumber, simCardNumber: sc.simCardNumber, pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : undefined, puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : undefined, isMultisim: sc.isMultisim ?? false, isMain: sc.isMain ?? false, })), } : undefined, }, }); } } if (tvDetails) { await prisma.tvContractDetails.upsert({ where: { contractId: id }, update: tvDetails, create: { contractId: id, ...tvDetails }, }); } if (carInsuranceDetails) { await prisma.carInsuranceDetails.upsert({ where: { contractId: id }, update: carInsuranceDetails, create: { contractId: id, ...carInsuranceDetails }, }); } return getContractById(id); } async function deleteContract(id) { // Vertragskette erhalten beim Löschen: // Wenn A → B → C und B gelöscht wird, soll C direkt auf A zeigen (A → C) // 1. Zu löschenden Vertrag holen um dessen Vorgänger zu kennen const contractToDelete = await prisma.contract.findUnique({ where: { id }, select: { previousContractId: true }, }); // 2. Folgevertrag(e) mit dem Vorgänger des gelöschten Vertrags verbinden // So bleibt die Kette erhalten: A → B → C wird zu A → C await prisma.contract.updateMany({ where: { previousContractId: id }, data: { previousContractId: contractToDelete?.previousContractId ?? null }, }); return prisma.contract.delete({ where: { id } }); } async function createFollowUpContract(previousContractId) { const previousContract = await getContractById(previousContractId); if (!previousContract) { throw new Error('Vorgängervertrag nicht gefunden'); } // Prüfen ob bereits ein Folgevertrag existiert const existingFollowUp = await prisma.contract.findFirst({ where: { previousContractId }, select: { id: true, contractNumber: true }, }); if (existingFollowUp) { throw new Error(`Es existiert bereits ein Folgevertrag: ${existingFollowUp.contractNumber}`); } // Copy data but exclude provider credentials and some fields const newContractData = { customerId: previousContract.customerId, type: previousContract.type, status: 'DRAFT', addressId: previousContract.addressId ?? undefined, bankCardId: previousContract.bankCardId ?? undefined, identityDocumentId: previousContract.identityDocumentId ?? undefined, salesPlatformId: previousContract.salesPlatformId ?? undefined, previousContractId: previousContract.id, // Explicitly NOT copying: providerName, tariffName, portalUsername, portalPassword, price fields cancellationPeriodId: previousContract.cancellationPeriodId ?? undefined, contractDurationId: previousContract.contractDurationId ?? undefined, notes: `Folgevertrag zu ${previousContract.contractNumber}`, }; // Copy type-specific details (without credentials) if (previousContract.energyDetails) { newContractData.energyDetails = { meterId: previousContract.energyDetails.meterId ?? undefined, annualConsumption: previousContract.energyDetails.annualConsumption ?? undefined, basePrice: previousContract.energyDetails.basePrice ?? undefined, unitPrice: previousContract.energyDetails.unitPrice ?? undefined, bonus: previousContract.energyDetails.bonus ?? undefined, previousProviderName: previousContract.providerName ?? undefined, previousCustomerNumber: previousContract.customerNumberAtProvider ?? undefined, }; } if (previousContract.internetDetails) { newContractData.internetDetails = { downloadSpeed: previousContract.internetDetails.downloadSpeed ?? undefined, uploadSpeed: previousContract.internetDetails.uploadSpeed ?? undefined, routerModel: previousContract.internetDetails.routerModel ?? undefined, routerSerialNumber: previousContract.internetDetails.routerSerialNumber ?? undefined, phoneNumbers: previousContract.internetDetails.phoneNumbers.map((pn) => ({ phoneNumber: pn.phoneNumber, isMain: pn.isMain, })), }; } if (previousContract.mobileDetails) { newContractData.mobileDetails = { requiresMultisim: previousContract.mobileDetails.requiresMultisim ?? undefined, dataVolume: previousContract.mobileDetails.dataVolume ?? undefined, includedMinutes: previousContract.mobileDetails.includedMinutes ?? undefined, includedSMS: previousContract.mobileDetails.includedSMS ?? undefined, deviceModel: previousContract.mobileDetails.deviceModel ?? undefined, deviceImei: previousContract.mobileDetails.deviceImei ?? undefined, phoneNumber: previousContract.mobileDetails.phoneNumber ?? undefined, simCardNumber: previousContract.mobileDetails.simCardNumber ?? undefined, // Copy simCards without PIN/PUK (security) simCards: previousContract.mobileDetails.simCards?.map((sc) => ({ phoneNumber: sc.phoneNumber ?? undefined, simCardNumber: sc.simCardNumber ?? undefined, isMultisim: sc.isMultisim, isMain: sc.isMain, })), }; } if (previousContract.tvDetails) { newContractData.tvDetails = { receiverModel: previousContract.tvDetails.receiverModel ?? undefined, smartcardNumber: previousContract.tvDetails.smartcardNumber ?? undefined, package: previousContract.tvDetails.package ?? undefined, }; } if (previousContract.carInsuranceDetails) { newContractData.carInsuranceDetails = { licensePlate: previousContract.carInsuranceDetails.licensePlate ?? undefined, hsn: previousContract.carInsuranceDetails.hsn ?? undefined, tsn: previousContract.carInsuranceDetails.tsn ?? undefined, vin: previousContract.carInsuranceDetails.vin ?? undefined, vehicleType: previousContract.carInsuranceDetails.vehicleType ?? undefined, firstRegistration: previousContract.carInsuranceDetails.firstRegistration ?? undefined, noClaimsClass: previousContract.carInsuranceDetails.noClaimsClass ?? undefined, insuranceType: previousContract.carInsuranceDetails.insuranceType, deductiblePartial: previousContract.carInsuranceDetails.deductiblePartial ?? undefined, deductibleFull: previousContract.carInsuranceDetails.deductibleFull ?? undefined, previousInsurer: previousContract.providerName ?? undefined, }; } return createContract(newContractData); } // Decrypt password for viewing async function getContractPassword(id) { const contract = await prisma.contract.findUnique({ where: { id }, select: { portalPasswordEncrypted: true }, }); if (!contract?.portalPasswordEncrypted) return null; try { return (0, encryption_js_1.decrypt)(contract.portalPasswordEncrypted); } catch { return null; } } // Decrypt SimCard PIN/PUK async function getSimCardCredentials(simCardId) { const simCard = await prisma.simCard.findUnique({ where: { id: simCardId }, select: { pin: true, puk: true }, }); if (!simCard) return { pin: null, puk: null }; try { return { pin: simCard.pin ? (0, encryption_js_1.decrypt)(simCard.pin) : null, puk: simCard.puk ? (0, encryption_js_1.decrypt)(simCard.puk) : null, }; } catch { return { pin: null, puk: null }; } } // Decrypt Internet password async function getInternetCredentials(contractId) { const internetDetails = await prisma.internetContractDetails.findUnique({ where: { contractId }, select: { internetPasswordEncrypted: true }, }); if (!internetDetails?.internetPasswordEncrypted) return { password: null }; try { return { password: (0, encryption_js_1.decrypt)(internetDetails.internetPasswordEncrypted), }; } catch { return { password: null }; } } // Decrypt SIP password for a phone number async function getSipCredentials(phoneNumberId) { const phoneNumber = await prisma.phoneNumber.findUnique({ where: { id: phoneNumberId }, select: { sipPasswordEncrypted: true }, }); if (!phoneNumber?.sipPasswordEncrypted) return { password: null }; try { return { password: (0, encryption_js_1.decrypt)(phoneNumber.sipPasswordEncrypted), }; } catch { return { password: null }; } } //# sourceMappingURL=contract.service.js.map