@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.
- package/dist/constants.d.ts +17 -0
- package/dist/constants.js +21 -0
- package/dist/constants.js.map +1 -0
- package/dist/dto/create-installment.input.d.ts +5 -0
- package/dist/dto/create-installment.input.js +39 -0
- package/dist/dto/create-installment.input.js.map +1 -0
- package/dist/dto/create-invoice.input.d.ts +13 -0
- package/dist/dto/create-invoice.input.js +95 -0
- package/dist/dto/create-invoice.input.js.map +1 -0
- package/dist/dto/create-line-item.input.d.ts +10 -0
- package/dist/dto/create-line-item.input.js +77 -0
- package/dist/dto/create-line-item.input.js.map +1 -0
- package/dist/dto/create-payment-plan.input.d.ts +11 -0
- package/dist/dto/create-payment-plan.input.js +76 -0
- package/dist/dto/create-payment-plan.input.js.map +1 -0
- package/dist/dto/create-recurring-invoice.input.d.ts +18 -0
- package/dist/dto/create-recurring-invoice.input.js +117 -0
- package/dist/dto/create-recurring-invoice.input.js.map +1 -0
- package/dist/dto/create-recurring-line-item.input.d.ts +10 -0
- package/dist/dto/create-recurring-line-item.input.js +77 -0
- package/dist/dto/create-recurring-line-item.input.js.map +1 -0
- package/dist/dto/create-refund.input.d.ts +5 -0
- package/dist/dto/create-refund.input.js +43 -0
- package/dist/dto/create-refund.input.js.map +1 -0
- package/dist/dto/index.d.ts +8 -0
- package/dist/dto/index.js +20 -0
- package/dist/dto/index.js.map +1 -0
- package/dist/dto/invoice-filter.input.d.ts +10 -0
- package/dist/dto/invoice-filter.input.js +64 -0
- package/dist/dto/invoice-filter.input.js.map +1 -0
- package/dist/dto/payment-plan-filter.input.d.ts +7 -0
- package/dist/dto/payment-plan-filter.input.js +46 -0
- package/dist/dto/payment-plan-filter.input.js.map +1 -0
- package/dist/dto/record-manual-payment.input.d.ts +9 -0
- package/dist/dto/record-manual-payment.input.js +58 -0
- package/dist/dto/record-manual-payment.input.js.map +1 -0
- package/dist/dto/recurring-invoice-filter.input.d.ts +7 -0
- package/dist/dto/recurring-invoice-filter.input.js +46 -0
- package/dist/dto/recurring-invoice-filter.input.js.map +1 -0
- package/dist/dto/update-invoice-metadata.input.d.ts +3 -0
- package/dist/dto/update-invoice-metadata.input.js +30 -0
- package/dist/dto/update-invoice-metadata.input.js.map +1 -0
- package/dist/dto/update-payment-config.input.d.ts +8 -0
- package/dist/dto/update-payment-config.input.js +61 -0
- package/dist/dto/update-payment-config.input.js.map +1 -0
- package/dist/dto/update-recurring-template.input.d.ts +12 -0
- package/dist/dto/update-recurring-template.input.js +89 -0
- package/dist/dto/update-recurring-template.input.js.map +1 -0
- package/dist/dto/upsert-payment-provider.input.d.ts +5 -0
- package/dist/dto/upsert-payment-provider.input.js +43 -0
- package/dist/dto/upsert-payment-provider.input.js.map +1 -0
- package/dist/dto/validators/is-metadata.d.ts +1 -0
- package/dist/dto/validators/is-metadata.js +41 -0
- package/dist/dto/validators/is-metadata.js.map +1 -0
- package/dist/exceptions/index.d.ts +34 -0
- package/dist/exceptions/index.js +73 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/gateways/gateway-registry.service.d.ts +10 -0
- package/dist/gateways/gateway-registry.service.js +45 -0
- package/dist/gateways/gateway-registry.service.js.map +1 -0
- package/dist/gateways/payment-gateway.interface.d.ts +50 -0
- package/dist/gateways/payment-gateway.interface.js +3 -0
- package/dist/gateways/payment-gateway.interface.js.map +1 -0
- package/dist/gateways/recurring-payment-gateway.interface.d.ts +32 -0
- package/dist/gateways/recurring-payment-gateway.interface.js +3 -0
- package/dist/gateways/recurring-payment-gateway.interface.js.map +1 -0
- package/dist/gateways/stripe/stripe-webhook.controller.d.ts +24 -0
- package/dist/gateways/stripe/stripe-webhook.controller.js +150 -0
- package/dist/gateways/stripe/stripe-webhook.controller.js.map +1 -0
- package/dist/gateways/stripe/stripe.gateway.d.ts +84 -0
- package/dist/gateways/stripe/stripe.gateway.js +424 -0
- package/dist/gateways/stripe/stripe.gateway.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +147 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/invoice-repository.interface.d.ts +23 -0
- package/dist/interfaces/invoice-repository.interface.js +3 -0
- package/dist/interfaces/invoice-repository.interface.js.map +1 -0
- package/dist/interfaces/payment-config-repository.interface.d.ts +11 -0
- package/dist/interfaces/payment-config-repository.interface.js +3 -0
- package/dist/interfaces/payment-config-repository.interface.js.map +1 -0
- package/dist/interfaces/payment-customer-repository.interface.d.ts +6 -0
- package/dist/interfaces/payment-customer-repository.interface.js +3 -0
- package/dist/interfaces/payment-customer-repository.interface.js.map +1 -0
- package/dist/interfaces/payment-email.interfaces.d.ts +74 -0
- package/dist/interfaces/payment-email.interfaces.js +3 -0
- package/dist/interfaces/payment-email.interfaces.js.map +1 -0
- package/dist/interfaces/payment-event-listener.interface.d.ts +61 -0
- package/dist/interfaces/payment-event-listener.interface.js +3 -0
- package/dist/interfaces/payment-event-listener.interface.js.map +1 -0
- package/dist/interfaces/payment-plan-repository.interface.d.ts +16 -0
- package/dist/interfaces/payment-plan-repository.interface.js +3 -0
- package/dist/interfaces/payment-plan-repository.interface.js.map +1 -0
- package/dist/interfaces/payment-repository.interface.d.ts +13 -0
- package/dist/interfaces/payment-repository.interface.js +3 -0
- package/dist/interfaces/payment-repository.interface.js.map +1 -0
- package/dist/interfaces/recurring-invoice-repository.interface.d.ts +16 -0
- package/dist/interfaces/recurring-invoice-repository.interface.js +3 -0
- package/dist/interfaces/recurring-invoice-repository.interface.js.map +1 -0
- package/dist/interfaces/refund-repository.interface.d.ts +8 -0
- package/dist/interfaces/refund-repository.interface.js +3 -0
- package/dist/interfaces/refund-repository.interface.js.map +1 -0
- package/dist/interfaces/transaction-manager.interface.d.ts +19 -0
- package/dist/interfaces/transaction-manager.interface.js +3 -0
- package/dist/interfaces/transaction-manager.interface.js.map +1 -0
- package/dist/interfaces/webhook-idempotency-repository.interface.d.ts +5 -0
- package/dist/interfaces/webhook-idempotency-repository.interface.js +3 -0
- package/dist/interfaces/webhook-idempotency-repository.interface.js.map +1 -0
- package/dist/models/e-transfer-instructions.model.d.ts +11 -0
- package/dist/models/e-transfer-instructions.model.js +56 -0
- package/dist/models/e-transfer-instructions.model.js.map +1 -0
- package/dist/models/index.d.ts +13 -0
- package/dist/models/index.js +36 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/invoice-client.model.d.ts +5 -0
- package/dist/models/invoice-client.model.js +32 -0
- package/dist/models/invoice-client.model.js.map +1 -0
- package/dist/models/invoice-line-item.model.d.ts +14 -0
- package/dist/models/invoice-line-item.model.js +72 -0
- package/dist/models/invoice-line-item.model.js.map +1 -0
- package/dist/models/invoice.model.d.ts +86 -0
- package/dist/models/invoice.model.js +210 -0
- package/dist/models/invoice.model.js.map +1 -0
- package/dist/models/online-payment-session.model.d.ts +6 -0
- package/dist/models/online-payment-session.model.js +40 -0
- package/dist/models/online-payment-session.model.js.map +1 -0
- package/dist/models/paginated-invoices.model.d.ts +5 -0
- package/dist/models/paginated-invoices.model.js +19 -0
- package/dist/models/paginated-invoices.model.js.map +1 -0
- package/dist/models/paginated-payment-plans.model.d.ts +5 -0
- package/dist/models/paginated-payment-plans.model.js +19 -0
- package/dist/models/paginated-payment-plans.model.js.map +1 -0
- package/dist/models/paginated-recurring-invoices.model.d.ts +5 -0
- package/dist/models/paginated-recurring-invoices.model.js +19 -0
- package/dist/models/paginated-recurring-invoices.model.js.map +1 -0
- package/dist/models/paginated.model.d.ts +6 -0
- package/dist/models/paginated.model.js +30 -0
- package/dist/models/paginated.model.js.map +1 -0
- package/dist/models/payment-config.model.d.ts +21 -0
- package/dist/models/payment-config.model.js +98 -0
- package/dist/models/payment-config.model.js.map +1 -0
- package/dist/models/payment-method-setup.model.d.ts +4 -0
- package/dist/models/payment-method-setup.model.js +32 -0
- package/dist/models/payment-method-setup.model.js.map +1 -0
- package/dist/models/payment-plan-installment.model.d.ts +12 -0
- package/dist/models/payment-plan-installment.model.js +57 -0
- package/dist/models/payment-plan-installment.model.js.map +1 -0
- package/dist/models/payment-plan.model.d.ts +25 -0
- package/dist/models/payment-plan.model.js +105 -0
- package/dist/models/payment-plan.model.js.map +1 -0
- package/dist/models/payment.model.d.ts +23 -0
- package/dist/models/payment.model.js +102 -0
- package/dist/models/payment.model.js.map +1 -0
- package/dist/models/recurring-invoice-line-item.model.d.ts +14 -0
- package/dist/models/recurring-invoice-line-item.model.js +72 -0
- package/dist/models/recurring-invoice-line-item.model.js.map +1 -0
- package/dist/models/recurring-invoice.model.d.ts +43 -0
- package/dist/models/recurring-invoice.model.js +157 -0
- package/dist/models/recurring-invoice.model.js.map +1 -0
- package/dist/models/refund.model.d.ts +15 -0
- package/dist/models/refund.model.js +73 -0
- package/dist/models/refund.model.js.map +1 -0
- package/dist/payments.module.d.ts +54 -0
- package/dist/payments.module.js +211 -0
- package/dist/payments.module.js.map +1 -0
- package/dist/register-payment-enums.d.ts +1 -0
- package/dist/register-payment-enums.js +18 -0
- package/dist/register-payment-enums.js.map +1 -0
- package/dist/services/customer.service.d.ts +15 -0
- package/dist/services/customer.service.js +63 -0
- package/dist/services/customer.service.js.map +1 -0
- package/dist/services/default-payment-email-templates.d.ts +8 -0
- package/dist/services/default-payment-email-templates.js +249 -0
- package/dist/services/default-payment-email-templates.js.map +1 -0
- package/dist/services/e-transfer.service.d.ts +35 -0
- package/dist/services/e-transfer.service.js +93 -0
- package/dist/services/e-transfer.service.js.map +1 -0
- package/dist/services/invoice-number.service.d.ts +9 -0
- package/dist/services/invoice-number.service.js +56 -0
- package/dist/services/invoice-number.service.js.map +1 -0
- package/dist/services/invoice.service.d.ts +66 -0
- package/dist/services/invoice.service.js +293 -0
- package/dist/services/invoice.service.js.map +1 -0
- package/dist/services/payment-config.service.d.ts +26 -0
- package/dist/services/payment-config.service.js +90 -0
- package/dist/services/payment-config.service.js.map +1 -0
- package/dist/services/payment-email.service.d.ts +20 -0
- package/dist/services/payment-email.service.js +153 -0
- package/dist/services/payment-email.service.js.map +1 -0
- package/dist/services/payment-plan.service.d.ts +47 -0
- package/dist/services/payment-plan.service.js +264 -0
- package/dist/services/payment-plan.service.js.map +1 -0
- package/dist/services/payment.service.d.ts +65 -0
- package/dist/services/payment.service.js +532 -0
- package/dist/services/payment.service.js.map +1 -0
- package/dist/services/recurring-interval.util.d.ts +3 -0
- package/dist/services/recurring-interval.util.js +43 -0
- package/dist/services/recurring-interval.util.js.map +1 -0
- package/dist/services/recurring-invoice.service.d.ts +88 -0
- package/dist/services/recurring-invoice.service.js +450 -0
- package/dist/services/recurring-invoice.service.js.map +1 -0
- package/dist/services/refund.service.d.ts +44 -0
- package/dist/services/refund.service.js +373 -0
- package/dist/services/refund.service.js.map +1 -0
- package/dist/services/static-branding-resolver.d.ts +6 -0
- package/dist/services/static-branding-resolver.js +13 -0
- package/dist/services/static-branding-resolver.js.map +1 -0
- package/dist/types/index.d.ts +240 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/payment-customer.types.d.ts +15 -0
- package/dist/types/payment-customer.types.js +3 -0
- package/dist/types/payment-customer.types.js.map +1 -0
- package/dist/types/recurring-invoice.types.d.ts +84 -0
- package/dist/types/recurring-invoice.types.js +3 -0
- package/dist/types/recurring-invoice.types.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,63 @@
|
|
|
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 CustomerService_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.CustomerService = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const constants_1 = require("../constants");
|
|
19
|
+
const gateway_registry_service_1 = require("../gateways/gateway-registry.service");
|
|
20
|
+
let CustomerService = CustomerService_1 = class CustomerService {
|
|
21
|
+
constructor(customerRepo, gatewayRegistry) {
|
|
22
|
+
this.customerRepo = customerRepo;
|
|
23
|
+
this.gatewayRegistry = gatewayRegistry;
|
|
24
|
+
this.logger = new common_1.Logger(CustomerService_1.name);
|
|
25
|
+
}
|
|
26
|
+
async createOrLinkCustomer(divisionId, clientDetailsId, email, name, provider = 'stripe') {
|
|
27
|
+
const existing = await this.customerRepo.findByClientAndProvider(divisionId, clientDetailsId, provider);
|
|
28
|
+
if (existing)
|
|
29
|
+
return existing;
|
|
30
|
+
const gateway = this.gatewayRegistry.getRecurring(provider);
|
|
31
|
+
const { providerCustomerId } = await gateway.createOrRetrieveCustomer({
|
|
32
|
+
email,
|
|
33
|
+
name,
|
|
34
|
+
metadata: { divisionId, clientDetailsId },
|
|
35
|
+
});
|
|
36
|
+
return this.customerRepo.create({
|
|
37
|
+
divisionId,
|
|
38
|
+
clientDetailsId,
|
|
39
|
+
provider,
|
|
40
|
+
providerCustomerId,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async findCustomer(divisionId, clientDetailsId, provider = 'stripe') {
|
|
44
|
+
return this.customerRepo.findByClientAndProvider(divisionId, clientDetailsId, provider);
|
|
45
|
+
}
|
|
46
|
+
async createSetupSession(divisionId, clientDetailsId, email, name, successUrl, cancelUrl, provider = 'stripe') {
|
|
47
|
+
const customer = await this.createOrLinkCustomer(divisionId, clientDetailsId, email, name, provider);
|
|
48
|
+
const gateway = this.gatewayRegistry.getRecurring(provider);
|
|
49
|
+
return gateway.createSetupSession({
|
|
50
|
+
providerCustomerId: customer.providerCustomerId,
|
|
51
|
+
successUrl,
|
|
52
|
+
cancelUrl,
|
|
53
|
+
metadata: { divisionId, clientDetailsId },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
exports.CustomerService = CustomerService;
|
|
58
|
+
exports.CustomerService = CustomerService = CustomerService_1 = __decorate([
|
|
59
|
+
(0, common_1.Injectable)(),
|
|
60
|
+
__param(0, (0, common_1.Inject)(constants_1.PAYMENT_CUSTOMER_REPOSITORY)),
|
|
61
|
+
__metadata("design:paramtypes", [Object, gateway_registry_service_1.GatewayRegistryService])
|
|
62
|
+
], CustomerService);
|
|
63
|
+
//# sourceMappingURL=customer.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customer.service.js","sourceRoot":"","sources":["../../src/services/customer.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAE5D,4CAA2D;AAE3D,mFAA8E;AAGvE,IAAM,eAAe,uBAArB,MAAM,eAAe;IAG1B,YAEE,YAAyD,EACxC,eAAuC;QADvC,iBAAY,GAAZ,YAAY,CAA4B;QACxC,oBAAe,GAAf,eAAe,CAAwB;QALzC,WAAM,GAAG,IAAI,eAAM,CAAC,iBAAe,CAAC,IAAI,CAAC,CAAC;IAMxD,CAAC;IASJ,KAAK,CAAC,oBAAoB,CACxB,UAAkB,EAClB,eAAuB,EACvB,KAAa,EACb,IAAa,EACb,WAAmB,QAAQ;QAG3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAC9D,UAAU,EACV,eAAe,EACf,QAAQ,CACT,CAAC;QACF,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAG9B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAG5D,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,OAAO,CAAC,wBAAwB,CAAC;YACpE,KAAK;YACL,IAAI;YACJ,QAAQ,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE;SAC1C,CAAC,CAAC;QAGH,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAC9B,UAAU;YACV,eAAe;YACf,QAAQ;YACR,kBAAkB;SACnB,CAAC,CAAC;IACL,CAAC;IAKD,KAAK,CAAC,YAAY,CAChB,UAAkB,EAClB,eAAuB,EACvB,WAAmB,QAAQ;QAE3B,OAAO,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAC9C,UAAU,EACV,eAAe,EACf,QAAQ,CACT,CAAC;IACJ,CAAC;IAQD,KAAK,CAAC,kBAAkB,CACtB,UAAkB,EAClB,eAAuB,EACvB,KAAa,EACb,IAAwB,EACxB,UAAkB,EAClB,SAAiB,EACjB,WAAmB,QAAQ;QAG3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAC9C,UAAU,EACV,eAAe,EACf,KAAK,EACL,IAAI,EACJ,QAAQ,CACT,CAAC;QAGF,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC5D,OAAO,OAAO,CAAC,kBAAkB,CAAC;YAChC,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB;YAC/C,UAAU;YACV,SAAS;YACT,QAAQ,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE;SAC1C,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAlGY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,eAAM,EAAC,uCAA2B,CAAC,CAAA;6CAEF,iDAAsB;GAN/C,eAAe,CAkG3B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IPaymentEmailTemplateRenderer, RenderedPaymentEmail, InvoiceEmailParams, ETransferEmailParams, PaymentConfirmationEmailParams, OverdueReminderEmailParams, RefundConfirmationEmailParams } from '../interfaces/payment-email.interfaces';
|
|
2
|
+
export declare class DefaultPaymentEmailTemplateRenderer implements IPaymentEmailTemplateRenderer {
|
|
3
|
+
renderInvoiceNotification(params: InvoiceEmailParams): RenderedPaymentEmail;
|
|
4
|
+
renderETransferInstructions(params: ETransferEmailParams): RenderedPaymentEmail;
|
|
5
|
+
renderPaymentConfirmation(params: PaymentConfirmationEmailParams): RenderedPaymentEmail;
|
|
6
|
+
renderOverdueReminder(params: OverdueReminderEmailParams): RenderedPaymentEmail;
|
|
7
|
+
renderRefundConfirmation(params: RefundConfirmationEmailParams): RenderedPaymentEmail;
|
|
8
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultPaymentEmailTemplateRenderer = void 0;
|
|
4
|
+
function escapeHtml(str) {
|
|
5
|
+
return str
|
|
6
|
+
.replace(/&/g, '&')
|
|
7
|
+
.replace(/</g, '<')
|
|
8
|
+
.replace(/>/g, '>')
|
|
9
|
+
.replace(/"/g, '"');
|
|
10
|
+
}
|
|
11
|
+
function formatAmount(amountCents, currency, locale) {
|
|
12
|
+
return new Intl.NumberFormat(locale ?? 'en-CA', {
|
|
13
|
+
style: 'currency',
|
|
14
|
+
currency,
|
|
15
|
+
}).format(amountCents / 100);
|
|
16
|
+
}
|
|
17
|
+
function formatDate(date, locale) {
|
|
18
|
+
return date.toLocaleDateString(locale ?? 'en-CA', {
|
|
19
|
+
year: 'numeric',
|
|
20
|
+
month: 'long',
|
|
21
|
+
day: 'numeric',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function formatPaymentMethod(method) {
|
|
25
|
+
const labels = {
|
|
26
|
+
CREDIT_CARD: 'Credit Card',
|
|
27
|
+
DEBIT: 'Debit',
|
|
28
|
+
E_TRANSFER: 'e-Transfer',
|
|
29
|
+
BANK_TRANSFER: 'Bank Transfer',
|
|
30
|
+
CHEQUE: 'Cheque',
|
|
31
|
+
CASH: 'Cash',
|
|
32
|
+
OTHER: 'Other',
|
|
33
|
+
};
|
|
34
|
+
return labels[method] ?? method;
|
|
35
|
+
}
|
|
36
|
+
function wrapEmail(headerColor, headerTitle, bodyHtml, branding) {
|
|
37
|
+
const footer = branding.companyName
|
|
38
|
+
? `${escapeHtml(branding.companyName)}${branding.supportEmail ? ` | ${escapeHtml(branding.supportEmail)}` : ''}`
|
|
39
|
+
: 'This is an automated message. Please do not reply directly to this email.';
|
|
40
|
+
return `
|
|
41
|
+
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 600px; margin: 0 auto; color: #333;">
|
|
42
|
+
<div style="background: ${headerColor}; color: white; padding: 24px; text-align: center;">
|
|
43
|
+
<h1 style="margin: 0; font-size: 24px;">${headerTitle}</h1>
|
|
44
|
+
</div>
|
|
45
|
+
<div style="padding: 24px; background: #fff;">
|
|
46
|
+
${bodyHtml}
|
|
47
|
+
</div>
|
|
48
|
+
<div style="padding: 16px 24px; background: #f8f9fa; text-align: center; font-size: 12px; color: #6b7280;">
|
|
49
|
+
<p style="margin: 0;">${footer}</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>`;
|
|
52
|
+
}
|
|
53
|
+
function summaryTable(rows, bgColor, accentColor, borderColor) {
|
|
54
|
+
const border = borderColor ? `border: 1px solid ${borderColor};` : '';
|
|
55
|
+
const tableRows = rows
|
|
56
|
+
.map((row) => `<tr>
|
|
57
|
+
<td style="padding: 4px 0;"><strong>${row.label}</strong></td>
|
|
58
|
+
<td style="text-align: right;${row.highlight ? ` font-size: 18px; font-weight: bold; color: ${accentColor};` : ''}">${row.value}</td>
|
|
59
|
+
</tr>`)
|
|
60
|
+
.join('');
|
|
61
|
+
return `
|
|
62
|
+
<div style="background: ${bgColor}; border-radius: 8px; padding: 16px; margin: 20px 0; ${border}">
|
|
63
|
+
<table style="width: 100%;">
|
|
64
|
+
${tableRows}
|
|
65
|
+
</table>
|
|
66
|
+
</div>`;
|
|
67
|
+
}
|
|
68
|
+
class DefaultPaymentEmailTemplateRenderer {
|
|
69
|
+
renderInvoiceNotification(params) {
|
|
70
|
+
const { invoice, clientName, branding } = params;
|
|
71
|
+
const locale = branding.locale;
|
|
72
|
+
const amount = formatAmount(invoice.total, invoice.currency, locale);
|
|
73
|
+
const dueDate = invoice.dueAt
|
|
74
|
+
? formatDate(invoice.dueAt, locale)
|
|
75
|
+
: 'Upon receipt';
|
|
76
|
+
let lineItemsHtml = '';
|
|
77
|
+
if (invoice.lineItems && invoice.lineItems.length > 0) {
|
|
78
|
+
const rows = invoice.lineItems
|
|
79
|
+
.map((item) => `<tr>
|
|
80
|
+
<td style="padding: 8px 12px; border-bottom: 1px solid #eee;">${escapeHtml(item.description)}</td>
|
|
81
|
+
<td style="padding: 8px 12px; border-bottom: 1px solid #eee; text-align: center;">${item.quantity}</td>
|
|
82
|
+
<td style="padding: 8px 12px; border-bottom: 1px solid #eee; text-align: right;">${formatAmount(item.unitPrice, invoice.currency, locale)}</td>
|
|
83
|
+
<td style="padding: 8px 12px; border-bottom: 1px solid #eee; text-align: right;">${formatAmount(item.quantity * item.unitPrice, invoice.currency, locale)}</td>
|
|
84
|
+
</tr>`)
|
|
85
|
+
.join('');
|
|
86
|
+
lineItemsHtml = `
|
|
87
|
+
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
|
|
88
|
+
<thead>
|
|
89
|
+
<tr style="background: #f8f9fa;">
|
|
90
|
+
<th style="padding: 8px 12px; text-align: left; border-bottom: 2px solid #dee2e6;">Description</th>
|
|
91
|
+
<th style="padding: 8px 12px; text-align: center; border-bottom: 2px solid #dee2e6;">Qty</th>
|
|
92
|
+
<th style="padding: 8px 12px; text-align: right; border-bottom: 2px solid #dee2e6;">Unit Price</th>
|
|
93
|
+
<th style="padding: 8px 12px; text-align: right; border-bottom: 2px solid #dee2e6;">Amount</th>
|
|
94
|
+
</tr>
|
|
95
|
+
</thead>
|
|
96
|
+
<tbody>${rows}</tbody>
|
|
97
|
+
</table>`;
|
|
98
|
+
}
|
|
99
|
+
const clientNoteHtml = invoice.clientNotes
|
|
100
|
+
? `<div style="background: #fffbeb; border-left: 4px solid #f59e0b; padding: 12px 16px; margin: 20px 0;"><strong>Note:</strong> ${escapeHtml(invoice.clientNotes)}</div>`
|
|
101
|
+
: '';
|
|
102
|
+
const body = `
|
|
103
|
+
<p>Hello ${escapeHtml(clientName)},</p>
|
|
104
|
+
<p>A new invoice has been issued for your account.</p>
|
|
105
|
+
${summaryTable([
|
|
106
|
+
{
|
|
107
|
+
label: 'Invoice Number:',
|
|
108
|
+
value: escapeHtml(invoice.invoiceNumber),
|
|
109
|
+
},
|
|
110
|
+
{ label: 'Amount Due:', value: amount, highlight: true },
|
|
111
|
+
{ label: 'Due Date:', value: dueDate },
|
|
112
|
+
], '#f8f9fa', branding.primaryColor)}
|
|
113
|
+
${lineItemsHtml}
|
|
114
|
+
${clientNoteHtml}
|
|
115
|
+
<p style="margin-top: 24px;">You can view and pay this invoice by logging into your account.</p>`;
|
|
116
|
+
return {
|
|
117
|
+
subject: `Invoice ${invoice.invoiceNumber} — ${amount}`,
|
|
118
|
+
html: wrapEmail(branding.primaryColor, `Invoice ${escapeHtml(invoice.invoiceNumber)}`, body, branding),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
renderETransferInstructions(params) {
|
|
122
|
+
const { invoice, instructions, clientName, branding } = params;
|
|
123
|
+
const locale = branding.locale;
|
|
124
|
+
const amount = formatAmount(invoice.total, invoice.currency, locale);
|
|
125
|
+
const securityHtml = instructions.securityAnswer
|
|
126
|
+
? `
|
|
127
|
+
<tr>
|
|
128
|
+
<td style="padding: 4px 0;"><strong>Security Question:</strong></td>
|
|
129
|
+
<td style="text-align: right;">${escapeHtml(instructions.securityQuestion ?? 'What is the payment code?')}</td>
|
|
130
|
+
</tr>
|
|
131
|
+
<tr>
|
|
132
|
+
<td style="padding: 4px 0;"><strong>Security Answer:</strong></td>
|
|
133
|
+
<td style="text-align: right; font-weight: bold;">${escapeHtml(instructions.securityAnswer)}</td>
|
|
134
|
+
</tr>`
|
|
135
|
+
: `
|
|
136
|
+
<tr>
|
|
137
|
+
<td colspan="2" style="padding: 4px 0; font-style: italic; color: #6b7280;">Auto-deposit is enabled — no security answer required.</td>
|
|
138
|
+
</tr>`;
|
|
139
|
+
const body = `
|
|
140
|
+
<p>Hello ${escapeHtml(clientName)},</p>
|
|
141
|
+
<p>To pay invoice <strong>${escapeHtml(invoice.invoiceNumber)}</strong>, please send an Interac e-Transfer using the details below.</p>
|
|
142
|
+
|
|
143
|
+
<div style="background: #f0fdfa; border-radius: 8px; padding: 16px; margin: 20px 0; border: 1px solid #99f6e4;">
|
|
144
|
+
<table style="width: 100%;">
|
|
145
|
+
<tr>
|
|
146
|
+
<td style="padding: 4px 0;"><strong>Amount:</strong></td>
|
|
147
|
+
<td style="text-align: right; font-size: 18px; font-weight: bold; color: #0d9488;">${amount}</td>
|
|
148
|
+
</tr>
|
|
149
|
+
<tr>
|
|
150
|
+
<td style="padding: 4px 0;"><strong>Recipient Email:</strong></td>
|
|
151
|
+
<td style="text-align: right;">${escapeHtml(instructions.eTransferEmail)}</td>
|
|
152
|
+
</tr>
|
|
153
|
+
<tr>
|
|
154
|
+
<td style="padding: 4px 0;"><strong>Recipient Name:</strong></td>
|
|
155
|
+
<td style="text-align: right;">${escapeHtml(instructions.eTransferRecipient)}</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td style="padding: 4px 0;"><strong>Reference Code:</strong></td>
|
|
159
|
+
<td style="text-align: right; font-family: monospace; font-weight: bold;">${escapeHtml(instructions.eTransferCode)}</td>
|
|
160
|
+
</tr>
|
|
161
|
+
${securityHtml}
|
|
162
|
+
</table>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<p><strong>Important:</strong> Please include the reference code <strong>${escapeHtml(instructions.eTransferCode)}</strong> in the message field of your e-Transfer so we can match your payment to this invoice.</p>`;
|
|
166
|
+
return {
|
|
167
|
+
subject: `e-Transfer Instructions — Invoice ${invoice.invoiceNumber}`,
|
|
168
|
+
html: wrapEmail('#0d9488', 'e-Transfer Instructions', body, branding),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
renderPaymentConfirmation(params) {
|
|
172
|
+
const { payment, invoice, clientName, branding } = params;
|
|
173
|
+
const locale = branding.locale;
|
|
174
|
+
const paymentAmount = formatAmount(payment.amount, payment.currency, locale);
|
|
175
|
+
const remainingBalance = formatAmount(Math.max(invoice.amountDue - payment.amount, 0), invoice.currency, locale);
|
|
176
|
+
const paymentDate = formatDate(payment.processedAt ?? payment.createdAt, locale);
|
|
177
|
+
const receiptHtml = payment.receiptUrl
|
|
178
|
+
? `<p style="text-align: center; margin-top: 20px;"><a href="${escapeHtml(payment.receiptUrl)}" style="background: ${branding.primaryColor}; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block;">View Receipt</a></p>`
|
|
179
|
+
: '';
|
|
180
|
+
const body = `
|
|
181
|
+
<p>Hello ${escapeHtml(clientName)},</p>
|
|
182
|
+
<p>We have received your payment. Thank you!</p>
|
|
183
|
+
${summaryTable([
|
|
184
|
+
{ label: 'Invoice:', value: escapeHtml(invoice.invoiceNumber) },
|
|
185
|
+
{ label: 'Payment Amount:', value: paymentAmount, highlight: true },
|
|
186
|
+
{ label: 'Payment Date:', value: paymentDate },
|
|
187
|
+
{ label: 'Method:', value: formatPaymentMethod(payment.method) },
|
|
188
|
+
{ label: 'Remaining Balance:', value: remainingBalance },
|
|
189
|
+
], '#f0fdf4', '#059669')}
|
|
190
|
+
${receiptHtml}`;
|
|
191
|
+
return {
|
|
192
|
+
subject: `Payment Received — Invoice ${invoice.invoiceNumber}`,
|
|
193
|
+
html: wrapEmail('#059669', 'Payment Received', body, branding),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
renderOverdueReminder(params) {
|
|
197
|
+
const { invoice, clientName, branding } = params;
|
|
198
|
+
const locale = branding.locale;
|
|
199
|
+
const amount = formatAmount(invoice.amountDue, invoice.currency, locale);
|
|
200
|
+
const dueDate = invoice.dueAt ? formatDate(invoice.dueAt, locale) : 'N/A';
|
|
201
|
+
const body = `
|
|
202
|
+
<p>Hello ${escapeHtml(clientName)},</p>
|
|
203
|
+
<p>This is a reminder that the following invoice is now past due. Please arrange payment at your earliest convenience.</p>
|
|
204
|
+
${summaryTable([
|
|
205
|
+
{
|
|
206
|
+
label: 'Invoice Number:',
|
|
207
|
+
value: escapeHtml(invoice.invoiceNumber),
|
|
208
|
+
},
|
|
209
|
+
{ label: 'Amount Due:', value: amount, highlight: true },
|
|
210
|
+
{ label: 'Original Due Date:', value: dueDate },
|
|
211
|
+
], '#fef2f2', '#dc2626', '#fecaca')}
|
|
212
|
+
<p>You can view and pay this invoice by logging into your account.</p>
|
|
213
|
+
<p>If you have already made this payment, please disregard this notice.</p>`;
|
|
214
|
+
return {
|
|
215
|
+
subject: `Payment Overdue — Invoice ${invoice.invoiceNumber}`,
|
|
216
|
+
html: wrapEmail('#dc2626', 'Payment Overdue', body, branding),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
renderRefundConfirmation(params) {
|
|
220
|
+
const { refund, payment, invoice, clientName, branding } = params;
|
|
221
|
+
const locale = branding.locale;
|
|
222
|
+
const refundAmount = formatAmount(refund.amount, refund.currency, locale);
|
|
223
|
+
const originalPayment = formatAmount(payment.amount, payment.currency, locale);
|
|
224
|
+
const refundDate = formatDate(refund.createdAt, locale);
|
|
225
|
+
const body = `
|
|
226
|
+
<p>Hello ${escapeHtml(clientName)},</p>
|
|
227
|
+
<p>A refund has been processed for your account.</p>
|
|
228
|
+
${summaryTable([
|
|
229
|
+
{ label: 'Invoice:', value: escapeHtml(invoice.invoiceNumber) },
|
|
230
|
+
{ label: 'Refund Amount:', value: refundAmount, highlight: true },
|
|
231
|
+
{ label: 'Original Payment:', value: originalPayment },
|
|
232
|
+
{
|
|
233
|
+
label: 'Payment Method:',
|
|
234
|
+
value: formatPaymentMethod(payment.method),
|
|
235
|
+
},
|
|
236
|
+
{ label: 'Refund Date:', value: refundDate },
|
|
237
|
+
...(refund.reason
|
|
238
|
+
? [{ label: 'Reason:', value: escapeHtml(refund.reason) }]
|
|
239
|
+
: []),
|
|
240
|
+
], '#fffbeb', '#d97706', '#fde68a')}
|
|
241
|
+
<p>The refund may take several business days to appear on your statement, depending on your payment provider.</p>`;
|
|
242
|
+
return {
|
|
243
|
+
subject: `Refund Processed — Invoice ${invoice.invoiceNumber}`,
|
|
244
|
+
html: wrapEmail('#d97706', 'Refund Processed', body, branding),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.DefaultPaymentEmailTemplateRenderer = DefaultPaymentEmailTemplateRenderer;
|
|
249
|
+
//# sourceMappingURL=default-payment-email-templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-payment-email-templates.js","sourceRoot":"","sources":["../../src/services/default-payment-email-templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IInvoiceRepository } from '../interfaces/invoice-repository.interface';
|
|
2
|
+
export interface ETransferInstructions {
|
|
3
|
+
invoiceNumber: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
currency: string;
|
|
6
|
+
eTransferCode: string;
|
|
7
|
+
eTransferEmail: string;
|
|
8
|
+
eTransferRecipient: string;
|
|
9
|
+
securityQuestion?: string;
|
|
10
|
+
securityAnswer?: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ETransferService {
|
|
14
|
+
private readonly invoiceRepo;
|
|
15
|
+
private readonly codePrefix;
|
|
16
|
+
private readonly logger;
|
|
17
|
+
private static readonly MAX_RETRIES;
|
|
18
|
+
private static readonly CODE_LENGTH;
|
|
19
|
+
constructor(invoiceRepo: IInvoiceRepository, codePrefix: string);
|
|
20
|
+
generateAnswer(): string;
|
|
21
|
+
generateCode(): string;
|
|
22
|
+
assignCode(invoiceId: string, autoDeposit: boolean): Promise<{
|
|
23
|
+
code: string;
|
|
24
|
+
answer: string | null;
|
|
25
|
+
}>;
|
|
26
|
+
getInstructions(params: {
|
|
27
|
+
invoiceNumber: string;
|
|
28
|
+
amount: number;
|
|
29
|
+
currency: string;
|
|
30
|
+
eTransferCode: string;
|
|
31
|
+
eTransferEmail: string;
|
|
32
|
+
eTransferRecipient: string;
|
|
33
|
+
eTransferAnswer?: string | null;
|
|
34
|
+
}): ETransferInstructions;
|
|
35
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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 ETransferService_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.ETransferService = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
const constants_1 = require("../constants");
|
|
20
|
+
const exceptions_1 = require("../exceptions");
|
|
21
|
+
const CODE_CHARSET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
22
|
+
let ETransferService = ETransferService_1 = class ETransferService {
|
|
23
|
+
constructor(invoiceRepo, codePrefix) {
|
|
24
|
+
this.invoiceRepo = invoiceRepo;
|
|
25
|
+
this.codePrefix = codePrefix;
|
|
26
|
+
this.logger = new common_1.Logger(ETransferService_1.name);
|
|
27
|
+
}
|
|
28
|
+
generateAnswer() {
|
|
29
|
+
return String((0, crypto_1.randomInt)(1000, 10000));
|
|
30
|
+
}
|
|
31
|
+
generateCode() {
|
|
32
|
+
let code = '';
|
|
33
|
+
for (let i = 0; i < ETransferService_1.CODE_LENGTH; i++) {
|
|
34
|
+
code += CODE_CHARSET[(0, crypto_1.randomInt)(CODE_CHARSET.length)];
|
|
35
|
+
}
|
|
36
|
+
const prefix = this.codePrefix ? `${this.codePrefix}-` : '';
|
|
37
|
+
return `${prefix}${code.slice(0, 4)}-${code.slice(4)}`;
|
|
38
|
+
}
|
|
39
|
+
async assignCode(invoiceId, autoDeposit) {
|
|
40
|
+
for (let attempt = 0; attempt < ETransferService_1.MAX_RETRIES; attempt++) {
|
|
41
|
+
const code = this.generateCode();
|
|
42
|
+
const answer = autoDeposit ? null : this.generateAnswer();
|
|
43
|
+
try {
|
|
44
|
+
await this.invoiceRepo.update(invoiceId, {
|
|
45
|
+
eTransferCode: code,
|
|
46
|
+
eTransferAnswer: answer,
|
|
47
|
+
});
|
|
48
|
+
return { code, answer };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error instanceof exceptions_1.UniqueConstraintViolationException) {
|
|
52
|
+
this.logger.warn(`E-transfer code collision on attempt ${attempt + 1}: ${code}`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Failed to assign a unique e-transfer code after ${ETransferService_1.MAX_RETRIES} attempts`);
|
|
59
|
+
}
|
|
60
|
+
getInstructions(params) {
|
|
61
|
+
const formattedAmount = (params.amount / 100).toFixed(2);
|
|
62
|
+
let message = `Send an Interac e-Transfer for $${formattedAmount} ${params.currency} ` +
|
|
63
|
+
`to ${params.eTransferEmail} (${params.eTransferRecipient}). ` +
|
|
64
|
+
`In the message field, enter: ${params.eTransferCode}`;
|
|
65
|
+
const instructions = {
|
|
66
|
+
invoiceNumber: params.invoiceNumber,
|
|
67
|
+
amount: params.amount,
|
|
68
|
+
currency: params.currency,
|
|
69
|
+
eTransferCode: params.eTransferCode,
|
|
70
|
+
eTransferEmail: params.eTransferEmail,
|
|
71
|
+
eTransferRecipient: params.eTransferRecipient,
|
|
72
|
+
message: '',
|
|
73
|
+
};
|
|
74
|
+
if (params.eTransferAnswer) {
|
|
75
|
+
const question = 'What is the secure code?';
|
|
76
|
+
message += ` Use security question '${question}' with answer '${params.eTransferAnswer}'.`;
|
|
77
|
+
instructions.securityQuestion = question;
|
|
78
|
+
instructions.securityAnswer = params.eTransferAnswer;
|
|
79
|
+
}
|
|
80
|
+
instructions.message = message;
|
|
81
|
+
return instructions;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
exports.ETransferService = ETransferService;
|
|
85
|
+
ETransferService.MAX_RETRIES = 5;
|
|
86
|
+
ETransferService.CODE_LENGTH = 8;
|
|
87
|
+
exports.ETransferService = ETransferService = ETransferService_1 = __decorate([
|
|
88
|
+
(0, common_1.Injectable)(),
|
|
89
|
+
__param(0, (0, common_1.Inject)(constants_1.INVOICE_REPOSITORY)),
|
|
90
|
+
__param(1, (0, common_1.Inject)(constants_1.E_TRANSFER_CODE_PREFIX)),
|
|
91
|
+
__metadata("design:paramtypes", [Object, String])
|
|
92
|
+
], ETransferService);
|
|
93
|
+
//# sourceMappingURL=e-transfer.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e-transfer.service.js","sourceRoot":"","sources":["../../src/services/e-transfer.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IInvoiceRepository } from '../interfaces/invoice-repository.interface';
|
|
2
|
+
export declare class InvoiceNumberService {
|
|
3
|
+
private readonly invoiceRepo;
|
|
4
|
+
private readonly logger;
|
|
5
|
+
private static readonly MAX_RETRIES;
|
|
6
|
+
constructor(invoiceRepo: IInvoiceRepository);
|
|
7
|
+
generate(_divisionId: string): Promise<string>;
|
|
8
|
+
private getNextSequence;
|
|
9
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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 InvoiceNumberService_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.InvoiceNumberService = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const constants_1 = require("../constants");
|
|
19
|
+
const exceptions_1 = require("../exceptions");
|
|
20
|
+
let InvoiceNumberService = InvoiceNumberService_1 = class InvoiceNumberService {
|
|
21
|
+
constructor(invoiceRepo) {
|
|
22
|
+
this.invoiceRepo = invoiceRepo;
|
|
23
|
+
this.logger = new common_1.Logger(InvoiceNumberService_1.name);
|
|
24
|
+
}
|
|
25
|
+
async generate(_divisionId) {
|
|
26
|
+
const year = new Date().getFullYear();
|
|
27
|
+
const prefix = `INV-${year}-`;
|
|
28
|
+
for (let attempt = 0; attempt < InvoiceNumberService_1.MAX_RETRIES; attempt++) {
|
|
29
|
+
const nextSequence = await this.getNextSequence(prefix);
|
|
30
|
+
const invoiceNumber = `${prefix}${String(nextSequence).padStart(5, '0')}`;
|
|
31
|
+
return invoiceNumber;
|
|
32
|
+
}
|
|
33
|
+
throw new exceptions_1.InvoiceNumberExhaustedException(`Failed to generate a unique invoice number after ${InvoiceNumberService_1.MAX_RETRIES} attempts`);
|
|
34
|
+
}
|
|
35
|
+
async getNextSequence(prefix) {
|
|
36
|
+
const maxNumber = await this.invoiceRepo.findMaxInvoiceNumber(prefix);
|
|
37
|
+
if (!maxNumber) {
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
const sequencePart = maxNumber.slice(prefix.length);
|
|
41
|
+
const parsed = parseInt(sequencePart, 10);
|
|
42
|
+
if (isNaN(parsed)) {
|
|
43
|
+
this.logger.warn(`Could not parse sequence from invoice number "${maxNumber}", starting from 1`);
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
return parsed + 1;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
exports.InvoiceNumberService = InvoiceNumberService;
|
|
50
|
+
InvoiceNumberService.MAX_RETRIES = 5;
|
|
51
|
+
exports.InvoiceNumberService = InvoiceNumberService = InvoiceNumberService_1 = __decorate([
|
|
52
|
+
(0, common_1.Injectable)(),
|
|
53
|
+
__param(0, (0, common_1.Inject)(constants_1.INVOICE_REPOSITORY)),
|
|
54
|
+
__metadata("design:paramtypes", [Object])
|
|
55
|
+
], InvoiceNumberService);
|
|
56
|
+
//# sourceMappingURL=invoice-number.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoice-number.service.js","sourceRoot":"","sources":["../../src/services/invoice-number.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAE5D,4CAAkD;AAClD,8CAAgE;AAezD,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAK/B,YAEE,WAAgD;QAA/B,gBAAW,GAAX,WAAW,CAAoB;QANjC,WAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IAO7D,CAAC;IAcJ,KAAK,CAAC,QAAQ,CAAC,WAAmB;QAChC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC;QAE9B,KACE,IAAI,OAAO,GAAG,CAAC,EACf,OAAO,GAAG,sBAAoB,CAAC,WAAW,EAC1C,OAAO,EAAE,EACT,CAAC;YACD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YACxD,MAAM,aAAa,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YAK1E,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,MAAM,IAAI,4CAA+B,CACvC,oDAAoD,sBAAoB,CAAC,WAAW,WAAW,CAChG,CAAC;IACJ,CAAC;IAMO,KAAK,CAAC,eAAe,CAAC,MAAc;QAC1C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAEtE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAE1C,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,iDAAiD,SAAS,oBAAoB,CAC/E,CAAC;YACF,OAAO,CAAC,CAAC;QACX,CAAC;QAED,OAAO,MAAM,GAAG,CAAC,CAAC;IACpB,CAAC;;AAnEU,oDAAoB;AAGP,gCAAW,GAAG,CAAC,AAAJ,CAAK;+BAH7B,oBAAoB;IADhC,IAAA,mBAAU,GAAE;IAOR,WAAA,IAAA,eAAM,EAAC,8BAAkB,CAAC,CAAA;;GANlB,oBAAoB,CAoEhC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { ModuleRef } from '@nestjs/core';
|
|
3
|
+
import type { IInvoiceRepository } from '../interfaces/invoice-repository.interface';
|
|
4
|
+
import type { IPaymentConfigRepository } from '../interfaces/payment-config-repository.interface';
|
|
5
|
+
import type { Invoice, InvoiceWithItems, InvoiceLineItem, InvoiceFilter, CreateLineItemData } from '../types';
|
|
6
|
+
import { InvoiceNumberService } from './invoice-number.service';
|
|
7
|
+
import { ETransferService } from './e-transfer.service';
|
|
8
|
+
export interface CreateInvoiceInput {
|
|
9
|
+
clientDetailsId: string;
|
|
10
|
+
taxRate?: number;
|
|
11
|
+
currency?: string;
|
|
12
|
+
referenceType?: string;
|
|
13
|
+
referenceId?: string;
|
|
14
|
+
dueAt?: Date;
|
|
15
|
+
notes?: string;
|
|
16
|
+
clientNotes?: string;
|
|
17
|
+
metadata?: Record<string, unknown> | null;
|
|
18
|
+
recurringInvoiceId?: string;
|
|
19
|
+
lineItems?: Array<{
|
|
20
|
+
description: string;
|
|
21
|
+
quantity: number;
|
|
22
|
+
unitPrice: number;
|
|
23
|
+
sortOrder?: number;
|
|
24
|
+
isTaxable?: boolean;
|
|
25
|
+
referenceType?: string;
|
|
26
|
+
referenceId?: string;
|
|
27
|
+
metadata?: Record<string, unknown> | null;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export declare class InvoiceService implements OnModuleInit {
|
|
31
|
+
private readonly invoiceRepo;
|
|
32
|
+
private readonly configRepo;
|
|
33
|
+
private readonly defaultCurrency;
|
|
34
|
+
private readonly invoiceNumberService;
|
|
35
|
+
private readonly eTransferService;
|
|
36
|
+
private readonly moduleRef;
|
|
37
|
+
private readonly logger;
|
|
38
|
+
private paymentEmailService;
|
|
39
|
+
private static readonly MAX_CREATE_RETRIES;
|
|
40
|
+
constructor(invoiceRepo: IInvoiceRepository, configRepo: IPaymentConfigRepository, defaultCurrency: string, invoiceNumberService: InvoiceNumberService, eTransferService: ETransferService, moduleRef: ModuleRef);
|
|
41
|
+
onModuleInit(): void;
|
|
42
|
+
createInvoice(divisionId: string, input: CreateInvoiceInput, createdBy: string): Promise<InvoiceWithItems>;
|
|
43
|
+
addLineItem(invoiceId: string, input: Omit<CreateLineItemData, 'invoiceId'>): Promise<InvoiceLineItem>;
|
|
44
|
+
removeLineItem(invoiceId: string, lineItemId: string): Promise<void>;
|
|
45
|
+
sendInvoice(id: string, eTransferEnabled: boolean, eTransferAutoDeposit: boolean, eTransferConfig?: {
|
|
46
|
+
eTransferEmail: string;
|
|
47
|
+
eTransferRecipient: string;
|
|
48
|
+
}): Promise<Invoice>;
|
|
49
|
+
voidInvoice(id: string, reason?: string, voidedBy?: string): Promise<Invoice>;
|
|
50
|
+
updateInvoiceMetadata(invoiceId: string, metadata: Record<string, unknown> | null): Promise<Invoice>;
|
|
51
|
+
findInvoice(divisionId: string, id: string): Promise<InvoiceWithItems | null>;
|
|
52
|
+
findInvoices(divisionId: string, filter?: InvoiceFilter, skip?: number, take?: number): Promise<{
|
|
53
|
+
items: Invoice[];
|
|
54
|
+
totalCount: number;
|
|
55
|
+
}>;
|
|
56
|
+
findInvoicesByClientDetailsIds(clientDetailsIds: string[], skip?: number, take?: number): Promise<{
|
|
57
|
+
items: Invoice[];
|
|
58
|
+
totalCount: number;
|
|
59
|
+
}>;
|
|
60
|
+
findInvoiceById(id: string): Promise<InvoiceWithItems | null>;
|
|
61
|
+
findOverdueInvoices(now: Date): Promise<Invoice[]>;
|
|
62
|
+
markOverdue(ids: string[]): Promise<number>;
|
|
63
|
+
findByETransferCode(code: string): Promise<Invoice | null>;
|
|
64
|
+
private recalculateTotals;
|
|
65
|
+
private resolveTaxRate;
|
|
66
|
+
}
|