tango-app-api-payment-subscription 3.0.15-dev → 3.0.17-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-payment-subscription",
3
- "version": "3.0.15-dev",
3
+ "version": "3.0.17-dev",
4
4
  "description": "paymentSubscription",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,15 +1,16 @@
1
+ /* eslint-disable new-cap */
1
2
  import { logger, download, sendEmailWithSES, appConfig } from 'tango-app-api-middleware';
2
3
  import * as paymentService from '../services/clientPayment.services.js';
3
4
  import * as storeService from '../services/store.service.js';
4
5
  import * as basePricingService from '../services/basePrice.service.js';
5
6
  import * as clientRequestService from '../services/clientRequest.service.js';
6
7
  import * as invoiceService from '../services/invoice.service.js';
8
+ import * as userService from '../services/user.service.js';
7
9
  import dayjs from 'dayjs';
8
10
  import Handlebars from 'handlebars';
9
11
  import fs from 'fs';
10
12
  import path from 'path';
11
13
 
12
-
13
14
  export const addBilling = async ( req, res ) => {
14
15
  try {
15
16
  let params = {
@@ -127,15 +128,16 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
127
128
  let differenceInDays = 14;
128
129
  if ( element?.trialEndDate ) {
129
130
  differenceInDays = dateDifference( element?.trialEndDate, currentDate );
131
+ if ( element.trialEndDate < currentDate ) {
132
+ expiredProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': 'Trial Expired' } );
133
+ element.toolTip = 'Trial Expired';
134
+ element.active = true;
135
+ } else {
136
+ trialProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': differenceInDays +' days trial left' } );
137
+ element.toolTip = 'On Trial';
138
+ element.active = true;
139
+ }
130
140
  }
131
- trialProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': differenceInDays +' days trial left' } );
132
- element.toolTip = 'On Trial';
133
- element.active = true;
134
- }
135
- if ( element.status == 'trial' && ( element.trialEndDate < currentDate ) ) {
136
- expiredProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName, 'toolTip': 'Trial Expired' } );
137
- element.toolTip = 'Trial Expired';
138
- element.active = true;
139
141
  }
140
142
  } );
141
143
  }
@@ -199,6 +201,16 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
199
201
  };
200
202
 
201
203
  export const pricingInfo = async ( req, res ) => {
204
+ try {
205
+ let pricingDetails = await calculatePricing( req, res );
206
+ return res.sendSuccess( pricingDetails );
207
+ } catch ( e ) {
208
+ logger.error( { error: e, function: 'pricingInfo' } );
209
+ return res.sendError( e, 500 );
210
+ }
211
+ };
212
+
213
+ async function calculatePricing( req, res ) {
202
214
  try {
203
215
  let input = req.body;
204
216
  let finalPrice = 0;
@@ -224,11 +236,12 @@ export const pricingInfo = async ( req, res ) => {
224
236
  ];
225
237
  let pricingDetails = await basePricingService.aggregate( query );
226
238
  if ( !pricingDetails.length ) {
227
- return res.sendError( 'no data found', 204 );
239
+ return false;
228
240
  }
229
241
  let productList = pricingDetails.map( ( item ) => {
230
242
  return { ...item.basePricing };
231
243
  } );
244
+ let camaraCount;
232
245
  input.products.forEach( async ( element, index ) => {
233
246
  let getProduct = productList.find( ( item ) => item.productName == element );
234
247
  let camaraPerSqft = getProduct.camaraPerStores.filter( ( data ) => data.sqft == input.camaraPerSqft );
@@ -265,7 +278,7 @@ export const pricingInfo = async ( req, res ) => {
265
278
  OriginalPrice = OriginalPrice + discountprice;
266
279
  finalPrice = finalPrice + discountprice;
267
280
  camaraArray.push( Number( Math.ceil( camaraPerSqft[0].camaraCount ) ) );
268
- let camaraCount = Math.max( ...camaraArray );
281
+ camaraCount = Math.max( ...camaraArray );
269
282
  if ( dummy.length == input.products.length ) {
270
283
  if ( input.products.length > 1 ) {
271
284
  // for extra product to add maximum discount
@@ -291,14 +304,14 @@ export const pricingInfo = async ( req, res ) => {
291
304
  dollerpriceOriginal = ( ( OriginalPrice * 50 ) / 100 );
292
305
  OriginalPrice = ( dollerpriceOriginal + OriginalPrice ) / 84;
293
306
  }
294
- res.sendSuccess( { OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
295
307
  }
296
308
  } );
309
+ return ( { OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
297
310
  } catch ( e ) {
298
- logger.error( { error: e, function: 'pricingInfo' } );
299
- return res.sendError( e, 500 );
311
+ logger.error( { error: e, function: 'calculatePricing' } );
312
+ return false;
300
313
  }
301
- };
314
+ }
302
315
 
303
316
  export const updateSubscriptionOLD = async ( req, res ) => {
304
317
  try {
@@ -613,22 +626,24 @@ export const notificationList = async ( req, res ) => {
613
626
  let getClientInfo = await paymentService.aggregate( query );
614
627
  if ( getClientInfo.length ) {
615
628
  getClientInfo.forEach( ( item ) => {
616
- let [ firstWord, secondWord ] = item.product.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
617
- firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
618
- let startDate = dayjs( item.product.trialStartDate );
619
- let endDate = dayjs( item.product.trialEndDate ).startOf( 'day' );
620
- let date = dayjs().startOf( 'day' );
621
- let days = date.diff( startDate, 'day' );
622
- let totalDays = endDate.diff( startDate, 'day' );
623
- let percentage = Math.round( ( days / totalDays )* 100 );
624
- let leftDays = endDate.diff( date, 'day' ) + 1;
625
- notificationList.push( {
626
- product: item.product.productName,
627
- name: `${firstWord} ${secondWord}`,
628
- day: leftDays < 0 ? 0 : leftDays,
629
- percentage: percentage > 100 ? 100 : percentage,
630
- category: 'trial product',
631
- } );
629
+ if ( item.product?.trialStartDate && item.product?.trialEndDate ) {
630
+ let [ firstWord, secondWord ] = item.product.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
631
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
632
+ let startDate = dayjs( item.product.trialStartDate );
633
+ let endDate = dayjs( item.product.trialEndDate ).startOf( 'day' );
634
+ let date = dayjs().startOf( 'day' );
635
+ let days = date.diff( startDate, 'day' );
636
+ let totalDays = endDate.diff( startDate, 'day' );
637
+ let percentage = Math.round( ( days / totalDays )* 100 );
638
+ let leftDays = endDate.diff( date, 'day' ) + 1;
639
+ notificationList.push( {
640
+ product: item.product.productName,
641
+ name: `${firstWord} ${secondWord}`,
642
+ day: leftDays < 0 ? 0 : leftDays,
643
+ percentage: percentage > 100 ? 100 : percentage,
644
+ category: 'trial product',
645
+ } );
646
+ }
632
647
  } );
633
648
  }
634
649
 
@@ -683,17 +698,26 @@ export const trialApproval = async ( req, res ) => {
683
698
  }
684
699
  clientProducts.save();
685
700
  await storeService.addremoveElement( { clientId: requestData.clientId, status: 'active' }, { $push: { product: requestData.name } } );
686
- const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialInitiateEmail.hbs', 'utf8' );
687
- const template = Handlebars.compile( templateHtml );
688
- const html = template( { data: '' } );
689
- let params = {
690
- toEmail: 'sudha@tangotech.co.in',
691
- mailSubject: 'test',
692
- htmlBody: html,
693
- attachment: '',
694
- sourceEmail: appConfig.cloud.aws.ses.adminEmail,
695
- };
696
- sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
701
+ let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
702
+ let [ firstWord, secondWord ] = requestData.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
703
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
704
+ if ( userDetails ) {
705
+ let data = {
706
+ userName: userDetails.userName,
707
+ product: firstWord +' '+ secondWord,
708
+ };
709
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialInitiateEmail.hbs', 'utf8' );
710
+ const template = Handlebars.compile( templateHtml );
711
+ const html = template( { data: data } );
712
+ let params = {
713
+ toEmail: userDetails.email,
714
+ mailSubject: 'Trial Initiated - Welcome to Tango Suite!',
715
+ htmlBody: html,
716
+ attachment: '',
717
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
718
+ };
719
+ await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
720
+ }
697
721
  }
698
722
  return res.sendSuccess( 'updated Successfully' );
699
723
  } );
@@ -706,6 +730,7 @@ export const trialApproval = async ( req, res ) => {
706
730
 
707
731
  export const trialExtendRequestApproval = async ( req, res ) => {
708
732
  try {
733
+ let trialDate;
709
734
  let clientDetails = await paymentService.findOne( { clientId: req.body.clientId, status: 'active' }, { planDetails: 1 } );
710
735
  if ( !clientDetails ) {
711
736
  return res.sendError( 'no data found', 204 );
@@ -713,6 +738,7 @@ export const trialExtendRequestApproval = async ( req, res ) => {
713
738
  clientDetails.planDetails.product.forEach( ( item ) => {
714
739
  if ( item.productName == req.body.product && item.status == 'trial' ) {
715
740
  item.trialEndDate = new Date( dayjs( item.trialEndDate ).add( req.body.days, 'days' ).format( 'YYYY-MM-DD' ) );
741
+ trialDate = item.trialEndDate;
716
742
  }
717
743
  } );
718
744
  clientDetails.save().then( async () => {
@@ -721,6 +747,28 @@ export const trialExtendRequestApproval = async ( req, res ) => {
721
747
  requestData.status = 'completed';
722
748
  requestData.save();
723
749
  }
750
+ let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
751
+ if ( userDetails ) {
752
+ let [ firstWord, secondWord ] = req.body.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
753
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
754
+ let data = {
755
+ userName: userDetails.userName,
756
+ product: firstWord +' '+secondWord,
757
+ days: req.body.days,
758
+ date: trialDate,
759
+ };
760
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialExtensionEmail.hbs', 'utf8' );
761
+ const template = Handlebars.compile( templateHtml );
762
+ const html = template( { data: data } );
763
+ let params = {
764
+ toEmail: userDetails.email,
765
+ mailSubject: 'TangoEye | Trial Extended - Enjoy More Time with Tango',
766
+ htmlBody: html,
767
+ attachment: '',
768
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
769
+ };
770
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
771
+ }
724
772
  return res.sendSuccess( 'Trial Extended Successfully' );
725
773
  } ).catch( ( e ) => {
726
774
  return res.sendError( e, 500 );
@@ -788,6 +836,23 @@ export const productSubscribe = async ( req, res ) => {
788
836
  product = product.filter( ( item ) => !removeProducts.includes( item.productName ) );
789
837
  clientInfo.planDetails.product = product;
790
838
  clientInfo.save().then( async () => {
839
+ let userDetails= await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
840
+ if ( userDetails ) {
841
+ let data = {
842
+ username: userDetails.userName,
843
+ };
844
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialSubscriptionEmail.hbs', 'utf8' );
845
+ const template = Handlebars.compile( templateHtml );
846
+ const html = template( { data: data } );
847
+ let params = {
848
+ toEmail: userDetails.email,
849
+ mailSubject: 'Subscribe - Tango Eye',
850
+ htmlBody: html,
851
+ attachment: '',
852
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
853
+ };
854
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
855
+ }
791
856
  } );
792
857
  return res.sendSuccess( 'Product Subscribed Successfully' );
793
858
  } catch ( e ) {
@@ -812,6 +877,20 @@ export const unsubscribeApproval = async ( req, res ) => {
812
877
  clientProducts.status = 'deactive';
813
878
  clientProducts.save();
814
879
  await storeService.updateMany( { clientId: requestData.clientId }, { status: 'deactive' } );
880
+ let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
881
+ if ( userDetails ) {
882
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialUnsubscribeEmail.hbs', 'utf8' );
883
+ const template = Handlebars.compile( templateHtml );
884
+ const html = template( { data: '' } );
885
+ let params = {
886
+ toEmail: userDetails.email,
887
+ mailSubject: 'unSubscribe - Tango Eye',
888
+ htmlBody: html,
889
+ attachment: '',
890
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
891
+ };
892
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
893
+ }
815
894
  }
816
895
  return res.sendSuccess( 'updated Successfully' );
817
896
  } );
@@ -979,14 +1058,16 @@ export const storeViewList = async ( req, res ) => {
979
1058
 
980
1059
  export const storeLocationList = async ( req, res ) => {
981
1060
  try {
982
- let storeDetails = await storeService.find( { clientId: req.query.clientId, status: 'active' }, { 'storeId': 1, 'storeName': 1, 'storeProfile.city': 1 } );
983
- if ( !storeDetails.length ) {
984
- return res.sendError( 'no data found', 204 );
1061
+ let storeDetails;
1062
+ storeDetails = await storeService.find( { clientId: req.query.clientId, status: 'active' }, { 'storeId': 1, 'storeName': 1, 'storeProfile.city': 1 } );
1063
+ let store = [];
1064
+ let location = [];
1065
+ if ( storeDetails.length ) {
1066
+ store = storeDetails.map( ( item ) => {
1067
+ return { id: item.id, storeId: item.storeId, storeName: item.storeName };
1068
+ } );
1069
+ location = storeDetails.filter( ( item ) => item.storeProfile.city != '' && item.storeProfile.city != null && typeof ( item.storeProfile.city ) != undefined ).map( ( item ) => item.storeProfile.city );
985
1070
  }
986
- let store = storeDetails.map( ( item ) => {
987
- return { id: item.id, storeId: item.storeId, storeName: item.storeName };
988
- } );
989
- let location = storeDetails.filter( ( item ) => item.storeProfile.city != '' && item.storeProfile.city != null && typeof ( item.storeProfile.city ) != undefined ).map( ( item ) => item.storeProfile.city );
990
1071
  let productDetails = await basePricingService.findOne( { clientId: { $exists: false } }, { 'basePricing': 1, '_id': 0 } );
991
1072
  let product = productDetails.basePricing.map( ( item ) => item.productName );
992
1073
  return res.sendSuccess( { store, location, product } );
@@ -1280,27 +1361,92 @@ export const priceList = async ( req, res ) => {
1280
1361
 
1281
1362
  export const pricingListUpdate = async ( req, res ) => {
1282
1363
  try {
1283
- req.body.products.forEach( ( item ) => {
1284
- delete item.originalPrice;
1285
- delete item.oldPrice;
1286
- delete item.oldStoreCount;
1287
- delete item.storeCount;
1288
- delete item.price;
1289
- if ( req.body.type == 'step' ) {
1290
- delete item.showImg;
1291
- delete item.showEditDelete;
1292
- delete item.lastIndex;
1293
- }
1294
- } );
1295
1364
  let getPriceInfo = await basePricingService.findOne( { clientId: { $exists: true }, clientId: req.body.clientId }, { standard: 1, step: 1 } );
1296
- let data = {
1297
- ...( req.body.type == 'standard' ) ? { standard: req.body.products } : { step: req.body.products },
1298
- client: req.body.clientId,
1299
- };
1365
+ let baseProduct = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
1300
1366
  if ( !getPriceInfo ) {
1367
+ if ( !req.body.client.planDetails.product.length ) {
1368
+ return res.sendError( 'no product found', 204 );
1369
+ }
1370
+ let products = req.body.client.planDetails.product.map( ( item ) => item.productName );
1371
+ let standardList = [];
1372
+ let stepList = [];
1373
+ products.forEach( ( product ) => {
1374
+ let baseDetails = baseProduct.basePricing.find( ( item ) => item.productName == product );
1375
+ let discountPrice = ( baseDetails.basePrice * baseDetails.discoutPercentage ) / 100;
1376
+ standardList.push(
1377
+ {
1378
+ productName: product,
1379
+ discountPercentage: baseDetails.discoutPercentage,
1380
+ basePrice: baseDetails.basePrice,
1381
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1382
+ },
1383
+ );
1384
+ stepList.push(
1385
+ {
1386
+ productName: product,
1387
+ discountPercentage: baseDetails.discoutPercentage,
1388
+ basePrice: baseDetails.basePrice,
1389
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1390
+ storeRange: '1-100',
1391
+ },
1392
+ );
1393
+ } );
1394
+ let data = {
1395
+ standard: standardList,
1396
+ step: stepList,
1397
+ clientId: req.body.clientId,
1398
+ };
1301
1399
  await basePricingService.create( data );
1400
+ let clientDetails = await paymentService.findOne( { clientId: req.body.clientId } );
1401
+ if ( clientDetails ) {
1402
+ let product = [];
1403
+ let clientId = req.body.clientId;
1404
+ clientDetails.planDetails.product.forEach( ( item ) => {
1405
+ product.push( {
1406
+ productName: item.productName,
1407
+ status: 'trial',
1408
+ trialStartDate: new Date(),
1409
+ trialEndDate: new Date( dayjs().add( 13, 'days' ).format( 'YYYY-MM-DD' ) ),
1410
+ } );
1411
+ } );
1412
+ req.body = {
1413
+ 'camaraPerSqft': clientDetails.planDetails.storeSize,
1414
+ 'storesCount': clientDetails.planDetails.totalStores,
1415
+ 'planName': clientDetails.planDetails.subscriptionPeriod,
1416
+ 'products': product.map( ( item ) => item.productName ),
1417
+ 'currencyType': 'rupees',
1418
+ };
1419
+ let pricingDetails = await calculatePricing( req, res );
1420
+ let details = {
1421
+ 'priceType': 'standard',
1422
+ 'planDetails.paymentStatus': clientDetails?.subscriptionType == 'free' ? 'free' : 'trial',
1423
+ 'planDetails.product': product,
1424
+ 'price': pricingDetails.price,
1425
+ };
1426
+ await paymentService.updateOne( { clientId: clientId }, details );
1427
+ }
1302
1428
  return res.sendSuccess( 'Pricig Updated Successfully' );
1303
1429
  }
1430
+ if ( getPriceInfo && !req.body?.products?.length ) {
1431
+ return res.sendError( 'Product is required', 400 );
1432
+ }
1433
+ if ( !req.body.type ) {
1434
+ req.body.type = 'standard';
1435
+ }
1436
+ if ( req.body?.products && req.body?.products?.length ) {
1437
+ req.body.products.forEach( ( item ) => {
1438
+ delete item.originalPrice;
1439
+ delete item.oldPrice;
1440
+ delete item.oldStoreCount;
1441
+ delete item.storeCount;
1442
+ delete item.price;
1443
+ if ( req.body.type == 'step' ) {
1444
+ delete item.showImg;
1445
+ delete item.showEditDelete;
1446
+ delete item.lastIndex;
1447
+ }
1448
+ } );
1449
+ }
1304
1450
  if ( req.body.type == 'standard' ) {
1305
1451
  getPriceInfo.standard = req.body.products;
1306
1452
  } else {
@@ -1324,7 +1470,21 @@ export const updatedRevisedPrice = async ( req, res ) => {
1324
1470
  invoiceDetails.amount = req.body.revisedAmount;
1325
1471
  invoiceDetails.revisedAmount = req.body.revisedAmount;
1326
1472
  invoiceDetails.discount = req.body.discount;
1327
- invoiceDetails.save().then( () => {
1473
+ invoiceDetails.save().then( async () => {
1474
+ let userDetails= await userService.findOne( { clientId: invoiceDetails.clientId, role: 'superadmin' } );
1475
+ if ( userDetails ) {
1476
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialCreditNoteEmail.hbs', 'utf8' );
1477
+ const template = Handlebars.compile( templateHtml );
1478
+ const html = template( { data: '' } );
1479
+ let params = {
1480
+ toEmail: 'sudha@tangotech.co.in',
1481
+ mailSubject: 'test',
1482
+ htmlBody: html,
1483
+ attachment: '',
1484
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
1485
+ };
1486
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1487
+ }
1328
1488
  return res.sendSuccess( 'Credit notes Updated Successfully' );
1329
1489
  } );
1330
1490
  } catch ( e ) {
@@ -1371,3 +1531,184 @@ export const getStoreProducts = async ( req, res ) => {
1371
1531
  }
1372
1532
  };
1373
1533
 
1534
+ export const getRemindClients = async ( req, res ) => {
1535
+ try {
1536
+ let clientDetails = await paymentService.find( { status: 'active' } );
1537
+ if ( !clientDetails.length ) {
1538
+ return res.sendError( 'no data found', 204 );
1539
+ }
1540
+ clientDetails.forEach( async ( client ) => {
1541
+ if ( client.planDetails?.product && client.planDetails?.product.length ) {
1542
+ client.planDetails.product.forEach( async ( item ) => {
1543
+ if ( item.status == 'trial' ) {
1544
+ let date = new Date();
1545
+ let userTimezoneOffset = item.trialEndDate.getTimezoneOffset() / 60000;
1546
+ item.trialEndDate = new Date( item.trialEndDate.getTime() - userTimezoneOffset );
1547
+ item.trialEndDate.setUTCHours( 0, 0, 0, 0 );
1548
+ const diffTime = parseInt( ( item.trialEndDate - date ) / ( 1000 * 60 * 60 * 24 ), 10 ) + 1;
1549
+ let userDetails= await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
1550
+ if ( userDetails ) {
1551
+ if ( diffTime == 3 ) {
1552
+ let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1553
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
1554
+ let data = {
1555
+ username: userDetails.userName,
1556
+ product: firstWord + ' ' + secondWord,
1557
+ };
1558
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialReminderEmail.hbs', 'utf8' );
1559
+ const template = Handlebars.compile( templateHtml );
1560
+ const html = template( { data: data } );
1561
+ let params = {
1562
+ toEmail: userDetails.email,
1563
+ mailSubject: 'TangoEye | Trial Ending Soon',
1564
+ htmlBody: html,
1565
+ attachment: '',
1566
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
1567
+ };
1568
+ await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1569
+ }
1570
+ }
1571
+ }
1572
+ } );
1573
+ }
1574
+ } );
1575
+ return res.sendSuccess();
1576
+ } catch ( e ) {
1577
+ logger.error( { error: e, function: 'getRemindClients' } );
1578
+ return res.sendError( e, 500 );
1579
+ }
1580
+ };
1581
+
1582
+
1583
+ export const getExpiredClients = async ( req, res ) => {
1584
+ try {
1585
+ let start = new Date();
1586
+ let userTimezoneOffset = start.getTimezoneOffset() * 60000;
1587
+ start = new Date( start.getTime() - userTimezoneOffset );
1588
+ start.setUTCHours( 0, 0, 0, 0 );
1589
+ let end = new Date();
1590
+ end = new Date( end.getTime() - userTimezoneOffset );
1591
+ end.setUTCHours( 23, 59, 59, 59 );
1592
+ let query = [
1593
+ {
1594
+ $match: {
1595
+ status: 'active',
1596
+ },
1597
+ },
1598
+ { $unwind: '$planDetails.product' },
1599
+ {
1600
+ $match: {
1601
+ 'planDetails.product.status': 'trial',
1602
+ 'planDetails.product.trialEndDate': { $gte: start, $lte: end },
1603
+ },
1604
+ },
1605
+ ];
1606
+ let clientDetails = await paymentService.aggregate( query );
1607
+ if ( !clientDetails.length ) {
1608
+ return res.sendError( 'no data found', 204 );
1609
+ }
1610
+ clientDetails.forEach( async ( client ) => {
1611
+ if ( client.planDetails?.product ) {
1612
+ let item = client.planDetails.product;
1613
+ let userDetails= await userService.findOne( { clientId: client.clientId, role: 'superadmin' } );
1614
+ if ( userDetails ) {
1615
+ let [ firstWord, secondWord ] = item.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
1616
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
1617
+ let data = {
1618
+ username: userDetails.userName,
1619
+ product: firstWord +' '+secondWord,
1620
+ };
1621
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialExpiredEmail.hbs', 'utf8' );
1622
+ const template = Handlebars.compile( templateHtml );
1623
+ const html = template( { data: data } );
1624
+ let params = {
1625
+ toEmail: userDetails.email,
1626
+ mailSubject: 'TangoEye | Trial Expired - Upgrade to Continue',
1627
+ htmlBody: html,
1628
+ attachment: '',
1629
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
1630
+ };
1631
+ await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1632
+ }
1633
+ }
1634
+ } );
1635
+ return res.sendSuccess();
1636
+ } catch ( e ) {
1637
+ logger.error( { error: e, function: 'getExpiredClients' } );
1638
+ return res.sendError( e, 500 );
1639
+ }
1640
+ };
1641
+
1642
+ export const invoiceDownload = async ( req, res ) => {
1643
+ try {
1644
+ // const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf.hbs', 'utf8' );
1645
+ // const template = Handlebars.compile( templateHtml );
1646
+ // const html = template( { data: '' } );
1647
+ // console.log( html );
1648
+ } catch ( e ) {
1649
+ // console.log( e );
1650
+ logger.error( { error: e, function: 'invoiceDownload' } );
1651
+ return res.sendError( e, 500 );
1652
+ }
1653
+ };
1654
+
1655
+ export const updateInvoiceStatus = async ( req, res ) => {
1656
+ try {
1657
+ if ( !req.params?.invoiceId ) {
1658
+ return res.sendError( 'Invoice id is required', 400 );
1659
+ }
1660
+ let invoiceDetails = await invoiceService.findOne( { _id: req.params.invoiceId } );
1661
+ if ( !invoiceDetails ) {
1662
+ return res.sendError( 'no data found', 204 );
1663
+ }
1664
+ invoiceDetails.status = req.body?.status || 'paid';
1665
+ invoiceDetails.save().then( async () => {
1666
+ let clientInfo = await paymentService.findOne( { clientId: invoiceDetails.clientId } );
1667
+ if ( clientInfo ) {
1668
+ clientInfo.planDetails.paymentStatus = 'paid';
1669
+ clientInfo.save();
1670
+ }
1671
+ return res.sendSuccess( 'Invoice updated Successfully' );
1672
+ } );
1673
+ } catch ( e ) {
1674
+ logger.error( { error: e, function: 'invoiceDownload' } );
1675
+ return res.sendError( e, 500 );
1676
+ }
1677
+ };
1678
+
1679
+
1680
+ export const invoiceCreate = async ( req, res ) => {
1681
+ try {
1682
+ let products = req.body.client.planDetails.product.map( ( item ) => item.productName );
1683
+ let storeDetails = await storeService.count( { clientId: req.body.clientId, status: 'active' } );
1684
+ let data;
1685
+ data = {
1686
+ invoice: `invoice #0${req.body.client.clientId} - ${Math.floor( Math.random() * 100 ) + 1}`,
1687
+ billingDate: new Date(),
1688
+ products: products,
1689
+ stores: storeDetails,
1690
+ status: '',
1691
+ clientId: req.body.clientId,
1692
+ };
1693
+ req.body = {
1694
+ 'camaraPerSqft': req.body.client.planDetails.storeSize,
1695
+ 'storesCount': req.body.client.planDetails.totalStores,
1696
+ 'planName': req.body.client.planDetails.subscriptionPeriod,
1697
+ 'products': products,
1698
+ 'currencyType': 'rupees',
1699
+ };
1700
+ let pricingDetails = await calculatePricing( req, res );
1701
+ data.amount = pricingDetails.price;
1702
+ await invoiceService.create( data );
1703
+ let clientInfo = await paymentService.findOne( { clientId: req.body.clientId } );
1704
+ if ( clientInfo ) {
1705
+ clientInfo.planDetails.paymentStatus = 'due';
1706
+ clientInfo.save();
1707
+ }
1708
+ return res.sendSuccess( 'Invoice Created Successfully' );
1709
+ } catch ( e ) {
1710
+ // console.log( e );
1711
+ logger.error( { error: e, function: 'invoiceDownload' } );
1712
+ return res.sendError( e, 500 );
1713
+ }
1714
+ };
@@ -33,7 +33,7 @@ export const validateProducts = {
33
33
  export const validateunsubscribeParams = {
34
34
  body: joi.object( {
35
35
  reason: joi.string().required(),
36
- description: joi.string().required(),
36
+ description: joi.string().optional().empty( '' ),
37
37
  clientId: joi.string().required(),
38
38
  } ),
39
39
  };
@@ -108,9 +108,9 @@ export const validateInvoiceParams = {
108
108
 
109
109
  export const validatePriceParams = {
110
110
  body: joi.object( {
111
- type: joi.string().required(),
111
+ type: joi.string().optional(),
112
112
  clientId: joi.string().required(),
113
- products: joi.array().required(),
113
+ products: joi.array().optional(),
114
114
  } ),
115
115
  };
116
116