tango-app-api-payment-subscription 3.0.14-dev → 3.0.16-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.14-dev",
3
+ "version": "3.0.16-dev",
4
4
  "description": "paymentSubscription",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -20,8 +20,8 @@
20
20
  "handlebars": "^4.7.8",
21
21
  "mongodb": "^6.4.0",
22
22
  "nodemon": "^3.1.0",
23
- "tango-api-schema": "^2.0.54",
24
- "tango-app-api-middleware": "^1.0.29",
23
+ "tango-api-schema": "^2.0.62",
24
+ "tango-app-api-middleware": "^1.0.49-dev",
25
25
  "winston": "^3.12.0",
26
26
  "winston-daily-rotate-file": "^5.0.0"
27
27
  },
@@ -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 = {
@@ -199,8 +200,20 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
199
200
  };
200
201
 
201
202
  export const pricingInfo = async ( req, res ) => {
203
+ try {
204
+ let pricingDetails = await calculatePricing( req, res );
205
+ console.log( await calculatePricing( req, res ), 'details' );
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;
216
+ console.log( input, 'input' );
204
217
  let finalPrice = 0;
205
218
  let dummy = [];
206
219
  let camaraArray = [];
@@ -224,11 +237,12 @@ export const pricingInfo = async ( req, res ) => {
224
237
  ];
225
238
  let pricingDetails = await basePricingService.aggregate( query );
226
239
  if ( !pricingDetails.length ) {
227
- return res.sendError( 'no data found', 204 );
240
+ return false;
228
241
  }
229
242
  let productList = pricingDetails.map( ( item ) => {
230
243
  return { ...item.basePricing };
231
244
  } );
245
+ let camaraCount;
232
246
  input.products.forEach( async ( element, index ) => {
233
247
  let getProduct = productList.find( ( item ) => item.productName == element );
234
248
  let camaraPerSqft = getProduct.camaraPerStores.filter( ( data ) => data.sqft == input.camaraPerSqft );
@@ -265,7 +279,7 @@ export const pricingInfo = async ( req, res ) => {
265
279
  OriginalPrice = OriginalPrice + discountprice;
266
280
  finalPrice = finalPrice + discountprice;
267
281
  camaraArray.push( Number( Math.ceil( camaraPerSqft[0].camaraCount ) ) );
268
- let camaraCount = Math.max( ...camaraArray );
282
+ camaraCount = Math.max( ...camaraArray );
269
283
  if ( dummy.length == input.products.length ) {
270
284
  if ( input.products.length > 1 ) {
271
285
  // for extra product to add maximum discount
@@ -291,14 +305,14 @@ export const pricingInfo = async ( req, res ) => {
291
305
  dollerpriceOriginal = ( ( OriginalPrice * 50 ) / 100 );
292
306
  OriginalPrice = ( dollerpriceOriginal + OriginalPrice ) / 84;
293
307
  }
294
- res.sendSuccess( { OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
295
308
  }
296
309
  } );
310
+ return ( { OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
297
311
  } catch ( e ) {
298
- logger.error( { error: e, function: 'pricingInfo' } );
299
- return res.sendError( e, 500 );
312
+ console.log( e );
313
+ return false;
300
314
  }
301
- };
315
+ }
302
316
 
303
317
  export const updateSubscriptionOLD = async ( req, res ) => {
304
318
  try {
@@ -683,17 +697,26 @@ export const trialApproval = async ( req, res ) => {
683
697
  }
684
698
  clientProducts.save();
685
699
  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 );
700
+ let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
701
+ let [ firstWord, secondWord ] = requestData.name.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
702
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
703
+ if ( userDetails ) {
704
+ let data = {
705
+ userName: userDetails.userName,
706
+ product: firstWord +' '+ secondWord,
707
+ };
708
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialInitiateEmail.hbs', 'utf8' );
709
+ const template = Handlebars.compile( templateHtml );
710
+ const html = template( { data: data } );
711
+ let params = {
712
+ toEmail: userDetails.email,
713
+ mailSubject: 'Trial Initiated - Welcome to Tango Suite!',
714
+ htmlBody: html,
715
+ attachment: '',
716
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
717
+ };
718
+ await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
719
+ }
697
720
  }
698
721
  return res.sendSuccess( 'updated Successfully' );
699
722
  } );
@@ -706,6 +729,7 @@ export const trialApproval = async ( req, res ) => {
706
729
 
707
730
  export const trialExtendRequestApproval = async ( req, res ) => {
708
731
  try {
732
+ let trialDate;
709
733
  let clientDetails = await paymentService.findOne( { clientId: req.body.clientId, status: 'active' }, { planDetails: 1 } );
710
734
  if ( !clientDetails ) {
711
735
  return res.sendError( 'no data found', 204 );
@@ -713,6 +737,7 @@ export const trialExtendRequestApproval = async ( req, res ) => {
713
737
  clientDetails.planDetails.product.forEach( ( item ) => {
714
738
  if ( item.productName == req.body.product && item.status == 'trial' ) {
715
739
  item.trialEndDate = new Date( dayjs( item.trialEndDate ).add( req.body.days, 'days' ).format( 'YYYY-MM-DD' ) );
740
+ trialDate = item.trialEndDate;
716
741
  }
717
742
  } );
718
743
  clientDetails.save().then( async () => {
@@ -721,6 +746,28 @@ export const trialExtendRequestApproval = async ( req, res ) => {
721
746
  requestData.status = 'completed';
722
747
  requestData.save();
723
748
  }
749
+ let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
750
+ if ( userDetails ) {
751
+ let [ firstWord, secondWord ] = req.body.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
752
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
753
+ let data = {
754
+ userName: userDetails.userName,
755
+ product: firstWord +' '+secondWord,
756
+ days: req.body.days,
757
+ date: trialDate,
758
+ };
759
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialExtensionEmail.hbs', 'utf8' );
760
+ const template = Handlebars.compile( templateHtml );
761
+ const html = template( { data: data } );
762
+ let params = {
763
+ toEmail: userDetails.email,
764
+ mailSubject: 'TangoEye | Trial Extended - Enjoy More Time with Tango',
765
+ htmlBody: html,
766
+ attachment: '',
767
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
768
+ };
769
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
770
+ }
724
771
  return res.sendSuccess( 'Trial Extended Successfully' );
725
772
  } ).catch( ( e ) => {
726
773
  return res.sendError( e, 500 );
@@ -788,6 +835,23 @@ export const productSubscribe = async ( req, res ) => {
788
835
  product = product.filter( ( item ) => !removeProducts.includes( item.productName ) );
789
836
  clientInfo.planDetails.product = product;
790
837
  clientInfo.save().then( async () => {
838
+ let userDetails= await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
839
+ if ( userDetails ) {
840
+ let data = {
841
+ username: userDetails.userName,
842
+ };
843
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialSubscriptionEmail.hbs', 'utf8' );
844
+ const template = Handlebars.compile( templateHtml );
845
+ const html = template( { data: data } );
846
+ let params = {
847
+ toEmail: userDetails.email,
848
+ mailSubject: 'Subscribe - Tango Eye',
849
+ htmlBody: html,
850
+ attachment: '',
851
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
852
+ };
853
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
854
+ }
791
855
  } );
792
856
  return res.sendSuccess( 'Product Subscribed Successfully' );
793
857
  } catch ( e ) {
@@ -812,6 +876,20 @@ export const unsubscribeApproval = async ( req, res ) => {
812
876
  clientProducts.status = 'deactive';
813
877
  clientProducts.save();
814
878
  await storeService.updateMany( { clientId: requestData.clientId }, { status: 'deactive' } );
879
+ let userDetails= await userService.findOne( { clientId: requestData.clientId, role: 'superadmin' } );
880
+ if ( userDetails ) {
881
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialUnsubscribeEmail.hbs', 'utf8' );
882
+ const template = Handlebars.compile( templateHtml );
883
+ const html = template( { data: '' } );
884
+ let params = {
885
+ toEmail: userDetails.email,
886
+ mailSubject: 'unSubscribe - Tango Eye',
887
+ htmlBody: html,
888
+ attachment: '',
889
+ sourceEmail: appConfig.cloud.aws.ses.adminEmail,
890
+ };
891
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
892
+ }
815
893
  }
816
894
  return res.sendSuccess( 'updated Successfully' );
817
895
  } );
@@ -979,14 +1057,16 @@ export const storeViewList = async ( req, res ) => {
979
1057
 
980
1058
  export const storeLocationList = async ( req, res ) => {
981
1059
  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 );
1060
+ let storeDetails;
1061
+ storeDetails = await storeService.find( { clientId: req.query.clientId, status: 'active' }, { 'storeId': 1, 'storeName': 1, 'storeProfile.city': 1 } );
1062
+ let store = [];
1063
+ let location = [];
1064
+ if ( storeDetails.length ) {
1065
+ store = storeDetails.map( ( item ) => {
1066
+ return { id: item.id, storeId: item.storeId, storeName: item.storeName };
1067
+ } );
1068
+ location = storeDetails.filter( ( item ) => item.storeProfile.city != '' && item.storeProfile.city != null && typeof ( item.storeProfile.city ) != undefined ).map( ( item ) => item.storeProfile.city );
985
1069
  }
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
1070
  let productDetails = await basePricingService.findOne( { clientId: { $exists: false } }, { 'basePricing': 1, '_id': 0 } );
991
1071
  let product = productDetails.basePricing.map( ( item ) => item.productName );
992
1072
  return res.sendSuccess( { store, location, product } );
@@ -1280,27 +1360,92 @@ export const priceList = async ( req, res ) => {
1280
1360
 
1281
1361
  export const pricingListUpdate = async ( req, res ) => {
1282
1362
  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
1363
  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
- };
1364
+ let baseProduct = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
1300
1365
  if ( !getPriceInfo ) {
1366
+ if ( !req.body.client.planDetails.product.length ) {
1367
+ return res.sendError( 'no product found', 204 );
1368
+ }
1369
+ let products = req.body.client.planDetails.product.map( ( item ) => item.productName );
1370
+ let standardList = [];
1371
+ let stepList = [];
1372
+ products.forEach( ( product ) => {
1373
+ let baseDetails = baseProduct.basePricing.find( ( item ) => item.productName == product );
1374
+ let discountPrice = ( baseDetails.basePrice * baseDetails.discoutPercentage ) / 100;
1375
+ standardList.push(
1376
+ {
1377
+ productName: product,
1378
+ discountPercentage: baseDetails.discoutPercentage,
1379
+ basePrice: baseDetails.basePrice,
1380
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1381
+ },
1382
+ );
1383
+ stepList.push(
1384
+ {
1385
+ productName: product,
1386
+ discountPercentage: baseDetails.discoutPercentage,
1387
+ basePrice: baseDetails.basePrice,
1388
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1389
+ storeRange: '1-100',
1390
+ },
1391
+ );
1392
+ } );
1393
+ let data = {
1394
+ standard: standardList,
1395
+ step: stepList,
1396
+ clientId: req.body.clientId,
1397
+ };
1301
1398
  await basePricingService.create( data );
1399
+ let clientDetails = await paymentService.findOne( { clientId: req.body.clientId } );
1400
+ if ( clientDetails ) {
1401
+ let product = [];
1402
+ let clientId = req.body.clientId;
1403
+ clientDetails.planDetails.product.forEach( ( item ) => {
1404
+ product.push( {
1405
+ productName: item.productName,
1406
+ status: 'trial',
1407
+ trialStartDate: new Date(),
1408
+ trialEndDate: new Date( dayjs().add( 13, 'days' ).format( 'YYYY-MM-DD' ) ),
1409
+ } );
1410
+ } );
1411
+ req.body = {
1412
+ 'camaraPerSqft': clientDetails.planDetails.storeSize,
1413
+ 'storesCount': clientDetails.planDetails.totalStores,
1414
+ 'planName': clientDetails.planDetails.subscriptionPeriod,
1415
+ 'products': product.map( ( item ) => item.productName ),
1416
+ 'currencyType': 'rupees',
1417
+ };
1418
+ let pricingDetails = await calculatePricing( req, res );
1419
+ let details = {
1420
+ 'priceType': 'standard',
1421
+ 'planDetails.paymentStatus': clientDetails?.subscriptionType == 'free' ? 'free' : 'trial',
1422
+ 'planDetails.product': product,
1423
+ 'price': pricingDetails.price,
1424
+ };
1425
+ await paymentService.updateOne( { clientId: clientId }, details );
1426
+ }
1302
1427
  return res.sendSuccess( 'Pricig Updated Successfully' );
1303
1428
  }
1429
+ if ( getPriceInfo && !req.body?.products?.length ) {
1430
+ return res.sendError( 'Product is required', 400 );
1431
+ }
1432
+ if ( !req.body.type ) {
1433
+ req.body.type = 'standard';
1434
+ }
1435
+ if ( req.body?.products && req.body?.products?.length ) {
1436
+ req.body.products.forEach( ( item ) => {
1437
+ delete item.originalPrice;
1438
+ delete item.oldPrice;
1439
+ delete item.oldStoreCount;
1440
+ delete item.storeCount;
1441
+ delete item.price;
1442
+ if ( req.body.type == 'step' ) {
1443
+ delete item.showImg;
1444
+ delete item.showEditDelete;
1445
+ delete item.lastIndex;
1446
+ }
1447
+ } );
1448
+ }
1304
1449
  if ( req.body.type == 'standard' ) {
1305
1450
  getPriceInfo.standard = req.body.products;
1306
1451
  } else {
@@ -1310,6 +1455,7 @@ export const pricingListUpdate = async ( req, res ) => {
1310
1455
  return res.sendSuccess( 'Pricig Updated Successfully' );
1311
1456
  } );
1312
1457
  } catch ( e ) {
1458
+ console.log( e );
1313
1459
  logger.error( { error: e, function: 'addPricingList' } );
1314
1460
  return res.sendError( e, 500 );
1315
1461
  }
@@ -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/trailReminderEmail.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/trailExpiredEmail.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
+ };
@@ -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