diff --git a/backend/prisma/migrations/20260603150000_contract_sales_platform_numbers/migration.sql b/backend/prisma/migrations/20260603150000_contract_sales_platform_numbers/migration.sql new file mode 100644 index 00000000..a95456d5 --- /dev/null +++ b/backend/prisma/migrations/20260603150000_contract_sales_platform_numbers/migration.sql @@ -0,0 +1,7 @@ +-- Vertrieb-/Provider-Trennung: viele Plattformen vergeben eigene Kunden-/ +-- Vertragsnummern, die nicht mit denen beim Endanbieter identisch sind. +-- Zwei neue optionale Felder unter "Anbieter & Tarif". + +ALTER TABLE `Contract` + ADD COLUMN IF NOT EXISTS `customerNumberAtSalesPlatform` VARCHAR(191) NULL, + ADD COLUMN IF NOT EXISTS `contractNumberAtSalesPlatform` VARCHAR(191) NULL; diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 194f8113..0756bfc7 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -687,6 +687,8 @@ model Contract { tariffName String? customerNumberAtProvider String? contractNumberAtProvider String? // Vertragsnummer beim Anbieter + customerNumberAtSalesPlatform String? // Kundennummer bei der Vertriebsplattform + contractNumberAtSalesPlatform String? // Vertragsnummer bei der Vertriebsplattform priceFirst12Months String? // Preis erste 12 Monate priceFrom13Months String? // Preis ab 13. Monat priceAfter24Months String? // Preis nach 24 Monaten diff --git a/backend/src/controllers/contract.controller.ts b/backend/src/controllers/contract.controller.ts index 9ab89165..b52d041b 100644 --- a/backend/src/controllers/contract.controller.ts +++ b/backend/src/controllers/contract.controller.ts @@ -203,6 +203,9 @@ export async function updateContract(req: AuthRequest, res: Response): Promise = { status: 'Status', startDate: 'Vertragsbeginn', endDate: 'Vertragsende', portalUsername: 'Portal-Benutzername', customerNumberAtProvider: 'Kundennummer beim Anbieter', + contractNumberAtProvider: 'Vertragsnummer beim Anbieter', + customerNumberAtSalesPlatform: 'Kundennummer bei Vertriebsplattform', + contractNumberAtSalesPlatform: 'Vertragsnummer bei Vertriebsplattform', providerId: 'Anbieter', tariffId: 'Tarif', cancellationPeriodId: 'Kündigungsfrist', contractDurationId: 'Vertragslaufzeit', platformId: 'Vertriebsplattform', cancellationDate: 'Kündigungsdatum', cancellationSentDate: 'Kündigung gesendet am', diff --git a/backend/src/services/contract.service.ts b/backend/src/services/contract.service.ts index aa23c0f6..f243f33a 100644 --- a/backend/src/services/contract.service.ts +++ b/backend/src/services/contract.service.ts @@ -203,6 +203,8 @@ interface ContractCreateData { providerName?: string; tariffName?: string; customerNumberAtProvider?: string; + customerNumberAtSalesPlatform?: string; + contractNumberAtSalesPlatform?: string; priceFirst12Months?: string; priceFrom13Months?: string; priceAfter24Months?: string; @@ -896,6 +898,9 @@ export async function createRenewalContract(previousContractId: number) { providerName: previousContract.providerName, tariffName: previousContract.tariffName, customerNumberAtProvider: previousContract.customerNumberAtProvider, + contractNumberAtProvider: previousContract.contractNumberAtProvider, + customerNumberAtSalesPlatform: previousContract.customerNumberAtSalesPlatform, + contractNumberAtSalesPlatform: previousContract.contractNumberAtSalesPlatform, portalUsername: previousContract.portalUsername, portalPasswordEncrypted: previousContract.portalPasswordEncrypted, commission: previousContract.commission, diff --git a/backend/src/utils/sanitize.ts b/backend/src/utils/sanitize.ts index c41d105a..6f59381f 100644 --- a/backend/src/utils/sanitize.ts +++ b/backend/src/utils/sanitize.ts @@ -75,6 +75,8 @@ const CONTRACT_DISPLAY_STRING_FIELDS = [ 'tariffName', 'customerNumberAtProvider', 'contractNumberAtProvider', + 'customerNumberAtSalesPlatform', + 'contractNumberAtSalesPlatform', 'portalUsername', 'previousProviderName', 'previousCustomerNumber', diff --git a/docs/todo.md b/docs/todo.md index 93aa1a0c..add908cc 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,20 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **🆕 Vertrag: Kunden-/Vertragsnummer bei Vertriebsplattform** + - Zwei neue optionale Felder + `Contract.customerNumberAtSalesPlatform` + + `contractNumberAtSalesPlatform`, Migration + `20260603150000_contract_sales_platform_numbers` mit + `IF NOT EXISTS`. + - Im ContractForm direkt unter „Kundennummer/Vertragsnummer beim + Anbieter" angeordnet. ContractDetail zeigt sie als eigene Zeilen + mit Copy-Button. Audit-Log-Mapping + Renewal-Copy + XSS-Strip + (CONTRACT_DISPLAY_STRING_FIELDS) mitgezogen. + - Bonus: das fehlende `contractNumberAtProvider` im Renewal-Copy + und Audit-Label-Mapping ist gleich mit drin – wurde bisher + nicht in VVL-Folgeverträge kopiert. + - [x] **🆕 Email-Links öffnen im neuen Tab** - In `EmailDetail` nach der DOMPurify-Sanitize jedes ``-Element auf `target="_blank"` + `rel="noopener noreferrer"` gesetzt. Letzteres diff --git a/frontend/src/pages/contracts/ContractDetail.tsx b/frontend/src/pages/contracts/ContractDetail.tsx index e6925dee..1414eba2 100644 --- a/frontend/src/pages/contracts/ContractDetail.tsx +++ b/frontend/src/pages/contracts/ContractDetail.tsx @@ -2080,6 +2080,24 @@ export default function ContractDetail() { )} + {c.customerNumberAtSalesPlatform && ( +
+
Kundennr. Vertriebsplattform
+
+ {c.customerNumberAtSalesPlatform} + +
+
+ )} + {c.contractNumberAtSalesPlatform && ( +
+
Vertragsnr. Vertriebsplattform
+
+ {c.contractNumberAtSalesPlatform} + +
+
+ )} {c.salesPlatform && (
Vertriebsplattform
diff --git a/frontend/src/pages/contracts/ContractForm.tsx b/frontend/src/pages/contracts/ContractForm.tsx index 9b480d1a..dce7cf33 100644 --- a/frontend/src/pages/contracts/ContractForm.tsx +++ b/frontend/src/pages/contracts/ContractForm.tsx @@ -302,6 +302,8 @@ export default function ContractForm() { tariffName: c.tariffName || '', customerNumberAtProvider: c.customerNumberAtProvider || '', contractNumberAtProvider: c.contractNumberAtProvider || '', + customerNumberAtSalesPlatform: c.customerNumberAtSalesPlatform || '', + contractNumberAtSalesPlatform: c.contractNumberAtSalesPlatform || '', priceFirst12Months: c.priceFirst12Months || '', priceFrom13Months: c.priceFrom13Months || '', priceAfter24Months: c.priceAfter24Months || '', @@ -556,6 +558,8 @@ export default function ContractForm() { tariffName: emptyToNull(data.tariffName), customerNumberAtProvider: emptyToNull(data.customerNumberAtProvider), contractNumberAtProvider: emptyToNull(data.contractNumberAtProvider), + customerNumberAtSalesPlatform: emptyToNull(data.customerNumberAtSalesPlatform), + contractNumberAtSalesPlatform: emptyToNull(data.contractNumberAtSalesPlatform), priceFirst12Months: emptyToNull(data.priceFirst12Months), priceFrom13Months: emptyToNull(data.priceFrom13Months), priceAfter24Months: emptyToNull(data.priceAfter24Months), @@ -952,6 +956,8 @@ export default function ContractForm() { /> + + diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index a04c54f5..d63aafb5 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -454,6 +454,8 @@ export interface Contract { tariffName?: string; customerNumberAtProvider?: string; contractNumberAtProvider?: string; + customerNumberAtSalesPlatform?: string; + contractNumberAtSalesPlatform?: string; priceFirst12Months?: string; priceFrom13Months?: string; priceAfter24Months?: string;