tango-app-api-payment-subscription 3.1.12 → 3.1.14-alpha.1

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.
@@ -10,6 +10,10 @@ import * as invoiceService from '../services/invoice.service.js';
10
10
  import * as userService from '../services/user.service.js';
11
11
  import * as dailyPriceService from '../services/dailyPrice.service.js';
12
12
  import * as cameraService from '../services/camera.service.js';
13
+ import * as billingService from '../services/billing.service.js';
14
+ import * as paymentAccountService from '../services/paymentAccount.service.js';
15
+
16
+
13
17
  import dayjs from 'dayjs';
14
18
  import Handlebars from 'handlebars';
15
19
  import fs from 'fs';
@@ -93,14 +97,39 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
93
97
  if ( !clientInfo ) {
94
98
  return res.sendError( 'no data found', 204 );
95
99
  }
96
- let storeCount = await storeService.count( { clientId: clientInfo[0].clientId } );
97
- let tangoProducts = [ 'tangoTraffic', 'tangoZone', 'tangoSop', 'prioritySupport' ];
100
+ let storeCount = await storeService.count( { clientId: clientInfo[0].clientId, status: 'active' } );
101
+ let tangoProductsList = await basePricingService.findOne( { clientId: { $exists: false } }, { basePricing: 1 } );
102
+ let tangoProducts = tangoProductsList.basePricing.map( ( item ) => item.productName );
98
103
  let activeProducts = clientInfo[0].planDetails.product;
99
104
  let liveProducts = [];
100
105
  let trialProducts = [];
101
106
  let expiredProducts = [];
102
107
  let currentDate = new Date();
103
108
 
109
+ let storeQuery = [
110
+ {
111
+ $match: {
112
+ clientId: clientInfo[0].clientId,
113
+ status: 'active',
114
+ },
115
+ },
116
+ { $unwind: '$product' },
117
+ {
118
+ $group: {
119
+ _id: '$product',
120
+ total: { $sum: 1 },
121
+ },
122
+ },
123
+ {
124
+ $project: {
125
+ _id: 0,
126
+ product: '$_id',
127
+ count: '$total',
128
+ },
129
+ },
130
+ ];
131
+
132
+ let productDetails = await storeService.aggregate( storeQuery );
104
133
  // Function to calculate the difference between two dates
105
134
  function dateDifference( date1, date2 ) {
106
135
  // Convert both dates to milliseconds
@@ -125,22 +154,29 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
125
154
  }
126
155
 
127
156
  activeProducts.forEach( ( element ) => {
128
- switch ( element.productName ) {
129
- case 'tangoTraffic':
130
- element.aliseProductName = 'Tango Traffic';
131
- break;
132
- case 'tangoZone':
133
- element.aliseProductName = 'Tango Zone';
134
- break;
135
- case 'tangoSop':
136
- element.aliseProductName = 'Tango SOP';
137
- break;
138
- case 'prioritySupport':
139
- element.aliseProductName = 'Priority Support';
140
- break;
141
- default:
142
- break;
157
+ let price = tangoProductsList.basePricing.find( ( item ) => item.productName == element.productName );
158
+ if ( price ) {
159
+ element.price = price.basePrice;
143
160
  }
161
+ let getProductCount = productDetails.find( ( item ) => item.product == element.productName );
162
+ element.storeCount = getProductCount?.count || 0;
163
+ element.aliseProductName = convertTitleCase( element.productName );
164
+ // switch ( element.productName ) {
165
+ // case 'tangoTraffic':
166
+ // element.aliseProductName = 'Tango Traffic';
167
+ // break;
168
+ // case 'tangoZone':
169
+ // element.aliseProductName = 'Tango Zone';
170
+ // break;
171
+ // case 'tangoTrax':
172
+ // element.aliseProductName = 'Tango Trax';
173
+ // break;
174
+ // case 'prioritySupport':
175
+ // element.aliseProductName = 'Priority Support';
176
+ // break;
177
+ // default:
178
+ // break;
179
+ // }
144
180
 
145
181
  if ( element.status == 'live' ) {
146
182
  liveProducts.push( { 'productName': element.productName, 'aliseProductName': element.aliseProductName } );
@@ -226,6 +262,16 @@ export const clientBillingSubscriptionInfo = async ( req, res, next ) => {
226
262
 
227
263
  export const pricingInfo = async ( req, res ) => {
228
264
  try {
265
+ if ( req.query?.clientId ) {
266
+ let clientDetails = await paymentService.findOne( { clientId: req.query.clientId }, { planDetails: 1, paymentInvoice: 1 } );
267
+ if ( clientDetails ) {
268
+ req.body.storesCount = clientDetails.planDetails.totalStores;
269
+ req.body.products = req.body?.products || clientDetails.planDetails.product.map( ( product ) => product.productName );
270
+ req.body.planName = req.body?.planName || clientDetails.planDetails.subscriptionPeriod;
271
+ req.body.currencyType = clientDetails.paymentInvoice?.currencyType ? clientDetails.paymentInvoice?.currencyType == 'inr' ? 'rupees' : 'dollar' : 'rupees';
272
+ req.body.camaraPerSqft = clientDetails.planDetails.storeSize;
273
+ }
274
+ }
229
275
  req.body.calculateSignup = true;
230
276
  let pricingDetails = await calculatePricing( req, res );
231
277
  return res.sendSuccess( pricingDetails );
@@ -256,6 +302,7 @@ async function calculatePricing( req, res ) {
256
302
  $project: {
257
303
  _id: 0,
258
304
  basePricing: 1,
305
+ discounts: 1,
259
306
  },
260
307
  },
261
308
  ];
@@ -267,10 +314,15 @@ async function calculatePricing( req, res ) {
267
314
  return { ...item.basePricing };
268
315
  } );
269
316
  let camaraCount;
317
+ let productWisePricing = [];
270
318
  input.products.forEach( async ( element, index ) => {
271
319
  let getProduct = productList.find( ( item ) => item.productName == element );
272
- let camaraPerSqft = getProduct.camaraPerStores.filter( ( data ) => data.sqft == input.camaraPerSqft );
273
- let basicprice = Math.round( getProduct.basePrice * ( camaraPerSqft[0].camaraCount ) );
320
+ let basicprice;
321
+ let camaraPerSqft;
322
+ if ( input.camaraPerSqft ) {
323
+ camaraPerSqft = getProduct?.camaraPerStores.filter( ( data ) => data.sqft == input.camaraPerSqft );
324
+ basicprice = Math.round( getProduct.basePrice * ( camaraPerSqft[0].camaraCount ) );
325
+ }
274
326
  if ( req.body.calculateSignup ) {
275
327
  productDiscounts.push( getProduct.signupPercentage );
276
328
  } else {
@@ -307,26 +359,39 @@ async function calculatePricing( req, res ) {
307
359
  let discountprice = Math.round( basicprice * ( Math.pow( 0.92, stage ) )/10 )*10;
308
360
  dummy.push( discountprice );
309
361
  OriginalPrice = OriginalPrice + discountprice;
362
+ if ( index>0&&pricingDetails.length>0 ) {
363
+ let addOnDiscounts = 0;
364
+ for ( const discount of pricingDetails[0].discounts ) {
365
+ if ( discount.products.length === input.products.length &&
366
+ discount.products.every( ( product ) => input.products.includes( product ) ) ) {
367
+ addOnDiscounts = discount.discount;
368
+ }
369
+ }
370
+ discountprice = discountprice-( ( discountprice*addOnDiscounts )/100 );
371
+ productWisePricing.push( { product: element, price: discountprice } );
372
+ } else {
373
+ productWisePricing.push( { product: element, price: discountprice } );
374
+ }
375
+
376
+
310
377
  finalPrice = finalPrice + discountprice;
311
- camaraArray.push( Number( Math.ceil( camaraPerSqft[0].camaraCount ) ) );
378
+ if ( camaraPerSqft&& camaraPerSqft.length>0 ) {
379
+ camaraArray.push( Number( Math.ceil( camaraPerSqft[0].camaraCount ) ) );
380
+ }
312
381
  camaraCount = Math.max( ...camaraArray );
313
382
  if ( dummy.length == input.products.length ) {
314
- if ( input.products.length > 1 ) {
315
- // for extra product to add maximum discount
316
- let maxProductDiscounts = Math.max( ...productDiscounts );
317
- let addtionalDiscount = ( finalPrice * maxProductDiscounts ) / 100;
318
- finalPrice = finalPrice - addtionalDiscount;
319
- // OriginalPrice = OriginalPrice + addtionalDiscount
320
- }
383
+ // if ( input.products.length > 1 &&pricingDetails.length>0 ) {
384
+ // let maxProductDiscounts = Math.max( ...productDiscounts );
385
+ // let addtionalDiscount = ( finalPrice * maxProductDiscounts ) / 100;
386
+ // finalPrice = finalPrice - addtionalDiscount;
387
+ // }
321
388
  if ( input.planName == 'quarterly' ) {
322
389
  let extraDiscount = ( finalPrice * 10 ) / 100;
323
390
  finalPrice = finalPrice - extraDiscount;
324
- // OriginalPrice = OriginalPrice + extra_discount
325
391
  }
326
392
  if ( input.planName == 'annual' ) {
327
393
  let extraDiscount = ( finalPrice * 20 ) / 100;
328
394
  finalPrice = finalPrice - extraDiscount;
329
- // OriginalPrice = OriginalPrice + extra_discount
330
395
  }
331
396
  finalPrice = Math.ceil( finalPrice / 10 ) * 10; // for round off to 10 position
332
397
  if ( input.currencyType && input.currencyType == 'dollar' ) {
@@ -337,7 +402,7 @@ async function calculatePricing( req, res ) {
337
402
  }
338
403
  }
339
404
  } );
340
- return ( { OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
405
+ return ( { productWisePricing: productWisePricing, OriginalPrice: Math.round( OriginalPrice ), price: Math.round( finalPrice ), camaraCount: camaraCount } );
341
406
  } catch ( e ) {
342
407
  logger.error( { error: e, function: 'calculatePricing' } );
343
408
  return false;
@@ -1491,7 +1556,7 @@ export const productViewList = async ( req, res ) => {
1491
1556
  {
1492
1557
  $match: {
1493
1558
  clientId: req.query.clientId,
1494
- // status: 'active',
1559
+ status: 'active',
1495
1560
  },
1496
1561
  },
1497
1562
  { $unwind: '$product' },
@@ -1511,6 +1576,7 @@ export const productViewList = async ( req, res ) => {
1511
1576
  ];
1512
1577
 
1513
1578
  let storeProductCount = await storeService.aggregate( query );
1579
+
1514
1580
  let clientProduct = await paymentService.findOne( { clientId: req.query.clientId }, { 'planDetails.product': 1 } );
1515
1581
 
1516
1582
  if ( !clientProduct.planDetails.product.length ) {
@@ -1535,6 +1601,7 @@ export const productViewList = async ( req, res ) => {
1535
1601
  basePrice: price,
1536
1602
  storeCount: count,
1537
1603
  status: item.status,
1604
+ totalCost: Math.round( price*count ),
1538
1605
  },
1539
1606
  );
1540
1607
  } );
@@ -1549,7 +1616,19 @@ export const productViewList = async ( req, res ) => {
1549
1616
  // item.basePrice = productBasePrice.basePrice;
1550
1617
  // }
1551
1618
  // } );
1552
- return res.sendSuccess( products );
1619
+ let storecount = await storeService.count( {
1620
+ clientId: req.query.clientId,
1621
+ status: 'active',
1622
+ } );
1623
+
1624
+ let totalSum = products.reduce( ( sum, product ) => sum + product.totalCost, 0 );
1625
+ let transaction = await paymentAccountService.findOneAccount( { clientId: req.query.clientId } );
1626
+ let planDetails = {
1627
+ totalSum: totalSum,
1628
+ totalStores: storecount,
1629
+ accountcredit: transaction.credit?transaction.credit:0,
1630
+ };
1631
+ return res.sendSuccess( { products: products, planDetails: planDetails } );
1553
1632
  } catch ( e ) {
1554
1633
  logger.error( { error: e, function: 'productViewList' } );
1555
1634
  return res.sendError( e, 500 );
@@ -2014,18 +2093,18 @@ export const invoiceList = async ( req, res ) => {
2014
2093
  item.billingDate = dayjs( item.billingDate ).format( 'DD MMM, YYYY' );
2015
2094
  if ( item.products?.length > 0 ) {
2016
2095
  let newProducts = [];
2017
- // for ( let productIndex = 0; productIndex < item.products.length; productIndex++ ) {
2018
- // let [ firstWord, secondWord ] = item.products[productIndex]?.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2019
- // firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
2020
- // item.products[productIndex].productName = firstWord + ' ' + secondWord;
2021
- // newProducts.push( item.products[productIndex]?.productName );
2022
- // }
2023
2096
  for ( let productIndex = 0; productIndex < item.products.length; productIndex++ ) {
2024
- let [ firstWord, secondWord ] = item.products[productIndex]?.product?.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2097
+ let [ firstWord, secondWord ] = item.products[productIndex]?.productName.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2025
2098
  firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
2026
- item.products[productIndex].product.product = firstWord + ' ' + secondWord;
2027
- newProducts.push( item.products[productIndex]?.product?.product );
2099
+ item.products[productIndex].productName = firstWord + ' ' + secondWord;
2100
+ newProducts.push( item.products[productIndex]?.productName );
2028
2101
  }
2102
+ // for ( let productIndex = 0; productIndex < item.products.length; productIndex++ ) {
2103
+ // let [ firstWord, secondWord ] = item.products[productIndex]?.product?.product.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
2104
+ // firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
2105
+ // item.products[productIndex].product.product = firstWord + ' ' + secondWord;
2106
+ // newProducts.push( item.products[productIndex]?.product?.product );
2107
+ // }
2029
2108
  item.productList = newProducts;
2030
2109
  }
2031
2110
  } );
@@ -2774,7 +2853,7 @@ export const invoiceDownload = async ( req, res ) => {
2774
2853
  invoiceDate,
2775
2854
  dueDate,
2776
2855
  };
2777
- const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf.hbs', 'utf8' );
2856
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/invoicePdf1.hbs', 'utf8' );
2778
2857
  const template = Handlebars.compile( templateHtml );
2779
2858
  const html = template( { ...invoiceData } );
2780
2859
  let file = {
@@ -2791,7 +2870,7 @@ export const invoiceDownload = async ( req, res ) => {
2791
2870
  };
2792
2871
  const date = dayjs( invoiceData.monthOfbilling, 'MM' );
2793
2872
  let monthName = date.format( 'MMMM' );
2794
-
2873
+ monthName = 'Jul-Sep';
2795
2874
 
2796
2875
  htmlpdf.generatePdf( file, options ).then( async function( pdfBuffer ) {
2797
2876
  if ( req.body.sendInvoice ) {
@@ -3060,7 +3139,7 @@ export const dailyPricingInsert = async ( req, res ) => {
3060
3139
  let query = [
3061
3140
  {
3062
3141
  $match: {
3063
- clientId: requestClient[clientIndex],
3142
+ clientId: getClient.clientId,
3064
3143
  },
3065
3144
  },
3066
3145
  { $unwind: '$stores' },
@@ -3085,7 +3164,21 @@ export const dailyPricingInsert = async ( req, res ) => {
3085
3164
  let dailyData = await dailyPriceService.aggregate( query );
3086
3165
  let cameraDetails = await cameraService.find( { storeId: getStore[storeIndex].storeId, clientId: requestClient[clientIndex], isActivated: true, isUp: true }, { streamName: 1 } );
3087
3166
  let firstDate = dayjs( getStore[storeIndex]?.edge?.firstFileDate ).format( 'YYYY-MM-DD' );
3088
- let workingdays = ( firstDate < requestData.date && getStore[storeIndex]?.status == 'active' && dailyData[0]?.dateString != dayjs( requestData.date, 'YYYY-MM-DD' ).format( 'YYYY-MM-DD' ) ) ? ( dailyData.length && dailyData[0]?.stores?.daysDifference ) ? ( dailyData[0]?.stores?.daysDifference + 1 ) : 1 : dailyData[0]?.stores?.daysDifference ? dailyData[0]?.stores?.daysDifference : 0;
3167
+ let workingdays;
3168
+ if ( firstDate < requestData.date && getStore[storeIndex]?.status == 'active' &&
3169
+ dailyData[0]?.dateString != dayjs( requestData.date, 'YYYY-MM-DD' ).format( 'YYYY-MM-DD' ) ) {
3170
+ if ( dailyData.length && dailyData[0]?.stores?.daysDifference ) {
3171
+ workingdays = dailyData[0]?.stores?.daysDifference + 1;
3172
+ } else {
3173
+ workingdays = 1;
3174
+ }
3175
+ } else {
3176
+ if ( dailyData[0]?.stores?.daysDifference ) {
3177
+ workingdays = dailyData[0]?.stores?.daysDifference;
3178
+ } else {
3179
+ workingdays = 0;
3180
+ }
3181
+ }
3089
3182
  let priceDetails = getClient.priceType == 'standard' ? getBaseprice.standard : getBaseprice.step;
3090
3183
  for ( let storeProductIndex = 0; storeProductIndex < getStore[storeIndex].product.length; storeProductIndex++ ) {
3091
3184
  let productDetails;
@@ -3189,6 +3282,7 @@ export const dailyPricingInsertV1 = async ( req, res ) => {
3189
3282
  for ( let i=1; i<requestData.days; i++ ) {
3190
3283
  dayList.push( dayjs( requestData.date ).add( i, 'day' ).format( 'YYYY-MM-DD' ) );
3191
3284
  }
3285
+
3192
3286
  if ( requestData && requestClient.length > 0 ) {
3193
3287
  for ( let i=0; i<dayList.length; i++ ) {
3194
3288
  requestData.date = dayList[i];
@@ -3207,7 +3301,7 @@ export const dailyPricingInsertV1 = async ( req, res ) => {
3207
3301
  let query = [
3208
3302
  {
3209
3303
  $match: {
3210
- clientId: requestClient[clientIndex],
3304
+ clientId: getClient.clientId,
3211
3305
  },
3212
3306
  },
3213
3307
  { $unwind: '$stores' },
@@ -3232,7 +3326,21 @@ export const dailyPricingInsertV1 = async ( req, res ) => {
3232
3326
  let dailyData = await dailyPriceService.aggregate( query );
3233
3327
  let cameraDetails = await cameraService.find( { storeId: getStore[storeIndex].storeId, clientId: requestClient[clientIndex], isActivated: true, isUp: true }, { streamName: 1 } );
3234
3328
  let firstDate = dayjs( getStore[storeIndex]?.edge?.firstFileDate ).format( 'YYYY-MM-DD' );
3235
- let workingdays = ( firstDate < requestData.date && getStore[storeIndex]?.status == 'active' && dailyData[0]?.dateString != dayjs( requestData.date, 'YYYY-MM-DD' ).format( 'YYYY-MM-DD' ) ) ? ( dailyData.length && dailyData[0]?.stores?.daysDifference ) ? ( dailyData[0]?.stores?.daysDifference + 1 ) : 1 : dailyData[0]?.stores?.daysDifference ? dailyData[0]?.stores?.daysDifference : 0;
3329
+ let workingdays;
3330
+ if ( firstDate < requestData.date && getStore[storeIndex]?.status == 'active' &&
3331
+ dailyData[0]?.dateString != dayjs( requestData.date, 'YYYY-MM-DD' ).format( 'YYYY-MM-DD' ) ) {
3332
+ if ( dailyData.length && dailyData[0]?.stores?.daysDifference ) {
3333
+ workingdays = dailyData[0]?.stores?.daysDifference + 1;
3334
+ } else {
3335
+ workingdays = 1;
3336
+ }
3337
+ } else {
3338
+ if ( dailyData[0]?.stores?.daysDifference ) {
3339
+ workingdays = dailyData[0]?.stores?.daysDifference;
3340
+ } else {
3341
+ workingdays = 0;
3342
+ }
3343
+ }
3236
3344
  let priceDetails = getClient.priceType == 'standard' ? getBaseprice.standard : getBaseprice.step;
3237
3345
  for ( let storeProductIndex = 0; storeProductIndex < getStore[storeIndex].product.length; storeProductIndex++ ) {
3238
3346
  let productDetails;
@@ -3276,13 +3384,14 @@ export const dailyPricingInsertV1 = async ( req, res ) => {
3276
3384
  },
3277
3385
  );
3278
3386
  if ( storeIndex == getStore.length - 1 ) {
3387
+ let activestores = storeList.filter( ( store ) => store.status=='active' );
3279
3388
  let params = {
3280
3389
  clientId: requestClient[clientIndex],
3281
3390
  stores: storeList,
3282
3391
  dateISO: new Date( requestData.date ),
3283
3392
  accountType: getClient?.planDetails?.subscriptionType,
3284
3393
  status: getClient?.status,
3285
- activeStores: getStore?.length,
3394
+ activeStores: activestores?.length,
3286
3395
  brandName: getClient?.clientName,
3287
3396
  proRate: getClient?.paymentInvoice?.proRate,
3288
3397
  dateString: dayjs( requestData.date, 'YYYY-MM-DD' ).format( 'YYYY-MM-DD' ),
@@ -3676,3 +3785,25 @@ function convertTitleCase( data ) {
3676
3785
  }
3677
3786
 
3678
3787
 
3788
+ export async function createDefaultbillings( req, res ) {
3789
+ let clientlist = await paymentService.find( { 'status': 'active' } );
3790
+
3791
+ for ( let client of clientlist ) {
3792
+ let storeslist = await storeService.find( { clientId: client.clientId }, { storeId: 1 } );
3793
+ storeslist = storeslist.map( ( a ) => a.storeId );
3794
+ let payload = {
3795
+ clientId: client.clientId,
3796
+ registeredCompanyName: client.billingDetails.companyName,
3797
+ gst: client.billingDetails.gstNumber,
3798
+ addressLineOne: client.billingDetails.billingAddress,
3799
+ placeOfSupply: client.billingDetails.PlaceOfSupply,
3800
+ stores: storeslist,
3801
+ currency: client.paymentInvoice.currencyType,
3802
+ generateInvoiceTo: [ ...client.paymentInvoice.invoiceCC, ...client.paymentInvoice.invoiceCC.invoiceTo?client.paymentInvoice.invoiceCC.invoiceTo:[] ],
3803
+ isPrimary: true,
3804
+
3805
+ };
3806
+ await billingService.create( payload );
3807
+ }
3808
+ }
3809
+
@@ -0,0 +1,16 @@
1
+
2
+ import { logger } from 'tango-app-api-middleware';
3
+
4
+ const processedEventIds = new Set();
5
+
6
+ export const checkDuplicateEvent = ( req, res, next ) => {
7
+ const eventId = req.headers['x-razorpay-event-id'];
8
+
9
+ if ( processedEventIds.has( eventId ) ) {
10
+ logger.error( { error: `Duplicate event with ID ${eventId}. Skipping processing.`, function: 'checkDuplicateEvent' } );
11
+ res.status( 200 ).send();
12
+ } else {
13
+ processedEventIds.add( eventId );
14
+ next();
15
+ }
16
+ };
@@ -40,11 +40,11 @@ export const validateProductListParams = {
40
40
  };
41
41
 
42
42
  export const validateProductsSchema = joi.object( {
43
- camaraPerSqft: joi.string().required(),
44
- currencyType: joi.string().required(),
45
- planName: joi.string().required(),
46
- products: joi.array().required(),
47
- storesCount: joi.string().required(),
43
+ camaraPerSqft: joi.string().optional(),
44
+ currencyType: joi.string().optional(),
45
+ planName: joi.string().optional(),
46
+ products: joi.array().optional(),
47
+ storesCount: joi.string().optional(),
48
48
  } );
49
49
 
50
50
  export const validateProducts = {
@@ -298,14 +298,14 @@ export const createBillingGroupBody = joi.object(
298
298
  groupName: joi.string().required(),
299
299
  groupTag: joi.string().required(),
300
300
  registeredCompanyName: joi.string().required(),
301
- gst: joi.string().required(),
301
+ gst: joi.string().optional(),
302
302
  addressLineOne: joi.string().optional(),
303
303
  addressLineTwo: joi.string().optional(),
304
304
  city: joi.string().optional(),
305
305
  state: joi.string().optional(),
306
306
  country: joi.string().optional(),
307
307
  pinCode: joi.string().optional(),
308
- placeOfSupply: joi.string().required(),
308
+ placeOfSupply: joi.string().optional(),
309
309
  po: joi.string().optional(),
310
310
  stores: joi.array().optional(),
311
311
  proRata: joi.string().optional(),
@@ -378,3 +378,62 @@ export const billingGroupBody = joi.object( {
378
378
  export const billingGroupSchema = {
379
379
  body: billingGroupBody,
380
380
  };
381
+
382
+ export const getVirtualAccountQuery = {
383
+ clientId: joi.string().required(),
384
+ };
385
+
386
+ export const getVirtualAccountSchema = {
387
+ query: getVirtualAccountQuery,
388
+ };
389
+
390
+ export const getInvoiceBody = joi.object( {
391
+ limit: joi.number().required(),
392
+ offset: joi.number().required(),
393
+ clientId: joi.string().required(),
394
+ sortColumn: joi.string().optional(),
395
+ sortBy: joi.number().optional(),
396
+ searchValue: joi.string().optional(),
397
+ isExport: joi.boolean().optional(),
398
+ filter: joi.string().optional(),
399
+ } );
400
+
401
+ export const getInvoiceSchema = {
402
+ body: getInvoiceBody,
403
+ };
404
+
405
+ export const valletPayParam = joi.object().keys( {
406
+ invoice: joi.string().required(),
407
+ } );
408
+
409
+ export const valletPayValid = {
410
+ params: valletPayParam,
411
+ };
412
+
413
+ export const verifyPaymentParam = joi.object().keys( {
414
+ invoice: joi.string().required(),
415
+ } );
416
+
417
+ export const verifyPaymentBody = joi.object().keys( {
418
+ razorpay_payment_id: joi.string().required(),
419
+ razorpay_order_id: joi.string().required(),
420
+ razorpay_signature: joi.string().required(),
421
+ } );
422
+
423
+ export const verifyPaymentValid = {
424
+ params: verifyPaymentParam,
425
+ body: verifyPaymentBody,
426
+ };
427
+
428
+ export const onetimeFeeParam = joi.object().keys( {
429
+ invoice: joi.string().required(),
430
+ } );
431
+
432
+ export const onetimeFeeBody = joi.object().keys( {
433
+ oneTimeFee: joi.number().required(),
434
+ } );
435
+
436
+ export const onetimeFeeValid = {
437
+ params: onetimeFeeParam,
438
+ body: onetimeFeeBody,
439
+ };
@@ -1498,12 +1498,19 @@
1498
1498
  </div>
1499
1499
  </div>
1500
1500
  <div class="frame-23972">
1501
+ <div class="frame-2394">
1502
+ <div class="text9">Discount ({{discountPercentage}}%)</div>
1503
+ <div class="frame-9157">
1504
+ <div class="text10">{{currencyType}} {{discountAmount}}</div>
1505
+ </div>
1506
+ </div>
1501
1507
  <div class="frame-2394">
1502
1508
  <div class="text9">Sub Total</div>
1503
1509
  <div class="frame-9157">
1504
1510
  <div class="text10">{{currencyType}} {{amount}}</div>
1505
1511
  </div>
1506
1512
  </div>
1513
+
1507
1514
  {{#each tax }}
1508
1515
  <div class="frame-2392">
1509
1516
  <div class="text9">{{type}} ({{value}}%)</div>