tango-app-api-payment-subscription 3.5.28 → 3.5.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Quarterly Invoice Creation Script — clientId 449 (Apr/May/Jun 2025)
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-09
|
|
4
|
+
**File to create:** `scripts/create-quarterly-invoices-449.js`
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Create **3 invoices** for clientId `449`, one per billing group, each covering the
|
|
9
|
+
**Apr–Jun 2025 quarter (FY 25-26)** as three per-month line-item blocks. This is a
|
|
10
|
+
one-off backfill of quarterly billing.
|
|
11
|
+
|
|
12
|
+
Target groups (all confirmed to exist on clientId 449, all INR, all GST prefix `33`):
|
|
13
|
+
|
|
14
|
+
| Group name | _id | GST | stores |
|
|
15
|
+
|-------------------------------|----------------------------|-----------------|--------|
|
|
16
|
+
| LILLE BY CHALLANI | `6a4f37925d8071b6ae34d1a2` | 33AALCC7452J1ZF | 6 |
|
|
17
|
+
| FEDHA JEWELS PRIVATE LIMITED | `6a4f37298b8646bec2a1f630` | 33AAFCF8793V1ZL | 7 |
|
|
18
|
+
| CHALLANI JEWELLERY MART | `6a4f32644cde0c2869be2e52` | 33AAIFC5600Q1ZC | 2 |
|
|
19
|
+
|
|
20
|
+
Client 449: `priceType: standard`, `status: active`.
|
|
21
|
+
|
|
22
|
+
## Invoice series & shape
|
|
23
|
+
|
|
24
|
+
- **Series: `INV-`** (normal series), NOT TINV-. Number format `INV-25-26-NNNNN`,
|
|
25
|
+
continuing the highest `invoiceIndex` for `^INV-25-26-` (matches controller logic).
|
|
26
|
+
- `advanceInvoice: false`, `advancePeriod` omitted.
|
|
27
|
+
- **One invoice document per group** whose `products` array contains three month-blocks
|
|
28
|
+
(Apr 2025, May 2025, Jun 2025), each line tagged `month: 'MMM YYYY'`.
|
|
29
|
+
- `advanceMonths: 3` recorded for reference (bundled quarter), but the invoice is a normal
|
|
30
|
+
INV- invoice — the quarterly nature lives in the line items, not the advance flag.
|
|
31
|
+
- No `storeDetails` block (that is TINV-only in the controller).
|
|
32
|
+
|
|
33
|
+
## Pricing — actual per-month snapshots, prorated
|
|
34
|
+
|
|
35
|
+
Client 449 is `priceType: standard`, so we replicate the **standard-price** path from
|
|
36
|
+
`createInvoice` → `standardPrice()`. For each group, for each of Apr/May/Jun 2025:
|
|
37
|
+
|
|
38
|
+
1. **Snapshot selection:** pick the latest daily-pricing doc with
|
|
39
|
+
`dateISO <= end-of-month`, sorted `dateISO: -1`, `limit 1` — the actual snapshot for
|
|
40
|
+
that month (differs from the controller, which always takes the newest snapshot).
|
|
41
|
+
2. **Days basis:** `daysInMonth` of that month (Apr=30, May=31, Jun=30).
|
|
42
|
+
3. **Basepricing doc:** resolved via the same rule as `resolveBasePricingScope` —
|
|
43
|
+
group-wise doc when `client.billingGroupWisePricing` is on AND a group doc exists,
|
|
44
|
+
else the brand-level doc (`groupId` unset). Read `negotiatePrice` from `standard[]`.
|
|
45
|
+
4. **overallStore products:** filter to `group.stores`, keep `workingdays > 0`, group by
|
|
46
|
+
(product, workingdays), sum store counts. Prorate:
|
|
47
|
+
`workingdays >= daysInMonth` → `price * count` (full month);
|
|
48
|
+
else `(price / daysInMonth) * workingdays * count`. `proRata: 'flat'` on the group
|
|
49
|
+
forces full-month working days.
|
|
50
|
+
5. **billingType** perZone / perCamera for `tangoZone` / `tangoTraffic`: multiply by zone
|
|
51
|
+
/ camera counts exactly as the controller does.
|
|
52
|
+
6. **billingMethod `eachStore`** products: emit one line per store (per-store proration),
|
|
53
|
+
as in the controller.
|
|
54
|
+
7. Tag every produced line with `month: 'MMM YYYY'` for that month.
|
|
55
|
+
|
|
56
|
+
The three months' line arrays are concatenated into the single `products` array.
|
|
57
|
+
|
|
58
|
+
**Empty-month handling:** if a month has no snapshot `<=` its end, or the group has no
|
|
59
|
+
running stores that month, that month contributes zero lines. The script logs this
|
|
60
|
+
**loudly** (WARN per group/month) so a short invoice is never produced silently.
|
|
61
|
+
|
|
62
|
+
## Invoice document fields (mirrors controller `data`)
|
|
63
|
+
|
|
64
|
+
- `invoice: INV-25-26-NNNNN`, `invoiceIndex`
|
|
65
|
+
- `groupId`, `groupName`, `clientId: '449'`
|
|
66
|
+
- `companyName` = uppercased `registeredCompanyName`; `companyAddress` built from group
|
|
67
|
+
address fields (`addressLineOne+addressLineTwo+city,state,country -pinCode`), matching
|
|
68
|
+
the controller
|
|
69
|
+
- `GSTNumber` = group.gst, `PlaceOfSupply` = group.placeOfSupply
|
|
70
|
+
- `products` = concatenated month-blocks
|
|
71
|
+
- `amount` = Σ line amounts (roundAmount, inr); `tax` = CGST 9% + SGST 9% (GST prefix `33`);
|
|
72
|
+
`totalAmount` = roundAmount(amount + tax)
|
|
73
|
+
- `currency: 'inr'`, `stores` = running-store count from the latest snapshot within Jun 2025
|
|
74
|
+
- `billingDate` = today (creation date, per controller convention), `monthOfbilling: '04'`
|
|
75
|
+
- `dueDate` = billingDate + (group.paymentTerm || 30) days
|
|
76
|
+
- `status: 'pendingCsm'`, `paymentStatus: 'unpaid'`, `paymentMethod: 'Online'`
|
|
77
|
+
- `advanceInvoice: false`, `advanceMonths: 3`
|
|
78
|
+
|
|
79
|
+
## Number allocation across the 3 invoices
|
|
80
|
+
|
|
81
|
+
Compute the starting index once (max `invoiceIndex` for `^INV-25-26-`), then increment
|
|
82
|
+
locally per group so the three invoices get consecutive numbers within one run. In
|
|
83
|
+
dry-run, the numbers shown are provisional (no write, so the counter is not advanced).
|
|
84
|
+
|
|
85
|
+
## Safety & idempotency
|
|
86
|
+
|
|
87
|
+
- **Dry-run by default.** Prints, per group: invoice number, per-month per-product
|
|
88
|
+
breakdown (product, storeCount, price, working-days/period, amount), subtotal, CGST,
|
|
89
|
+
SGST, total, and any empty-month WARNs. Writes nothing.
|
|
90
|
+
- **`--apply`** performs the inserts via `invoiceModel.create`.
|
|
91
|
+
- **Duplicate guard:** before creating a group's invoice, check for an existing
|
|
92
|
+
`INV-`-series invoice for that `groupId` already carrying a `products.month = 'Apr 2025'`
|
|
93
|
+
line. If found, SKIP that group with a warning (prevents double-billing on re-run).
|
|
94
|
+
- **No side effects:** no PDF, no email, no OpenSearch activity log, no PO mapping.
|
|
95
|
+
- **Connection:** reuse `getConnection()` from `config/database/database.js` (or
|
|
96
|
+
`MONGO_URI` override), and the `tango-api-schema` models — same as existing scripts.
|
|
97
|
+
|
|
98
|
+
## Flags
|
|
99
|
+
|
|
100
|
+
- `node scripts/create-quarterly-invoices-449.js` → DRY RUN
|
|
101
|
+
- `node scripts/create-quarterly-invoices-449.js --apply` → write
|
|
102
|
+
- `--clientId=449` (default 449), `--year=2025` (Q1 = Apr/May/Jun of this calendar year;
|
|
103
|
+
FY label derived as `YY-(YY+1)`)
|
|
104
|
+
|
|
105
|
+
## Out of scope
|
|
106
|
+
|
|
107
|
+
TINV/advance series, multi-client support, PDF/email generation, non-standard (step)
|
|
108
|
+
pricing beyond what `standardPrice` covers for this client.
|
package/package.json
CHANGED
|
@@ -2078,38 +2078,54 @@ export async function clientInvoiceList( req, res ) {
|
|
|
2078
2078
|
let filterEndDate = '';
|
|
2079
2079
|
|
|
2080
2080
|
if ( !hasMonthYear ) {
|
|
2081
|
+
// Start = start-of-month (00:00:00); End = end-of-month (23:59:59.999)
|
|
2082
|
+
// via .toDate() so invoices on the last day (with any time) are included.
|
|
2081
2083
|
if ( req.body?.filter && req.body.filter == 'current' ) {
|
|
2082
|
-
filterStartDate =
|
|
2083
|
-
filterEndDate =
|
|
2084
|
+
filterStartDate = dayjs().startOf( 'month' ).toDate();
|
|
2085
|
+
filterEndDate = dayjs().endOf( 'month' ).toDate();
|
|
2084
2086
|
}
|
|
2085
2087
|
if ( req.body?.filter && req.body.filter == 'prev' ) {
|
|
2086
|
-
filterStartDate =
|
|
2087
|
-
filterEndDate =
|
|
2088
|
+
filterStartDate = dayjs().subtract( 1, 'month' ).startOf( 'month' ).toDate();
|
|
2089
|
+
filterEndDate = dayjs().subtract( 1, 'month' ).endOf( 'month' ).toDate();
|
|
2088
2090
|
}
|
|
2089
2091
|
// Rolling windows. 'last3' = the prototype's "Last 3 Months" (was the
|
|
2090
2092
|
// legacy 'last' id, which silently meant 12 months and made every other
|
|
2091
2093
|
// filter look broken). 'last' is kept as an alias of 'last3' so older
|
|
2092
2094
|
// clients don't break mid-deploy.
|
|
2093
2095
|
if ( req.body?.filter && ( req.body.filter == 'last3' || req.body.filter == 'last' ) ) {
|
|
2094
|
-
filterStartDate =
|
|
2095
|
-
filterEndDate =
|
|
2096
|
+
filterStartDate = dayjs().subtract( 3, 'month' ).startOf( 'month' ).toDate();
|
|
2097
|
+
filterEndDate = dayjs().endOf( 'month' ).toDate();
|
|
2096
2098
|
}
|
|
2097
2099
|
if ( req.body?.filter && req.body.filter == 'last6' ) {
|
|
2098
|
-
filterStartDate =
|
|
2099
|
-
filterEndDate =
|
|
2100
|
+
filterStartDate = dayjs().subtract( 6, 'month' ).startOf( 'month' ).toDate();
|
|
2101
|
+
filterEndDate = dayjs().endOf( 'month' ).toDate();
|
|
2100
2102
|
}
|
|
2101
2103
|
if ( req.body?.filter && req.body.filter == 'last12' ) {
|
|
2102
|
-
filterStartDate =
|
|
2103
|
-
filterEndDate =
|
|
2104
|
+
filterStartDate = dayjs().subtract( 12, 'month' ).startOf( 'month' ).toDate();
|
|
2105
|
+
filterEndDate = dayjs().endOf( 'month' ).toDate();
|
|
2104
2106
|
}
|
|
2105
2107
|
|
|
2106
2108
|
if ( req.body?.filter ) {
|
|
2109
|
+
// billingDate may be stored as a Date OR a string on legacy rows. A raw
|
|
2110
|
+
// { billingDate: { $gte: <Date> } } range compares across BSON types for
|
|
2111
|
+
// string rows and silently fails to filter — so the Duration filter
|
|
2112
|
+
// appeared to "show all". Coerce to a Date in an $expr, mirroring the
|
|
2113
|
+
// Month/Year filter below.
|
|
2114
|
+
const billingDateExpr = {
|
|
2115
|
+
$cond: [
|
|
2116
|
+
{ $eq: [ { $type: '$billingDate' }, 'date' ] },
|
|
2117
|
+
'$billingDate',
|
|
2118
|
+
{ $toDate: '$billingDate' },
|
|
2119
|
+
],
|
|
2120
|
+
};
|
|
2107
2121
|
query.push( {
|
|
2108
2122
|
$match: {
|
|
2109
|
-
$
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2123
|
+
$expr: {
|
|
2124
|
+
$and: [
|
|
2125
|
+
{ $gte: [ billingDateExpr, filterStartDate ] },
|
|
2126
|
+
{ $lte: [ billingDateExpr, filterEndDate ] },
|
|
2127
|
+
],
|
|
2128
|
+
},
|
|
2113
2129
|
},
|
|
2114
2130
|
} );
|
|
2115
2131
|
}
|
|
@@ -21,47 +21,47 @@ 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
27
|
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: '
|
|
28
|
+
invoiceRouter.post( '/clientInvoiceList', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), clientInvoiceList );
|
|
29
|
+
invoiceRouter.post( '/creditTransactionlist', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), creditTransactionlist );
|
|
30
30
|
invoiceRouter.post( '/pendingInvoices', isAllowedSessionHandler, pendingInvoices );
|
|
31
|
-
invoiceRouter.post( '/applyDiscount', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
31
|
+
invoiceRouter.post( '/applyDiscount', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), applyDiscount );
|
|
32
32
|
invoiceRouter.post( '/migrateInvoice', migrateInvoice );
|
|
33
|
-
invoiceRouter.post( '/PaymentStatusChange', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
34
|
-
invoiceRouter.post( '/recordPayment', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
33
|
+
invoiceRouter.post( '/PaymentStatusChange', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), PaymentStatusChange );
|
|
34
|
+
invoiceRouter.post( '/recordPayment', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), recordPayment );
|
|
35
35
|
invoiceRouter.post( '/checkPaymentStatus', checkPaymentStatus );
|
|
36
36
|
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: '
|
|
37
|
+
invoiceRouter.get( '/invoiceAnnexure/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceAnnexure );
|
|
38
|
+
invoiceRouter.get( '/invoiceBankDetails/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango', 'client' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), invoiceBankDetails );
|
|
39
|
+
invoiceRouter.put( '/updateInvoice', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), updateInvoice );
|
|
40
40
|
invoiceRouter.get( '/getClientBasePricing/:clientId', isAllowedSessionHandler, getClientBasePricing );
|
|
41
|
-
invoiceRouter.delete( '/deleteInvoice/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: '
|
|
41
|
+
invoiceRouter.delete( '/deleteInvoice/:invoiceId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), deleteInvoice );
|
|
42
42
|
|
|
43
43
|
invoiceRouter.post( '/approveInvoiceCsm', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'csmApproval', permissions: [ 'isEdit' ] } ] } ), approveInvoiceCsm );
|
|
44
44
|
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: '
|
|
45
|
+
invoiceRouter.post( '/approveInvoiceApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), approveInvoiceApproval );
|
|
46
46
|
|
|
47
47
|
invoiceRouter.get( '/getInvoiceHeads', isAllowedSessionHandler, getInvoiceHeads );
|
|
48
48
|
invoiceRouter.post( '/updateInvoiceHeads', isAllowedSessionHandler, validate( updateInvoiceHeadsSchema ), updateInvoiceHeads );
|
|
49
49
|
|
|
50
50
|
// Bank-statement reconciliation (billing "Transactions" tab). Upload mutates
|
|
51
51
|
// 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: '
|
|
52
|
+
invoiceRouter.post( '/bankStatement/upload', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), uploadBankStatement );
|
|
53
|
+
invoiceRouter.post( '/bankStatement/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), bankTransactionList );
|
|
54
|
+
invoiceRouter.get( '/bankStatement/resolveOptions', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), resolveOptions );
|
|
55
|
+
invoiceRouter.post( '/bankStatement/resolve', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), resolveBankTransaction );
|
|
56
56
|
|
|
57
57
|
// Estimates (quotations) — per-brand quotation documents with their own
|
|
58
58
|
// 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: '
|
|
59
|
+
invoiceRouter.post( '/estimate/list', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), estimateList );
|
|
60
|
+
invoiceRouter.post( '/estimate/create', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), createEstimate );
|
|
61
61
|
invoiceRouter.post( '/estimate/approveCsm', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'TangoAdmin', name: 'csmApproval', permissions: [ 'isEdit' ] } ] } ), approveEstimateCsm );
|
|
62
62
|
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: '
|
|
63
|
+
invoiceRouter.post( '/estimate/approveApproval', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), approveEstimateApproval );
|
|
64
|
+
invoiceRouter.post( '/estimate/update', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), updateEstimate );
|
|
65
|
+
invoiceRouter.post( '/estimate/download/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), downloadEstimate );
|
|
66
|
+
invoiceRouter.get( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [] } ] } ), getEstimate );
|
|
67
|
+
invoiceRouter.delete( '/estimate/:estimateId', isAllowedSessionHandler, superadminBypass( { userType: [ 'tango' ], access: [ { featureName: 'Global', name: 'Billing', permissions: [ 'isEdit' ] } ] } ), deleteEstimate );
|