tango-app-api-analysis-traffic 3.0.0-beta.2 → 3.1.0-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.
- package/index.js +4 -1
- package/package.json +6 -3
- package/src/controllers/emailers.controllers.js +1862 -0
- package/src/controllers/handlebars.js +23 -0
- package/src/controllers/nob.controllers.js +303 -0
- package/src/controllers/tangoTrafficV3.controllers.js +2170 -0
- package/src/docs/nob.docs.js +77 -0
- package/src/dtos/nob.dtos.js +57 -0
- package/src/dtos/validation.dtos.js +22 -0
- package/src/hbs/dailyMailerMultiple.hbs +1231 -0
- package/src/hbs/dailyMailerSingle.hbs +971 -0
- package/src/hbs/weeklyMailerMultiple.hbs +1142 -0
- package/src/hbs/weeklyMailerSingle.hbs +869 -0
- package/src/routes/emailers.js +20 -0
- package/src/routes/nob.routes.js +16 -0
- package/src/routes/traffic.routes.js +59 -4
- package/src/services/nob.service.js +9 -0
- package/src/services/user.service.js +67 -0
- package/src/validations/nob.validations.js +144 -0
|
@@ -0,0 +1,1862 @@
|
|
|
1
|
+
import { logger, insertOpenSearchData, getOpenSearchData, getAssinedStoreEmailers, sendMessageToQueue, signedUrl, sendEmailWithSES, fileUpload, updateOpenSearchData } from 'tango-app-api-middleware';
|
|
2
|
+
import * as clientService from '../services/clients.services.js';
|
|
3
|
+
import * as userService from '../services/user.service.js';
|
|
4
|
+
import * as storeService from '../services/stores.service.js';
|
|
5
|
+
import { findCamera } from '../services/camera.service.js';
|
|
6
|
+
import handlebars, { registerHelpers } from './handlebars.js';
|
|
7
|
+
const __filename = fileURLToPath( import.meta.url );
|
|
8
|
+
const __dirname = dirname( __filename );
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname } from 'path';
|
|
11
|
+
import puppeteer from 'puppeteer';
|
|
12
|
+
import { readFileSync } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import dayjs from 'dayjs';
|
|
15
|
+
registerHelpers();
|
|
16
|
+
|
|
17
|
+
// Lamda Service Call //
|
|
18
|
+
async function LamdaServiceCall( url, data ) {
|
|
19
|
+
try {
|
|
20
|
+
const requestOptions = {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify( data ),
|
|
26
|
+
};
|
|
27
|
+
const response = await fetch( url, requestOptions );
|
|
28
|
+
if ( !response.ok ) {
|
|
29
|
+
throw new Error( `Response status: ${response.status}` );
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const json = await response.json();
|
|
33
|
+
return json;
|
|
34
|
+
} catch ( error ) {
|
|
35
|
+
logger.error( { error: error, message: data, function: 'LamdaServiceCall' } );
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ///// V1 API's ///////
|
|
41
|
+
export const cardsFunnelV1 = async ( req, res ) => {
|
|
42
|
+
try {
|
|
43
|
+
let reqestData = req.body;
|
|
44
|
+
let getClientData = await getClientConfig( reqestData.clientId );
|
|
45
|
+
if ( !getClientData ) {
|
|
46
|
+
return res.sendError( 'Invalid Client Id', 400 );
|
|
47
|
+
}
|
|
48
|
+
reqestData.featureConfigs = getClientData.featureConfigs;
|
|
49
|
+
reqestData.currency = getClientData.paymentInvoice?.currencyType || 'inr';
|
|
50
|
+
reqestData.revenue = getClientData.averageTransactionValue || '0';
|
|
51
|
+
let LamdaURL = 'https://55mojecvuvtphucgsalx5jtyki0untzp.lambda-url.ap-south-1.on.aws/';
|
|
52
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
53
|
+
if ( resultData ) {
|
|
54
|
+
if ( resultData.status_code == '200' ) {
|
|
55
|
+
return res.sendSuccess( resultData );
|
|
56
|
+
} else {
|
|
57
|
+
return res.sendError( 'No Content', 204 );
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
return res.sendError( 'No Content', 204 );
|
|
61
|
+
}
|
|
62
|
+
} catch ( error ) {
|
|
63
|
+
logger.error( { error: error, message: req.query, function: 'cardsFunnelV1' } );
|
|
64
|
+
return res.sendError( { error: error }, 500 );
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
async function getClientConfig( clientId ) {
|
|
69
|
+
try {
|
|
70
|
+
let getClientData = await clientService.findOne( { clientId: clientId }, { 'paymentInvoice.currencyType': 1, 'averageTransactionValue': 1, 'featureConfigs.billableCalculation': 1, 'featureConfigs.missedOpportunityCalculation': 1, 'featureConfigs.conversionCalculation': 1, 'featureConfigs.open': 1, 'featureConfigs.close': 1, 'isFootfallAuditStores': 1 } );
|
|
71
|
+
if ( !getClientData ) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return getClientData;
|
|
75
|
+
} catch ( error ) {
|
|
76
|
+
logger.error( { error: error, message: data, function: 'getClientConfig' } );
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const welcome = async ( req, res ) => {
|
|
82
|
+
try {
|
|
83
|
+
let result = {
|
|
84
|
+
'Message': 'Welcome',
|
|
85
|
+
};
|
|
86
|
+
return res.sendSuccess( result );
|
|
87
|
+
} catch ( error ) {
|
|
88
|
+
logger.error( { error: error, message: req.query, function: 'trafficCards' } );
|
|
89
|
+
return res.sendError( { error: error }, 500 );
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const createEmailers = async ( req, res ) => {
|
|
94
|
+
try {
|
|
95
|
+
let requestData = req.body;
|
|
96
|
+
const kolkataOffset = 5.5 * 60; // +5:30 in minutes
|
|
97
|
+
// // Check Client config ////
|
|
98
|
+
let getClientData = await clientService.findOne( { clientId: requestData.clientId }, { clientId: 1, emailersConfig: 1 } );
|
|
99
|
+
|
|
100
|
+
if ( !getClientData ) {
|
|
101
|
+
return res.sendError( 'Invalid clientId', 400 );
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
switch ( requestData.templateType ) {
|
|
105
|
+
case 'monthly':
|
|
106
|
+
if ( getClientData && !getClientData.emailersConfig.monthly ) {
|
|
107
|
+
return res.sendError( 'Client Not Enabled Monthly Emails', 400 );
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
case 'weekly':
|
|
111
|
+
if ( getClientData && !getClientData.emailersConfig.weekly ) {
|
|
112
|
+
return res.sendError( 'Client Not Enabled Weekly Emails', 400 );
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
if ( getClientData && !getClientData.emailersConfig.daily ) {
|
|
117
|
+
return res.sendError( 'Client Not Enabled Daily Emails', 400 );
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// // Get active Users ////
|
|
123
|
+
let getUserData = await userService.findUserModel( { clientId: requestData.clientId, isActive: true, userType: 'client' }, { userName: 1, email: 1, role: 1, clientId: 1, isActive: 1, userType: 1, assignedStores: 1 } );
|
|
124
|
+
|
|
125
|
+
if ( !getUserData && getUserData.length < 1 ) {
|
|
126
|
+
return res.sendError( 'Active Users Empty', 400 );
|
|
127
|
+
}
|
|
128
|
+
let emailersIds = [];
|
|
129
|
+
// // Make for Loop and Get Assigned Stores each users ////
|
|
130
|
+
for ( let i = 0; i < getUserData.length; i++ ) {
|
|
131
|
+
let getUserStores = await getAssinedStoreEmailers( getUserData[i] );
|
|
132
|
+
let currentDate = new Date();
|
|
133
|
+
let emailersInsertData = {
|
|
134
|
+
clientId: requestData.clientId,
|
|
135
|
+
fromDate: requestData.fromDate,
|
|
136
|
+
toDate: requestData.toDate,
|
|
137
|
+
templateType: requestData.templateType,
|
|
138
|
+
status: 'open',
|
|
139
|
+
createdAt: currentDate,
|
|
140
|
+
dateISO: new Date( currentDate.getTime() + kolkataOffset * 60 * 1000 ),
|
|
141
|
+
userEmail: getUserData[i].email,
|
|
142
|
+
userName: getUserData[i].userName,
|
|
143
|
+
storeIds: getUserStores || [],
|
|
144
|
+
};
|
|
145
|
+
// // Insert emailers ////
|
|
146
|
+
let insertOS = await insertOpenSearchData( JSON.parse( process.env.OPENSEARCH ).emailers, emailersInsertData );
|
|
147
|
+
if ( insertOS && insertOS.body.result == 'created' ) {
|
|
148
|
+
emailersIds.push( insertOS.body._id );
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// // Send SQS Message ////
|
|
152
|
+
for ( let j = 0; j < emailersIds.length; j++ ) {
|
|
153
|
+
let sqsMessageRequestData = {
|
|
154
|
+
'emailersId': emailersIds[j],
|
|
155
|
+
};
|
|
156
|
+
const msg = sendMessageToQueue( `${JSON.parse( process.env.SQS ).url}${JSON.parse( process.env.SQS ).emailers}`, JSON.stringify( sqsMessageRequestData ) );
|
|
157
|
+
console.log( 'Send SQS Message =>'+[ j ], msg );
|
|
158
|
+
}
|
|
159
|
+
return res.sendSuccess( 'Emailers Triggered Successfully' );
|
|
160
|
+
} catch ( error ) {
|
|
161
|
+
// console.log( 'error =>', error );
|
|
162
|
+
logger.error( { error: error, message: req.query, function: 'createEmailers' } );
|
|
163
|
+
return res.sendError( { error: error }, 500 );
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const emailersList = async ( req, res ) => {
|
|
168
|
+
try {
|
|
169
|
+
let requestBody = req.query;
|
|
170
|
+
// // Get Data From Emailers Collection Based on Filters////
|
|
171
|
+
let from = ( req.query.offset - 1 ) * req.query.limit;
|
|
172
|
+
let start = new Date( requestBody.fromDate );
|
|
173
|
+
let userTimezoneOffset = start.getTimezoneOffset() * 60000;
|
|
174
|
+
start = new Date( start.getTime() - userTimezoneOffset );
|
|
175
|
+
start.setUTCHours( 0, 0, 0, 0 );
|
|
176
|
+
let end = new Date( requestBody.toDate );
|
|
177
|
+
end = new Date( end.getTime() - userTimezoneOffset );
|
|
178
|
+
end.setUTCHours( 23, 59, 59, 59 );
|
|
179
|
+
|
|
180
|
+
const mustConditions = [];
|
|
181
|
+
|
|
182
|
+
if ( requestBody.clientId ) {
|
|
183
|
+
mustConditions.push( { match: { clientId: requestBody.clientId } } );
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if ( requestBody.templateType ) {
|
|
187
|
+
mustConditions.push( { match: { templateType: requestBody.templateType } } );
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if ( requestBody.userEmail ) {
|
|
191
|
+
mustConditions.push( { match: { userEmail: requestBody.userEmail } } );
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if ( requestBody.status ) {
|
|
195
|
+
mustConditions.push( { match: { status: requestBody.status } } );
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if ( requestBody._id ) {
|
|
199
|
+
mustConditions.push( { match: { _id: requestBody._id } } );
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if ( requestBody.dateRange ) {
|
|
203
|
+
mustConditions.push( {
|
|
204
|
+
range: {
|
|
205
|
+
dateIso: {
|
|
206
|
+
gte: start, // Start date
|
|
207
|
+
lte: end, // End date
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
} );
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// console.log( 'mustConditions =>', mustConditions );
|
|
214
|
+
let query = {
|
|
215
|
+
from: from,
|
|
216
|
+
size: req.query.limit,
|
|
217
|
+
query: {
|
|
218
|
+
bool: {
|
|
219
|
+
must: mustConditions,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
sort: [
|
|
223
|
+
{
|
|
224
|
+
createdAt: {
|
|
225
|
+
order: 'desc',
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
};
|
|
230
|
+
let result = await getOpenSearchData( JSON.parse( process.env.OPENSEARCH ).emailers, query );
|
|
231
|
+
if ( !result || !result.body.hits.hits.length ) {
|
|
232
|
+
return res.sendError( 'no data found', 204 );
|
|
233
|
+
}
|
|
234
|
+
return res.sendSuccess( { count: result.body.hits.total.value, result: result.body.hits.hits } );
|
|
235
|
+
} catch ( error ) {
|
|
236
|
+
logger.error( { error: error, message: req.query, function: 'emailersList' } );
|
|
237
|
+
return res.sendError( { error: error }, 500 );
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export const sendEmailers = async ( req, res ) => {
|
|
242
|
+
try {
|
|
243
|
+
let requestBody = req.body;
|
|
244
|
+
// // Get Data From Emailers Collection Based on _id////
|
|
245
|
+
const mustConditions = [];
|
|
246
|
+
if ( requestBody._id ) {
|
|
247
|
+
mustConditions.push( { match: { _id: requestBody._id } } );
|
|
248
|
+
}
|
|
249
|
+
let query = {
|
|
250
|
+
query: {
|
|
251
|
+
bool: {
|
|
252
|
+
must: mustConditions,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
let getEmailSourceData = await getOpenSearchData( JSON.parse( process.env.OPENSEARCH ).emailers, query );
|
|
257
|
+
// console.log( 'getEmailSourceData =>', getEmailSourceData.body.hits.hits[0] );
|
|
258
|
+
// console.log( 'getEmailSourceData.length =>', getEmailSourceData.body.hits.hits.length );
|
|
259
|
+
if ( !getEmailSourceData.body.hits.hits.length ) {
|
|
260
|
+
return res.sendError( 'Invalide Emailer ID', 400 );
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
let emailerSourceData = getEmailSourceData.body.hits.hits[0];
|
|
264
|
+
if ( emailerSourceData._source.status == 'completed' ) {
|
|
265
|
+
return res.sendError( 'Email Already Send', 400 );
|
|
266
|
+
}
|
|
267
|
+
// // Get Stores Data ////
|
|
268
|
+
let getStoreSourceData = await storeService.findOneStore( { storeId: emailerSourceData._source.storeIds[0] }, { storeId: 1, storeName: 1, status: 1, storeProfile: 1 } );
|
|
269
|
+
const camera = await findCamera( { storeId: emailerSourceData._source.storeIds[0], isUp: true, isActivated: true }, { thumbnailImage: 1 } );
|
|
270
|
+
let cameraBaseImage = '';
|
|
271
|
+
const bucket= JSON.parse( process.env.BUCKET );
|
|
272
|
+
if ( camera ) {
|
|
273
|
+
const params = {
|
|
274
|
+
file_path: camera.thumbnailImage,
|
|
275
|
+
Bucket: bucket.baseImage,
|
|
276
|
+
};
|
|
277
|
+
cameraBaseImage = await signedUrl( params );
|
|
278
|
+
}
|
|
279
|
+
let storeData = {
|
|
280
|
+
storeId: getStoreSourceData.storeId,
|
|
281
|
+
storeName: getStoreSourceData.storeName,
|
|
282
|
+
storeLocation: getStoreSourceData.storeProfile.city+' '+getStoreSourceData.storeProfile.pincode,
|
|
283
|
+
storeCount: emailerSourceData._source.storeIds.length-1,
|
|
284
|
+
storeBaseImage: cameraBaseImage,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// // Get Client Data ///
|
|
288
|
+
let clientData = await clientService.findOne( { clientId: emailerSourceData._source.clientId }, { clientId: 1, emailersConfig: 1, featureConfigs: 1, clientName: 1 } );
|
|
289
|
+
|
|
290
|
+
// // Get Template Data ///
|
|
291
|
+
let templateData = {
|
|
292
|
+
userEmail: emailerSourceData._source.userEmail,
|
|
293
|
+
userName: emailerSourceData._source.userName,
|
|
294
|
+
templateType: emailerSourceData._source.templateType,
|
|
295
|
+
clientId: emailerSourceData._source.clientId,
|
|
296
|
+
clientName: clientData.clientName,
|
|
297
|
+
storeId: emailerSourceData._source.storeIds.slice( 0, 30 ),
|
|
298
|
+
allStores: emailerSourceData._source.storeIds,
|
|
299
|
+
fromDate: emailerSourceData._source.fromDate,
|
|
300
|
+
toDate: emailerSourceData._source.toDate,
|
|
301
|
+
templateType: emailerSourceData._source.templateType,
|
|
302
|
+
hourFormat: 12,
|
|
303
|
+
featureConfigs: {
|
|
304
|
+
open: clientData?.featureConfigs?.open || '10:00:00',
|
|
305
|
+
close: clientData?.featureConfigs?.close || '23:00:00',
|
|
306
|
+
billableCalculation: clientData?.featureConfigs?.billableCalculation || 'engagers-count',
|
|
307
|
+
conversionCalculation: clientData?.featureConfigs?.conversionCalculation || 'engagers-count',
|
|
308
|
+
missedOpportunityCalculation: clientData?.featureConfigs?.missedOpportunityCalculation || 'engagers-conversion',
|
|
309
|
+
bufferTime: 30,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
// console.log( 'templateData =>', templateData );
|
|
313
|
+
|
|
314
|
+
// // Get Lamda Metrics Data ////
|
|
315
|
+
let lamdaMetrics = await getLamdaMetricsData( templateData );
|
|
316
|
+
|
|
317
|
+
// // Get Lamda Chart Data ///
|
|
318
|
+
let lamdaCharts = await getLamdaChartData( templateData );
|
|
319
|
+
|
|
320
|
+
// // Call Send Email Function ////
|
|
321
|
+
let emailStatus = await emailerSendEmail( storeData, clientData, lamdaMetrics, lamdaCharts, templateData );
|
|
322
|
+
|
|
323
|
+
// return res.sendSuccess( 'Email Send Successfully' );
|
|
324
|
+
// // Once Email Successfully Send Update Status to Completed ////
|
|
325
|
+
if ( emailStatus ) {
|
|
326
|
+
const document = {
|
|
327
|
+
doc: {
|
|
328
|
+
status: 'open',
|
|
329
|
+
// fromDate: '2025-01-13',
|
|
330
|
+
// toDate: '2025-01-19',
|
|
331
|
+
// status: 'completed',
|
|
332
|
+
// storeIds: [ '430-8' ],
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
let updateResult = await updateOpenSearchData( JSON.parse( process.env.OPENSEARCH ).emailers, requestBody._id, document );
|
|
336
|
+
if ( updateResult?.statusCode == 200 && updateResult?.body?.result == 'updated' ) {
|
|
337
|
+
return res.sendSuccess( 'Email Send Successfully' );
|
|
338
|
+
} else {
|
|
339
|
+
return res.sendSuccess( 'Email Send Successfully' );
|
|
340
|
+
// return res.sendError( { error: error }, 500 );
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} catch ( error ) {
|
|
344
|
+
// console.log( 'error =>', error );
|
|
345
|
+
logger.error( { error: error, message: req.query, function: 'sendEmails' } );
|
|
346
|
+
return res.sendError( { error: error }, 500 );
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
async function getLamdaMetricsData( templateData ) {
|
|
351
|
+
try {
|
|
352
|
+
let resultLamdaMetricsData;
|
|
353
|
+
if ( templateData.allStores.length == 1 && templateData.templateType == 'daily' ) {
|
|
354
|
+
// // Call Lamda API No 1 Single Store Single Date
|
|
355
|
+
// API Number: 1 (Daily Emailer With Single Store)
|
|
356
|
+
resultLamdaMetricsData = await lamdaAPI1( templateData );
|
|
357
|
+
return resultLamdaMetricsData;
|
|
358
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'daily' ) {
|
|
359
|
+
// // Call Lamda API No 2 Multiple Store Single Date
|
|
360
|
+
// API Number: 3 (Daily Emailer With Multi Stores)
|
|
361
|
+
resultLamdaMetricsData = await lamdaAPI3( templateData );
|
|
362
|
+
return resultLamdaMetricsData;
|
|
363
|
+
} else if ( templateData.allStores.length == 1 && templateData.templateType == 'weekly' ) {
|
|
364
|
+
// // Call Lamda API No 3 Single Store Multiple Date
|
|
365
|
+
// API Number: 2 (Weekly Emailer With Single Store)
|
|
366
|
+
resultLamdaMetricsData = await lamdaAPI2( templateData );
|
|
367
|
+
return resultLamdaMetricsData;
|
|
368
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'weekly' ) {
|
|
369
|
+
// // Call Lamda API No 4 Multiple Store Multiple Date
|
|
370
|
+
// API Number: 4 (Weekly Emailer With Multi Stores)
|
|
371
|
+
resultLamdaMetricsData = await lamdaAPI4( templateData );
|
|
372
|
+
return resultLamdaMetricsData;
|
|
373
|
+
} else if ( templateData.allStores.length == 1 && templateData.templateType == 'monthly' ) {
|
|
374
|
+
// // Call Lamda API No 5 Single Store Multiple Date
|
|
375
|
+
|
|
376
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'monthly' ) {
|
|
377
|
+
// // Call Lamda API No 6 Multiple Store Multiple Date
|
|
378
|
+
|
|
379
|
+
} else {
|
|
380
|
+
// Default Value
|
|
381
|
+
}
|
|
382
|
+
} catch ( error ) {
|
|
383
|
+
// console.log( 'error =>', error );
|
|
384
|
+
logger.error( { error: error, function: 'getLamdaMetricsData' } );
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function lamdaAPI1( templateData ) {
|
|
390
|
+
try {
|
|
391
|
+
// let lamdaAPIResultData = {
|
|
392
|
+
// 'status_code': '200',
|
|
393
|
+
// 'emailerCards': {
|
|
394
|
+
// 'footfall': {
|
|
395
|
+
// 'totalCount': 100,
|
|
396
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
397
|
+
// 'lastWeekComparisonFlag': false, // Daily => sameDayLastWeekComparisonFlag
|
|
398
|
+
// 'vsMTDAvgRate': 60,
|
|
399
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
400
|
+
// },
|
|
401
|
+
// 'potentialBuyers': {
|
|
402
|
+
// 'totalCount': 100,
|
|
403
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
404
|
+
// 'lastWeekComparisonFlag': true, // Daily => sameDayLastWeekComparisonFlag
|
|
405
|
+
// 'vsMTDAvgRate': 70,
|
|
406
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
407
|
+
// },
|
|
408
|
+
// 'conversion': {
|
|
409
|
+
// 'totalCount': 100,
|
|
410
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
411
|
+
// 'lastWeekComparisonFlag': true, // Daily => sameDayLastWeekComparisonFlag
|
|
412
|
+
// 'vsMTDAvgRate': 70,
|
|
413
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
414
|
+
// },
|
|
415
|
+
// 'avgDwellTime': {
|
|
416
|
+
// 'dwellTime': 100,
|
|
417
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
418
|
+
// 'lastWeekComparisonFlag': true, // Daily => sameDayLastWeekComparisonFlag
|
|
419
|
+
// 'vsMTDAvg': 70,
|
|
420
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
421
|
+
// },
|
|
422
|
+
// 'operationalHours': {
|
|
423
|
+
// 'openTime': '09:00 AM',
|
|
424
|
+
// 'closeTime': '10:00 PM',
|
|
425
|
+
// },
|
|
426
|
+
// },
|
|
427
|
+
// 'highestFootfall': {
|
|
428
|
+
// 'PeekFootfallBetween': '04:00 PM - 06:00 PM',
|
|
429
|
+
// 'customerCount': 60,
|
|
430
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
431
|
+
// 'vsSameDayLastWeekComparisonFlag': true,
|
|
432
|
+
// },
|
|
433
|
+
// };
|
|
434
|
+
let newTemplateData = templateData;
|
|
435
|
+
|
|
436
|
+
// newTemplateData.dateType = 'daily';
|
|
437
|
+
// newTemplateData.valueType = 'actual';
|
|
438
|
+
// newTemplateData.filterBy = 'actual';
|
|
439
|
+
// newTemplateData.nob = false;
|
|
440
|
+
// newTemplateData.processType = 'conversion';
|
|
441
|
+
// newTemplateData.limit = 20;
|
|
442
|
+
// newTemplateData.offset = 0;
|
|
443
|
+
|
|
444
|
+
const overallLamdaURL = 'https://qkox3l2cg5qhblymaie7qlgku40toykp.lambda-url.ap-south-1.on.aws/';
|
|
445
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
446
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== '200' ) {
|
|
447
|
+
return '';
|
|
448
|
+
}
|
|
449
|
+
return lamdaAPIResultData;
|
|
450
|
+
} catch ( error ) {
|
|
451
|
+
logger.error( { error: error, message: data, function: 'lamdaAPI1' } );
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function lamdaAPI2( templateData ) {
|
|
457
|
+
try {
|
|
458
|
+
// let lamdaAPIResultData = {
|
|
459
|
+
// 'status_code': '200',
|
|
460
|
+
// 'emailerCards': {
|
|
461
|
+
// 'footfall': {
|
|
462
|
+
// 'totalCount': 100,
|
|
463
|
+
// 'lastWeekRate': 89,
|
|
464
|
+
// 'lastWeekComparisonFlag': true,
|
|
465
|
+
// 'vsMTDAvgRate': 60,
|
|
466
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
467
|
+
// },
|
|
468
|
+
// 'potentialBuyers': {
|
|
469
|
+
// 'totalCount': 100,
|
|
470
|
+
// 'lastWeekRate': 89,
|
|
471
|
+
// 'lastWeekComparisonFlag': false,
|
|
472
|
+
// 'vsMTDAvgRate': 70,
|
|
473
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
474
|
+
// },
|
|
475
|
+
// 'conversion': {
|
|
476
|
+
// 'totalCount': 100,
|
|
477
|
+
// 'lastWeekRate': 89,
|
|
478
|
+
// 'lastWeekComparisonFlag': false,
|
|
479
|
+
// 'vsMTDAvgRate': 70,
|
|
480
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
481
|
+
// },
|
|
482
|
+
// 'avgDwellTime': {
|
|
483
|
+
// 'dwellTime': 100,
|
|
484
|
+
// 'lastWeekRate': 89,
|
|
485
|
+
// 'lastWeekComparisonFlag': false,
|
|
486
|
+
// 'vsMTDAvgRate': 70,
|
|
487
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
488
|
+
// },
|
|
489
|
+
// 'operationalHours': {
|
|
490
|
+
// 'lastWeekRate': 89,
|
|
491
|
+
// 'lastWeekComparisonFlag': false,
|
|
492
|
+
// 'lateOpenDays': 3,
|
|
493
|
+
// 'earlyCloseDays': 5,
|
|
494
|
+
// },
|
|
495
|
+
// },
|
|
496
|
+
// 'highestFootfall': {
|
|
497
|
+
// 'PeekFootfallDay': 'Sunday',
|
|
498
|
+
// 'customerCount': 60,
|
|
499
|
+
// 'PeekFootfallBetween': '04:00 PM - 06:00 PM',
|
|
500
|
+
// 'vsLastWeekRate': 20,
|
|
501
|
+
// 'vsLastWeekComparisonFlag': false,
|
|
502
|
+
// },
|
|
503
|
+
// 'highestWeekdayFootfall': {
|
|
504
|
+
// 'PeekFootfallDay': 'Sunday',
|
|
505
|
+
// 'customerCount': 60,
|
|
506
|
+
// 'PeekFootfallBetween': '04:00 PM - 06:00 PM',
|
|
507
|
+
// 'vsLastWeekRate': 20,
|
|
508
|
+
// 'vsLastWeekComparisonFlag': false,
|
|
509
|
+
// },
|
|
510
|
+
// 'storeHeath': {
|
|
511
|
+
// 'storeHeath': 'Good', // ["Red","Amber", "Good"]
|
|
512
|
+
// },
|
|
513
|
+
// };
|
|
514
|
+
let newTemplateData = templateData;
|
|
515
|
+
const overallLamdaURL = 'https://6mgiyf73ktst7nskse7zn5zcxy0ptezt.lambda-url.ap-south-1.on.aws/';
|
|
516
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
517
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== '200' ) {
|
|
518
|
+
return '';
|
|
519
|
+
}
|
|
520
|
+
return lamdaAPIResultData;
|
|
521
|
+
} catch ( error ) {
|
|
522
|
+
logger.error( { error: error, message: data, function: 'lamdaAPI2' } );
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async function lamdaAPI3( templateData ) {
|
|
528
|
+
try {
|
|
529
|
+
// let lamdaAPIResultData = {
|
|
530
|
+
// 'status_code': '200',
|
|
531
|
+
// 'emailerCards': {
|
|
532
|
+
// 'avgFootfall': {
|
|
533
|
+
// 'totalCount': 100,
|
|
534
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
535
|
+
// 'lastWeekComparisonFlag': true, // Daily => sameDayLastWeekComparisonFlag
|
|
536
|
+
// 'vsMTDAvgRate': 60,
|
|
537
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
538
|
+
// },
|
|
539
|
+
// 'avgPotentialBuyers': {
|
|
540
|
+
// 'totalCount': 100,
|
|
541
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
542
|
+
// 'lastWeekComparisonFlag': false, // Daily => sameDayLastWeekComparisonFlag
|
|
543
|
+
// 'vsMTDAvgRate': 70,
|
|
544
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
545
|
+
// },
|
|
546
|
+
// 'avgConversion': {
|
|
547
|
+
// 'totalCount': 100,
|
|
548
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
549
|
+
// 'lastWeekComparisonFlag': false, // Daily => sameDayLastWeekComparisonFlag
|
|
550
|
+
// 'vsMTDAvgRate': 70,
|
|
551
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
552
|
+
// },
|
|
553
|
+
// 'avgDwellTime': {
|
|
554
|
+
// 'dwellTime': 100,
|
|
555
|
+
// 'lastWeekRate': 89, // Daily => sameDayLastWeek
|
|
556
|
+
// 'lastWeekComparisonFlag': false, // Daily => sameDayLastWeekComparisonFlag
|
|
557
|
+
// 'vsMTDAvgRate': 70,
|
|
558
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
559
|
+
// },
|
|
560
|
+
// 'avgOperationalHours': {
|
|
561
|
+
// 'avgOperationalHours': 9,
|
|
562
|
+
// 'lastWeekRate': 30,
|
|
563
|
+
// 'lastWeekComparisonFlag': true,
|
|
564
|
+
// },
|
|
565
|
+
// },
|
|
566
|
+
// 'conversionMetrics': {
|
|
567
|
+
// 'highEngagers': {
|
|
568
|
+
// 'storeName': 'LKST2025',
|
|
569
|
+
// 'storeId': '11-2025',
|
|
570
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
571
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
572
|
+
// 'vsMTDAvgRate': 20,
|
|
573
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
574
|
+
// },
|
|
575
|
+
// 'lowEngagers': {
|
|
576
|
+
// 'storeName': 'LKST2025',
|
|
577
|
+
// 'storeId': '11-2025',
|
|
578
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
579
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
580
|
+
// 'vsMTDAvgRate': 20,
|
|
581
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
582
|
+
// },
|
|
583
|
+
// 'highPotentialBuyers': {
|
|
584
|
+
// 'storeName': 'LKST2025',
|
|
585
|
+
// 'storeId': '11-2025',
|
|
586
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
587
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
588
|
+
// 'vsMTDAvgRate': 20,
|
|
589
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
590
|
+
// },
|
|
591
|
+
// 'lowPotentialBuyers': {
|
|
592
|
+
// 'storeName': 'LKST2025',
|
|
593
|
+
// 'storeId': '11-2025',
|
|
594
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
595
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
596
|
+
// 'vsMTDAvgRate': 20,
|
|
597
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
598
|
+
// },
|
|
599
|
+
// 'highFootfallCount': {
|
|
600
|
+
// 'storeName': 'LKST2025',
|
|
601
|
+
// 'storeId': '11-2025',
|
|
602
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
603
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
604
|
+
// 'vsMTDAvgRate': 20,
|
|
605
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
606
|
+
// },
|
|
607
|
+
// 'lowFootfallCount': {
|
|
608
|
+
// 'storeName': 'LKST2025',
|
|
609
|
+
// 'storeId': '11-2025',
|
|
610
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
611
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
612
|
+
// 'vsMTDAvgRate': 20,
|
|
613
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
614
|
+
// },
|
|
615
|
+
// },
|
|
616
|
+
// 'lowOperationalHours': [
|
|
617
|
+
// { 'storeName': 'LKST2025', 'storeId': '11-2025' },
|
|
618
|
+
// { 'storeName': 'LKST2024', 'storeId': '11-2024' },
|
|
619
|
+
// { 'storeName': 'LKST2023', 'storeId': '11-2023' },
|
|
620
|
+
// ],
|
|
621
|
+
// 'fullDownTime': [
|
|
622
|
+
// { 'storeName': 'LKST2025', 'storeId': '11-2025' },
|
|
623
|
+
// { 'storeName': 'LKST2024', 'storeId': '11-2024' },
|
|
624
|
+
// { 'storeName': 'LKST2023', 'storeId': '11-2023' },
|
|
625
|
+
// ],
|
|
626
|
+
// };
|
|
627
|
+
let newTemplateData = templateData;
|
|
628
|
+
const overallLamdaURL = 'https://bqk7ozecu7smfrzyb2hbb5lo540avjkl.lambda-url.ap-south-1.on.aws/';
|
|
629
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
630
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== 200 ) {
|
|
631
|
+
return '';
|
|
632
|
+
}
|
|
633
|
+
return lamdaAPIResultData;
|
|
634
|
+
} catch ( error ) {
|
|
635
|
+
logger.error( { error: error, message: data, function: 'lamdaAPI2' } );
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
async function lamdaAPI4( templateData ) {
|
|
642
|
+
try {
|
|
643
|
+
// let lamdaAPIResultData = {
|
|
644
|
+
// 'status_code': '200',
|
|
645
|
+
// 'emailerCards': {
|
|
646
|
+
// 'avgFootfall': {
|
|
647
|
+
// 'totalCount': 100,
|
|
648
|
+
// 'lastWeekRate': 89,
|
|
649
|
+
// 'lastWeekComparisonFlag': true,
|
|
650
|
+
// 'vsMTDAvgRate': 60,
|
|
651
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
652
|
+
// },
|
|
653
|
+
// 'avgPotentialBuyers': {
|
|
654
|
+
// 'totalCount': 100,
|
|
655
|
+
// 'lastWeekRate': 89,
|
|
656
|
+
// 'lastWeekComparisonFlag': false,
|
|
657
|
+
// 'vsMTDAvgRate': 70,
|
|
658
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
659
|
+
// },
|
|
660
|
+
// 'avgConversion': {
|
|
661
|
+
// 'totalCount': 100,
|
|
662
|
+
// 'lastWeekRate': 89,
|
|
663
|
+
// 'lastWeekComparisonFlag': false,
|
|
664
|
+
// 'vsMTDAvgRate': 70,
|
|
665
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
666
|
+
// },
|
|
667
|
+
// 'avgDwellTime': {
|
|
668
|
+
// 'dwellTime': 100,
|
|
669
|
+
// 'lastWeekRate': 89,
|
|
670
|
+
// 'lastWeekComparisonFlag': false,
|
|
671
|
+
// 'vsMTDAvgRate': 70,
|
|
672
|
+
// 'vsMTDAvgComparisonFlag': true,
|
|
673
|
+
// },
|
|
674
|
+
// 'avgOperationalHours': {
|
|
675
|
+
// 'lastWeekRate': 89,
|
|
676
|
+
// 'lastWeekComparisonFlag': false,
|
|
677
|
+
// 'lateOpenDays': 3,
|
|
678
|
+
// 'earlyCloseDays': 5,
|
|
679
|
+
// },
|
|
680
|
+
// },
|
|
681
|
+
// 'conversionMetrics': {
|
|
682
|
+
// 'highEngagers': {
|
|
683
|
+
// 'storeName': 'LKST2025',
|
|
684
|
+
// 'storeId': '11-2025',
|
|
685
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
686
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
687
|
+
// 'vsMTDAvgRate': 20,
|
|
688
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
689
|
+
// },
|
|
690
|
+
// 'lowEngagers': {
|
|
691
|
+
// 'storeName': 'LKST2025',
|
|
692
|
+
// 'storeId': '11-2025',
|
|
693
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
694
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
695
|
+
// 'vsMTDAvgRate': 20,
|
|
696
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
697
|
+
// },
|
|
698
|
+
// 'highPotentialBuyers': {
|
|
699
|
+
// 'storeName': 'LKST2025',
|
|
700
|
+
// 'storeId': '11-2025',
|
|
701
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
702
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
703
|
+
// 'vsMTDAvgRate': 20,
|
|
704
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
705
|
+
// },
|
|
706
|
+
// 'lowPotentialBuyers': {
|
|
707
|
+
// 'storeName': 'LKST2025',
|
|
708
|
+
// 'storeId': '11-2025',
|
|
709
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
710
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
711
|
+
// 'vsMTDAvgRate': 20,
|
|
712
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
713
|
+
// },
|
|
714
|
+
// 'highFootfallCount': {
|
|
715
|
+
// 'storeName': 'LKST2025',
|
|
716
|
+
// 'storeId': '11-2025',
|
|
717
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
718
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
719
|
+
// 'vsMTDAvgRate': 20,
|
|
720
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
721
|
+
// },
|
|
722
|
+
// 'lowFootfallCount': {
|
|
723
|
+
// 'storeName': 'LKST2025',
|
|
724
|
+
// 'storeId': '11-2025',
|
|
725
|
+
// 'vsSameDayLastWeekRate': 20,
|
|
726
|
+
// 'vsSameDayLastWeekComparisonFlag': false,
|
|
727
|
+
// 'vsMTDAvgRate': 20,
|
|
728
|
+
// 'vsMTDAvgComparisonFlag': false,
|
|
729
|
+
// },
|
|
730
|
+
// },
|
|
731
|
+
// 'avgWeekdayFootfall': {
|
|
732
|
+
// 'weekDay': 'Sunday',
|
|
733
|
+
// 'customerCount': 60,
|
|
734
|
+
// 'PeekFootfallBetween': '04:00 PM - 06:00 PM',
|
|
735
|
+
// 'vsLastWeekRate': 20,
|
|
736
|
+
// 'vsLastWeekComparisonFlag': false,
|
|
737
|
+
// },
|
|
738
|
+
// 'lowOperationalHours': [
|
|
739
|
+
// { 'storeName': 'LKST2025', 'storeId': '11-2025' },
|
|
740
|
+
// { 'storeName': 'LKST2024', 'storeId': '11-2024' },
|
|
741
|
+
// { 'storeName': 'LKST2023', 'storeId': '11-2023' },
|
|
742
|
+
// ],
|
|
743
|
+
// 'fullDownTime': [
|
|
744
|
+
// { 'storeName': 'LKST2025', 'storeId': '11-2025' },
|
|
745
|
+
// { 'storeName': 'LKST2024', 'storeId': '11-2024' },
|
|
746
|
+
// { 'storeName': 'LKST2023', 'storeId': '11-2023' },
|
|
747
|
+
// ],
|
|
748
|
+
// };
|
|
749
|
+
let newTemplateData = templateData;
|
|
750
|
+
const overallLamdaURL = 'https://7ozawm36scwmwhh4vzkecqkgv40lpjxt.lambda-url.ap-south-1.on.aws/';
|
|
751
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
752
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== '200' ) {
|
|
753
|
+
return '';
|
|
754
|
+
}
|
|
755
|
+
return lamdaAPIResultData;
|
|
756
|
+
} catch ( error ) {
|
|
757
|
+
logger.error( { error: error, message: data, function: 'lamdaAPI4' } );
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
async function hourlyChartLamdaAPI( templateData ) {
|
|
763
|
+
try {
|
|
764
|
+
// console.log( 'hourlyChartLamdaAPI' );
|
|
765
|
+
const bucketDetails = JSON.parse( process.env.BUCKET );
|
|
766
|
+
let hourlyChartUrl;
|
|
767
|
+
|
|
768
|
+
// let lamdaAPIResultData = {
|
|
769
|
+
// 'status_code': 200,
|
|
770
|
+
// 'hourlyData': [
|
|
771
|
+
// { rate: 6, count: 22, time: '01:00' },
|
|
772
|
+
// { rate: 1, count: 2, time: '03:00' },
|
|
773
|
+
// { rate: 1, count: 3, time: '05:00' },
|
|
774
|
+
// { rate: 10, count: 36, time: '07:00' },
|
|
775
|
+
// { rate: 6, count: 21, time: '09:00' },
|
|
776
|
+
// { rate: 8, count: 32, time: '11:00' },
|
|
777
|
+
// { rate: 7, count: 28, time: '13:00' },
|
|
778
|
+
// { rate: 15, count: 56, time: '15:00' },
|
|
779
|
+
// { rate: 12, count: 47, time: '17:00' },
|
|
780
|
+
// { rate: 12, count: 47, time: '19:00' },
|
|
781
|
+
// { rate: 10, count: 36, time: '21:00' },
|
|
782
|
+
// { rate: 13, count: 48, time: '23:59' },
|
|
783
|
+
// ],
|
|
784
|
+
// };
|
|
785
|
+
// return lamdaAPIResultData;
|
|
786
|
+
|
|
787
|
+
let newTemplateData = templateData;
|
|
788
|
+
newTemplateData.valueType = 'actual';
|
|
789
|
+
newTemplateData.nob = false;
|
|
790
|
+
newTemplateData.processType = 'footfall';
|
|
791
|
+
newTemplateData.limit = 20;
|
|
792
|
+
newTemplateData.offset = 0;
|
|
793
|
+
|
|
794
|
+
const overallLamdaURL = 'https://okpiyyhjvzbopvufnburhf3ase0hjfnl.lambda-url.ap-south-1.on.aws/';
|
|
795
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
796
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== 200 ) {
|
|
797
|
+
return hourlyChartUrl;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
let hourlyData = lamdaAPIResultData.hourlyData || [];
|
|
801
|
+
let hourlyChartImagePath = await overallHourlyChart( hourlyData );
|
|
802
|
+
|
|
803
|
+
// Upload hourly chart
|
|
804
|
+
const hourlyChartParams = {
|
|
805
|
+
Bucket: bucketDetails.mailer,
|
|
806
|
+
Key: `${dayjs().format( 'YYYY-MM-DD-HH:mm:ss' )}/mail/emailHourlyUserChart.png`,
|
|
807
|
+
ContentType: 'image/png',
|
|
808
|
+
body: hourlyChartImagePath,
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const hourlyChartResponse = await fileUpload( hourlyChartParams );
|
|
812
|
+
if ( hourlyChartResponse && hourlyChartResponse.Key ) {
|
|
813
|
+
hourlyChartUrl = await signedUrl( {
|
|
814
|
+
Bucket: bucketDetails.mailer,
|
|
815
|
+
file_path: hourlyChartResponse.Key,
|
|
816
|
+
} );
|
|
817
|
+
} else {
|
|
818
|
+
throw new Error( 'S3 Upload failed for hourly chart' );
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
return hourlyChartUrl;
|
|
822
|
+
} catch ( error ) {
|
|
823
|
+
// console.log( ' error hourlyChartLamdaAPI=>', error );
|
|
824
|
+
logger.error( { error: error, function: 'hourlyChartLamdaAPI' } );
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
async function dailyChartLamdaAPI( templateData ) {
|
|
830
|
+
try {
|
|
831
|
+
const bucketDetails = JSON.parse( process.env.BUCKET );
|
|
832
|
+
let chartUrl;
|
|
833
|
+
|
|
834
|
+
// let lamdaAPIResultData = {
|
|
835
|
+
// 'status_code': '200',
|
|
836
|
+
// 'storeData': [ { count: 378, storeName: 'VS T1', storeId: '430-8' } ],
|
|
837
|
+
// 'totalCount': 1,
|
|
838
|
+
// };
|
|
839
|
+
// return lamdaAPIResultData;
|
|
840
|
+
|
|
841
|
+
let newTemplateData = templateData;
|
|
842
|
+
newTemplateData.valueType = 'actual';
|
|
843
|
+
newTemplateData.nob = false;
|
|
844
|
+
newTemplateData.processType = 'footfall';
|
|
845
|
+
newTemplateData.limit = 20;
|
|
846
|
+
newTemplateData.offset = 0;
|
|
847
|
+
const overallLamdaURL = 'https://eboa7d5kzefml2srjo567sbxoe0bzmog.lambda-url.ap-south-1.on.aws/';
|
|
848
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
849
|
+
// console.log( 'newTemplateData =>', newTemplateData );
|
|
850
|
+
// console.log( 'lamdaAPIResultData =>', lamdaAPIResultData );
|
|
851
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== '200' ) {
|
|
852
|
+
return chartUrl;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
let dailyData = lamdaAPIResultData.storeData || [];
|
|
856
|
+
let chartImagePath = await overallChart( dailyData );
|
|
857
|
+
// Upload overall chart
|
|
858
|
+
const overallChartParams = {
|
|
859
|
+
Bucket: bucketDetails.mailer,
|
|
860
|
+
Key: `${dayjs().format( 'YYYY-MM-DD-HH:mm:ss' )}/mail/emaildailyUserChart.png`,
|
|
861
|
+
ContentType: 'image/png',
|
|
862
|
+
body: chartImagePath,
|
|
863
|
+
};
|
|
864
|
+
const overallChartResponse = await fileUpload( overallChartParams );
|
|
865
|
+
if ( overallChartResponse && overallChartResponse.Key ) {
|
|
866
|
+
chartUrl = await signedUrl( {
|
|
867
|
+
Bucket: bucketDetails.mailer,
|
|
868
|
+
file_path: overallChartResponse.Key,
|
|
869
|
+
} );
|
|
870
|
+
} else {
|
|
871
|
+
throw new Error( 'S3 Upload failed for overall chart' );
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return chartUrl;
|
|
875
|
+
} catch ( error ) {
|
|
876
|
+
logger.error( { error: error, message: data, function: 'dailyChartLamdaAPI' } );
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function dailyFootfallTrendChartLamdaAPI( templateData ) {
|
|
882
|
+
try {
|
|
883
|
+
const bucketDetails = JSON.parse( process.env.BUCKET );
|
|
884
|
+
let chartUrl;
|
|
885
|
+
|
|
886
|
+
// let lamdaAPIResultData = {
|
|
887
|
+
// 'fromDate': '2025-01-02',
|
|
888
|
+
// 'status_code': '200',
|
|
889
|
+
// 'toDate': '2025-01-08',
|
|
890
|
+
// 'totalCount': 7,
|
|
891
|
+
// 'footfallTrendData': [
|
|
892
|
+
// {
|
|
893
|
+
// 'engagers_count': 39,
|
|
894
|
+
// 'footfallGroupCount': 37,
|
|
895
|
+
// 'down_time': '0%',
|
|
896
|
+
// 'conversion_count': 16,
|
|
897
|
+
// 'bounced_footfall_count_avg': 1,
|
|
898
|
+
// 'engagersGroupCount': 36,
|
|
899
|
+
// 'storeId': '11-1002',
|
|
900
|
+
// 'conversionRate': 40,
|
|
901
|
+
// 'bounced_count': 1,
|
|
902
|
+
// 'footfall_count': 40,
|
|
903
|
+
// 'potentialBuyers_count': 36,
|
|
904
|
+
// 'footfall_count_avg': 40,
|
|
905
|
+
// 'avgDwellTime': 21,
|
|
906
|
+
// 'engagers_count_avg': 39,
|
|
907
|
+
// 'storeName': '2025-01-03',
|
|
908
|
+
// 'missedOpportunity_count_avg': 4,
|
|
909
|
+
// 'missedOpportunity_count': 4,
|
|
910
|
+
// },
|
|
911
|
+
// {
|
|
912
|
+
// 'engagers_count': 51,
|
|
913
|
+
// 'footfallGroupCount': 48,
|
|
914
|
+
// 'down_time': '0%',
|
|
915
|
+
// 'conversion_count': 31,
|
|
916
|
+
// 'bounced_footfall_count_avg': 6,
|
|
917
|
+
// 'engagersGroupCount': 43,
|
|
918
|
+
// 'storeId': '11-1002',
|
|
919
|
+
// 'conversionRate': 54,
|
|
920
|
+
// 'bounced_count': 6,
|
|
921
|
+
// 'footfall_count': 57,
|
|
922
|
+
// 'potentialBuyers_count': 43,
|
|
923
|
+
// 'footfall_count_avg': 57,
|
|
924
|
+
// 'avgDwellTime': 32,
|
|
925
|
+
// 'engagers_count_avg': 51,
|
|
926
|
+
// 'storeName': '2025-01-08',
|
|
927
|
+
// 'missedOpportunity_count_avg': 1,
|
|
928
|
+
// 'missedOpportunity_count': 1,
|
|
929
|
+
// },
|
|
930
|
+
// {
|
|
931
|
+
// 'engagers_count': 79,
|
|
932
|
+
// 'footfallGroupCount': 80,
|
|
933
|
+
// 'down_time': '1%',
|
|
934
|
+
// 'conversion_count': 44,
|
|
935
|
+
// 'bounced_footfall_count_avg': 8,
|
|
936
|
+
// 'engagersGroupCount': 72,
|
|
937
|
+
// 'storeId': '11-1002',
|
|
938
|
+
// 'conversionRate': 51,
|
|
939
|
+
// 'bounced_count': 8,
|
|
940
|
+
// 'footfall_count': 87,
|
|
941
|
+
// 'potentialBuyers_count': 72,
|
|
942
|
+
// 'footfall_count_avg': 87,
|
|
943
|
+
// 'avgDwellTime': 38,
|
|
944
|
+
// 'engagers_count_avg': 79,
|
|
945
|
+
// 'storeName': '2025-01-06',
|
|
946
|
+
// 'missedOpportunity_count_avg': 10,
|
|
947
|
+
// 'missedOpportunity_count': 10,
|
|
948
|
+
// },
|
|
949
|
+
// {
|
|
950
|
+
// 'engagers_count': 70,
|
|
951
|
+
// 'footfallGroupCount': 63,
|
|
952
|
+
// 'down_time': '0%',
|
|
953
|
+
// 'conversion_count': 33,
|
|
954
|
+
// 'bounced_footfall_count_avg': 1,
|
|
955
|
+
// 'engagersGroupCount': 62,
|
|
956
|
+
// 'storeId': '11-1002',
|
|
957
|
+
// 'conversionRate': 46,
|
|
958
|
+
// 'bounced_count': 1,
|
|
959
|
+
// 'footfall_count': 71,
|
|
960
|
+
// 'potentialBuyers_count': 62,
|
|
961
|
+
// 'footfall_count_avg': 71,
|
|
962
|
+
// 'avgDwellTime': 35,
|
|
963
|
+
// 'engagers_count_avg': 70,
|
|
964
|
+
// 'storeName': '2025-01-05',
|
|
965
|
+
// 'missedOpportunity_count_avg': 5,
|
|
966
|
+
// 'missedOpportunity_count': 5,
|
|
967
|
+
// },
|
|
968
|
+
// {
|
|
969
|
+
// 'engagers_count': 45,
|
|
970
|
+
// 'footfallGroupCount': 43,
|
|
971
|
+
// 'down_time': '1%',
|
|
972
|
+
// 'conversion_count': 23,
|
|
973
|
+
// 'bounced_footfall_count_avg': 2,
|
|
974
|
+
// 'engagersGroupCount': 41,
|
|
975
|
+
// 'storeId': '11-1002',
|
|
976
|
+
// 'conversionRate': 49,
|
|
977
|
+
// 'bounced_count': 2,
|
|
978
|
+
// 'footfall_count': 47,
|
|
979
|
+
// 'potentialBuyers_count': 41,
|
|
980
|
+
// 'footfall_count_avg': 47,
|
|
981
|
+
// 'avgDwellTime': 32,
|
|
982
|
+
// 'engagers_count_avg': 45,
|
|
983
|
+
// 'storeName': '2025-01-02',
|
|
984
|
+
// 'missedOpportunity_count_avg': 7,
|
|
985
|
+
// 'missedOpportunity_count': 7,
|
|
986
|
+
// },
|
|
987
|
+
// {
|
|
988
|
+
// 'engagers_count': 70,
|
|
989
|
+
// 'footfallGroupCount': 68,
|
|
990
|
+
// 'down_time': '1%',
|
|
991
|
+
// 'conversion_count': 36,
|
|
992
|
+
// 'bounced_footfall_count_avg': 8,
|
|
993
|
+
// 'engagersGroupCount': 60,
|
|
994
|
+
// 'storeId': '11-1002',
|
|
995
|
+
// 'conversionRate': 46,
|
|
996
|
+
// 'bounced_count': 8,
|
|
997
|
+
// 'footfall_count': 78,
|
|
998
|
+
// 'potentialBuyers_count': 60,
|
|
999
|
+
// 'footfall_count_avg': 78,
|
|
1000
|
+
// 'avgDwellTime': 31,
|
|
1001
|
+
// 'engagers_count_avg': 70,
|
|
1002
|
+
// 'storeName': '2025-01-04',
|
|
1003
|
+
// 'missedOpportunity_count_avg': 5,
|
|
1004
|
+
// 'missedOpportunity_count': 5,
|
|
1005
|
+
// },
|
|
1006
|
+
// {
|
|
1007
|
+
// 'engagers_count': 60,
|
|
1008
|
+
// 'footfallGroupCount': 61,
|
|
1009
|
+
// 'down_time': '1%',
|
|
1010
|
+
// 'conversion_count': 23,
|
|
1011
|
+
// 'bounced_footfall_count_avg': 6,
|
|
1012
|
+
// 'engagersGroupCount': 55,
|
|
1013
|
+
// 'storeId': '11-1002',
|
|
1014
|
+
// 'conversionRate': 35,
|
|
1015
|
+
// 'bounced_count': 6,
|
|
1016
|
+
// 'footfall_count': 66,
|
|
1017
|
+
// 'potentialBuyers_count': 55,
|
|
1018
|
+
// 'footfall_count_avg': 66,
|
|
1019
|
+
// 'avgDwellTime': 28,
|
|
1020
|
+
// 'engagers_count_avg': 60,
|
|
1021
|
+
// 'storeName': '2025-01-07',
|
|
1022
|
+
// 'missedOpportunity_count_avg': 6,
|
|
1023
|
+
// 'missedOpportunity_count': 6,
|
|
1024
|
+
// },
|
|
1025
|
+
// ],
|
|
1026
|
+
// };
|
|
1027
|
+
// return lamdaAPIResultData;
|
|
1028
|
+
|
|
1029
|
+
let newTemplateData = templateData;
|
|
1030
|
+
// newTemplateData.dateType = 'weekly';
|
|
1031
|
+
let processTypeValue = 'engagers';
|
|
1032
|
+
if ( templateData.featureConfigs.conversionCalculation !== 'engagers-count' ) {
|
|
1033
|
+
processTypeValue='potentialBuyer';
|
|
1034
|
+
}
|
|
1035
|
+
let filterByTypeValue = 'average';
|
|
1036
|
+
if ( templateData.templateType == 'daily' ) {
|
|
1037
|
+
filterByTypeValue='actual';
|
|
1038
|
+
}
|
|
1039
|
+
newTemplateData.dateType = templateData.templateType;
|
|
1040
|
+
newTemplateData.valueType = 'actual';
|
|
1041
|
+
newTemplateData.filterBy = filterByTypeValue;
|
|
1042
|
+
newTemplateData.nob = false;
|
|
1043
|
+
newTemplateData.processType = processTypeValue;
|
|
1044
|
+
newTemplateData.limit = 31;
|
|
1045
|
+
newTemplateData.offset = 0;
|
|
1046
|
+
const overallLamdaURL = 'https://x6sjlqwaqd64kyioxhwrwfesbm0jjitx.lambda-url.ap-south-1.on.aws/';
|
|
1047
|
+
let lamdaAPIResultData = await LamdaServiceCall( overallLamdaURL, newTemplateData );
|
|
1048
|
+
if ( !lamdaAPIResultData || lamdaAPIResultData.status_code !== '200' ) {
|
|
1049
|
+
return chartUrl;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
let dailyData = lamdaAPIResultData.footfallTrendData || [];
|
|
1053
|
+
let chartImagePath = await footfallTrend( dailyData );
|
|
1054
|
+
// Upload overall chart
|
|
1055
|
+
const overallChartParams = {
|
|
1056
|
+
Bucket: bucketDetails.mailer,
|
|
1057
|
+
Key: `${dayjs().format( 'YYYY-MM-DD-HH:mm:ss' )}/mail/emailweeklyUserChart.png`,
|
|
1058
|
+
ContentType: 'image/png',
|
|
1059
|
+
body: chartImagePath,
|
|
1060
|
+
};
|
|
1061
|
+
const overallChartResponse = await fileUpload( overallChartParams );
|
|
1062
|
+
if ( overallChartResponse && overallChartResponse.Key ) {
|
|
1063
|
+
chartUrl = await signedUrl( {
|
|
1064
|
+
Bucket: bucketDetails.mailer,
|
|
1065
|
+
file_path: overallChartResponse.Key,
|
|
1066
|
+
} );
|
|
1067
|
+
} else {
|
|
1068
|
+
throw new Error( 'S3 Upload failed for overall chart' );
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
return chartUrl;
|
|
1072
|
+
} catch ( error ) {
|
|
1073
|
+
logger.error( { error: error, message: data, function: 'dailyFootfallTrendChartLamdaAPI' } );
|
|
1074
|
+
return false;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
async function getLamdaChartData( templateData ) {
|
|
1079
|
+
try {
|
|
1080
|
+
let resultLamdaChartData = {
|
|
1081
|
+
dailyData: '',
|
|
1082
|
+
hourlyData: '',
|
|
1083
|
+
};
|
|
1084
|
+
if ( templateData.allStores.length == 1 && templateData.templateType == 'daily' ) {
|
|
1085
|
+
// // Call Lamda API No 1 Single Store Single Date
|
|
1086
|
+
const [ chartImagePath, hourlyChartImagePath ] = await Promise.all( [
|
|
1087
|
+
dailyChartLamdaAPI( templateData ), // For the overall chart (col-8)
|
|
1088
|
+
hourlyChartLamdaAPI( templateData ), // For the hourly chart (col-4)
|
|
1089
|
+
] );
|
|
1090
|
+
resultLamdaChartData.dailyData = chartImagePath;
|
|
1091
|
+
resultLamdaChartData.hourlyData = hourlyChartImagePath;
|
|
1092
|
+
return resultLamdaChartData;
|
|
1093
|
+
} else {
|
|
1094
|
+
// Default Value
|
|
1095
|
+
resultLamdaChartData.dailyFootfallTrendData = await dailyFootfallTrendChartLamdaAPI( templateData );
|
|
1096
|
+
return resultLamdaChartData;
|
|
1097
|
+
}
|
|
1098
|
+
} catch ( error ) {
|
|
1099
|
+
// console.log( 'error =>', error );
|
|
1100
|
+
logger.error( { error: error, function: 'getLamdaChartData' } );
|
|
1101
|
+
return false;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
async function emailerSendEmail( storeData, clientData, lamdaMetrics, lamdaCharts, templateData ) {
|
|
1106
|
+
try {
|
|
1107
|
+
let hbsFileName = '../hbs/dailyMailerSingle.hbs';
|
|
1108
|
+
if ( templateData.allStores.length == 1 && templateData.templateType == 'daily' ) {
|
|
1109
|
+
// // Call Lamda API No 1 Single Store Single Date
|
|
1110
|
+
hbsFileName = '../hbs/dailyMailerSingle.hbs';
|
|
1111
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'daily' ) {
|
|
1112
|
+
// // Call Lamda API No 3 Multiple Store Single Date
|
|
1113
|
+
hbsFileName = '../hbs/dailyMailerMultiple.hbs';
|
|
1114
|
+
} else if ( templateData.allStores.length == 1 && templateData.templateType == 'weekly' ) {
|
|
1115
|
+
// // Call Lamda API No 2 Single Store Multiple Date
|
|
1116
|
+
hbsFileName = '../hbs/weeklyMailerSingle.hbs';
|
|
1117
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'weekly' ) {
|
|
1118
|
+
// // Call Lamda API No 4 Multiple Store Multiple Date
|
|
1119
|
+
hbsFileName = '../hbs/weeklyMailerMultiple.hbs';
|
|
1120
|
+
} else if ( templateData.allStores.length == 1 && templateData.templateType == 'monthly' ) {
|
|
1121
|
+
// // Call Lamda API No 5 Single Store Multiple Date
|
|
1122
|
+
hbsFileName = '../hbs/dailyMailerSingle.hbs';
|
|
1123
|
+
} else if ( templateData.allStores.length > 1 && templateData.templateType == 'monthly' ) {
|
|
1124
|
+
// // Call Lamda API No 6 Multiple Store Multiple Date
|
|
1125
|
+
hbsFileName = '../hbs/dailyMailerSingle.hbs';
|
|
1126
|
+
} else {
|
|
1127
|
+
// Default Value
|
|
1128
|
+
}
|
|
1129
|
+
// Prepare email with Handlebars template
|
|
1130
|
+
const fileContent = readFileSync(
|
|
1131
|
+
join( __dirname, hbsFileName ),
|
|
1132
|
+
'utf8',
|
|
1133
|
+
);
|
|
1134
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
1135
|
+
|
|
1136
|
+
const emailVars = {
|
|
1137
|
+
// email: inputData.email,
|
|
1138
|
+
clientName: clientData.clientName,
|
|
1139
|
+
domain: JSON.parse( process.env.URL ).apiDomain,
|
|
1140
|
+
overallChartImage: lamdaCharts.dailyData, // Use the S3 URL for the overall chart
|
|
1141
|
+
hourlyChartImage: lamdaCharts.hourlyData, // Use the S3 URL for the hourly chart
|
|
1142
|
+
lamdaMetrics: lamdaMetrics,
|
|
1143
|
+
storeData: storeData,
|
|
1144
|
+
templateData: templateData,
|
|
1145
|
+
chartImage: lamdaCharts.dailyFootfallTrendData,
|
|
1146
|
+
featureConfigs: {
|
|
1147
|
+
open: clientData?.featureConfigs?.open || '10:00:00',
|
|
1148
|
+
close: clientData?.featureConfigs?.close || '23:00:00',
|
|
1149
|
+
billableCalculation: clientData?.featureConfigs?.billableCalculation || 'engagers-count',
|
|
1150
|
+
conversionCalculation: clientData?.featureConfigs?.conversionCalculation || 'engagers-count',
|
|
1151
|
+
missedOpportunityCalculation: clientData?.featureConfigs?.missedOpportunityCalculation || 'engagers-conversion',
|
|
1152
|
+
bufferTime: 30,
|
|
1153
|
+
},
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
const html = htmlContent( { data: emailVars } );
|
|
1157
|
+
|
|
1158
|
+
// Prepare email subject and send the email
|
|
1159
|
+
const subject = `Footfall Trend Report for ${clientData.clientName}`;
|
|
1160
|
+
const ses = JSON.parse( process.env.SES );
|
|
1161
|
+
|
|
1162
|
+
// templateData.userEmail
|
|
1163
|
+
await sendEmailWithSES(
|
|
1164
|
+
'nafila@tangotech.co.in',
|
|
1165
|
+
subject,
|
|
1166
|
+
html,
|
|
1167
|
+
'',
|
|
1168
|
+
ses.adminEmail,
|
|
1169
|
+
);
|
|
1170
|
+
|
|
1171
|
+
// return res.sendSuccess( { result: 'EMAIL-SENT' } );
|
|
1172
|
+
|
|
1173
|
+
return true;
|
|
1174
|
+
} catch ( error ) {
|
|
1175
|
+
logger.error( { error: error, function: 'emailerSendEmail' } );
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const overallChart = async ( data ) => {
|
|
1181
|
+
// console.log( 'Generating footfall chart...' );
|
|
1182
|
+
|
|
1183
|
+
// let chartImagePath = path.resolve( __dirname, 'emailchart-image.png' );
|
|
1184
|
+
// console.log( 'Chart Image Path:', chartImagePath );
|
|
1185
|
+
|
|
1186
|
+
const browser = await puppeteer.launch( { headless: true } );
|
|
1187
|
+
const page = await browser.newPage();
|
|
1188
|
+
|
|
1189
|
+
const chartHtmlContent = `
|
|
1190
|
+
<!DOCTYPE html>
|
|
1191
|
+
<html>
|
|
1192
|
+
<head>
|
|
1193
|
+
<style>
|
|
1194
|
+
#testGraphics {
|
|
1195
|
+
width: 100%;
|
|
1196
|
+
height: 600px;
|
|
1197
|
+
}
|
|
1198
|
+
</style>
|
|
1199
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1200
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
1201
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1202
|
+
</head>
|
|
1203
|
+
<body>
|
|
1204
|
+
<div id="testGraphics"></div>
|
|
1205
|
+
<script>
|
|
1206
|
+
am5.ready(function() {
|
|
1207
|
+
const root = am5.Root.new("testGraphics");
|
|
1208
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
1209
|
+
|
|
1210
|
+
const chart = root.container.children.push(
|
|
1211
|
+
am5xy.XYChart.new(root, {
|
|
1212
|
+
panX: true,
|
|
1213
|
+
panY: true,
|
|
1214
|
+
wheelX: "panX",
|
|
1215
|
+
wheelY: "zoomX",
|
|
1216
|
+
pinchZoomX: true,
|
|
1217
|
+
paddingLeft: 0,
|
|
1218
|
+
paddingRight: 0,
|
|
1219
|
+
width: am5.percent(100),
|
|
1220
|
+
})
|
|
1221
|
+
);
|
|
1222
|
+
|
|
1223
|
+
const cursor = chart.set("cursor", am5xy.XYCursor.new(root, {}));
|
|
1224
|
+
cursor.lineY.set("visible", false);
|
|
1225
|
+
|
|
1226
|
+
const xRenderer = am5xy.AxisRendererX.new(root, {
|
|
1227
|
+
minGridDistance: 30,
|
|
1228
|
+
minorGridEnabled: true,
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
xRenderer.labels.template.setAll({
|
|
1232
|
+
rotation: -45,
|
|
1233
|
+
centerY: am5.p50,
|
|
1234
|
+
centerX: am5.p100,
|
|
1235
|
+
paddingRight: 5,
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
const xAxis = chart.xAxes.push(
|
|
1239
|
+
am5xy.CategoryAxis.new(root, {
|
|
1240
|
+
categoryField: "storeName",
|
|
1241
|
+
renderer: xRenderer,
|
|
1242
|
+
})
|
|
1243
|
+
);
|
|
1244
|
+
|
|
1245
|
+
const yRenderer = am5xy.AxisRendererY.new(root, {
|
|
1246
|
+
strokeOpacity: 0.1,
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
const yAxis = chart.yAxes.push(
|
|
1250
|
+
am5xy.ValueAxis.new(root, {
|
|
1251
|
+
renderer: yRenderer,
|
|
1252
|
+
})
|
|
1253
|
+
);
|
|
1254
|
+
|
|
1255
|
+
const formattedData = ${JSON.stringify( data )}.map((item) => ({
|
|
1256
|
+
storeName: item.storeName,
|
|
1257
|
+
value: Number(item.count),
|
|
1258
|
+
}));
|
|
1259
|
+
|
|
1260
|
+
const series = chart.series.push(
|
|
1261
|
+
am5xy.ColumnSeries.new(root, {
|
|
1262
|
+
xAxis: xAxis,
|
|
1263
|
+
yAxis: yAxis,
|
|
1264
|
+
valueYField: "value",
|
|
1265
|
+
categoryXField: "storeName",
|
|
1266
|
+
})
|
|
1267
|
+
);
|
|
1268
|
+
|
|
1269
|
+
xAxis.data.setAll(formattedData);
|
|
1270
|
+
series.data.setAll(formattedData);
|
|
1271
|
+
|
|
1272
|
+
series.columns.template.setAll({ strokeOpacity: 0 });
|
|
1273
|
+
|
|
1274
|
+
series.appear(1000);
|
|
1275
|
+
chart.appear(1000, 100);
|
|
1276
|
+
});
|
|
1277
|
+
</script>
|
|
1278
|
+
</body>
|
|
1279
|
+
</html>
|
|
1280
|
+
`;
|
|
1281
|
+
let chartBuffer;
|
|
1282
|
+
try {
|
|
1283
|
+
// console.log( 'overallChart... Try' );
|
|
1284
|
+
await page.setContent( chartHtmlContent, { waitUntil: 'domcontentloaded' } );
|
|
1285
|
+
await page.waitForSelector( '#testGraphics', { visible: true } );
|
|
1286
|
+
chartBuffer = await page.screenshot( { encoding: 'binary' } );
|
|
1287
|
+
// console.log( 'Screenshot saved to:', chartImagePath );
|
|
1288
|
+
} catch ( err ) {
|
|
1289
|
+
// console.error( 'Error generating chart screenshot:', err );
|
|
1290
|
+
throw new Error( 'Failed to generate chart screenshot' );
|
|
1291
|
+
} finally {
|
|
1292
|
+
await browser.close();
|
|
1293
|
+
}
|
|
1294
|
+
// console.log( 'chartBuffer daily... Try', chartBuffer );
|
|
1295
|
+
return chartBuffer;
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
const overallHourlyChart = async ( data ) => {
|
|
1299
|
+
// console.log( 'Generating heatmap chart...' );
|
|
1300
|
+
|
|
1301
|
+
const browser = await puppeteer.launch( { headless: true } );
|
|
1302
|
+
const page = await browser.newPage();
|
|
1303
|
+
|
|
1304
|
+
const chartHtmlContent = `
|
|
1305
|
+
<!DOCTYPE html>
|
|
1306
|
+
<html>
|
|
1307
|
+
<head>
|
|
1308
|
+
<style>
|
|
1309
|
+
#heatmapchart {
|
|
1310
|
+
width: 100%;
|
|
1311
|
+
height: 600px;
|
|
1312
|
+
}
|
|
1313
|
+
</style>
|
|
1314
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1315
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
1316
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1317
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Responsive.js"></script>
|
|
1318
|
+
</head>
|
|
1319
|
+
<body>
|
|
1320
|
+
<div id="heatmapchart"></div>
|
|
1321
|
+
<script>
|
|
1322
|
+
am5.ready(function () {
|
|
1323
|
+
const root = am5.Root.new("heatmapchart");
|
|
1324
|
+
root.setThemes([am5themes_Animated.new(root), am5themes_Responsive.new(root)]);
|
|
1325
|
+
|
|
1326
|
+
// Create chart
|
|
1327
|
+
const chart = root.container.children.push(
|
|
1328
|
+
am5xy.XYChart.new(root, {
|
|
1329
|
+
panX: false,
|
|
1330
|
+
panY: false,
|
|
1331
|
+
wheelX: "none",
|
|
1332
|
+
wheelY: "none",
|
|
1333
|
+
paddingLeft: 0,
|
|
1334
|
+
layout: root.verticalLayout,
|
|
1335
|
+
})
|
|
1336
|
+
);
|
|
1337
|
+
|
|
1338
|
+
// Create axes and renderers
|
|
1339
|
+
const yRenderer = am5xy.AxisRendererY.new(root, {
|
|
1340
|
+
minGridDistance: 20,
|
|
1341
|
+
inversed: true,
|
|
1342
|
+
opposite: true,
|
|
1343
|
+
minorGridEnabled: true,
|
|
1344
|
+
});
|
|
1345
|
+
|
|
1346
|
+
yRenderer.grid.template.set("visible", false);
|
|
1347
|
+
|
|
1348
|
+
const yAxis = chart.yAxes.push(
|
|
1349
|
+
am5xy.CategoryAxis.new(root, {
|
|
1350
|
+
renderer: yRenderer,
|
|
1351
|
+
categoryField: "time",
|
|
1352
|
+
})
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
const xRenderer = am5xy.AxisRendererX.new(root, {
|
|
1356
|
+
minGridDistance: 30,
|
|
1357
|
+
opposite: true,
|
|
1358
|
+
minorGridEnabled: true,
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
xRenderer.grid.template.set("visible", false);
|
|
1362
|
+
|
|
1363
|
+
const xAxis = chart.xAxes.push(
|
|
1364
|
+
am5xy.CategoryAxis.new(root, {
|
|
1365
|
+
renderer: xRenderer,
|
|
1366
|
+
categoryField: "weekday",
|
|
1367
|
+
})
|
|
1368
|
+
);
|
|
1369
|
+
|
|
1370
|
+
// Create series
|
|
1371
|
+
const series = chart.series.push(
|
|
1372
|
+
am5xy.ColumnSeries.new(root, {
|
|
1373
|
+
calculateAggregates: true,
|
|
1374
|
+
stroke: am5.color(0xffffff),
|
|
1375
|
+
clustered: false,
|
|
1376
|
+
xAxis: xAxis,
|
|
1377
|
+
yAxis: yAxis,
|
|
1378
|
+
categoryXField: "weekday",
|
|
1379
|
+
categoryYField: "time",
|
|
1380
|
+
valueField: "rate",
|
|
1381
|
+
})
|
|
1382
|
+
);
|
|
1383
|
+
|
|
1384
|
+
series.columns.template.setAll({
|
|
1385
|
+
tooltipText: "{rate}",
|
|
1386
|
+
strokeOpacity: 1,
|
|
1387
|
+
strokeWidth: 2,
|
|
1388
|
+
width: am5.percent(100),
|
|
1389
|
+
height: am5.percent(100),
|
|
1390
|
+
fill: am5.color(0xffffff),
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1393
|
+
// Apply range-based color rules
|
|
1394
|
+
series.columns.template.adapters.add("fill", (fill, target) => {
|
|
1395
|
+
const dataItem = target.dataItem?.dataContext;
|
|
1396
|
+
if (dataItem && dataItem.rate !== undefined) {
|
|
1397
|
+
const rate = dataItem.rate;
|
|
1398
|
+
if (rate >= 0 && rate <= 10) {
|
|
1399
|
+
return am5.color(0xEAF8FF);
|
|
1400
|
+
} else if (rate > 10 && rate <= 20) {
|
|
1401
|
+
return am5.color(0xCCE9FE);
|
|
1402
|
+
} else if (rate > 20 && rate <= 30) {
|
|
1403
|
+
return am5.color(0xB0D6FC);
|
|
1404
|
+
} else if (rate > 30 && rate <= 40) {
|
|
1405
|
+
return am5.color(0x94C2FA);
|
|
1406
|
+
} else if (rate > 40 && rate <= 55) {
|
|
1407
|
+
return am5.color(0x78A9F8);
|
|
1408
|
+
} else if (rate > 55 && rate <= 75) {
|
|
1409
|
+
return am5.color(0x99D2FD);
|
|
1410
|
+
} else if (rate > 75 && rate <= 90) {
|
|
1411
|
+
return am5.color(0x66BCFD);
|
|
1412
|
+
} else if (rate > 90 && rate <= 100) {
|
|
1413
|
+
return am5.color(0x3460F3);
|
|
1414
|
+
} else {
|
|
1415
|
+
return am5.color(0xFFF);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return fill;
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
series.bullets.push(() =>
|
|
1422
|
+
am5.Bullet.new(root, {
|
|
1423
|
+
sprite: am5.Label.new(root, {
|
|
1424
|
+
text: "{rate.formatNumber('#.#')}%",
|
|
1425
|
+
fill: am5.color(0x000000),
|
|
1426
|
+
centerY: am5.p50,
|
|
1427
|
+
centerX: am5.p50,
|
|
1428
|
+
populateText: true,
|
|
1429
|
+
fontSize: 16,
|
|
1430
|
+
fontWeight: "bold",
|
|
1431
|
+
}),
|
|
1432
|
+
})
|
|
1433
|
+
);
|
|
1434
|
+
|
|
1435
|
+
// Format data
|
|
1436
|
+
const formattedData = ${JSON.stringify( data )}.map((item) => ({
|
|
1437
|
+
...item,
|
|
1438
|
+
weekday: "Hourly Data",
|
|
1439
|
+
}));
|
|
1440
|
+
|
|
1441
|
+
series.data.setAll(formattedData);
|
|
1442
|
+
|
|
1443
|
+
// Set axis data
|
|
1444
|
+
const times = Array.from(new Set(formattedData.map((item) => item.time)));
|
|
1445
|
+
|
|
1446
|
+
xAxis.data.setAll([{ weekday: "Hourly Data" }]);
|
|
1447
|
+
yAxis.data.setAll(times.map((time) => ({ time })));
|
|
1448
|
+
|
|
1449
|
+
chart.appear(1000, 100);
|
|
1450
|
+
});
|
|
1451
|
+
</script>
|
|
1452
|
+
</body>
|
|
1453
|
+
</html>
|
|
1454
|
+
`;
|
|
1455
|
+
|
|
1456
|
+
let chartBuffer;
|
|
1457
|
+
try {
|
|
1458
|
+
await page.setContent( chartHtmlContent, { waitUntil: 'domcontentloaded' } );
|
|
1459
|
+
await page.waitForSelector( '#heatmapchart', { visible: true } );
|
|
1460
|
+
chartBuffer = await page.screenshot( { encoding: 'binary' } );
|
|
1461
|
+
} catch ( err ) {
|
|
1462
|
+
// console.error( 'Error generating chart screenshot:', err );
|
|
1463
|
+
throw new Error( 'Failed to generate chart screenshot' );
|
|
1464
|
+
} finally {
|
|
1465
|
+
await browser.close();
|
|
1466
|
+
}
|
|
1467
|
+
// console.log( 'chartBuffer hourly... Try', chartBuffer );
|
|
1468
|
+
return chartBuffer;
|
|
1469
|
+
};
|
|
1470
|
+
|
|
1471
|
+
const footfallTrend = async ( data ) => {
|
|
1472
|
+
// console.log( 'Generating footfall chart...' );
|
|
1473
|
+
|
|
1474
|
+
const browser = await puppeteer.launch( { headless: true } );
|
|
1475
|
+
const page = await browser.newPage();
|
|
1476
|
+
|
|
1477
|
+
const chartHtmlContent = `
|
|
1478
|
+
<!DOCTYPE html>
|
|
1479
|
+
<html>
|
|
1480
|
+
<head>
|
|
1481
|
+
<style>
|
|
1482
|
+
#Footfalltrend {
|
|
1483
|
+
width: 100%;
|
|
1484
|
+
height: 600px;
|
|
1485
|
+
}
|
|
1486
|
+
</style>
|
|
1487
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1488
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
1489
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1490
|
+
</head>
|
|
1491
|
+
<body>
|
|
1492
|
+
<div id="Footfalltrend"></div>
|
|
1493
|
+
<script>
|
|
1494
|
+
am5.ready(function() {
|
|
1495
|
+
const root = am5.Root.new('Footfalltrend');
|
|
1496
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
1497
|
+
|
|
1498
|
+
const chart = root.container.children.push(
|
|
1499
|
+
am5xy.XYChart.new(root, {
|
|
1500
|
+
panX: false,
|
|
1501
|
+
panY: false,
|
|
1502
|
+
wheelX: 'panX',
|
|
1503
|
+
wheelY: 'zoomX',
|
|
1504
|
+
layout: root.verticalLayout
|
|
1505
|
+
})
|
|
1506
|
+
);
|
|
1507
|
+
|
|
1508
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, {
|
|
1509
|
+
orientation: "horizontal"
|
|
1510
|
+
}));
|
|
1511
|
+
|
|
1512
|
+
const xRenderer = am5xy.AxisRendererX.new(root, {
|
|
1513
|
+
minGridDistance: 20,
|
|
1514
|
+
minorGridEnabled: true,
|
|
1515
|
+
});
|
|
1516
|
+
|
|
1517
|
+
xRenderer.labels.template.setAll({
|
|
1518
|
+
rotation: -45,
|
|
1519
|
+
centerY: am5.p50,
|
|
1520
|
+
centerX: am5.p100,
|
|
1521
|
+
paddingRight: 5,
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
const xAxis = chart.xAxes.push(
|
|
1525
|
+
am5xy.CategoryAxis.new(root, {
|
|
1526
|
+
categoryField: "storeName",
|
|
1527
|
+
renderer: xRenderer,
|
|
1528
|
+
tooltip: am5.Tooltip.new(root, { labelText: "{fullStoreName}" })
|
|
1529
|
+
})
|
|
1530
|
+
);
|
|
1531
|
+
|
|
1532
|
+
const formattedData = ${JSON.stringify( data )}.map((item) => ({
|
|
1533
|
+
fullStoreName: item.storeName,
|
|
1534
|
+
storeName: item.storeName,
|
|
1535
|
+
footfall: Number(item.footfall_count),
|
|
1536
|
+
conversion: Number(item.conversion_count),
|
|
1537
|
+
bounced: Number(item.bounced_count),
|
|
1538
|
+
engagers: Number(item.engagers_count),
|
|
1539
|
+
missedopportunities: Number(item.missedOpportunity_count),
|
|
1540
|
+
}));
|
|
1541
|
+
|
|
1542
|
+
formattedData.sort((a, b) => {
|
|
1543
|
+
const dateA = new Date(a.storeName);
|
|
1544
|
+
const dateB = new Date(b.storeName);
|
|
1545
|
+
return dateA - dateB;
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
xAxis.data.setAll(formattedData);
|
|
1549
|
+
|
|
1550
|
+
const yAxis = chart.yAxes.push(
|
|
1551
|
+
am5xy.ValueAxis.new(root, {
|
|
1552
|
+
min: 0,
|
|
1553
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
1554
|
+
})
|
|
1555
|
+
);
|
|
1556
|
+
|
|
1557
|
+
yAxis.children.unshift(am5.Label.new(root, {
|
|
1558
|
+
rotation: -90,
|
|
1559
|
+
text: "Footfall",
|
|
1560
|
+
y: am5.p50,
|
|
1561
|
+
centerX: am5.p50,
|
|
1562
|
+
fontFamily: "Arial",
|
|
1563
|
+
fontSize: "14px",
|
|
1564
|
+
fill: am5.color(0x000000)
|
|
1565
|
+
}));
|
|
1566
|
+
|
|
1567
|
+
const createColumnSeries = (name, field, color) => {
|
|
1568
|
+
const series = chart.series.push(
|
|
1569
|
+
am5xy.ColumnSeries.new(root, {
|
|
1570
|
+
name: name,
|
|
1571
|
+
xAxis: xAxis,
|
|
1572
|
+
yAxis: yAxis,
|
|
1573
|
+
valueYField: field,
|
|
1574
|
+
categoryXField: "storeName",
|
|
1575
|
+
fill: color,
|
|
1576
|
+
stroke: color,
|
|
1577
|
+
stacked: true,
|
|
1578
|
+
})
|
|
1579
|
+
);
|
|
1580
|
+
|
|
1581
|
+
series.data.setAll(formattedData);
|
|
1582
|
+
|
|
1583
|
+
series.bullets.push(() => {
|
|
1584
|
+
return am5.Bullet.new(root, {
|
|
1585
|
+
sprite: am5.Label.new(root, {
|
|
1586
|
+
text: "{valueY}",
|
|
1587
|
+
fill: root.interfaceColors.get("alternativeText"),
|
|
1588
|
+
centerY: am5.p50,
|
|
1589
|
+
centerX: am5.p50,
|
|
1590
|
+
populateText: true,
|
|
1591
|
+
fontSize: 12 // Reduce font size
|
|
1592
|
+
})
|
|
1593
|
+
});
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
series.columns.template.setAll({
|
|
1597
|
+
tooltipText: "{name}: {valueY}",
|
|
1598
|
+
width: am5.percent(90),
|
|
1599
|
+
tooltipY: 0,
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
series.appear(1000);
|
|
1603
|
+
return series;
|
|
1604
|
+
};
|
|
1605
|
+
|
|
1606
|
+
createColumnSeries("Footfall", "footfall", am5.color(0x67b7dc));
|
|
1607
|
+
createColumnSeries("Bounced", "bounced", am5.color(0x6794dc));
|
|
1608
|
+
createColumnSeries("Engagers", "engagers", am5.color(0x6771dc));
|
|
1609
|
+
|
|
1610
|
+
const createLineSeries = (name, fieldName, xAxis, yAxis, color) => {
|
|
1611
|
+
const series = chart.series.push(
|
|
1612
|
+
am5xy.LineSeries.new(root, {
|
|
1613
|
+
name: name,
|
|
1614
|
+
xAxis: xAxis,
|
|
1615
|
+
yAxis: yAxis,
|
|
1616
|
+
valueYField: fieldName,
|
|
1617
|
+
categoryXField: 'storeName',
|
|
1618
|
+
tooltip: am5.Tooltip.new(root, {
|
|
1619
|
+
pointerOrientation: "horizontal",
|
|
1620
|
+
labelText: "{name}: {valueY}",
|
|
1621
|
+
background: am5.Rectangle.new(root, {
|
|
1622
|
+
fill: color // Tooltip background color
|
|
1623
|
+
})
|
|
1624
|
+
})
|
|
1625
|
+
})
|
|
1626
|
+
);
|
|
1627
|
+
|
|
1628
|
+
series.strokes.template.setAll({
|
|
1629
|
+
strokeWidth: 2,
|
|
1630
|
+
stroke: color,
|
|
1631
|
+
templateField: "strokeSettings",
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1634
|
+
series.data.setAll(formattedData);
|
|
1635
|
+
|
|
1636
|
+
series.bullets.push(() => {
|
|
1637
|
+
return am5.Bullet.new(root, {
|
|
1638
|
+
sprite: am5.Circle.new(root, {
|
|
1639
|
+
strokeWidth: 1,
|
|
1640
|
+
stroke: color,
|
|
1641
|
+
radius: 1,
|
|
1642
|
+
fill: root.interfaceColors.get("background")
|
|
1643
|
+
}),
|
|
1644
|
+
});
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
series.appear();
|
|
1648
|
+
};
|
|
1649
|
+
|
|
1650
|
+
createLineSeries("Conversion", "conversion", xAxis, yAxis, am5.color(0x00FF00));
|
|
1651
|
+
|
|
1652
|
+
const legend = chart.children.push(
|
|
1653
|
+
am5.Legend.new(root, {
|
|
1654
|
+
centerX: am5.p50,
|
|
1655
|
+
x: am5.p50
|
|
1656
|
+
})
|
|
1657
|
+
);
|
|
1658
|
+
|
|
1659
|
+
legend.data.setAll(chart.series.values);
|
|
1660
|
+
|
|
1661
|
+
chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
1662
|
+
behavior: "none"
|
|
1663
|
+
}));
|
|
1664
|
+
|
|
1665
|
+
chart.appear(1000, 100);
|
|
1666
|
+
});
|
|
1667
|
+
</script>
|
|
1668
|
+
</body>
|
|
1669
|
+
</html>
|
|
1670
|
+
`;
|
|
1671
|
+
|
|
1672
|
+
let weeklyChartBuffer;
|
|
1673
|
+
try {
|
|
1674
|
+
await page.setContent( chartHtmlContent, { waitUntil: 'domcontentloaded' } );
|
|
1675
|
+
await page.waitForSelector( '#Footfalltrend', { visible: true } );
|
|
1676
|
+
weeklyChartBuffer = await page.screenshot( { encoding: 'binary' } );
|
|
1677
|
+
} catch ( err ) {
|
|
1678
|
+
// console.error( 'Error generating chart screenshot:', err );
|
|
1679
|
+
throw new Error( 'Failed to generate chart screenshot' );
|
|
1680
|
+
} finally {
|
|
1681
|
+
await browser.close();
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
return weeklyChartBuffer;
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
|
|
1688
|
+
// const footfallTrend = async ( data ) => {
|
|
1689
|
+
// console.log( 'Generating footfall chart...' );
|
|
1690
|
+
|
|
1691
|
+
// const browser = await puppeteer.launch( { headless: true } );
|
|
1692
|
+
// const page = await browser.newPage();
|
|
1693
|
+
|
|
1694
|
+
// const chartHtmlContent = `
|
|
1695
|
+
// <!DOCTYPE html>
|
|
1696
|
+
// <html>
|
|
1697
|
+
// <head>
|
|
1698
|
+
// <style>
|
|
1699
|
+
// #Footfalltrend {
|
|
1700
|
+
// width: 100%;
|
|
1701
|
+
// height: 600px;
|
|
1702
|
+
// }
|
|
1703
|
+
// </style>
|
|
1704
|
+
// <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1705
|
+
// <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
1706
|
+
// <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1707
|
+
// </head>
|
|
1708
|
+
// <body>
|
|
1709
|
+
// <div id="Footfalltrend"></div>
|
|
1710
|
+
// <script>
|
|
1711
|
+
// am5.ready(function() {
|
|
1712
|
+
// const root = am5.Root.new('Footfalltrend');
|
|
1713
|
+
// root.setThemes([am5themes_Animated.new(root)]);
|
|
1714
|
+
|
|
1715
|
+
// const chart = root.container.children.push(
|
|
1716
|
+
// am5xy.XYChart.new(root, {
|
|
1717
|
+
// panX: false,
|
|
1718
|
+
// panY: false,
|
|
1719
|
+
// wheelX: 'panX',
|
|
1720
|
+
// wheelY: 'zoomX',
|
|
1721
|
+
// layout: root.verticalLayout
|
|
1722
|
+
// })
|
|
1723
|
+
// );
|
|
1724
|
+
|
|
1725
|
+
// chart.set("scrollbarX", am5.Scrollbar.new(root, {
|
|
1726
|
+
// orientation: "horizontal"
|
|
1727
|
+
// }));
|
|
1728
|
+
|
|
1729
|
+
// const xRenderer = am5xy.AxisRendererX.new(root, {
|
|
1730
|
+
// minGridDistance: 20,
|
|
1731
|
+
// minorGridEnabled: true,
|
|
1732
|
+
// });
|
|
1733
|
+
|
|
1734
|
+
// xRenderer.labels.template.setAll({
|
|
1735
|
+
// rotation: -45,
|
|
1736
|
+
// centerY: am5.p50,
|
|
1737
|
+
// centerX: am5.p100,
|
|
1738
|
+
// paddingRight: 5,
|
|
1739
|
+
// });
|
|
1740
|
+
|
|
1741
|
+
// const xAxis = chart.xAxes.push(
|
|
1742
|
+
// am5xy.CategoryAxis.new(root, {
|
|
1743
|
+
// categoryField: "storeName",
|
|
1744
|
+
// renderer: xRenderer,
|
|
1745
|
+
// tooltip: am5.Tooltip.new(root, { labelText: "{fullStoreName}" })
|
|
1746
|
+
// })
|
|
1747
|
+
// );
|
|
1748
|
+
|
|
1749
|
+
// const formattedData = ${JSON.stringify( data )}.map((item) => ({
|
|
1750
|
+
// fullStoreName: item.storeName,
|
|
1751
|
+
// storeName: item.storeName,
|
|
1752
|
+
// footfall: Number(item.footfall_count),
|
|
1753
|
+
// conversion: Number(item.conversion_count),
|
|
1754
|
+
// bounced: Number(item.bounced_count),
|
|
1755
|
+
// engagers: Number(item.engagers_count),
|
|
1756
|
+
// missedopportunities: Number(item.missedOpportunity_count),
|
|
1757
|
+
// }));
|
|
1758
|
+
|
|
1759
|
+
// formattedData.sort((a, b) => {
|
|
1760
|
+
// const dateA = new Date(a.storeName);
|
|
1761
|
+
// const dateB = new Date(b.storeName);
|
|
1762
|
+
// return dateA - dateB;
|
|
1763
|
+
// });
|
|
1764
|
+
|
|
1765
|
+
// xAxis.data.setAll(formattedData);
|
|
1766
|
+
|
|
1767
|
+
// const yAxis = chart.yAxes.push(
|
|
1768
|
+
// am5xy.ValueAxis.new(root, {
|
|
1769
|
+
// min: 0,
|
|
1770
|
+
// renderer: am5xy.AxisRendererY.new(root, {})
|
|
1771
|
+
// })
|
|
1772
|
+
// );
|
|
1773
|
+
|
|
1774
|
+
// yAxis.children.unshift(am5.Label.new(root, {
|
|
1775
|
+
// rotation: -90,
|
|
1776
|
+
// text: "Footfall",
|
|
1777
|
+
// y: am5.p50,
|
|
1778
|
+
// centerX: am5.p50,
|
|
1779
|
+
// fontFamily: "Arial",
|
|
1780
|
+
// fontSize: "14px",
|
|
1781
|
+
// fill: am5.color(0x000000)
|
|
1782
|
+
// }));
|
|
1783
|
+
|
|
1784
|
+
// const createColumnSeries = (name, field, color) => {
|
|
1785
|
+
// const series = chart.series.push(
|
|
1786
|
+
// am5xy.ColumnSeries.new(root, {
|
|
1787
|
+
// name: name,
|
|
1788
|
+
// xAxis: xAxis,
|
|
1789
|
+
// yAxis: yAxis,
|
|
1790
|
+
// valueYField: field,
|
|
1791
|
+
// categoryXField: "storeName",
|
|
1792
|
+
// fill: color,
|
|
1793
|
+
// stroke: color,
|
|
1794
|
+
// stacked: true,
|
|
1795
|
+
// })
|
|
1796
|
+
// );
|
|
1797
|
+
|
|
1798
|
+
// series.data.setAll(formattedData);
|
|
1799
|
+
|
|
1800
|
+
// series.bullets.push(() => {
|
|
1801
|
+
// return am5.Bullet.new(root, {
|
|
1802
|
+
// sprite: am5.Label.new(root, {
|
|
1803
|
+
// text: "{valueY}",
|
|
1804
|
+
// fill: root.interfaceColors.get("alternativeText"),
|
|
1805
|
+
// centerY: am5.p50,
|
|
1806
|
+
// centerX: am5.p50,
|
|
1807
|
+
// populateText: true,
|
|
1808
|
+
// fontSize: 12 // Reduce font size
|
|
1809
|
+
// })
|
|
1810
|
+
// });
|
|
1811
|
+
// });
|
|
1812
|
+
|
|
1813
|
+
// series.columns.template.setAll({
|
|
1814
|
+
// tooltipText: "{name}: {valueY}",
|
|
1815
|
+
// width: am5.percent(90),
|
|
1816
|
+
// tooltipY: 0,
|
|
1817
|
+
// });
|
|
1818
|
+
|
|
1819
|
+
// series.appear(1000);
|
|
1820
|
+
// return series;
|
|
1821
|
+
// };
|
|
1822
|
+
|
|
1823
|
+
// createColumnSeries("Bounced", "bounced", am5.color(0x67b7dc));
|
|
1824
|
+
// createColumnSeries("Missed Opportunity", "missedopportunities", am5.color(0x6794dc));
|
|
1825
|
+
// createColumnSeries("Conversion", "conversion", am5.color(0x6771dc));
|
|
1826
|
+
|
|
1827
|
+
// const legend = chart.children.push(
|
|
1828
|
+
// am5.Legend.new(root, {
|
|
1829
|
+
// centerX: am5.p50,
|
|
1830
|
+
// x: am5.p50
|
|
1831
|
+
// })
|
|
1832
|
+
// );
|
|
1833
|
+
|
|
1834
|
+
// legend.data.setAll(chart.series.values);
|
|
1835
|
+
|
|
1836
|
+
// chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
1837
|
+
// behavior: "none"
|
|
1838
|
+
// }));
|
|
1839
|
+
|
|
1840
|
+
// chart.appear(1000, 100);
|
|
1841
|
+
// });
|
|
1842
|
+
// </script>
|
|
1843
|
+
// </body>
|
|
1844
|
+
// </html>
|
|
1845
|
+
// `;
|
|
1846
|
+
// let weeklyChartBuffer;
|
|
1847
|
+
// try {
|
|
1848
|
+
// await page.setContent( chartHtmlContent, { waitUntil: 'domcontentloaded' } );
|
|
1849
|
+
// await page.waitForSelector( '#Footfalltrend', { visible: true } );
|
|
1850
|
+
// weeklyChartBuffer = await page.screenshot( { encoding: 'binary' } );
|
|
1851
|
+
// // await page.screenshot( { path: chartImagePath } );
|
|
1852
|
+
// // console.log( 'Screenshot saved to:', chartImagePath );
|
|
1853
|
+
// // console.log( 'Screenshot saved to:', chartImagePath );
|
|
1854
|
+
// } catch ( err ) {
|
|
1855
|
+
// console.error( 'Error generating chart screenshot:', err );
|
|
1856
|
+
// throw new Error( 'Failed to generate chart screenshot' );
|
|
1857
|
+
// } finally {
|
|
1858
|
+
// await browser.close();
|
|
1859
|
+
// }
|
|
1860
|
+
|
|
1861
|
+
// return weeklyChartBuffer;
|
|
1862
|
+
// };
|