tango-app-api-payment-subscription 3.0.22-dev → 3.0.24-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 { paymentDocs } from './src/docs/payment.docs.js';
4
5
 
5
- export { paymentSubscriptionRouter };
6
+ export { paymentSubscriptionRouter, paymentDocs };
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.24-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 );
@@ -707,6 +784,8 @@ export const trialApproval = async ( req, res ) => {
707
784
  }
708
785
  requestData.status = 'completed';
709
786
  requestData.save().then( async () => {
787
+ req.body.clientId = requestData.clientId;
788
+ updatePricing( req, res, true );
710
789
  if ( req.body.type == 'approve' ) {
711
790
  let clientProducts = await paymentService.findOne( { clientId: requestData.clientId, status: 'active' }, { planDetails: 1 } );
712
791
  if ( clientProducts?.planDetails.subscriptionType == 'free' ) {
@@ -751,6 +830,17 @@ export const trialApproval = async ( req, res ) => {
751
830
  await sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
752
831
  }
753
832
  }
833
+ const logObj = {
834
+ clientId: req.body.clientId,
835
+ userName: req.user?.userName,
836
+ email: req.user?.email,
837
+ date: new Date(),
838
+ logType: 'billing',
839
+ logSubType: 'Trial Approved',
840
+ changes: [ 'status' ],
841
+ eventType: 'update',
842
+ };
843
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
754
844
  return res.sendSuccess( 'updated Successfully' );
755
845
  } );
756
846
  } catch ( e ) {
@@ -801,6 +891,17 @@ export const trialExtendRequestApproval = async ( req, res ) => {
801
891
  };
802
892
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
803
893
  }
894
+ const logObj = {
895
+ clientId: req.body.clientId,
896
+ userName: req.user?.userName,
897
+ email: req.user?.email,
898
+ date: new Date(),
899
+ logType: 'billing',
900
+ logSubType: 'Trial Extend Approved',
901
+ changes: [ 'status' ],
902
+ eventType: 'update',
903
+ };
904
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
804
905
  return res.sendSuccess( 'Trial Extended Successfully' );
805
906
  } ).catch( ( e ) => {
806
907
  logger.error( { error: e, function: 'trialExtendRequestApproval' } );
@@ -867,20 +968,21 @@ export const productSubscribe = async ( req, res ) => {
867
968
  }
868
969
  }
869
970
  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;
971
+ // req.body = {
972
+ // 'camaraPerSqft': clientInfo.planDetails.storeSize,
973
+ // 'storesCount': clientInfo.planDetails.totalStores,
974
+ // 'planName': clientInfo.planDetails.subscriptionPeriod,
975
+ // 'products': product.map( ( item ) => item.productName ),
976
+ // 'currencyType': 'rupees',
977
+ // };
978
+ // let pricingDetails = await calculatePricing( req, res );
979
+ // clientInfo.price = pricingDetails.price;
879
980
  if ( product.length > 1 ) {
880
981
  clientInfo.planDetails.subscriptionType = 'premium';
881
982
  }
882
983
  clientInfo.planDetails.product = product;
883
984
  clientInfo.save().then( async () => {
985
+ updatePricing( req, res, true );
884
986
  let userDetails= await userService.findOne( { clientId: clientInfo.clientId, role: 'superadmin' } );
885
987
  if ( userDetails ) {
886
988
  let data = {
@@ -899,6 +1001,17 @@ export const productSubscribe = async ( req, res ) => {
899
1001
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
900
1002
  }
901
1003
  } );
1004
+ const logObj = {
1005
+ clientId: req.body.clientId,
1006
+ userName: req.user?.userName,
1007
+ email: req.user?.email,
1008
+ date: new Date(),
1009
+ logType: 'billing',
1010
+ logSubType: 'Product subscribe and unsubscribe',
1011
+ changes: [ 'Plan Details' ],
1012
+ eventType: 'update',
1013
+ };
1014
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
902
1015
  return res.sendSuccess( 'Product Subscribed Successfully' );
903
1016
  } catch ( e ) {
904
1017
  logger.error( { error: e, function: 'updateProductSubscribe' } );
@@ -937,6 +1050,17 @@ export const unsubscribeApproval = async ( req, res ) => {
937
1050
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
938
1051
  }
939
1052
  }
1053
+ const logObj = {
1054
+ clientId: req.body.clientId,
1055
+ userName: req.user?.userName,
1056
+ email: req.user?.email,
1057
+ date: new Date(),
1058
+ logType: 'billing',
1059
+ logSubType: 'Unsubscribed Approved',
1060
+ changes: [ 'status' ],
1061
+ eventType: 'update',
1062
+ };
1063
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
940
1064
  return res.sendSuccess( 'updated Successfully' );
941
1065
  } );
942
1066
  } catch ( e ) {
@@ -1204,6 +1328,7 @@ export const addStoreProduct = async ( req, res ) => {
1204
1328
  clientInfo.planDetails.product = clientProduct;
1205
1329
  clientInfo.save();
1206
1330
  storeDetails.forEach( async ( item ) => {
1331
+ updatePricing( req, res, true );
1207
1332
  let product;
1208
1333
  if ( item?.product?.length ) {
1209
1334
  product = item.product.concat( storeProduct );
@@ -1221,6 +1346,17 @@ export const addStoreProduct = async ( req, res ) => {
1221
1346
  }
1222
1347
  await storeService.updateOne( { storeId: item.storeId, clientId: req.body.clientId }, { product: product } );
1223
1348
  } );
1349
+ const logObj = {
1350
+ clientId: req.body.clientId,
1351
+ userName: req.user?.userName,
1352
+ email: req.user?.email,
1353
+ date: new Date(),
1354
+ logType: 'billing',
1355
+ logSubType: 'Store Prosuct Addition',
1356
+ changes: [ 'product' ],
1357
+ eventType: 'update',
1358
+ };
1359
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1224
1360
  return res.sendSuccess( 'product updated Successfully' );
1225
1361
  } catch ( e ) {
1226
1362
  logger.error( { error: e, function: 'addStoreProduct' } );
@@ -1433,7 +1569,7 @@ export const priceList = async ( req, res ) => {
1433
1569
  } );
1434
1570
  data = temp;
1435
1571
  let discountPrice = totalProductPrice - totalnegotiatePrice;
1436
- let discountPercentage = totalnegotiatePrice > 0 ? ( totalnegotiatePrice / totalProductPrice ) * 100 : 0;
1572
+ let discountPercentage = discountPrice > 0 ? ( discountPrice / totalProductPrice ) * 100 : 0;
1437
1573
  let gstAmount = discountTotalPrice * ( 18 / 100 );
1438
1574
  let finalValue = parseFloat( discountTotalPrice ) + gstAmount;
1439
1575
  let result = {
@@ -1457,69 +1593,12 @@ export const priceList = async ( req, res ) => {
1457
1593
  export const pricingListUpdate = async ( req, res ) => {
1458
1594
  try {
1459
1595
  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
1596
  if ( !getPriceInfo ) {
1462
1597
  if ( !req.body.client.planDetails.product.length ) {
1463
1598
  return res.sendError( 'no product found', 204 );
1464
1599
  }
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
- }
1600
+ updatePricing( req, res, false );
1601
+
1523
1602
  return res.sendSuccess( 'Pricig Updated Successfully' );
1524
1603
  }
1525
1604
  if ( getPriceInfo && !req.body?.products?.length ) {
@@ -1548,7 +1627,7 @@ export const pricingListUpdate = async ( req, res ) => {
1548
1627
  getPriceInfo.step = req.body.products;
1549
1628
  }
1550
1629
  getPriceInfo.save().then( async () => {
1551
- let userDetails= await userService.findOne( { clientId: invoiceDetails.clientId, role: 'superadmin' } );
1630
+ let userDetails= await userService.findOne( { clientId: req.body.clientId, role: 'superadmin' } );
1552
1631
  if ( userDetails ) {
1553
1632
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/revisedPriceEmail.hbs', 'utf8' );
1554
1633
  const template = Handlebars.compile( templateHtml );
@@ -1562,7 +1641,24 @@ export const pricingListUpdate = async ( req, res ) => {
1562
1641
  };
1563
1642
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1564
1643
  }
1565
-
1644
+ let keys = [];
1645
+ if ( req.body.type == 'standard' ) {
1646
+ keys = [ 'productName', 'discountPercentage', 'basePrice', 'negotiatePrice' ];
1647
+ }
1648
+ if ( req.body.type == 'standard' ) {
1649
+ keys = [ 'productName', 'discountPercentage', 'basePrice', 'negotiatePrice', 'storeRange' ];
1650
+ }
1651
+ const logObj = {
1652
+ clientId: req.body.clientId,
1653
+ userName: req.user?.userName,
1654
+ email: req.user?.email,
1655
+ date: new Date(),
1656
+ logType: 'billing',
1657
+ logSubType: 'Update Product Pricing Details',
1658
+ changes: keys,
1659
+ eventType: 'update',
1660
+ };
1661
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1566
1662
  return res.sendSuccess( 'Pricig Updated Successfully' );
1567
1663
  } );
1568
1664
  } catch ( e ) {
@@ -1571,6 +1667,78 @@ export const pricingListUpdate = async ( req, res ) => {
1571
1667
  }
1572
1668
  };
1573
1669
 
1670
+
1671
+ async function updatePricing( req, res, update ) {
1672
+ let baseProduct = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
1673
+ let clientDetails = await paymentService.findOne( { clientId: req.body.clientId } );
1674
+ if ( clientDetails ) {
1675
+ let products = clientDetails.planDetails.product.map( ( item ) => item.productName );
1676
+ let standardList = [];
1677
+ let stepList = [];
1678
+ products.forEach( ( product ) => {
1679
+ let baseDetails = baseProduct.basePricing.find( ( item ) => item.productName == product );
1680
+ let discountPrice = ( baseDetails.basePrice * baseDetails.discoutPercentage ) / 100;
1681
+ standardList.push(
1682
+ {
1683
+ productName: product,
1684
+ discountPercentage: baseDetails.discoutPercentage,
1685
+ basePrice: baseDetails.basePrice,
1686
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1687
+ },
1688
+ );
1689
+ stepList.push(
1690
+ {
1691
+ productName: product,
1692
+ discountPercentage: baseDetails.discoutPercentage,
1693
+ basePrice: baseDetails.basePrice,
1694
+ negotiatePrice: baseDetails.basePrice - discountPrice,
1695
+ storeRange: '1-100',
1696
+ },
1697
+ );
1698
+ } );
1699
+ let data = {
1700
+ standard: standardList,
1701
+ step: stepList,
1702
+ clientId: req.body.clientId,
1703
+ };
1704
+ if ( !update ) {
1705
+ await basePricingService.create( data );
1706
+ } else {
1707
+ delete data.clientId;
1708
+ await basePricingService.updateOne( { clientId: req.body.clientId }, data );
1709
+ }
1710
+ let product = [];
1711
+ let clientId = req.body.clientId;
1712
+ if ( !update ) {
1713
+ clientDetails.planDetails.product.forEach( ( item ) => {
1714
+ product.push( {
1715
+ productName: item.productName,
1716
+ status: 'trial',
1717
+ trialStartDate: new Date(),
1718
+ trialEndDate: new Date( dayjs().add( 13, 'days' ).format( 'YYYY-MM-DD' ) ),
1719
+ } );
1720
+ } );
1721
+ } else {
1722
+ product = clientDetails.planDetails.product;
1723
+ }
1724
+ req.body = {
1725
+ 'camaraPerSqft': clientDetails.planDetails.storeSize,
1726
+ 'storesCount': clientDetails.planDetails.totalStores,
1727
+ 'planName': clientDetails.planDetails.subscriptionPeriod,
1728
+ 'products': product.map( ( item ) => item.productName ),
1729
+ 'currencyType': 'rupees',
1730
+ };
1731
+ let pricingDetails = await calculatePricing( req, res );
1732
+ let details = {
1733
+ 'priceType': 'standard',
1734
+ 'planDetails.paymentStatus': clientDetails?.subscriptionType == 'free' ? 'free' : 'trial',
1735
+ 'planDetails.product': product,
1736
+ 'price': pricingDetails.price,
1737
+ };
1738
+ await paymentService.updateOne( { clientId: clientId }, details );
1739
+ }
1740
+ }
1741
+
1574
1742
  export const updatedRevisedPrice = async ( req, res ) => {
1575
1743
  try {
1576
1744
  let invoiceDetails = await invoiceService.findOne( { invoice: req.body.invoice } );
@@ -1595,6 +1763,17 @@ export const updatedRevisedPrice = async ( req, res ) => {
1595
1763
  };
1596
1764
  sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1597
1765
  }
1766
+ const logObj = {
1767
+ clientId: req.body.clientId,
1768
+ userName: req.user?.userName,
1769
+ email: req.user?.email,
1770
+ date: new Date(),
1771
+ logType: 'billing',
1772
+ logSubType: 'Revised Price Updation',
1773
+ changes: [ 'amount', 'revisedAmount', 'discount' ],
1774
+ eventType: 'update',
1775
+ };
1776
+ insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1598
1777
  return res.sendSuccess( 'Credit notes Updated Successfully' );
1599
1778
  } );
1600
1779
  } catch ( e ) {
@@ -1605,7 +1784,7 @@ export const updatedRevisedPrice = async ( req, res ) => {
1605
1784
 
1606
1785
  export const unpaidInvoiceList = async ( req, res ) => {
1607
1786
  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 } );
1787
+ 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
1788
  if ( !invoiceDetails.length ) {
1610
1789
  return res.sendError( 'no data found', 204 );
1611
1790
  }
@@ -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 paymentDocs = {
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
+