tango-app-api-payment-subscription 3.5.28 → 3.5.30
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/docs/superpowers/specs/2026-07-09-quarterly-invoices-449-design.md +108 -0
- package/package.json +2 -2
- package/src/controllers/brandsBilling.controller.js +15 -0
- package/src/controllers/invoice.controller.js +356 -69
- package/src/hbs/invoiceBulkEmail.hbs +70 -0
- package/src/hbs/invoicepaymentemail.hbs +817 -856
- package/src/routes/invoice.routes.js +27 -25
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { createInvoice, invoiceDownload, invoiceDownloadBulk, clientInvoiceList, creditTransactionlist, pendingInvoices, applyDiscount, migrateInvoice, PaymentStatusChange, checkPaymentStatus, getInvoice, invoiceAnnexure, invoiceBankDetails, updateInvoice, getClientBasePricing, deleteInvoice, approveInvoiceCsm, approveInvoiceFinance, approveInvoiceApproval, recordPayment } from '../controllers/invoice.controller.js';
|
|
2
|
+
import { createInvoice, invoiceDownload, invoiceDownloadBulk, invoiceBulkEmailPreview, invoiceBulkEmailSend, clientInvoiceList, creditTransactionlist, pendingInvoices, applyDiscount, migrateInvoice, PaymentStatusChange, checkPaymentStatus, getInvoice, invoiceAnnexure, invoiceBankDetails, updateInvoice, getClientBasePricing, deleteInvoice, approveInvoiceCsm, approveInvoiceFinance, approveInvoiceApproval, recordPayment } from '../controllers/invoice.controller.js';
|
|
3
3
|
import { isAllowedSessionHandler, accessVerification, validate } from 'tango-app-api-middleware';
|
|
4
4
|
import { getInvoiceHeads, updateInvoiceHeads } from '../controllers/applicationDefault.controllers.js';
|
|
5
5
|
import { uploadBankStatement, bankTransactionList, resolveOptions, resolveBankTransaction } from '../controllers/bankTransaction.controller.js';
|
|
@@ -21,47 +21,49 @@ function superadminBypass( accessConfig ) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
invoiceRouter.post( '/createInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
25
|
-
invoiceRouter.post( '/regerateInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
26
|
-
invoiceRouter.post( '/invoiceDownload/bulk', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: '
|
|
24
|
+
invoiceRouter.post( '/createInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), createInvoice );
|
|
25
|
+
invoiceRouter.post( '/regerateInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), createInvoice );
|
|
26
|
+
invoiceRouter.post( '/invoiceDownload/bulk', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceDownloadBulk );
|
|
27
|
+
invoiceRouter.post( '/invoiceEmail/bulk/preview', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceBulkEmailPreview );
|
|
28
|
+
invoiceRouter.post( '/invoiceEmail/bulk/send', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceBulkEmailSend );
|
|
27
29
|
invoiceRouter.post( '/invoiceDownload/:invoiceId', isAllowedSessionHandler, invoiceDownload );
|
|
28
|
-
invoiceRouter.post( '/clientInvoiceList', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: '
|
|
29
|
-
invoiceRouter.post( '/creditTransactionlist', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: '
|
|
30
|
+
invoiceRouter.post( '/clientInvoiceList', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), clientInvoiceList );
|
|
31
|
+
invoiceRouter.post( '/creditTransactionlist', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), creditTransactionlist );
|
|
30
32
|
invoiceRouter.post( '/pendingInvoices', isAllowedSessionHandler, pendingInvoices );
|
|
31
|
-
invoiceRouter.post( '/applyDiscount', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
33
|
+
invoiceRouter.post( '/applyDiscount', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), applyDiscount );
|
|
32
34
|
invoiceRouter.post( '/migrateInvoice', migrateInvoice );
|
|
33
|
-
invoiceRouter.post( '/PaymentStatusChange', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
34
|
-
invoiceRouter.post( '/recordPayment', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
35
|
+
invoiceRouter.post( '/PaymentStatusChange', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), PaymentStatusChange );
|
|
36
|
+
invoiceRouter.post( '/recordPayment', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), recordPayment );
|
|
35
37
|
invoiceRouter.post( '/checkPaymentStatus', checkPaymentStatus );
|
|
36
38
|
invoiceRouter.get( '/getInvoice/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ ] } ), getInvoice );
|
|
37
|
-
invoiceRouter.get( '/invoiceAnnexure/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: '
|
|
38
|
-
invoiceRouter.get( '/invoiceBankDetails/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: '
|
|
39
|
-
invoiceRouter.put( '/updateInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
39
|
+
invoiceRouter.get( '/invoiceAnnexure/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceAnnexure );
|
|
40
|
+
invoiceRouter.get( '/invoiceBankDetails/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceBankDetails );
|
|
41
|
+
invoiceRouter.put( '/updateInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), updateInvoice );
|
|
40
42
|
invoiceRouter.get( '/getClientBasePricing/:clientId', isAllowedSessionHandler, getClientBasePricing );
|
|
41
|
-
invoiceRouter.delete( '/deleteInvoice/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
43
|
+
invoiceRouter.delete( '/deleteInvoice/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), deleteInvoice );
|
|
42
44
|
|
|
43
45
|
invoiceRouter.post( '/approveInvoiceCsm', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'csmApproval', permissions: [ 'isEdit' ] } ] } ), approveInvoiceCsm );
|
|
44
46
|
invoiceRouter.post( '/approveInvoiceFinance', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'financeApproval', permissions: [ 'isEdit' ] } ] } ), approveInvoiceFinance );
|
|
45
|
-
invoiceRouter.post( '/approveInvoiceApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
47
|
+
invoiceRouter.post( '/approveInvoiceApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), approveInvoiceApproval );
|
|
46
48
|
|
|
47
49
|
invoiceRouter.get( '/getInvoiceHeads', isAllowedSessionHandler, getInvoiceHeads );
|
|
48
50
|
invoiceRouter.post( '/updateInvoiceHeads', isAllowedSessionHandler, validate( updateInvoiceHeadsSchema ), updateInvoiceHeads );
|
|
49
51
|
|
|
50
52
|
// Bank-statement reconciliation (billing "Transactions" tab). Upload mutates
|
|
51
53
|
// the banktransaction collection so it needs edit rights; list is read-only.
|
|
52
|
-
invoiceRouter.post( '/bankStatement/upload', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
53
|
-
invoiceRouter.post( '/bankStatement/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
54
|
-
invoiceRouter.get( '/bankStatement/resolveOptions', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
55
|
-
invoiceRouter.post( '/bankStatement/resolve', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
54
|
+
invoiceRouter.post( '/bankStatement/upload', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), uploadBankStatement );
|
|
55
|
+
invoiceRouter.post( '/bankStatement/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), bankTransactionList );
|
|
56
|
+
invoiceRouter.get( '/bankStatement/resolveOptions', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), resolveOptions );
|
|
57
|
+
invoiceRouter.post( '/bankStatement/resolve', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), resolveBankTransaction );
|
|
56
58
|
|
|
57
59
|
// Estimates (quotations) — per-brand quotation documents with their own
|
|
58
60
|
// lifecycle. List/get are read; create/status/delete need edit rights.
|
|
59
|
-
invoiceRouter.post( '/estimate/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
60
|
-
invoiceRouter.post( '/estimate/create', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
61
|
+
invoiceRouter.post( '/estimate/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), estimateList );
|
|
62
|
+
invoiceRouter.post( '/estimate/create', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), createEstimate );
|
|
61
63
|
invoiceRouter.post( '/estimate/approveCsm', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'csmApproval', permissions: [ 'isEdit' ] } ] } ), approveEstimateCsm );
|
|
62
64
|
invoiceRouter.post( '/estimate/approveFinance', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'financeApproval', permissions: [ 'isEdit' ] } ] } ), approveEstimateFinance );
|
|
63
|
-
invoiceRouter.post( '/estimate/approveApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
64
|
-
invoiceRouter.post( '/estimate/update', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
65
|
-
invoiceRouter.post( '/estimate/download/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
66
|
-
invoiceRouter.get( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
67
|
-
invoiceRouter.delete( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
65
|
+
invoiceRouter.post( '/estimate/approveApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), approveEstimateApproval );
|
|
66
|
+
invoiceRouter.post( '/estimate/update', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), updateEstimate );
|
|
67
|
+
invoiceRouter.post( '/estimate/download/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), downloadEstimate );
|
|
68
|
+
invoiceRouter.get( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), getEstimate );
|
|
69
|
+
invoiceRouter.delete( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), deleteEstimate );
|