d5f87d384c6e229e79057416690c30db19ed8afc
[motion.git] / server / config / kue.mail.js
1   'use strict';
2
3   var _ = require('lodash');
4   var moment = require('moment');
5
6   var MailApplication = require('../models').MailApplication;
7   var MailAccount = require('../models').MailAccount;
8   var MailQueue = require('../models').MailQueue;
9   var MailRoom = require('../models').MailRoom;
10   var Interval = require('../models').Interval;
11
12   var ReportMailSession = require('../models').ReportMailSession;
13   var ReportMail = require('../models').ReportMail;
14
15   var User = require('../models').User;
16
17   var timeouts = {};
18
19   module.exports = function(kue) {
20     var kueMail = kue.createQueue();
21     // KUE PROCESS
22     kueMail.process('mail', 20, function(job, done) {
23       onProcess(job, done);
24     });
25     // REPORT MAIL HOOKS
26     ReportMail.afterUpdate(function(doc) {
27       if (doc.changed('agentconnectedAt')) {
28         if (timeouts[doc.uniqueid]) {
29           clearTimeout(timeouts[doc.uniqueid].timeout);
30           timeouts[doc.uniqueid].done();
31           delete timeouts[doc.uniqueid];
32         }
33
34         MailRoom
35           .findById(doc.uniqueid)
36           .then(function(mailRoom) {
37             mailRoom
38               .update({
39                 UserId: doc.agentid
40               })
41           })
42           .catch(function(err) {
43             console.error(err);
44           });
45
46         ReportMail
47           .update({
48             agentringnoanswerAt: moment().format("YYYY-MM-DD HH:mm:ss"),
49             reason: "answered_elsewhere",
50             lastevent: "answered_elsewhere"
51           }, {
52             where: {
53               uniqueid: doc.uniqueid,
54               reason: null
55             },
56             individualHooks: true
57           })
58           .catch(function(err) {
59             console.error(err);
60           });
61
62         ReportMailSession
63           .update({
64             mailleaveAt: moment().format("YYYY-MM-DD HH:mm:ss"),
65             fullname: doc.fullname,
66             membername: doc.membername,
67             mailqueuename: doc.mailqueuename
68           }, {
69             where: {
70               uniqueid: doc.uniqueid,
71             },
72             individualHooks: true
73           })
74           .catch(function(err) {
75             console.error(err);
76           });
77       }
78     });
79     // MAIL ROOM HOOKS
80     MailRoom.afterCreate(function(doc) {
81       onSave(kueMail, doc);
82     });
83     MailRoom.afterDestroy(function(doc) {
84       onSave(kueMail, doc);
85     });
86   };
87
88   function onSave(kue, doc, cb) {
89     if (doc.status === 'NEW') {
90       // CREATE KUE PROCESS
91       kue.create('mail', doc.dataValues).save();
92     }
93   }
94
95   function onProcess(job, done) {
96     MailAccount
97       .findById(job.data.MailAccountId, {
98         include: [{
99           model: MailApplication,
100           include: [{
101             model: MailQueue,
102             include: [{
103               model: User
104             }]
105           }, {
106             model: User
107           }, {
108             model: Interval,
109             include: [{
110               all: true
111             }]
112           }]
113         }]
114       })
115       .then(function(mailAccount) {
116         if (!mailAccount) {
117           done(new Error('No Available MailApplications..'));
118           return;
119         }
120
121         if (!mailAccount.MailApplications.length) {
122           done(new Error('DialPlan ended..'));
123           return;
124         }
125
126         job.data.MailRoomId = job.data.id;
127         var session = _.merge(job.data, mailAccount.dataValues);
128
129         onReportSession({
130           uniqueid: session.MailRoomId,
131           subject: session.subject,
132           from: session.from,
133           cc: session.cc,
134           attachment: session.attachment,
135           accountname: session.name,
136           accountaddress: session.address,
137           mailjoinAt: moment().format("YYYY-MM-DD HH:mm:ss")
138         });
139
140         session.MailApplications = _.sortBy(session.MailApplications, 'priority');
141         onInvite(session, 0, 0, 0, 0, done);
142       })
143       .catch(function(err) {
144         console.error(err);
145       });
146   }
147
148   function onInvite(data, i, j, holdtime, count, done) {
149     console.log('invite', 'i', i, 'j', j, 'holdtime', holdtime);
150     var timeout = 0;
151     var aTimeout;
152
153     if (i === data.MailApplications.length) {
154       console.error('DialPlan ended..');
155
156       onReportSession({
157         uniqueid: data.MailRoomId,
158         mailunmanagedAt: moment().format("YYYY-MM-DD HH:mm:ss"),
159         mailleaveAt: moment().format("YYYY-MM-DD HH:mm:ss")
160       });
161
162       done(new Error('DialPlan ended..'));
163       return;
164     }
165
166     if (data.MailApplications[i].MailQueue) {
167       // QUEUE APPLICATION
168
169       // ONLINE AGENTS COUNTER
170       var online = _.countBy(data.MailApplications[i].MailQueue.Users, {
171         online: true
172       }).true;
173
174       if (online && onInterval(data.MailApplications[i].Interval ? data.MailApplications[i].Interval : data.MailApplications[i].interval)) {
175         // AT LEAST ONE AVAILABLE AGENT
176         if (j === data.MailApplications[i].MailQueue.Users.length) {
177           if (data.MailApplications[i].timeout > holdtime) {
178             onInvite(data, i, 0, holdtime, count, done);
179             return;
180           } else {
181             onInvite(data, ++i, 0, 0, count, done);
182             return;
183           }
184         }
185
186         switch (data.MailApplications[i].MailQueue.strategy) {
187           case 'rrmemory':
188             if (data.MailApplications[i].MailQueue.Users[j].online &&
189               onInterval(data.MailApplications[i].Interval ? data.MailApplications[i].Interval : data.MailApplications[i].interval)) {
190               // AVAILABLE
191               timeout = (((data.MailApplications[i].timeout - holdtime) > data.MailApplications[i].MailQueue.timeout) ?
192                 data.MailApplications[i].MailQueue.timeout : (data.MailApplications[i].timeout - holdtime));
193
194               onReport({
195                 uniqueid: data.MailRoomId,
196                 sorting: count,
197                 subject: data.subject,
198                 timeslot: timeout,
199                 from: data.from,
200                 attachment: data.attachment,
201                 accountname: data.name,
202                 accountaddress: data.address,
203                 application: data.MailApplications[i].app,
204                 fullname: data.MailApplications[i].MailQueue.Users[j].fullname,
205                 membername: data.MailApplications[i].MailQueue.Users[j].name,
206                 agentid: data.MailApplications[i].MailQueue.Users[j].id,
207                 mailqueuename: data.MailApplications[i].MailQueue.name,
208                 lastevent: 'called',
209                 holdtime: holdtime,
210                 agentcalledAt: moment().format("YYYY-MM-DD HH:mm:ss")
211               });
212
213               console.log('queue', data.MailApplications[i].MailQueue.name, 'agent', data.MailApplications[i].MailQueue.Users[j].name, 'timeout', timeout, 'holdtime', holdtime);
214               aTimeout = setTimeout(function() {
215                 onReportUpdate({
216                   uniqueid: data.MailRoomId,
217                   count: count,
218                   reason: 'timeout',
219                   lastevent: 'timeout',
220                   agentringnoanswerAt: moment().format("YYYY-MM-DD HH:mm:ss")
221                 });
222
223                 holdtime += timeout;
224                 onInvite(data, i, ++j, holdtime, ++count, done);
225                 return;
226               }, timeout * 1000);
227
228               if (!timeouts[data.MailRoomId]) {
229                 timeouts[data.MailRoomId] = {};
230               }
231
232               timeouts[data.MailRoomId].timeout = aTimeout;
233               timeouts[data.MailRoomId].done = done;
234
235             } else {
236               onInvite(data, i, ++j, holdtime, count, done);
237               return;
238             }
239
240             break;
241           case 'beepall':
242
243             timeout = (((data.MailApplications[i].timeout - holdtime) > data.MailApplications[i].MailQueue.timeout) ?
244               data.MailApplications[i].MailQueue.timeout : (data.MailApplications[i].timeout - holdtime));
245
246             var users = [];
247             data.MailApplications[i].MailQueue.Users.forEach(function(user) {
248               if (user.online) {
249                 users.push({
250                   uniqueid: data.MailRoomId,
251                   sorting: count,
252                   subject: data.subject,
253                   timeslot: timeout,
254                   from: data.from,
255                   attachment: data.attachment,
256                   accountname: data.name,
257                   accountaddress: data.address,
258                   application: data.MailApplications[i].app,
259                   fullname: user.fullname,
260                   membername: user.name,
261                   agentid: user.id,
262                   mailqueuename: data.MailApplications[i].MailQueue.name,
263                   lastevent: 'called',
264                   holdtime: holdtime,
265                   agentcalledAt: moment().format("YYYY-MM-DD HH:mm:ss")
266                 });
267               }
268             });
269
270             if (users.length && onInterval(data.MailApplications[i].Interval ? data.MailApplications[i].Interval : data.MailApplications[i].interval)) {
271               onReport(users, true);
272               aTimeout = setTimeout(function() {
273                 console.log('count', count);
274                 onReportUpdate({
275                   uniqueid: data.MailRoomId,
276                   count: count,
277                   reason: 'timeout',
278                   lastevent: 'timeout',
279                   agentringnoanswerAt: moment().format("YYYY-MM-DD HH:mm:ss")
280                 });
281                 holdtime += timeout;
282                 j += data.MailApplications[i].MailQueue.Users.length;
283                 onInvite(data, i, j, holdtime, ++count, done);
284                 return;
285               }, timeout * 1000);
286
287               if (!timeouts[data.MailRoomId]) {
288                 timeouts[data.MailRoomId] = {};
289               }
290
291               timeouts[data.MailRoomId].timeout = aTimeout;
292               timeouts[data.MailRoomId].done = done;
293
294             } else {
295               console.log('queue', data.MailApplications[i].MailQueue.name, 'timeout', timeout, 'holdtime', holdtime);
296
297               onInvite(data, ++i, 0, 0, count, done);
298               return;
299             }
300
301             break;
302           default:
303             console.error('Unknown strategy');
304         }
305       } else {
306         onInvite(data, ++i, 0, 0, count, done);
307         return;
308       }
309     } else {
310       // AGENT APPLICATION
311       timeout = data.MailApplications[i].timeout;
312       if (data.MailApplications[i].User.online &&
313         onInterval(data.MailApplications[i].Interval ? data.MailApplications[i].Interval : data.MailApplications[i].interval)) {
314         onReport({
315           uniqueid: data.MailRoomId,
316           sorting: count,
317           subject: data.subject,
318           timeslot: timeout,
319           from: data.from,
320           attachment: data.attachment,
321           accountname: data.name,
322           accountaddress: data.address,
323           application: data.MailApplications[i].app,
324           fullname: data.MailApplications[i].User.fullname,
325           membername: data.MailApplications[i].User.name,
326           agentid: data.MailApplications[i].User.id,
327           lastevent: 'called',
328           holdtime: holdtime,
329           agentcalledAt: moment().format("YYYY-MM-DD HH:mm:ss")
330         });
331
332         console.log('agent', data.MailApplications[i].User.name, 'timeout', timeout, 'holdtime', holdtime);
333
334         aTimeout = setTimeout(function() {
335           onReportUpdate({
336             uniqueid: data.MailRoomId,
337             count: count,
338             reason: 'timeout',
339             lastevent: 'timeout',
340             agentringnoanswerAt: moment().format("YYYY-MM-DD HH:mm:ss")
341           });
342
343           onInvite(data, ++i, 0, 0, count, done);
344           return;
345         }, timeout * 1000);
346
347         if (!timeouts[data.MailRoomId]) {
348           timeouts[data.MailRoomId] = {};
349         }
350
351         timeouts[data.MailRoomId].timeout = aTimeout;
352         timeouts[data.MailRoomId].done = done;
353       } else {
354         onInvite(data, ++i, 0, 0, ++count, done);
355         return
356       }
357     }
358   }
359
360   function onReport(report, bulk) {
361     if (bulk) {
362       ReportMail
363         .bulkCreate(report, {
364           individualHooks: true
365         })
366         .catch(function(err) {
367           console.error(err);
368         });
369     } else {
370       ReportMail
371         .create(report)
372         .catch(function(err) {
373           console.error(err);
374         });
375     }
376   }
377
378   function onReportSession(report) {
379
380     ReportMailSession
381       .findOrCreate({
382         where: {
383           uniqueid: report.uniqueid
384         },
385         defaults: report
386       })
387       .spread(function(reportMailSession, created) {
388         if (!created) {
389           reportMailSession
390             .update(report, {
391               individualHooks: true
392             })
393             .catch(function(err) {
394               console.error(err);
395             });
396         }
397       });
398   }
399
400   function onReportUpdate(report) {
401     ReportMail
402       .update(report, {
403         where: {
404           uniqueid: report.uniqueid,
405           sorting: report.count
406         },
407         individualHooks: true
408       })
409       .catch(function(err) {
410         console.error(err);
411       });
412   }
413
414   function onInterval(interval) {
415     if (_.isObject(interval)) {
416       for (var i = 0; i < interval.SubIntervals.length; i++) {
417         if (!onCheckInterval(interval.SubIntervals[i].interval)) {
418           return false;
419         }
420       }
421       return true;
422     } else {
423       return onCheckInterval(interval);
424     }
425   }
426
427   function onCheckInterval(interval) {
428
429     var daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
430     var daysOfMonth = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
431     var months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
432     var i, shift;
433
434     var tRange = interval.split(',')[0];
435     var dwRange = interval.split(',')[1];
436     var dmRange = interval.split(',')[2];
437     var mRange = interval.split(',')[3];
438     // TIME RANGE CHECKING
439     if (tRange !== '*') {
440       var time = moment().format("HH:mm");
441       var tFrom = tRange.split('-')[0];
442       var tTo = tRange.split('-')[1];
443
444       if ((time < tFrom) || (time > tTo)) {
445         console.log('TRANGE KO');
446         return false;
447       }
448     }
449     // DAYS OF WEEK RANGE CHECKING
450     if (dwRange !== '*') {
451       var cWeekDay = daysOfWeek[moment().day()];
452       var dwFrom = _.indexOf(daysOfWeek, dwRange.split('-')[0]);
453       var dwTo = _.indexOf(daysOfWeek, dwRange.split('-')[1]);
454
455       for (i = 0; i < dwFrom; i++) {
456         shift = daysOfWeek.shift();
457         daysOfWeek.push(shift);
458       }
459
460       dwFrom = _.indexOf(daysOfWeek, dwRange.split('-')[0]);
461       dwTo = _.indexOf(daysOfWeek, dwRange.split('-')[1]) + 1;
462
463       daysOfWeek = daysOfWeek.slice(dwFrom, dwTo);
464
465       if (!_.includes(daysOfWeek, cWeekDay)) {
466         console.log('DWRANGE KO');
467         return false;
468       }
469     }
470     // DAYS OF MONTH RANGE CHECKING
471     if (dmRange !== '*') {
472       var cMonthDay = moment().date();
473       var dmFrom = _.indexOf(daysOfMonth, parseInt(dmRange.split('-')[0], 10));
474       var dmTo = _.indexOf(daysOfMonth, parseInt(dmRange.split('-')[1]));
475
476       for (i = 0; i < dmFrom; i++) {
477         shift = daysOfMonth.shift();
478         daysOfMonth.push(shift);
479       }
480
481       dmFrom = _.indexOf(daysOfMonth, parseInt(dmRange.split('-')[0], 10));
482       dmTo = _.indexOf(daysOfMonth, parseInt(dmRange.split('-')[1]), 10) + 1;
483
484       daysOfMonth = daysOfMonth.slice(dmFrom, dmTo);
485
486       if (!_.includes(daysOfMonth, cMonthDay)) {
487         console.log('DMRANGE KO');
488         return false;
489       }
490     }
491     // MONTHS RANGE CHECKING
492     if (mRange !== '*') {
493       var cMonth = months[moment().month()];
494       var mFrom = _.indexOf(months, mRange.split('-')[0]);
495       var mTo = _.indexOf(months, mRange.split('-')[1]);
496
497       for (i = 0; i < mFrom; i++) {
498         shift = months.shift();
499         months.push(shift);
500       }
501
502       mFrom = _.indexOf(months, mRange.split('-')[0]);
503       mTo = _.indexOf(months, mRange.split('-')[1]) + 1;
504
505       months = months.slice(mFrom, mTo);
506
507       if (!_.includes(months, cMonth)) {
508         console.log('MRANGE KO');
509         return false;
510       }
511     }
512
513     console.log('INTERVAL OK');
514
515     return true;
516   }