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