diff --git a/backend/prisma/migrations/20260727100000_mobile_network/migration.sql b/backend/prisma/migrations/20260727100000_mobile_network/migration.sql new file mode 100644 index 00000000..abe47cf8 --- /dev/null +++ b/backend/prisma/migrations/20260727100000_mobile_network/migration.sql @@ -0,0 +1,6 @@ +-- Mobilfunknetz pro Mobilfunkvertrag (TELEKOM | VODAFONE | TELEFONICA, +-- NULL = nicht gewählt). String statt Enum, damit weitere Netze ohne +-- Migration ergänzbar sind. + +ALTER TABLE `MobileContractDetails` + ADD COLUMN IF NOT EXISTS `mobileNetwork` VARCHAR(191) NULL; diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 8b374ab7..4ff4bb23 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -970,6 +970,10 @@ model MobileContractDetails { contractId Int @unique contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade) requiresMultisim Boolean @default(false) // Multisim erforderlich? + // Physisches Mobilfunknetz, auf dem der Tarif läuft: TELEKOM | VODAFONE + // | TELEFONICA (null = nicht gewählt). Als String statt Enum gehalten, + // damit weitere Netze ohne Migration ergänzbar sind. + mobileNetwork String? dataVolume Float? includedMinutes Int? includedSMS Int? diff --git a/backend/src/services/contract.service.ts b/backend/src/services/contract.service.ts index 5c7291a9..1ed62d8d 100644 --- a/backend/src/services/contract.service.ts +++ b/backend/src/services/contract.service.ts @@ -279,6 +279,7 @@ interface ContractCreateData { }; mobileDetails?: { requiresMultisim?: boolean; + mobileNetwork?: string | null; dataVolume?: number; includedMinutes?: number; includedSMS?: number; @@ -386,6 +387,7 @@ export async function createContract(data: ContractCreateData) { mobileDetails: { create: { requiresMultisim: mobileDetails.requiresMultisim, + mobileNetwork: mobileDetails.mobileNetwork ?? null, dataVolume: mobileDetails.dataVolume, includedMinutes: mobileDetails.includedMinutes, includedSMS: mobileDetails.includedSMS, diff --git a/docs/todo.md b/docs/todo.md index 3e08e8a8..daf83e59 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,17 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **📱 Mobilfunk: Feld „Mobilfunknetz" unter Anbieter & Tarif** + - Neues Dropdown „Mobilfunknetz" in der Anbieter-&-Tarif-Karte, nur + sichtbar wenn Vertragstyp = Mobilfunk. Optionen: Bitte auswählen + (leer), Telekom, Vodafone, Telefónica. + - Neues Feld `MobileContractDetails.mobileNetwork` (String, nullable, + speichert TELEKOM/VODAFONE/TELEFONICA) + Migration + `20260727100000_mobile_network` (`ADD COLUMN IF NOT EXISTS`). + String statt Enum, damit weitere Netze ohne Migration möglich sind. + - Anzeige in der Vertragsansicht (Mobilfunk-Details) mit lesbarem + Netz-Namen. + - [x] **🐞 Lieferbestätigung: eingegebenes Datum ändert Vertragsbeginn nicht** - Beim Upload einer Lieferbestätigung mit Datum wurde `startDate` nur gesetzt, wenn es noch LEER war (`if (!contract.startDate)`). Hatte diff --git a/frontend/src/pages/contracts/ContractDetail.tsx b/frontend/src/pages/contracts/ContractDetail.tsx index c7efcd3b..e212d3cd 100644 --- a/frontend/src/pages/contracts/ContractDetail.tsx +++ b/frontend/src/pages/contracts/ContractDetail.tsx @@ -3077,6 +3077,12 @@ export default function ContractDetail() { {c.mobileDetails && (
+ {c.mobileDetails.mobileNetwork && ( +
+
Mobilfunknetz
+
{({ TELEKOM: 'Telekom', VODAFONE: 'Vodafone', TELEFONICA: 'Telefónica' } as Record)[c.mobileDetails.mobileNetwork] || c.mobileDetails.mobileNetwork}
+
+ )} {c.mobileDetails.dataVolume && (
Datenvolumen
diff --git a/frontend/src/pages/contracts/ContractForm.tsx b/frontend/src/pages/contracts/ContractForm.tsx index 52c5bb32..1ff62374 100644 --- a/frontend/src/pages/contracts/ContractForm.tsx +++ b/frontend/src/pages/contracts/ContractForm.tsx @@ -345,6 +345,7 @@ export default function ContractForm() { activationCode: c.internetDetails?.activationCode || '', // Mobile details requiresMultisim: c.mobileDetails?.requiresMultisim || false, + mobileNetwork: c.mobileDetails?.mobileNetwork || '', dataVolume: c.mobileDetails?.dataVolume || '', includedMinutes: c.mobileDetails?.includedMinutes || '', includedSMS: c.mobileDetails?.includedSMS || '', @@ -656,6 +657,7 @@ export default function ContractForm() { if (data.type === 'MOBILE') { contractData.mobileDetails = { requiresMultisim: data.requiresMultisim || false, + mobileNetwork: emptyToNull(data.mobileNetwork), dataVolume: data.dataVolume ? parseFloat(data.dataVolume) : null, includedMinutes: safeParseInt(data.includedMinutes) ?? null, includedSMS: safeParseInt(data.includedSMS) ?? null, @@ -1019,6 +1021,18 @@ export default function ContractForm() { options={availableTariffs.map((t) => ({ value: t.id, label: t.name }))} disabled={!selectedProviderId} /> + {contractType === 'MOBILE' && ( + diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index f3a62060..84e2c049 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -588,6 +588,8 @@ export interface MobileContractDetails { id: number; contractId: number; requiresMultisim?: boolean; + /** Physisches Mobilfunknetz: TELEKOM | VODAFONE | TELEFONICA (oder null). */ + mobileNetwork?: string | null; dataVolume?: number; includedMinutes?: number; includedSMS?: number;