@tiledesk/tiledesk-server 2.13.50 → 2.13.51
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/CHANGELOG.md +4 -0
- package/app.js +2 -1
- package/jobs.js +2 -1
- package/jobsManager.js +6 -1
- package/package.json +1 -1
- package/pubmodules/queue/reconnect.js +16 -3
- package/pubmodules/queue/reconnectFanout.js +4 -0
- package/routes/request.js +3 -0
- package/services/requestService.js +392 -813
- package/services/subscriptionNotifier.js +12 -1
- package/services/updateRequestSnapshotQueued.js +71 -0
- package/test/messageRoute.js +12 -12
- package/test/requestRoute.js +46 -44
- package/test/requestService.js +84 -84
- package/test/webhookRoute.js +1 -1
|
@@ -243,270 +243,152 @@ class RequestService {
|
|
|
243
243
|
|
|
244
244
|
// TODO changePreflightByRequestId se un agente entra in request freflight true disabilitare add agente e reassing ma mettere un bottone removePreflight???
|
|
245
245
|
// usalo no_populate
|
|
246
|
-
route(request_id, departmentid, id_project, nobot, no_populate) {
|
|
247
|
-
var that = this;
|
|
246
|
+
async route(request_id, departmentid, id_project, nobot, no_populate) {
|
|
248
247
|
|
|
249
|
-
|
|
248
|
+
try {
|
|
250
249
|
winston.debug("request_id:" + request_id);
|
|
251
250
|
winston.debug("departmentid:" + departmentid);
|
|
252
251
|
winston.debug("id_project:" + id_project);
|
|
253
252
|
winston.debug("nobot:" + nobot);
|
|
253
|
+
winston.info("main_flow_cache_3 route");
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (err) {
|
|
265
|
-
winston.error(err);
|
|
266
|
-
return reject(err);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
winston.debug('request return', request);
|
|
270
|
-
|
|
271
|
-
// cambia var in let
|
|
272
|
-
|
|
273
|
-
//it is important to clone here
|
|
274
|
-
var requestBeforeRoute = Object.assign({}, request.toObject());
|
|
275
|
-
winston.debug("requestBeforeRoute", requestBeforeRoute);
|
|
276
|
-
|
|
277
|
-
var beforeParticipants = requestBeforeRoute.participants;
|
|
278
|
-
winston.debug("beforeParticipants: ", beforeParticipants);
|
|
279
|
-
|
|
280
|
-
return that.routeInternal(request, departmentid, id_project, nobot).then( async function (routedRequest) {
|
|
281
|
-
|
|
282
|
-
winston.debug("after routeInternal", routedRequest);
|
|
283
|
-
winston.debug("requestBeforeRoute.status:" + requestBeforeRoute.status);
|
|
284
|
-
winston.debug("routedRequest.status:" + routedRequest.status);
|
|
285
|
-
|
|
286
|
-
let beforeDepartmentId;
|
|
287
|
-
if (requestBeforeRoute.department) { //requestBeforeRoute.department can be empty for internal ticket
|
|
288
|
-
beforeDepartmentId = requestBeforeRoute.department.toString();
|
|
289
|
-
winston.debug("beforeDepartmentId:" + beforeDepartmentId);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
let afterDepartmentId;
|
|
294
|
-
if (routedRequest.department) {
|
|
295
|
-
afterDepartmentId = routedRequest.department.toString();
|
|
296
|
-
winston.debug("afterDepartmentId:" + afterDepartmentId);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
winston.debug("requestBefore status: ", requestBeforeRoute.status)
|
|
300
|
-
winston.debug("routedRequest status: ", routedRequest.status)
|
|
301
|
-
/**
|
|
302
|
-
* Case 1
|
|
303
|
-
* After internal routing:
|
|
304
|
-
* - same STATUS
|
|
305
|
-
* - same DEPARTMENT
|
|
306
|
-
* - same PARTICIPANTS
|
|
307
|
-
*/
|
|
308
|
-
if (requestBeforeRoute.status === routedRequest.status &&
|
|
309
|
-
beforeDepartmentId === afterDepartmentId &&
|
|
310
|
-
requestUtil.arraysEqual(beforeParticipants, routedRequest.participants)) {
|
|
311
|
-
|
|
312
|
-
winston.verbose("Request " + request.request_id + " contains already the same participants at the same request status. Routed to the same participants");
|
|
313
|
-
|
|
314
|
-
if (routedRequest.attributes && routedRequest.attributes.fully_abandoned && routedRequest.attributes.fully_abandoned === true) {
|
|
315
|
-
request.status = RequestConstants.ABANDONED;
|
|
316
|
-
request.attributes.fully_abandoned = true;
|
|
317
|
-
request.markModified('status');
|
|
318
|
-
request.markModified('attributes');
|
|
319
|
-
request.save((err, savedRequest) => {
|
|
320
|
-
if (err) {
|
|
321
|
-
winston.error("Error updating request with status ABANDONED ", err);
|
|
322
|
-
} else {
|
|
323
|
-
winston.verbose("Status modified in ABANDONED for request: " + savedRequest._id);
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* TODO: Restore proper functioning
|
|
330
|
-
* Option commented on 03/12/2025 by Johnny in order to allows clients to receive the request populated
|
|
331
|
-
* in such case of Abandoned Request (Status 150)
|
|
332
|
-
*/
|
|
333
|
-
// if (no_populate === "true" || no_populate === true) {
|
|
334
|
-
// winston.debug("no_populate is true");
|
|
335
|
-
// requestEvent.emit('request.update', request);
|
|
336
|
-
// return resolve(request);
|
|
337
|
-
// }
|
|
338
|
-
|
|
339
|
-
return request
|
|
340
|
-
.populate('lead')
|
|
341
|
-
.populate('department')
|
|
342
|
-
.populate('participatingBots')
|
|
343
|
-
.populate('participatingAgents')
|
|
344
|
-
.populate({ path: 'requester', populate: { path: 'id_user' } })
|
|
345
|
-
.execPopulate(function (err, requestComplete) {
|
|
346
|
-
winston.debug("requestComplete", requestComplete);
|
|
347
|
-
|
|
348
|
-
var oldParticipants = beforeParticipants;
|
|
349
|
-
winston.debug("oldParticipants ", oldParticipants);
|
|
350
|
-
|
|
351
|
-
let newParticipants = requestComplete.participants;
|
|
352
|
-
winston.debug("newParticipants ", newParticipants);
|
|
353
|
-
|
|
354
|
-
var removedParticipants = oldParticipants.filter(d => !newParticipants.includes(d));
|
|
355
|
-
winston.debug("removedParticipants ", removedParticipants);
|
|
356
|
-
|
|
357
|
-
var addedParticipants = newParticipants.filter(d => !oldParticipants.includes(d));
|
|
358
|
-
winston.debug("addedParticipants ", addedParticipants);
|
|
359
|
-
|
|
360
|
-
requestEvent.emit('request.update', requestComplete);
|
|
361
|
-
requestEvent.emit("request.update.comment", { comment: "REROUTE", request: requestComplete });//Deprecated
|
|
362
|
-
requestEvent.emit("request.updated", { comment: "REROUTE", request: requestComplete, patch: { removedParticipants: removedParticipants, addedParticipants: addedParticipants } });
|
|
363
|
-
|
|
364
|
-
requestEvent.emit('request.participants.update', {
|
|
365
|
-
beforeRequest: request,
|
|
366
|
-
removedParticipants: removedParticipants,
|
|
367
|
-
addedParticipants: addedParticipants,
|
|
368
|
-
request: requestComplete
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
return resolve(requestComplete);
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
let project = await projectService.getCachedProject(id_project).catch((err) => {
|
|
376
|
-
winston.warn("Error getting cached project. Skip conversation quota check.")
|
|
377
|
-
winston.warn("Getting cached project error: ", err)
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
let isTestConversation = false;
|
|
382
|
-
let isVoiceConversation = false;
|
|
383
|
-
let isStandardConversation = false;
|
|
384
|
-
|
|
385
|
-
let payload = {
|
|
386
|
-
project: project,
|
|
387
|
-
request: request
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (request.attributes && request.attributes.sourcePage && (request.attributes.sourcePage.indexOf("td_draft=true") > -1)) {
|
|
391
|
-
winston.verbose("is a test conversation --> skip quote availability check")
|
|
392
|
-
isTestConversation = true;
|
|
393
|
-
}
|
|
394
|
-
else if (request.channel && (request.channel.name === 'voice-vxml')) {
|
|
395
|
-
winston.verbose("is a voice conversation --> skip quote availability check")
|
|
396
|
-
isVoiceConversation = true;
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
isStandardConversation = true;
|
|
400
|
-
let available = await qm.checkQuote(project, request, 'requests');
|
|
401
|
-
if (available === false) {
|
|
402
|
-
winston.info("Requests limits reached for project " + project._id)
|
|
403
|
-
return reject("Requests limits reached for project " + project._id);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
255
|
+
// Find request
|
|
256
|
+
let query = Request.findOne({ request_id, id_project });
|
|
257
|
+
if (cacheEnabler.request) {
|
|
258
|
+
query = query.cache(cacheUtil.defaultTTL, id_project + ":requests:request_id:" + request_id + ":simple");
|
|
259
|
+
winston.debug('request cache enabled');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const request = await query.exec();
|
|
406
263
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
* - STATUS changed from 50 to 100 or 200
|
|
411
|
-
*/
|
|
412
|
-
if (requestBeforeRoute.status === RequestConstants.TEMP && (routedRequest.status === RequestConstants.ASSIGNED || routedRequest.status === RequestConstants.UNASSIGNED)) {
|
|
413
|
-
// console.log("Case 2 - Leaving TEMP status")
|
|
414
|
-
if (isStandardConversation) {
|
|
415
|
-
requestEvent.emit('request.create.quote', payload);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
264
|
+
if (!request) {
|
|
265
|
+
throw new Error(`Request not found: ${request_id}`);
|
|
266
|
+
}
|
|
418
267
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
268
|
+
// Clone before route
|
|
269
|
+
const requestBeforeRoute = request.toObject();
|
|
270
|
+
const beforeParticipants = requestBeforeRoute.participants;
|
|
271
|
+
const beforeDepartmentId = requestBeforeRoute.department?.toString();
|
|
272
|
+
|
|
273
|
+
// Route internal
|
|
274
|
+
const routedRequest = await this.routeInternal(request, departmentid, id_project, nobot);
|
|
275
|
+
|
|
276
|
+
const afterDepartmentId = routedRequest.department?.toString();
|
|
277
|
+
|
|
278
|
+
// Case 1 - No changes
|
|
279
|
+
if (
|
|
280
|
+
requestBeforeRoute.status === routedRequest.status &&
|
|
281
|
+
beforeDepartmentId === afterDepartmentId &&
|
|
282
|
+
requestUtil.arraysEqual(beforeParticipants, routedRequest.participants)
|
|
283
|
+
) {
|
|
284
|
+
|
|
285
|
+
winston.verbose(`Request ${request.request_id} routed to same status/participants`);
|
|
286
|
+
|
|
287
|
+
if (routedRequest.attributes?.fully_abandoned === true) {
|
|
288
|
+
request.status = RequestConstants.ABANDONED;
|
|
289
|
+
request.attributes.fully_abandoned = true;
|
|
290
|
+
request.markModified("status");
|
|
291
|
+
request.markModified("attributes");
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
await request.save();
|
|
295
|
+
winston.verbose(`Status set to ABANDONED for request ${request._id}`);
|
|
296
|
+
} catch (err) {
|
|
297
|
+
winston.error("Error updating request to ABANDONED", err);
|
|
429
298
|
}
|
|
299
|
+
}
|
|
430
300
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (err) {
|
|
461
|
-
winston.error('Error populating the request.', err);
|
|
462
|
-
return reject(err);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
winston.verbose("Request routed", requestComplete.toObject());
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
var oldParticipants = beforeParticipants;
|
|
469
|
-
winston.debug("oldParticipants ", oldParticipants);
|
|
470
|
-
|
|
471
|
-
let newParticipants = requestComplete.participants;
|
|
472
|
-
winston.debug("newParticipants ", newParticipants);
|
|
473
|
-
|
|
474
|
-
var removedParticipants = oldParticipants.filter(d => !newParticipants.includes(d));
|
|
475
|
-
winston.debug("removedParticipants ", removedParticipants);
|
|
476
|
-
|
|
477
|
-
var addedParticipants = newParticipants.filter(d => !oldParticipants.includes(d));
|
|
478
|
-
winston.debug("addedParticipants ", addedParticipants);
|
|
301
|
+
/**
|
|
302
|
+
* TODO: Restore proper functioning
|
|
303
|
+
* Option commented on 03/12/2025 by Johnny in order to allows clients to receive the request populated
|
|
304
|
+
* in such case of Abandoned Request (Status 150)
|
|
305
|
+
*/
|
|
306
|
+
// if (no_populate === "true" || no_populate === true) {
|
|
307
|
+
// winston.debug("no_populate is true");
|
|
308
|
+
// requestEvent.emit('request.update', request);
|
|
309
|
+
// return request;
|
|
310
|
+
// }
|
|
311
|
+
|
|
312
|
+
const requestComplete = await request
|
|
313
|
+
.populate("lead")
|
|
314
|
+
.populate("department")
|
|
315
|
+
.populate("participatingBots")
|
|
316
|
+
.populate("participatingAgents")
|
|
317
|
+
.populate({ path: "requester", populate: { path: "id_user" } })
|
|
318
|
+
.execPopulate();
|
|
319
|
+
|
|
320
|
+
this.emitParticipantsEvents(
|
|
321
|
+
request,
|
|
322
|
+
requestComplete,
|
|
323
|
+
beforeParticipants
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
return requestComplete;
|
|
327
|
+
}
|
|
479
328
|
|
|
329
|
+
|
|
330
|
+
// Quota check
|
|
331
|
+
let project;
|
|
332
|
+
try {
|
|
333
|
+
project = await projectService.getCachedProject(id_project);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
winston.warn("Error getting cached project, skip quota check", err);
|
|
336
|
+
}
|
|
480
337
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
338
|
+
const isTestConversation = request.attributes?.sourcePage?.includes("td_draft=true");
|
|
339
|
+
const isVoiceConversation = request.channel?.name === "voice-vxml";
|
|
340
|
+
const isStandardConversation = !isTestConversation && !isVoiceConversation;
|
|
484
341
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
342
|
+
if (isStandardConversation) {
|
|
343
|
+
const available = await qm.checkQuote(project, request, "requests");
|
|
344
|
+
if (!available) {
|
|
345
|
+
throw new Error(`Requests limits reached for project ${project._id}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
491
348
|
|
|
492
|
-
|
|
349
|
+
// Case 2 - Leaving TEMP status. After internal routing: STATUS changed from 50 to 100 or 200
|
|
350
|
+
if (requestBeforeRoute.status === RequestConstants.TEMP &&
|
|
351
|
+
[RequestConstants.ASSIGNED, RequestConstants.UNASSIGNED].includes(routedRequest.status) &&
|
|
352
|
+
isStandardConversation
|
|
353
|
+
) {
|
|
354
|
+
requestEvent.emit("request.create.quote", { project, request });
|
|
355
|
+
}
|
|
493
356
|
|
|
494
|
-
|
|
357
|
+
// Case 3 - Conversation opened through proactive message. After internal routing: STATUS changed from undefined to 100
|
|
358
|
+
if (
|
|
359
|
+
!requestBeforeRoute.status &&
|
|
360
|
+
routedRequest.status === RequestConstants.ASSIGNED &&
|
|
361
|
+
isStandardConversation
|
|
362
|
+
) {
|
|
363
|
+
requestEvent.emit("request.create.quote", { project, request });
|
|
364
|
+
}
|
|
495
365
|
|
|
496
|
-
|
|
497
|
-
|
|
366
|
+
// Save and populate
|
|
367
|
+
const savedRequest = await routedRequest.save();
|
|
498
368
|
|
|
369
|
+
const requestComplete = await savedRequest
|
|
370
|
+
.populate("lead")
|
|
371
|
+
.populate("department")
|
|
372
|
+
.populate("participatingBots")
|
|
373
|
+
.populate("participatingAgents")
|
|
374
|
+
.populate({ path: "requester", populate: { path: "id_user" } })
|
|
375
|
+
.execPopulate();
|
|
499
376
|
|
|
500
377
|
|
|
501
|
-
|
|
378
|
+
this.emitParticipantsEvents(
|
|
379
|
+
request,
|
|
380
|
+
requestComplete,
|
|
381
|
+
beforeParticipants
|
|
382
|
+
);
|
|
502
383
|
|
|
503
|
-
|
|
504
|
-
return reject(err);
|
|
505
|
-
});
|
|
384
|
+
requestEvent.emit("request.department.update", requestComplete);
|
|
506
385
|
|
|
386
|
+
return requestComplete;
|
|
507
387
|
|
|
508
|
-
|
|
509
|
-
|
|
388
|
+
} catch (error) {
|
|
389
|
+
winston.error("Route error", { error, request_id, id_project });
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
510
392
|
}
|
|
511
393
|
|
|
512
394
|
|
|
@@ -579,558 +461,249 @@ class RequestService {
|
|
|
579
461
|
};
|
|
580
462
|
|
|
581
463
|
async create(request) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (!departmentid) {
|
|
612
|
-
departmentid = 'default';
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (!createdBy) {
|
|
616
|
-
if (project_user_id) {
|
|
617
|
-
createdBy = project_user_id;
|
|
618
|
-
} else {
|
|
619
|
-
createdBy = "system";
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// Utils
|
|
464
|
+
const createdAt = request.createdAt || new Date();
|
|
465
|
+
|
|
466
|
+
let {
|
|
467
|
+
request_id,
|
|
468
|
+
project_user_id,
|
|
469
|
+
lead_id,
|
|
470
|
+
id_project,
|
|
471
|
+
first_text,
|
|
472
|
+
sourcePage,
|
|
473
|
+
language,
|
|
474
|
+
userAgent,
|
|
475
|
+
status,
|
|
476
|
+
attributes,
|
|
477
|
+
subject,
|
|
478
|
+
preflight,
|
|
479
|
+
channel,
|
|
480
|
+
location,
|
|
481
|
+
participants = [],
|
|
482
|
+
tags,
|
|
483
|
+
notes,
|
|
484
|
+
priority,
|
|
485
|
+
auto_close,
|
|
486
|
+
followers
|
|
487
|
+
} = request;
|
|
488
|
+
|
|
489
|
+
let departmentid = request.departmentid || 'default';
|
|
490
|
+
let createdBy = request.createdBy || project_user_id || "system";
|
|
491
|
+
|
|
492
|
+
// Utils and flags
|
|
624
493
|
let payload;
|
|
625
494
|
let isTestConversation = false;
|
|
626
495
|
let isVoiceConversation = false;
|
|
627
496
|
let isStandardConversation = false;
|
|
628
|
-
var that = this;
|
|
629
497
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
winston.debug("context", context);
|
|
498
|
+
const context = {
|
|
499
|
+
request: {
|
|
500
|
+
request_id, project_user_id, lead_id, id_project,
|
|
501
|
+
first_text, departmentid, sourcePage, language, userAgent, status,
|
|
502
|
+
createdBy, attributes, subject, preflight, channel, location,
|
|
503
|
+
participants,tags,notes,priority,auto_close,followers
|
|
504
|
+
}
|
|
505
|
+
};
|
|
641
506
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
507
|
+
winston.debug("context: ", context);
|
|
508
|
+
|
|
509
|
+
// Initial assignment
|
|
510
|
+
let agents = [];
|
|
511
|
+
let participantsAgents = [];
|
|
512
|
+
let participantsBots = [];
|
|
513
|
+
let hasBot = false;
|
|
514
|
+
let dep_id;
|
|
515
|
+
let assigned_at;
|
|
516
|
+
let snapshot = {};
|
|
517
|
+
|
|
518
|
+
// Getting operators
|
|
519
|
+
let result;
|
|
520
|
+
try {
|
|
521
|
+
result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
|
|
522
|
+
winston.debug("Get operators result: ", result);
|
|
523
|
+
} catch (err) {
|
|
524
|
+
throw new Error("Error getting operators", { cause: err });
|
|
525
|
+
}
|
|
649
526
|
|
|
650
|
-
|
|
651
|
-
// (method) DepartmentService.getOperators(departmentid: any, projectid: any, nobot: any, disableWebHookCall: any, context: any): Promise<any>
|
|
652
|
-
var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
|
|
653
|
-
winston.debug("getOperators", result);
|
|
527
|
+
agents = result.agents;
|
|
654
528
|
|
|
529
|
+
// Status and quote management
|
|
530
|
+
if (status === RequestConstants.TEMP) {
|
|
531
|
+
// Skip assignment
|
|
532
|
+
if (participants.length === 0) {
|
|
533
|
+
dep_id = result.department._id;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
|
|
538
|
+
let project;
|
|
539
|
+
try {
|
|
540
|
+
project = await projectService.getCachedProject(id_project);
|
|
655
541
|
} catch (err) {
|
|
656
|
-
|
|
542
|
+
throw new Error("Error getting project", { cause: err });
|
|
657
543
|
}
|
|
658
544
|
|
|
659
|
-
|
|
545
|
+
if (!project) {
|
|
546
|
+
winston.error(`Project not found for id_project: ${id_project}`);
|
|
547
|
+
throw new Error(`Project not found for id_project: ${id_project}`);
|
|
548
|
+
}
|
|
660
549
|
|
|
661
|
-
|
|
662
|
-
// skip assignment
|
|
663
|
-
if (participants.length == 0) {
|
|
664
|
-
dep_id = result.department._id;
|
|
665
|
-
}
|
|
666
|
-
} else {
|
|
550
|
+
payload = { project, request };
|
|
667
551
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
552
|
+
// Test conversation
|
|
553
|
+
if (attributes?.sourcePage?.includes("td_draft=true")) {
|
|
554
|
+
winston.verbose("is a test conversation --> skip quote availability check");
|
|
555
|
+
isTestConversation = true;
|
|
556
|
+
}
|
|
672
557
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
558
|
+
// Voice conversation
|
|
559
|
+
else if (channel?.name === "voice-vxml") {
|
|
560
|
+
isVoiceConversation = true;
|
|
561
|
+
const available = await qm.checkQuote(project, request, "voice_duration");
|
|
562
|
+
if (!available) {
|
|
563
|
+
winston.info(`Voice duration limits reached for project ${id_project}`);
|
|
564
|
+
throw new Error(`Voice duration limits reached for project ${id_project}`);
|
|
676
565
|
}
|
|
566
|
+
}
|
|
677
567
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if (available === false) {
|
|
686
|
-
winston.info("Voice duration limits reached for project " + project._id);
|
|
687
|
-
return reject("Voice duration limits reached for project " + project._id);
|
|
688
|
-
}
|
|
568
|
+
// Standard conversation
|
|
569
|
+
else {
|
|
570
|
+
isStandardConversation = true;
|
|
571
|
+
const available = await qm.checkQuote(project, request, "requests");
|
|
572
|
+
if (!available) {
|
|
573
|
+
winston.info(`Requests limits reached for project ${project._id}`);
|
|
574
|
+
throw new Error(`Requests limits reached for project ${project._id}`);
|
|
689
575
|
}
|
|
690
|
-
|
|
691
|
-
isStandardConversation = true;
|
|
692
|
-
let available = await qm.checkQuote(project, request, 'requests');
|
|
693
|
-
if (available === false) {
|
|
694
|
-
winston.info("Requests limits reached for project " + project._id)
|
|
695
|
-
return reject("Requests limits reached for project " + project._id);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
|
|
576
|
+
}
|
|
699
577
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
// for preflight it is important to save agents in req for trigger. try to optimize it
|
|
705
|
-
dep_id = result.department._id;
|
|
578
|
+
// Assignment
|
|
579
|
+
if (participants.length === 0) {
|
|
580
|
+
if (result.operators?.length > 0) {
|
|
581
|
+
participants.push(result.operators[0].id_user.toString());
|
|
706
582
|
}
|
|
583
|
+
dep_id = result.department._id;
|
|
584
|
+
}
|
|
707
585
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
// botprefix
|
|
711
|
-
if (participants[0].startsWith("bot_")) {
|
|
712
|
-
|
|
713
|
-
hasBot = true;
|
|
714
|
-
winston.debug("hasBot:" + hasBot);
|
|
715
|
-
|
|
716
|
-
// botprefix
|
|
717
|
-
var assigned_operator_idStringBot = participants[0].replace("bot_", "");
|
|
718
|
-
winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
|
|
719
|
-
|
|
720
|
-
participantsBots.push(assigned_operator_idStringBot);
|
|
721
|
-
|
|
722
|
-
} else {
|
|
723
|
-
|
|
724
|
-
participantsAgents.push(participants[0]);
|
|
725
|
-
|
|
726
|
-
}
|
|
586
|
+
if (participants.length > 0) {
|
|
587
|
+
status = RequestConstants.ASSIGNED;
|
|
727
588
|
|
|
728
|
-
|
|
589
|
+
const firstParticipant = participants[0];
|
|
729
590
|
|
|
591
|
+
if (firstParticipant.startsWith("bot_")) {
|
|
592
|
+
hasBot = true;
|
|
593
|
+
const botId = firstParticipant.replace("bot_", "");
|
|
594
|
+
participantsBots.push(botId);
|
|
730
595
|
} else {
|
|
731
|
-
|
|
596
|
+
participantsAgents.push(firstParticipant);
|
|
732
597
|
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (dep_id) {
|
|
736
|
-
snapshot.department = result.department;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
snapshot.agents = agents;
|
|
740
|
-
snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
|
|
741
|
-
|
|
742
|
-
if (request.requester) {
|
|
743
|
-
snapshot.requester = request.requester;
|
|
744
|
-
}
|
|
745
|
-
if (request.lead) {
|
|
746
|
-
snapshot.lead = request.lead;
|
|
747
|
-
}
|
|
748
598
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
lead: lead_id,
|
|
753
|
-
first_text: first_text,
|
|
754
|
-
subject: subject,
|
|
755
|
-
status: status,
|
|
756
|
-
participants: participants,
|
|
757
|
-
participantsAgents: participantsAgents,
|
|
758
|
-
participantsBots: participantsBots,
|
|
759
|
-
hasBot: hasBot,
|
|
760
|
-
department: dep_id,
|
|
761
|
-
// agents: agents,
|
|
762
|
-
//others
|
|
763
|
-
sourcePage: sourcePage,
|
|
764
|
-
language: language,
|
|
765
|
-
userAgent: userAgent,
|
|
766
|
-
assigned_at: assigned_at,
|
|
767
|
-
attributes: attributes,
|
|
768
|
-
//standard
|
|
769
|
-
id_project: id_project,
|
|
770
|
-
createdBy: createdBy,
|
|
771
|
-
updatedBy: createdBy,
|
|
772
|
-
preflight: preflight,
|
|
773
|
-
channel: channel,
|
|
774
|
-
location: location,
|
|
775
|
-
snapshot: snapshot,
|
|
776
|
-
tags: tags,
|
|
777
|
-
notes: notes,
|
|
778
|
-
priority: priority,
|
|
779
|
-
auto_close: auto_close,
|
|
780
|
-
followers: followers,
|
|
781
|
-
createdAt: createdAt
|
|
782
|
-
});
|
|
783
|
-
|
|
784
|
-
if (isTestConversation) {
|
|
785
|
-
newRequest.draft = true;
|
|
599
|
+
assigned_at = Date.now();
|
|
600
|
+
} else {
|
|
601
|
+
status = RequestConstants.UNASSIGNED;
|
|
786
602
|
}
|
|
603
|
+
}
|
|
787
604
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
if (err) {
|
|
794
|
-
winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
|
|
795
|
-
return reject(err);
|
|
796
|
-
}
|
|
797
|
-
winston.debug("Request created", savedRequest.toObject());
|
|
798
|
-
|
|
799
|
-
requestEvent.emit('request.create.simple', savedRequest);
|
|
800
|
-
|
|
801
|
-
if (isStandardConversation) {
|
|
802
|
-
requestEvent.emit('request.create.quote', payload);;
|
|
803
|
-
}
|
|
605
|
+
// Snapshot
|
|
606
|
+
if (dep_id) {
|
|
607
|
+
snapshot.department = result.department;
|
|
608
|
+
}
|
|
609
|
+
snapshot.agents = agents;
|
|
804
610
|
|
|
805
|
-
|
|
611
|
+
if (request.requester) {
|
|
612
|
+
snapshot.requester = request.requester;
|
|
613
|
+
}
|
|
614
|
+
if (request.lead) {
|
|
615
|
+
snapshot.lead = request.lead;
|
|
616
|
+
}
|
|
806
617
|
|
|
807
|
-
|
|
618
|
+
// Create request
|
|
619
|
+
const newRequest = new Request({
|
|
620
|
+
request_id,
|
|
621
|
+
requester: project_user_id,
|
|
622
|
+
lead: lead_id,
|
|
623
|
+
first_text,
|
|
624
|
+
subject,
|
|
625
|
+
status,
|
|
626
|
+
participants,
|
|
627
|
+
participantsAgents,
|
|
628
|
+
participantsBots,
|
|
629
|
+
hasBot,
|
|
630
|
+
department: dep_id,
|
|
631
|
+
sourcePage,
|
|
632
|
+
language,
|
|
633
|
+
userAgent,
|
|
634
|
+
assigned_at,
|
|
635
|
+
attributes,
|
|
636
|
+
id_project,
|
|
637
|
+
createdBy,
|
|
638
|
+
updatedBy: createdBy,
|
|
639
|
+
preflight,
|
|
640
|
+
channel,
|
|
641
|
+
location,
|
|
642
|
+
tags,
|
|
643
|
+
notes,
|
|
644
|
+
priority,
|
|
645
|
+
auto_close,
|
|
646
|
+
followers,
|
|
647
|
+
createdAt
|
|
808
648
|
})
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// DEPRECATED
|
|
812
|
-
// async _create(request) {
|
|
813
|
-
|
|
814
|
-
// var startDate = new Date();
|
|
815
|
-
|
|
816
|
-
// if (!request.createdAt) {
|
|
817
|
-
// request.createdAt = new Date();
|
|
818
|
-
// }
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
// var request_id = request.request_id;
|
|
822
|
-
// var project_user_id = request.project_user_id;
|
|
823
|
-
// var lead_id = request.lead_id;
|
|
824
|
-
// var id_project = request.id_project;
|
|
825
|
-
|
|
826
|
-
// var first_text = request.first_text;
|
|
827
|
-
|
|
828
|
-
// //removed for ticket
|
|
829
|
-
// // // lascia che sia nico a fare il replace...certo tu devi fare il test che tutto sia ok quindi dopo demo
|
|
830
|
-
// // var first_text;
|
|
831
|
-
// // if (request.first_text) { //first_text can be empty for type image
|
|
832
|
-
// // first_text = request.first_text.replace(/[\n\r]+/g, ' '); //replace new line with space
|
|
833
|
-
// // }
|
|
834
|
-
|
|
835
|
-
// var departmentid = request.departmentid;
|
|
836
|
-
// var sourcePage = request.sourcePage;
|
|
837
|
-
// var language = request.language;
|
|
838
|
-
// var userAgent = request.userAgent;
|
|
839
|
-
// var status = request.status;
|
|
840
|
-
// var createdBy = request.createdBy;
|
|
841
|
-
// var attributes = request.attributes;
|
|
842
|
-
// var subject = request.subject;
|
|
843
|
-
// var preflight = request.preflight;
|
|
844
|
-
// var channel = request.channel;
|
|
845
|
-
// var location = request.location;
|
|
846
|
-
// var participants = request.participants || [];
|
|
847
|
-
|
|
848
|
-
// var tags = request.tags;
|
|
849
|
-
// var notes = request.notes;
|
|
850
|
-
// var priority = request.priority;
|
|
851
|
-
|
|
852
|
-
// var auto_close = request.auto_close;
|
|
853
|
-
|
|
854
|
-
// var followers = request.followers;
|
|
855
|
-
// let createdAt = request.createdAt;
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
// if (!departmentid) {
|
|
859
|
-
// departmentid = 'default';
|
|
860
|
-
// }
|
|
861
|
-
|
|
862
|
-
// if (!createdBy) {
|
|
863
|
-
// if (project_user_id) {
|
|
864
|
-
// createdBy = project_user_id;
|
|
865
|
-
// } else {
|
|
866
|
-
// createdBy = "system";
|
|
867
|
-
// }
|
|
868
|
-
|
|
869
|
-
// }
|
|
870
|
-
|
|
871
|
-
// let isTestConversation = false;
|
|
872
|
-
// let isVoiceConversation = false;
|
|
873
|
-
|
|
874
|
-
// var that = this;
|
|
875
|
-
|
|
876
|
-
// return new Promise(async (resolve, reject) => {
|
|
877
|
-
|
|
878
|
-
// let q = Project.findOne({ _id: request.id_project, status: 100 });
|
|
879
|
-
// if (cacheEnabler.project) {
|
|
880
|
-
// q.cache(cacheUtil.longTTL, "projects:id:" + request.id_project) //project_cache
|
|
881
|
-
// winston.debug('project cache enabled for /project detail');
|
|
882
|
-
// }
|
|
883
|
-
// q.exec(async function (err, p) {
|
|
884
|
-
// if (err) {
|
|
885
|
-
// winston.error('Error getting project ', err);
|
|
886
|
-
// }
|
|
887
|
-
// if (!p) {
|
|
888
|
-
// winston.warn('Project not found ');
|
|
889
|
-
// }
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
// let payload = {
|
|
893
|
-
// project: p,
|
|
894
|
-
// request: request
|
|
895
|
-
// }
|
|
896
|
-
|
|
897
|
-
// if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
|
|
898
|
-
// winston.verbose("is a test conversation --> skip quote availability check")
|
|
899
|
-
// isTestConversation = true;
|
|
900
|
-
// }
|
|
901
|
-
// else if (channel && (channel.name === 'voice-vxml')) {
|
|
902
|
-
// winston.verbose("is a voice conversation --> skip quote availability check")
|
|
903
|
-
// isVoiceConversation = true;
|
|
904
|
-
// }
|
|
905
|
-
// else {
|
|
906
|
-
// // console.log("! check quota moved")
|
|
907
|
-
// // let available = await qm.checkQuote(p, request, 'requests');
|
|
908
|
-
// // if (available === false) {
|
|
909
|
-
// // winston.info("Requests limits reached for project " + p._id)
|
|
910
|
-
// // return false;
|
|
911
|
-
// // }
|
|
912
|
-
// }
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
// var context = {
|
|
916
|
-
// request: {
|
|
917
|
-
// request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
|
|
918
|
-
// first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
|
|
919
|
-
// createdBy: createdBy, attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location,
|
|
920
|
-
// participants: participants, tags: tags, notes: notes,
|
|
921
|
-
// priority: priority, auto_close: auto_close, followers: followers
|
|
922
|
-
// }
|
|
923
|
-
// };
|
|
924
|
-
|
|
925
|
-
// winston.debug("context", context);
|
|
926
|
-
|
|
927
|
-
// var participantsAgents = [];
|
|
928
|
-
// var participantsBots = [];
|
|
929
|
-
// var hasBot = false;
|
|
930
|
-
|
|
931
|
-
// var dep_id = undefined;
|
|
932
|
-
|
|
933
|
-
// var assigned_at = undefined;
|
|
934
|
-
|
|
935
|
-
// var agents = [];
|
|
936
|
-
|
|
937
|
-
// var snapshot = {};
|
|
938
|
-
|
|
939
|
-
// try {
|
|
940
|
-
// // getOperators(departmentid, projectid, nobot, disableWebHookCall, context) {
|
|
941
|
-
// var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
|
|
942
|
-
// // console.log("************* after get operator: "+new Date().toISOString());
|
|
943
|
-
|
|
944
|
-
// winston.debug("getOperators", result);
|
|
945
|
-
// } catch (err) {
|
|
946
|
-
// return reject(err);
|
|
947
|
-
// }
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
// agents = result.agents;
|
|
952
|
-
|
|
953
|
-
// if (status == 50) {
|
|
954
|
-
// // skip assignment
|
|
955
|
-
// if (participants.length == 0) {
|
|
956
|
-
// dep_id = result.department._id;
|
|
957
|
-
// }
|
|
958
|
-
// } else {
|
|
959
|
-
|
|
960
|
-
// if (participants.length == 0) {
|
|
961
|
-
// if (result.operators && result.operators.length > 0) {
|
|
962
|
-
// participants.push(result.operators[0].id_user.toString());
|
|
963
|
-
// }
|
|
964
|
-
// // for preflight it is important to save agents in req for trigger. try to optimize it
|
|
965
|
-
// dep_id = result.department._id;
|
|
966
|
-
|
|
967
|
-
// }
|
|
968
|
-
|
|
969
|
-
// if (participants.length > 0) {
|
|
970
|
-
|
|
971
|
-
// status = RequestConstants.ASSIGNED;
|
|
972
|
-
|
|
973
|
-
// /**
|
|
974
|
-
// * QUOTAS - START!!!
|
|
975
|
-
// */
|
|
976
|
-
// if (!isTestConversation && !isVoiceConversation) {
|
|
977
|
-
// requestEvent.emit('request.create.quote', payload);
|
|
978
|
-
// }
|
|
979
|
-
// /**
|
|
980
|
-
// * QUOTAS - END!!!
|
|
981
|
-
// */
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
// // botprefix
|
|
986
|
-
// if (participants[0].startsWith("bot_")) {
|
|
987
|
-
|
|
988
|
-
// hasBot = true;
|
|
989
|
-
// winston.debug("hasBot:" + hasBot);
|
|
990
|
-
|
|
991
|
-
// // botprefix
|
|
992
|
-
// var assigned_operator_idStringBot = participants[0].replace("bot_", "");
|
|
993
|
-
// winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
|
|
994
|
-
|
|
995
|
-
// participantsBots.push(assigned_operator_idStringBot);
|
|
996
|
-
|
|
997
|
-
// } else {
|
|
998
|
-
|
|
999
|
-
// participantsAgents.push(participants[0]);
|
|
1000
|
-
|
|
1001
|
-
// }
|
|
1002
|
-
|
|
1003
|
-
// assigned_at = Date.now();
|
|
1004
|
-
|
|
1005
|
-
// } else {
|
|
1006
|
-
|
|
1007
|
-
// status = RequestConstants.UNASSIGNED;
|
|
1008
|
-
|
|
1009
|
-
// }
|
|
1010
649
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
// if (dep_id) {
|
|
1017
|
-
// snapshot.department = result.department;
|
|
1018
|
-
// }
|
|
1019
|
-
|
|
1020
|
-
// // console.log("result.agents",result.agents);
|
|
1021
|
-
// snapshot.agents = agents;
|
|
1022
|
-
// snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
|
|
1023
|
-
|
|
1024
|
-
// if (request.requester) { //.toObject()????
|
|
1025
|
-
// snapshot.requester = request.requester;
|
|
1026
|
-
// }
|
|
1027
|
-
// if (request.lead) {
|
|
1028
|
-
// snapshot.lead = request.lead;
|
|
1029
|
-
// }
|
|
1030
|
-
|
|
1031
|
-
// // winston.debug("assigned_operator_id", assigned_operator_id);
|
|
1032
|
-
// // winston.debug("req status", status);
|
|
1033
|
-
|
|
1034
|
-
// var newRequest = new Request({
|
|
1035
|
-
// request_id: request_id,
|
|
1036
|
-
// requester: project_user_id,
|
|
1037
|
-
// lead: lead_id,
|
|
1038
|
-
// first_text: first_text,
|
|
1039
|
-
// subject: subject,
|
|
1040
|
-
// status: status,
|
|
1041
|
-
// participants: participants,
|
|
1042
|
-
// participantsAgents: participantsAgents,
|
|
1043
|
-
// participantsBots: participantsBots,
|
|
1044
|
-
// hasBot: hasBot,
|
|
1045
|
-
// department: dep_id,
|
|
1046
|
-
// // agents: agents,
|
|
1047
|
-
|
|
1048
|
-
// //others
|
|
1049
|
-
// sourcePage: sourcePage,
|
|
1050
|
-
// language: language,
|
|
1051
|
-
// userAgent: userAgent,
|
|
1052
|
-
// assigned_at: assigned_at,
|
|
1053
|
-
|
|
1054
|
-
// attributes: attributes,
|
|
1055
|
-
// //standard
|
|
1056
|
-
// id_project: id_project,
|
|
1057
|
-
// createdBy: createdBy,
|
|
1058
|
-
// updatedBy: createdBy,
|
|
1059
|
-
// preflight: preflight,
|
|
1060
|
-
// channel: channel,
|
|
1061
|
-
// location: location,
|
|
1062
|
-
// snapshot: snapshot,
|
|
1063
|
-
// tags: tags,
|
|
1064
|
-
// notes: notes,
|
|
1065
|
-
// priority: priority,
|
|
1066
|
-
// auto_close: auto_close,
|
|
1067
|
-
// followers: followers,
|
|
1068
|
-
// createdAt: createdAt
|
|
1069
|
-
// });
|
|
1070
|
-
|
|
1071
|
-
// if (isTestConversation) {
|
|
1072
|
-
// newRequest.draft = true;
|
|
1073
|
-
// }
|
|
1074
|
-
|
|
1075
|
-
// winston.debug('newRequest.', newRequest);
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
// //cacheinvalidation
|
|
1079
|
-
// return newRequest.save( async function (err, savedRequest) {
|
|
650
|
+
if (isTestConversation) {
|
|
651
|
+
newRequest.draft = true;
|
|
652
|
+
}
|
|
1080
653
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
// return reject(err);
|
|
1084
|
-
// }
|
|
654
|
+
winston.debug('newRequest.', newRequest);
|
|
655
|
+
winston.info("main_flow_cache_ requestService create");
|
|
1085
656
|
|
|
657
|
+
// Save request
|
|
658
|
+
try {
|
|
659
|
+
const savedRequest = await newRequest.save();
|
|
660
|
+
winston.debug("Request created", savedRequest.toObject());
|
|
1086
661
|
|
|
1087
|
-
|
|
662
|
+
/**
|
|
663
|
+
* Se non faccio findOne usando la cache adesso, quando verrà eseguita la query in reroute() la request non ha il department.
|
|
664
|
+
*/
|
|
665
|
+
let q = Request.findOne({ request_id, id_project });
|
|
666
|
+
if (cacheEnabler.request) {
|
|
667
|
+
q.cache(cacheUtil.defaultTTL, id_project + ":requests:request_id:" + request_id + ":simple");
|
|
668
|
+
winston.debug('request cache enabled');
|
|
669
|
+
}
|
|
670
|
+
await q.exec();
|
|
1088
671
|
|
|
1089
|
-
|
|
1090
|
-
// winston.verbose("Performance Request created in millis: " + endDate - startDate);
|
|
672
|
+
requestEvent.emit("request.create.simple", savedRequest);
|
|
1091
673
|
|
|
1092
|
-
|
|
674
|
+
if (isStandardConversation) {
|
|
675
|
+
requestEvent.emit("request.create.quote", payload);
|
|
676
|
+
}
|
|
1093
677
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
678
|
+
// Emit event to update snapshot in queue
|
|
679
|
+
if (Object.keys(snapshot).length > 0) {
|
|
680
|
+
requestEvent.emit("request.snapshot.update", {
|
|
681
|
+
request: savedRequest,
|
|
682
|
+
snapshot: snapshot
|
|
683
|
+
});
|
|
684
|
+
}
|
|
1097
685
|
|
|
1098
|
-
|
|
686
|
+
return savedRequest;
|
|
1099
687
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
688
|
+
} catch (err) {
|
|
689
|
+
winston.error(`RequestService error on save request ${newRequest.request_id}`, err);
|
|
690
|
+
throw new Error("RequestService error on save request", { cause: err });
|
|
691
|
+
}
|
|
1104
692
|
|
|
1105
|
-
|
|
1106
|
-
// });
|
|
1107
|
-
|
|
1108
|
-
// }
|
|
693
|
+
}
|
|
1109
694
|
|
|
1110
695
|
// DEPRECATED
|
|
1111
|
-
// async
|
|
1112
|
-
|
|
1113
|
-
// var startDate = new Date();
|
|
696
|
+
// async create(request) {
|
|
1114
697
|
|
|
1115
|
-
// if (!request.createdAt)
|
|
698
|
+
// if (!request.createdAt) {
|
|
1116
699
|
// request.createdAt = new Date();
|
|
1117
700
|
// }
|
|
1118
701
|
|
|
1119
|
-
|
|
1120
702
|
// var request_id = request.request_id;
|
|
1121
703
|
// var project_user_id = request.project_user_id;
|
|
1122
704
|
// var lead_id = request.lead_id;
|
|
1123
705
|
// var id_project = request.id_project;
|
|
1124
|
-
|
|
1125
706
|
// var first_text = request.first_text;
|
|
1126
|
-
|
|
1127
|
-
// //removed for ticket
|
|
1128
|
-
// // // lascia che sia nico a fare il replace...certo tu devi fare il test che tutto sia ok quindi dopo demo
|
|
1129
|
-
// // var first_text;
|
|
1130
|
-
// // if (request.first_text) { //first_text can be empty for type image
|
|
1131
|
-
// // first_text = request.first_text.replace(/[\n\r]+/g, ' '); //replace new line with space
|
|
1132
|
-
// // }
|
|
1133
|
-
|
|
1134
707
|
// var departmentid = request.departmentid;
|
|
1135
708
|
// var sourcePage = request.sourcePage;
|
|
1136
709
|
// var language = request.language;
|
|
@@ -1143,13 +716,10 @@ class RequestService {
|
|
|
1143
716
|
// var channel = request.channel;
|
|
1144
717
|
// var location = request.location;
|
|
1145
718
|
// var participants = request.participants || [];
|
|
1146
|
-
|
|
1147
719
|
// var tags = request.tags;
|
|
1148
720
|
// var notes = request.notes;
|
|
1149
721
|
// var priority = request.priority;
|
|
1150
|
-
|
|
1151
722
|
// var auto_close = request.auto_close;
|
|
1152
|
-
|
|
1153
723
|
// var followers = request.followers;
|
|
1154
724
|
// let createdAt = request.createdAt;
|
|
1155
725
|
|
|
@@ -1163,13 +733,16 @@ class RequestService {
|
|
|
1163
733
|
// } else {
|
|
1164
734
|
// createdBy = "system";
|
|
1165
735
|
// }
|
|
1166
|
-
|
|
1167
736
|
// }
|
|
1168
737
|
|
|
738
|
+
// // Utils
|
|
739
|
+
// let payload;
|
|
740
|
+
// let isTestConversation = false;
|
|
741
|
+
// let isVoiceConversation = false;
|
|
742
|
+
// let isStandardConversation = false;
|
|
1169
743
|
// var that = this;
|
|
1170
744
|
|
|
1171
|
-
// return new Promise(async (resolve, reject) => {
|
|
1172
|
-
|
|
745
|
+
// return new Promise( async (resolve, reject) => {
|
|
1173
746
|
// var context = {
|
|
1174
747
|
// request: {
|
|
1175
748
|
// request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
|
|
@@ -1179,33 +752,25 @@ class RequestService {
|
|
|
1179
752
|
// priority: priority, auto_close: auto_close, followers: followers
|
|
1180
753
|
// }
|
|
1181
754
|
// };
|
|
1182
|
-
|
|
1183
755
|
// winston.debug("context", context);
|
|
1184
756
|
|
|
1185
757
|
// var participantsAgents = [];
|
|
1186
758
|
// var participantsBots = [];
|
|
1187
759
|
// var hasBot = false;
|
|
1188
|
-
|
|
1189
760
|
// var dep_id = undefined;
|
|
1190
|
-
|
|
1191
761
|
// var assigned_at = undefined;
|
|
1192
|
-
|
|
1193
762
|
// var agents = [];
|
|
1194
|
-
|
|
1195
763
|
// var snapshot = {};
|
|
1196
764
|
|
|
1197
765
|
// try {
|
|
1198
|
-
// //
|
|
766
|
+
// // (method) DepartmentService.getOperators(departmentid: any, projectid: any, nobot: any, disableWebHookCall: any, context: any): Promise<any>
|
|
1199
767
|
// var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
|
|
1200
|
-
// // console.log("************* after get operator: "+new Date().toISOString());
|
|
1201
|
-
|
|
1202
768
|
// winston.debug("getOperators", result);
|
|
769
|
+
|
|
1203
770
|
// } catch (err) {
|
|
1204
771
|
// return reject(err);
|
|
1205
772
|
// }
|
|
1206
773
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
774
|
// agents = result.agents;
|
|
1210
775
|
|
|
1211
776
|
// if (status == 50) {
|
|
@@ -1215,19 +780,48 @@ class RequestService {
|
|
|
1215
780
|
// }
|
|
1216
781
|
// } else {
|
|
1217
782
|
|
|
783
|
+
// let project = await projectService.getCachedProject(id_project).catch((err) => {
|
|
784
|
+
// winston.warn("Error getting cached project. Skip conversation quota check.")
|
|
785
|
+
// winston.warn("Getting cached project error: ", err)
|
|
786
|
+
// })
|
|
787
|
+
|
|
788
|
+
// payload = {
|
|
789
|
+
// project: project,
|
|
790
|
+
// request: request
|
|
791
|
+
// }
|
|
792
|
+
|
|
793
|
+
// if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
|
|
794
|
+
// winston.verbose("is a test conversation --> skip quote availability check")
|
|
795
|
+
// isTestConversation = true;
|
|
796
|
+
// }
|
|
797
|
+
// else if (channel && (channel.name === 'voice-vxml')) {
|
|
798
|
+
// isVoiceConversation = true;
|
|
799
|
+
// let available = await qm.checkQuote(project, request, 'voice_duration');
|
|
800
|
+
// if (available === false) {
|
|
801
|
+
// winston.info("Voice duration limits reached for project " + project._id);
|
|
802
|
+
// return reject("Voice duration limits reached for project " + project._id);
|
|
803
|
+
// }
|
|
804
|
+
// }
|
|
805
|
+
// else {
|
|
806
|
+
// isStandardConversation = true;
|
|
807
|
+
// let available = await qm.checkQuote(project, request, 'requests');
|
|
808
|
+
// if (available === false) {
|
|
809
|
+
// winston.info("Requests limits reached for project " + project._id)
|
|
810
|
+
// return reject("Requests limits reached for project " + project._id);
|
|
811
|
+
// }
|
|
812
|
+
// }
|
|
813
|
+
|
|
814
|
+
|
|
1218
815
|
// if (participants.length == 0) {
|
|
1219
816
|
// if (result.operators && result.operators.length > 0) {
|
|
1220
817
|
// participants.push(result.operators[0].id_user.toString());
|
|
1221
818
|
// }
|
|
1222
819
|
// // for preflight it is important to save agents in req for trigger. try to optimize it
|
|
1223
820
|
// dep_id = result.department._id;
|
|
1224
|
-
|
|
1225
821
|
// }
|
|
1226
822
|
|
|
1227
823
|
// if (participants.length > 0) {
|
|
1228
|
-
|
|
1229
824
|
// status = RequestConstants.ASSIGNED;
|
|
1230
|
-
|
|
1231
825
|
// // botprefix
|
|
1232
826
|
// if (participants[0].startsWith("bot_")) {
|
|
1233
827
|
|
|
@@ -1249,34 +843,24 @@ class RequestService {
|
|
|
1249
843
|
// assigned_at = Date.now();
|
|
1250
844
|
|
|
1251
845
|
// } else {
|
|
1252
|
-
|
|
1253
846
|
// status = RequestConstants.UNASSIGNED;
|
|
1254
|
-
|
|
1255
847
|
// }
|
|
1256
|
-
|
|
1257
848
|
// }
|
|
1258
849
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
850
|
// if (dep_id) {
|
|
1263
851
|
// snapshot.department = result.department;
|
|
1264
852
|
// }
|
|
1265
853
|
|
|
1266
|
-
// // console.log("result.agents",result.agents);
|
|
1267
854
|
// snapshot.agents = agents;
|
|
1268
855
|
// snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
|
|
1269
856
|
|
|
1270
|
-
// if (request.requester) {
|
|
857
|
+
// if (request.requester) {
|
|
1271
858
|
// snapshot.requester = request.requester;
|
|
1272
859
|
// }
|
|
1273
860
|
// if (request.lead) {
|
|
1274
861
|
// snapshot.lead = request.lead;
|
|
1275
862
|
// }
|
|
1276
863
|
|
|
1277
|
-
// // winston.debug("assigned_operator_id", assigned_operator_id);
|
|
1278
|
-
// // winston.debug("req status", status);
|
|
1279
|
-
|
|
1280
864
|
// var newRequest = new Request({
|
|
1281
865
|
// request_id: request_id,
|
|
1282
866
|
// requester: project_user_id,
|
|
@@ -1290,13 +874,11 @@ class RequestService {
|
|
|
1290
874
|
// hasBot: hasBot,
|
|
1291
875
|
// department: dep_id,
|
|
1292
876
|
// // agents: agents,
|
|
1293
|
-
|
|
1294
877
|
// //others
|
|
1295
878
|
// sourcePage: sourcePage,
|
|
1296
879
|
// language: language,
|
|
1297
880
|
// userAgent: userAgent,
|
|
1298
881
|
// assigned_at: assigned_at,
|
|
1299
|
-
|
|
1300
882
|
// attributes: attributes,
|
|
1301
883
|
// //standard
|
|
1302
884
|
// id_project: id_project,
|
|
@@ -1305,7 +887,7 @@ class RequestService {
|
|
|
1305
887
|
// preflight: preflight,
|
|
1306
888
|
// channel: channel,
|
|
1307
889
|
// location: location,
|
|
1308
|
-
// snapshot: snapshot,
|
|
890
|
+
// //snapshot: snapshot,
|
|
1309
891
|
// tags: tags,
|
|
1310
892
|
// notes: notes,
|
|
1311
893
|
// priority: priority,
|
|
@@ -1314,62 +896,34 @@ class RequestService {
|
|
|
1314
896
|
// createdAt: createdAt
|
|
1315
897
|
// });
|
|
1316
898
|
|
|
1317
|
-
//
|
|
899
|
+
// if (isTestConversation) {
|
|
900
|
+
// newRequest.draft = true;
|
|
901
|
+
// }
|
|
1318
902
|
|
|
903
|
+
// winston.debug('newRequest.', newRequest);
|
|
1319
904
|
|
|
1320
905
|
// //cacheinvalidation
|
|
1321
|
-
// return newRequest.save(function (err, savedRequest) {
|
|
906
|
+
// return newRequest.save( async function (err, savedRequest) {
|
|
1322
907
|
|
|
1323
908
|
// if (err) {
|
|
1324
909
|
// winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
|
|
1325
910
|
// return reject(err);
|
|
1326
911
|
// }
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
912
|
// winston.debug("Request created", savedRequest.toObject());
|
|
1330
913
|
|
|
1331
|
-
// var endDate = new Date();
|
|
1332
|
-
// winston.verbose("Performance Request created in millis: " + endDate - startDate);
|
|
1333
|
-
|
|
1334
914
|
// requestEvent.emit('request.create.simple', savedRequest);
|
|
1335
915
|
|
|
1336
|
-
//
|
|
1337
|
-
// if (cacheEnabler.project) {
|
|
1338
|
-
// q.cache(cacheUtil.longTTL, "projects:id:" + request.id_project) //project_cache
|
|
1339
|
-
// winston.debug('project cache enabled for /project detail');
|
|
1340
|
-
// }
|
|
1341
|
-
// q.exec(async function (err, p) {
|
|
1342
|
-
// if (err) {
|
|
1343
|
-
// winston.error('Error getting project ', err);
|
|
1344
|
-
// }
|
|
1345
|
-
// if (!p) {
|
|
1346
|
-
// winston.warn('Project not found ');
|
|
1347
|
-
// }
|
|
1348
|
-
// //TODO REMOVE settings from project
|
|
1349
|
-
// let payload = {
|
|
1350
|
-
// project: p,
|
|
1351
|
-
// request: request
|
|
1352
|
-
// }
|
|
1353
|
-
|
|
916
|
+
// if (isStandardConversation) {
|
|
1354
917
|
// requestEvent.emit('request.create.quote', payload);;
|
|
1355
|
-
|
|
1356
|
-
// });
|
|
918
|
+
// }
|
|
1357
919
|
|
|
1358
920
|
// return resolve(savedRequest);
|
|
1359
921
|
|
|
1360
922
|
// });
|
|
1361
|
-
//
|
|
1362
|
-
// // return reject(err);
|
|
1363
|
-
// // });
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
// });
|
|
923
|
+
// })
|
|
1367
924
|
// }
|
|
1368
925
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
926
|
+
|
|
1373
927
|
//DEPRECATED. USED ONLY IN SAME TESTS
|
|
1374
928
|
createWithId(request_id, requester_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes) {
|
|
1375
929
|
|
|
@@ -2921,6 +2475,31 @@ class RequestService {
|
|
|
2921
2475
|
})
|
|
2922
2476
|
}
|
|
2923
2477
|
|
|
2478
|
+
emitParticipantsEvents(beforeRequest, requestComplete, oldParticipants) {
|
|
2479
|
+
const newParticipants = requestComplete.participants;
|
|
2480
|
+
|
|
2481
|
+
const removedParticipants = oldParticipants.filter(
|
|
2482
|
+
p => !newParticipants.includes(p)
|
|
2483
|
+
);
|
|
2484
|
+
const addedParticipants = newParticipants.filter(
|
|
2485
|
+
p => !oldParticipants.includes(p)
|
|
2486
|
+
);
|
|
2487
|
+
|
|
2488
|
+
requestEvent.emit("request.update", requestComplete);
|
|
2489
|
+
requestEvent.emit("request.updated", {
|
|
2490
|
+
comment: "REROUTE",
|
|
2491
|
+
request: requestComplete,
|
|
2492
|
+
patch: { removedParticipants, addedParticipants }
|
|
2493
|
+
});
|
|
2494
|
+
|
|
2495
|
+
requestEvent.emit("request.participants.update", {
|
|
2496
|
+
beforeRequest,
|
|
2497
|
+
removedParticipants,
|
|
2498
|
+
addedParticipants,
|
|
2499
|
+
request: requestComplete
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2924
2503
|
|
|
2925
2504
|
}
|
|
2926
2505
|
|