tango-app-api-payment-subscription 3.0.61-dev → 3.0.62-dev

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/.eslintrc.cjs CHANGED
@@ -36,7 +36,7 @@ module.exports = {
36
36
  'no-unused-vars': 'error',
37
37
  'new-cap': [ 'error', { 'newIsCap': true, 'capIsNew': false } ],
38
38
  'prefer-const': 'off',
39
- 'no-console': 'error',
39
+ // 'no-console': 'error',
40
40
  },
41
41
  };
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-payment-subscription",
3
- "version": "3.0.61-dev",
3
+ "version": "3.0.62-dev",
4
4
  "description": "paymentSubscription",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  "mongodb": "^6.4.0",
26
26
  "nodemon": "^3.1.0",
27
27
  "swagger-ui-express": "^5.0.0",
28
- "tango-api-schema": "^2.0.131",
28
+ "tango-api-schema": "^2.0.139",
29
29
  "tango-app-api-middleware": "^3.1.26",
30
30
  "winston": "^3.12.0",
31
31
  "winston-daily-rotate-file": "^5.0.0"
@@ -3,107 +3,122 @@ 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
5
  import dayjs from 'dayjs';
6
- import { logger, checkFileExist, signedUrl } from 'tango-app-api-middleware';
6
+ import { logger, checkFileExist, signedUrl, download, sendEmailWithSES } from 'tango-app-api-middleware';
7
7
  import Handlebars from 'handlebars';
8
8
  import fs from 'fs';
9
9
  import path from 'path';
10
10
  import htmlpdf from 'html-pdf-node';
11
- import basePricingModel from 'tango-api-schema/schema/basePricing.model.js';
11
+ import * as basepricingService from '../services/basePrice.service.js';
12
+ import * as paymentAccountService from '../services/paymentAccount.service.js';
13
+
12
14
  export async function createInvoice( req, res ) {
13
15
  try {
14
- if ( req.body.clientList.length > 0 ) {
15
- req.body.clientList = req.body.clientList;
16
- } else {
17
- let clients = await clientService.find( { status: 'active' } );
18
- req.body.clientList = clients.map( ( client ) => client.clientId );
19
- }
20
- for ( let client of req.body.clientList ) {
21
- let invoiceGroup = await billingService.aggregatebilling( [
22
- {
23
- $match: {
24
- clientId: client,
16
+ let invoiceGroupList = [];
17
+ if ( req.body.allClient ) {
18
+ if ( req.body.clientList&& req.body.clientList.length > 0 ) {
19
+ req.body.clientList = req.body.clientList;
20
+ } else {
21
+ let clients = await clientService.find( { status: 'active' } );
22
+ req.body.clientList = clients.map( ( client ) => client.clientId );
23
+ }
24
+
25
+ for ( let client of req.body.clientList ) {
26
+ let invoiceGroup = await billingService.aggregatebilling( [
27
+ {
28
+ $match: {
29
+ clientId: client,
30
+ },
25
31
  },
26
- },
27
- ] );
28
- for ( let group of invoiceGroup ) {
29
- let Finacialyear = getCurrentFinancialYear();
30
- let previousinvoice = await invoiceService.findandsort( {}, {}, { invoiceIndex: -1 } );
31
- let invoiceNo = '00001';
32
- if ( previousinvoice && previousinvoice.length > 0 ) {
33
- invoiceNo = Number( previousinvoice[0].invoiceIndex ) + 1;
34
- invoiceNo = invoiceNo.toString().padStart( 5, '0' );
32
+ ] );
33
+ for ( let invGrp of invoiceGroup ) {
34
+ invoiceGroupList.push( invGrp );
35
35
  }
36
+ }
37
+ }
38
+ if ( req.body.invoiceId ) {
39
+ let findInvoice = await invoiceService.findOne( { invoice: req.body.invoiceId } );
40
+ let invoiceGroup = await billingService.findOne( { _id: findInvoice.groupId } );
41
+ invoiceGroupList.push( invoiceGroup );
42
+ }
36
43
 
37
- let address = group.addressLineOne + group.addressLineTwo + group.city + ',' + group.state + ',' + group.country + ' -' + group.pinCode;
38
- let getClient = await clientService.findOne( { clientId: client, status: 'active' } );
39
- let products;
40
- if ( getClient.priceType === 'standard' ) {
41
- products = await standardPrice( client, group );
42
- } else {
43
- products = await stepPrice( client, group, res );
44
- }
45
- let amount = products.reduce( ( sum, product ) => sum + product.amount, 0 );
46
- let taxList = [];
47
- let totalAmount = 0;
48
- if ( group.gst && group.gst.slice( 0, 2 ) == '33' ) {
49
- let taxAmount = ( amount * 18 ) / 100;
50
- totalAmount = ( amount + taxAmount ).toFixed( 2 );
51
- taxList.push(
52
- {
53
- 'currency': '₹',
54
- 'type': 'CGST',
55
- 'value': 9,
56
- 'taxAmount': ( ( amount * 9 ) / 100 ).toFixed( 2 ),
57
- }, {
58
- 'currency': '₹',
59
- 'type': 'SGST',
60
- 'value': 9,
61
- 'taxAmount': ( ( amount * 9 ) / 100 ).toFixed( 2 ),
62
- },
63
- );
64
- } else {
65
- let taxAmount = ( amount * 18 ) / 100;
66
- totalAmount = ( amount + taxAmount ).toFixed( 2 );
67
- taxList.push(
68
- {
69
- 'currency': '₹',
70
- 'type': 'IGST',
71
- 'value': 18,
72
- 'taxAmount': ( taxAmount ).toFixed( 2 ),
73
- },
74
- );
75
- }
44
+ for ( let group of invoiceGroupList ) {
45
+ let Finacialyear = getCurrentFinancialYear();
46
+ let previousinvoice = await invoiceService.findandsort( {}, {}, { invoiceIndex: -1 } );
47
+ let invoiceNo = '00001';
48
+ if ( previousinvoice && previousinvoice.length > 0 ) {
49
+ invoiceNo = Number( previousinvoice[0].invoiceIndex ) + 1;
50
+ invoiceNo = invoiceNo.toString().padStart( 5, '0' );
51
+ }
76
52
 
53
+ let address = group.addressLineOne + group.addressLineTwo + group.city + ',' + group.state + ',' + group.country + ' -' + group.pinCode;
54
+ let getClient = await clientService.findOne( { clientId: group.clientId, status: 'active' } );
55
+ let products;
77
56
 
78
- let totalStoreCount = products.reduce( ( sum, item ) => sum + item.storeCount, 0 );
79
- let data = {
80
- groupName: group.groupName,
81
- groupId: group._id,
82
- invoice: `INV-${Finacialyear}-${invoiceNo}`,
83
- products: products,
84
- status: 'pending',
85
- amount: amount,
86
- invoiceIndex: invoiceNo,
87
- tax: taxList,
88
- companyName: group.registeredCompanyName,
89
- companyAddress: address,
90
- PlaceOfSupply: group.placeOfSupply,
91
- GSTNumber: group.gst,
92
- totalAmount: totalAmount,
93
- clientId: client,
94
- paymentMethod: '',
95
- billingDate: new Date(),
96
- stores: totalStoreCount,
97
- };
98
-
99
- let invoiceExists = await invoiceService.findOne( { monthOfbilling: req.body.monthOfbilling, clientId: getClient.clientId } );
100
- if ( invoiceExists ) {
101
- logger.info( `invoice already exist for the month${req.body.monthOfbilling} for ${getClient.clientId}` );
102
- } else {
103
- await invoiceService.create( data );
104
- }
57
+ if ( getClient.priceType === 'standard' ) {
58
+ products = await standardPrice( group );
59
+ } else {
60
+ products = await stepPrice( group );
61
+ }
62
+ let amount = products.reduce( ( sum, product ) => sum + product.amount, 0 );
63
+ let taxList = [];
64
+ let totalAmount = 0;
65
+ if ( group.gst && group.gst.slice( 0, 2 ) == '33' ) {
66
+ let taxAmount = ( amount * 18 ) / 100;
67
+ totalAmount = Math.round( amount + taxAmount );
68
+ taxList.push(
69
+ {
70
+ 'currency': '₹',
71
+ 'type': 'CGST',
72
+ 'value': 9,
73
+ 'taxAmount': ( ( amount * 9 ) / 100 ).toFixed( 2 ),
74
+ }, {
75
+ 'currency': '₹',
76
+ 'type': 'SGST',
77
+ 'value': 9,
78
+ 'taxAmount': ( ( amount * 9 ) / 100 ).toFixed( 2 ),
79
+ },
80
+ );
81
+ } else {
82
+ let taxAmount = ( amount * 18 ) / 100;
83
+ totalAmount = Math.round( amount + taxAmount );
84
+ taxList.push(
85
+ {
86
+ 'currency': '₹',
87
+ 'type': 'IGST',
88
+ 'value': 18,
89
+ 'taxAmount': ( taxAmount ).toFixed( 2 ),
90
+ },
91
+ );
92
+ }
93
+
94
+
95
+ let totalStoreCount = products.reduce( ( sum, item ) => sum + item.storeCount, 0 );
96
+ let data = {
97
+ groupName: group.groupName,
98
+ groupId: group._id,
99
+ invoice: `INV-${Finacialyear}-${invoiceNo}`,
100
+ products: products,
101
+ status: 'pending',
102
+ amount: Math.round( amount ),
103
+ invoiceIndex: invoiceNo,
104
+ tax: taxList,
105
+ companyName: group.registeredCompanyName,
106
+ companyAddress: address,
107
+ PlaceOfSupply: group.placeOfSupply,
108
+ GSTNumber: group.gst,
109
+ totalAmount: Math.round( totalAmount ),
110
+ clientId: group.clientId,
111
+ paymentMethod: '',
112
+ billingDate: new Date(),
113
+ stores: totalStoreCount,
114
+ currency: group.currency?group.currency:'inr',
115
+ };
116
+ if ( req.body.invoiceId ) {
117
+ await invoiceService.deleteRecord( { invoice: req.body.invoiceId } );
105
118
  }
119
+ await invoiceService.create( data );
106
120
  }
121
+
107
122
  res.sendSuccess( 'Invoice Created SuccessFully' );
108
123
  } catch ( error ) {
109
124
  logger.error( { error: error, function: 'createInvoice' } );
@@ -165,6 +180,8 @@ export async function invoiceDownload( req, res ) {
165
180
  totalAmount: invoiceInfo.totalAmount.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ),
166
181
  invoiceDate,
167
182
  dueDate,
183
+ discount: 0,
184
+ logo: `${JSON.parse( process.env.URL ).apiDomain}/logo.png`,
168
185
  };
169
186
  const currentMonthDays = dayjs().daysInMonth();
170
187
  let getgroup = await billingService.findOne( { _id: invoiceInfo.groupId } );
@@ -304,7 +321,8 @@ export async function invoiceDownload( req, res ) {
304
321
  ],
305
322
  );
306
323
  invoiceData.annuxureData = annuxureData;
307
-
324
+ let virtualAccount= await paymentAccountService.findOneAccount( { clientId: invoiceInfo.clientId } );
325
+ invoiceData.virtualAccount = virtualAccount;
308
326
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf.hbs', 'utf8' );
309
327
  const template = Handlebars.compile( templateHtml );
310
328
  const html = template( { ...invoiceData } );
@@ -327,25 +345,18 @@ export async function invoiceDownload( req, res ) {
327
345
  htmlpdf.generatePdf( file, options ).then( async function( pdfBuffer ) {
328
346
  if ( req.body.sendInvoice ) {
329
347
  let mailSubject = `Invoice for ${monthName} - Tango/${clientDetails.clientName}`;
330
- let mailbody = `<div>Dear Team,</div>
331
- <div style="margin-top:10px">
332
- Please find attached the Invoice for the month of ${monthName}'24.
333
- </div>
334
- <div style="margin-top:10px">
335
- Best Regards,
336
- </div>
337
- <div style="margin-top:5px">
338
- Tango Finance
339
- </div>`;
340
-
348
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicepaymentemail.hbs', 'utf8' );
349
+ const template = Handlebars.compile( templateHtml );
350
+ const mailbody = template( { ...invoiceData } );
341
351
  let filename = `${clientDetails.clientName}-${invoiceData.invoice}-${monthName}.pdf`;
342
352
  let attachments = {
343
353
  filename: `${filename}`,
344
354
  content: pdfBuffer,
345
355
  contentType: 'application/pdf', // e.g., 'application/pdf'
346
356
  };
347
- clientDetails.paymentInvoice.invoiceCC = [ ...clientDetails.paymentInvoice.invoiceCC, ...[ 'sireesha@tangotech.co.in' ] ];
348
- const result = await sendEmailWithSES( clientDetails.paymentInvoice.invoiceTo, mailSubject, mailbody, attachments, 'no-reply@tangotech.ai', clientDetails.paymentInvoice.invoiceCC );
357
+ let billingGroup = await billingService.findOne( { _id: invoiceInfo.groupId } );
358
+
359
+ const result = await sendEmailWithSES( billingGroup.generateInvoiceTo, mailSubject, mailbody, attachments, 'no-reply@tangotech.ai' );
349
360
  if ( result ) {
350
361
  await invoiceService.updateOne( { _id: req.params.invoiceId }, { status: req.body.status } );
351
362
  return res.sendSuccess( result );
@@ -377,12 +388,12 @@ function inWords( num ) {
377
388
  }
378
389
 
379
390
 
380
- async function standardPrice( client, group ) {
391
+ async function standardPrice( group ) {
381
392
  const currentMonthDays = dayjs().daysInMonth();
382
393
  let products = await dailyPricingService.aggregate( [
383
394
  {
384
395
  $match: {
385
- clientId: client,
396
+ clientId: group.clientId,
386
397
  },
387
398
  },
388
399
  {
@@ -473,7 +484,7 @@ async function standardPrice( client, group ) {
473
484
  {
474
485
  $lookup: {
475
486
  from: 'basepricings',
476
- let: { clientId: client },
487
+ let: { clientId: group.clientId },
477
488
  pipeline: [
478
489
  {
479
490
  $match: {
@@ -601,12 +612,12 @@ async function standardPrice( client, group ) {
601
612
  }
602
613
 
603
614
 
604
- async function stepPrice( client, group, res ) {
615
+ async function stepPrice( group ) {
605
616
  const currentMonthDays = dayjs().daysInMonth();
606
617
  let products = await dailyPricingService.aggregate( [
607
618
  {
608
619
  $match: {
609
- clientId: client,
620
+ clientId: group.clientId,
610
621
  },
611
622
  },
612
623
  {
@@ -701,7 +712,7 @@ async function stepPrice( client, group, res ) {
701
712
 
702
713
 
703
714
  ] );
704
- let stepPrice = await basePricingModel.findOne( { clientId: client } );
715
+ let stepPrice = await basepricingService.findOne( { clientId: client } );
705
716
  let data = products;
706
717
  let pricing = stepPrice.step;
707
718
 
@@ -772,7 +783,6 @@ async function stepPrice( client, group, res ) {
772
783
  };
773
784
  } );
774
785
 
775
- // return res.sendSuccess( finalresult );
776
786
  return finalresult;
777
787
  }
778
788
 
@@ -813,7 +823,7 @@ export async function clientInvoiceList( req, res ) {
813
823
  $project: {
814
824
  clientName: '$clientDetails.clientName',
815
825
  logo: '$clientDetails.logo',
816
- currencyType: '$clientDetails.currencyType',
826
+ currencyType: '$currency',
817
827
  invoice: 1,
818
828
  stores: 1,
819
829
  totalAmount: 1,
@@ -821,6 +831,7 @@ export async function clientInvoiceList( req, res ) {
821
831
  status: 1,
822
832
  paymentStatus: 1,
823
833
  clientId: 1,
834
+ billingDate: 1,
824
835
  },
825
836
  },
826
837
  ];
@@ -841,6 +852,28 @@ export async function clientInvoiceList( req, res ) {
841
852
  } );
842
853
  }
843
854
  let count = await invoiceService.aggregate( query );
855
+ if ( count.length == 0 ) {
856
+ return res.sendError( 'No data', 204 );
857
+ }
858
+
859
+ if ( req.body.export ) {
860
+ const exportdata = [];
861
+ count.forEach( ( element ) => {
862
+ exportdata.push( {
863
+ 'Client': element.clientName,
864
+ 'Invoice #': element.invoice,
865
+ 'Billing date': dayjs( element.billingDate ).format( 'DD MMM, YYYY' ),
866
+ 'Group Name': element.groupName,
867
+ 'Amount': element.totalAmount,
868
+ 'Stores': element.stores,
869
+ 'Payment Status': element.paymentStatus,
870
+ 'Approval Status': element.status,
871
+
872
+ } );
873
+ } );
874
+ await download( exportdata, res );
875
+ return;
876
+ }
844
877
  if ( req.body.limit && req.body.offset && !req.body.export ) {
845
878
  query.push(
846
879
  { $skip: ( req.body.offset - 1 ) * req.body.limit },
@@ -850,18 +883,129 @@ export async function clientInvoiceList( req, res ) {
850
883
  let invoiceList = await invoiceService.aggregate( query );
851
884
  const bucket = JSON.parse( process.env.BUCKET );
852
885
  for ( let client of invoiceList ) {
853
- const isLogoExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/logo/${client?.logo}` } );
854
- if ( isLogoExist ) {
855
- client.logo = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/logo/${client?.logo}` } );
886
+ if ( client?.logo&&client?.logo!='' ) {
887
+ const isLogoExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/logo/${client?.logo}` } );
888
+ if ( isLogoExist ) {
889
+ client.logo = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/logo/${client?.logo}` } );
890
+ } else {
891
+ client.logo = '';
892
+ }
856
893
  } else {
857
894
  client.logo = '';
858
895
  }
859
- // return client;
860
896
  }
861
-
862
897
  res.sendSuccess( { count: count.length, data: invoiceList } );
863
898
  } catch ( error ) {
864
899
  logger.error( { error: error, function: 'clientInvoiceList' } );
865
900
  return res.sendError( error, 500 );
866
901
  }
867
902
  }
903
+
904
+
905
+ export async function creditTransactionlist( req, res ) {
906
+ try {
907
+ let query = [ {
908
+ $match: {
909
+ clientId: { $in: req.body.clientId },
910
+ },
911
+ }, {
912
+ $lookup: {
913
+ from: 'clients',
914
+ let: { clientId: '$clientId' },
915
+ pipeline: [
916
+ {
917
+ $match: {
918
+ $expr: {
919
+ $eq: [ '$clientId', '$$clientId' ],
920
+ },
921
+ },
922
+ },
923
+ {
924
+ $project: {
925
+ clientName: 1,
926
+ logo: '$profileDetails.logo',
927
+ currencyType: '$paymentInvoice.currencyType',
928
+ },
929
+ },
930
+ ],
931
+ as: 'clientDetails',
932
+ },
933
+ },
934
+ {
935
+ $unwind: { path: '$clientDetails', preserveNullAndEmptyArrays: true },
936
+ },
937
+ {
938
+ $project: {
939
+ clientName: '$clientDetails.clientName',
940
+ logo: '$clientDetails.logo',
941
+ currencyType: '$clientDetails.currencyType',
942
+ clientId: 1,
943
+ credit: 1,
944
+ },
945
+ },
946
+ ];
947
+ if ( req.body.searchValue && req.body.searchValue != '' ) {
948
+ query.push( {
949
+ $match: {
950
+ $or: [
951
+ { clientName: { $regex: req.body.searchValue, $options: 'i' } },
952
+ { paymentStatus: { $regex: req.body.searchValue, $options: 'i' } },
953
+ ],
954
+ },
955
+ } );
956
+ }
957
+ if ( req.body.sortColumName && req.body.sortColumName !== '' && req.body.sortBy ) {
958
+ query.push( {
959
+ $sort: { [req.body.sortColumName]: req.body.sortBy },
960
+ } );
961
+ }
962
+ let count = await paymentAccountService.aggregate( query );
963
+ if ( req.body.export ) {
964
+ const exportdata = [];
965
+ count.forEach( ( element ) => {
966
+ exportdata.push( {
967
+ 'Client': element.clientName,
968
+ 'Balance Credits': element.credit,
969
+ } );
970
+ } );
971
+ await download( exportdata, res );
972
+ return;
973
+ }
974
+ if ( req.body.limit && req.body.offset && !req.body.export ) {
975
+ query.push(
976
+ { $skip: ( req.body.offset - 1 ) * req.body.limit },
977
+ { $limit: Number( req.body.limit ) },
978
+ );
979
+ }
980
+ let TransactionsList= await paymentAccountService.aggregate( query );
981
+ const bucket = JSON.parse( process.env.BUCKET );
982
+ for ( let client of TransactionsList ) {
983
+ if ( client?.logo&&client?.logo!='' ) {
984
+ const isLogoExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/logo/${client?.logo}` } );
985
+ if ( isLogoExist ) {
986
+ client.logo = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/logo/${client?.logo}` } );
987
+ } else {
988
+ client.logo = '';
989
+ }
990
+ } else {
991
+ client.logo = '';
992
+ }
993
+ }
994
+
995
+
996
+ res.sendSuccess( { count: count.length, data: TransactionsList } );
997
+ } catch ( error ) {
998
+ logger.error( { error: error, function: 'creditTransactionlist' } );
999
+ return res.sendError( error, 500 );
1000
+ }
1001
+ }
1002
+
1003
+ export async function pendingInvoices( req, res ) {
1004
+ try {
1005
+ let invoicelist = await invoiceService.find( { clientId: req.body.clientId, status: 'approved', paymentStatus: 'unpaid' } );
1006
+ res.sendSuccess( invoicelist );
1007
+ } catch ( error ) {
1008
+ logger.error( { error: error, function: 'pendingInvoices' } );
1009
+ return res.sendError( error, 500 );
1010
+ }
1011
+ }