tango-app-api-payment-subscription 3.0.22-dev → 3.0.23-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/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
 
2
2
 
3
3
  import { paymentSubscriptionRouter } from './src/routes/paymentSubscription.routes.js';
4
+ import { paymentDoc } from './src/docs/payment.docs.js';
4
5
 
5
- export { paymentSubscriptionRouter };
6
+ export { paymentSubscriptionRouter, paymentDoc };
6
7
 
7
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-payment-subscription",
3
- "version": "3.0.22-dev",
3
+ "version": "3.0.23-dev",
4
4
  "description": "paymentSubscription",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -18,15 +18,17 @@
18
18
  "dotenv": "^16.4.5",
19
19
  "express": "^4.18.3",
20
20
  "handlebars": "^4.7.8",
21
+ "html-to-pdfmake": "^2.5.6",
22
+ "joi-to-swagger": "^6.2.0",
23
+ "jsdom": "^24.0.0",
21
24
  "mongodb": "^6.4.0",
22
25
  "nodemon": "^3.1.0",
26
+ "pdfmake": "^0.2.10",
27
+ "swagger-ui-express": "^5.0.0",
23
28
  "tango-api-schema": "^2.0.62",
24
29
  "tango-app-api-middleware": "^1.0.49-dev",
25
30
  "winston": "^3.12.0",
26
- "winston-daily-rotate-file": "^5.0.0",
27
- "html-to-pdfmake": "^2.5.6",
28
- "jsdom": "^24.0.0",
29
- "pdfmake": "^0.2.10"
31
+ "winston-daily-rotate-file": "^5.0.0"
30
32
  },
31
33
  "devDependencies": {
32
34
  "eslint": "^8.57.0",
@@ -1,6 +1,6 @@
1
1
 
2
2
  /* eslint-disable new-cap */
3
- import { logger, download, sendEmailWithSES, appConfig } from 'tango-app-api-middleware';
3
+ import { logger, download, sendEmailWithSES, appConfig, insertOpenSearchData } from 'tango-app-api-middleware';
4
4
  import * as paymentService from '../services/clientPayment.services.js';
5
5
  import * as storeService from '../services/store.service.js';
6
6
  import * as basePricingService from '../services/basePrice.service.js';
@@ -32,16 +32,17 @@ export const addBilling = async ( req, res ) => {
32
32
  billingDetails.nextBillingDate = '--';
33
33
  resultData.billingDetails = billingDetails;
34
34
  logger.info( 'Billing Details Added Successfully' );
35
- // const logObj = {
36
- // clientId: req.body.clientId,
37
- // userName: req.user?.userName,
38
- // email: req.user?.email,
39
- // date: new Date(),
40
- // logType: 'billing',
41
- // logSubType: 'billingInfo',
42
- // changes: [ 'billingAddress', 'gstNumber' ],
43
- // eventType: 'update',
44
- // };
35
+ const logObj = {
36
+ clientId: req.body.clientId,
37
+ userName: req.user?.userName,
38
+ email: req.user?.email,
39
+ date: new Date(),
40
+ logType: 'billing',
41
+ logSubType: 'billingInfo Updated',
42
+ changes: [ 'Billing Address', 'Gst Number' ],
43
+ eventType: 'update',
44
+ };
45
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
45
46
  return res.sendSuccess( { message: 'Billing Details Added Successfully', data: resultData } );
46
47
  } else {
47
48
  logger.error( 'Error Occurs WHile updating billing Details' );
@@ -72,6 +73,7 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
72
73
  price: 1,
73
74
  priceType: 1,
74
75
  virtualAccount: 1,
76
+ // paymentInvoice: 1,
75
77
  },
76
78
  },
77
79
  {
@@ -404,6 +406,17 @@ export const updateSubscription = async ( req, res ) => {
404
406
  let productExists = await clientRequestService.findOne( { clientId: requestBody.clientId, name: item.name, category: 'Trial', status: 'pending' } );
405
407
  if ( !productExists ) {
406
408
  await clientRequestService.insert( params );
409
+ const logObj = {
410
+ clientId: req.body.clientId,
411
+ userName: req.user?.userName,
412
+ email: req.user?.email,
413
+ date: new Date(),
414
+ logType: 'billing',
415
+ logSubType: 'Trial Request',
416
+ changes: [ 'Name', 'Description', 'Category' ],
417
+ eventType: 'insert',
418
+ };
419
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
407
420
  }
408
421
  }
409
422
  if ( item.type == 'subscription' ) {
@@ -444,6 +457,17 @@ export const updateSubscription = async ( req, res ) => {
444
457
  };
445
458
 
446
459
  let result = await paymentService.updateOne( { clientId: req.params.clientId }, data );
460
+ const logObj = {
461
+ clientId: req.body.clientId,
462
+ userName: req.user?.userName,
463
+ email: req.user?.email,
464
+ date: new Date(),
465
+ logType: 'billing',
466
+ logSubType: 'Subscrption Details updated',
467
+ changes: [ 'Plan Details', 'Price', 'Price Type' ],
468
+ eventType: 'update',
469
+ };
470
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
447
471
  let storeProduct = clientProducts.map( ( item ) => item.productName );
448
472
  await storeService.updateMany( { clientId: req.params.clientId, status: 'active' }, { product: storeProduct } );
449
473
 
@@ -517,6 +541,18 @@ export const unsubscribeProduct = async ( req, res ) => {
517
541
  };
518
542
  await clientRequestService.insert( params );
519
543
 
544
+ const logObj = {
545
+ clientId: req.body.clientId,
546
+ userName: req.user?.userName,
547
+ email: req.user?.email,
548
+ date: new Date(),
549
+ logType: 'billing',
550
+ logSubType: 'Unsubscribed Request',
551
+ changes: [ 'Reason', 'Description', 'Category' ],
552
+ eventType: 'insert',
553
+ };
554
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
555
+
520
556
  return res.sendSuccess( 'Request Send Successfully' );
521
557
  } catch ( e ) {
522
558
  logger.error( { error: e, function: 'unsubscribeProduct' } );
@@ -539,6 +575,17 @@ export const trialExtendRequest = async ( req, res ) => {
539
575
  status: 'pending',
540
576
  };
541
577
  await clientRequestService.insert( params );
578
+ const logObj = {
579
+ clientId: req.body.clientId,
580
+ userName: req.user?.userName,
581
+ email: req.user?.email,
582
+ date: new Date(),
583
+ logType: 'billing',
584
+ logSubType: 'Trial Extend Request',
585
+ changes: [ 'Name', 'Description', 'Category' ],
586
+ eventType: 'insert',
587
+ };
588
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
542
589
 
543
590
  return res.sendSuccess( 'Request Send Successfully' );
544
591
  } catch ( e ) {
@@ -564,6 +611,18 @@ export const trialRequest = async ( req, res ) => {
564
611
  };
565
612
  await clientRequestService.insert( params );
566
613
 
614
+ const logObj = {
615
+ clientId: req.body.clientId,
616
+ userName: req.user?.userName,
617
+ email: req.user?.email,
618
+ date: new Date(),
619
+ logType: 'billing',
620
+ logSubType: 'Trial Request',
621
+ changes: [ 'Name', 'Description', 'Category' ],
622
+ eventType: 'insert',
623
+ };
624
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
625
+
567
626
  return res.sendSuccess( 'Request Send Successfully' );
568
627
  } catch ( e ) {
569
628
  logger.error( { error: e, function: 'trialRequest' } );
@@ -577,6 +636,13 @@ export const invoiceDetails = async ( req, res ) => {
577
636
  if ( !clientInvoiceDetails ) {
578
637
  return res.sendError( 'no data found', 204 );
579
638
  }
639
+ if ( !clientInvoiceDetails?.paymentInvoice?.paymentAgreementTo || !clientInvoiceDetails?.paymentInvoice?.paymentAgreementTo.length ) {
640
+ let userDetails = await userService.findOne( { clientId: req.params.clientId, isActive: true, role: 'superadmin' } );
641
+ if ( userDetails ) {
642
+ clientInvoiceDetails.paymentInvoice.paymentAgreementTo = [ userDetails.email ];
643
+ clientInvoiceDetails.paymentInvoice.invoiceTo = [ userDetails.email ];
644
+ }
645
+ }
580
646
  let data = {
581
647
  proRate: clientInvoiceDetails?.paymentInvoice?.proRate || '',
582
648
  paymenttype: clientInvoiceDetails?.paymentInvoice?.paymentType || '',
@@ -610,7 +676,18 @@ export const updateInvoiceDetails = async ( req, res ) => {
610
676
  clientInvoiceDetails.paymentInvoice.paymentAgreementTo = data.paymentAgreementTo;
611
677
  clientInvoiceDetails.paymentInvoice.invoiceOn = data.invoiceOn;
612
678
  clientInvoiceDetails.paymentInvoice.extendPaymentPeriodDays = data.extendPaymentPeriodDays;
613
- clientInvoiceDetails.save().then( () => {
679
+ clientInvoiceDetails.save().then( async () => {
680
+ const logObj = {
681
+ clientId: req.body.clientId,
682
+ userName: req.user?.userName,
683
+ email: req.user?.email,
684
+ date: new Date(),
685
+ logType: 'billing',
686
+ logSubType: 'Update Payment and Invoice Details',
687
+ changes: [ 'Pro Rate', 'Payment Type', 'Payment Cycle', 'Currency Type', 'Invoice To', 'Payment Agreement To', 'Invoice On', 'Extend Payment PeriodDays' ],
688
+ eventType: 'update',
689
+ };
690
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
614
691
  return res.sendSuccess( 'Invoice Updated Successfully' );
615
692
  } ).catch( ( e ) => {
616
693
  return res.sendError( e, 500 );
@@ -751,6 +828,17 @@ export const trialApproval = async ( req, res ) => {
751
828
  await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
752
829
  }
753
830
  }
831
+ const logObj = {
832
+ clientId: req.body.clientId,
833
+ userName: req.user?.userName,
834
+ email: req.user?.email,
835
+ date: new Date(),
836
+ logType: 'billing',
837
+ logSubType: 'Trial Approved',
838
+ changes: [ 'status' ],
839
+ eventType: 'update',
840
+ };
841
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
754
842
  return res.sendSuccess( 'updated Successfully' );
755
843
  } );
756
844
  } catch ( e ) {
@@ -801,6 +889,17 @@ export const trialExtendRequestApproval = async ( req, res ) => {
801
889
  };
802
890
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
803
891
  }
892
+ const logObj = {
893
+ clientId: req.body.clientId,
894
+ userName: req.user?.userName,
895
+ email: req.user?.email,
896
+ date: new Date(),
897
+ logType: 'billing',
898
+ logSubType: 'Trial Extend Approved',
899
+ changes: [ 'status' ],
900
+ eventType: 'update',
901
+ };
902
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
804
903
  return res.sendSuccess( 'Trial Extended Successfully' );
805
904
  } ).catch( ( e ) => {
806
905
  logger.error( { error: e, function: 'trialExtendRequestApproval' } );
@@ -867,20 +966,21 @@ export const productSubscribe = async ( req, res ) => {
867
966
  }
868
967
  }
869
968
  product = product.filter( ( item ) => !removeProducts.includes( item.productName ) );
870
- req.body = {
871
- 'camaraPerSqft': clientInfo.planDetails.storeSize,
872
- 'storesCount': clientInfo.planDetails.totalStores,
873
- 'planName': clientInfo.planDetails.subscriptionPeriod,
874
- 'products': product.map( ( item ) => item.productName ),
875
- 'currencyType': 'rupees',
876
- };
877
- let pricingDetails = await calculatePricing( req, res );
878
- clientInfo.price = pricingDetails.price;
969
+ // req.body = {
970
+ // 'camaraPerSqft': clientInfo.planDetails.storeSize,
971
+ // 'storesCount': clientInfo.planDetails.totalStores,
972
+ // 'planName': clientInfo.planDetails.subscriptionPeriod,
973
+ // 'products': product.map( ( item ) => item.productName ),
974
+ // 'currencyType': 'rupees',
975
+ // };
976
+ // let pricingDetails = await calculatePricing( req, res );
977
+ // clientInfo.price = pricingDetails.price;
879
978
  if ( product.length > 1 ) {
880
979
  clientInfo.planDetails.subscriptionType = 'premium';
881
980
  }
882
981
  clientInfo.planDetails.product = product;
883
982
  clientInfo.save().then( async () => {
983
+ updatePricing( req, res, true );
884
984
  let userDetails= await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
885
985
  if ( userDetails ) {
886
986
  let data = {
@@ -899,6 +999,17 @@ export const productSubscribe = async ( req, res ) => {
899
999
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
900
1000
  }
901
1001
  } );
1002
+ const logObj = {
1003
+ clientId: req.body.clientId,
1004
+ userName: req.user?.userName,
1005
+ email: req.user?.email,
1006
+ date: new Date(),
1007
+ logType: 'billing',
1008
+ logSubType: 'Product subscribe and unsubscribe',
1009
+ changes: [ 'Plan Details' ],
1010
+ eventType: 'update',
1011
+ };
1012
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
902
1013
  return res.sendSuccess( 'Product Subscribed Successfully' );
903
1014
  } catch ( e ) {
904
1015
  logger.error( { error: e, function: 'updateProductSubscribe' } );
@@ -937,6 +1048,17 @@ export const unsubscribeApproval = async ( req, res ) => {
937
1048
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
938
1049
  }
939
1050
  }
1051
+ const logObj = {
1052
+ clientId: req.body.clientId,
1053
+ userName: req.user?.userName,
1054
+ email: req.user?.email,
1055
+ date: new Date(),
1056
+ logType: 'billing',
1057
+ logSubType: 'Unsubscribed Approved',
1058
+ changes: [ 'status' ],
1059
+ eventType: 'update',
1060
+ };
1061
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
940
1062
  return res.sendSuccess( 'updated Successfully' );
941
1063
  } );
942
1064
  } catch ( e ) {
@@ -1204,6 +1326,7 @@ export const addStoreProduct = async ( req, res ) => {
1204
1326
  clientInfo.planDetails.product = clientProduct;
1205
1327
  clientInfo.save();
1206
1328
  storeDetails.forEach( async ( item ) => {
1329
+ updatePricing( req, res, true );
1207
1330
  let product;
1208
1331
  if ( item?.product?.length ) {
1209
1332
  product = item.product.concat( storeProduct );
@@ -1221,6 +1344,17 @@ export const addStoreProduct = async ( req, res ) => {
1221
1344
  }
1222
1345
  await storeService.updateOne( { storeId: item.storeId, clientId: req.body.clientId }, { product: product } );
1223
1346
  } );
1347
+ const logObj = {
1348
+ clientId: req.body.clientId,
1349
+ userName: req.user?.userName,
1350
+ email: req.user?.email,
1351
+ date: new Date(),
1352
+ logType: 'billing',
1353
+ logSubType: 'Store Prosuct Addition',
1354
+ changes: [ 'product' ],
1355
+ eventType: 'update',
1356
+ };
1357
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1224
1358
  return res.sendSuccess( 'product updated Successfully' );
1225
1359
  } catch ( e ) {
1226
1360
  logger.error( { error: e, function: 'addStoreProduct' } );
@@ -1433,7 +1567,7 @@ export const priceList = async ( req, res ) => {
1433
1567
  } );
1434
1568
  data = temp;
1435
1569
  let discountPrice = totalProductPrice - totalnegotiatePrice;
1436
- let discountPercentage = totalnegotiatePrice > 0 ? ( totalnegotiatePrice / totalProductPrice ) * 100 : 0;
1570
+ let discountPercentage = discountPrice > 0 ? ( discountPrice / totalProductPrice ) * 100 : 0;
1437
1571
  let gstAmount = discountTotalPrice * ( 18 / 100 );
1438
1572
  let finalValue = parseFloat( discountTotalPrice ) + gstAmount;
1439
1573
  let result = {
@@ -1457,69 +1591,12 @@ export const priceList = async ( req, res ) => {
1457
1591
  export const pricingListUpdate = async ( req, res ) => {
1458
1592
  try {
1459
1593
  let getPriceInfo = await basePricingService.findOne( { clientId: { $exists: true }, clientId: req.body.clientId }, { standard: 1, step: 1 } );
1460
- let baseProduct = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
1461
1594
  if ( !getPriceInfo ) {
1462
1595
  if ( !req.body.client.planDetails.product.length ) {
1463
1596
  return res.sendError( 'no product found', 204 );
1464
1597
  }
1465
- let products = req.body.client.planDetails.product.map( ( item ) => item.productName );
1466
- let standardList = [];
1467
- let stepList = [];
1468
- products.forEach( ( product ) => {
1469
- let baseDetails = baseProduct.basePricing.find( ( item ) => item.productName == product );
1470
- let discountPrice = ( baseDetails.basePrice * baseDetails.discoutPercentage ) / 100;
1471
- standardList.push(
1472
- {
1473
- productName: product,
1474
- discountPercentage: baseDetails.discoutPercentage,
1475
- basePrice: baseDetails.basePrice,
1476
- negotiatePrice: baseDetails.basePrice - discountPrice,
1477
- },
1478
- );
1479
- stepList.push(
1480
- {
1481
- productName: product,
1482
- discountPercentage: baseDetails.discoutPercentage,
1483
- basePrice: baseDetails.basePrice,
1484
- negotiatePrice: baseDetails.basePrice - discountPrice,
1485
- storeRange: '1-100',
1486
- },
1487
- );
1488
- } );
1489
- let data = {
1490
- standard: standardList,
1491
- step: stepList,
1492
- clientId: req.body.clientId,
1493
- };
1494
- await basePricingService.create( data );
1495
- let clientDetails = await paymentService.findOne( { clientId: req.body.clientId } );
1496
- if ( clientDetails ) {
1497
- let product = [];
1498
- let clientId = req.body.clientId;
1499
- clientDetails.planDetails.product.forEach( ( item ) => {
1500
- product.push( {
1501
- productName: item.productName,
1502
- status: 'trial',
1503
- trialStartDate: new Date(),
1504
- trialEndDate: new Date( dayjs().add( 13, 'days' ).format( 'YYYY-MM-DD' ) ),
1505
- } );
1506
- } );
1507
- req.body = {
1508
- 'camaraPerSqft': clientDetails.planDetails.storeSize,
1509
- 'storesCount': clientDetails.planDetails.totalStores,
1510
- 'planName': clientDetails.planDetails.subscriptionPeriod,
1511
- 'products': product.map( ( item ) => item.productName ),
1512
- 'currencyType': 'rupees',
1513
- };
1514
- let pricingDetails = await calculatePricing( req, res );
1515
- let details = {
1516
- 'priceType': 'standard',
1517
- 'planDetails.paymentStatus': clientDetails?.subscriptionType == 'free' ? 'free' : 'trial',
1518
- 'planDetails.product': product,
1519
- 'price': pricingDetails.price,
1520
- };
1521
- await paymentService.updateOne( { clientId: clientId }, details );
1522
- }
1598
+ updatePricing( req, res, false );
1599
+
1523
1600
  return res.sendSuccess( 'Pricig Updated Successfully' );
1524
1601
  }
1525
1602
  if ( getPriceInfo && !req.body?.products?.length ) {
@@ -1548,7 +1625,7 @@ export const pricingListUpdate = async ( req, res ) => {
1548
1625
  getPriceInfo.step = req.body.products;
1549
1626
  }
1550
1627
  getPriceInfo.save().then( async () => {
1551
- let userDetails= await userService.findOne( { clientId: invoiceDetails.clientId, role: 'superadmin' } );
1628
+ let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
1552
1629
  if ( userDetails ) {
1553
1630
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/revisedPriceEmail.hbs', 'utf8' );
1554
1631
  const template = Handlebars.compile( templateHtml );
@@ -1562,7 +1639,24 @@ export const pricingListUpdate = async ( req, res ) => {
1562
1639
  };
1563
1640
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1564
1641
  }
1565
-
1642
+ let keys = [];
1643
+ if ( req.body.type == 'standard' ) {
1644
+ keys = [ 'productName', 'discountPercentage', 'basePrice', 'negotiatePrice' ];
1645
+ }
1646
+ if ( req.body.type == 'standard' ) {
1647
+ keys = [ 'productName', 'discountPercentage', 'basePrice', 'negotiatePrice', 'storeRange' ];
1648
+ }
1649
+ const logObj = {
1650
+ clientId: req.body.clientId,
1651
+ userName: req.user?.userName,
1652
+ email: req.user?.email,
1653
+ date: new Date(),
1654
+ logType: 'billing',
1655
+ logSubType: 'Update Product Pricing Details',
1656
+ changes: keys,
1657
+ eventType: 'update',
1658
+ };
1659
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1566
1660
  return res.sendSuccess( 'Pricig Updated Successfully' );
1567
1661
  } );
1568
1662
  } catch ( e ) {
@@ -1571,6 +1665,78 @@ export const pricingListUpdate = async ( req, res ) => {
1571
1665
  }
1572
1666
  };
1573
1667
 
1668
+
1669
+ async function updatePricing( req, res, update ) {
1670
+ let baseProduct = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
1671
+ let clientDetails = await paymentService.findOne( { clientId: req.body.clientId } );
1672
+ if ( clientDetails ) {
1673
+ let products = clientDetails.planDetails.product.map( ( item ) => item.productName );
1674
+ let standardList = [];
1675
+ let stepList = [];
1676
+ products.forEach( ( product ) => {
1677
+ let baseDetails = baseProduct.basePricing.find( ( item ) => item.productName == product );
1678
+ let discountPrice = ( baseDetails.basePrice * baseDetails.discoutPercentage ) / 100;
1679
+ standardList.push(
1680
+ {
1681
+ productName: product,
1682
+ discountPercentage: baseDetails.discoutPercentage,
1683
+ basePrice: baseDetails.basePrice,
1684
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1685
+ },
1686
+ );
1687
+ stepList.push(
1688
+ {
1689
+ productName: product,
1690
+ discountPercentage: baseDetails.discoutPercentage,
1691
+ basePrice: baseDetails.basePrice,
1692
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1693
+ storeRange: '1-100',
1694
+ },
1695
+ );
1696
+ } );
1697
+ let data = {
1698
+ standard: standardList,
1699
+ step: stepList,
1700
+ clientId: req.body.clientId,
1701
+ };
1702
+ if ( !update ) {
1703
+ await basePricingService.create( data );
1704
+ } else {
1705
+ delete data.clientId;
1706
+ await basePricingService.updateOne( { clientId: req.body.clientId }, data );
1707
+ }
1708
+ let product = [];
1709
+ let clientId = req.body.clientId;
1710
+ if ( !update ) {
1711
+ clientDetails.planDetails.product.forEach( ( item ) => {
1712
+ product.push( {
1713
+ productName: item.productName,
1714
+ status: 'trial',
1715
+ trialStartDate: new Date(),
1716
+ trialEndDate: new Date( dayjs().add( 13, 'days' ).format( 'YYYY-MM-DD' ) ),
1717
+ } );
1718
+ } );
1719
+ } else {
1720
+ product = clientDetails.planDetails.product;
1721
+ }
1722
+ req.body = {
1723
+ 'camaraPerSqft': clientDetails.planDetails.storeSize,
1724
+ 'storesCount': clientDetails.planDetails.totalStores,
1725
+ 'planName': clientDetails.planDetails.subscriptionPeriod,
1726
+ 'products': product.map( ( item ) => item.productName ),
1727
+ 'currencyType': 'rupees',
1728
+ };
1729
+ let pricingDetails = await calculatePricing( req, res );
1730
+ let details = {
1731
+ 'priceType': 'standard',
1732
+ 'planDetails.paymentStatus': clientDetails?.subscriptionType == 'free' ? 'free' : 'trial',
1733
+ 'planDetails.product': product,
1734
+ 'price': pricingDetails.price,
1735
+ };
1736
+ await paymentService.updateOne( { clientId: clientId }, details );
1737
+ }
1738
+ }
1739
+
1574
1740
  export const updatedRevisedPrice = async ( req, res ) => {
1575
1741
  try {
1576
1742
  let invoiceDetails = await invoiceService.findOne( { invoice: req.body.invoice } );
@@ -1595,6 +1761,17 @@ export const updatedRevisedPrice = async ( req, res ) => {
1595
1761
  };
1596
1762
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1597
1763
  }
1764
+ const logObj = {
1765
+ clientId: req.body.clientId,
1766
+ userName: req.user?.userName,
1767
+ email: req.user?.email,
1768
+ date: new Date(),
1769
+ logType: 'billing',
1770
+ logSubType: 'Revised Price Updation',
1771
+ changes: [ 'amount', 'revisedAmount', 'discount' ],
1772
+ eventType: 'update',
1773
+ };
1774
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1598
1775
  return res.sendSuccess( 'Credit notes Updated Successfully' );
1599
1776
  } );
1600
1777
  } catch ( e ) {
@@ -1605,7 +1782,7 @@ export const updatedRevisedPrice = async ( req, res ) => {
1605
1782
 
1606
1783
  export const unpaidInvoiceList = async ( req, res ) => {
1607
1784
  try {
1608
- let invoiceDetails = await invoiceService.find( { clientId: req.params.clientId, status: { $nin: [ 'paid', 'trial', 'free' ] } }, { invoice: 1, status: 1, amount: 1, revisedAmount: 1, totalAmount: 1, discount: 1 } );
1785
+ let invoiceDetails = await invoiceService.find( { clientId: req.params.clientId, status: { $nin: [ 'Payment Received', 'trial', 'free' ] } }, { invoice: 1, status: 1, amount: 1, revisedAmount: 1, totalAmount: 1, discount: 1 } );
1609
1786
  if ( !invoiceDetails.length ) {
1610
1787
  return res.sendError( 'no data found', 204 );
1611
1788
  }
@@ -0,0 +1,123 @@
1
+
2
+
3
+ import * as schema from '../dtos/validation.dtos.js';
4
+ import j2s from 'joi-to-swagger';
5
+
6
+ export const paymentDoc = {
7
+ '/v3/paymentSubscription/addBilling': {
8
+ post: {
9
+ tags: [ 'payment' ],
10
+ description: 'Add Billing Details',
11
+ operationId: '',
12
+ parameters: {},
13
+ requestBody: {
14
+ content: {
15
+ 'application/json': {
16
+ schema: j2s( schema.validateBillingSchema ).swagger,
17
+ },
18
+ },
19
+ },
20
+ responses: {
21
+ 200: { description: 'Billing Details Updated Successfully.' },
22
+ 401: { description: 'Incorrect Update' },
23
+ 422: { description: 'Field Error' },
24
+ },
25
+ },
26
+ },
27
+
28
+ '/v3/paymentSubscription/clientBillingSubscriptionInfo/{clientId}': {
29
+ get: {
30
+ tags: [ 'payment' ],
31
+ description: 'Get Client Details',
32
+ operationId: '',
33
+ parameters: [
34
+ {
35
+ in: 'path',
36
+ name: 'clientId',
37
+ schema: { type: 'string' },
38
+ required: true,
39
+ },
40
+ ],
41
+ responses: {
42
+ 200: { description: 'Get Client Details Successfully' },
43
+ 401: { description: 'Incorrect Update' },
44
+ 422: { description: 'Field Error' },
45
+ },
46
+ },
47
+ },
48
+
49
+ '/v3/paymentSubscription/basePricing': {
50
+ post: {
51
+ tags: [ 'payment' ],
52
+ description: 'Get Client pricing Details',
53
+ operationId: '',
54
+ parameters: [],
55
+ requestBody: {
56
+ content: {
57
+ 'application/json': {
58
+ schema: j2s( schema.validateProductsSchema ).swagger,
59
+ },
60
+ },
61
+ },
62
+ responses: {
63
+ 200: { description: 'Get Client pricing Details Successfully' },
64
+ 401: { description: 'Incorrect Update' },
65
+ 422: { description: 'Field Error' },
66
+ },
67
+ },
68
+ },
69
+
70
+ '/v3/paymentSubscription/update/subscription/{clientId}': {
71
+ put: {
72
+ tags: [ 'payment' ],
73
+ description: 'Update Subscription CLients',
74
+ operationId: '',
75
+ parameters: [
76
+ {
77
+ in: 'path',
78
+ name: 'clientId',
79
+ schema: {
80
+ type: 'string',
81
+ },
82
+ required: true,
83
+ },
84
+ ],
85
+ requestBody: {
86
+ content: {
87
+ 'application/json': {
88
+ schema: j2s( schema.validateUpdateSubscriptionSchema ).swagger,
89
+ },
90
+ },
91
+ },
92
+ responses: {
93
+ 200: { description: 'Subscription Details Updated Successfully' },
94
+ 401: { description: 'Incorrect Update' },
95
+ 422: { description: 'Field Error' },
96
+ },
97
+ },
98
+ },
99
+
100
+ '/v3/paymentSubscription/getTrialProducts': {
101
+ get: {
102
+ tags: [ 'payment' ],
103
+ description: 'Get Trial Products Details',
104
+ operationId: '',
105
+ parameters: [
106
+ {
107
+ in: 'query',
108
+ name: 'clientId',
109
+ schema: { type: 'string' },
110
+ required: true,
111
+ },
112
+ ],
113
+ responses: {
114
+ 200: { description: 'Get Trial Products Details Successfully' },
115
+ 401: { description: 'Incorrect Update' },
116
+ 422: { description: 'Field Error' },
117
+ },
118
+ },
119
+ },
120
+
121
+
122
+ };
123
+
@@ -1,160 +1,193 @@
1
1
  import joi from 'joi';
2
2
 
3
+ export const validateBillingSchema = joi.object( {
4
+ clientId: joi.string().required(),
5
+ gstNo: joi.string().required(),
6
+ billingAddress: joi.string().required(),
7
+ } );
8
+
3
9
  export const validateBillingParams = {
4
- body: joi.object( {
5
- clientId: joi.string().required(),
6
- gstNo: joi.string().required(),
7
- billingAddress: joi.string().required(),
8
- } ),
10
+ body: validateBillingSchema,
9
11
  };
10
12
 
13
+ export const validateBrandSchema = joi.object( {
14
+ clientId: joi.string().required(),
15
+ } );
16
+
11
17
  export const validateBrandParams = {
12
- params: joi.object( {
13
- clientId: joi.string().required(),
14
- } ),
18
+ params: validateBrandSchema,
15
19
  };
16
20
 
21
+ export const validateStoreSchema = joi.object( {
22
+ clientId: joi.string().required(),
23
+ } );
24
+
17
25
  export const validateStoreParams = {
18
- query: joi.object( {
19
- clientId: joi.string().required(),
20
- } ),
26
+ query: validateStoreSchema,
21
27
  };
22
28
 
29
+ export const validateProductListSchema = joi.object( {
30
+ clientId: joi.string().required(),
31
+ sortColumn: joi.string().required(),
32
+ sortBy: joi.number().required(),
33
+ } );
34
+
23
35
  export const validateProductListParams = {
24
- query: joi.object( {
25
- clientId: joi.string().required(),
26
- sortColumn: joi.string().required(),
27
- sortBy: joi.number().required(),
28
- } ),
36
+ query: validateProductListSchema,
29
37
  };
30
38
 
39
+ export const validateProductsSchema = joi.object( {
40
+ camaraPerSqft: joi.string().required(),
41
+ currencyType: joi.string().required(),
42
+ planName: joi.string().required(),
43
+ products: joi.array().required(),
44
+ storesCount: joi.string().required(),
45
+ } );
46
+
31
47
  export const validateProducts = {
32
- body: joi.object( {
33
- camaraPerSqft: joi.string().required(),
34
- currencyType: joi.string().required(),
35
- planName: joi.string().required(),
36
- products: joi.array().required(),
37
- storesCount: joi.string().required(),
38
- } ),
48
+ body: validateProductsSchema,
39
49
  };
40
50
 
51
+ export const validateunsubscribeSchema = joi.object( {
52
+ reason: joi.string().required(),
53
+ description: joi.string().optional().empty( '' ),
54
+ clientId: joi.string().required(),
55
+ } );
56
+
41
57
  export const validateunsubscribeParams = {
42
- body: joi.object( {
43
- reason: joi.string().required(),
44
- description: joi.string().optional().empty( '' ),
45
- clientId: joi.string().required(),
46
- } ),
58
+ body: validateunsubscribeSchema,
47
59
  };
48
60
 
61
+ export const validateTrialExtendandSubscibeSchema = joi.object( {
62
+ product: joi.string().required(),
63
+ clientId: joi.string().required(),
64
+ } );
65
+
49
66
  export const validateTrialExtendandSubscibeParams = {
50
- body: joi.object( {
51
- product: joi.string().required(),
52
- clientId: joi.string().required(),
53
- } ),
67
+ body: validateTrialExtendandSubscibeSchema,
54
68
  };
55
69
 
70
+ export const validateSubscibeSchema = joi.object( {
71
+ product: joi.array().required(),
72
+ clientId: joi.string().required(),
73
+ } );
74
+
56
75
  export const validateSubscibeParams = {
57
- body: joi.object( {
58
- product: joi.array().required(),
59
- clientId: joi.string().required(),
60
- } ),
76
+ body: validateSubscibeSchema,
61
77
  };
62
78
 
79
+ export const validateTrialandUnsubscribeSchema = joi.object( {
80
+ id: joi.string().required(),
81
+ type: joi.string().required(),
82
+ } );
83
+
63
84
  export const validateTrialandUnsubscribeParams = {
64
- body: joi.object( {
65
- id: joi.string().required(),
66
- type: joi.string().required(),
67
- } ),
85
+ body: validateTrialandUnsubscribeSchema,
68
86
  };
69
87
 
88
+ export const validateTrialExtendRequestSchema = joi.object( {
89
+ clientId: joi.string().required(),
90
+ days: joi.number().required(),
91
+ product: joi.string().required(),
92
+ } );
70
93
 
71
94
  export const validateTrialExtendRequestParams = {
72
- body: joi.object( {
73
- clientId: joi.string().required(),
74
- days: joi.number().required(),
75
- product: joi.string().required(),
76
- } ),
95
+ body: validateTrialExtendRequestSchema,
77
96
  };
78
97
 
98
+ export const validateStoreViewSchema = joi.object( {
99
+ limit: joi.number().required(),
100
+ offset: joi.number().required(),
101
+ clientId: joi.string().required(),
102
+ sortColumn: joi.string().optional().empty( '' ),
103
+ sortBy: joi.number().optional().empty( '' ),
104
+ searchValue: joi.string().optional().empty( '' ),
105
+ product: joi.array().optional().empty(),
106
+ store: joi.array().optional().empty(),
107
+ location: joi.array().optional().empty(),
108
+ } );
79
109
 
80
110
  export const validateStoreViewParams = {
81
- body: joi.object( {
82
- limit: joi.number().required(),
83
- offset: joi.number().required(),
84
- clientId: joi.string().required(),
85
- sortColumn: joi.string().optional().empty( '' ),
86
- sortBy: joi.number().optional().empty( '' ),
87
- searchValue: joi.string().optional().empty( '' ),
88
- product: joi.array().optional().empty(),
89
- store: joi.array().optional().empty(),
90
- location: joi.array().optional().empty(),
91
- } ),
111
+ body: validateStoreViewSchema,
92
112
  };
93
113
 
114
+ export const validateAddStoreProductSchema = joi.object( {
115
+ clientId: joi.string().required(),
116
+ store: joi.array().required().empty(),
117
+ product: joi.array().required(),
118
+ selectAll: joi.boolean().optional(),
119
+ } );
120
+
94
121
  export const validateAddStoreProductParams = {
95
- body: joi.object( {
96
- clientId: joi.string().required(),
97
- store: joi.array().required().empty(),
98
- product: joi.array().required(),
99
- selectAll: joi.boolean().optional(),
100
- } ),
122
+ body: validateAddStoreProductSchema,
101
123
  };
102
124
 
125
+ export const validateInvoiceSchema = joi.object( {
126
+ limit: joi.number().required(),
127
+ offset: joi.number().required(),
128
+ searchValue: joi.string().optional().empty( '' ),
129
+ filter: joi.string().optional(),
130
+ sortColumn: joi.string().optional(),
131
+ sortBy: joi.number().optional(),
132
+ clientId: joi.string().required(),
133
+ export: joi.boolean().optional(),
134
+ } );
103
135
 
104
136
  export const validateInvoiceParams = {
105
- body: joi.object( {
106
- limit: joi.number().required(),
107
- offset: joi.number().required(),
108
- searchValue: joi.string().optional().empty( '' ),
109
- filter: joi.string().optional(),
110
- sortColumn: joi.string().optional(),
111
- sortBy: joi.number().optional(),
112
- clientId: joi.string().required(),
113
- export: joi.boolean().optional(),
114
- } ),
137
+ body: validateInvoiceSchema,
115
138
  };
116
139
 
140
+ export const validatePriceSchema = joi.object( {
141
+ type: joi.string().optional(),
142
+ clientId: joi.string().required(),
143
+ products: joi.array().optional(),
144
+ } );
145
+
117
146
  export const validatePriceParams = {
118
- body: joi.object( {
119
- type: joi.string().optional(),
120
- clientId: joi.string().required(),
121
- products: joi.array().optional(),
122
- } ),
147
+ body: validatePriceSchema,
123
148
  };
124
149
 
150
+ export const revisedSchema = joi.object( {
151
+ invoice: joi.string().required(),
152
+ revisedAmount: joi.number().required(),
153
+ discount: joi.number().required(),
154
+ } );
155
+
125
156
  export const revisedParams = {
126
- body: joi.object( {
127
- invoice: joi.string().required(),
128
- revisedAmount: joi.number().required(),
129
- discount: joi.number().required(),
130
- } ),
157
+ body: revisedSchema,
131
158
  };
132
159
 
133
160
 
161
+ export const validatePriceListSchema = joi.object( {
162
+ priceType: joi.string().required(),
163
+ clientId: joi.string().required(),
164
+ } );
165
+
134
166
  export const validatePriceListParams = {
135
- body: joi.object( {
136
- priceType: joi.string().required(),
137
- clientId: joi.string().required(),
138
- } ),
167
+ body: validatePriceListSchema,
139
168
  };
140
169
 
170
+ export const validateStoreProductsSchema = joi.object( {
171
+ clientId: joi.string().required(),
172
+ store: joi.array().required().empty(),
173
+ } );
174
+
141
175
  export const validateStoreProductsParams = {
142
- body: joi.object( {
143
- clientId: joi.string().required(),
144
- store: joi.array().required().empty(),
145
- } ),
146
- };
147
-
148
- export const validateUpdateSubscriptionSchema = {
149
- body: joi.object( {
150
- clientId: joi.string().required(),
151
- price: joi.number().required(),
152
- priceType: joi.string().required(),
153
- subscriptionType: joi.string().required(),
154
- subscriptionPeriod: joi.string().required(),
155
- totalCamera: joi.number().required(),
156
- totalStores: joi.string().required(),
157
- storeSize: joi.string().required(),
158
- products: joi.array().required(),
159
- } ),
176
+ body: validateStoreProductsSchema,
177
+ };
178
+
179
+ export const validateUpdateSubscriptionSchema =joi.object( {
180
+ clientId: joi.string().required(),
181
+ price: joi.number().required(),
182
+ priceType: joi.string().required(),
183
+ subscriptionType: joi.string().required(),
184
+ subscriptionPeriod: joi.string().required(),
185
+ totalCamera: joi.number().required(),
186
+ totalStores: joi.string().required(),
187
+ storeSize: joi.string().required(),
188
+ products: joi.array().required(),
189
+ } );
190
+
191
+ export const validateUpdateSubscriptionParams = {
192
+ body: validateUpdateSubscriptionSchema,
160
193
  };
@@ -24,7 +24,7 @@ paymentSubscriptionRouter.put( '/update/subscription/:clientId', isAllowedSessio
24
24
  userType: [ 'tango', 'client' ], access: [
25
25
  { featureName: 'settings', name: 'paymentSubscriptions', permissions: [ 'isEdit' ] },
26
26
  ],
27
- } ), validate( validationDtos.validateUpdateSubscriptionSchema ), validateClient, paymentController.updateSubscription );
27
+ } ), validate( validationDtos.validateUpdateSubscriptionParams ), validateClient, paymentController.updateSubscription );
28
28
 
29
29
  paymentSubscriptionRouter.get( '/getTrialProducts', isAllowedSessionHandler, authorize( {
30
30
  userType: [ 'tango', 'client' ], access: [
@@ -84,13 +84,13 @@ paymentSubscriptionRouter.post( '/admin/subscribeproduct', isAllowedSessionHandl
84
84
  userType: [ 'tango' ], access: [
85
85
  { featureName: 'settings', name: 'paymentSubscriptions', permissions: [ 'isEdit' ] },
86
86
  ],
87
- } ), validate( validationDtos.validateSubscibeParams ), paymentController.productSubscribe );
87
+ } ), validate( validationDtos.validateSubscibeParams ), validateClient, paymentController.productSubscribe );
88
88
 
89
89
  paymentSubscriptionRouter.post( '/admin/unsubscribeApproval', isAllowedSessionHandler, authorize( {
90
90
  userType: [ 'tango' ], access: [
91
91
  { featureName: 'settings', name: 'paymentSubscriptions', permissions: [ 'isEdit' ] },
92
92
  ],
93
- } ), validate( validationDtos.validateTrialandUnsubscribeParams ), paymentController.unsubscribeApproval );
93
+ } ), validate( validationDtos.validateTrialandUnsubscribeParams ), validateClient, paymentController.unsubscribeApproval );
94
94
 
95
95
  paymentSubscriptionRouter.get( '/admin/getProductViewList', isAllowedSessionHandler, authorize( {
96
96
  userType: [ 'tango' ], access: [
@@ -16,3 +16,7 @@ export const create = ( record ) => {
16
16
  return model.basePricingModel.create( record );
17
17
  };
18
18
 
19
+ export const updateOne = ( query, record ) => {
20
+ return model.basePricingModel.updateOne( query, { $set: record } );
21
+ };
22
+