@valentine-efagene/qshelter-common 2.0.30 → 2.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@ export * from './ContractPhase';
8
8
  export * from './ContractPhaseStep';
9
9
  export * from './ContractPhaseStepApproval';
10
10
  export * from './ContractPhaseStepDocument';
11
+ export * from './ContractTermination';
11
12
  export * from './ContractTransition';
12
13
  export * from './DeviceEndpoint';
13
14
  export * from './DocumentRequirementRule';
@@ -8,6 +8,7 @@ export * from './ContractPhase';
8
8
  export * from './ContractPhaseStep';
9
9
  export * from './ContractPhaseStepApproval';
10
10
  export * from './ContractPhaseStepDocument';
11
+ export * from './ContractTermination';
11
12
  export * from './ContractTransition';
12
13
  export * from './DeviceEndpoint';
13
14
  export * from './DocumentRequirementRule';
@@ -39,6 +39,7 @@ export type * from './models/ContractPayment.js';
39
39
  export type * from './models/ContractDocument.js';
40
40
  export type * from './models/ContractTransition.js';
41
41
  export type * from './models/ContractEvent.js';
42
+ export type * from './models/ContractTermination.js';
42
43
  export type * from './models/Prequalification.js';
43
44
  export type * from './models/PaymentMethodChangeRequest.js';
44
45
  export type * from './models/DocumentRequirementRule.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.30",
3
+ "version": "2.0.31",
4
4
  "description": "Shared database schemas and utilities for QShelter services",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -0,0 +1,119 @@
1
+ /*
2
+ Warnings:
3
+
4
+ - You are about to alter the column `status` on the `contract_documents` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(16))`.
5
+ - You are about to alter the column `status` on the `contract_installments` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(14))`.
6
+ - You are about to alter the column `status` on the `contract_payments` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(15))`.
7
+ - You are about to alter the column `decision` on the `contract_phase_step_approvals` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(13))`.
8
+ - You are about to drop the column `requiredDocumentTypes` on the `contract_phase_steps` table. All the data in the column will be lost.
9
+ - You are about to alter the column `stepType` on the `contract_phase_steps` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(11))`.
10
+ - You are about to alter the column `status` on the `contract_phase_steps` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(12))`.
11
+ - You are about to alter the column `phaseCategory` on the `contract_phases` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(7))`.
12
+ - You are about to alter the column `phaseType` on the `contract_phases` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(8))`.
13
+ - You are about to alter the column `status` on the `contract_phases` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(9))`.
14
+ - You are about to alter the column `status` on the `contracts` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(6))`.
15
+ - You are about to alter the column `state` on the `contracts` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(6))`.
16
+ - You are about to alter the column `paymentFrequency` on the `payment_plans` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(0))`.
17
+ - You are about to drop the column `requiredDocumentTypes` on the `property_payment_method_phases` table. All the data in the column will be lost.
18
+ - You are about to drop the column `stepDefinitions` on the `property_payment_method_phases` table. All the data in the column will be lost.
19
+ - You are about to alter the column `phaseCategory` on the `property_payment_method_phases` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(7))`.
20
+ - You are about to alter the column `phaseType` on the `property_payment_method_phases` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(8))`.
21
+
22
+ */
23
+ -- AlterTable
24
+ ALTER TABLE `contract_documents` MODIFY `status` ENUM('PENDING', 'APPROVED', 'REJECTED') NOT NULL DEFAULT 'PENDING';
25
+
26
+ -- AlterTable
27
+ ALTER TABLE `contract_installments` MODIFY `status` ENUM('PENDING', 'PAID', 'OVERDUE', 'PARTIALLY_PAID', 'WAIVED') NOT NULL DEFAULT 'PENDING';
28
+
29
+ -- AlterTable
30
+ ALTER TABLE `contract_payments` MODIFY `status` ENUM('INITIATED', 'PENDING', 'COMPLETED', 'FAILED', 'REFUNDED') NOT NULL DEFAULT 'INITIATED';
31
+
32
+ -- AlterTable
33
+ ALTER TABLE `contract_phase_step_approvals` MODIFY `decision` ENUM('APPROVED', 'REJECTED', 'REQUEST_CHANGES') NOT NULL;
34
+
35
+ -- AlterTable
36
+ ALTER TABLE `contract_phase_steps` DROP COLUMN `requiredDocumentTypes`,
37
+ MODIFY `stepType` ENUM('UPLOAD', 'REVIEW', 'SIGNATURE', 'APPROVAL', 'EXTERNAL_CHECK', 'WAIT') NOT NULL,
38
+ MODIFY `status` ENUM('PENDING', 'IN_PROGRESS', 'COMPLETED', 'FAILED', 'SKIPPED') NOT NULL DEFAULT 'PENDING';
39
+
40
+ -- AlterTable
41
+ ALTER TABLE `contract_phases` ADD COLUMN `approvedDocumentsCount` INTEGER NOT NULL DEFAULT 0,
42
+ ADD COLUMN `completedStepsCount` INTEGER NOT NULL DEFAULT 0,
43
+ ADD COLUMN `completionCriterion` ENUM('DOCUMENT_APPROVALS', 'PAYMENT_AMOUNT', 'STEPS_COMPLETED') NULL,
44
+ ADD COLUMN `paymentPlanSnapshot` JSON NULL,
45
+ ADD COLUMN `requiredDocumentSnapshot` JSON NULL,
46
+ ADD COLUMN `requiredDocumentsCount` INTEGER NOT NULL DEFAULT 0,
47
+ ADD COLUMN `stepDefinitionsSnapshot` JSON NULL,
48
+ ADD COLUMN `totalStepsCount` INTEGER NOT NULL DEFAULT 0,
49
+ MODIFY `phaseCategory` ENUM('DOCUMENTATION', 'PAYMENT') NOT NULL,
50
+ MODIFY `phaseType` ENUM('KYC', 'VERIFICATION', 'DOWNPAYMENT', 'MORTGAGE', 'BALLOON', 'CUSTOM') NOT NULL,
51
+ MODIFY `status` ENUM('PENDING', 'IN_PROGRESS', 'AWAITING_APPROVAL', 'ACTIVE', 'COMPLETED', 'SKIPPED', 'FAILED') NOT NULL DEFAULT 'PENDING';
52
+
53
+ -- AlterTable
54
+ ALTER TABLE `contracts` MODIFY `status` ENUM('DRAFT', 'PENDING', 'ACTIVE', 'COMPLETED', 'CANCELLED', 'TERMINATED') NOT NULL DEFAULT 'DRAFT',
55
+ MODIFY `state` ENUM('DRAFT', 'PENDING', 'ACTIVE', 'COMPLETED', 'CANCELLED', 'TERMINATED') NOT NULL DEFAULT 'DRAFT';
56
+
57
+ -- AlterTable
58
+ ALTER TABLE `payment_plans` MODIFY `paymentFrequency` ENUM('MONTHLY', 'BIWEEKLY', 'WEEKLY', 'ONE_TIME', 'CUSTOM') NOT NULL;
59
+
60
+ -- AlterTable
61
+ ALTER TABLE `property_payment_method_phases` DROP COLUMN `requiredDocumentTypes`,
62
+ DROP COLUMN `stepDefinitions`,
63
+ ADD COLUMN `completionCriterion` ENUM('DOCUMENT_APPROVALS', 'PAYMENT_AMOUNT', 'STEPS_COMPLETED') NULL,
64
+ ADD COLUMN `requiredDocumentSnapshot` JSON NULL,
65
+ ADD COLUMN `stepDefinitionsSnapshot` JSON NULL,
66
+ MODIFY `phaseCategory` ENUM('DOCUMENTATION', 'PAYMENT') NOT NULL,
67
+ MODIFY `phaseType` ENUM('KYC', 'VERIFICATION', 'DOWNPAYMENT', 'MORTGAGE', 'BALLOON', 'CUSTOM') NOT NULL;
68
+
69
+ -- CreateTable
70
+ CREATE TABLE `payment_method_phase_steps` (
71
+ `id` VARCHAR(191) NOT NULL,
72
+ `phaseId` VARCHAR(191) NOT NULL,
73
+ `name` VARCHAR(191) NOT NULL,
74
+ `stepType` ENUM('UPLOAD', 'REVIEW', 'SIGNATURE', 'APPROVAL', 'EXTERNAL_CHECK', 'WAIT') NOT NULL,
75
+ `order` INTEGER NOT NULL,
76
+ `metadata` JSON NULL,
77
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
78
+ `updatedAt` DATETIME(3) NOT NULL,
79
+
80
+ INDEX `payment_method_phase_steps_phaseId_idx`(`phaseId`),
81
+ PRIMARY KEY (`id`)
82
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
83
+
84
+ -- CreateTable
85
+ CREATE TABLE `payment_method_phase_documents` (
86
+ `id` VARCHAR(191) NOT NULL,
87
+ `phaseId` VARCHAR(191) NOT NULL,
88
+ `documentType` VARCHAR(191) NOT NULL,
89
+ `isRequired` BOOLEAN NOT NULL DEFAULT true,
90
+ `description` TEXT NULL,
91
+ `allowedMimeTypes` VARCHAR(191) NULL,
92
+ `maxSizeBytes` INTEGER NULL,
93
+ `metadata` JSON NULL,
94
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
95
+
96
+ INDEX `payment_method_phase_documents_phaseId_documentType_idx`(`phaseId`, `documentType`),
97
+ PRIMARY KEY (`id`)
98
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
99
+
100
+ -- CreateTable
101
+ CREATE TABLE `contract_phase_step_documents` (
102
+ `id` VARCHAR(191) NOT NULL,
103
+ `stepId` VARCHAR(191) NOT NULL,
104
+ `documentType` VARCHAR(191) NOT NULL,
105
+ `isRequired` BOOLEAN NOT NULL DEFAULT true,
106
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
107
+
108
+ INDEX `contract_phase_step_documents_stepId_documentType_idx`(`stepId`, `documentType`),
109
+ PRIMARY KEY (`id`)
110
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
111
+
112
+ -- AddForeignKey
113
+ ALTER TABLE `payment_method_phase_steps` ADD CONSTRAINT `payment_method_phase_steps_phaseId_fkey` FOREIGN KEY (`phaseId`) REFERENCES `property_payment_method_phases`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
114
+
115
+ -- AddForeignKey
116
+ ALTER TABLE `payment_method_phase_documents` ADD CONSTRAINT `payment_method_phase_documents_phaseId_fkey` FOREIGN KEY (`phaseId`) REFERENCES `property_payment_method_phases`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
117
+
118
+ -- AddForeignKey
119
+ ALTER TABLE `contract_phase_step_documents` ADD CONSTRAINT `contract_phase_step_documents_stepId_fkey` FOREIGN KEY (`stepId`) REFERENCES `contract_phase_steps`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,69 @@
1
+ -- CreateTable
2
+ CREATE TABLE `contract_terminations` (
3
+ `id` VARCHAR(191) NOT NULL,
4
+ `contractId` VARCHAR(191) NOT NULL,
5
+ `tenantId` VARCHAR(191) NOT NULL,
6
+ `requestNumber` VARCHAR(191) NOT NULL,
7
+ `initiatedBy` ENUM('BUYER', 'SELLER', 'ADMIN', 'SYSTEM') NOT NULL,
8
+ `initiatorId` VARCHAR(191) NULL,
9
+ `type` ENUM('BUYER_WITHDRAWAL', 'SELLER_WITHDRAWAL', 'MUTUAL_AGREEMENT', 'PAYMENT_DEFAULT', 'DOCUMENT_FAILURE', 'FRAUD', 'FORCE_MAJEURE', 'PROPERTY_UNAVAILABLE', 'REGULATORY', 'OTHER') NOT NULL,
10
+ `reason` TEXT NULL,
11
+ `supportingDocs` JSON NULL,
12
+ `status` ENUM('REQUESTED', 'PENDING_REVIEW', 'PENDING_REFUND', 'REFUND_IN_PROGRESS', 'REFUND_COMPLETED', 'COMPLETED', 'REJECTED', 'CANCELLED') NOT NULL DEFAULT 'REQUESTED',
13
+ `requiresApproval` BOOLEAN NOT NULL DEFAULT true,
14
+ `autoApproveEligible` BOOLEAN NOT NULL DEFAULT false,
15
+ `reviewedBy` VARCHAR(191) NULL,
16
+ `reviewedAt` DATETIME(3) NULL,
17
+ `reviewNotes` TEXT NULL,
18
+ `rejectionReason` TEXT NULL,
19
+ `contractSnapshot` JSON NOT NULL,
20
+ `totalContractAmount` DOUBLE NOT NULL,
21
+ `totalPaidToDate` DOUBLE NOT NULL,
22
+ `outstandingBalance` DOUBLE NOT NULL,
23
+ `refundableAmount` DOUBLE NOT NULL DEFAULT 0,
24
+ `penaltyAmount` DOUBLE NOT NULL DEFAULT 0,
25
+ `forfeitedAmount` DOUBLE NOT NULL DEFAULT 0,
26
+ `adminFeeAmount` DOUBLE NOT NULL DEFAULT 0,
27
+ `netRefundAmount` DOUBLE NOT NULL DEFAULT 0,
28
+ `settlementNotes` TEXT NULL,
29
+ `refundStatus` ENUM('NOT_APPLICABLE', 'PENDING', 'INITIATED', 'PROCESSING', 'PARTIAL_COMPLETED', 'COMPLETED', 'FAILED') NOT NULL DEFAULT 'NOT_APPLICABLE',
30
+ `refundReference` VARCHAR(191) NULL,
31
+ `refundMethod` VARCHAR(191) NULL,
32
+ `refundAccountDetails` JSON NULL,
33
+ `refundInitiatedAt` DATETIME(3) NULL,
34
+ `refundCompletedAt` DATETIME(3) NULL,
35
+ `refundFailureReason` TEXT NULL,
36
+ `unitReleasedAt` DATETIME(3) NULL,
37
+ `unitReservedForId` VARCHAR(191) NULL,
38
+ `requestedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
39
+ `approvedAt` DATETIME(3) NULL,
40
+ `executedAt` DATETIME(3) NULL,
41
+ `completedAt` DATETIME(3) NULL,
42
+ `cancelledAt` DATETIME(3) NULL,
43
+ `idempotencyKey` VARCHAR(191) NULL,
44
+ `metadata` JSON NULL,
45
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
46
+ `updatedAt` DATETIME(3) NOT NULL,
47
+
48
+ UNIQUE INDEX `contract_terminations_requestNumber_key`(`requestNumber`),
49
+ UNIQUE INDEX `contract_terminations_idempotencyKey_key`(`idempotencyKey`),
50
+ INDEX `contract_terminations_contractId_idx`(`contractId`),
51
+ INDEX `contract_terminations_tenantId_idx`(`tenantId`),
52
+ INDEX `contract_terminations_status_idx`(`status`),
53
+ INDEX `contract_terminations_type_idx`(`type`),
54
+ INDEX `contract_terminations_initiatorId_idx`(`initiatorId`),
55
+ INDEX `contract_terminations_requestedAt_idx`(`requestedAt`),
56
+ PRIMARY KEY (`id`)
57
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
58
+
59
+ -- AddForeignKey
60
+ ALTER TABLE `contract_terminations` ADD CONSTRAINT `contract_terminations_contractId_fkey` FOREIGN KEY (`contractId`) REFERENCES `contracts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
61
+
62
+ -- AddForeignKey
63
+ ALTER TABLE `contract_terminations` ADD CONSTRAINT `contract_terminations_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
64
+
65
+ -- AddForeignKey
66
+ ALTER TABLE `contract_terminations` ADD CONSTRAINT `contract_terminations_initiatorId_fkey` FOREIGN KEY (`initiatorId`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
67
+
68
+ -- AddForeignKey
69
+ ALTER TABLE `contract_terminations` ADD CONSTRAINT `contract_terminations_reviewedBy_fkey` FOREIGN KEY (`reviewedBy`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
@@ -99,6 +99,51 @@ enum ApprovalDecision {
99
99
  REQUEST_CHANGES
100
100
  }
101
101
 
102
+ // =============================================================================
103
+ // CONTRACT TERMINATION / CANCELLATION ENUMS
104
+ // =============================================================================
105
+
106
+ enum TerminationType {
107
+ BUYER_WITHDRAWAL // Buyer wants to cancel (voluntary)
108
+ SELLER_WITHDRAWAL // Seller/developer cancels
109
+ MUTUAL_AGREEMENT // Both parties agree to terminate
110
+ PAYMENT_DEFAULT // Buyer failed payment obligations
111
+ DOCUMENT_FAILURE // Buyer failed to provide required documents
112
+ FRAUD // Fraudulent activity detected
113
+ FORCE_MAJEURE // External circumstances (disaster, etc.)
114
+ PROPERTY_UNAVAILABLE // Property no longer available
115
+ REGULATORY // Regulatory/legal requirement
116
+ OTHER // Other reasons (with notes)
117
+ }
118
+
119
+ enum TerminationStatus {
120
+ REQUESTED // Initial request submitted
121
+ PENDING_REVIEW // Awaiting admin review
122
+ PENDING_REFUND // Approved, awaiting refund processing
123
+ REFUND_IN_PROGRESS // Refund being processed
124
+ REFUND_COMPLETED // Refund completed
125
+ COMPLETED // Termination fully executed (no refund or refund done)
126
+ REJECTED // Termination request rejected
127
+ CANCELLED // Termination request was cancelled
128
+ }
129
+
130
+ enum RefundStatus {
131
+ NOT_APPLICABLE // No refund needed (no payments made)
132
+ PENDING // Refund not yet initiated
133
+ INITIATED // Refund request sent to payment gateway
134
+ PROCESSING // Gateway processing refund
135
+ PARTIAL_COMPLETED // Some refund completed (penalties deducted)
136
+ COMPLETED // Full refund completed
137
+ FAILED // Refund failed (needs manual intervention)
138
+ }
139
+
140
+ enum TerminationInitiator {
141
+ BUYER
142
+ SELLER
143
+ ADMIN
144
+ SYSTEM
145
+ }
146
+
102
147
  enum CompletionCriterion {
103
148
  DOCUMENT_APPROVALS
104
149
  PAYMENT_AMOUNT
@@ -160,6 +205,10 @@ model User {
160
205
  paymentMethodChangeRequests PaymentMethodChangeRequest[] @relation("ChangeRequestor")
161
206
  reviewedChangeRequests PaymentMethodChangeRequest[] @relation("ChangeReviewer")
162
207
 
208
+ // Contract terminations
209
+ initiatedTerminations ContractTermination[] @relation("TerminationInitiator")
210
+ reviewedTerminations ContractTermination[] @relation("TerminationReviewer")
211
+
163
212
  @@index([email])
164
213
  @@index([tenantId])
165
214
  @@map("users")
@@ -234,6 +283,9 @@ model Tenant {
234
283
  paymentMethodChangeRequests PaymentMethodChangeRequest[]
235
284
  documentRequirementRules DocumentRequirementRule[]
236
285
 
286
+ // Contract terminations
287
+ contractTerminations ContractTermination[]
288
+
237
289
  @@index([subdomain])
238
290
  @@map("tenants")
239
291
  }
@@ -832,6 +884,7 @@ model Contract {
832
884
  payments ContractPayment[]
833
885
  transitions ContractTransition[]
834
886
  events ContractEvent[]
887
+ terminations ContractTermination[]
835
888
 
836
889
  // Prequalification that led to this contract (optional)
837
890
  prequalification Prequalification?
@@ -1107,6 +1160,98 @@ model ContractEvent {
1107
1160
  @@map("contract_events")
1108
1161
  }
1109
1162
 
1163
+ // =============================================================================
1164
+ // CONTRACT TERMINATION - Full lifecycle for cancellation/termination
1165
+ // =============================================================================
1166
+ // Tracks termination requests from initiation through refund completion.
1167
+ // Industry-standard flow:
1168
+ // 1. Request created (by buyer/seller/admin/system)
1169
+ // 2. Admin reviews (if required by policy)
1170
+ // 3. Financial settlement calculated (refunds, penalties, forfeitures)
1171
+ // 4. Refund processed (if applicable)
1172
+ // 5. Contract marked terminated, unit released
1173
+ // =============================================================================
1174
+
1175
+ model ContractTermination {
1176
+ id String @id @default(cuid())
1177
+ contractId String
1178
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
1179
+ tenantId String
1180
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1181
+
1182
+ // Request identification
1183
+ requestNumber String @unique // TRM-XXXXXX
1184
+
1185
+ // Who initiated and why
1186
+ initiatedBy TerminationInitiator
1187
+ initiatorId String? // userId if BUYER/SELLER/ADMIN
1188
+ initiator User? @relation("TerminationInitiator", fields: [initiatorId], references: [id])
1189
+ type TerminationType
1190
+ reason String? @db.Text
1191
+ supportingDocs Json? // [{type, url, uploadedAt}]
1192
+
1193
+ // Workflow status
1194
+ status TerminationStatus @default(REQUESTED)
1195
+ requiresApproval Boolean @default(true)
1196
+ autoApproveEligible Boolean @default(false) // Pre-signature, no payments
1197
+
1198
+ // Admin review
1199
+ reviewedBy String?
1200
+ reviewer User? @relation("TerminationReviewer", fields: [reviewedBy], references: [id])
1201
+ reviewedAt DateTime?
1202
+ reviewNotes String? @db.Text
1203
+ rejectionReason String? @db.Text
1204
+
1205
+ // Financial snapshot at time of request
1206
+ contractSnapshot Json // Full contract state snapshot
1207
+ totalContractAmount Float
1208
+ totalPaidToDate Float
1209
+ outstandingBalance Float
1210
+
1211
+ // Settlement calculation
1212
+ refundableAmount Float @default(0) // Amount eligible for refund
1213
+ penaltyAmount Float @default(0) // Penalties/fees to deduct
1214
+ forfeitedAmount Float @default(0) // Amount forfeited (non-refundable deposits)
1215
+ adminFeeAmount Float @default(0) // Processing fees
1216
+ netRefundAmount Float @default(0) // refundableAmount - penaltyAmount - adminFeeAmount
1217
+ settlementNotes String? @db.Text
1218
+
1219
+ // Refund processing
1220
+ refundStatus RefundStatus @default(NOT_APPLICABLE)
1221
+ refundReference String? // Payment gateway reference
1222
+ refundMethod String? // ORIGINAL_METHOD, BANK_TRANSFER, CHECK, WALLET
1223
+ refundAccountDetails Json? // Encrypted bank details if needed
1224
+ refundInitiatedAt DateTime?
1225
+ refundCompletedAt DateTime?
1226
+ refundFailureReason String? @db.Text
1227
+
1228
+ // Property unit handling
1229
+ unitReleasedAt DateTime?
1230
+ unitReservedForId String? // If unit being held for another buyer
1231
+
1232
+ // Timing
1233
+ requestedAt DateTime @default(now())
1234
+ approvedAt DateTime?
1235
+ executedAt DateTime?
1236
+ completedAt DateTime?
1237
+ cancelledAt DateTime?
1238
+
1239
+ // Idempotency and audit
1240
+ idempotencyKey String? @unique
1241
+ metadata Json?
1242
+
1243
+ createdAt DateTime @default(now())
1244
+ updatedAt DateTime @updatedAt
1245
+
1246
+ @@index([contractId])
1247
+ @@index([tenantId])
1248
+ @@index([status])
1249
+ @@index([type])
1250
+ @@index([initiatorId])
1251
+ @@index([requestedAt])
1252
+ @@map("contract_terminations")
1253
+ }
1254
+
1110
1255
  // =============================================================================
1111
1256
  // PREQUALIFICATION - Eligibility assessment before contract creation
1112
1257
  // =============================================================================