shuttlepro-shared 1.4.14 → 1.4.16
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.
|
@@ -35,13 +35,21 @@ class CallRepository {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
async getCall(callId) {
|
|
39
|
+
try {
|
|
40
|
+
return await Call.findOne({ callId }).lean().exec();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(`❌ Failed to end call ${callId}:`, error);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
async endCall(callId, agentId = null, updateObj = {}, callHistory = {}) {
|
|
39
48
|
try {
|
|
40
49
|
return await Call.findOneAndUpdate(
|
|
41
50
|
{ callId },
|
|
42
51
|
{
|
|
43
52
|
$set: {
|
|
44
|
-
...(updateObj?.status === "ended" ? { endTime: new Date() } : {}),
|
|
45
53
|
...updateObj,
|
|
46
54
|
},
|
|
47
55
|
$push: {
|
|
@@ -193,18 +201,54 @@ class CallRepository {
|
|
|
193
201
|
|
|
194
202
|
/* ----------------- Query Helpers ----------------- */
|
|
195
203
|
|
|
196
|
-
async getCallsByWorkspace(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
async getCallsByWorkspace(
|
|
205
|
+
workspaceId,
|
|
206
|
+
{
|
|
207
|
+
filters = {},
|
|
208
|
+
select = null,
|
|
209
|
+
sortBy = { createdAt: -1 },
|
|
210
|
+
limit = null,
|
|
211
|
+
skip = null,
|
|
212
|
+
} = {}
|
|
213
|
+
) {
|
|
214
|
+
let query = Call.find({ workspaceId, ...filters })
|
|
215
|
+
.select(select || {}) // if null → select all fields
|
|
216
|
+
.sort(sortBy) // default newest first
|
|
217
|
+
.lean();
|
|
218
|
+
|
|
219
|
+
if (limit !== null) {
|
|
220
|
+
query = query.limit(limit);
|
|
221
|
+
}
|
|
222
|
+
if (skip !== null) {
|
|
223
|
+
query = query.skip(skip);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return query.exec();
|
|
201
227
|
}
|
|
202
228
|
|
|
203
|
-
async getCallsByAgent(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
229
|
+
async getCallsByAgent(
|
|
230
|
+
agentId,
|
|
231
|
+
{
|
|
232
|
+
filters = {},
|
|
233
|
+
select = null,
|
|
234
|
+
sortBy = { createdAt: -1 },
|
|
235
|
+
limit = null,
|
|
236
|
+
skip = null,
|
|
237
|
+
} = {}
|
|
238
|
+
) {
|
|
239
|
+
let query = Call.find({ agentId, ...filters })
|
|
240
|
+
.select(select || {}) // if null → select all fields
|
|
241
|
+
.sort(sortBy) // default newest first
|
|
242
|
+
.lean();
|
|
243
|
+
|
|
244
|
+
if (limit !== null) {
|
|
245
|
+
query = query.limit(limit);
|
|
246
|
+
}
|
|
247
|
+
if (skip !== null) {
|
|
248
|
+
query = query.skip(skip);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return query.exec();
|
|
208
252
|
}
|
|
209
253
|
|
|
210
254
|
async getCallsByReceiver(receiver, filters = {}) {
|
|
@@ -236,45 +280,109 @@ class CallRepository {
|
|
|
236
280
|
/* ----------------- Reporting & Analytics ----------------- */
|
|
237
281
|
|
|
238
282
|
// Stats grouped by agent
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
283
|
+
// Stats grouped by agent
|
|
284
|
+
async getAgentStats({ from, to }, filters = {}) {
|
|
285
|
+
const result = await Call.aggregate([
|
|
286
|
+
{
|
|
287
|
+
$match: {
|
|
288
|
+
createdAt: { $gte: from, $lte: to },
|
|
289
|
+
...filters,
|
|
290
|
+
},
|
|
291
|
+
},
|
|
242
292
|
{
|
|
243
293
|
$group: {
|
|
244
294
|
_id: "$agentId",
|
|
245
295
|
totalCalls: { $sum: 1 },
|
|
246
|
-
|
|
247
|
-
$sum: { $cond: [{ $eq: ["$status", "
|
|
296
|
+
pending: {
|
|
297
|
+
$sum: { $cond: [{ $eq: ["$status", "pending"] }, 1, 0] },
|
|
298
|
+
},
|
|
299
|
+
abandoned: {
|
|
300
|
+
$sum: { $cond: [{ $eq: ["$status", "abandoned"] }, 1, 0] },
|
|
248
301
|
},
|
|
249
302
|
ended: {
|
|
250
303
|
$sum: { $cond: [{ $eq: ["$status", "ended"] }, 1, 0] },
|
|
251
304
|
},
|
|
252
|
-
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
$project: {
|
|
309
|
+
_id: 0,
|
|
310
|
+
agentId: "$_id",
|
|
311
|
+
totalCalls: 1,
|
|
312
|
+
pending: 1,
|
|
313
|
+
abandoned: 1,
|
|
314
|
+
ended: 1,
|
|
253
315
|
},
|
|
254
316
|
},
|
|
255
317
|
]);
|
|
318
|
+
|
|
319
|
+
if (filters.agentId) {
|
|
320
|
+
// single agent case
|
|
321
|
+
return (
|
|
322
|
+
result.find((r) => r.agentId === filters.agentId) || {
|
|
323
|
+
agentId: filters.agentId,
|
|
324
|
+
totalCalls: 0,
|
|
325
|
+
pending: 0,
|
|
326
|
+
abandoned: 0,
|
|
327
|
+
ended: 0,
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// multi-agent case
|
|
333
|
+
if (result.length === 0) {
|
|
334
|
+
return [];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return result;
|
|
256
338
|
}
|
|
257
339
|
|
|
258
340
|
// Daily call summary
|
|
259
|
-
async getDailySummary(workspaceId, from, to) {
|
|
341
|
+
async getDailySummary(workspaceId, from, to, filters = {}, groupBy = null) {
|
|
342
|
+
const matchStage = {
|
|
343
|
+
workspaceId,
|
|
344
|
+
createdAt: { $gte: from, $lte: to },
|
|
345
|
+
...filters,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const groupId = {
|
|
349
|
+
day: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } },
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// If admin wants to group by agentId / receiver / platformId
|
|
353
|
+
if (groupBy && ["agentId", "receiver", "platformId"].includes(groupBy)) {
|
|
354
|
+
groupId[groupBy] = `$${groupBy}`;
|
|
355
|
+
}
|
|
356
|
+
|
|
260
357
|
return Call.aggregate([
|
|
261
|
-
{ $match:
|
|
358
|
+
{ $match: matchStage },
|
|
262
359
|
{
|
|
263
360
|
$group: {
|
|
264
|
-
_id:
|
|
265
|
-
day: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } },
|
|
266
|
-
},
|
|
361
|
+
_id: groupId,
|
|
267
362
|
total: { $sum: 1 },
|
|
268
|
-
ended: {
|
|
269
|
-
$sum: { $cond: [{ $eq: ["$status", "ended"] }, 1, 0] },
|
|
270
|
-
},
|
|
363
|
+
ended: { $sum: { $cond: [{ $eq: ["$status", "ended"] }, 1, 0] } },
|
|
271
364
|
abandoned: {
|
|
272
365
|
$sum: { $cond: [{ $eq: ["$status", "abandoned"] }, 1, 0] },
|
|
273
366
|
},
|
|
274
367
|
avgDuration: { $avg: "$duration" },
|
|
368
|
+
minDuration: { $min: "$duration" },
|
|
369
|
+
maxDuration: { $max: "$duration" },
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
$project: {
|
|
374
|
+
_id: 0,
|
|
375
|
+
day: "$_id.day",
|
|
376
|
+
groupBy: groupBy ? `$_id.${groupBy}` : null,
|
|
377
|
+
total: 1,
|
|
378
|
+
ended: 1,
|
|
379
|
+
abandoned: 1,
|
|
380
|
+
avgDuration: { $round: ["$avgDuration", 2] }, // round to 2 decimals
|
|
381
|
+
minDuration: 1,
|
|
382
|
+
maxDuration: 1,
|
|
275
383
|
},
|
|
276
384
|
},
|
|
277
|
-
{ $sort: {
|
|
385
|
+
{ $sort: { day: 1 } },
|
|
278
386
|
]);
|
|
279
387
|
}
|
|
280
388
|
|