tango-app-api-payment-subscription 3.0.43-dev → 3.0.45-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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  /* eslint-disable new-cap */
3
- import { logger, download, sendEmailWithSES, appConfig, insertOpenSearchData } from 'tango-app-api-middleware';
3
+ import { logger, download, sendEmailWithSES, appConfig, insertOpenSearchData, getOpenSearchData, updateOpenSearchData, getOpenSearchById } from 'tango-app-api-middleware';
4
4
  import * as paymentService from '../services/clientPayment.services.js';
5
5
  import * as basePriceService from '../services/basePrice.service.js';
6
6
  import * as storeService from '../services/store.service.js';
@@ -13,16 +13,18 @@ import dayjs from 'dayjs';
13
13
  import Handlebars from 'handlebars';
14
14
  import fs from 'fs';
15
15
  import path from 'path';
16
- import { JSDOM } from 'jsdom';
17
- import pdfMake from 'pdfmake';
18
- import htmlToPdfmake from 'html-to-pdfmake';
16
+ // import { JSDOM } from 'jsdom';
17
+ // import pdfMake from 'pdfmake';
18
+ // import htmlToPdfmake from 'html-to-pdfmake';
19
19
  import axios from 'axios';
20
-
20
+ import htmlpdf from 'html-pdf-node';
21
21
  export const addBilling = async ( req, res ) => {
22
22
  try {
23
23
  let params = {
24
24
  'billingDetails.gstNumber': req.body.gstNo,
25
25
  'billingDetails.billingAddress': req.body.billingAddress,
26
+ 'billingDetails.companyName': req.body.companyName,
27
+ 'billingDetails.PlaceOfSupply': req.body.PlaceOfSupply,
26
28
  };
27
29
  let result = await paymentService.updateOne( { clientId: req.body.clientId }, params );
28
30
  if ( result.modifiedCount ) {
@@ -45,7 +47,7 @@ export const addBilling = async ( req, res ) => {
45
47
  changes: [ 'Billing Address', 'Gst Number' ],
46
48
  eventType: 'update',
47
49
  };
48
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
50
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
49
51
  return res.sendSuccess( { message: 'Billing Details Added Successfully', data: resultData } );
50
52
  } else {
51
53
  logger.error( 'Error Occurs WHile updating billing Details' );
@@ -152,7 +154,7 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
152
154
  element.toolTip = 'Trial Expired';
153
155
  element.active = true;
154
156
  } else {
155
- trialProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': differenceInDays +' days trial left' } );
157
+ trialProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': differenceInDays + ' days trial left' } );
156
158
  element.toolTip = 'On Trial';
157
159
  element.active = true;
158
160
  }
@@ -173,7 +175,7 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
173
175
  let getPI = false;
174
176
  if ( getPendingInvoice.length > 0 ) {
175
177
  if ( getPendingInvoice[0].billingDate >= currentDate ) {
176
- getPI= false;
178
+ getPI = false;
177
179
  } else {
178
180
  getPI = true;
179
181
  }
@@ -202,7 +204,7 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
202
204
  currentPlanInfo.expiredProducts = expiredProducts || '--';
203
205
  currentPlanInfo.product = activeProducts || '--';
204
206
  currentPlanInfo.pendingClientRequest = getPCR;
205
- currentPlanInfo.currencyType = clientInfo[0].paymentInvoice.currencyType;
207
+ currentPlanInfo.currencyType = clientInfo[0].paymentInvoice && clientInfo[0].paymentInvoice.currencyType;
206
208
  currentPlanInfo.dollarPrice = await convertINRtoUSD( clientInfo[0].price );
207
209
  let data = {
208
210
  _id: clientInfo[0]._id,
@@ -273,7 +275,7 @@ async function calculatePricing( req, res ) {
273
275
  productDiscounts.push( getProduct.discoutPercentage );
274
276
  }
275
277
  let stage = 0;
276
- if ( input.storesCount == '1-25' ) {
278
+ if ( input.storesCount == '2-25' ) {
277
279
  stage = 0;
278
280
  } else if ( input.storesCount == '26-50' ) {
279
281
  stage = 1;
@@ -298,7 +300,9 @@ async function calculatePricing( req, res ) {
298
300
  } else if ( input.storesCount == '2000+' ) {
299
301
  stage = 9;
300
302
  }
301
- let discountprice = Math.round( basicprice * Math.pow( 0.9, stage ) );
303
+
304
+
305
+ let discountprice = Math.round( basicprice * ( Math.pow( 0.92, stage ) )/10 )*10;
302
306
  dummy.push( discountprice );
303
307
  OriginalPrice = OriginalPrice + discountprice;
304
308
  finalPrice = finalPrice + discountprice;
@@ -426,7 +430,7 @@ export const updateSubscription = async ( req, res ) => {
426
430
  changes: [ 'Name', 'Description', 'Category' ],
427
431
  eventType: 'insert',
428
432
  };
429
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
433
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
430
434
  }
431
435
  }
432
436
  if ( item.type == 'subscription' ) {
@@ -436,6 +440,25 @@ export const updateSubscription = async ( req, res ) => {
436
440
  subscribedDate: new Date(),
437
441
  status: 'live',
438
442
  } );
443
+ let productObj = {
444
+ userName: req.user?.userName,
445
+ email: req.user?.email,
446
+ clientId: requestBody.clientId,
447
+ clientNotification: false,
448
+ adminNotification: true,
449
+ logSubType: 'Your subscription is now active! Get ready to maximize your instore sales potential with the Tangoeye suite',
450
+ category: 'Brand Activity Log',
451
+ features: 'Subscription',
452
+ // title: 'Subscribed',
453
+ alertCta: [],
454
+ markasRead: false,
455
+ logType: 'Subscribed',
456
+ showPushNotification: true,
457
+ changes: [ 'Plan Details', 'Price', 'Price Type' ],
458
+ eventType: 'update',
459
+ date: new Date(),
460
+ };
461
+ insertOpenSearchData( appConfig.opensearch.activityLog, productObj );
439
462
  } else {
440
463
  clientProducts[existsIndex].status = 'live';
441
464
  clientProducts[existsIndex].subscribedDate = new Date();
@@ -462,7 +485,7 @@ export const updateSubscription = async ( req, res ) => {
462
485
  };
463
486
  let pricingDetails = await calculatePricing( req, res );
464
487
  if ( subscriptionCount ) {
465
- let userDetails= await userService.findOne( { clientId: requestBody.clientId, role: 'superadmin' } );
488
+ let userDetails = await userService.findOne( { clientId: requestBody.clientId, role: 'superadmin' } );
466
489
  if ( userDetails ) {
467
490
  let data = {
468
491
  userName: userDetails.userName,
@@ -488,17 +511,17 @@ export const updateSubscription = async ( req, res ) => {
488
511
  };
489
512
 
490
513
  let result = await paymentService.updateOne( { clientId: req.params.clientId }, data );
491
- const logObj = {
492
- clientId: req.body.clientId,
493
- userName: req.user?.userName,
494
- email: req.user?.email,
495
- date: new Date(),
496
- logType: 'billing',
497
- logSubType: 'Subscrption Details updated',
498
- changes: [ 'Plan Details', 'Price', 'Price Type' ],
499
- eventType: 'update',
500
- };
501
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
514
+ // const logObj = {
515
+ // clientId: req.body.clientId,
516
+ // userName: req.user?.userName,
517
+ // email: req.user?.email,
518
+ // date: new Date(),
519
+ // logType: 'billing',
520
+ // logSubType: 'Subscrption Details updated',
521
+ // changes: [ 'Plan Details', 'Price', 'Price Type' ],
522
+ // eventType: 'update',
523
+ // };
524
+ // insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
502
525
  let storeProduct = clientProducts.map( ( item ) => item.productName );
503
526
  await storeService.updateMany( { clientId: req.params.clientId }, { product: storeProduct } );
504
527
 
@@ -552,7 +575,7 @@ export const updateSubscription = async ( req, res ) => {
552
575
 
553
576
  export const trialProductList = async ( req, res ) => {
554
577
  try {
555
- let query =[
578
+ let query = [
556
579
  {
557
580
  $match: {
558
581
  clientId: req.query.clientId,
@@ -619,7 +642,7 @@ export const unsubscribeProduct = async ( req, res ) => {
619
642
  changes: [ 'Reason', 'Description', 'Category' ],
620
643
  eventType: 'insert',
621
644
  };
622
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
645
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
623
646
 
624
647
  return res.sendSuccess( 'Request Send Successfully' );
625
648
  } catch ( e ) {
@@ -653,7 +676,7 @@ export const trialExtendRequest = async ( req, res ) => {
653
676
  changes: [ 'Name', 'Description', 'Category' ],
654
677
  eventType: 'insert',
655
678
  };
656
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
679
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
657
680
 
658
681
  return res.sendSuccess( 'Request Send Successfully' );
659
682
  } catch ( e ) {
@@ -689,7 +712,7 @@ export const trialRequest = async ( req, res ) => {
689
712
  changes: [ 'Name', 'Description', 'Category' ],
690
713
  eventType: 'insert',
691
714
  };
692
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
715
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
693
716
 
694
717
  return res.sendSuccess( 'Request Send Successfully' );
695
718
  } catch ( e ) {
@@ -717,6 +740,8 @@ export const invoiceDetails = async ( req, res ) => {
717
740
  paymentCycle: clientInvoiceDetails?.paymentInvoice?.paymentCycle || '',
718
741
  currencyType: clientInvoiceDetails?.paymentInvoice?.currencyType || '',
719
742
  invoiceTo: clientInvoiceDetails?.paymentInvoice?.invoiceTo || [],
743
+ invoiceCC: clientInvoiceDetails?.paymentInvoice?.invoiceCC || [],
744
+ PomNumber: clientInvoiceDetails?.paymentInvoice?.PomNumber || [],
720
745
  paymentAgreementTo: clientInvoiceDetails?.paymentInvoice?.paymentAgreementTo || [],
721
746
  invoiceOn: clientInvoiceDetails?.paymentInvoice?.invoiceOn || '',
722
747
  extendPaymentPeriodDays: clientInvoiceDetails?.paymentInvoice?.extendPaymentPeriodDays || '',
@@ -741,6 +766,9 @@ export const updateInvoiceDetails = async ( req, res ) => {
741
766
  clientInvoiceDetails.paymentInvoice.paymentCycle = data.paymentCycle;
742
767
  clientInvoiceDetails.paymentInvoice.currencyType = data.currencyType;
743
768
  clientInvoiceDetails.paymentInvoice.invoiceTo = data.invoiceTo;
769
+ clientInvoiceDetails.paymentInvoice.invoiceCC = data.invoiceCC;
770
+ clientInvoiceDetails.paymentInvoice.invoiceCC = data.invoiceCC;
771
+ clientInvoiceDetails.paymentInvoice.PomNumber = data.PomNumber;
744
772
  clientInvoiceDetails.paymentInvoice.paymentAgreementTo = data.paymentAgreementTo;
745
773
  clientInvoiceDetails.paymentInvoice.invoiceOn = data.invoiceOn;
746
774
  clientInvoiceDetails.paymentInvoice.extendPaymentPeriodDays = data.extendPaymentPeriodDays;
@@ -755,7 +783,7 @@ export const updateInvoiceDetails = async ( req, res ) => {
755
783
  changes: [ 'Pro Rate', 'Payment Type', 'Payment Cycle', 'Currency Type', 'Invoice To', 'Payment Agreement To', 'Invoice On', 'Extend Payment PeriodDays' ],
756
784
  eventType: 'update',
757
785
  };
758
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
786
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
759
787
  return res.sendSuccess( 'Invoice Updated Successfully' );
760
788
  } ).catch( ( e ) => {
761
789
  return res.sendError( e, 500 );
@@ -808,7 +836,7 @@ export const notificationList = async ( req, res ) => {
808
836
  let date = dayjs().startOf( 'day' );
809
837
  let days = date.diff( startDate, 'day' );
810
838
  let totalDays = endDate.diff( startDate, 'day' );
811
- let percentage = Math.round( ( days / totalDays )* 100 );
839
+ let percentage = Math.round( ( days / totalDays ) * 100 );
812
840
  let leftDays = endDate.diff( date, 'day' );
813
841
  notificationList.push( {
814
842
  product: item.product.productName,
@@ -853,6 +881,25 @@ export const trialApproval = async ( req, res ) => {
853
881
  requestData.status = 'completed';
854
882
  requestData.save().then( async () => {
855
883
  if ( req.body.type == 'approve' ) {
884
+ let logObj = {
885
+ userName: req.user?.userName,
886
+ email: req.user?.email,
887
+ clientId: requestData.clientId,
888
+ clientNotification: false,
889
+ adminNotification: true,
890
+ logSubType: 'Subscription - Your 14 Days free trial has been started',
891
+ category: 'Brand Activity Log',
892
+ features: 'Subscription',
893
+ // title: 'Start Trial',
894
+ alertCta: [],
895
+ markasRead: false,
896
+ logType: 'Start Trial',
897
+ showPushNotification: true,
898
+ date: new Date(),
899
+ changes: [ 'Plan Details' ],
900
+ eventType: 'update',
901
+ };
902
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
856
903
  let clientProducts = await paymentService.findOne( { clientId: requestData.clientId }, { planDetails: 1 } );
857
904
  if ( clientProducts?.planDetails.subscriptionType == 'free' ) {
858
905
  clientProducts.planDetails.subscriptionType = 'premium';
@@ -877,13 +924,13 @@ export const trialApproval = async ( req, res ) => {
877
924
  await storeService.addremoveElement( { clientId: requestData.clientId }, { $push: { product: requestData.name } } );
878
925
  req.body.clientId = requestData.clientId;
879
926
  updatePricing( req, res, true );
880
- let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
927
+ let userDetails = await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
881
928
  let [ firstWord, secondWord ] = requestData.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
882
929
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
883
930
  if ( userDetails ) {
884
931
  let data = {
885
932
  userName: userDetails.userName,
886
- product: firstWord +' '+ secondWord,
933
+ product: firstWord + ' ' + secondWord,
887
934
  domain: appConfig.url.domain,
888
935
  };
889
936
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialInitiateEmail.hbs', 'utf8' );
@@ -934,17 +981,17 @@ export const trialApproval = async ( req, res ) => {
934
981
  logger.error( { error: error, function: 'oldBulkStoreUpdate' } );
935
982
  } );
936
983
  }
937
- const logObj = {
938
- clientId: req.body.clientId,
939
- userName: req.user?.userName,
940
- email: req.user?.email,
941
- date: new Date(),
942
- logType: 'billing',
943
- logSubType: 'Trial Approved',
944
- changes: [ 'status' ],
945
- eventType: 'update',
946
- };
947
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
984
+ // const logObj = {
985
+ // clientId: req.body.clientId,
986
+ // userName: req.user?.userName,
987
+ // email: req.user?.email,
988
+ // date: new Date(),
989
+ // logType: 'billing',
990
+ // logSubType: 'Trial Approved',
991
+ // changes: [ 'status' ],
992
+ // eventType: 'update',
993
+ // };
994
+ // insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
948
995
  return res.sendSuccess( 'updated Successfully' );
949
996
  } );
950
997
  } catch ( e ) {
@@ -973,13 +1020,13 @@ export const trialExtendRequestApproval = async ( req, res ) => {
973
1020
  requestData.status = 'completed';
974
1021
  requestData.save();
975
1022
  }
976
- let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
1023
+ let userDetails = await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
977
1024
  if ( userDetails ) {
978
1025
  let [ firstWord, secondWord ] = req.body.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
979
1026
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
980
1027
  let data = {
981
1028
  userName: userDetails.userName,
982
- product: firstWord +' '+secondWord,
1029
+ product: firstWord + ' ' + secondWord,
983
1030
  days: req.body.days,
984
1031
  date: dayjs( trialDate ).format( 'YYYY-MM-DD' ),
985
1032
  domain: appConfig.url.domain,
@@ -996,17 +1043,36 @@ export const trialExtendRequestApproval = async ( req, res ) => {
996
1043
  };
997
1044
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
998
1045
  }
999
- const logObj = {
1000
- clientId: req.body.clientId,
1046
+ let notifyObj = {
1001
1047
  userName: req.user?.userName,
1002
1048
  email: req.user?.email,
1049
+ clientId: req.body.clientId,
1050
+ clientNotification: false,
1051
+ adminNotification: true,
1052
+ logSubType: `Your Trial has been extended for ${req.body.days} days, explore the service with no extra charge and keep unlocking better insights`,
1053
+ category: 'Brand Activity Log',
1054
+ features: 'Subscription',
1055
+ // title: 'Trial Extend',
1056
+ alertCta: [],
1057
+ markasRead: false,
1058
+ logType: 'Trial Extend',
1059
+ showPushNotification: true,
1003
1060
  date: new Date(),
1004
- logType: 'billing',
1005
- logSubType: 'Trial Extend Approved',
1006
1061
  changes: [ 'status' ],
1007
1062
  eventType: 'update',
1008
1063
  };
1009
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1064
+ insertOpenSearchData( appConfig.opensearch.activityLog, notifyObj );
1065
+ // const logObj = {
1066
+ // clientId: req.body.clientId,
1067
+ // userName: req.user?.userName,
1068
+ // email: req.user?.email,
1069
+ // date: new Date(),
1070
+ // logType: 'billing',
1071
+ // logSubType: 'Trial Extend Approved',
1072
+ // changes: [ 'status' ],
1073
+ // eventType: 'update',
1074
+ // };
1075
+ // insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1010
1076
  return res.sendSuccess( 'Trial Extended Successfully' );
1011
1077
  } ).catch( ( e ) => {
1012
1078
  logger.error( { error: e, function: 'trialExtendRequestApproval' } );
@@ -1043,11 +1109,31 @@ export const productSubscribe = async ( req, res ) => {
1043
1109
  let removeProducts = req.body.product.filter( ( item ) => item.type == 'unsubscribe' ).map( ( item ) => item.name );
1044
1110
  let productList = product.map( ( item ) => item.productName );
1045
1111
  for ( let item of req.body.product ) {
1046
- if ( productList.includes( item.name ) && item.type =='unsubscribe' ) {
1112
+ if ( productList.includes( item.name ) && item.type == 'unsubscribe' ) {
1047
1113
  await storeService.addremoveElement( { clientId: clientInfo.clientId, product: { $in: item.name } }, { $pull: { product: item.name } } );
1114
+ await clientRequestService.deleteOne( { clientId: clientInfo.clientId, status: 'pending', name: item.name } );
1048
1115
  }
1049
1116
  if ( !productList.includes( item.name ) && [ 'trial', 'subscription' ].includes( item.type ) ) {
1050
1117
  if ( item.type == 'trial' ) {
1118
+ let logObj = {
1119
+ userName: req.user?.userName,
1120
+ email: req.user?.email,
1121
+ clientId: clientInfo.clientId,
1122
+ clientNotification: false,
1123
+ adminNotification: true,
1124
+ logSubType: 'Subscription - Your 14 Days free trial has been started',
1125
+ category: 'Brand Activity Log',
1126
+ features: 'Subscription',
1127
+ // title: 'Start Trial',
1128
+ alertCta: [],
1129
+ markasRead: false,
1130
+ logType: 'Start Trial',
1131
+ showPushNotification: true,
1132
+ date: new Date(),
1133
+ changes: [ 'Plan Details' ],
1134
+ eventType: 'update',
1135
+ };
1136
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1051
1137
  product.push( {
1052
1138
  productName: item.name,
1053
1139
  trialStartDate: new Date(),
@@ -1056,9 +1142,28 @@ export const productSubscribe = async ( req, res ) => {
1056
1142
  } );
1057
1143
  let [ firstWord, secondWord ] = item.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1058
1144
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
1059
- let productName =firstWord + ' ' +secondWord;
1145
+ let productName = firstWord + ' ' + secondWord;
1060
1146
  trialProduct.push( productName );
1061
1147
  } else {
1148
+ let logObj = {
1149
+ userName: req.user?.userName,
1150
+ email: req.user?.email,
1151
+ clientId: clientInfo.clientId,
1152
+ clientNotification: false,
1153
+ adminNotification: true,
1154
+ logSubType: 'Your subscription is now active! Get ready to maximize your instore sales potential with the Tangoeye suite',
1155
+ category: 'Brand Activity Log',
1156
+ features: 'Subscription',
1157
+ // title: 'Subscribed',
1158
+ alertCta: [],
1159
+ markasRead: false,
1160
+ logType: 'Subscribed',
1161
+ showPushNotification: true,
1162
+ date: new Date(),
1163
+ changes: [ 'Plan Details' ],
1164
+ eventType: 'update',
1165
+ };
1166
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1062
1167
  product.push( {
1063
1168
  productName: item.name,
1064
1169
  subscribedDate: new Date(),
@@ -1082,7 +1187,7 @@ export const productSubscribe = async ( req, res ) => {
1082
1187
  if ( product.length > 1 ) {
1083
1188
  clientInfo.planDetails.subscriptionType = 'premium';
1084
1189
  }
1085
- let userDetails= await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
1190
+ let userDetails = await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
1086
1191
  if ( subscriptionCount ) {
1087
1192
  if ( userDetails ) {
1088
1193
  let data = {
@@ -1161,17 +1266,17 @@ export const productSubscribe = async ( req, res ) => {
1161
1266
  logger.error( { error: error, function: 'oldBulkStoreUpdate' } );
1162
1267
  } );
1163
1268
  } );
1164
- const logObj = {
1165
- clientId: req.body.clientId,
1166
- userName: req.user?.userName,
1167
- email: req.user?.email,
1168
- date: new Date(),
1169
- logType: 'billing',
1170
- logSubType: 'Product subscribe and unsubscribe',
1171
- changes: [ 'Plan Details' ],
1172
- eventType: 'update',
1173
- };
1174
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1269
+ // const logObj = {
1270
+ // clientId: req.body.clientId,
1271
+ // userName: req.user?.userName,
1272
+ // email: req.user?.email,
1273
+ // date: new Date(),
1274
+ // logType: 'billing',
1275
+ // logSubType: 'Product subscribe and unsubscribe',
1276
+ // changes: [ 'Plan Details' ],
1277
+ // eventType: 'update',
1278
+ // };
1279
+ // insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1175
1280
  return res.sendSuccess( 'Product Subscribed Successfully' );
1176
1281
  } catch ( e ) {
1177
1282
  logger.error( { error: e, function: 'updateProductSubscribe' } );
@@ -1196,7 +1301,8 @@ export const unsubscribeApproval = async ( req, res ) => {
1196
1301
  clientProducts.save();
1197
1302
  await storeService.updateMany( { clientId: requestData.clientId }, { status: 'deactive' } );
1198
1303
  await userService.updateMany( { clientId: requestData.clientId }, { isActive: false } );
1199
- let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
1304
+ await clientRequestService.deleteMany( { clientId: requestData.clientId } );
1305
+ let userDetails = await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
1200
1306
  if ( userDetails ) {
1201
1307
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialUnsubscribeEmail.hbs', 'utf8' );
1202
1308
  const template = Handlebars.compile( templateHtml );
@@ -1221,7 +1327,7 @@ export const unsubscribeApproval = async ( req, res ) => {
1221
1327
  changes: [ 'status' ],
1222
1328
  eventType: 'update',
1223
1329
  };
1224
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1330
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1225
1331
  return res.sendSuccess( 'updated Successfully' );
1226
1332
  } );
1227
1333
  } catch ( e ) {
@@ -1463,7 +1569,7 @@ export const addStoreProduct = async ( req, res ) => {
1463
1569
  };
1464
1570
  let [ firstWord, secondWord ] = item.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1465
1571
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
1466
- let productName =firstWord + ' ' +secondWord;
1572
+ let productName = firstWord + ' ' + secondWord;
1467
1573
  trialProduct.push( productName );
1468
1574
  } else {
1469
1575
  clientProduct[productExistsIndex] = {
@@ -1483,8 +1589,28 @@ export const addStoreProduct = async ( req, res ) => {
1483
1589
  } );
1484
1590
  let [ firstWord, secondWord ] = item.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1485
1591
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
1486
- let productName =firstWord + ' ' +secondWord;
1592
+ let productName = firstWord + ' ' + secondWord;
1487
1593
  trialProduct.push( productName );
1594
+ let logObj = {
1595
+ userName: req.user?.userName,
1596
+ email: req.user?.email,
1597
+ clientId: req.body.clientId,
1598
+ clientNotification: false,
1599
+ adminNotification: true,
1600
+ logSubType: 'Subscription - Your 14 Days free trial has been started',
1601
+ category: 'Brand Activity Log',
1602
+ features: 'Subscription',
1603
+ // title: 'Start Trial',
1604
+ alertCta: [],
1605
+ markasRead: false,
1606
+ logType: 'Start Trial',
1607
+ showPushNotification: true,
1608
+ date: new Date(),
1609
+ changes: [ 'product' ],
1610
+ eventType: 'update',
1611
+
1612
+ };
1613
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1488
1614
  }
1489
1615
  if ( item.type == 'subscription' ) {
1490
1616
  clientProduct.push( {
@@ -1493,12 +1619,31 @@ export const addStoreProduct = async ( req, res ) => {
1493
1619
  status: 'live',
1494
1620
  } );
1495
1621
  subscriptionCount = subscriptionCount + 1;
1622
+ let logObj = {
1623
+ userName: req.user?.userName,
1624
+ email: req.user?.email,
1625
+ clientId: req.body.clientId,
1626
+ clientNotification: false,
1627
+ adminNotification: true,
1628
+ logSubType: 'Your subscription is now active! Get ready to maximize your instore sales potential with the Tangoeye suite',
1629
+ category: 'Brand Activity Log',
1630
+ features: 'Subscription',
1631
+ // title: 'Subscribed',
1632
+ alertCta: [],
1633
+ markasRead: false,
1634
+ logType: 'Subscribed',
1635
+ showPushNotification: true,
1636
+ date: new Date(),
1637
+ changes: [ 'product' ],
1638
+ eventType: 'update',
1639
+ };
1640
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1496
1641
  }
1497
1642
  }
1498
1643
  }
1499
1644
  },
1500
1645
  );
1501
- let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
1646
+ let userDetails = await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
1502
1647
  if ( subscriptionCount ) {
1503
1648
  if ( userDetails ) {
1504
1649
  let data = {
@@ -1560,17 +1705,17 @@ export const addStoreProduct = async ( req, res ) => {
1560
1705
  }
1561
1706
  await storeService.updateOne( { storeId: item.storeId, clientId: clientId }, { product: product } );
1562
1707
  } );
1563
- const logObj = {
1564
- clientId: clientId,
1565
- userName: req.user?.userName,
1566
- email: req.user?.email,
1567
- date: new Date(),
1568
- logType: 'billing',
1569
- logSubType: 'Store Prosuct Addition',
1570
- changes: [ 'product' ],
1571
- eventType: 'update',
1572
- };
1573
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1708
+ // const logObj = {
1709
+ // clientId: clientId,
1710
+ // userName: req.user?.userName,
1711
+ // email: req.user?.email,
1712
+ // date: new Date(),
1713
+ // logType: 'billing',
1714
+ // logSubType: 'Store Product Addition',
1715
+ // changes: [ 'product' ],
1716
+ // eventType: 'update',
1717
+ // };
1718
+ // insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1574
1719
  let products = clientInfo.planDetails.product.map( ( item ) => {
1575
1720
  let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1576
1721
  return firstWord.toLowerCase() + '_' + secondWord.toLowerCase();
@@ -1620,13 +1765,13 @@ export const invoiceList = async ( req, res ) => {
1620
1765
  req.body.limit = 10000;
1621
1766
  }
1622
1767
  let limit = req.body.limit || 10;
1623
- let offset = ( req.body.offset-1 ) || 0;
1768
+ let offset = ( req.body.offset - 1 ) || 0;
1624
1769
  let skip = limit * offset;
1625
1770
  let date;
1626
1771
  let endDate;
1627
1772
  if ( req.body.filter && req.body.filter == 'current' ) {
1628
1773
  date = new Date( dayjs().startOf( 'month' ).format( 'YYYY-MM-DD' ) );
1629
- endDate= new Date( dayjs().endOf( 'month' ).format( 'YYYY-MM-DD' ) );
1774
+ endDate = new Date( dayjs().endOf( 'month' ).format( 'YYYY-MM-DD' ) );
1630
1775
  }
1631
1776
  if ( req.body.filter && req.body.filter == 'prev' ) {
1632
1777
  date = new Date( dayjs().subtract( 1, 'month' ).startOf( 'month' ).format( 'YYYY-MM-DD' ) );
@@ -1634,7 +1779,7 @@ export const invoiceList = async ( req, res ) => {
1634
1779
  }
1635
1780
  if ( req.body.filter && req.body.filter == 'last' ) {
1636
1781
  date = new Date( dayjs().subtract( 2, 'month' ).startOf( 'month' ).format( 'YYYY-MM-DD' ) );
1637
- endDate= new Date( dayjs().endOf( 'month' ).format( 'YYYY-MM-DD' ) );
1782
+ endDate = new Date( dayjs().endOf( 'month' ).format( 'YYYY-MM-DD' ) );
1638
1783
  }
1639
1784
  let query = [];
1640
1785
  query = [
@@ -1694,7 +1839,7 @@ export const invoiceList = async ( req, res ) => {
1694
1839
  }
1695
1840
  invoiceDetails[0].data.forEach( ( item ) => {
1696
1841
  item.billingDate = dayjs( item.billingDate ).format( 'DD MMM, YYYY' );
1697
- if ( item.products?.length>0 ) {
1842
+ if ( item.products?.length > 0 ) {
1698
1843
  let newProducts = [];
1699
1844
  for ( let productIndex = 0; productIndex < item.products.length; productIndex++ ) {
1700
1845
  let [ firstWord, secondWord ] = item.products[productIndex]?.product?.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
@@ -1800,7 +1945,7 @@ export const priceList = async ( req, res ) => {
1800
1945
  } else {
1801
1946
  product.showImg = false;
1802
1947
  product.showEditDelete = false;
1803
- if ( index == productDetails.length-1 ) {
1948
+ if ( index == productDetails.length - 1 ) {
1804
1949
  if ( index != 0 ) {
1805
1950
  product.showImg = true;
1806
1951
  product.showEditDelete = true;
@@ -1815,7 +1960,7 @@ export const priceList = async ( req, res ) => {
1815
1960
  let rangeArray = product.storeRange.split( '-' );
1816
1961
  let startNumber = parseInt( rangeArray[0] );
1817
1962
  let endNumber = parseInt( rangeArray[1] );
1818
- let diff = endNumber - startNumber +1;
1963
+ let diff = endNumber - startNumber + 1;
1819
1964
  product.storeCount = diff;
1820
1965
  item.storeCount = item.storeCount - diff;
1821
1966
  }
@@ -1875,8 +2020,8 @@ export const pricingListUpdate = async ( req, res ) => {
1875
2020
  let productList;
1876
2021
  if ( req.body?.products && req.body?.products?.length ) {
1877
2022
  productList = JSON.parse( JSON.stringify( req.body ) );
1878
- let amount =0;
1879
- let origPrice=0;
2023
+ let amount = 0;
2024
+ let origPrice = 0;
1880
2025
  let IGST = 18;
1881
2026
  let CGST = 9;
1882
2027
  let SGST = 9;
@@ -1969,7 +2114,7 @@ export const pricingListUpdate = async ( req, res ) => {
1969
2114
  changes: keys,
1970
2115
  eventType: 'update',
1971
2116
  };
1972
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
2117
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
1973
2118
  return res.sendSuccess( 'Pricig Updated Successfully' );
1974
2119
  } );
1975
2120
  } catch ( e ) {
@@ -2024,10 +2169,10 @@ async function updatePricing( req, res, update ) {
2024
2169
  let clientId = req.body.clientId;
2025
2170
  let paymentInvoice = clientDetails.paymentInvoice;
2026
2171
  if ( !update ) {
2027
- let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
2172
+ let userDetails = await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
2028
2173
  paymentInvoice.invoiceTo = [ userDetails.email ];
2029
2174
  paymentInvoice.paymentAgreementTo = [ userDetails.email ];
2030
- paymentInvoice.currencyType = userDetails.countryCode == '91' ? 'inr': 'dollar';
2175
+ paymentInvoice.currencyType = userDetails.countryCode == '91' ? 'inr' : 'dollar';
2031
2176
  clientDetails.planDetails.product.forEach( ( item ) => {
2032
2177
  product.push( {
2033
2178
  productName: item.productName,
@@ -2051,9 +2196,9 @@ async function updatePricing( req, res, update ) {
2051
2196
  if ( subscriptionProduct.length ) {
2052
2197
  let invoiceCount = await invoiceService.count( { clientId: req.params.clientId, status: 'pending' } );
2053
2198
  if ( invoiceCount ) {
2054
- paymentStatus ='due';
2199
+ paymentStatus = 'due';
2055
2200
  } else {
2056
- paymentStatus ='unbilled';
2201
+ paymentStatus = 'unbilled';
2057
2202
  }
2058
2203
  }
2059
2204
  let details = {
@@ -2099,7 +2244,7 @@ export const updatedRevisedPrice = async ( req, res ) => {
2099
2244
  }
2100
2245
  amount = amount + item.price;
2101
2246
  } );
2102
- let invoiceDate= dayjs( invoiceDetails.createdAt ).format( 'DD MMM, YYYY' );
2247
+ let invoiceDate = dayjs( invoiceDetails.createdAt ).format( 'DD MMM, YYYY' );
2103
2248
  let days = clientDetails?.paymentInvoice?.extendPaymentPeriodDays || 10;
2104
2249
  let dueDate = invoiceDetails?.dueDate ? dayjs( invoiceDetails?.dueDate ).format( 'DD MMM, YYYY' ) : dayjs().add( days, 'days' ).format( 'DD MMM, YYYY' );
2105
2250
  let discountAmount = ( amount * req.body.discount ) / 100;
@@ -2143,7 +2288,7 @@ export const updatedRevisedPrice = async ( req, res ) => {
2143
2288
  changes: [ 'amount', 'revisedAmount', 'discount' ],
2144
2289
  eventType: 'update',
2145
2290
  };
2146
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
2291
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
2147
2292
  return res.sendSuccess( 'Credit notes Updated Successfully' );
2148
2293
  } );
2149
2294
  } catch ( e ) {
@@ -2204,7 +2349,7 @@ export const getRemindClients = async ( req, res ) => {
2204
2349
  let endDate = dayjs( item.trialEndDate ).startOf( 'day' ).add( 1, 'days' );
2205
2350
  let date = dayjs().startOf( 'day' );
2206
2351
  let leftDays = endDate.diff( date, 'day' );
2207
- let userDetails= await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2352
+ let userDetails = await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2208
2353
  if ( userDetails ) {
2209
2354
  if ( leftDays == 3 ) {
2210
2355
  let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
@@ -2214,6 +2359,23 @@ export const getRemindClients = async ( req, res ) => {
2214
2359
  product: firstWord + ' ' + secondWord,
2215
2360
  domain: appConfig.url.domain,
2216
2361
  };
2362
+ let logObj = {
2363
+ clientId: client.clientId,
2364
+ clientNotification: false,
2365
+ adminNotification: true,
2366
+ logSubType: 'Subscription - Your Free trial is about to expire in 3 days. Pleas make sure to subscribe to the products',
2367
+ category: 'Brand Activity Log',
2368
+ features: 'Subscription',
2369
+ // title: 'Trial reminder',
2370
+ alertCta: [ { buttonName: 'Subscribe now', redirectionUrl: 'manage/settings/payment-subscription' }, { buttonName: 'Remind me later', redirectionUrl: 'cancel' } ],
2371
+ markasRead: false,
2372
+ logType: 'Trial reminder',
2373
+ showPushNotification: true,
2374
+ date: new Date(),
2375
+ userName: userDetails?.userName,
2376
+ email: userDetails?.email,
2377
+ };
2378
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
2217
2379
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialReminderEmail.hbs', 'utf8' );
2218
2380
  const template = Handlebars.compile( templateHtml );
2219
2381
  const html = template( { data: data } );
@@ -2268,13 +2430,13 @@ export const getExpiredClientsOld = async ( req, res ) => {
2268
2430
  clientDetails.forEach( async ( client ) => {
2269
2431
  if ( client.planDetails?.product ) {
2270
2432
  let item = client.planDetails.product;
2271
- let userDetails= await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2433
+ let userDetails = await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2272
2434
  if ( userDetails ) {
2273
2435
  let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2274
2436
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
2275
2437
  let data = {
2276
2438
  userName: userDetails.userName,
2277
- product: firstWord +' '+secondWord,
2439
+ product: firstWord + ' ' + secondWord,
2278
2440
  domain: appConfig.url.domain,
2279
2441
  };
2280
2442
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialExpiredEmail.hbs', 'utf8' );
@@ -2310,7 +2472,7 @@ export const getExpiredClients = async ( req, res ) => {
2310
2472
  let endDate = dayjs( item.trialEndDate ).startOf( 'day' );
2311
2473
  let date = dayjs().startOf( 'day' );
2312
2474
  let leftDays = endDate.diff( date, 'day' );
2313
- let userDetails= await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2475
+ let userDetails = await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
2314
2476
  if ( userDetails ) {
2315
2477
  if ( leftDays == -1 ) {
2316
2478
  let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
@@ -2346,12 +2508,12 @@ export const getExpiredClients = async ( req, res ) => {
2346
2508
 
2347
2509
  export const invoiceDownload = async ( req, res ) => {
2348
2510
  try {
2349
- let invoiceDetails;
2511
+ let invoiceData;
2350
2512
  let invoiceInfo = await invoiceService.findOne( { _id: req.params.invoiceId } );
2351
2513
  if ( invoiceInfo ) {
2352
2514
  let clientDetails = await paymentService.findOne( { clientId: invoiceInfo.clientId } );
2353
2515
  let amount = 0;
2354
- invoiceInfo.products.forEach( ( item ) => {
2516
+ invoiceInfo.products.forEach( ( item, index ) => {
2355
2517
  let [ firstWord, secondWord ] = item.product.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2356
2518
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
2357
2519
  item.product.product = firstWord + ' ' + secondWord;
@@ -2359,60 +2521,141 @@ export const invoiceDownload = async ( req, res ) => {
2359
2521
  item.basePrice = convertINRtoUSD( item.basePrice );
2360
2522
  item.price = convertINRtoUSD( item.price );
2361
2523
  }
2524
+ item.index = index + 1;
2362
2525
  if ( clientDetails.priceType == 'step' ) {
2363
2526
  item.count = item.product.storeRange;
2364
2527
  }
2528
+
2365
2529
  amount = amount + item.price;
2530
+
2531
+ item.basePrice = item.basePrice.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } );
2532
+ item.price = item.price.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } );
2533
+ item.currency = clientDetails?.paymentInvoice?.currencyType == 'dollar' ? '$' : '₹';
2366
2534
  } );
2367
- let invoiceDate= dayjs( invoiceInfo.createdAt ).format( 'DD MMM, YYYY' );
2535
+ for ( let tax of invoiceInfo.tax ) {
2536
+ tax.taxAmount = tax.taxAmount.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } );
2537
+ }
2538
+ let invoiceDate = dayjs( invoiceInfo.createdAt ).format( 'DD/MM/YYYY' );
2368
2539
  let days = clientDetails?.paymentInvoice?.extendPaymentPeriodDays || 10;
2369
- let dueDate = invoiceInfo?.dueDate ? dayjs( invoiceInfo?.dueDate ).format( 'DD MMM, YYYY' ) : dayjs().add( days, 'days' ).format( 'DD MMM, YYYY' );
2540
+ let dueDate = invoiceInfo?.dueDate ? dayjs( invoiceInfo?.dueDate ).format( 'DD/MM/YYYY' ) : dayjs().add( days, 'days' ).format( 'DD/MM/YYYY' );
2370
2541
 
2371
- invoiceDetails = {
2542
+ invoiceInfo.totalAmount = invoiceInfo.totalAmount;
2543
+ let AmountinWords = inWords( invoiceInfo.totalAmount );
2544
+ invoiceData = {
2372
2545
  ...invoiceInfo._doc,
2373
2546
  clientName: clientDetails.clientName,
2374
2547
  extendDays: clientDetails.paymentInvoice.extendPaymentPeriodDays,
2375
2548
  address: clientDetails.billingDetails.billingAddress,
2376
- amount: amount,
2549
+ subtotal: amount.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ),
2550
+ companyName: invoiceInfo.companyName,
2551
+ companyAddress: invoiceInfo.companyAddress,
2552
+ PlaceOfSupply: invoiceInfo.PlaceOfSupply,
2553
+ GSTNumber: invoiceInfo.GSTNumber,
2554
+ PoNum: '',
2555
+ amountwords: AmountinWords,
2556
+ Terms: `Term ${clientDetails.paymentInvoice.extendPaymentPeriodDays}`,
2377
2557
  currencyType: clientDetails?.paymentInvoice?.currencyType == 'dollar' ? '$' : '₹',
2378
- // total: ( amount + ( parseFloat( amount ) * 0.19 ) ).toFixed( 2 ),
2379
- total: amount.toFixed( 2 ),
2558
+ totalAmount: invoiceInfo.totalAmount.toLocaleString( 'en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ),
2380
2559
  invoiceDate,
2381
2560
  dueDate,
2382
2561
  };
2383
- }
2384
- const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf.hbs', 'utf8' );
2385
- const template = Handlebars.compile( templateHtml );
2386
- const html = template( { data: invoiceDetails } );
2387
- let fonts = {
2388
- Helvetica: {
2389
- normal: 'Helvetica',
2390
- bold: 'Helvetica-Bold',
2391
- italics: 'Helvetica-Oblique',
2392
- bolditalics: 'Helvetica-BoldOblique',
2393
- },
2394
- };
2395
- let printer = new pdfMake( fonts );
2396
-
2397
- let { window } = new JSDOM( '' );
2398
- const htmlTemplate = htmlToPdfmake( html, { window: window, tableAutoSize: true } );
2399
- const docDefinition = {
2400
- pageMargins: [ 40, 10, 40, 40 ],
2401
- content: htmlTemplate,
2402
- defaultStyle: {
2403
- font: 'Helvetica',
2404
- },
2405
- };
2406
- let pdfDoc = printer.createPdfKitDocument( docDefinition );
2407
- res.setHeader( 'Content-disposition', `attachment; filename=Report_1.pdf` );
2408
- res.setHeader( 'Content-Type', 'application/pdf' );
2409
- pdfDoc.pipe( res );
2410
- pdfDoc.end();
2562
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf.hbs', 'utf8' );
2563
+ const template = Handlebars.compile( templateHtml );
2564
+ const html = template( { ...invoiceData } );
2565
+ let file = {
2566
+ content: html,
2567
+ };
2568
+ let options = {
2569
+ format: 'A4', margin: {
2570
+ top: '0.5in',
2571
+ right: '0.5in',
2572
+ bottom: '0.5in',
2573
+ left: '0.5in',
2574
+ },
2575
+ printBackground: true, preferCSSPageSize: true,
2576
+ };
2577
+ const date = dayjs( invoiceData.monthOfbilling, 'MM' );
2578
+ const monthName = date.format( 'MMMM' );
2579
+
2580
+
2581
+ htmlpdf.generatePdf( file, options ).then( async function( pdfBuffer ) {
2582
+ if ( req.body.sendInvoice ) {
2583
+ let mailSubject = `Invoice for ${monthName} - Tango/${clientDetails.clientName}`;
2584
+ let mailbody = `<div>Dear Team,</div>
2585
+ <div style="margin-top:10px">
2586
+ Please find attached the Invoice for the month of ${monthName}'24.
2587
+ </div>
2588
+ <div style="margin-top:10px">
2589
+ Best Regards,
2590
+ </div>
2591
+ <div style="margin-top:5px">
2592
+ Tango Finance
2593
+ </div>`;
2594
+
2595
+ let filename = `${clientDetails.clientName}-${invoiceData.invoice}-${monthName}.pdf`;
2596
+ let attachments = {
2597
+ filename: `${filename}`,
2598
+ content: pdfBuffer,
2599
+ contentType: 'application/pdf', // e.g., 'application/pdf'
2600
+ };
2601
+ clientDetails.paymentInvoice.invoiceCC = [ ...clientDetails.paymentInvoice.invoiceCC, ...[ 'sireesha@tangotech.co.in' ] ];
2602
+ // return;
2603
+ const result = await sendEmailWithSES( clientDetails.paymentInvoice.invoiceTo, mailSubject, mailbody, attachments, 'no-reply@tangotech.ai', clientDetails.paymentInvoice.invoiceCC );
2604
+ if ( result ) {
2605
+ await invoiceService.updateOne( { _id: req.params.invoiceId }, { status: req.body.status } );
2606
+ return res.sendSuccess( result );
2607
+ }
2608
+ }
2609
+ res.set( 'Content-Disposition', 'attachment; filename="generated-pdf.pdf"' );
2610
+ res.set( 'Content-Type', 'application/pdf' );
2611
+ res.send( pdfBuffer );
2612
+ } );
2613
+ return;
2614
+ }
2615
+
2616
+
2617
+ // let fonts = {
2618
+ // Helvetica: {
2619
+ // normal: 'Helvetica',
2620
+ // bold: 'Helvetica-Bold',
2621
+ // italics: 'Helvetica-Oblique',
2622
+ // bolditalics: 'Helvetica-BoldOblique',
2623
+ // },
2624
+ // };
2625
+ // let printer = new pdfMake( fonts );
2626
+
2627
+ // let { window } = new JSDOM( '' );
2628
+ // const htmlTemplate = htmlToPdfmake( html, { window: window, tableAutoSize: true } );
2629
+ // const docDefinition = {
2630
+ // pageMargins: [ 40, 10, 40, 40 ],
2631
+ // content: htmlTemplate,
2632
+ // defaultStyle: {
2633
+ // font: 'Helvetica',
2634
+ // },
2635
+ // };
2636
+ // let pdfDoc = printer.createPdfKitDocument( docDefinition );
2637
+ // res.setHeader( 'Content-disposition', `attachment; filename=Report_1.pdf` );
2638
+ // res.setHeader( 'Content-Type', 'application/pdf' );
2639
+ // pdfDoc.pipe( res );
2640
+ // pdfDoc.end();
2411
2641
  } catch ( e ) {
2412
2642
  logger.error( { error: e, function: 'invoiceDownload' } );
2413
2643
  return res.sendError( e, 500 );
2414
2644
  }
2415
2645
  };
2646
+ function inWords( num ) {
2647
+ let a = [ '', 'one ', 'two ', 'three ', 'four ', 'five ', 'six ', 'seven ', 'eight ', 'nine ', 'ten ', 'eleven ', 'twelve ', 'thirteen ', 'fourteen ', 'fifteen ', 'sixteen ', 'seventeen ', 'eighteen ', 'nineteen ' ]; let b = [ '', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' ];
2648
+ if ( ( num = num.toString() ).length > 9 ) return 'overflow';
2649
+ let n = ( '000000000' + num ).substr( -9 ).match( /^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/ );
2650
+ if ( !n ) return; let str = '';
2651
+ str += ( n[1] != 0 ) ? ( a[Number( n[1] )] || b[n[1][0]] + ' ' + a[n[1][1]] ) + 'crore ' : '';
2652
+ str += ( n[2] != 0 ) ? ( a[Number( n[2] )] || b[n[2][0]] + ' ' + a[n[2][1]] ) + 'lakh ' : '';
2653
+ str += ( n[3] != 0 ) ? ( a[Number( n[3] )] || b[n[3][0]] + ' ' + a[n[3][1]] ) + 'thousand ' : '';
2654
+ str += ( n[4] != 0 ) ? ( a[Number( n[4] )] || b[n[4][0]] + ' ' + a[n[4][1]] ) + 'hundred ' : '';
2655
+ str += ( n[5] != 0 ) ? ( ( str != '' ) ? 'and ' : '' ) + ( a[Number( n[5] )] || b[n[5][0]] + ' ' + a[n[5][1]] ) : '';
2656
+
2657
+ return str.toLowerCase().split( ' ' ).map( ( word ) => word.charAt( 0 ).toUpperCase() + word.slice( 1 ) ).join( ' ' );
2658
+ }
2416
2659
 
2417
2660
  export const updateInvoiceStatus = async ( req, res ) => {
2418
2661
  try {
@@ -2442,7 +2685,7 @@ export const updateInvoiceStatus = async ( req, res ) => {
2442
2685
  changes: [ 'amount', 'paymentType', 'status' ],
2443
2686
  eventType: 'update',
2444
2687
  };
2445
- insertOpenSearchData( 'tango-retail-activity-logs', logObj );
2688
+ insertOpenSearchData( appConfig.opensearch.activityLog, logObj );
2446
2689
  return res.sendSuccess( 'Invoice updated Successfully' );
2447
2690
  } );
2448
2691
  } catch ( e ) {
@@ -2491,7 +2734,12 @@ export const invoiceCreate = async ( req, res ) => {
2491
2734
  export const dailyPricingInsert = async ( req, res ) => {
2492
2735
  try {
2493
2736
  let requestData = req.body;
2494
- let requestClient = requestData.clientId;
2737
+ let clientlist = await paymentService.find( { 'status': 'active' } );
2738
+ let requestClient = [];
2739
+
2740
+ for ( let client of clientlist ) {
2741
+ requestClient.push( client.clientId );
2742
+ }
2495
2743
  if ( requestData.clientId && requestClient.length > 0 ) {
2496
2744
  for ( let clientIndex = 0; clientIndex < requestClient.length; clientIndex++ ) {
2497
2745
  let getClient = await paymentService.findOne( { clientId: requestClient[clientIndex], status: 'active' } );
@@ -2502,55 +2750,57 @@ export const dailyPricingInsert = async ( req, res ) => {
2502
2750
  let storeList = [];
2503
2751
  for ( let storeIndex = 0; storeIndex < getStore.length; storeIndex++ ) {
2504
2752
  let productList = [];
2505
- let priceDetails = getClient.priceType == 'standard' ? getBaseprice.standard : getBaseprice.step;
2506
- for ( let storeProductIndex = 0; storeProductIndex < getStore[storeIndex].product.length; storeProductIndex++ ) {
2507
- let productDetails;
2508
- if ( getClient.priceType == 'standard' ) {
2509
- productDetails = priceDetails.find( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2510
- } else {
2511
- productDetails = priceDetails.find( ( item ) => {
2512
- let range = item.storeRange.split( '-' );
2513
- if ( parseInt( range[0] ) <= ( storeIndex + 1 ) && parseInt( range[1] ) >= ( storeIndex + 1 ) ) {
2514
- return ( item.productName == getStore[storeIndex].product[storeProductIndex] && parseInt( range[0] ) <= ( storeIndex + 1 ) && parseInt( range[1] ) >= ( storeIndex + 1 ) );
2753
+ if ( getBaseprice ) {
2754
+ let priceDetails = getClient.priceType == 'standard' ? getBaseprice.standard : getBaseprice.step;
2755
+ for ( let storeProductIndex = 0; storeProductIndex < getStore[storeIndex].product.length; storeProductIndex++ ) {
2756
+ let productDetails;
2757
+ if ( getClient.priceType == 'standard' ) {
2758
+ productDetails = priceDetails.find( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2759
+ } else {
2760
+ productDetails = priceDetails.find( ( item ) => {
2761
+ let range = item.storeRange.split( '-' );
2762
+ if ( parseInt( range[0] ) <= ( storeIndex + 1 ) && parseInt( range[1] ) >= ( storeIndex + 1 ) ) {
2763
+ return ( item.productName == getStore[storeIndex].product[storeProductIndex] && parseInt( range[0] ) <= ( storeIndex + 1 ) && parseInt( range[1] ) >= ( storeIndex + 1 ) );
2764
+ }
2765
+ } );
2766
+ if ( !productDetails ) {
2767
+ let stepProductDetails = priceDetails.filter( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2768
+ productDetails = stepProductDetails[stepProductDetails.length - 1];
2515
2769
  }
2516
- } );
2517
- if ( !productDetails ) {
2518
- let stepProductDetails = priceDetails.filter( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2519
- productDetails = stepProductDetails[stepProductDetails.length -1];
2770
+ }
2771
+ let productStatus = getClient.planDetails.product.find( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2772
+ if ( productDetails ) {
2773
+ let newObject = {
2774
+ productName: productDetails.productName,
2775
+ status: productStatus ? productStatus.status : '',
2776
+ price: productStatus ? [ 'trial', 'free' ].includes( productStatus.status ) ? 0 : productDetails.negotiatePrice : 0,
2777
+ featureStoreCount: storeIndex + 1,
2778
+ basePrice: productDetails.negotiatePrice,
2779
+ ...( getClient.priceType == 'step' ? { storeRange: productDetails.storeRange } : { storeRange: 'standard' } ),
2780
+ };
2781
+ productList.push( newObject );
2520
2782
  }
2521
2783
  }
2522
- let productStatus = getClient.planDetails.product.find( ( item ) => item.productName == getStore[storeIndex].product[storeProductIndex] );
2523
- if ( productDetails ) {
2524
- let newObject = {
2525
- productName: productDetails.productName,
2526
- status: productStatus ? productStatus.status : '',
2527
- price: productStatus ? [ 'trial', 'free' ].includes( productStatus.status ) ? 0 : productDetails.negotiatePrice : 0,
2528
- featureStoreCount: storeIndex+1,
2529
- basePrice: productDetails.negotiatePrice,
2530
- ...( getClient.priceType == 'step' ? { storeRange: productDetails.storeRange } : { storeRange: 'standard' } ),
2784
+ storeList.push(
2785
+ {
2786
+ storeId: getStore[storeIndex].storeId,
2787
+ products: productList,
2788
+ },
2789
+ );
2790
+ if ( storeIndex == getStore.length - 1 ) {
2791
+ let params = {
2792
+ clientId: requestClient[clientIndex],
2793
+ stores: storeList,
2794
+ dateISO: new Date( requestData.date ),
2795
+ dateString: dayjs( requestData.date ).format( 'YYYY-MM-DD' ),
2531
2796
  };
2532
- productList.push( newObject );
2797
+ await dailyPriceService.create( params );
2533
2798
  }
2534
2799
  }
2535
- storeList.push(
2536
- {
2537
- storeId: getStore[storeIndex].storeId,
2538
- products: productList,
2539
- },
2540
- );
2541
- if ( storeIndex == getStore.length-1 ) {
2542
- let params = {
2543
- clientId: requestClient[clientIndex],
2544
- stores: storeList,
2545
- dateISO: new Date( requestData.date ),
2546
- dateString: dayjs( requestData.date ).format( 'YYYY-MM-DD' ),
2547
- };
2548
- await dailyPriceService.create( params );
2549
- }
2550
2800
  }
2551
2801
  }
2552
2802
  }
2553
- if ( clientIndex == requestClient.length-1 ) {
2803
+ if ( clientIndex == requestClient.length - 1 ) {
2554
2804
  return res.sendSuccess( 'Price Details Inserted Successfully' );
2555
2805
  }
2556
2806
  }
@@ -2563,13 +2813,18 @@ export const dailyPricingInsert = async ( req, res ) => {
2563
2813
 
2564
2814
  export const invoiceGenerate = async ( req, res ) => {
2565
2815
  try {
2566
- let requestData = req.body;
2567
- let requestClient = requestData.clientId;
2568
- let start = new Date( requestData.fromDate );
2569
- let end = new Date( requestData.toDate );
2570
- let userTimezoneOffset = end.getTimezoneOffset() * 60000;
2571
- end = new Date( end.getTime() - userTimezoneOffset );
2572
- end.setUTCHours( 23, 59, 59, 59 );
2816
+ // let requestData = req.body;
2817
+
2818
+ let clientlist = await paymentService.find( { 'status': 'active' } );
2819
+ let requestClient = [];
2820
+
2821
+ for ( let client of clientlist ) {
2822
+ requestClient.push( client.clientId );
2823
+ }
2824
+ const currentYear = dayjs().year();
2825
+ const date = dayjs( `${currentYear}-${req.body.monthOfbilling}-01` );
2826
+ let billingmonth = dayjs( date ).format( 'MMM-YYYY' );
2827
+
2573
2828
  for ( let clientIndex = 0; clientIndex < requestClient.length; clientIndex++ ) {
2574
2829
  let getClient = await paymentService.findOne( { clientId: requestClient[clientIndex], status: 'active' } );
2575
2830
  if ( getClient ) {
@@ -2578,10 +2833,17 @@ export const invoiceGenerate = async ( req, res ) => {
2578
2833
  $match: {
2579
2834
  $and: [
2580
2835
  { clientId: requestClient[clientIndex] },
2581
- { dateISO: { $gte: start, $lte: end } },
2582
2836
  ],
2583
2837
  },
2584
2838
  },
2839
+ {
2840
+ $sort: {
2841
+ _id: -1,
2842
+ },
2843
+ },
2844
+ {
2845
+ $limit: 1,
2846
+ },
2585
2847
  {
2586
2848
  $unwind: '$stores',
2587
2849
  },
@@ -2590,10 +2852,13 @@ export const invoiceGenerate = async ( req, res ) => {
2590
2852
  },
2591
2853
  {
2592
2854
  $group: {
2593
- _id: { product: '$stores.products.productName', storeRange: '$stores.products.storeRange' },
2855
+ _id: {
2856
+ product: '$stores.products.productName',
2857
+ storeRange: '$stores.products.storeRange',
2858
+ },
2594
2859
  price: { $sum: '$stores.products.price' },
2595
2860
  count: { $sum: 1 },
2596
- basePrice: { $first: '$stores.products.basePrice' },
2861
+ basePrice: { $first: '$stores.products.price' },
2597
2862
  },
2598
2863
  },
2599
2864
  {
@@ -2605,72 +2870,104 @@ export const invoiceGenerate = async ( req, res ) => {
2605
2870
  basePrice: 1,
2606
2871
  },
2607
2872
  },
2873
+ {
2874
+ $project: {
2875
+ 'price': 1,
2876
+ 'count': 1,
2877
+ 'basePrice': 1,
2878
+ 'product': 1,
2879
+ 'HSNnumber': '998314',
2880
+ 'Month': billingmonth,
2881
+ 'description': 'Footfall Traffic Analytics',
2882
+ },
2883
+ },
2608
2884
  ];
2609
- // {
2610
- // $facet: {
2611
- // data: [
2612
- // {
2613
- // $unwind: '$stores',
2614
- // },
2615
- // {
2616
- // $unwind: '$stores.products',
2617
- // },
2618
- // {
2619
- // $group: {
2620
- // _id: { product: '$stores.products.productName', storeRange: '$stores.products.storeRange' },
2621
- // price: { $sum: '$stores.products.price' },
2622
- // },
2623
- // },
2624
- // {
2625
- // $project: {
2626
- // _id: 0,
2627
- // product: '$_id',
2628
- // price: 1,
2629
- // },
2630
- // },
2631
- // ],
2632
- // count: [
2633
- // {
2634
- // $unwind: '$stores',
2635
- // },
2636
- // { $sort: { 'stores.products._id': -1 } },
2637
- // { $project: { lastElement: { $arrayElemAt: [ '$stores.products', -1 ] } } },
2638
- // { $project: {
2639
- // count: '$lastElement.featureStoreCount',
2640
- // },
2641
- // },
2642
- // ],
2643
- // },
2644
- // },
2885
+
2645
2886
  let invoiceDetails = await dailyPriceService.aggregate( query );
2646
- if ( !invoiceDetails.length ) {
2647
- return res.sendError( 'no data found', 204 );
2648
- }
2649
- let amount = 0;
2650
- invoiceDetails.forEach( ( item ) => {
2651
- amount = item.price + amount;
2652
- } );
2653
- let storeQuery = {
2654
- clientId: requestClient[clientIndex],
2655
- status: 'active',
2656
- };
2657
- let storeCount = await storeService.count( storeQuery );
2658
- let data = {
2659
- invoice: `invoice#${requestClient[clientIndex]}-${new Date().getTime()}`,
2660
- products: invoiceDetails,
2661
- status: 'pending',
2662
- amount: amount,
2663
- totalAmount: amount,
2664
- clientId: requestClient[clientIndex],
2665
- paymentMethod: getClient?.paymentInvoice?.paymentType || 'online',
2666
- billingDate: new Date(),
2667
- stores: storeCount,
2668
- };
2887
+ if ( invoiceDetails.length > 0 ) {
2888
+ let amount = 0;
2889
+ invoiceDetails.forEach( ( item ) => {
2890
+ amount = item.price + amount;
2891
+ } );
2892
+ let storeQuery = {
2893
+ clientId: requestClient[clientIndex],
2894
+ status: 'active',
2895
+ };
2896
+ let storeCount = await storeService.count( storeQuery );
2897
+ let Finacialyear = getCurrentFinancialYear();
2898
+
2899
+ let taxList = [];
2900
+ let totalAmount = 0;
2901
+ if ( getClient.billingDetails.gstNumber && getClient.billingDetails.gstNumber.slice( 0, 2 ) == '33' ) {
2902
+ let taxAmount = ( amount * 9 ) / 100;
2903
+ totalAmount = amount + taxAmount;
2904
+ taxList.push(
2905
+ {
2906
+ 'currency': '',
2907
+ 'type': 'CGST',
2908
+ 'value': 9,
2909
+ 'taxAmount': taxAmount,
2910
+ }, {
2911
+ 'currency': '₹',
2912
+ 'type': 'SGST',
2913
+ 'value': 9,
2914
+ 'taxAmount': taxAmount,
2915
+ },
2916
+ );
2917
+ } else {
2918
+ let taxAmount = ( amount * 18 ) / 100;
2919
+ totalAmount = amount + taxAmount;
2920
+
2921
+ taxList.push(
2922
+ {
2923
+ 'currency': '₹',
2924
+ 'type': 'IGST',
2925
+ 'value': 18,
2926
+ 'taxAmount': taxAmount,
2927
+ },
2928
+ );
2929
+ }
2930
+
2931
+
2932
+ let previousinvoice = await invoiceService.findandsort( {}, {}, { _id: -1 } );
2933
+ let invoiceNo = '00001';
2934
+ if ( previousinvoice && previousinvoice.length > 0 ) {
2935
+ invoiceNo = Number( previousinvoice[0].invoiceIndex ) + 1;
2936
+ invoiceNo = invoiceNo.toString().padStart( 5, '0' );
2937
+ }
2938
+ let data = {
2939
+ invoice: `INV-${Finacialyear}-${invoiceNo}`,
2940
+ products: invoiceDetails,
2941
+ status: 'pending',
2942
+ amount: amount,
2943
+ monthOfbilling: req.body.monthOfbilling,
2944
+ invoiceIndex: invoiceNo,
2945
+ tax: taxList,
2946
+ companyName: getClient.billingDetails.companyName,
2947
+ companyAddress: getClient.billingDetails.billingAddress,
2948
+ PlaceOfSupply: getClient.billingDetails.PlaceOfSupply,
2949
+ GSTNumber: getClient.billingDetails.gstNumber,
2950
+ totalAmount: totalAmount,
2951
+ clientId: requestClient[clientIndex],
2952
+ paymentMethod: getClient?.paymentInvoice?.paymentType || 'Fund Trasfer',
2953
+ billingDate: new Date(),
2954
+ stores: storeCount,
2955
+ };
2956
+
2957
+ let invoiceExists = await invoiceService.findOne( { monthOfbilling: req.body.monthOfbilling, clientId: getClient.clientId } );
2958
+
2669
2959
 
2670
- await invoiceService.create( data );
2671
- if ( clientIndex == requestClient.length-1 ) {
2960
+ if ( invoiceExists ) {
2961
+ logger.info( `invoice already exist for the month${req.body.monthOfbilling} for ${getClient.clientId}` );
2962
+ } else {
2963
+ await invoiceService.create( data );
2964
+ }
2965
+ }
2966
+ if ( clientIndex == requestClient.length - 1 ) {
2672
2967
  return res.sendSuccess( 'invocie Generated Succesfully' );
2673
2968
  }
2969
+ } else {
2970
+ return res.sendError( 'client not found', 204 );
2674
2971
  }
2675
2972
  }
2676
2973
  } catch ( e ) {
@@ -2680,12 +2977,20 @@ export const invoiceGenerate = async ( req, res ) => {
2680
2977
  };
2681
2978
 
2682
2979
  function convertINRtoUSD( amountINR ) {
2683
- // Current exchange rate (1 INR = 0.012 USD)
2684
2980
  const exchangeRate = 0.012;
2685
- // Convert INR to USD
2686
2981
  const amountUSD = amountINR * exchangeRate;
2687
2982
  return amountUSD;
2688
2983
  }
2984
+ function getCurrentFinancialYear() {
2985
+ const today = new Date();
2986
+ const currentMonth = today.getMonth();
2987
+ const currentYear = today.getFullYear();
2988
+ if ( currentMonth >= 3 ) {
2989
+ return currentYear.toString().slice( -2 ) + '-' + ( currentYear + 1 ).toString().slice( -2 );
2990
+ } else {
2991
+ return ( ( currentYear - 1 ).toString().slice( -2 ) ) + '-' + currentYear.toString().slice( -2 );
2992
+ }
2993
+ }
2689
2994
 
2690
2995
 
2691
2996
  export const invoiceRevised = async ( req, res ) => {
@@ -2694,11 +2999,11 @@ export const invoiceRevised = async ( req, res ) => {
2694
2999
  if ( !invoiceDetails ) {
2695
3000
  return res.sendError( 'no data found', 204 );
2696
3001
  }
2697
- let userDetails= await userService.findOne( { clientId: invoiceDetails.clientId, role: 'superadmin' } );
3002
+ let userDetails = await userService.findOne( { clientId: invoiceDetails.clientId, role: 'superadmin' } );
2698
3003
  let clientDetails = await paymentService.findOne( { clientId: invoiceDetails.clientId } );
2699
3004
  if ( userDetails ) {
2700
3005
  let amount = 0;
2701
- let invoiceDate= dayjs( invoiceDetails.createdAt ).format( 'DD MMM, YYYY' );
3006
+ let invoiceDate = dayjs( invoiceDetails.createdAt ).format( 'DD MMM, YYYY' );
2702
3007
  let days = clientDetails?.paymentInvoice?.extendPaymentPeriodDays || 10;
2703
3008
  let dueDate = invoiceDetails?.dueDate ? dayjs( invoiceDetails?.dueDate ).format( 'DD MMM, YYYY' ) : dayjs().add( days, 'days' ).format( 'DD MMM, YYYY' );
2704
3009
  invoiceDetails.products.forEach( ( item ) => {
@@ -2741,3 +3046,90 @@ export const invoiceRevised = async ( req, res ) => {
2741
3046
  return res.sendError( e, 500 );
2742
3047
  }
2743
3048
  };
3049
+
3050
+ export const clientNotificationList = async ( req, res ) => {
3051
+ try {
3052
+ let query;
3053
+ if ( req.user.role == 'superadmin' ) {
3054
+ query = {
3055
+ query: {
3056
+ bool: {
3057
+ must: [
3058
+ { match: { clientId: req.user.clientId } },
3059
+ { match: { type: 'notification' } },
3060
+ { match: { adminNotification: true } },
3061
+ { match: { markasRead: false } },
3062
+ ],
3063
+ },
3064
+ },
3065
+ _source: [ 'description', 'alertCta', 'clientId', 'markasRead', 'showPushNotification', 'date', 'title' ],
3066
+ stored_fields: [ '_source' ],
3067
+ };
3068
+ } else {
3069
+ query = {
3070
+ query: {
3071
+ bool: {
3072
+ must: [
3073
+ { match: { clientId: req.user.clientId } },
3074
+ { match: { type: 'notification' } },
3075
+ { match: { clientNotification: true } },
3076
+ { match: { markasRead: false } },
3077
+ ],
3078
+ },
3079
+ },
3080
+ _source: [ 'description', 'alertCta', 'clientId', 'markasRead', 'showPushNotification', 'date', 'title' ],
3081
+ stored_fields: [ '_source' ],
3082
+ };
3083
+ }
3084
+ let result = await getOpenSearchData( appConfig.opensearch.activityLog, query );
3085
+ if ( !result || !result.body.hits.hits.length ) {
3086
+ return res.sendError( 'no data found', 204 );
3087
+ }
3088
+ return res.sendSuccess( result.body.hits.hits );
3089
+ } catch ( e ) {
3090
+ logger.error( { error: e, function: 'clientNotificationList' } );
3091
+ return res.sendError( e, 500 );
3092
+ }
3093
+ };
3094
+
3095
+ export const updateNotification = async ( req, res ) => {
3096
+ try {
3097
+ let openSearchDetails = await getOpenSearchById( appConfig.opensearch.activityLog, req.params.notificationId );
3098
+ if ( openSearchDetails.statusCode == 200 && openSearchDetails?.body?._source ) {
3099
+ const document = {
3100
+ doc: {
3101
+ markasRead: true,
3102
+ },
3103
+ };
3104
+ let updateResult = await updateOpenSearchData( appConfig.opensearch.activityLog, req.params.notificationId, document );
3105
+ if ( updateResult?.statusCode == 200 && updateResult?.body?.result == 'updated' ) {
3106
+ return res.sendSuccess( 'Notification Updated SUccessfully' );
3107
+ }
3108
+ return res.sendError( 'Something went wrong', 500 );
3109
+ }
3110
+ } catch ( e ) {
3111
+ logger.error( { error: e, function: 'updateNotification' } );
3112
+ return res.sendError( e, 500 );
3113
+ }
3114
+ };
3115
+
3116
+ export const updatePushNotification = async ( req, res ) => {
3117
+ try {
3118
+ let openSearchDetails = await getOpenSearchById( appConfig.opensearch.activityLog, req.params.notificationId );
3119
+ if ( openSearchDetails.statusCode == 200 && openSearchDetails?.body?._source ) {
3120
+ const document = {
3121
+ doc: {
3122
+ showPushNotification: false,
3123
+ },
3124
+ };
3125
+ let updateResult = await updateOpenSearchData( appConfig.opensearch.activityLog, req.params.notificationId, document );
3126
+ if ( updateResult?.statusCode == 200 && updateResult?.body?.result == 'updated' ) {
3127
+ return res.sendSuccess( 'Notification Updated SUccessfully' );
3128
+ }
3129
+ return res.sendError( 'Something went wrong', 500 );
3130
+ }
3131
+ } catch ( e ) {
3132
+ logger.error( { error: e, function: 'updatePushNotification' } );
3133
+ return res.sendError( e, 500 );
3134
+ }
3135
+ };