tango-app-api-store-builder 1.0.2-alpha → 1.0.2
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/data/Bitz_Final_Store_List_28.08.25.xlsx +0 -0
- package/data/Coastline 3.0 Tango.xlsx +0 -0
- package/data/Fixture capacity.xlsx +0 -0
- package/data/JJ_OD New Launch_Tango.xlsx +0 -0
- package/data/LKST 98 - Inventory Analysis.xlsx +0 -0
- package/data/OE_Vs_NON_OE_UPDATED.xlsx +0 -0
- package/data/Sale, Non sale stores.xlsx +0 -0
- package/data/Updated IVM New Fixture Flow-v8.xlsx +0 -0
- package/data/VM_logic.xlsx +0 -0
- package/data/euro_center_stores_tentpole.xls +0 -0
- package/data/ivmLogic.json +6058 -0
- package/data/logs.json +3 -0
- package/data/missing_stores.json +3 -0
- package/data/response.json +2119 -0
- package/index.js +7 -1
- package/package.json +15 -4
- package/src/controllers/fixtureTemplate.controller.js +1767 -0
- package/src/controllers/managePlano.controller.js +1986 -0
- package/src/controllers/planoLibrary.controller.js +1487 -0
- package/src/controllers/script.controller.js +14680 -0
- package/src/controllers/storeBuilder.controller.js +7361 -23
- package/src/controllers/task.controller.js +1149 -0
- package/src/dtos/validation.dtos.js +277 -1
- package/src/routes/fixtureTemplate.routes.js +30 -0
- package/src/routes/managePlano.routes.js +29 -0
- package/src/routes/planoLibrary.routes.js +42 -0
- package/src/routes/script.routes.js +44 -0
- package/src/routes/storeBuilder.routes.js +55 -5
- package/src/routes/task.routes.js +20 -0
- package/src/service/assignService.service.js +11 -0
- package/src/service/checklist.service.js +7 -0
- package/src/service/fixtureConfig.service.js +52 -0
- package/src/service/fixtureConfigDuplicate.service.js +52 -0
- package/src/service/fixtureShelf.service.js +53 -0
- package/src/service/fixtureShelfDuplicate.service.js +53 -0
- package/src/service/planoCompliance.service.js +33 -0
- package/src/service/planoDuplicateModel.service.js +41 -0
- package/src/service/planoGlobalComment.service.js +25 -0
- package/src/service/planoLibrary.service.js +45 -0
- package/src/service/planoLibraryDuplicate.service.js +45 -0
- package/src/service/planoMapping.service.js +44 -0
- package/src/service/planoMappingDuplicate.service.js +44 -0
- package/src/service/planoProduct.service.js +42 -0
- package/src/service/planoProductDuplicate.service.js +42 -0
- package/src/service/planoQrConversionRequest.service.js +32 -0
- package/src/service/planoRevision.service.js +15 -0
- package/src/service/planoStaticData.service.js +11 -0
- package/src/service/planoTask.service.js +39 -0
- package/src/service/planoVm.service.js +49 -0
- package/src/service/planoVmDuplicate.service.js +49 -0
- package/src/service/planogram.service.js +8 -0
- package/src/service/planoproductCategory.service.js +47 -0
- package/src/service/processedTaskservice.js +29 -0
- package/src/service/processedchecklist.service.js +17 -0
- package/src/service/storeBuilder.service.js +20 -0
- package/src/service/storeBuilderDuplicate.service.js +53 -0
- package/src/service/storeFixture.service.js +83 -0
- package/src/service/storeFixtureDuplicate.service.js +69 -0
- package/src/service/task.service.js +6 -0
- package/src/service/templateLog.service.js +10 -0
- package/src/service/user.service.js +14 -0
- package/src/service/vmType.service.js +33 -0
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
import * as processedService from '../service/processedTaskservice.js';
|
|
2
|
+
import * as storeService from '../service/store.service.js';
|
|
3
|
+
import * as processedChecklistService from '../service/processedchecklist.service.js';
|
|
4
|
+
import * as userService from '../service/user.service.js';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
6
|
+
import { logger, fileUpload, signedUrl, insertOpenSearchData, sendMessageToQueue } from 'tango-app-api-middleware';
|
|
7
|
+
import * as planoTaskService from '../service/planoTask.service.js';
|
|
8
|
+
import * as planoService from '../service/planogram.service.js';
|
|
9
|
+
import * as checklistService from '../service/checklist.service.js';
|
|
10
|
+
import timeZone from 'dayjs/plugin/timezone.js';
|
|
11
|
+
import * as planoProductService from '../service/planoProduct.service.js';
|
|
12
|
+
import mongoose from 'mongoose';
|
|
13
|
+
const ObjectId = mongoose.Types.ObjectId;
|
|
14
|
+
import * as floorService from '../service/storeBuilder.service.js';
|
|
15
|
+
import * as planoStaticService from '../service/planoStaticData.service.js';
|
|
16
|
+
import * as assignService from '../service/assignService.service.js';
|
|
17
|
+
import * as taskAssignService from '../service/assignService.service.js';
|
|
18
|
+
import * as storeBuilderService from '../service/storeBuilder.service.js';
|
|
19
|
+
import * as storeFixtureService from '../service/storeFixture.service.js';
|
|
20
|
+
import * as fixtureShelfService from '../service/fixtureShelf.service.js';
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
dayjs.extend( timeZone );
|
|
24
|
+
|
|
25
|
+
async function createUser( data ) {
|
|
26
|
+
try {
|
|
27
|
+
let params = {
|
|
28
|
+
userName: data.userName,
|
|
29
|
+
email: data.email,
|
|
30
|
+
mobileNumber: data?.mobileNumber || '',
|
|
31
|
+
clientId: data.clientId,
|
|
32
|
+
role: 'user',
|
|
33
|
+
password: '5dqFKAJj29PsV6P+kL+3Dw==',
|
|
34
|
+
isActive: true,
|
|
35
|
+
userType: 'client',
|
|
36
|
+
rolespermission: [
|
|
37
|
+
{
|
|
38
|
+
featureName: 'Global',
|
|
39
|
+
modules: [
|
|
40
|
+
{
|
|
41
|
+
name: 'Store',
|
|
42
|
+
isAdd: false,
|
|
43
|
+
isEdit: false,
|
|
44
|
+
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'User',
|
|
48
|
+
isAdd: false,
|
|
49
|
+
isEdit: false,
|
|
50
|
+
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Camera',
|
|
54
|
+
isAdd: false,
|
|
55
|
+
isEdit: false,
|
|
56
|
+
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Configuration',
|
|
60
|
+
isAdd: false,
|
|
61
|
+
isEdit: false,
|
|
62
|
+
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Subscription',
|
|
66
|
+
isAdd: false,
|
|
67
|
+
isEdit: false,
|
|
68
|
+
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Billing',
|
|
72
|
+
isAdd: false,
|
|
73
|
+
isEdit: false,
|
|
74
|
+
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
featurName: 'TangoEye',
|
|
80
|
+
modules: [
|
|
81
|
+
{
|
|
82
|
+
name: 'ZoneTag',
|
|
83
|
+
isAdd: false,
|
|
84
|
+
isEdit: false,
|
|
85
|
+
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
featurName: 'TangoTrax',
|
|
91
|
+
modules: [
|
|
92
|
+
{
|
|
93
|
+
name: 'checklist',
|
|
94
|
+
isAdd: false,
|
|
95
|
+
isEdit: false,
|
|
96
|
+
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Task',
|
|
100
|
+
isAdd: false,
|
|
101
|
+
isEdit: false,
|
|
102
|
+
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
let response = await userService.create( params );
|
|
109
|
+
return response;
|
|
110
|
+
} catch ( e ) {
|
|
111
|
+
logger.error( 'createUser =>', e );
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function createTask( req, res ) {
|
|
117
|
+
try {
|
|
118
|
+
if ( req.body?.floorId ) {
|
|
119
|
+
await storeBuilderService.updateOne( { _id: new mongoose.Types.ObjectId( req.body?.floorId ) }, { isEdited: false } );
|
|
120
|
+
}
|
|
121
|
+
let scheduleEndTime = '11:59 PM';
|
|
122
|
+
if ( req.body?.redo ) {
|
|
123
|
+
if ( !req.body.taskId ) {
|
|
124
|
+
return res.sendError( 'Task id is required', 400 );
|
|
125
|
+
}
|
|
126
|
+
let taskInfo = await processedService.findOne( { _id: req.body.taskId } );
|
|
127
|
+
if ( !taskInfo ) {
|
|
128
|
+
return res.sendError( 'No data found', 204 );
|
|
129
|
+
}
|
|
130
|
+
let payload = {
|
|
131
|
+
...taskInfo.toObject(),
|
|
132
|
+
...{
|
|
133
|
+
checklistStatus: 'open',
|
|
134
|
+
redoStatus: true,
|
|
135
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
136
|
+
scheduleStartTime_iso: dayjs.utc( '12:00 AM', 'hh:mm A' ).format(),
|
|
137
|
+
scheduleEndTime_iso: dayjs.utc( scheduleEndTime, 'hh:mm A' ).format(),
|
|
138
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
139
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
140
|
+
refTaskId: req.body.taskId,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
delete payload._id;
|
|
145
|
+
delete payload.createdAt;
|
|
146
|
+
delete payload.updatedAt;
|
|
147
|
+
let response;
|
|
148
|
+
if ( [ 'merchRollout', 'vmRollout' ].includes( taskInfo?.planoType ) ) {
|
|
149
|
+
response = await processedService.create( payload );
|
|
150
|
+
} else {
|
|
151
|
+
await processedService.updateOne( { _id: req.body.taskId }, payload );
|
|
152
|
+
await planoTaskService.updateMany( { taskId: req.body.taskId, status: 'complete' }, { taskType: 'initial' } );
|
|
153
|
+
response = { _id: req.body.taskId };
|
|
154
|
+
}
|
|
155
|
+
return res.sendSuccess( { message: 'Task redo triggered successfully', taskId: response?._id } );
|
|
156
|
+
} else {
|
|
157
|
+
if ( !req.body?.checkListName ) {
|
|
158
|
+
return res.sendError( 'ChecklistName is required', 400 );
|
|
159
|
+
}
|
|
160
|
+
// let taskDetails = await taskService.find( { isPlano: true, ...( req.body.checkListName )? { checkListName: req.body.checkListName } : {} } );
|
|
161
|
+
// if ( !taskDetails.length ) {
|
|
162
|
+
// return res.sendError( 'No data found', 204 );
|
|
163
|
+
// }
|
|
164
|
+
let response;
|
|
165
|
+
let userDetails;
|
|
166
|
+
let storeList;
|
|
167
|
+
let endDate;
|
|
168
|
+
let taskConfig = await planoStaticService.findOne( { clientId: req.body.clientId, type: 'task' } );
|
|
169
|
+
req.body.days = req.body?.days || 7;
|
|
170
|
+
if ( taskConfig && !req.body?.endTime ) {
|
|
171
|
+
scheduleEndTime = taskConfig?.dueTime || '11:59 PM';
|
|
172
|
+
req.body.days = taskConfig?.dueDay || 1;
|
|
173
|
+
req.body.geoFencing = taskConfig?.allowedStoreLocation || false;
|
|
174
|
+
}
|
|
175
|
+
if ( req.body?.endTime ) {
|
|
176
|
+
scheduleEndTime = req.body.endTime;
|
|
177
|
+
}
|
|
178
|
+
let days = req.body.days - 1;
|
|
179
|
+
endDate = dayjs().add( days, 'day' ).format( 'YYYY-MM-DD' );
|
|
180
|
+
endDate = `${endDate} ${scheduleEndTime}`;
|
|
181
|
+
if ( !req.body?.stores?.length ) {
|
|
182
|
+
let assignQuery = [
|
|
183
|
+
{
|
|
184
|
+
$addFields: {
|
|
185
|
+
store: { $toLower: '$storeName' },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
$match: {
|
|
190
|
+
client_id: req.body.clientId,
|
|
191
|
+
store: req.body.store.toLowerCase(),
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
$sort: {
|
|
196
|
+
_id: -1,
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
$limit: 1,
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
let getUserDetails = await assignService.aggregate( assignQuery );
|
|
204
|
+
if ( !getUserDetails.length ) {
|
|
205
|
+
getUserDetails = await taskAssignService.taskAggregate( assignQuery );
|
|
206
|
+
if ( !getUserDetails.length ) {
|
|
207
|
+
let storeQuery = [
|
|
208
|
+
{
|
|
209
|
+
$addFields: {
|
|
210
|
+
store: { $toLower: '$storeName' },
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
$match: {
|
|
215
|
+
clientId: req.body.clientId,
|
|
216
|
+
store: req.body.store.toLowerCase(),
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
$project: {
|
|
221
|
+
spocDetails: 1,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
let getEmail = await storeService.aggregate( storeQuery );
|
|
226
|
+
console.log( getEmail );
|
|
227
|
+
if ( getEmail.length ) {
|
|
228
|
+
getUserDetails = [ { storeName: req.body.store, userEmail: getEmail?.[0]?.spocDetails?.[0]?.email } ];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
req.body.stores = [
|
|
233
|
+
{
|
|
234
|
+
store: getUserDetails[0].storeName,
|
|
235
|
+
email: req.body?.email ? req.body.email : getUserDetails[0].userEmail,
|
|
236
|
+
},
|
|
237
|
+
];
|
|
238
|
+
}
|
|
239
|
+
storeList = req.body.stores.map( ( ele ) => ele.store.toLowerCase() );
|
|
240
|
+
let userEmailList = [ ...new Set( req.body.stores.map( ( ele ) => ele.email ) ) ];
|
|
241
|
+
for ( let mail of userEmailList ) {
|
|
242
|
+
let query = [
|
|
243
|
+
{
|
|
244
|
+
$addFields: {
|
|
245
|
+
emailLower: { $toLower: '$email' },
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
$match: {
|
|
250
|
+
clientId: req.body.clientId,
|
|
251
|
+
emailLower: mail.toLowerCase(),
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
];
|
|
255
|
+
userDetails = await userService.aggregate( query );
|
|
256
|
+
if ( !userDetails.length ) {
|
|
257
|
+
let userData = {
|
|
258
|
+
clientId: req.body.clientId,
|
|
259
|
+
mobileNumber: '',
|
|
260
|
+
email: mail,
|
|
261
|
+
userName: mail.split( '@' )[0],
|
|
262
|
+
};
|
|
263
|
+
await createUser( userData );
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// await Promise.all( taskDetails.map( async ( task ) => {
|
|
267
|
+
let taskId = new ObjectId();
|
|
268
|
+
let [ first ] = req.body?.checkListName.split( ' ' );
|
|
269
|
+
first = first.toLowerCase();
|
|
270
|
+
if ( req.body?.checkListName.toLowerCase().includes( 'rollout' ) ) {
|
|
271
|
+
if ( req.body.checkListName.toLowerCase().includes( 'visual' ) ) {
|
|
272
|
+
first = 'vmRollout';
|
|
273
|
+
} else {
|
|
274
|
+
first = 'merchRollout';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if ( req.body?.checkListName.toLowerCase().includes( 'measurement' ) ) {
|
|
278
|
+
first = 'fixtureMeasurement';
|
|
279
|
+
}
|
|
280
|
+
let startDate = dayjs().format( 'YYYY-MM-DD hh:mm A' );
|
|
281
|
+
let data = {
|
|
282
|
+
client_id: req.body.clientId,
|
|
283
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
284
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
285
|
+
sourceCheckList_id: taskId,
|
|
286
|
+
checkListName: req.body.checkListName,
|
|
287
|
+
checkListId: taskId,
|
|
288
|
+
scheduleStartTime: dayjs().format( 'hh:mm A' ),
|
|
289
|
+
scheduleEndTime: scheduleEndTime,
|
|
290
|
+
scheduleStartTime_iso: dayjs.utc( startDate, 'YYYY-MM-DD hh:mm A' ).format(),
|
|
291
|
+
scheduleEndTime_iso: dayjs.utc( endDate, 'YYYY-MM-DD hh:mm A' ).format(),
|
|
292
|
+
allowedOverTime: false,
|
|
293
|
+
allowedStoreLocation: req.body?.geoFencing || false,
|
|
294
|
+
createdBy: req?.user?._id,
|
|
295
|
+
createdByName: req?.user?.userName,
|
|
296
|
+
questionAnswers: [],
|
|
297
|
+
isdeleted: false,
|
|
298
|
+
questionCount: 0,
|
|
299
|
+
storeCount: 0,
|
|
300
|
+
locationCount: 0,
|
|
301
|
+
checkListType: 'task',
|
|
302
|
+
country: '',
|
|
303
|
+
store_id: '',
|
|
304
|
+
storeName: '',
|
|
305
|
+
userId: '',
|
|
306
|
+
userName: '',
|
|
307
|
+
userEmail: '',
|
|
308
|
+
checklistStatus: 'open',
|
|
309
|
+
timeFlagStatus: true,
|
|
310
|
+
timeFlag: 0,
|
|
311
|
+
questionFlag: 0,
|
|
312
|
+
mobileDetectionFlag: 0,
|
|
313
|
+
storeOpenCloseFlag: 0,
|
|
314
|
+
reinitiateStatus: false,
|
|
315
|
+
markasread: false,
|
|
316
|
+
uniformDetectionFlag: 0,
|
|
317
|
+
scheduleRepeatedType: 'daily',
|
|
318
|
+
approvalStatus: false,
|
|
319
|
+
approvalEnable: false,
|
|
320
|
+
redoStatus: false,
|
|
321
|
+
isPlano: true,
|
|
322
|
+
planoType: first,
|
|
323
|
+
};
|
|
324
|
+
let query = [
|
|
325
|
+
{
|
|
326
|
+
$addFields: {
|
|
327
|
+
store: { $toLower: '$storeName' },
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
$match: {
|
|
332
|
+
clientId: req.body.clientId,
|
|
333
|
+
store: { $in: storeList },
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
let storeDetails = await storeService.aggregate( query );
|
|
339
|
+
await Promise.all( storeDetails.map( async ( store ) => {
|
|
340
|
+
let getUserEmail = req.body.stores.find( ( ele ) => ele.store.toLowerCase() == store.storeName.toLowerCase() );
|
|
341
|
+
let planoDetails = await planoService.findOne( { storeName: store.storeName } );
|
|
342
|
+
if ( planoDetails ) {
|
|
343
|
+
const [ floorDetails, floorCount ] = await Promise.all( [
|
|
344
|
+
await floorService.find( { planoId: planoDetails._id, ...( req.body?.floorId ) ? { _id: req.body?.floorId } : {} }, { _id: 1, floorName: 1 } ),
|
|
345
|
+
await floorService.count( { planoId: planoDetails._id } ),
|
|
346
|
+
] );
|
|
347
|
+
for ( let i = 0; i < floorDetails.length; i++ ) {
|
|
348
|
+
if ( getUserEmail ) {
|
|
349
|
+
let query = [
|
|
350
|
+
{
|
|
351
|
+
$addFields: {
|
|
352
|
+
emailLower: { $toLower: '$email' },
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
$match: {
|
|
357
|
+
clientId: req.body.clientId,
|
|
358
|
+
emailLower: getUserEmail.email.toLowerCase(),
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
];
|
|
362
|
+
userDetails = await userService.aggregate( query );
|
|
363
|
+
userDetails = userDetails[0];
|
|
364
|
+
}
|
|
365
|
+
let taskData = { ...data };
|
|
366
|
+
if ( floorCount > 1 ) {
|
|
367
|
+
taskData.checkListName = taskData.checkListName + ' - ' + floorDetails[i].floorName;
|
|
368
|
+
}
|
|
369
|
+
taskData.floorId = floorDetails[i]._id;
|
|
370
|
+
taskData.store_id = store.storeId;
|
|
371
|
+
taskData.storeName = store.storeName;
|
|
372
|
+
taskData.userId = userDetails._id;
|
|
373
|
+
taskData.userName = userDetails.userName;
|
|
374
|
+
taskData.userEmail = userDetails.email;
|
|
375
|
+
taskData.planoId = planoDetails?._id;
|
|
376
|
+
if ( !req.body?.checkListName.toLowerCase().includes( 'rollout' ) ) {
|
|
377
|
+
let planoProgress = req.body.checkListName == 'Fixture Verification' ? 50 : req.body.checkListName == 'VM Verification' ? 75 : 25;
|
|
378
|
+
if ( req.body?.checkListName && req.body.checkListName == 'Layout Verification' ) {
|
|
379
|
+
await planoTaskService.deleteMany( { planoId: planoDetails?._id, floorId: taskData?.floorId } );
|
|
380
|
+
planoProgress = 25;
|
|
381
|
+
await processedService.deleteMany( { planoId: planoDetails?._id, floorId: taskData?.floorId, isPlano: true } );
|
|
382
|
+
} else {
|
|
383
|
+
let type = req.body.checkListName == 'Fixture Verification' ? 'fixture' : 'vm';
|
|
384
|
+
await planoTaskService.deleteMany( { planoId: planoDetails?._id, floorId: taskData?.floorId, type: type } );
|
|
385
|
+
await processedService.deleteMany( { planoId: planoDetails?._id, floorId: taskData?.floorId, isPlano: true, type: type } );
|
|
386
|
+
}
|
|
387
|
+
await floorService.updateOne( { _id: taskData?.floorId }, { planoProgress } );
|
|
388
|
+
}
|
|
389
|
+
// for ( let j=0; j<req.body.days; j++ ) {
|
|
390
|
+
// let currDate = dayjs().add( j, 'days' );
|
|
391
|
+
// let time = j ? '12:00 AM' : currDate.format( 'hh:mm A' );
|
|
392
|
+
let insertData = { ...taskData };
|
|
393
|
+
response = await processedService.updateOne( { store_id: insertData.store_id, userEmail: insertData.userEmail, planoId: insertData.planoId, planoType: taskData.planoType, ...( taskData?.floorId ) ? { floorId: taskData.floorId }:{}, ...( [ 'merchRollout', 'vmRollout' ].includes( taskData.planoType ) && { sourceCheckList_id: taskData.sourceCheckList_id } ) }, insertData );
|
|
394
|
+
// }
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} ) );
|
|
398
|
+
// } ) );
|
|
399
|
+
return res.sendSuccess( { message: 'Task created successfully', taskId: response?.upsertedId } );
|
|
400
|
+
}
|
|
401
|
+
} catch ( e ) {
|
|
402
|
+
console.log( e );
|
|
403
|
+
logger.error( { functionName: 'createTask', error: e } );
|
|
404
|
+
return res.sendError( e, 500 );
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export async function createPlano( req, res ) {
|
|
409
|
+
try {
|
|
410
|
+
let checklistDetails = await checklistService.find( { isPlano: true, client_id: req.body.clientId } );
|
|
411
|
+
let storeList = req.body.stores.map( ( ele ) => ele.store.toLowerCase() );
|
|
412
|
+
let userDetails;
|
|
413
|
+
if ( !checklistDetails.length ) {
|
|
414
|
+
return res.sendError( 'No data found', 204 );
|
|
415
|
+
}
|
|
416
|
+
await Promise.all( checklistDetails.map( async ( checklist ) => {
|
|
417
|
+
let data = {
|
|
418
|
+
client_id: req.body.clientId,
|
|
419
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
420
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
421
|
+
sourceCheckList_id: checklist._id,
|
|
422
|
+
checkListName: checklist.checkListName,
|
|
423
|
+
checkListId: checklist._id,
|
|
424
|
+
scheduleStartTime: '08:00 AM',
|
|
425
|
+
scheduleEndTime: '11:59 PM',
|
|
426
|
+
scheduleStartTime_iso: dayjs.utc( '08:00 AM', 'hh:mm A' ).format(),
|
|
427
|
+
scheduleEndTime_iso: dayjs.utc( '11:59 PM', 'hh:mm A' ).format(),
|
|
428
|
+
allowedOverTime: false,
|
|
429
|
+
allowedStoreLocation: false,
|
|
430
|
+
createdBy: checklist.createdBy,
|
|
431
|
+
createdByName: checklist.createdByName,
|
|
432
|
+
questionAnswers: [],
|
|
433
|
+
isdeleted: false,
|
|
434
|
+
questionCount: 0,
|
|
435
|
+
storeCount: 0,
|
|
436
|
+
locationCount: 0,
|
|
437
|
+
checkListType: 'custom',
|
|
438
|
+
country: '',
|
|
439
|
+
store_id: '',
|
|
440
|
+
storeName: '',
|
|
441
|
+
userId: '',
|
|
442
|
+
userName: '',
|
|
443
|
+
userEmail: '',
|
|
444
|
+
checklistStatus: 'open',
|
|
445
|
+
timeFlagStatus: true,
|
|
446
|
+
timeFlag: 0,
|
|
447
|
+
questionFlag: 0,
|
|
448
|
+
mobileDetectionFlag: 0,
|
|
449
|
+
storeOpenCloseFlag: 0,
|
|
450
|
+
reinitiateStatus: false,
|
|
451
|
+
markasread: false,
|
|
452
|
+
uniformDetectionFlag: 0,
|
|
453
|
+
scheduleRepeatedType: 'daily',
|
|
454
|
+
approvalStatus: false,
|
|
455
|
+
approvalEnable: false,
|
|
456
|
+
redoStatus: false,
|
|
457
|
+
isPlano: true,
|
|
458
|
+
planoType: checklist.checkListName == 'Planogram QR' ? 'qr' : 'rfid',
|
|
459
|
+
};
|
|
460
|
+
let query = [
|
|
461
|
+
{
|
|
462
|
+
$addFields: {
|
|
463
|
+
store: { $toLower: '$storeName' },
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
$match: {
|
|
468
|
+
clientId: req.body.clientId,
|
|
469
|
+
store: { $in: storeList },
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
];
|
|
473
|
+
|
|
474
|
+
let storeDetails = await storeService.aggregate( query );
|
|
475
|
+
await Promise.all( storeDetails.map( async ( store ) => {
|
|
476
|
+
let getUserEmail = req.body.stores.find( ( ele ) => ele.store.toLowerCase() == store.storeName.toLowerCase() );
|
|
477
|
+
let planoDetails = await planoService.findOne( { storeId: store.storeId } );
|
|
478
|
+
if ( getUserEmail ) {
|
|
479
|
+
let query = [
|
|
480
|
+
{
|
|
481
|
+
$addFields: {
|
|
482
|
+
emailLower: { $toLower: '$email' },
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
$match: {
|
|
487
|
+
clientId: req.body.clientId,
|
|
488
|
+
email: getUserEmail.email,
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
];
|
|
492
|
+
userDetails = await userService.aggregate( query );
|
|
493
|
+
if ( !userDetails.length ) {
|
|
494
|
+
let userData = {
|
|
495
|
+
clientId: req.body.clientId,
|
|
496
|
+
mobileNumber: '',
|
|
497
|
+
email: getUserEmail.email,
|
|
498
|
+
userName: getUserEmail.email.split( '@' )[0],
|
|
499
|
+
};
|
|
500
|
+
userDetails = await createUser( userData );
|
|
501
|
+
} else {
|
|
502
|
+
userDetails = userDetails[0];
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
let checklistData = { ...data };
|
|
506
|
+
checklistData.store_id = store.storeId;
|
|
507
|
+
checklistData.storeName = store.storeName;
|
|
508
|
+
checklistData.userId = userDetails._id;
|
|
509
|
+
checklistData.userName = userDetails.userName;
|
|
510
|
+
checklistData.userEmail = userDetails.email;
|
|
511
|
+
checklistData.planoId = planoDetails?._id;
|
|
512
|
+
for ( let i = 0; i < req.body.days; i++ ) {
|
|
513
|
+
let currDate = dayjs().add( i, 'day' );
|
|
514
|
+
let insertData = { ...checklistData, date_string: currDate.format( 'YYYY-MM-DD' ), date_iso: new Date( currDate.format( 'YYYY-MM-DD' ) ), scheduleStartTime_iso: dayjs.utc( `${currDate.format( 'YYYY-MM-DD' )} 08:00 AM`, 'YYYY-MM-DD hh:mm A' ).format(), scheduleEndTime_iso: dayjs.utc( `${currDate.format( 'YYYY-MM-DD' )} 11:59 PM`, 'YYYY-MM-DD hh:mm A' ).format() };
|
|
515
|
+
let response = await processedChecklistService.updateOne( { date_string: currDate.format( 'YYYY-MM-DD' ), store_id: insertData.store_id, userEmail: insertData.userEmail, planoId: insertData.planoId, sourceCheckList_id: checklist._id }, insertData );
|
|
516
|
+
}
|
|
517
|
+
} ) );
|
|
518
|
+
} ) );
|
|
519
|
+
|
|
520
|
+
return res.sendSuccess( 'Checklist created successfully' );
|
|
521
|
+
} catch ( e ) {
|
|
522
|
+
logger.error( { functionName: 'createTask', error: e } );
|
|
523
|
+
return res.sendError( e, 500 );
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export async function getTaskDetails( req, res ) {
|
|
528
|
+
try {
|
|
529
|
+
if ( !req.query.storeId ) {
|
|
530
|
+
return res.sendError( 'Store id is required', 400 );
|
|
531
|
+
}
|
|
532
|
+
// let date = req.query?.date || dayjs().format( 'YYYY-MM-DD' );
|
|
533
|
+
// let getDetails = await processedService.find( { store_id: req.query.storeId, date_string: date, isPlano: true, checklistStatus: { $ne: 'submit' }, userId: req.user._id }, { checkListName: 1, taskType: '$planoType', checklistStatus: 1 } );
|
|
534
|
+
return res.sendSuccess( [] );
|
|
535
|
+
} catch ( e ) {
|
|
536
|
+
logger.error( { functionName: 'getTaskDetails', error: e } );
|
|
537
|
+
return res.sendError( e, 500 );
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export async function uploadImage( req, res ) {
|
|
542
|
+
try {
|
|
543
|
+
if ( !req.body.taskId ) {
|
|
544
|
+
return res.sendError( 'task id is required', 400 );
|
|
545
|
+
}
|
|
546
|
+
if ( !req.body.qno ) {
|
|
547
|
+
return res.sendError( 'Qno is required', 400 );
|
|
548
|
+
}
|
|
549
|
+
if ( !req.files.file ) {
|
|
550
|
+
return res.sendError( 'Please upload a file', 400 );
|
|
551
|
+
}
|
|
552
|
+
let params = {
|
|
553
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
554
|
+
Key: `${req.body.taskId}/${req.body.qno}/${Date.now()}/`,
|
|
555
|
+
fileName: req.files.file.name,
|
|
556
|
+
ContentType: req.files.file.mimeType && req.files.file.mimeType != undefined ? req.files.file.mimeType : req.files.file.mimetype,
|
|
557
|
+
body: req.files.file.data,
|
|
558
|
+
};
|
|
559
|
+
let fileRes = await fileUpload( params );
|
|
560
|
+
if ( fileRes.Key ) {
|
|
561
|
+
params = {
|
|
562
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
563
|
+
file_path: fileRes.Key,
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
let imageUrl = await signedUrl( params );
|
|
567
|
+
return res.sendSuccess( { url: imageUrl, path: fileRes.Key } );
|
|
568
|
+
}
|
|
569
|
+
return res.sendError( 'Something went wrong', 500 );
|
|
570
|
+
} catch ( e ) {
|
|
571
|
+
logger.error( { functionName: 'uploadImage', error: e } );
|
|
572
|
+
return res.sendError( e, 500 );
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export async function updateStatus( req, res ) {
|
|
577
|
+
try {
|
|
578
|
+
if ( !req.body.taskId ) {
|
|
579
|
+
return res.sendError( 'No data found', 204 );
|
|
580
|
+
}
|
|
581
|
+
if ( !req.body.status ) {
|
|
582
|
+
return res.sendError( 'Status is required', 400 );
|
|
583
|
+
}
|
|
584
|
+
let taskDetails = await processedService.findOne( { _id: req.body.taskId } );
|
|
585
|
+
if ( !taskDetails ) {
|
|
586
|
+
return res.sendError( 'No data found', 204 );
|
|
587
|
+
}
|
|
588
|
+
let storeTimeZone = await storeService.findOne( { storeName: { $regex: taskDetails.storeName, $options: 'i' }, clientId: taskDetails.client_id }, { 'storeProfile.timeZone': 1 } );
|
|
589
|
+
let currentDateTime;
|
|
590
|
+
if ( storeTimeZone?.storeProfile?.timeZone ) {
|
|
591
|
+
currentDateTime = dayjs().tz( storeTimeZone?.storeProfile?.timeZone );
|
|
592
|
+
} else {
|
|
593
|
+
currentDateTime = requestData?.currentTime ? dayjs( requestData.currentTime, 'HH:mm:ss' ) : dayjs();
|
|
594
|
+
}
|
|
595
|
+
let timeString = currentDateTime.format( 'hh:mm A, DD MMM YYYY' );
|
|
596
|
+
let comments = {
|
|
597
|
+
userId: req.user._id,
|
|
598
|
+
userName: req.user.Name,
|
|
599
|
+
email: req.user.email,
|
|
600
|
+
comment: req.body.comments,
|
|
601
|
+
};
|
|
602
|
+
// if ( req.body.status == 'inprogress' ) {
|
|
603
|
+
// await processedService.updateOne( { planoId: taskDetails.planoId, userEmail: taskDetails.userEmail, store_id: taskDetails.store_id, ...( taskDetails?.floorId ) ? { floorId: taskDetails.floorId } : {}, date_iso: { $gt: new Date( dayjs().format( 'YYYY-MM-DD' ) ) } }, { checklistStatus: 'inprogress', startTime_string: timeString } );
|
|
604
|
+
// }
|
|
605
|
+
await processedService.updateOne( { _id: req.body.taskId }, { checklistStatus: req.body.status, ...( req.body.status == 'inprogress' ) ? { startTime_string: timeString } : { submitTime_string: timeString }, comments: { $push: comments } } );
|
|
606
|
+
// if ( req.body.status == 'submit' ) {
|
|
607
|
+
// await processedService.deleteMany( { planoId: taskDetails.planoId, userEmail: taskDetails.userEmail, store_id: taskDetails.store_id, ...( taskDetails?.floorId ) ? { floorId: taskDetails.floorId } : {}, date_iso: { $gt: new Date( dayjs().format( 'YYYY-MM-DD' ) ) } } );
|
|
608
|
+
// }
|
|
609
|
+
let vmTask = await planoTaskService.find(
|
|
610
|
+
{
|
|
611
|
+
planoId: new mongoose.Types.ObjectId( taskDetails.planoId ),
|
|
612
|
+
floorId: new mongoose.Types.ObjectId( taskDetails.floorId ),
|
|
613
|
+
type: 'vm',
|
|
614
|
+
},
|
|
615
|
+
|
|
616
|
+
);
|
|
617
|
+
if ( vmTask.length > 0 ) {
|
|
618
|
+
let allTaskDone = vmTask.filter( ( data ) => data.status === 'incomplete' );
|
|
619
|
+
if ( allTaskDone.length === 0 ) {
|
|
620
|
+
await floorService.updateOne( { _id: new mongoose.Types.ObjectId( taskDetails.floorId ) }, { planoProgress: 100 } );
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// if ( req.body.status == 'submit' && [ 'merchRollout', 'vmRollout' ].includes( taskDetails.planoType ) ) {
|
|
625
|
+
// let merchVmTaskDetails = await planoTaskService.find(
|
|
626
|
+
// {
|
|
627
|
+
// planoId: new mongoose.Types.ObjectId( taskDetails.planoId ),
|
|
628
|
+
// floorId: new mongoose.Types.ObjectId( taskDetails.floorId ),
|
|
629
|
+
// type: taskDetails.planoType,
|
|
630
|
+
// taskId: new mongoose.Types.ObjectId( req.body.taskId ),
|
|
631
|
+
// status: 'complete',
|
|
632
|
+
// },
|
|
633
|
+
// { fixtureId: 1 },
|
|
634
|
+
// );
|
|
635
|
+
// let query = taskDetails.planoType == 'merchRollout' ? { isMerchEdited: false } : { isVmEdited: false };
|
|
636
|
+
// await storeFixtureService.updateMany( { _id: { $in: merchVmTaskDetails?.map( ( ele ) => ele.fixtureId ) } }, query );
|
|
637
|
+
// }
|
|
638
|
+
return res.sendSuccess( 'Task status updated successfully' );
|
|
639
|
+
} catch ( e ) {
|
|
640
|
+
logger.error( { functionName: 'storeLayout', error: e } );
|
|
641
|
+
return res.sendError( e, 500 );
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export async function updateAnswers( req, res ) {
|
|
646
|
+
try {
|
|
647
|
+
req.body.answers.forEach( ( ans ) => {
|
|
648
|
+
if ( ans?.correctedFixture?.length ) {
|
|
649
|
+
ans.correctedFixture.forEach( ( fixture ) => {
|
|
650
|
+
if ( fixture.image ) {
|
|
651
|
+
fixture.image = fixture.image.split( '.com/' )[1].split( '?' )[0];
|
|
652
|
+
fixture.image = decodeURIComponent( fixture.image );
|
|
653
|
+
}
|
|
654
|
+
if ( fixture.video ) {
|
|
655
|
+
fixture.video = fixture.video.split( '.com/' )[1].split( '?' )[0];
|
|
656
|
+
fixture.video = decodeURIComponent( fixture.video );
|
|
657
|
+
}
|
|
658
|
+
} );
|
|
659
|
+
}
|
|
660
|
+
if ( ans.image ) {
|
|
661
|
+
ans.image = ans.image.split( '.com/' )[1].split( '?' )[0];
|
|
662
|
+
ans.image = decodeURIComponent( ans.image );
|
|
663
|
+
}
|
|
664
|
+
if ( ans.video ) {
|
|
665
|
+
ans.video = ans.video.split( '.com/' )[1].split( '?' )[0];
|
|
666
|
+
ans.video = decodeURIComponent( ans.video );
|
|
667
|
+
}
|
|
668
|
+
if ( ans?.newVms?.length ) {
|
|
669
|
+
ans.newVms.forEach( ( vms ) => {
|
|
670
|
+
if ( vms?.imageUrl ) {
|
|
671
|
+
vms.imageUrl = vms.imageUrl.split( '.com/' )[1].split( '?' )[0];
|
|
672
|
+
vms.imageUrl = decodeURIComponent( vms.imageUrl );
|
|
673
|
+
}
|
|
674
|
+
if ( vms?.video ) {
|
|
675
|
+
vms.video = vms.video.split( '.com/' )[1].split( '?' )[0];
|
|
676
|
+
vms.video = decodeURIComponent( vms.video );
|
|
677
|
+
}
|
|
678
|
+
} );
|
|
679
|
+
}
|
|
680
|
+
} );
|
|
681
|
+
|
|
682
|
+
let taskDetails = await processedService.findOne( {
|
|
683
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ), userId: req.user._id, isPlano: true,
|
|
684
|
+
planoType: req.body.type, planoId: new mongoose.Types.ObjectId( req.body.planoId ), floorId: new mongoose.Types.ObjectId( req.body.floorId ),
|
|
685
|
+
} );
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
let data = {
|
|
689
|
+
fixtureId: req.body.fixtureId,
|
|
690
|
+
answers: req.body.answers,
|
|
691
|
+
status: req.body.answers?.find( ( ans ) => typeof ans.value == 'boolean' && ans?.value == false ) ? 'incomplete' : 'complete',
|
|
692
|
+
planoId: req.body.planoId,
|
|
693
|
+
floorId: req.body.floorId,
|
|
694
|
+
type: req.body.type,
|
|
695
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
696
|
+
taskId: taskDetails?._id,
|
|
697
|
+
storeName: taskDetails?.storeName,
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
await planoTaskService.updateOne( { planoId: req.body.planoId, floorId: req.body.floorId, fixtureId: req.body.fixtureId, type: req.body.type, date_string: dayjs().format( 'YYYY-MM-DD' ), ...( taskDetails?._id ) ? { taskId: taskDetails?._id } : {} }, data );
|
|
701
|
+
return res.sendSuccess( 'Fixture details updated successfully' );
|
|
702
|
+
} catch ( e ) {
|
|
703
|
+
logger.error( { functionName: 'updateAnswers', error: e } );
|
|
704
|
+
return res.sendError( e, 500 );
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export async function updateAnswersv2( req, res ) {
|
|
709
|
+
try {
|
|
710
|
+
let taskDetails = await processedService.findOne( { _id: new mongoose.Types.ObjectId( req.body.taskId ) } );
|
|
711
|
+
if ( !taskDetails ) {
|
|
712
|
+
return res.sendError( 'No data found', 204 );
|
|
713
|
+
}
|
|
714
|
+
let data = {
|
|
715
|
+
fixtureId: req.body.fixtureId,
|
|
716
|
+
answers: req.body.answers,
|
|
717
|
+
status: req.body.status,
|
|
718
|
+
planoId: req.body.planoId,
|
|
719
|
+
floorId: req.body.floorId,
|
|
720
|
+
type: req.body.type,
|
|
721
|
+
date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ),
|
|
722
|
+
taskId: req.body.taskId,
|
|
723
|
+
taskType: req.body.taskType,
|
|
724
|
+
storeName: req.body?.storeName,
|
|
725
|
+
storeId: req.body?.storeId,
|
|
726
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
727
|
+
approvalStatus: 'pending',
|
|
728
|
+
};
|
|
729
|
+
if ( req.body.type === 'layout' ) {
|
|
730
|
+
await planoTaskService.updateOne( { planoId: req.body.planoId, taskType: req.body.taskType, floorId: req.body.floorId, fixtureId: req.body.fixtureId, type: req.body.type, ...( taskDetails?._id ) ? { taskId: taskDetails?._id } : {} }, data );
|
|
731
|
+
} else {
|
|
732
|
+
await planoTaskService.updateOne( { planoId: req.body.planoId, floorId: req.body.floorId, fixtureId: req.body.fixtureId, type: req.body.type, ...( taskDetails?._id ) ? { taskId: taskDetails?._id } : {} }, data );
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
await insertOpenSearchData( JSON.parse( process.env.OPENSEARCH ).planotaskcompliances, data );
|
|
736
|
+
if ( req.body.type === 'layout' ) {
|
|
737
|
+
let sqsData = {
|
|
738
|
+
bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
739
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
740
|
+
storeName: data?.storeName,
|
|
741
|
+
videoPath: data?.answers[0]?.video,
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
const sqs = JSON.parse( process.env.SQS );
|
|
745
|
+
await sendMessageToQueue( `${sqs.url}${sqs.storeBuilder}`, JSON.stringify( sqsData ) );
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if ( req.body.type === 'fixture' ) {
|
|
749
|
+
let fixtureData = await storeFixtureService.findOne( { _id: new mongoose.Types.ObjectId( req.body.fixtureId ) } );
|
|
750
|
+
|
|
751
|
+
if ( fixtureData ) {
|
|
752
|
+
fixtureData = fixtureData?.toObject();
|
|
753
|
+
|
|
754
|
+
let fixtureShelves = await fixtureShelfService.find( { fixtureId: fixtureData._id } );
|
|
755
|
+
|
|
756
|
+
if ( fixtureShelves.length ) {
|
|
757
|
+
fixtureShelves = fixtureShelves.map( ( shelf ) => shelf?.toObject() );
|
|
758
|
+
|
|
759
|
+
fixtureData.shelfConfig = fixtureShelves;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
let sqsData = {
|
|
764
|
+
bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
765
|
+
date_string: dayjs().format( 'YYYY-MM-DD' ),
|
|
766
|
+
storeName: data?.storeName,
|
|
767
|
+
imagePath: data?.answers[0]?.image,
|
|
768
|
+
fixtureId: req.body.fixtureId,
|
|
769
|
+
fixtureData: fixtureData,
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
const sqs = JSON.parse( process.env.SQS );
|
|
773
|
+
await sendMessageToQueue( `${sqs.url}${sqs.fixtureImageProcess}`, JSON.stringify( sqsData ) );
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
return res.sendSuccess( 'Fixture details updated successfully' );
|
|
778
|
+
} catch ( e ) {
|
|
779
|
+
logger.error( { functionName: 'updateAnswers', error: e } );
|
|
780
|
+
return res.sendError( e, 500 );
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
export async function getFixtureDetails( req, res ) {
|
|
785
|
+
try {
|
|
786
|
+
if ( !req.query.fixtureId && !req.query.planoId ) {
|
|
787
|
+
return res.sendError( 'Fixture/Plano id is required', 400 );
|
|
788
|
+
}
|
|
789
|
+
let query = { type: req.query.type };
|
|
790
|
+
if ( req.query?.fixtureId ) {
|
|
791
|
+
query['fixtureId'] = req.query.fixtureId;
|
|
792
|
+
} else {
|
|
793
|
+
if ( !req.query.floorId ) {
|
|
794
|
+
return res.sendError( 'Floor id is required', 400 );
|
|
795
|
+
}
|
|
796
|
+
query['planoId'] = req.query.planoId;
|
|
797
|
+
query['floorId'] = req.query.floorId;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if ( req.query?.date ) {
|
|
801
|
+
query['date_string'] = req.query?.date;
|
|
802
|
+
}
|
|
803
|
+
let fixtureDetails = await planoTaskService.findOne( query );
|
|
804
|
+
if ( !fixtureDetails ) {
|
|
805
|
+
return res.sendError( 'No data found', 204 );
|
|
806
|
+
}
|
|
807
|
+
fixtureDetails = await Promise.all( fixtureDetails.answers.map( async ( ans ) => {
|
|
808
|
+
if ( ans?.correctedFixture?.length ) {
|
|
809
|
+
for ( let fixture of ans.correctedFixture ) {
|
|
810
|
+
if ( fixture.image ) {
|
|
811
|
+
let params = {
|
|
812
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
813
|
+
file_path: fixture.image,
|
|
814
|
+
};
|
|
815
|
+
fixture.image = await signedUrl( params );
|
|
816
|
+
}
|
|
817
|
+
if ( fixture.video ) {
|
|
818
|
+
let params = {
|
|
819
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
820
|
+
file_path: fixture.video,
|
|
821
|
+
};
|
|
822
|
+
fixture.video = await signedUrl( params );
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if ( ans?.newVms?.length ) {
|
|
827
|
+
for ( let fixture of ans.newVms ) {
|
|
828
|
+
if ( fixture.imageUrl ) {
|
|
829
|
+
let params = {
|
|
830
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
831
|
+
file_path: fixture.imageUrl,
|
|
832
|
+
};
|
|
833
|
+
fixture.imageUrl = await signedUrl( params );
|
|
834
|
+
}
|
|
835
|
+
if ( fixture.video ) {
|
|
836
|
+
let params = {
|
|
837
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
838
|
+
file_path: fixture.video,
|
|
839
|
+
};
|
|
840
|
+
fixture.video = await signedUrl( params );
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if ( ans.image ) {
|
|
845
|
+
let params = {
|
|
846
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
847
|
+
file_path: ans.image,
|
|
848
|
+
};
|
|
849
|
+
let imageUrl = await signedUrl( params );
|
|
850
|
+
ans.image = imageUrl;
|
|
851
|
+
}
|
|
852
|
+
if ( ans.video ) {
|
|
853
|
+
let params = {
|
|
854
|
+
Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
|
|
855
|
+
file_path: ans.video,
|
|
856
|
+
};
|
|
857
|
+
let imageUrl = await signedUrl( params );
|
|
858
|
+
ans.video = imageUrl;
|
|
859
|
+
}
|
|
860
|
+
return ans;
|
|
861
|
+
} ) );
|
|
862
|
+
|
|
863
|
+
return res.sendSuccess( fixtureDetails );
|
|
864
|
+
} catch ( e ) {
|
|
865
|
+
logger.error( { functionName: 'getFixtureDetails', error: 'e' } );
|
|
866
|
+
return res.sendError( e, 500 );
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export async function getVmDetails( req, res ) {
|
|
871
|
+
try {
|
|
872
|
+
let getVms = await planoProductService.find( { type: 'vm', productName: { $ne: ' ' } }, { productName: 1 } );
|
|
873
|
+
if ( !getVms.length ) {
|
|
874
|
+
return res.sendError( 'No data found', 204 );
|
|
875
|
+
}
|
|
876
|
+
getVms = [ ...new Set( getVms.map( ( ele ) => ele.productName ) ) ];
|
|
877
|
+
getVms.push( 'other' );
|
|
878
|
+
return res.sendSuccess( getVms );
|
|
879
|
+
} catch ( e ) {
|
|
880
|
+
logger.error( { functionName: 'getVmDetails', error: e } );
|
|
881
|
+
return res.sendError( e, 500 );
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
export async function generatetaskDetails( req, res ) {
|
|
886
|
+
try {
|
|
887
|
+
let query = [
|
|
888
|
+
{
|
|
889
|
+
$match: {
|
|
890
|
+
date_iso: { $gte: new Date( req.body.fromDate ), $lte: new Date( req.body.toDate ) },
|
|
891
|
+
isPlano: true,
|
|
892
|
+
planoType: 'layout',
|
|
893
|
+
...( req.body?.store?.length ) ? { storeName: { $in: req.body.store } } : {},
|
|
894
|
+
userEmail: { $nin: [ 'sandeep.pal@yopmail.com', 'balaji@tangotech.co.in', 'gowri@tangotech.co.in', 'gowri@yopmail.com' ] },
|
|
895
|
+
},
|
|
896
|
+
},
|
|
897
|
+
// {
|
|
898
|
+
// $lookup: {
|
|
899
|
+
// from: '$planogram',
|
|
900
|
+
// let: { plano: '$planoId' },
|
|
901
|
+
// pipeline: [
|
|
902
|
+
// {
|
|
903
|
+
// $match: {
|
|
904
|
+
// $expr: {
|
|
905
|
+
// $and: {
|
|
906
|
+
// $eq: [ '$_id', '$$plano' ],
|
|
907
|
+
// },
|
|
908
|
+
// },
|
|
909
|
+
// },
|
|
910
|
+
// },
|
|
911
|
+
// ],
|
|
912
|
+
// as: 'planogram',
|
|
913
|
+
// },
|
|
914
|
+
// },
|
|
915
|
+
// {
|
|
916
|
+
// $lookup: {
|
|
917
|
+
// from: 'checklistassignconfigs',
|
|
918
|
+
// let: { storeId: '$store_id', email: '$userEmail' },
|
|
919
|
+
// pipeline: [
|
|
920
|
+
// {
|
|
921
|
+
// $match: {
|
|
922
|
+
// $expr: {
|
|
923
|
+
// $and: [
|
|
924
|
+
// // { $eq: [ '$checkListId', new ObjectId( '6789e3c7a5683c58215ec089' ) ] },
|
|
925
|
+
// { $eq: [ '$store_id', '$$storeId' ] },
|
|
926
|
+
// { $eq: [ '$userEmail', '$$email' ] },
|
|
927
|
+
// ],
|
|
928
|
+
// },
|
|
929
|
+
// },
|
|
930
|
+
// },
|
|
931
|
+
// ],
|
|
932
|
+
// as: 'assignUser',
|
|
933
|
+
// },
|
|
934
|
+
// },
|
|
935
|
+
{
|
|
936
|
+
$project: {
|
|
937
|
+
_id: 1,
|
|
938
|
+
storeName: 1,
|
|
939
|
+
store_id: 1,
|
|
940
|
+
userEmail: 1,
|
|
941
|
+
planoId: 1,
|
|
942
|
+
checklistStatus: 1,
|
|
943
|
+
date_string: 1,
|
|
944
|
+
storeStatus: {
|
|
945
|
+
$cond: {
|
|
946
|
+
if: { $eq: [ '$checklistStatus', 'submit' ] },
|
|
947
|
+
then: '',
|
|
948
|
+
else: '',
|
|
949
|
+
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
$group: {
|
|
956
|
+
_id: '$storeName',
|
|
957
|
+
count: { $sum: 1 },
|
|
958
|
+
planoId: { $last: '$planoId' },
|
|
959
|
+
taskId: { $push: '$_id' },
|
|
960
|
+
checklistStatus: { $last: '$checklistStatus' },
|
|
961
|
+
date_string: { $last: '$date_string' },
|
|
962
|
+
},
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
$project: {
|
|
966
|
+
_id: 0,
|
|
967
|
+
taskId: 1,
|
|
968
|
+
planoId: 1,
|
|
969
|
+
checklistStatus: 1,
|
|
970
|
+
count: 1,
|
|
971
|
+
date_string: 1,
|
|
972
|
+
storeName: '$_id',
|
|
973
|
+
},
|
|
974
|
+
},
|
|
975
|
+
];
|
|
976
|
+
let taskDetails = await processedService.aggregate( query );
|
|
977
|
+
// ...( req.body.store.length ) ? { storeName: { $in: req.body.store } } : {}, taskId: { $in: taskDetails.flatMap( ( ele ) => ele.taskId ) } },
|
|
978
|
+
let processedTaskDetails = await planoTaskService.find( { date_string: { $gte: req.body.fromDate, $lte: req.body.toDate }, type: 'layout' }, { status: 1, planoId: 1, date_string: 1, _id: 0, taskId: 1 } );
|
|
979
|
+
|
|
980
|
+
processedTaskDetails = await Promise.all( processedTaskDetails.map( async ( ele ) => {
|
|
981
|
+
ele = { ...ele.toObject(), storeName: '' };
|
|
982
|
+
if ( ele.planoId ) {
|
|
983
|
+
let planoDetails = await planoService.findOne( { _id: ele.planoId }, { storeName: 1 } );
|
|
984
|
+
if ( planoDetails ) {
|
|
985
|
+
ele.storeName = planoDetails.storeName;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return ele;
|
|
989
|
+
} ) );
|
|
990
|
+
|
|
991
|
+
processedTaskDetails.forEach( ( item ) => {
|
|
992
|
+
let taskIndex = taskDetails.findIndex( ( taskItem ) => taskItem.checklistStatus == 'submit' && taskItem.date_string == item.date_string && item.planoId.toString() == taskItem.planoId.toString() );
|
|
993
|
+
if ( taskIndex != -1 ) {
|
|
994
|
+
taskDetails[taskIndex].storeStatus = item.status == 'complete' ? 'yes' : 'No';
|
|
995
|
+
}
|
|
996
|
+
} );
|
|
997
|
+
|
|
998
|
+
taskDetails.forEach( ( ele ) => {
|
|
999
|
+
delete ele.planoId;
|
|
1000
|
+
} );
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
let completeStore = taskDetails.filter( ( ele ) => ele.checklistStatus == 'submit' );
|
|
1004
|
+
completeStore = completeStore.reduce( ( acc, ele ) => {
|
|
1005
|
+
if ( !acc[ele.storeName] ) {
|
|
1006
|
+
acc[ele.storeName] = {
|
|
1007
|
+
storeName: ele.storeName,
|
|
1008
|
+
status: 'submit',
|
|
1009
|
+
storeStatus: ele.storeStatus,
|
|
1010
|
+
date: ele.date_string,
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
return acc;
|
|
1014
|
+
}, {} );
|
|
1015
|
+
|
|
1016
|
+
completeStore = Object.values( completeStore );
|
|
1017
|
+
|
|
1018
|
+
let completeStoreList = completeStore.map( ( item ) => item.storeName );
|
|
1019
|
+
|
|
1020
|
+
let incompleteStore = taskDetails.filter( ( ele ) => ele.checklistStatus != 'submit' );
|
|
1021
|
+
|
|
1022
|
+
incompleteStore = incompleteStore.reduce( ( acc, ele ) => {
|
|
1023
|
+
if ( !acc[ele.storeName] ) {
|
|
1024
|
+
acc[ele.storeName] = {
|
|
1025
|
+
storeName: ele.storeName,
|
|
1026
|
+
status: ele.checklistStatus,
|
|
1027
|
+
storeStatus: ele.storeStatus,
|
|
1028
|
+
date: ele.date_string,
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
return acc;
|
|
1032
|
+
}, {} );
|
|
1033
|
+
|
|
1034
|
+
incompleteStore = Object.values( incompleteStore );
|
|
1035
|
+
|
|
1036
|
+
incompleteStore = incompleteStore.filter( ( ele ) => !completeStoreList.includes( ele.storeName ) );
|
|
1037
|
+
|
|
1038
|
+
if ( !taskDetails.length ) {
|
|
1039
|
+
return res.sendError( 'No date found', 204 );
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
let data = [ ...completeStore, ...incompleteStore ];
|
|
1043
|
+
let yesCount = completeStore.filter( ( ele ) => ele.storeStatus == 'yes' );
|
|
1044
|
+
let noCount = completeStore.filter( ( ele ) => ele.storeStatus == 'No' );
|
|
1045
|
+
|
|
1046
|
+
return res.sendSuccess( { count: data.length, completeStore: completeStore.length, incompleteStore: incompleteStore.length, yesCount: yesCount.length, noCount: noCount.length, data } );
|
|
1047
|
+
} catch ( e ) {
|
|
1048
|
+
console.log( e );
|
|
1049
|
+
logger.error( { functioName: 'generatetaskDetails', error: e } );
|
|
1050
|
+
return res.sendError( e, 500 );
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
export async function taskSubmitDetails( req, res ) {
|
|
1055
|
+
try {
|
|
1056
|
+
let query = [
|
|
1057
|
+
{
|
|
1058
|
+
$match: {
|
|
1059
|
+
date_string: { $gte: req.body.fromDate, $lte: req.body.toDate },
|
|
1060
|
+
type: 'layout',
|
|
1061
|
+
status: req.body.status,
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
$group: {
|
|
1066
|
+
_id: '',
|
|
1067
|
+
planoId: { $addToSet: '$planoId' },
|
|
1068
|
+
},
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
$lookup: {
|
|
1072
|
+
from: 'processedtasks',
|
|
1073
|
+
let: { plano_id: '$planoId' },
|
|
1074
|
+
pipeline: [
|
|
1075
|
+
{
|
|
1076
|
+
$match: {
|
|
1077
|
+
$expr: {
|
|
1078
|
+
$and: [
|
|
1079
|
+
{ $in: [ '$planoId', '$$plano_id' ] },
|
|
1080
|
+
],
|
|
1081
|
+
},
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
$group: {
|
|
1086
|
+
_id: '$planoId',
|
|
1087
|
+
storeName: { $first: '$storeName' },
|
|
1088
|
+
},
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
$project: {
|
|
1092
|
+
storeName: 1,
|
|
1093
|
+
_id: 0,
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
],
|
|
1097
|
+
as: 'planogram',
|
|
1098
|
+
},
|
|
1099
|
+
},
|
|
1100
|
+
{ $unwind: { path: '$planogram', preserveNullAndEmptyArrays: true } },
|
|
1101
|
+
{
|
|
1102
|
+
$project: {
|
|
1103
|
+
_id: 0,
|
|
1104
|
+
storeName: '$planogram.storeName',
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
];
|
|
1108
|
+
|
|
1109
|
+
let processedTaskDetails = await planoTaskService.aggregate( query );
|
|
1110
|
+
processedTaskDetails = processedTaskDetails.map( ( ele ) => ele.storeName );
|
|
1111
|
+
return res.sendSuccess( { count: processedTaskDetails.length, data: processedTaskDetails } );
|
|
1112
|
+
} catch ( e ) {
|
|
1113
|
+
logger.error( { functioName: 'taskSubmitDetails', error: e } );
|
|
1114
|
+
return res.sendError( e, 500 );
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
export async function redoTask( req, res ) {
|
|
1119
|
+
try {
|
|
1120
|
+
if ( !req.body.taskId ) {
|
|
1121
|
+
return res.sendError( 'Task id is required', 400 );
|
|
1122
|
+
}
|
|
1123
|
+
let getTaskDetails = await processedService.findOne( { _id: req.body.taskId } );
|
|
1124
|
+
if ( !getTaskDetails ) {
|
|
1125
|
+
return res.sendError( e, 204 );
|
|
1126
|
+
}
|
|
1127
|
+
await processedService.updateOne( { _id: req.body.taskId }, { checklistStatus: 'open', redoStatus: true } );
|
|
1128
|
+
return res.sendSuccess( 'Task is republished successfully' );
|
|
1129
|
+
} catch ( e ) {
|
|
1130
|
+
logger.error( { functionName: 'redoTask', error: e } );
|
|
1131
|
+
return res.sendError( e, 500 );
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
export async function revokeTask( req, res ) {
|
|
1136
|
+
try {
|
|
1137
|
+
if ( !req.body.planoId ) {
|
|
1138
|
+
return res.sendError( 'plano id is required', 400 );
|
|
1139
|
+
}
|
|
1140
|
+
if ( !req.body.floorId ) {
|
|
1141
|
+
return res.sendError( 'floor id is required', 400 );
|
|
1142
|
+
}
|
|
1143
|
+
await processedService.deleteMany( { planoId: req.body.planoId, floorId: req.body.floorId, ...( req.body?.type != 'fixture' && { checklistStatus: { $ne: 'submit' } } ), ...( req.body?.type && { planoType: req.body?.type } ) } );
|
|
1144
|
+
return res.sendSuccess( 'Task revoked successfully' );
|
|
1145
|
+
} catch ( e ) {
|
|
1146
|
+
logger.error( { functionName: 'revokeTask', error: e } );
|
|
1147
|
+
return res.sendError( e, 500 );
|
|
1148
|
+
}
|
|
1149
|
+
}
|