@ambushsoftworks/nestjs-payments-graphql 0.1.0

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.
Files changed (217) hide show
  1. package/dist/constants.d.ts +17 -0
  2. package/dist/constants.js +21 -0
  3. package/dist/constants.js.map +1 -0
  4. package/dist/dto/create-installment.input.d.ts +5 -0
  5. package/dist/dto/create-installment.input.js +39 -0
  6. package/dist/dto/create-installment.input.js.map +1 -0
  7. package/dist/dto/create-invoice.input.d.ts +13 -0
  8. package/dist/dto/create-invoice.input.js +95 -0
  9. package/dist/dto/create-invoice.input.js.map +1 -0
  10. package/dist/dto/create-line-item.input.d.ts +10 -0
  11. package/dist/dto/create-line-item.input.js +77 -0
  12. package/dist/dto/create-line-item.input.js.map +1 -0
  13. package/dist/dto/create-payment-plan.input.d.ts +11 -0
  14. package/dist/dto/create-payment-plan.input.js +76 -0
  15. package/dist/dto/create-payment-plan.input.js.map +1 -0
  16. package/dist/dto/create-recurring-invoice.input.d.ts +18 -0
  17. package/dist/dto/create-recurring-invoice.input.js +117 -0
  18. package/dist/dto/create-recurring-invoice.input.js.map +1 -0
  19. package/dist/dto/create-recurring-line-item.input.d.ts +10 -0
  20. package/dist/dto/create-recurring-line-item.input.js +77 -0
  21. package/dist/dto/create-recurring-line-item.input.js.map +1 -0
  22. package/dist/dto/create-refund.input.d.ts +5 -0
  23. package/dist/dto/create-refund.input.js +43 -0
  24. package/dist/dto/create-refund.input.js.map +1 -0
  25. package/dist/dto/index.d.ts +8 -0
  26. package/dist/dto/index.js +20 -0
  27. package/dist/dto/index.js.map +1 -0
  28. package/dist/dto/invoice-filter.input.d.ts +10 -0
  29. package/dist/dto/invoice-filter.input.js +64 -0
  30. package/dist/dto/invoice-filter.input.js.map +1 -0
  31. package/dist/dto/payment-plan-filter.input.d.ts +7 -0
  32. package/dist/dto/payment-plan-filter.input.js +46 -0
  33. package/dist/dto/payment-plan-filter.input.js.map +1 -0
  34. package/dist/dto/record-manual-payment.input.d.ts +9 -0
  35. package/dist/dto/record-manual-payment.input.js +58 -0
  36. package/dist/dto/record-manual-payment.input.js.map +1 -0
  37. package/dist/dto/recurring-invoice-filter.input.d.ts +7 -0
  38. package/dist/dto/recurring-invoice-filter.input.js +46 -0
  39. package/dist/dto/recurring-invoice-filter.input.js.map +1 -0
  40. package/dist/dto/update-invoice-metadata.input.d.ts +3 -0
  41. package/dist/dto/update-invoice-metadata.input.js +30 -0
  42. package/dist/dto/update-invoice-metadata.input.js.map +1 -0
  43. package/dist/dto/update-payment-config.input.d.ts +8 -0
  44. package/dist/dto/update-payment-config.input.js +61 -0
  45. package/dist/dto/update-payment-config.input.js.map +1 -0
  46. package/dist/dto/update-recurring-template.input.d.ts +12 -0
  47. package/dist/dto/update-recurring-template.input.js +89 -0
  48. package/dist/dto/update-recurring-template.input.js.map +1 -0
  49. package/dist/dto/upsert-payment-provider.input.d.ts +5 -0
  50. package/dist/dto/upsert-payment-provider.input.js +43 -0
  51. package/dist/dto/upsert-payment-provider.input.js.map +1 -0
  52. package/dist/dto/validators/is-metadata.d.ts +1 -0
  53. package/dist/dto/validators/is-metadata.js +41 -0
  54. package/dist/dto/validators/is-metadata.js.map +1 -0
  55. package/dist/exceptions/index.d.ts +34 -0
  56. package/dist/exceptions/index.js +73 -0
  57. package/dist/exceptions/index.js.map +1 -0
  58. package/dist/gateways/gateway-registry.service.d.ts +10 -0
  59. package/dist/gateways/gateway-registry.service.js +45 -0
  60. package/dist/gateways/gateway-registry.service.js.map +1 -0
  61. package/dist/gateways/payment-gateway.interface.d.ts +50 -0
  62. package/dist/gateways/payment-gateway.interface.js +3 -0
  63. package/dist/gateways/payment-gateway.interface.js.map +1 -0
  64. package/dist/gateways/recurring-payment-gateway.interface.d.ts +32 -0
  65. package/dist/gateways/recurring-payment-gateway.interface.js +3 -0
  66. package/dist/gateways/recurring-payment-gateway.interface.js.map +1 -0
  67. package/dist/gateways/stripe/stripe-webhook.controller.d.ts +24 -0
  68. package/dist/gateways/stripe/stripe-webhook.controller.js +150 -0
  69. package/dist/gateways/stripe/stripe-webhook.controller.js.map +1 -0
  70. package/dist/gateways/stripe/stripe.gateway.d.ts +84 -0
  71. package/dist/gateways/stripe/stripe.gateway.js +424 -0
  72. package/dist/gateways/stripe/stripe.gateway.js.map +1 -0
  73. package/dist/index.d.ts +70 -0
  74. package/dist/index.js +147 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/interfaces/invoice-repository.interface.d.ts +23 -0
  77. package/dist/interfaces/invoice-repository.interface.js +3 -0
  78. package/dist/interfaces/invoice-repository.interface.js.map +1 -0
  79. package/dist/interfaces/payment-config-repository.interface.d.ts +11 -0
  80. package/dist/interfaces/payment-config-repository.interface.js +3 -0
  81. package/dist/interfaces/payment-config-repository.interface.js.map +1 -0
  82. package/dist/interfaces/payment-customer-repository.interface.d.ts +6 -0
  83. package/dist/interfaces/payment-customer-repository.interface.js +3 -0
  84. package/dist/interfaces/payment-customer-repository.interface.js.map +1 -0
  85. package/dist/interfaces/payment-email.interfaces.d.ts +74 -0
  86. package/dist/interfaces/payment-email.interfaces.js +3 -0
  87. package/dist/interfaces/payment-email.interfaces.js.map +1 -0
  88. package/dist/interfaces/payment-event-listener.interface.d.ts +61 -0
  89. package/dist/interfaces/payment-event-listener.interface.js +3 -0
  90. package/dist/interfaces/payment-event-listener.interface.js.map +1 -0
  91. package/dist/interfaces/payment-plan-repository.interface.d.ts +16 -0
  92. package/dist/interfaces/payment-plan-repository.interface.js +3 -0
  93. package/dist/interfaces/payment-plan-repository.interface.js.map +1 -0
  94. package/dist/interfaces/payment-repository.interface.d.ts +13 -0
  95. package/dist/interfaces/payment-repository.interface.js +3 -0
  96. package/dist/interfaces/payment-repository.interface.js.map +1 -0
  97. package/dist/interfaces/recurring-invoice-repository.interface.d.ts +16 -0
  98. package/dist/interfaces/recurring-invoice-repository.interface.js +3 -0
  99. package/dist/interfaces/recurring-invoice-repository.interface.js.map +1 -0
  100. package/dist/interfaces/refund-repository.interface.d.ts +8 -0
  101. package/dist/interfaces/refund-repository.interface.js +3 -0
  102. package/dist/interfaces/refund-repository.interface.js.map +1 -0
  103. package/dist/interfaces/transaction-manager.interface.d.ts +19 -0
  104. package/dist/interfaces/transaction-manager.interface.js +3 -0
  105. package/dist/interfaces/transaction-manager.interface.js.map +1 -0
  106. package/dist/interfaces/webhook-idempotency-repository.interface.d.ts +5 -0
  107. package/dist/interfaces/webhook-idempotency-repository.interface.js +3 -0
  108. package/dist/interfaces/webhook-idempotency-repository.interface.js.map +1 -0
  109. package/dist/models/e-transfer-instructions.model.d.ts +11 -0
  110. package/dist/models/e-transfer-instructions.model.js +56 -0
  111. package/dist/models/e-transfer-instructions.model.js.map +1 -0
  112. package/dist/models/index.d.ts +13 -0
  113. package/dist/models/index.js +36 -0
  114. package/dist/models/index.js.map +1 -0
  115. package/dist/models/invoice-client.model.d.ts +5 -0
  116. package/dist/models/invoice-client.model.js +32 -0
  117. package/dist/models/invoice-client.model.js.map +1 -0
  118. package/dist/models/invoice-line-item.model.d.ts +14 -0
  119. package/dist/models/invoice-line-item.model.js +72 -0
  120. package/dist/models/invoice-line-item.model.js.map +1 -0
  121. package/dist/models/invoice.model.d.ts +86 -0
  122. package/dist/models/invoice.model.js +210 -0
  123. package/dist/models/invoice.model.js.map +1 -0
  124. package/dist/models/online-payment-session.model.d.ts +6 -0
  125. package/dist/models/online-payment-session.model.js +40 -0
  126. package/dist/models/online-payment-session.model.js.map +1 -0
  127. package/dist/models/paginated-invoices.model.d.ts +5 -0
  128. package/dist/models/paginated-invoices.model.js +19 -0
  129. package/dist/models/paginated-invoices.model.js.map +1 -0
  130. package/dist/models/paginated-payment-plans.model.d.ts +5 -0
  131. package/dist/models/paginated-payment-plans.model.js +19 -0
  132. package/dist/models/paginated-payment-plans.model.js.map +1 -0
  133. package/dist/models/paginated-recurring-invoices.model.d.ts +5 -0
  134. package/dist/models/paginated-recurring-invoices.model.js +19 -0
  135. package/dist/models/paginated-recurring-invoices.model.js.map +1 -0
  136. package/dist/models/paginated.model.d.ts +6 -0
  137. package/dist/models/paginated.model.js +30 -0
  138. package/dist/models/paginated.model.js.map +1 -0
  139. package/dist/models/payment-config.model.d.ts +21 -0
  140. package/dist/models/payment-config.model.js +98 -0
  141. package/dist/models/payment-config.model.js.map +1 -0
  142. package/dist/models/payment-method-setup.model.d.ts +4 -0
  143. package/dist/models/payment-method-setup.model.js +32 -0
  144. package/dist/models/payment-method-setup.model.js.map +1 -0
  145. package/dist/models/payment-plan-installment.model.d.ts +12 -0
  146. package/dist/models/payment-plan-installment.model.js +57 -0
  147. package/dist/models/payment-plan-installment.model.js.map +1 -0
  148. package/dist/models/payment-plan.model.d.ts +25 -0
  149. package/dist/models/payment-plan.model.js +105 -0
  150. package/dist/models/payment-plan.model.js.map +1 -0
  151. package/dist/models/payment.model.d.ts +23 -0
  152. package/dist/models/payment.model.js +102 -0
  153. package/dist/models/payment.model.js.map +1 -0
  154. package/dist/models/recurring-invoice-line-item.model.d.ts +14 -0
  155. package/dist/models/recurring-invoice-line-item.model.js +72 -0
  156. package/dist/models/recurring-invoice-line-item.model.js.map +1 -0
  157. package/dist/models/recurring-invoice.model.d.ts +43 -0
  158. package/dist/models/recurring-invoice.model.js +157 -0
  159. package/dist/models/recurring-invoice.model.js.map +1 -0
  160. package/dist/models/refund.model.d.ts +15 -0
  161. package/dist/models/refund.model.js +73 -0
  162. package/dist/models/refund.model.js.map +1 -0
  163. package/dist/payments.module.d.ts +54 -0
  164. package/dist/payments.module.js +211 -0
  165. package/dist/payments.module.js.map +1 -0
  166. package/dist/register-payment-enums.d.ts +1 -0
  167. package/dist/register-payment-enums.js +18 -0
  168. package/dist/register-payment-enums.js.map +1 -0
  169. package/dist/services/customer.service.d.ts +15 -0
  170. package/dist/services/customer.service.js +63 -0
  171. package/dist/services/customer.service.js.map +1 -0
  172. package/dist/services/default-payment-email-templates.d.ts +8 -0
  173. package/dist/services/default-payment-email-templates.js +249 -0
  174. package/dist/services/default-payment-email-templates.js.map +1 -0
  175. package/dist/services/e-transfer.service.d.ts +35 -0
  176. package/dist/services/e-transfer.service.js +93 -0
  177. package/dist/services/e-transfer.service.js.map +1 -0
  178. package/dist/services/invoice-number.service.d.ts +9 -0
  179. package/dist/services/invoice-number.service.js +56 -0
  180. package/dist/services/invoice-number.service.js.map +1 -0
  181. package/dist/services/invoice.service.d.ts +66 -0
  182. package/dist/services/invoice.service.js +293 -0
  183. package/dist/services/invoice.service.js.map +1 -0
  184. package/dist/services/payment-config.service.d.ts +26 -0
  185. package/dist/services/payment-config.service.js +90 -0
  186. package/dist/services/payment-config.service.js.map +1 -0
  187. package/dist/services/payment-email.service.d.ts +20 -0
  188. package/dist/services/payment-email.service.js +153 -0
  189. package/dist/services/payment-email.service.js.map +1 -0
  190. package/dist/services/payment-plan.service.d.ts +47 -0
  191. package/dist/services/payment-plan.service.js +264 -0
  192. package/dist/services/payment-plan.service.js.map +1 -0
  193. package/dist/services/payment.service.d.ts +65 -0
  194. package/dist/services/payment.service.js +532 -0
  195. package/dist/services/payment.service.js.map +1 -0
  196. package/dist/services/recurring-interval.util.d.ts +3 -0
  197. package/dist/services/recurring-interval.util.js +43 -0
  198. package/dist/services/recurring-interval.util.js.map +1 -0
  199. package/dist/services/recurring-invoice.service.d.ts +88 -0
  200. package/dist/services/recurring-invoice.service.js +450 -0
  201. package/dist/services/recurring-invoice.service.js.map +1 -0
  202. package/dist/services/refund.service.d.ts +44 -0
  203. package/dist/services/refund.service.js +373 -0
  204. package/dist/services/refund.service.js.map +1 -0
  205. package/dist/services/static-branding-resolver.d.ts +6 -0
  206. package/dist/services/static-branding-resolver.js +13 -0
  207. package/dist/services/static-branding-resolver.js.map +1 -0
  208. package/dist/types/index.d.ts +240 -0
  209. package/dist/types/index.js +19 -0
  210. package/dist/types/index.js.map +1 -0
  211. package/dist/types/payment-customer.types.d.ts +15 -0
  212. package/dist/types/payment-customer.types.js +3 -0
  213. package/dist/types/payment-customer.types.js.map +1 -0
  214. package/dist/types/recurring-invoice.types.d.ts +84 -0
  215. package/dist/types/recurring-invoice.types.js +3 -0
  216. package/dist/types/recurring-invoice.types.js.map +1 -0
  217. package/package.json +70 -0
@@ -0,0 +1,532 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var PaymentService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.PaymentService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const core_1 = require("@nestjs/core");
19
+ const constants_1 = require("../constants");
20
+ const gateway_registry_service_1 = require("../gateways/gateway-registry.service");
21
+ const payment_email_service_1 = require("./payment-email.service");
22
+ const exceptions_1 = require("../exceptions");
23
+ const payment_plan_service_1 = require("./payment-plan.service");
24
+ const PAYABLE_STATUSES = new Set(['SENT', 'PARTIALLY_PAID', 'OVERDUE']);
25
+ let PaymentService = PaymentService_1 = class PaymentService {
26
+ constructor(invoiceRepo, paymentRepo, webhookIdempotencyRepo, transactionManager, gatewayRegistry, moduleRef) {
27
+ this.invoiceRepo = invoiceRepo;
28
+ this.paymentRepo = paymentRepo;
29
+ this.webhookIdempotencyRepo = webhookIdempotencyRepo;
30
+ this.transactionManager = transactionManager;
31
+ this.gatewayRegistry = gatewayRegistry;
32
+ this.moduleRef = moduleRef;
33
+ this.logger = new common_1.Logger(PaymentService_1.name);
34
+ this.paymentEventListener = null;
35
+ this.paymentEmailService = null;
36
+ this.paymentPlanService = null;
37
+ }
38
+ onModuleInit() {
39
+ try {
40
+ this.paymentEventListener = this.moduleRef.get(constants_1.PAYMENT_EVENT_LISTENER, {
41
+ strict: false,
42
+ });
43
+ this.logger.log('Payment event listener resolved successfully');
44
+ }
45
+ catch {
46
+ this.paymentEventListener = null;
47
+ this.logger.log('No payment event listener registered — booking auto-confirmation disabled');
48
+ }
49
+ try {
50
+ this.paymentEmailService = this.moduleRef.get(payment_email_service_1.PaymentEmailService, {
51
+ strict: false,
52
+ });
53
+ }
54
+ catch {
55
+ this.paymentEmailService = null;
56
+ }
57
+ try {
58
+ this.paymentPlanService = this.moduleRef.get(payment_plan_service_1.PaymentPlanService, {
59
+ strict: false,
60
+ });
61
+ }
62
+ catch {
63
+ this.paymentPlanService = null;
64
+ }
65
+ }
66
+ async recordManualPayment(input) {
67
+ const { payment, invoiceSnapshot } = await this.transactionManager.runInTransaction(async (repos) => {
68
+ const invoice = await repos.invoices.findByIdForUpdate(input.invoiceId);
69
+ if (!invoice) {
70
+ throw new exceptions_1.InvalidInvoiceStateException(`Invoice ${input.invoiceId} not found`);
71
+ }
72
+ this.validatePayable(invoice);
73
+ const isPendingETransfer = input.method === 'E_TRANSFER' && !!invoice.eTransferAnswer;
74
+ if (isPendingETransfer) {
75
+ const pendingAmount = await repos.payments.sumPendingConfirmationByInvoiceId(invoice.id);
76
+ const effectiveAmountDue = invoice.amountDue - pendingAmount;
77
+ if (input.amount > effectiveAmountDue) {
78
+ throw new exceptions_1.PaymentAmountExceededException(`Payment amount (${input.amount}) exceeds effective amount due (${effectiveAmountDue}) after accounting for pending payments.`);
79
+ }
80
+ }
81
+ else {
82
+ this.validateAmount(invoice, input.amount);
83
+ }
84
+ const status = isPendingETransfer
85
+ ? 'PENDING_CONFIRMATION'
86
+ : 'SUCCEEDED';
87
+ const created = await repos.payments.create({
88
+ invoiceId: input.invoiceId,
89
+ amount: input.amount,
90
+ currency: input.currency ?? invoice.currency,
91
+ method: input.method,
92
+ status,
93
+ referenceNumber: input.referenceNumber,
94
+ notes: input.notes,
95
+ processedAt: isPendingETransfer
96
+ ? undefined
97
+ : (input.processedAt ?? new Date()),
98
+ receivedBy: input.receivedBy,
99
+ createdBy: input.createdBy,
100
+ });
101
+ let snapshot = null;
102
+ if (!isPendingETransfer) {
103
+ const newStatus = await this.applyPaymentToInvoice(repos.invoices, invoice, input.amount);
104
+ snapshot =
105
+ newStatus === 'PAID'
106
+ ? {
107
+ invoiceId: invoice.id,
108
+ divisionId: invoice.divisionId,
109
+ referenceType: invoice.referenceType,
110
+ referenceId: invoice.referenceId,
111
+ metadata: null,
112
+ lineItems: [],
113
+ recurringInvoiceId: null,
114
+ }
115
+ : null;
116
+ }
117
+ return { payment: created, invoiceSnapshot: snapshot };
118
+ });
119
+ const enrichedSnapshot = await this.buildEnrichedPaidEvent(invoiceSnapshot);
120
+ if (enrichedSnapshot && this.paymentEventListener) {
121
+ try {
122
+ await this.paymentEventListener.onInvoicePaid(enrichedSnapshot);
123
+ }
124
+ catch (err) {
125
+ this.logger.warn(`Payment event listener failed for invoice ${enrichedSnapshot.invoiceId}: ${err instanceof Error ? err.message : String(err)}`);
126
+ }
127
+ }
128
+ if (payment.status === 'SUCCEEDED' && this.paymentEmailService) {
129
+ const inv = await this.invoiceRepo.findById(payment.invoiceId);
130
+ if (inv) {
131
+ await this.paymentEmailService.sendPaymentConfirmation(payment, inv);
132
+ }
133
+ }
134
+ return payment;
135
+ }
136
+ async createPendingPayment(input) {
137
+ try {
138
+ return await this.paymentRepo.create({
139
+ invoiceId: input.invoiceId,
140
+ amount: input.amount,
141
+ currency: input.currency,
142
+ method: input.method,
143
+ status: 'PENDING',
144
+ provider: input.provider,
145
+ providerPaymentId: input.providerPaymentId,
146
+ createdBy: input.createdBy,
147
+ });
148
+ }
149
+ catch (error) {
150
+ if (error instanceof exceptions_1.UniqueConstraintViolationException) {
151
+ this.logger.warn(`Duplicate pending payment for provider=${input.provider} ` +
152
+ `providerPaymentId=${input.providerPaymentId}. Returning existing.`);
153
+ const existing = await this.paymentRepo.findByProviderPaymentId(input.provider, input.providerPaymentId);
154
+ if (existing) {
155
+ return existing;
156
+ }
157
+ }
158
+ throw error;
159
+ }
160
+ }
161
+ async handlePaymentSucceeded(event) {
162
+ const alreadyProcessed = await this.webhookIdempotencyRepo.exists(event.eventId);
163
+ if (alreadyProcessed) {
164
+ this.logger.log(`Skipping already-processed webhook event: ${event.eventId}`);
165
+ return;
166
+ }
167
+ const result = await this.transactionManager.runInTransaction(async (repos) => {
168
+ let payment = await repos.payments.findByProviderPaymentId('stripe', event.providerPaymentId);
169
+ if (!payment) {
170
+ const invoiceId = event.providerData?.invoiceId;
171
+ if (!invoiceId) {
172
+ this.logger.error(`Payment succeeded webhook for unknown providerPaymentId=${event.providerPaymentId} ` +
173
+ `and no invoiceId in providerData. Skipping.`);
174
+ await repos.webhookIdempotency.record(event.eventId);
175
+ return { invoiceSnapshot: null };
176
+ }
177
+ payment = await repos.payments.create({
178
+ invoiceId,
179
+ amount: event.amount,
180
+ currency: event.currency,
181
+ method: 'CREDIT_CARD',
182
+ status: 'SUCCEEDED',
183
+ provider: 'stripe',
184
+ providerPaymentId: event.providerPaymentId,
185
+ providerData: event.providerData,
186
+ receiptUrl: event.receiptUrl,
187
+ processedAt: new Date(),
188
+ createdBy: 'system',
189
+ });
190
+ }
191
+ else {
192
+ const realPaymentIntentId = event.providerData?.paymentIntentId;
193
+ payment = await repos.payments.update(payment.id, {
194
+ status: 'SUCCEEDED',
195
+ ...(realPaymentIntentId && {
196
+ providerPaymentId: realPaymentIntentId,
197
+ }),
198
+ providerData: event.providerData,
199
+ receiptUrl: event.receiptUrl,
200
+ processedAt: new Date(),
201
+ });
202
+ }
203
+ let invoiceSnapshot = null;
204
+ const invoice = await repos.invoices.findByIdForUpdate(payment.invoiceId);
205
+ if (invoice && PAYABLE_STATUSES.has(invoice.status)) {
206
+ const newStatus = await this.applyPaymentToInvoice(repos.invoices, invoice, payment.amount);
207
+ if (newStatus === 'PAID') {
208
+ invoiceSnapshot = {
209
+ invoiceId: invoice.id,
210
+ divisionId: invoice.divisionId,
211
+ referenceType: invoice.referenceType,
212
+ referenceId: invoice.referenceId,
213
+ metadata: null,
214
+ lineItems: [],
215
+ recurringInvoiceId: null,
216
+ };
217
+ }
218
+ }
219
+ await repos.webhookIdempotency.record(event.eventId);
220
+ return { invoiceSnapshot, payment };
221
+ });
222
+ const enrichedSnapshot = await this.buildEnrichedPaidEvent(result.invoiceSnapshot);
223
+ if (enrichedSnapshot && this.paymentEventListener) {
224
+ try {
225
+ await this.paymentEventListener.onInvoicePaid(enrichedSnapshot);
226
+ }
227
+ catch (err) {
228
+ this.logger.warn(`Payment event listener failed for invoice ${enrichedSnapshot.invoiceId}: ${err instanceof Error ? err.message : String(err)}`);
229
+ }
230
+ }
231
+ if (result.payment && this.paymentEmailService) {
232
+ const inv = await this.invoiceRepo.findById(result.payment.invoiceId);
233
+ if (inv) {
234
+ await this.paymentEmailService.sendPaymentConfirmation(result.payment, inv);
235
+ }
236
+ }
237
+ }
238
+ async handlePaymentFailed(event) {
239
+ const alreadyProcessed = await this.webhookIdempotencyRepo.exists(event.eventId);
240
+ if (alreadyProcessed) {
241
+ this.logger.log(`Skipping already-processed webhook event: ${event.eventId}`);
242
+ return;
243
+ }
244
+ await this.transactionManager.runInTransaction(async (repos) => {
245
+ const payment = await repos.payments.findByProviderPaymentId('stripe', event.providerPaymentId);
246
+ if (payment &&
247
+ (payment.status === 'PENDING' || payment.status === 'PROCESSING')) {
248
+ await repos.payments.update(payment.id, {
249
+ status: 'FAILED',
250
+ providerData: event.providerData,
251
+ });
252
+ }
253
+ await repos.webhookIdempotency.record(event.eventId);
254
+ });
255
+ }
256
+ async handlePaymentProcessing(event) {
257
+ const alreadyProcessed = await this.webhookIdempotencyRepo.exists(event.eventId);
258
+ if (alreadyProcessed) {
259
+ this.logger.log(`Skipping already-processed webhook event: ${event.eventId}`);
260
+ return;
261
+ }
262
+ await this.transactionManager.runInTransaction(async (repos) => {
263
+ const payment = await repos.payments.findByProviderPaymentId('stripe', event.providerPaymentId);
264
+ if (payment && payment.status === 'PENDING') {
265
+ await repos.payments.update(payment.id, {
266
+ status: 'PROCESSING',
267
+ providerData: event.providerData,
268
+ });
269
+ }
270
+ await repos.webhookIdempotency.record(event.eventId);
271
+ });
272
+ }
273
+ async reconcilePayment(paymentId) {
274
+ const payment = await this.paymentRepo.findById(paymentId);
275
+ if (!payment) {
276
+ throw new exceptions_1.InvalidInvoiceStateException(`Payment ${paymentId} not found`);
277
+ }
278
+ if (!payment.provider || !payment.providerPaymentId) {
279
+ throw new exceptions_1.RefundNotAllowedException('Cannot reconcile manual payments — only online payments with a provider can be reconciled');
280
+ }
281
+ const gateway = this.gatewayRegistry.get(payment.provider);
282
+ const providerStatus = await gateway.getPaymentStatus(payment.providerPaymentId);
283
+ const statusMap = {
284
+ pending: 'PENDING',
285
+ processing: 'PROCESSING',
286
+ succeeded: 'SUCCEEDED',
287
+ failed: 'FAILED',
288
+ cancelled: 'CANCELLED',
289
+ };
290
+ const mappedStatus = statusMap[providerStatus.status] ?? payment.status;
291
+ if (mappedStatus === payment.status) {
292
+ this.logger.log(`Payment ${paymentId} is already in sync with provider (status=${payment.status})`);
293
+ return payment;
294
+ }
295
+ this.logger.log(`Reconciling payment ${paymentId}: local=${payment.status} provider=${mappedStatus}`);
296
+ if (mappedStatus === 'SUCCEEDED' &&
297
+ (payment.status === 'PENDING' || payment.status === 'PROCESSING')) {
298
+ const { updatedPayment, invoiceSnapshot } = await this.transactionManager.runInTransaction(async (repos) => {
299
+ const paymentIntentId = providerStatus.paymentIntentId;
300
+ const updated = await repos.payments.update(payment.id, {
301
+ status: 'SUCCEEDED',
302
+ ...(paymentIntentId && { providerPaymentId: paymentIntentId }),
303
+ needsReconciliation: false,
304
+ receiptUrl: providerStatus.receiptUrl ?? payment.receiptUrl,
305
+ processedAt: new Date(),
306
+ });
307
+ let snapshot = null;
308
+ const invoice = await repos.invoices.findByIdForUpdate(payment.invoiceId);
309
+ if (invoice && PAYABLE_STATUSES.has(invoice.status)) {
310
+ const newStatus = await this.applyPaymentToInvoice(repos.invoices, invoice, payment.amount);
311
+ if (newStatus === 'PAID') {
312
+ snapshot = {
313
+ invoiceId: invoice.id,
314
+ divisionId: invoice.divisionId,
315
+ referenceType: invoice.referenceType,
316
+ referenceId: invoice.referenceId,
317
+ metadata: null,
318
+ lineItems: [],
319
+ recurringInvoiceId: null,
320
+ };
321
+ }
322
+ }
323
+ return { updatedPayment: updated, invoiceSnapshot: snapshot };
324
+ });
325
+ const enrichedSnapshot = await this.buildEnrichedPaidEvent(invoiceSnapshot);
326
+ if (enrichedSnapshot && this.paymentEventListener) {
327
+ try {
328
+ await this.paymentEventListener.onInvoicePaid(enrichedSnapshot);
329
+ }
330
+ catch (err) {
331
+ this.logger.warn(`Payment event listener failed for invoice ${enrichedSnapshot.invoiceId}: ${err instanceof Error ? err.message : String(err)}`);
332
+ }
333
+ }
334
+ if (updatedPayment.status === 'SUCCEEDED' && this.paymentEmailService) {
335
+ const inv = await this.invoiceRepo.findById(updatedPayment.invoiceId);
336
+ if (inv) {
337
+ await this.paymentEmailService.sendPaymentConfirmation(updatedPayment, inv);
338
+ }
339
+ }
340
+ return updatedPayment;
341
+ }
342
+ const updated = await this.paymentRepo.update(payment.id, {
343
+ status: mappedStatus,
344
+ needsReconciliation: false,
345
+ receiptUrl: providerStatus.receiptUrl ?? payment.receiptUrl,
346
+ });
347
+ return updated;
348
+ }
349
+ async findStalePayments(statuses, olderThan) {
350
+ return this.paymentRepo.findStaleByStatuses(statuses, olderThan);
351
+ }
352
+ async confirmPayment(paymentId) {
353
+ const { payment, invoiceSnapshot } = await this.transactionManager.runInTransaction(async (repos) => {
354
+ const locked = await repos.payments.findByIdForUpdate(paymentId);
355
+ if (!locked) {
356
+ throw new exceptions_1.InvalidPaymentStateException('Payment not found');
357
+ }
358
+ if (locked.status !== 'PENDING_CONFIRMATION') {
359
+ throw new exceptions_1.InvalidPaymentStateException('Payment is not pending confirmation');
360
+ }
361
+ const updated = await repos.payments.update(locked.id, {
362
+ status: 'SUCCEEDED',
363
+ processedAt: new Date(),
364
+ });
365
+ const invoice = await repos.invoices.findByIdForUpdate(locked.invoiceId);
366
+ if (!invoice) {
367
+ throw new exceptions_1.InvalidInvoiceStateException(`Invoice ${locked.invoiceId} not found`);
368
+ }
369
+ const newStatus = await this.applyPaymentToInvoice(repos.invoices, invoice, locked.amount);
370
+ const snapshot = newStatus === 'PAID'
371
+ ? {
372
+ invoiceId: invoice.id,
373
+ divisionId: invoice.divisionId,
374
+ referenceType: invoice.referenceType,
375
+ referenceId: invoice.referenceId,
376
+ metadata: null,
377
+ lineItems: [],
378
+ recurringInvoiceId: null,
379
+ }
380
+ : null;
381
+ return { payment: updated, invoiceSnapshot: snapshot };
382
+ });
383
+ const enrichedSnapshot = await this.buildEnrichedPaidEvent(invoiceSnapshot);
384
+ if (enrichedSnapshot && this.paymentEventListener) {
385
+ try {
386
+ await this.paymentEventListener.onInvoicePaid(enrichedSnapshot);
387
+ }
388
+ catch (err) {
389
+ this.logger.warn(`Payment event listener failed for invoice ${enrichedSnapshot.invoiceId}: ${err instanceof Error ? err.message : String(err)}`);
390
+ }
391
+ }
392
+ if (this.paymentEmailService) {
393
+ const inv = await this.invoiceRepo.findById(payment.invoiceId);
394
+ if (inv) {
395
+ await this.paymentEmailService.sendPaymentConfirmation(payment, inv);
396
+ }
397
+ }
398
+ return payment;
399
+ }
400
+ async rejectPayment(paymentId, reason) {
401
+ return this.transactionManager.runInTransaction(async (repos) => {
402
+ const locked = await repos.payments.findByIdForUpdate(paymentId);
403
+ if (!locked) {
404
+ throw new exceptions_1.InvalidPaymentStateException('Payment not found');
405
+ }
406
+ if (locked.status !== 'PENDING_CONFIRMATION') {
407
+ throw new exceptions_1.InvalidPaymentStateException('Payment is not pending confirmation');
408
+ }
409
+ let updatedNotes = locked.notes;
410
+ if (reason) {
411
+ updatedNotes = locked.notes
412
+ ? `[Rejected: ${reason}] ${locked.notes}`
413
+ : `[Rejected: ${reason}]`;
414
+ }
415
+ return repos.payments.update(locked.id, {
416
+ status: 'REJECTED',
417
+ notes: updatedNotes,
418
+ });
419
+ });
420
+ }
421
+ async buildEnrichedPaidEvent(snapshot) {
422
+ if (!snapshot)
423
+ return null;
424
+ const invoice = await this.invoiceRepo.findByIdWithItems(snapshot.invoiceId);
425
+ if (!invoice)
426
+ return snapshot;
427
+ return {
428
+ ...snapshot,
429
+ metadata: invoice.metadata,
430
+ recurringInvoiceId: invoice.recurringInvoiceId ?? null,
431
+ lineItems: this.mapLineItemEvents(invoice.lineItems),
432
+ };
433
+ }
434
+ mapLineItemEvents(items) {
435
+ return items.map((item) => ({
436
+ id: item.id,
437
+ description: item.description,
438
+ quantity: item.quantity,
439
+ unitPrice: item.unitPrice,
440
+ isTaxable: item.isTaxable,
441
+ referenceType: item.referenceType,
442
+ referenceId: item.referenceId,
443
+ metadata: item.metadata,
444
+ }));
445
+ }
446
+ validatePayable(invoice) {
447
+ if (!PAYABLE_STATUSES.has(invoice.status)) {
448
+ throw new exceptions_1.InvoiceNotPayableException(`Cannot record payment for invoice in "${invoice.status}" status. ` +
449
+ `Invoice must be in one of: ${Array.from(PAYABLE_STATUSES).join(', ')}.`);
450
+ }
451
+ }
452
+ validateAmount(invoice, amount) {
453
+ if (amount > invoice.amountDue) {
454
+ throw new exceptions_1.PaymentAmountExceededException(`Payment amount (${amount}) exceeds invoice amount due (${invoice.amountDue}).`);
455
+ }
456
+ }
457
+ async applyPaymentToInvoice(invoiceRepo, invoice, amount) {
458
+ const newAmountPaid = invoice.amountPaid + amount;
459
+ const newAmountDue = invoice.total - newAmountPaid;
460
+ const newStatus = newAmountDue <= 0 ? 'PAID' : 'PARTIALLY_PAID';
461
+ await invoiceRepo.update(invoice.id, {
462
+ amountPaid: newAmountPaid,
463
+ amountDue: Math.max(newAmountDue, 0),
464
+ status: newStatus,
465
+ });
466
+ if (newStatus === 'PAID' && this.paymentPlanService) {
467
+ try {
468
+ await this.paymentPlanService.onInvoicePaid(invoice.id);
469
+ }
470
+ catch (error) {
471
+ this.logger.warn(`Failed to update installment status for invoice ${invoice.id}: ${error instanceof Error ? error.message : String(error)}`);
472
+ }
473
+ }
474
+ return newStatus;
475
+ }
476
+ async recordAutoChargePayment(input) {
477
+ const { payment, invoiceSnapshot } = await this.transactionManager.runInTransaction(async (repos) => {
478
+ const invoice = await repos.invoices.findByIdForUpdate(input.invoiceId);
479
+ if (!invoice) {
480
+ throw new exceptions_1.InvalidInvoiceStateException(`Invoice ${input.invoiceId} not found`);
481
+ }
482
+ this.validatePayable(invoice);
483
+ const created = await repos.payments.create({
484
+ invoiceId: input.invoiceId,
485
+ amount: input.amount,
486
+ currency: input.currency,
487
+ method: 'CREDIT_CARD',
488
+ status: 'SUCCEEDED',
489
+ provider: input.provider,
490
+ providerPaymentId: input.providerPaymentId,
491
+ receiptUrl: input.receiptUrl,
492
+ processedAt: new Date(),
493
+ createdBy: 'system',
494
+ notes: 'Auto-charged via saved payment method',
495
+ });
496
+ const newStatus = await this.applyPaymentToInvoice(repos.invoices, invoice, input.amount);
497
+ const snapshot = newStatus === 'PAID'
498
+ ? {
499
+ invoiceId: invoice.id,
500
+ divisionId: invoice.divisionId,
501
+ referenceType: invoice.referenceType,
502
+ referenceId: invoice.referenceId,
503
+ metadata: null,
504
+ lineItems: [],
505
+ recurringInvoiceId: invoice.recurringInvoiceId ?? null,
506
+ }
507
+ : null;
508
+ return { payment: created, invoiceSnapshot: snapshot };
509
+ });
510
+ const enrichedSnapshot = await this.buildEnrichedPaidEvent(invoiceSnapshot);
511
+ if (enrichedSnapshot && this.paymentEventListener) {
512
+ try {
513
+ await this.paymentEventListener.onInvoicePaid(enrichedSnapshot);
514
+ }
515
+ catch (err) {
516
+ this.logger.warn(`Payment event listener failed for auto-charge invoice ${enrichedSnapshot.invoiceId}: ${err instanceof Error ? err.message : String(err)}`);
517
+ }
518
+ }
519
+ return payment;
520
+ }
521
+ };
522
+ exports.PaymentService = PaymentService;
523
+ exports.PaymentService = PaymentService = PaymentService_1 = __decorate([
524
+ (0, common_1.Injectable)(),
525
+ __param(0, (0, common_1.Inject)(constants_1.INVOICE_REPOSITORY)),
526
+ __param(1, (0, common_1.Inject)(constants_1.PAYMENT_REPOSITORY)),
527
+ __param(2, (0, common_1.Inject)(constants_1.WEBHOOK_IDEMPOTENCY_REPOSITORY)),
528
+ __param(3, (0, common_1.Inject)(constants_1.TRANSACTION_MANAGER)),
529
+ __metadata("design:paramtypes", [Object, Object, Object, Object, gateway_registry_service_1.GatewayRegistryService,
530
+ core_1.ModuleRef])
531
+ ], PaymentService);
532
+ //# sourceMappingURL=payment.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment.service.js","sourceRoot":"","sources":["../../src/services/payment.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type IntervalUnit = 'DAYS' | 'MONTHS';
2
+ export declare function computeNextInvoiceDate(anchorDate: Date, intervalUnit: IntervalUnit, intervalValue: number, cycleCount: number): Date;
3
+ export declare function computeCycleCount(anchorDate: Date, currentNextInvoiceAt: Date, intervalUnit: IntervalUnit, intervalValue: number): number;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeNextInvoiceDate = computeNextInvoiceDate;
4
+ exports.computeCycleCount = computeCycleCount;
5
+ const MS_PER_DAY = 86_400_000;
6
+ function computeNextInvoiceDate(anchorDate, intervalUnit, intervalValue, cycleCount) {
7
+ if (cycleCount === 0) {
8
+ return new Date(anchorDate.getTime());
9
+ }
10
+ if (intervalUnit === 'DAYS') {
11
+ return new Date(anchorDate.getTime() + cycleCount * intervalValue * MS_PER_DAY);
12
+ }
13
+ const anchorDay = anchorDate.getUTCDate();
14
+ const totalMonths = cycleCount * intervalValue;
15
+ const anchorYear = anchorDate.getUTCFullYear();
16
+ const anchorMonth = anchorDate.getUTCMonth();
17
+ const targetMonth = anchorMonth + totalMonths;
18
+ const targetYear = anchorYear + Math.floor(targetMonth / 12);
19
+ const targetMonthNormalized = ((targetMonth % 12) + 12) % 12;
20
+ const lastDayOfTargetMonth = new Date(Date.UTC(targetYear, targetMonthNormalized + 1, 0)).getUTCDate();
21
+ const clampedDay = Math.min(anchorDay, lastDayOfTargetMonth);
22
+ return new Date(Date.UTC(targetYear, targetMonthNormalized, clampedDay, anchorDate.getUTCHours(), anchorDate.getUTCMinutes(), anchorDate.getUTCSeconds(), anchorDate.getUTCMilliseconds()));
23
+ }
24
+ function computeCycleCount(anchorDate, currentNextInvoiceAt, intervalUnit, intervalValue) {
25
+ if (intervalValue < 1) {
26
+ return 0;
27
+ }
28
+ const anchorTime = anchorDate.getTime();
29
+ const currentTime = currentNextInvoiceAt.getTime();
30
+ if (currentTime <= anchorTime) {
31
+ return 0;
32
+ }
33
+ if (intervalUnit === 'DAYS') {
34
+ return Math.round((currentTime - anchorTime) / (intervalValue * MS_PER_DAY));
35
+ }
36
+ const anchorYear = anchorDate.getUTCFullYear();
37
+ const anchorMonth = anchorDate.getUTCMonth();
38
+ const currentYear = currentNextInvoiceAt.getUTCFullYear();
39
+ const currentMonth = currentNextInvoiceAt.getUTCMonth();
40
+ const totalMonthDiff = (currentYear - anchorYear) * 12 + (currentMonth - anchorMonth);
41
+ return Math.round(totalMonthDiff / intervalValue);
42
+ }
43
+ //# sourceMappingURL=recurring-interval.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recurring-interval.util.js","sourceRoot":"","sources":["../../src/services/recurring-interval.util.ts"],"names":[],"mappings":";;AAyBA,wDA8CC;AAeD,8CAiCC;AA9GD,MAAM,UAAU,GAAG,UAAU,CAAC;AAgB9B,SAAgB,sBAAsB,CACpC,UAAgB,EAChB,YAA0B,EAC1B,aAAqB,EACrB,UAAkB;IAElB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,IAAI,IAAI,CACb,UAAU,CAAC,OAAO,EAAE,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAC/D,CAAC;IACJ,CAAC;IAID,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,UAAU,GAAG,aAAa,CAAC;IAE/C,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,EAAE,CAAC;IAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;IAC9C,MAAM,UAAU,GAAG,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;IAG7D,MAAM,oBAAoB,GAAG,IAAI,IAAI,CACnC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,qBAAqB,GAAG,CAAC,EAAE,CAAC,CAAC,CACnD,CAAC,UAAU,EAAE,CAAC;IAEf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IAE7D,OAAO,IAAI,IAAI,CACb,IAAI,CAAC,GAAG,CACN,UAAU,EACV,qBAAqB,EACrB,UAAU,EACV,UAAU,CAAC,WAAW,EAAE,EACxB,UAAU,CAAC,aAAa,EAAE,EAC1B,UAAU,CAAC,aAAa,EAAE,EAC1B,UAAU,CAAC,kBAAkB,EAAE,CAChC,CACF,CAAC;AACJ,CAAC;AAeD,SAAgB,iBAAiB,CAC/B,UAAgB,EAChB,oBAA0B,EAC1B,YAA0B,EAC1B,aAAqB;IAErB,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC;IAEnD,IAAI,WAAW,IAAI,UAAU,EAAE,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,KAAK,CACf,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,aAAa,GAAG,UAAU,CAAC,CAC1D,CAAC;IACJ,CAAC;IAGD,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,EAAE,CAAC;IAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAG,oBAAoB,CAAC,cAAc,EAAE,CAAC;IAC1D,MAAM,YAAY,GAAG,oBAAoB,CAAC,WAAW,EAAE,CAAC;IAExD,MAAM,cAAc,GAClB,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC;IAEjE,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,aAAa,CAAC,CAAC;AACpD,CAAC"}