tango-app-api-payment-subscription 3.5.2 → 3.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import * as invoiceService from '../services/invoice.service.js';
|
|
|
2
2
|
import * as dailyPricingService from '../services/dailyPrice.service.js';
|
|
3
3
|
import * as clientService from '../services/clientPayment.services.js';
|
|
4
4
|
import * as billingService from '../services/billing.service.js';
|
|
5
|
+
import mongoose from 'mongoose';
|
|
5
6
|
import dayjs from 'dayjs';
|
|
6
7
|
import { logger, checkFileExist, signedUrl, download, sendEmailWithSES, insertOpenSearchData } from 'tango-app-api-middleware';
|
|
7
8
|
// import Handlebars from 'handlebars';
|
|
@@ -65,6 +66,25 @@ async function getInvoiceCcEmails( clientId ) {
|
|
|
65
66
|
export async function createInvoice( req, res ) {
|
|
66
67
|
try {
|
|
67
68
|
let invoiceGroupList = [];
|
|
69
|
+
// Optional groupIds filter — when present, only those billing groups will
|
|
70
|
+
// be processed. Lets the UI generate an invoice for a specific subset of
|
|
71
|
+
// groups instead of every group on the client. Strings are matched against
|
|
72
|
+
// billing _id.
|
|
73
|
+
const groupIdsFilter = Array.isArray( req.body.groupIds ) && req.body.groupIds.length > 0 ?
|
|
74
|
+
req.body.groupIds :
|
|
75
|
+
null;
|
|
76
|
+
const groupObjectIdFilter = groupIdsFilter ?
|
|
77
|
+
groupIdsFilter
|
|
78
|
+
.map( ( id ) => {
|
|
79
|
+
try {
|
|
80
|
+
return new mongoose.Types.ObjectId( id );
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
} )
|
|
85
|
+
.filter( ( id ) => id !== null ) :
|
|
86
|
+
null;
|
|
87
|
+
|
|
68
88
|
if ( req.body.allClient ) {
|
|
69
89
|
if ( req.body.clientList && req.body.clientList.length > 0 ) {
|
|
70
90
|
req.body.clientList = req.body.clientList;
|
|
@@ -74,12 +94,12 @@ export async function createInvoice( req, res ) {
|
|
|
74
94
|
}
|
|
75
95
|
|
|
76
96
|
for ( let client of req.body.clientList ) {
|
|
97
|
+
const matchStage = { clientId: client };
|
|
98
|
+
if ( groupObjectIdFilter && groupObjectIdFilter.length ) {
|
|
99
|
+
matchStage._id = { $in: groupObjectIdFilter };
|
|
100
|
+
}
|
|
77
101
|
let invoiceGroup = await billingService.aggregatebilling( [
|
|
78
|
-
{
|
|
79
|
-
$match: {
|
|
80
|
-
clientId: client,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
102
|
+
{ $match: matchStage },
|
|
83
103
|
] );
|
|
84
104
|
for ( let invGrp of invoiceGroup ) {
|
|
85
105
|
invoiceGroupList.push( invGrp );
|
|
@@ -95,7 +115,14 @@ export async function createInvoice( req, res ) {
|
|
|
95
115
|
|
|
96
116
|
for ( let group of invoiceGroupList ) {
|
|
97
117
|
let Finacialyear = getCurrentFinancialYear();
|
|
98
|
-
|
|
118
|
+
// Scope the highest-index lookup to invoices created in the current FY
|
|
119
|
+
// (invoice IDs are `INV-${FY}-${index}`). Without this scope the new FY
|
|
120
|
+
// would continue the previous year's sequence instead of resetting.
|
|
121
|
+
let previousinvoice = await invoiceService.findandsort(
|
|
122
|
+
{ invoice: { $regex: `^INV-${Finacialyear}-` } },
|
|
123
|
+
{},
|
|
124
|
+
{ invoiceIndex: -1 },
|
|
125
|
+
);
|
|
99
126
|
let invoiceNo = '00001';
|
|
100
127
|
if ( previousinvoice && previousinvoice.length > 0 ) {
|
|
101
128
|
invoiceNo = Number( previousinvoice[0].invoiceIndex ) + 1;
|
|
@@ -2110,6 +2137,13 @@ export async function updateInvoice( req, res ) {
|
|
|
2110
2137
|
return res.sendError( 'Invoice not found', 404 );
|
|
2111
2138
|
}
|
|
2112
2139
|
|
|
2140
|
+
// Lock once final-approved. The UI hides the Edit icon for these rows,
|
|
2141
|
+
// but a direct API call would otherwise still let someone mutate a
|
|
2142
|
+
// finalised invoice. Match the frontend's isInvoiceLocked() check.
|
|
2143
|
+
if ( invoice.status === 'approved' ) {
|
|
2144
|
+
return res.sendError( 'Cannot edit a final-approved invoice.', 409 );
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2113
2147
|
let updateData = {};
|
|
2114
2148
|
const allowedFields = [
|
|
2115
2149
|
'companyName', 'companyAddress', 'GSTNumber', 'PlaceOfSupply',
|
|
@@ -2220,6 +2254,12 @@ export async function deleteInvoice( req, res ) {
|
|
|
2220
2254
|
return res.sendError( 'Invoice not found', 404 );
|
|
2221
2255
|
}
|
|
2222
2256
|
|
|
2257
|
+
// Same lock the UI enforces — a final-approved invoice must not be
|
|
2258
|
+
// deletable, even by a power user hitting the API directly.
|
|
2259
|
+
if ( invoice.status === 'approved' ) {
|
|
2260
|
+
return res.sendError( 'Cannot delete a final-approved invoice.', 409 );
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2223
2263
|
await invoiceService.deleteRecord( { _id: invoiceId } );
|
|
2224
2264
|
|
|
2225
2265
|
const logObj = {
|
|
@@ -3772,7 +3772,15 @@ export const invoiceGenerate = async ( req, res ) => {
|
|
|
3772
3772
|
}
|
|
3773
3773
|
|
|
3774
3774
|
|
|
3775
|
-
|
|
3775
|
+
// Scope the highest-index lookup to the current financial year
|
|
3776
|
+
// (invoice IDs are `INV-${FY}-${index}`). Sort by invoiceIndex (not
|
|
3777
|
+
// _id) so the largest sequence number wins even if records were
|
|
3778
|
+
// back-dated or imported out of order.
|
|
3779
|
+
let previousinvoice = await invoiceService.findandsort(
|
|
3780
|
+
{ invoice: { $regex: `^INV-${Finacialyear}-` } },
|
|
3781
|
+
{},
|
|
3782
|
+
{ invoiceIndex: -1 },
|
|
3783
|
+
);
|
|
3776
3784
|
let invoiceNo = '00001';
|
|
3777
3785
|
if ( previousinvoice && previousinvoice.length > 0 ) {
|
|
3778
3786
|
invoiceNo = Number( previousinvoice[0].invoiceIndex ) + 1;
|
package/src/hbs/invoicePdf.hbs
CHANGED
|
@@ -1643,7 +1643,7 @@
|
|
|
1643
1643
|
</div>
|
|
1644
1644
|
<div class="frame-54">
|
|
1645
1645
|
<div class="ifsc-code">IFSC Code</div>
|
|
1646
|
-
<div class="hdfc-0000269">
|
|
1646
|
+
<div class="hdfc-0000269">HDFC0000386</div>
|
|
1647
1647
|
</div>
|
|
1648
1648
|
<div class="frame-532">
|
|
1649
1649
|
<div class="payment-type">Payment Type</div>
|