@ambushsoftworks/nestjs-payments-graphql 0.1.0 → 0.1.3

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.
@@ -0,0 +1,504 @@
1
+ // =============================================================================
2
+ // @ambushsoftworks/nestjs-payments-graphql — Reference Prisma schema
3
+ // =============================================================================
4
+ //
5
+ // This file is a DOCUMENTATION FRAGMENT. It is not loaded by Prisma at runtime
6
+ // and it is not imported automatically anywhere. Copy the models and enums
7
+ // below into your own `schema.prisma` and wire up the consumer-owned relations
8
+ // (marked with `// CONSUMER:`) to the models in your application.
9
+ //
10
+ // Field shapes are fixed by the package's repository interfaces
11
+ // (IInvoiceRepository, IPaymentRepository, etc.). You may:
12
+ // - Rename models freely (your repo adapter is the mapping layer).
13
+ // - Add columns (e.g. a soft-delete flag, additional audit fields).
14
+ // - Swap column types for compatible ones (e.g. `@db.VarChar(255)` on strings).
15
+ //
16
+ // You may NOT:
17
+ // - Change the cardinality of a field (e.g. make a required field optional
18
+ // without reflecting that in your repository adapter).
19
+ // - Drop tracked enum values (listed below).
20
+ //
21
+ // The package is database-agnostic — PostgreSQL examples are shown (e.g.
22
+ // `@db.Decimal(5, 4)`); swap for your provider's equivalents as needed.
23
+ //
24
+ // -----------------------------------------------------------------------------
25
+ // Model checklist
26
+ // -----------------------------------------------------------------------------
27
+ //
28
+ // Always required:
29
+ // - Invoice
30
+ // - InvoiceLineItem
31
+ // - Payment
32
+ // - Refund
33
+ // - PaymentConfig
34
+ // - PaymentProvider
35
+ // - ProcessedWebhookEvent
36
+ //
37
+ // Required when `features.paymentPlans = true`:
38
+ // - PaymentPlan
39
+ // - PaymentPlanInstallment
40
+ //
41
+ // Required when `features.recurringInvoices = true`:
42
+ // - RecurringInvoice
43
+ // - RecurringInvoiceLineItem
44
+ // - PaymentCustomer
45
+ //
46
+ // All enums are required if you use the corresponding model.
47
+ // =============================================================================
48
+
49
+
50
+ // -----------------------------------------------------------------------------
51
+ // Enums
52
+ // -----------------------------------------------------------------------------
53
+ // These enum value sets must match exactly — core services compare against
54
+ // these strings. Add new values at your own risk; the package will not
55
+ // recognize them.
56
+
57
+ enum InvoiceStatus {
58
+ DRAFT
59
+ SENT
60
+ PARTIALLY_PAID
61
+ PAID
62
+ OVERDUE
63
+ VOID
64
+ REFUNDED
65
+ }
66
+
67
+ enum PaymentMethod {
68
+ CREDIT_CARD
69
+ DEBIT
70
+ E_TRANSFER
71
+ BANK_TRANSFER
72
+ CHEQUE
73
+ CASH
74
+ OTHER
75
+ }
76
+
77
+ enum PaymentStatus {
78
+ PENDING
79
+ PENDING_CONFIRMATION
80
+ PROCESSING
81
+ SUCCEEDED
82
+ FAILED
83
+ CANCELLED
84
+ REJECTED
85
+ REFUNDED
86
+ PARTIALLY_REFUNDED
87
+ }
88
+
89
+ enum RefundStatus {
90
+ PENDING
91
+ PROCESSING
92
+ SUCCEEDED
93
+ FAILED
94
+ }
95
+
96
+ enum PaymentPlanStatus {
97
+ ACTIVE
98
+ COMPLETED
99
+ CANCELLED
100
+ DEFAULTED
101
+ }
102
+
103
+ enum InstallmentStatus {
104
+ PENDING
105
+ INVOICED
106
+ PAID
107
+ OVERDUE
108
+ WAIVED
109
+ CANCELLED
110
+ }
111
+
112
+ enum RecurringIntervalUnit {
113
+ DAYS
114
+ MONTHS
115
+ }
116
+
117
+ enum RecurringInvoiceStatus {
118
+ ACTIVE
119
+ PAUSED
120
+ CANCELLED
121
+ }
122
+
123
+
124
+ // -----------------------------------------------------------------------------
125
+ // Core models (always required)
126
+ // -----------------------------------------------------------------------------
127
+
128
+ model PaymentConfig {
129
+ id String @id @default(uuid())
130
+ divisionId String @unique // CONSUMER: tenant/org/division scope — unique per tenant
131
+
132
+ // E-transfer settings
133
+ eTransferEnabled Boolean @default(false)
134
+ eTransferEmail String?
135
+ eTransferRecipient String? // Display name for e-transfer recipient
136
+ eTransferAutoDeposit Boolean @default(true)
137
+
138
+ // Defaults applied when an invoice omits currency or tax rate
139
+ defaultCurrency String @default("USD")
140
+ defaultTaxRate Decimal? @db.Decimal(5, 4) // e.g. 0.1300 for 13%
141
+
142
+ createdAt DateTime @default(now())
143
+ updatedAt DateTime @updatedAt
144
+
145
+ providers PaymentProvider[]
146
+
147
+ // CONSUMER: add @relation to your Tenant/Division/Organization model
148
+ // division Division @relation(fields: [divisionId], references: [id], onDelete: Cascade)
149
+ }
150
+
151
+ model PaymentProvider {
152
+ id String @id @default(uuid())
153
+ paymentConfigId String
154
+ providerType String // e.g. "stripe"
155
+ isActive Boolean @default(true)
156
+ config Json? // Non-secret config (account IDs, webhook endpoint IDs)
157
+
158
+ createdAt DateTime @default(now())
159
+ updatedAt DateTime @updatedAt
160
+
161
+ paymentConfig PaymentConfig @relation(fields: [paymentConfigId], references: [id], onDelete: Cascade)
162
+
163
+ @@unique([paymentConfigId, providerType])
164
+ }
165
+
166
+ model Invoice {
167
+ id String @id @default(uuid())
168
+ divisionId String // CONSUMER: tenant/org scope
169
+ invoiceNumber String @unique
170
+ status InvoiceStatus @default(DRAFT)
171
+
172
+ // CONSUMER: opaque foreign key to your client/customer/contact record.
173
+ // The package treats this as an opaque string.
174
+ clientDetailsId String
175
+
176
+ // Polymorphic entity reference — what this invoice is FOR (booking, order,
177
+ // enrollment, etc.). Both fields nullable so invoices may stand alone.
178
+ referenceType String?
179
+ referenceId String?
180
+
181
+ // Payment plan link (populated when an invoice is generated from an installment)
182
+ paymentPlanId String?
183
+ installmentNumber Int?
184
+
185
+ // Recurring invoice link (populated when an invoice is generated from a recurring config)
186
+ recurringInvoiceId String?
187
+
188
+ // Financial amounts — ALL IN CENTS (integer minor units).
189
+ // taxRate is a decimal fraction: 0.1300 = 13%.
190
+ subtotal Int @default(0)
191
+ taxRate Decimal @default(0) @db.Decimal(5, 4)
192
+ taxAmount Int @default(0)
193
+ discount Int @default(0)
194
+ total Int @default(0)
195
+ amountPaid Int @default(0)
196
+ amountDue Int @default(0)
197
+
198
+ currency String @default("USD")
199
+
200
+ // E-transfer — code is the client-visible confirmation string, answer is
201
+ // the security answer the client must provide to the bank.
202
+ eTransferCode String? @unique
203
+ eTransferAnswer String?
204
+
205
+ issuedAt DateTime?
206
+ dueAt DateTime?
207
+
208
+ notes String? // Internal staff notes (never exposed to clients)
209
+ clientNotes String? // Visible on invoice to client
210
+
211
+ // Consumer-defined key-value pairs (opaque to the package)
212
+ metadata Json?
213
+
214
+ // Audit fields
215
+ createdBy String // CONSUMER: accountId/userId who created this invoice
216
+ voidedBy String?
217
+ voidedAt DateTime?
218
+ voidReason String?
219
+
220
+ createdAt DateTime @default(now())
221
+ updatedAt DateTime @updatedAt
222
+
223
+ // Relations
224
+ lineItems InvoiceLineItem[]
225
+ payments Payment[]
226
+ // Reverse relation for PaymentPlanInstallment.invoiceId one-to-one
227
+ installment PaymentPlanInstallment?
228
+ paymentPlan PaymentPlan? @relation("InvoicePlan", fields: [paymentPlanId], references: [id], onDelete: SetNull)
229
+ recurringInvoice RecurringInvoice? @relation(fields: [recurringInvoiceId], references: [id])
230
+
231
+ // CONSUMER: add relations to your tenant and client models.
232
+ // Use `onDelete: Restrict` on financial relations — data-retention rules
233
+ // typically forbid cascade-deleting invoices when a client is removed.
234
+ // division Division @relation(fields: [divisionId], references: [id], onDelete: Restrict)
235
+ // clientDetails Details @relation(fields: [clientDetailsId], references: [id], onDelete: Restrict)
236
+
237
+ @@index([divisionId, status])
238
+ @@index([clientDetailsId])
239
+ @@index([referenceType, referenceId])
240
+ @@index([paymentPlanId])
241
+ @@index([recurringInvoiceId])
242
+ @@index([status, dueAt]) // For overdue scheduler
243
+ }
244
+
245
+ model InvoiceLineItem {
246
+ id String @id @default(uuid())
247
+ invoiceId String
248
+
249
+ description String
250
+ quantity Int @default(1)
251
+ unitPrice Int // cents
252
+ sortOrder Int @default(0)
253
+ isTaxable Boolean @default(true)
254
+
255
+ // Optional polymorphic reference — what this line item represents
256
+ referenceType String?
257
+ referenceId String?
258
+
259
+ // Consumer-defined key-value pairs (opaque to the package)
260
+ metadata Json?
261
+
262
+ createdAt DateTime @default(now())
263
+ updatedAt DateTime @updatedAt
264
+
265
+ invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
266
+
267
+ @@index([invoiceId, sortOrder])
268
+ }
269
+
270
+ model Payment {
271
+ id String @id @default(uuid())
272
+ invoiceId String
273
+ amount Int // cents
274
+ currency String @default("USD")
275
+ method PaymentMethod
276
+ status PaymentStatus @default(PENDING)
277
+
278
+ // Provider fields (both null for manual payments, both set for online)
279
+ provider String? // e.g. "stripe"
280
+ providerPaymentId String?
281
+ providerData Json? // Provider-specific metadata — NEVER log raw card data
282
+ receiptUrl String?
283
+
284
+ // Manual payment fields
285
+ referenceNumber String? // cheque number, e-transfer confirmation, etc.
286
+ notes String?
287
+ processedAt DateTime? // When payment was actually processed (may differ from createdAt)
288
+ receivedBy String? // CONSUMER: accountId who recorded the manual payment
289
+
290
+ // Reconciliation — set true when gateway cancellation fails during voidInvoice
291
+ needsReconciliation Boolean @default(false)
292
+
293
+ // Audit
294
+ createdBy String // CONSUMER: accountId/userId who created the payment
295
+
296
+ createdAt DateTime @default(now())
297
+ updatedAt DateTime @updatedAt
298
+
299
+ invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Restrict)
300
+ refunds Refund[]
301
+
302
+ // Note: null-null is valid (manual payments) — PostgreSQL unique allows multiple nulls.
303
+ @@unique([provider, providerPaymentId])
304
+ @@index([invoiceId, status])
305
+ }
306
+
307
+ model Refund {
308
+ id String @id @default(uuid())
309
+ paymentId String
310
+ amount Int // cents
311
+ currency String @default("USD")
312
+ status RefundStatus @default(PENDING)
313
+ reason String?
314
+
315
+ // Provider fields (null for manual refunds)
316
+ providerRefundId String?
317
+ providerData Json?
318
+
319
+ // Audit
320
+ createdBy String // CONSUMER: accountId/userId who created the refund
321
+ processedBy String? // CONSUMER: accountId who processed a manual refund
322
+
323
+ createdAt DateTime @default(now())
324
+ updatedAt DateTime @updatedAt
325
+
326
+ payment Payment @relation(fields: [paymentId], references: [id], onDelete: Restrict)
327
+
328
+ @@index([paymentId])
329
+ }
330
+
331
+ model ProcessedWebhookEvent {
332
+ // Stripe event IDs are their own primary key.
333
+ // The package's IWebhookIdempotencyRepository uses this to no-op on replays.
334
+ eventId String @id
335
+ processedAt DateTime @default(now())
336
+
337
+ @@index([processedAt]) // For TTL cleanup via cleanupBefore()
338
+ }
339
+
340
+
341
+ // -----------------------------------------------------------------------------
342
+ // Payment plan models (required when features.paymentPlans = true)
343
+ // -----------------------------------------------------------------------------
344
+
345
+ model PaymentPlan {
346
+ id String @id @default(uuid())
347
+ divisionId String // CONSUMER: tenant/org scope
348
+ status PaymentPlanStatus @default(ACTIVE)
349
+
350
+ clientDetailsId String // CONSUMER: opaque client ID
351
+
352
+ // Polymorphic entity reference
353
+ referenceType String?
354
+ referenceId String?
355
+
356
+ totalAmount Int // cents
357
+ currency String @default("USD")
358
+
359
+ name String?
360
+ description String?
361
+
362
+ createdBy String // CONSUMER: accountId
363
+ cancelledBy String?
364
+ cancelledAt DateTime?
365
+ cancelReason String?
366
+
367
+ createdAt DateTime @default(now())
368
+ updatedAt DateTime @updatedAt
369
+
370
+ installments PaymentPlanInstallment[]
371
+ invoices Invoice[] @relation("InvoicePlan")
372
+
373
+ // CONSUMER: add relations to your tenant and client models.
374
+ // division Division @relation(fields: [divisionId], references: [id], onDelete: Restrict)
375
+ // clientDetails Details @relation(fields: [clientDetailsId], references: [id], onDelete: Restrict)
376
+
377
+ @@index([divisionId, status])
378
+ @@index([clientDetailsId])
379
+ @@index([referenceType, referenceId])
380
+ }
381
+
382
+ model PaymentPlanInstallment {
383
+ id String @id @default(uuid())
384
+ paymentPlanId String
385
+ sequenceOrder Int
386
+ amount Int // cents
387
+ status InstallmentStatus @default(PENDING)
388
+ dueAt DateTime?
389
+
390
+ // One-to-one link to the generated invoice (null until invoiced).
391
+ // INVARIANT: when set, Invoice.paymentPlanId and Invoice.installmentNumber
392
+ // must also be set atomically by the consumer repository adapter.
393
+ invoiceId String? @unique
394
+
395
+ createdAt DateTime @default(now())
396
+ updatedAt DateTime @updatedAt
397
+
398
+ paymentPlan PaymentPlan @relation(fields: [paymentPlanId], references: [id], onDelete: Cascade)
399
+ invoice Invoice? @relation(fields: [invoiceId], references: [id], onDelete: SetNull)
400
+
401
+ @@index([paymentPlanId, sequenceOrder])
402
+ }
403
+
404
+
405
+ // -----------------------------------------------------------------------------
406
+ // Recurring invoice models (required when features.recurringInvoices = true)
407
+ // -----------------------------------------------------------------------------
408
+
409
+ model RecurringInvoice {
410
+ id String @id @default(uuid())
411
+ divisionId String // CONSUMER: tenant/org scope
412
+
413
+ // Schedule configuration
414
+ intervalUnit RecurringIntervalUnit
415
+ intervalValue Int
416
+ anchorDate DateTime // Immutable after creation — all next dates are computed from this
417
+ nextInvoiceAt DateTime
418
+ lastGeneratedAt DateTime? // Null = never generated; set after each successful generation
419
+
420
+ status RecurringInvoiceStatus @default(ACTIVE)
421
+ autoSend Boolean @default(true)
422
+
423
+ // Invoice template fields
424
+ clientDetailsId String // CONSUMER: opaque client ID
425
+ currency String @default("USD")
426
+ taxRate Decimal @default(0) @db.Decimal(5, 4)
427
+ notes String?
428
+ clientNotes String?
429
+
430
+ // Polymorphic entity reference
431
+ referenceType String?
432
+ referenceId String?
433
+
434
+ // Auto-charge (Phase 2) — uses the stored PaymentCustomer for the client
435
+ autoCharge Boolean @default(false)
436
+ metadata Json?
437
+ consecutiveFailures Int @default(0)
438
+ lastFailureReason String?
439
+
440
+ // Lifecycle tracking
441
+ pausedAt DateTime?
442
+ pausedBy String?
443
+ cancelledAt DateTime?
444
+ cancelledBy String?
445
+ cancelReason String?
446
+
447
+ createdBy String
448
+ createdAt DateTime @default(now())
449
+ updatedAt DateTime @updatedAt
450
+
451
+ templateLineItems RecurringInvoiceLineItem[]
452
+ generatedInvoices Invoice[]
453
+
454
+ // CONSUMER: add relations to your tenant and client models.
455
+ // division Division @relation(fields: [divisionId], references: [id], onDelete: Restrict)
456
+ // clientDetails Details @relation(fields: [clientDetailsId], references: [id], onDelete: Restrict)
457
+
458
+ @@index([status, nextInvoiceAt]) // Used by the generator claim query
459
+ @@index([divisionId, status])
460
+ }
461
+
462
+ model RecurringInvoiceLineItem {
463
+ id String @id @default(uuid())
464
+ recurringInvoiceId String
465
+
466
+ description String
467
+ quantity Int @default(1)
468
+ unitPrice Int // cents
469
+ sortOrder Int @default(0)
470
+ isTaxable Boolean @default(true)
471
+
472
+ referenceType String?
473
+ referenceId String?
474
+
475
+ metadata Json?
476
+
477
+ createdAt DateTime @default(now())
478
+ updatedAt DateTime @updatedAt
479
+
480
+ recurringInvoice RecurringInvoice @relation(fields: [recurringInvoiceId], references: [id], onDelete: Cascade)
481
+
482
+ @@index([recurringInvoiceId, sortOrder])
483
+ }
484
+
485
+ model PaymentCustomer {
486
+ // Maps a (division, client, provider) triple to a provider-side customer ID
487
+ // (e.g. Stripe Customer). Powers auto-charge on recurring invoices and
488
+ // future saved-payment-method flows.
489
+ id String @id @default(uuid())
490
+ divisionId String
491
+ clientDetailsId String
492
+ provider String // "stripe"
493
+ providerCustomerId String
494
+
495
+ createdAt DateTime @default(now())
496
+ updatedAt DateTime @updatedAt
497
+
498
+ // CONSUMER: add relations to your tenant and client models.
499
+ // division Division @relation(fields: [divisionId], references: [id], onDelete: Restrict)
500
+ // clientDetails Details @relation(fields: [clientDetailsId], references: [id], onDelete: Restrict)
501
+
502
+ @@unique([divisionId, clientDetailsId, provider])
503
+ @@index([providerCustomerId])
504
+ }