@talkpilot/core-db 1.3.5 → 1.3.7
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/.cursor/rules/development.mdc +65 -65
- package/DEVELOPMENT.md +141 -126
- package/README.md +190 -190
- package/README_OLD.md +160 -160
- package/dist/talkpilot/calls/calls.types.d.ts +5 -0
- package/dist/talkpilot/calls/calls.types.d.ts.map +1 -1
- package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts +19 -0
- package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts.map +1 -0
- package/dist/talkpilot/contextNotes/contextNotes.getters.js +57 -0
- package/dist/talkpilot/contextNotes/contextNotes.getters.js.map +1 -0
- package/dist/talkpilot/contextNotes/contextNotes.types.d.ts +19 -0
- package/dist/talkpilot/contextNotes/contextNotes.types.d.ts.map +1 -0
- package/dist/talkpilot/contextNotes/contextNotes.types.js +3 -0
- package/dist/talkpilot/contextNotes/contextNotes.types.js.map +1 -0
- package/dist/talkpilot/contextNotes/index.d.ts +3 -0
- package/dist/talkpilot/contextNotes/index.d.ts.map +1 -0
- package/dist/talkpilot/contextNotes/index.js +19 -0
- package/dist/talkpilot/contextNotes/index.js.map +1 -0
- package/dist/talkpilot/flows/flows.schema.d.ts +3 -0
- package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.js +1 -0
- package/dist/talkpilot/flows/flows.schema.js.map +1 -1
- package/dist/talkpilot/flows/flows.types.d.ts +2 -0
- package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
- package/dist/talkpilot/index.d.ts +2 -0
- package/dist/talkpilot/index.d.ts.map +1 -1
- package/dist/talkpilot/index.js +2 -0
- package/dist/talkpilot/index.js.map +1 -1
- package/dist/talkpilot/products/index.d.ts +3 -0
- package/dist/talkpilot/products/index.d.ts.map +1 -0
- package/dist/talkpilot/products/index.js +19 -0
- package/dist/talkpilot/products/index.js.map +1 -0
- package/dist/talkpilot/products/products.getters.d.ts +6 -0
- package/dist/talkpilot/products/products.getters.d.ts.map +1 -0
- package/dist/talkpilot/products/products.getters.js +14 -0
- package/dist/talkpilot/products/products.getters.js.map +1 -0
- package/dist/talkpilot/products/products.types.d.ts +9 -0
- package/dist/talkpilot/products/products.types.d.ts.map +1 -0
- package/dist/talkpilot/products/products.types.js +3 -0
- package/dist/talkpilot/products/products.types.js.map +1 -0
- package/dist/test-utils/factories/index.d.ts +1 -0
- package/dist/test-utils/factories/index.d.ts.map +1 -1
- package/dist/test-utils/factories/index.js +1 -0
- package/dist/test-utils/factories/index.js.map +1 -1
- package/dist/test-utils/factories/talkpilot/contextNotes.d.ts +16 -0
- package/dist/test-utils/factories/talkpilot/contextNotes.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/contextNotes.js +30 -0
- package/dist/test-utils/factories/talkpilot/contextNotes.js.map +1 -0
- package/jest.config.js +20 -19
- package/package.json +46 -46
- package/src/__tests__/setup.ts +20 -20
- package/src/connection.ts +54 -54
- package/src/index.ts +26 -26
- package/src/municipal/__tests__/validation.spec.ts +62 -62
- package/src/municipal/cities/cities.getters.ts +50 -50
- package/src/municipal/cities/cities.types.ts +11 -11
- package/src/municipal/cities/index.ts +2 -2
- package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +282 -282
- package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +72 -72
- package/src/municipal/departmentsSubjects/index.ts +9 -9
- package/src/municipal/index.ts +22 -22
- package/src/municipal/mongodb-client.ts +61 -61
- package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +92 -92
- package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +92 -92
- package/src/municipal/muniIssues/index.ts +17 -17
- package/src/municipal/muniIssues/muniIssues.constants.ts +18 -18
- package/src/municipal/muniIssues/muniIssues.getters.ts +24 -24
- package/src/municipal/muniIssues/muniIssues.schema.ts +66 -66
- package/src/municipal/muniIssues/muniIssues.setters.ts +24 -24
- package/src/municipal/muniIssues/muniIssues.setup.ts +65 -65
- package/src/municipal/muniIssues/muniIssues.types.ts +37 -37
- package/src/municipal/streets/index.ts +2 -2
- package/src/municipal/streets/streets.getters.ts +125 -125
- package/src/municipal/streets/streets.types.ts +18 -18
- package/src/municipal/systemInstructions/__tests__/getters.spec.ts +113 -113
- package/src/municipal/systemInstructions/__tests__/setters.spec.ts +274 -274
- package/src/municipal/systemInstructions/index.ts +7 -7
- package/src/municipal/systemInstructions/instructions.getters.ts +57 -57
- package/src/municipal/systemInstructions/instructions.setters.ts +119 -119
- package/src/municipal/systemInstructions/instructions.types.ts +30 -30
- package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -30
- package/src/municipal/tickets/__tests__/tickets.statistics.spec.ts +51 -51
- package/src/municipal/tickets/index.ts +3 -3
- package/src/municipal/tickets/tickets.constants.ts +8 -8
- package/src/municipal/tickets/tickets.getters.ts +121 -121
- package/src/municipal/tickets/tickets.statistics.aggregation.ts +96 -96
- package/src/municipal/tickets/tickets.statistics.getters.ts +71 -71
- package/src/municipal/tickets/tickets.types.ts +53 -53
- package/src/municipal/utils/types.ts +11 -11
- package/src/talkpilot/__tests__/db.spec.ts +38 -38
- package/src/talkpilot/__tests__/mongodb-client.spec.ts +18 -18
- package/src/talkpilot/__tests__/validation.spec.ts +68 -68
- package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -29
- package/src/talkpilot/agents/agents.getters.ts +34 -34
- package/src/talkpilot/agents/agents.types.ts +14 -14
- package/src/talkpilot/agents/index.ts +2 -2
- package/src/talkpilot/backgroundToolResults/__tests__/backgroundToolResults.getters.spec.ts +147 -147
- package/src/talkpilot/backgroundToolResults/backgroundToolResults.getters.ts +65 -65
- package/src/talkpilot/backgroundToolResults/backgroundToolResults.types.ts +23 -23
- package/src/talkpilot/backgroundToolResults/index.ts +2 -2
- package/src/talkpilot/calls/__tests__/callStats.utils.spec.ts +128 -128
- package/src/talkpilot/calls/__tests__/calls.dashboard.spec.ts +149 -149
- package/src/talkpilot/calls/__tests__/calls.spec.ts +270 -270
- package/src/talkpilot/calls/__tests__/calls.statistics.spec.ts +344 -344
- package/src/talkpilot/calls/calls.constants.ts +20 -20
- package/src/talkpilot/calls/calls.getters.ts +248 -248
- package/src/talkpilot/calls/calls.statistics.getters.ts +587 -587
- package/src/talkpilot/calls/calls.statistics.types.ts +44 -44
- package/src/talkpilot/calls/calls.types.ts +119 -116
- package/src/talkpilot/calls/dashboard/calls.dashboard.ts +292 -292
- package/src/talkpilot/calls/dashboard/calls.dashboard.types.ts +57 -57
- package/src/talkpilot/calls/index.ts +6 -6
- package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +160 -160
- package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +117 -117
- package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -25
- package/src/talkpilot/clientAudioBuffers/index.ts +2 -2
- package/src/talkpilot/clients/clients.getters.ts +16 -16
- package/src/talkpilot/clients/clients.types.ts +14 -14
- package/src/talkpilot/clients/index.ts +2 -2
- package/src/talkpilot/clientsConfig/__tests__/clientsConfig.getters.spec.ts +53 -53
- package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +190 -190
- package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +55 -55
- package/src/talkpilot/clientsConfig/clientsConfig.types.ts +127 -127
- package/src/talkpilot/clientsConfig/index.ts +2 -2
- package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +176 -0
- package/src/talkpilot/contextNotes/contextNotes.getters.ts +86 -0
- package/src/talkpilot/contextNotes/contextNotes.types.ts +20 -0
- package/src/talkpilot/contextNotes/index.ts +2 -0
- package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +96 -71
- package/src/talkpilot/flows/flows.getter.ts +14 -14
- package/src/talkpilot/flows/flows.schema.ts +154 -153
- package/src/talkpilot/flows/flows.types.ts +187 -184
- package/src/talkpilot/flows/index.ts +2 -2
- package/src/talkpilot/groups/__tests__/groups.spec.ts +90 -90
- package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -32
- package/src/talkpilot/groups/groups.getters.ts +30 -30
- package/src/talkpilot/groups/groups.types.ts +29 -29
- package/src/talkpilot/groups/index.ts +3 -3
- package/src/talkpilot/groups/phone.utils.ts +46 -46
- package/src/talkpilot/index.ts +31 -29
- package/src/talkpilot/leads/index.ts +2 -2
- package/src/talkpilot/leads/leads.getter.ts +6 -6
- package/src/talkpilot/leads/leads.schema.ts +33 -33
- package/src/talkpilot/leads/leads.types.ts +20 -20
- package/src/talkpilot/mongodb-client.ts +78 -78
- package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +252 -252
- package/src/talkpilot/phone_numbers/index.ts +2 -2
- package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +158 -158
- package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +17 -17
- package/src/talkpilot/phone_numbers/phone_numbers.types.ts +30 -30
- package/src/talkpilot/plans/__tests__/plans.spec.ts +70 -70
- package/src/talkpilot/plans/index.ts +2 -2
- package/src/talkpilot/plans/plans.getters.ts +132 -132
- package/src/talkpilot/plans/plans.types.ts +89 -89
- package/src/talkpilot/products/__tests__/products.getters.spec.ts +45 -0
- package/src/talkpilot/products/index.ts +2 -0
- package/src/talkpilot/products/products.getters.ts +12 -0
- package/src/talkpilot/products/products.types.ts +9 -0
- package/src/talkpilot/results/index.ts +7 -7
- package/src/talkpilot/results/results.getter.ts +39 -39
- package/src/talkpilot/results/results.schema.ts +25 -25
- package/src/talkpilot/results/results.types.ts +34 -34
- package/src/talkpilot/retry_analyze/__tests__/retryAnalyze.getters.spec.ts +156 -156
- package/src/talkpilot/retry_analyze/index.ts +2 -2
- package/src/talkpilot/retry_analyze/retryAnalyze.getters.ts +84 -84
- package/src/talkpilot/retry_analyze/retryAnalyze.types.ts +13 -13
- package/src/talkpilot/sessions/__tests__/sessions.spec.ts +147 -147
- package/src/talkpilot/sessions/index.ts +2 -2
- package/src/talkpilot/sessions/sessions.getter.ts +92 -92
- package/src/talkpilot/sessions/sessions.schema.ts +34 -34
- package/src/talkpilot/sessions/sessions.types.ts +30 -30
- package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +45 -45
- package/src/talkpilot/subscriptions/index.ts +3 -3
- package/src/talkpilot/subscriptions/subscriptions.getters.ts +146 -146
- package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +33 -33
- package/src/talkpilot/subscriptions/subscriptions.types.ts +66 -66
- package/src/talkpilot/utils/__tests__/query.utils.spec.ts +49 -49
- package/src/talkpilot/utils/query.utils.ts +21 -21
- package/src/test-utils/db-utils.ts +26 -26
- package/src/test-utils/factories/index.ts +15 -14
- package/src/test-utils/factories/municipal/cities.ts +16 -16
- package/src/test-utils/factories/municipal/departmentsSubjects.ts +37 -37
- package/src/test-utils/factories/municipal/muniIssues.ts +32 -32
- package/src/test-utils/factories/municipal/streets.ts +22 -22
- package/src/test-utils/factories/municipal/tickets.ts +39 -39
- package/src/test-utils/factories/talkpilot/agents.ts +19 -19
- package/src/test-utils/factories/talkpilot/calls.ts +37 -37
- package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +20 -20
- package/src/test-utils/factories/talkpilot/clientsConfig.ts +18 -18
- package/src/test-utils/factories/talkpilot/contextNotes.ts +33 -0
- package/src/test-utils/factories/talkpilot/flows.ts +33 -33
- package/src/test-utils/factories/talkpilot/groups.ts +33 -33
- package/src/test-utils/factories/talkpilot/phone_numbers.ts +22 -22
- package/src/test-utils/factories/talkpilot/sessions.ts +35 -35
- package/src/test-utils/factories/websitalk/scans.ts +23 -23
- package/src/utils/date.utils.ts +116 -116
- package/src/utils/shared.types.ts +4 -4
- package/src/utils/validation.ts +23 -23
- package/src/websitalk/index.ts +15 -15
- package/src/websitalk/mongodb-client.ts +61 -61
- package/src/websitalk/scans/__tests__/scans.spec.ts +218 -218
- package/src/websitalk/scans/index.ts +2 -2
- package/src/websitalk/scans/scans.getters.ts +113 -113
- package/src/websitalk/scans/scans.types.ts +53 -53
- package/tsconfig.json +23 -23
- package/.claude/settings.local.json +0 -11
- package/dist/municipal/tickets/tickets.deprecated.getters.d.ts +0 -12
- package/dist/municipal/tickets/tickets.deprecated.getters.d.ts.map +0 -1
- package/dist/municipal/tickets/tickets.deprecated.getters.js +0 -131
- package/dist/municipal/tickets/tickets.deprecated.getters.js.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.dates.d.ts +0 -7
- package/dist/municipal/tickets/tickets.statistics.dates.d.ts.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.dates.js +0 -40
- package/dist/municipal/tickets/tickets.statistics.dates.js.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.pipeline.d.ts +0 -53
- package/dist/municipal/tickets/tickets.statistics.pipeline.d.ts.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.pipeline.js +0 -112
- package/dist/municipal/tickets/tickets.statistics.pipeline.js.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.utils.d.ts +0 -7
- package/dist/municipal/tickets/tickets.statistics.utils.d.ts.map +0 -1
- package/dist/municipal/tickets/tickets.statistics.utils.js +0 -40
- package/dist/municipal/tickets/tickets.statistics.utils.js.map +0 -1
- package/dist/talkpilot/calls/calls.statistics.ticketScope.d.ts +0 -12
- package/dist/talkpilot/calls/calls.statistics.ticketScope.d.ts.map +0 -1
- package/dist/talkpilot/calls/calls.statistics.ticketScope.js +0 -37
- package/dist/talkpilot/calls/calls.statistics.ticketScope.js.map +0 -1
- package/dist/talkpilot/calls/calls.statistics.tickets.d.ts +0 -17
- package/dist/talkpilot/calls/calls.statistics.tickets.d.ts.map +0 -1
- package/dist/talkpilot/calls/calls.statistics.tickets.js +0 -33
- package/dist/talkpilot/calls/calls.statistics.tickets.js.map +0 -1
- package/dist/utils/statistics.aggregation.d.ts +0 -20
- package/dist/utils/statistics.aggregation.d.ts.map +0 -1
- package/dist/utils/statistics.aggregation.js +0 -43
- package/dist/utils/statistics.aggregation.js.map +0 -1
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import { CityName, getDb, ObjectId, Ticket } from "../index";
|
|
2
|
-
import { Collection, Filter, ObjectId as MongoObjectId } from "mongodb";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Generate a new ticket ID as a string
|
|
6
|
-
* @returns A new ObjectId as a string
|
|
7
|
-
*/
|
|
8
|
-
export const generateTicketId = (): string => {
|
|
9
|
-
return new ObjectId().toString();
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const getTicketsCollection = (): Collection<Ticket> => {
|
|
13
|
-
return getDb().collection<Ticket>("tickets");
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const findTickets = async (
|
|
17
|
-
filter: Filter<Ticket> = {},
|
|
18
|
-
): Promise<Ticket[]> => {
|
|
19
|
-
return await getTicketsCollection().find(filter).toArray();
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const findTicketsByCallSid = async (
|
|
23
|
-
callSid: string,
|
|
24
|
-
): Promise<Ticket[]> => {
|
|
25
|
-
return await getTicketsCollection().find({ callSid }).toArray();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const getTicketById = async (
|
|
29
|
-
ticketId: string,
|
|
30
|
-
): Promise<Ticket | null> => {
|
|
31
|
-
const ticket = await getTicketsCollection().findOne({
|
|
32
|
-
_id: new ObjectId(ticketId),
|
|
33
|
-
});
|
|
34
|
-
return ticket ? ticket : null;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const createTicket = async (
|
|
38
|
-
ticketData: Omit<Ticket, "_id" | "createdAt" | "updatedAt">,
|
|
39
|
-
ticketId?: string,
|
|
40
|
-
): Promise<MongoObjectId> => {
|
|
41
|
-
const ticket: Ticket = {
|
|
42
|
-
_id: ticketId ? new ObjectId(ticketId) : new ObjectId(),
|
|
43
|
-
...ticketData,
|
|
44
|
-
createdAt: new Date(),
|
|
45
|
-
updatedAt: new Date(),
|
|
46
|
-
};
|
|
47
|
-
const { insertedId } = await getTicketsCollection().insertOne(ticket);
|
|
48
|
-
return insertedId;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export const updateTicket = async (
|
|
52
|
-
ticketId: string,
|
|
53
|
-
data: Partial<Omit<Ticket, "_id" | "createdAt" | "updatedAt">>,
|
|
54
|
-
): Promise<Ticket | null> => {
|
|
55
|
-
const result = await getTicketsCollection().findOneAndUpdate(
|
|
56
|
-
{ _id: new ObjectId(ticketId) },
|
|
57
|
-
{ $set: { ...data, updatedAt: new Date() } },
|
|
58
|
-
{ returnDocument: "after" },
|
|
59
|
-
);
|
|
60
|
-
return result || null;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const deleteTicket = async (ticketId: string): Promise<boolean> => {
|
|
64
|
-
const result = await getTicketsCollection().deleteOne({
|
|
65
|
-
_id: new ObjectId(ticketId),
|
|
66
|
-
});
|
|
67
|
-
return result.deletedCount > 0;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export const findTicketByQuery = async (query: Partial<Ticket>) => {
|
|
71
|
-
return await getTicketsCollection().findOne(query);
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* Update ticket files by external call number
|
|
75
|
-
*/
|
|
76
|
-
export const updateTicketFilesByCallNumber = async (params: {
|
|
77
|
-
cityName: CityName;
|
|
78
|
-
callNumber: string;
|
|
79
|
-
image1?: string;
|
|
80
|
-
image2?: string;
|
|
81
|
-
image3?: string;
|
|
82
|
-
}): Promise<boolean> => {
|
|
83
|
-
const { cityName, callNumber, image1, image2, image3 } = params;
|
|
84
|
-
|
|
85
|
-
const update: any = {};
|
|
86
|
-
if (image1) update["externalCallFields.image1"] = image1;
|
|
87
|
-
if (image2) update["externalCallFields.image2"] = image2;
|
|
88
|
-
if (image3) update["externalCallFields.image3"] = image3;
|
|
89
|
-
|
|
90
|
-
const result = await getTicketsCollection().updateOne(
|
|
91
|
-
{
|
|
92
|
-
cityName: cityName,
|
|
93
|
-
"externalCallFields.call_number": callNumber,
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
$set: {
|
|
97
|
-
...update,
|
|
98
|
-
updatedAt: new Date(),
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
return result.matchedCount > 0;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Remove guestJwt from ticket by external call number
|
|
108
|
-
*/
|
|
109
|
-
export const clearGuestJwtByCallNumber = async (params: {
|
|
110
|
-
cityName: CityName;
|
|
111
|
-
callNumber: string;
|
|
112
|
-
}): Promise<boolean> => {
|
|
113
|
-
const { cityName, callNumber } = params;
|
|
114
|
-
|
|
115
|
-
const result = await getTicketsCollection().updateOne(
|
|
116
|
-
{ cityName, "externalCallFields.call_number": callNumber },
|
|
117
|
-
{ $unset: { guestJwt: "" }, $set: { updatedAt: new Date() } },
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
return result.matchedCount > 0;
|
|
121
|
-
};
|
|
1
|
+
import { CityName, getDb, ObjectId, Ticket } from "../index";
|
|
2
|
+
import { Collection, Filter, ObjectId as MongoObjectId } from "mongodb";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate a new ticket ID as a string
|
|
6
|
+
* @returns A new ObjectId as a string
|
|
7
|
+
*/
|
|
8
|
+
export const generateTicketId = (): string => {
|
|
9
|
+
return new ObjectId().toString();
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const getTicketsCollection = (): Collection<Ticket> => {
|
|
13
|
+
return getDb().collection<Ticket>("tickets");
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const findTickets = async (
|
|
17
|
+
filter: Filter<Ticket> = {},
|
|
18
|
+
): Promise<Ticket[]> => {
|
|
19
|
+
return await getTicketsCollection().find(filter).toArray();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const findTicketsByCallSid = async (
|
|
23
|
+
callSid: string,
|
|
24
|
+
): Promise<Ticket[]> => {
|
|
25
|
+
return await getTicketsCollection().find({ callSid }).toArray();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const getTicketById = async (
|
|
29
|
+
ticketId: string,
|
|
30
|
+
): Promise<Ticket | null> => {
|
|
31
|
+
const ticket = await getTicketsCollection().findOne({
|
|
32
|
+
_id: new ObjectId(ticketId),
|
|
33
|
+
});
|
|
34
|
+
return ticket ? ticket : null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const createTicket = async (
|
|
38
|
+
ticketData: Omit<Ticket, "_id" | "createdAt" | "updatedAt">,
|
|
39
|
+
ticketId?: string,
|
|
40
|
+
): Promise<MongoObjectId> => {
|
|
41
|
+
const ticket: Ticket = {
|
|
42
|
+
_id: ticketId ? new ObjectId(ticketId) : new ObjectId(),
|
|
43
|
+
...ticketData,
|
|
44
|
+
createdAt: new Date(),
|
|
45
|
+
updatedAt: new Date(),
|
|
46
|
+
};
|
|
47
|
+
const { insertedId } = await getTicketsCollection().insertOne(ticket);
|
|
48
|
+
return insertedId;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const updateTicket = async (
|
|
52
|
+
ticketId: string,
|
|
53
|
+
data: Partial<Omit<Ticket, "_id" | "createdAt" | "updatedAt">>,
|
|
54
|
+
): Promise<Ticket | null> => {
|
|
55
|
+
const result = await getTicketsCollection().findOneAndUpdate(
|
|
56
|
+
{ _id: new ObjectId(ticketId) },
|
|
57
|
+
{ $set: { ...data, updatedAt: new Date() } },
|
|
58
|
+
{ returnDocument: "after" },
|
|
59
|
+
);
|
|
60
|
+
return result || null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const deleteTicket = async (ticketId: string): Promise<boolean> => {
|
|
64
|
+
const result = await getTicketsCollection().deleteOne({
|
|
65
|
+
_id: new ObjectId(ticketId),
|
|
66
|
+
});
|
|
67
|
+
return result.deletedCount > 0;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const findTicketByQuery = async (query: Partial<Ticket>) => {
|
|
71
|
+
return await getTicketsCollection().findOne(query);
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Update ticket files by external call number
|
|
75
|
+
*/
|
|
76
|
+
export const updateTicketFilesByCallNumber = async (params: {
|
|
77
|
+
cityName: CityName;
|
|
78
|
+
callNumber: string;
|
|
79
|
+
image1?: string;
|
|
80
|
+
image2?: string;
|
|
81
|
+
image3?: string;
|
|
82
|
+
}): Promise<boolean> => {
|
|
83
|
+
const { cityName, callNumber, image1, image2, image3 } = params;
|
|
84
|
+
|
|
85
|
+
const update: any = {};
|
|
86
|
+
if (image1) update["externalCallFields.image1"] = image1;
|
|
87
|
+
if (image2) update["externalCallFields.image2"] = image2;
|
|
88
|
+
if (image3) update["externalCallFields.image3"] = image3;
|
|
89
|
+
|
|
90
|
+
const result = await getTicketsCollection().updateOne(
|
|
91
|
+
{
|
|
92
|
+
cityName: cityName,
|
|
93
|
+
"externalCallFields.call_number": callNumber,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
$set: {
|
|
97
|
+
...update,
|
|
98
|
+
updatedAt: new Date(),
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return result.matchedCount > 0;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Remove guestJwt from ticket by external call number
|
|
108
|
+
*/
|
|
109
|
+
export const clearGuestJwtByCallNumber = async (params: {
|
|
110
|
+
cityName: CityName;
|
|
111
|
+
callNumber: string;
|
|
112
|
+
}): Promise<boolean> => {
|
|
113
|
+
const { cityName, callNumber } = params;
|
|
114
|
+
|
|
115
|
+
const result = await getTicketsCollection().updateOne(
|
|
116
|
+
{ cityName, "externalCallFields.call_number": callNumber },
|
|
117
|
+
{ $unset: { guestJwt: "" }, $set: { updatedAt: new Date() } },
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return result.matchedCount > 0;
|
|
121
|
+
};
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import { CityName } from "../utils/types";
|
|
2
|
-
import { STATS_MAX_TIME_MS, UNCLASSIFIED } from "./tickets.constants";
|
|
3
|
-
import { getTicketsCollection } from "./tickets.getters";
|
|
4
|
-
import type { TicketStatsDateRange } from "./tickets.types";
|
|
5
|
-
|
|
6
|
-
const effectiveSubjectIdExpr = {
|
|
7
|
-
$ifNull: [
|
|
8
|
-
"$externalCallFields.event_subject_id",
|
|
9
|
-
{
|
|
10
|
-
$ifNull: [
|
|
11
|
-
"$externalCallFields.event_sub_subject_id",
|
|
12
|
-
"$externalCallFields.event_sub_subject_id2",
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const departmentsSubjectsLookup = (cityName: CityName) => ({
|
|
19
|
-
$lookup: {
|
|
20
|
-
from: "departmentsSubjects",
|
|
21
|
-
let: { sid: "$effectiveSubjectId", c: cityName },
|
|
22
|
-
pipeline: [
|
|
23
|
-
{
|
|
24
|
-
$match: {
|
|
25
|
-
$expr: {
|
|
26
|
-
$and: [
|
|
27
|
-
{ $eq: ["$cityName", "$$c"] },
|
|
28
|
-
{
|
|
29
|
-
$or: [
|
|
30
|
-
{ $eq: ["$subject_id", { $ifNull: ["$$sid", ""] }] },
|
|
31
|
-
{ $eq: ["$sub_subject_id", { $ifNull: ["$$sid", ""] }] },
|
|
32
|
-
{ $eq: ["$sub_subject_id2", { $ifNull: ["$$sid", ""] }] },
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
{ $limit: 1 },
|
|
40
|
-
],
|
|
41
|
-
as: "subj",
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const subjectLabelExpr = {
|
|
46
|
-
$cond: {
|
|
47
|
-
if: { $gt: [{ $size: "$subj" }, 0] },
|
|
48
|
-
then: {
|
|
49
|
-
$ifNull: [{ $arrayElemAt: ["$subj.subjectName", 0] }, UNCLASSIFIED],
|
|
50
|
-
},
|
|
51
|
-
else: UNCLASSIFIED,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const ticketDateMatch = (dateRange: TicketStatsDateRange) => ({
|
|
56
|
-
createdAt: { $gte: dateRange.from, $lte: dateRange.to },
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
export const isDraftSubjectIdExpr = {
|
|
60
|
-
$or: [
|
|
61
|
-
{ $eq: [{ $type: "$externalCallFields.event_subject_id" }, "missing"] },
|
|
62
|
-
{ $eq: ["$externalCallFields.event_subject_id", null] },
|
|
63
|
-
{
|
|
64
|
-
$regexMatch: {
|
|
65
|
-
input: { $ifNull: ["$externalCallFields.event_subject_id", ""] },
|
|
66
|
-
regex: /^\s*$/,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const ticketsWithCallSidMatch = (
|
|
73
|
-
cityName: CityName,
|
|
74
|
-
dateRange: TicketStatsDateRange,
|
|
75
|
-
) => ({
|
|
76
|
-
cityName,
|
|
77
|
-
callSid: { $exists: true, $nin: [null, ""] },
|
|
78
|
-
...ticketDateMatch(dateRange),
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
export const subjectResolutionStages = (
|
|
82
|
-
cityName: CityName,
|
|
83
|
-
): Record<string, unknown>[] => [
|
|
84
|
-
{ $addFields: { effectiveSubjectId: effectiveSubjectIdExpr } },
|
|
85
|
-
departmentsSubjectsLookup(cityName),
|
|
86
|
-
{ $addFields: { subject: subjectLabelExpr } },
|
|
87
|
-
];
|
|
88
|
-
|
|
89
|
-
export const runTicketStatsAggregate = async <T>(
|
|
90
|
-
pipeline: Record<string, unknown>[],
|
|
91
|
-
): Promise<T[]> => {
|
|
92
|
-
const rows = await getTicketsCollection()
|
|
93
|
-
.aggregate(pipeline, { maxTimeMS: STATS_MAX_TIME_MS })
|
|
94
|
-
.toArray();
|
|
95
|
-
return rows as T[];
|
|
96
|
-
};
|
|
1
|
+
import { CityName } from "../utils/types";
|
|
2
|
+
import { STATS_MAX_TIME_MS, UNCLASSIFIED } from "./tickets.constants";
|
|
3
|
+
import { getTicketsCollection } from "./tickets.getters";
|
|
4
|
+
import type { TicketStatsDateRange } from "./tickets.types";
|
|
5
|
+
|
|
6
|
+
const effectiveSubjectIdExpr = {
|
|
7
|
+
$ifNull: [
|
|
8
|
+
"$externalCallFields.event_subject_id",
|
|
9
|
+
{
|
|
10
|
+
$ifNull: [
|
|
11
|
+
"$externalCallFields.event_sub_subject_id",
|
|
12
|
+
"$externalCallFields.event_sub_subject_id2",
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const departmentsSubjectsLookup = (cityName: CityName) => ({
|
|
19
|
+
$lookup: {
|
|
20
|
+
from: "departmentsSubjects",
|
|
21
|
+
let: { sid: "$effectiveSubjectId", c: cityName },
|
|
22
|
+
pipeline: [
|
|
23
|
+
{
|
|
24
|
+
$match: {
|
|
25
|
+
$expr: {
|
|
26
|
+
$and: [
|
|
27
|
+
{ $eq: ["$cityName", "$$c"] },
|
|
28
|
+
{
|
|
29
|
+
$or: [
|
|
30
|
+
{ $eq: ["$subject_id", { $ifNull: ["$$sid", ""] }] },
|
|
31
|
+
{ $eq: ["$sub_subject_id", { $ifNull: ["$$sid", ""] }] },
|
|
32
|
+
{ $eq: ["$sub_subject_id2", { $ifNull: ["$$sid", ""] }] },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{ $limit: 1 },
|
|
40
|
+
],
|
|
41
|
+
as: "subj",
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const subjectLabelExpr = {
|
|
46
|
+
$cond: {
|
|
47
|
+
if: { $gt: [{ $size: "$subj" }, 0] },
|
|
48
|
+
then: {
|
|
49
|
+
$ifNull: [{ $arrayElemAt: ["$subj.subjectName", 0] }, UNCLASSIFIED],
|
|
50
|
+
},
|
|
51
|
+
else: UNCLASSIFIED,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const ticketDateMatch = (dateRange: TicketStatsDateRange) => ({
|
|
56
|
+
createdAt: { $gte: dateRange.from, $lte: dateRange.to },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const isDraftSubjectIdExpr = {
|
|
60
|
+
$or: [
|
|
61
|
+
{ $eq: [{ $type: "$externalCallFields.event_subject_id" }, "missing"] },
|
|
62
|
+
{ $eq: ["$externalCallFields.event_subject_id", null] },
|
|
63
|
+
{
|
|
64
|
+
$regexMatch: {
|
|
65
|
+
input: { $ifNull: ["$externalCallFields.event_subject_id", ""] },
|
|
66
|
+
regex: /^\s*$/,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const ticketsWithCallSidMatch = (
|
|
73
|
+
cityName: CityName,
|
|
74
|
+
dateRange: TicketStatsDateRange,
|
|
75
|
+
) => ({
|
|
76
|
+
cityName,
|
|
77
|
+
callSid: { $exists: true, $nin: [null, ""] },
|
|
78
|
+
...ticketDateMatch(dateRange),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export const subjectResolutionStages = (
|
|
82
|
+
cityName: CityName,
|
|
83
|
+
): Record<string, unknown>[] => [
|
|
84
|
+
{ $addFields: { effectiveSubjectId: effectiveSubjectIdExpr } },
|
|
85
|
+
departmentsSubjectsLookup(cityName),
|
|
86
|
+
{ $addFields: { subject: subjectLabelExpr } },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
export const runTicketStatsAggregate = async <T>(
|
|
90
|
+
pipeline: Record<string, unknown>[],
|
|
91
|
+
): Promise<T[]> => {
|
|
92
|
+
const rows = await getTicketsCollection()
|
|
93
|
+
.aggregate(pipeline, { maxTimeMS: STATS_MAX_TIME_MS })
|
|
94
|
+
.toArray();
|
|
95
|
+
return rows as T[];
|
|
96
|
+
};
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import { CityName } from "../utils/types";
|
|
2
|
-
import {
|
|
3
|
-
DAY_MS,
|
|
4
|
-
endOfCalendarDayInTz,
|
|
5
|
-
startOfCalendarDayInTz,
|
|
6
|
-
} from "../../utils/date.utils";
|
|
7
|
-
import { DEFAULT_LOOKBACK_DAYS } from "./tickets.constants";
|
|
8
|
-
import {
|
|
9
|
-
isDraftSubjectIdExpr,
|
|
10
|
-
runTicketStatsAggregate,
|
|
11
|
-
subjectResolutionStages,
|
|
12
|
-
ticketsWithCallSidMatch,
|
|
13
|
-
} from "./tickets.statistics.aggregation";
|
|
14
|
-
import type {
|
|
15
|
-
TicketStatsDateRange,
|
|
16
|
-
TicketStatsDateScope,
|
|
17
|
-
TicketSubjectRow,
|
|
18
|
-
} from "./tickets.types";
|
|
19
|
-
|
|
20
|
-
export const resolveTicketStatsDateRange = (
|
|
21
|
-
dateScope?: TicketStatsDateScope,
|
|
22
|
-
): TicketStatsDateRange => {
|
|
23
|
-
const to = dateScope?.to ?? new Date();
|
|
24
|
-
const from =
|
|
25
|
-
dateScope?.from ?? new Date(to.getTime() - DEFAULT_LOOKBACK_DAYS * DAY_MS);
|
|
26
|
-
return { from, to };
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const ticketStatsDateScopeFromYmd = (
|
|
30
|
-
startStr: string,
|
|
31
|
-
endStr: string,
|
|
32
|
-
timezone: string,
|
|
33
|
-
): TicketStatsDateScope => ({
|
|
34
|
-
from: startOfCalendarDayInTz(startStr, timezone),
|
|
35
|
-
to: endOfCalendarDayInTz(endStr, timezone),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
export const findCallSidsWithTicketsByCity = async (
|
|
39
|
-
cityName: CityName,
|
|
40
|
-
dateScope?: TicketStatsDateScope,
|
|
41
|
-
): Promise<string[]> => {
|
|
42
|
-
const rows = await runTicketStatsAggregate<{ _id: unknown }>([
|
|
43
|
-
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
44
|
-
{ $group: { _id: "$callSid" } },
|
|
45
|
-
]);
|
|
46
|
-
return rows.map((r) => String(r._id)).filter(Boolean);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export const findCallSidsWithDraftTicketsByCity = async (
|
|
50
|
-
cityName: CityName,
|
|
51
|
-
dateScope?: TicketStatsDateScope,
|
|
52
|
-
): Promise<string[]> => {
|
|
53
|
-
const rows = await runTicketStatsAggregate<{ _id: unknown }>([
|
|
54
|
-
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
55
|
-
{ $match: { $expr: isDraftSubjectIdExpr } },
|
|
56
|
-
{ $group: { _id: "$callSid" } },
|
|
57
|
-
]);
|
|
58
|
-
return rows.map((r) => String(r._id)).filter(Boolean);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const findTicketSubjectRows = async (
|
|
62
|
-
cityName: CityName,
|
|
63
|
-
dateScope?: TicketStatsDateScope,
|
|
64
|
-
): Promise<TicketSubjectRow[]> => {
|
|
65
|
-
const rows = await runTicketStatsAggregate<{ callSid: unknown; subject: unknown }>([
|
|
66
|
-
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
67
|
-
...subjectResolutionStages(cityName),
|
|
68
|
-
{ $project: { _id: 0, callSid: 1, subject: 1 } },
|
|
69
|
-
]);
|
|
70
|
-
return rows.map((r) => ({ callSid: String(r.callSid), subject: String(r.subject) }));
|
|
71
|
-
};
|
|
1
|
+
import { CityName } from "../utils/types";
|
|
2
|
+
import {
|
|
3
|
+
DAY_MS,
|
|
4
|
+
endOfCalendarDayInTz,
|
|
5
|
+
startOfCalendarDayInTz,
|
|
6
|
+
} from "../../utils/date.utils";
|
|
7
|
+
import { DEFAULT_LOOKBACK_DAYS } from "./tickets.constants";
|
|
8
|
+
import {
|
|
9
|
+
isDraftSubjectIdExpr,
|
|
10
|
+
runTicketStatsAggregate,
|
|
11
|
+
subjectResolutionStages,
|
|
12
|
+
ticketsWithCallSidMatch,
|
|
13
|
+
} from "./tickets.statistics.aggregation";
|
|
14
|
+
import type {
|
|
15
|
+
TicketStatsDateRange,
|
|
16
|
+
TicketStatsDateScope,
|
|
17
|
+
TicketSubjectRow,
|
|
18
|
+
} from "./tickets.types";
|
|
19
|
+
|
|
20
|
+
export const resolveTicketStatsDateRange = (
|
|
21
|
+
dateScope?: TicketStatsDateScope,
|
|
22
|
+
): TicketStatsDateRange => {
|
|
23
|
+
const to = dateScope?.to ?? new Date();
|
|
24
|
+
const from =
|
|
25
|
+
dateScope?.from ?? new Date(to.getTime() - DEFAULT_LOOKBACK_DAYS * DAY_MS);
|
|
26
|
+
return { from, to };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const ticketStatsDateScopeFromYmd = (
|
|
30
|
+
startStr: string,
|
|
31
|
+
endStr: string,
|
|
32
|
+
timezone: string,
|
|
33
|
+
): TicketStatsDateScope => ({
|
|
34
|
+
from: startOfCalendarDayInTz(startStr, timezone),
|
|
35
|
+
to: endOfCalendarDayInTz(endStr, timezone),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const findCallSidsWithTicketsByCity = async (
|
|
39
|
+
cityName: CityName,
|
|
40
|
+
dateScope?: TicketStatsDateScope,
|
|
41
|
+
): Promise<string[]> => {
|
|
42
|
+
const rows = await runTicketStatsAggregate<{ _id: unknown }>([
|
|
43
|
+
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
44
|
+
{ $group: { _id: "$callSid" } },
|
|
45
|
+
]);
|
|
46
|
+
return rows.map((r) => String(r._id)).filter(Boolean);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const findCallSidsWithDraftTicketsByCity = async (
|
|
50
|
+
cityName: CityName,
|
|
51
|
+
dateScope?: TicketStatsDateScope,
|
|
52
|
+
): Promise<string[]> => {
|
|
53
|
+
const rows = await runTicketStatsAggregate<{ _id: unknown }>([
|
|
54
|
+
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
55
|
+
{ $match: { $expr: isDraftSubjectIdExpr } },
|
|
56
|
+
{ $group: { _id: "$callSid" } },
|
|
57
|
+
]);
|
|
58
|
+
return rows.map((r) => String(r._id)).filter(Boolean);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const findTicketSubjectRows = async (
|
|
62
|
+
cityName: CityName,
|
|
63
|
+
dateScope?: TicketStatsDateScope,
|
|
64
|
+
): Promise<TicketSubjectRow[]> => {
|
|
65
|
+
const rows = await runTicketStatsAggregate<{ callSid: unknown; subject: unknown }>([
|
|
66
|
+
{ $match: ticketsWithCallSidMatch(cityName, resolveTicketStatsDateRange(dateScope)) },
|
|
67
|
+
...subjectResolutionStages(cityName),
|
|
68
|
+
{ $project: { _id: 0, callSid: 1, subject: 1 } },
|
|
69
|
+
]);
|
|
70
|
+
return rows.map((r) => ({ callSid: String(r.callSid), subject: String(r.subject) }));
|
|
71
|
+
};
|