@talkpilot/core-db 1.3.77 → 1.3.79
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/README.md +28 -1
- package/dist/municipal/muniIssues/index.d.ts +2 -2
- package/dist/municipal/muniIssues/index.d.ts.map +1 -1
- package/dist/municipal/muniIssues/index.js +1 -2
- package/dist/municipal/muniIssues/index.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.constants.d.ts +0 -2
- package/dist/municipal/muniIssues/muniIssues.constants.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.constants.js +1 -8
- package/dist/municipal/muniIssues/muniIssues.constants.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.getters.d.ts +1 -6
- package/dist/municipal/muniIssues/muniIssues.getters.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.getters.js +1 -31
- package/dist/municipal/muniIssues/muniIssues.getters.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.schema.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.schema.js +0 -13
- package/dist/municipal/muniIssues/muniIssues.schema.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.setters.d.ts +1 -5
- package/dist/municipal/muniIssues/muniIssues.setters.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.setters.js +2 -39
- package/dist/municipal/muniIssues/muniIssues.setters.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.types.d.ts +2 -23
- package/dist/municipal/muniIssues/muniIssues.types.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.constants.d.ts +7 -0
- package/dist/talkpilot/calls/calls.constants.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.constants.js +8 -1
- package/dist/talkpilot/calls/calls.constants.js.map +1 -1
- package/dist/talkpilot/calls/calls.getters.d.ts +2 -1
- package/dist/talkpilot/calls/calls.getters.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.getters.js +6 -1
- package/dist/talkpilot/calls/calls.getters.js.map +1 -1
- package/dist/talkpilot/calls/calls.types.d.ts +16 -2
- package/dist/talkpilot/calls/calls.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +1 -74
- package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +0 -1
- package/src/municipal/muniIssues/index.ts +0 -5
- package/src/municipal/muniIssues/muniIssues.constants.ts +0 -8
- package/src/municipal/muniIssues/muniIssues.getters.ts +2 -46
- package/src/municipal/muniIssues/muniIssues.schema.ts +0 -14
- package/src/municipal/muniIssues/muniIssues.setters.ts +3 -59
- package/src/municipal/muniIssues/muniIssues.types.ts +4 -35
- package/src/talkpilot/calls/__tests__/calls.spec.ts +48 -0
- package/src/talkpilot/calls/calls.constants.ts +8 -0
- package/src/talkpilot/calls/calls.getters.ts +19 -1
- package/src/talkpilot/calls/calls.types.ts +18 -1
- package/src/municipal/muniIssues/__tests__/muniIssues.getters.spec.ts +0 -66
package/README.md
CHANGED
|
@@ -182,7 +182,8 @@ Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and fact
|
|
|
182
182
|
| 1.3.61 | Optional `activeFlowId` on `WebsiteTalkProduct` (CP-1849). WebsiteTalk updates this flow instead of the flow on a phone number. |
|
|
183
183
|
| 1.3.62 | Pause/Resume support for WebsiteTalk scans (CP-1752): `PAUSED` and `CANCELED` added to `SCAN_STATUSES` (`PAUSED` deliberately excluded from `FINISHED_SCAN_STATUSES` — pausing isn't done, `CANCELED` is). Added `Scan.pausedAt`, tracked across pause/resume so elapsed-time display can freeze correctly instead of counting the paused duration. |
|
|
184
184
|
| 1.3.64 | New `callTokenUsage` collection with `incrementCallTokenUsage` (CP-1810): per-call realtime token usage, one document per `callSid`. |
|
|
185
|
-
| 1.3.
|
|
185
|
+
| 1.3.71 | Who ended a call (CP-1873): optional `Call.endedBy` (`system` / `agent` / `user`), `CallEndedByValues`, and `setCallEndedBy` (first write wins). **Breaking** vs 1.3.69–1.3.70: the value `resident` was replaced by `user`. |
|
|
186
|
+
| 1.3.74 | Added `human` to `CallEndedByValues` (CP-1873): a human agent ended the call, after a transfer or in a conference. |
|
|
186
187
|
|
|
187
188
|
### 1.1.9
|
|
188
189
|
|
|
@@ -805,6 +806,32 @@ Optional `activeFlowId` on `WebsiteTalkProduct`. WTIS reads this field when it u
|
|
|
805
806
|
|
|
806
807
|
No — the field is optional. **WTIS** should upgrade to **1.3.61** so the call-script update can use it.
|
|
807
808
|
|
|
809
|
+
### 1.3.71 — Who ended the call (CP-1873)
|
|
810
|
+
|
|
811
|
+
Records who ended a connected call. Unset for calls that never connected (busy, no-answer) and for calls moved to a conference.
|
|
812
|
+
|
|
813
|
+
**Added**
|
|
814
|
+
|
|
815
|
+
| Item | Purpose |
|
|
816
|
+
| --- | --- |
|
|
817
|
+
| `Call.endedBy` | `system` (our platform, e.g. silence timeout), `agent` (the bot ended the flow) or `user` (the caller hung up). |
|
|
818
|
+
| `CallEndedByValues` / `CallEndedBy` | Const object and the type derived from it, same pattern as `CallStatusValues`. |
|
|
819
|
+
| `setCallEndedBy(callSid, endedBy)` | Writes only if `endedBy` is not set yet; returns `true` when this call wrote it. |
|
|
820
|
+
|
|
821
|
+
`endedBy` is not part of `CallUpdateParams`, so `updateCallByCallSid` cannot overwrite it.
|
|
822
|
+
|
|
823
|
+
**Do I need to update my app?**
|
|
824
|
+
|
|
825
|
+
**TalkPilot Server** must upgrade to **1.3.71** to write the field. 1.3.69–1.3.70 used `resident` instead of `user` — don't use them.
|
|
826
|
+
|
|
827
|
+
### 1.3.74 — Human agent ended the call (CP-1873)
|
|
828
|
+
|
|
829
|
+
New `CallEndedByValues.Human` (`"human"`): a human agent ended the call, either after a transfer or in a conference.
|
|
830
|
+
|
|
831
|
+
**Do I need to update my app?**
|
|
832
|
+
|
|
833
|
+
No — purely additive. **TalkPilot Server** should upgrade to **1.3.74** to write it.
|
|
834
|
+
|
|
808
835
|
## 🛠 CI/CD & deployment
|
|
809
836
|
|
|
810
837
|
- This package is consumed by Cloud Build-based services (TalkPilot Server, MIS, CIS) as a dependency when Docker images are built. Keep `dist/` in sync with your builds because the compiled artifact is what downstream services install.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./muniIssues.getters";
|
|
2
2
|
export * from "./muniIssues.setters";
|
|
3
3
|
export * from "./muniIssues.setup";
|
|
4
|
-
export { MUNI_ISSUES_COLLECTION,
|
|
4
|
+
export { MUNI_ISSUES_COLLECTION, MUNI_ISSUE_SYNC_STATUSES, MUNI_ISSUE_TEXT_MAX_LENGTH, MUNI_ISSUE_NAME_MAX_LENGTH, } from "./muniIssues.constants";
|
|
5
5
|
export { muniIssuesJsonSchema, muniIssuesIndexes } from "./muniIssues.schema";
|
|
6
|
-
export type { MuniIssue, MuniIssueContent, MuniIssueJira, MuniIssueSyncStatus,
|
|
6
|
+
export type { MuniIssue, MuniIssueContent, MuniIssueJira, MuniIssueSyncStatus, CreateMuniIssueInput, } from "./muniIssues.types";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,sBAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
|
|
@@ -14,13 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.muniIssuesIndexes = exports.muniIssuesJsonSchema = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.
|
|
17
|
+
exports.muniIssuesIndexes = exports.muniIssuesJsonSchema = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
|
|
18
18
|
__exportStar(require("./muniIssues.getters"), exports);
|
|
19
19
|
__exportStar(require("./muniIssues.setters"), exports);
|
|
20
20
|
__exportStar(require("./muniIssues.setup"), exports);
|
|
21
21
|
var muniIssues_constants_1 = require("./muniIssues.constants");
|
|
22
22
|
Object.defineProperty(exports, "MUNI_ISSUES_COLLECTION", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUES_COLLECTION; } });
|
|
23
|
-
Object.defineProperty(exports, "MUNI_ISSUE_STATUSES", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_STATUSES; } });
|
|
24
23
|
Object.defineProperty(exports, "MUNI_ISSUE_SYNC_STATUSES", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_SYNC_STATUSES; } });
|
|
25
24
|
Object.defineProperty(exports, "MUNI_ISSUE_TEXT_MAX_LENGTH", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_TEXT_MAX_LENGTH; } });
|
|
26
25
|
Object.defineProperty(exports, "MUNI_ISSUE_NAME_MAX_LENGTH", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_NAME_MAX_LENGTH; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,uDAAqC;AACrC,qDAAmC;AACnC,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,uDAAqC;AACrC,qDAAmC;AACnC,+DAKgC;AAJ9B,8HAAA,sBAAsB,OAAA;AACtB,gIAAA,wBAAwB,OAAA;AACxB,kIAAA,0BAA0B,OAAA;AAC1B,kIAAA,0BAA0B,OAAA;AAE5B,yDAA8E;AAArE,yHAAA,oBAAoB,OAAA;AAAE,sHAAA,iBAAiB,OAAA"}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
export declare const MUNI_ISSUES_COLLECTION = "muniIssues";
|
|
3
3
|
/** Sync state of the issue's Jira ticket at write time. */
|
|
4
4
|
export declare const MUNI_ISSUE_SYNC_STATUSES: readonly ["created", "failed"];
|
|
5
|
-
/** Customer-facing complaint status, set manually by the TalkPilot team. */
|
|
6
|
-
export declare const MUNI_ISSUE_STATUSES: readonly ["in_review", "in_progress", "resolved", "no_issue_found"];
|
|
7
5
|
/** Max length for the long free-text fields — well above the ~2000-char target. */
|
|
8
6
|
export declare const MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
|
|
9
7
|
/** Max length for the short identity fields (a person's name and role). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.constants.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gCAAiC,CAAC;AAEvE,
|
|
1
|
+
{"version":3,"file":"muniIssues.constants.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gCAAiC,CAAC;AAEvE,mFAAmF;AACnF,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAG,QAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,EAAG,OAAgB,CAAC"}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VALIDATION_ACTION = exports.VALIDATION_LEVEL = exports.NAMESPACE_EXISTS = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.
|
|
3
|
+
exports.VALIDATION_ACTION = exports.VALIDATION_LEVEL = exports.NAMESPACE_EXISTS = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
|
|
4
4
|
/** Mongo collection name for reported municipal issues. */
|
|
5
5
|
exports.MUNI_ISSUES_COLLECTION = "muniIssues";
|
|
6
6
|
/** Sync state of the issue's Jira ticket at write time. */
|
|
7
7
|
exports.MUNI_ISSUE_SYNC_STATUSES = ["created", "failed"];
|
|
8
|
-
/** Customer-facing complaint status, set manually by the TalkPilot team. */
|
|
9
|
-
exports.MUNI_ISSUE_STATUSES = [
|
|
10
|
-
"in_review",
|
|
11
|
-
"in_progress",
|
|
12
|
-
"resolved",
|
|
13
|
-
"no_issue_found",
|
|
14
|
-
];
|
|
15
8
|
/** Max length for the long free-text fields — well above the ~2000-char target. */
|
|
16
9
|
exports.MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
|
|
17
10
|
/** Max length for the short identity fields (a person's name and role). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.constants.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,YAAY,CAAC;AAEnD,2DAA2D;AAC9C,QAAA,wBAAwB,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAEvE,
|
|
1
|
+
{"version":3,"file":"muniIssues.constants.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,YAAY,CAAC;AAEnD,2DAA2D;AAC9C,QAAA,wBAAwB,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAEvE,mFAAmF;AACtE,QAAA,0BAA0B,GAAG,IAAI,CAAC;AAE/C,2EAA2E;AAC9D,QAAA,0BAA0B,GAAG,GAAG,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAEnC,yEAAyE;AAC5D,QAAA,gBAAgB,GAAG,QAAiB,CAAC;AACrC,QAAA,iBAAiB,GAAG,OAAgB,CAAC"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { Collection, ObjectId } from "mongodb";
|
|
2
|
-
import {
|
|
2
|
+
import { MuniIssue } from "./muniIssues.types";
|
|
3
3
|
export declare const getMuniIssuesCollection: () => Collection<MuniIssue>;
|
|
4
4
|
export declare const generateMuniIssueId: () => ObjectId;
|
|
5
5
|
export declare const getMuniIssueById: (id: string) => Promise<MuniIssue | null>;
|
|
6
6
|
export declare const getMuniIssueByJiraKey: (jiraKey: string) => Promise<MuniIssue | null>;
|
|
7
|
-
/** A client's tracked issues, newest first. `limit` 0 means no limit (Mongo). */
|
|
8
|
-
export declare const findMuniIssuesByClient: (clientId: string, { answered, skip, limit }?: FindMuniIssuesOptions) => Promise<MuniIssue[]>;
|
|
9
|
-
export declare const countMuniIssuesByClient: (clientId: string, { answered }?: Pick<FindMuniIssuesOptions, "answered">) => Promise<number>;
|
|
10
|
-
/** One tracked issue, only if it belongs to the client. */
|
|
11
|
-
export declare const getMuniIssueByIdForClient: (id: string, clientId: string) => Promise<MuniIssue | null>;
|
|
12
7
|
//# sourceMappingURL=muniIssues.getters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.getters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"muniIssues.getters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,eAAO,MAAM,uBAAuB,QAAO,UAAU,CAAC,SAAS,CAE9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,QAA0B,CAAC;AAElE,eAAO,MAAM,gBAAgB,GAC3B,IAAI,MAAM,KACT,OAAO,CAAC,SAAS,GAAG,IAAI,CAI1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAE1B,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getMuniIssueByJiraKey = exports.getMuniIssueById = exports.generateMuniIssueId = exports.getMuniIssuesCollection = void 0;
|
|
4
4
|
const mongodb_1 = require("mongodb");
|
|
5
5
|
const index_1 = require("../index");
|
|
6
6
|
const muniIssues_constants_1 = require("./muniIssues.constants");
|
|
@@ -21,34 +21,4 @@ const getMuniIssueByJiraKey = async (jiraKey) => {
|
|
|
21
21
|
return (0, exports.getMuniIssuesCollection)().findOne({ "jira.key": jiraKey });
|
|
22
22
|
};
|
|
23
23
|
exports.getMuniIssueByJiraKey = getMuniIssueByJiraKey;
|
|
24
|
-
// Tracked issues of one client. Issues without a status predate complaint tracking and are excluded.
|
|
25
|
-
const clientIssuesFilter = (clientId, answered) => ({
|
|
26
|
-
clientId,
|
|
27
|
-
status: { $exists: true },
|
|
28
|
-
...(answered !== undefined && { response: { $exists: answered } }),
|
|
29
|
-
});
|
|
30
|
-
/** A client's tracked issues, newest first. `limit` 0 means no limit (Mongo). */
|
|
31
|
-
const findMuniIssuesByClient = async (clientId, { answered, skip = 0, limit = 0 } = {}) => {
|
|
32
|
-
return (0, exports.getMuniIssuesCollection)()
|
|
33
|
-
.find(clientIssuesFilter(clientId, answered))
|
|
34
|
-
.sort({ createdAt: -1 })
|
|
35
|
-
.skip(skip)
|
|
36
|
-
.limit(limit)
|
|
37
|
-
.toArray();
|
|
38
|
-
};
|
|
39
|
-
exports.findMuniIssuesByClient = findMuniIssuesByClient;
|
|
40
|
-
const countMuniIssuesByClient = async (clientId, { answered } = {}) => {
|
|
41
|
-
return (0, exports.getMuniIssuesCollection)().countDocuments(clientIssuesFilter(clientId, answered));
|
|
42
|
-
};
|
|
43
|
-
exports.countMuniIssuesByClient = countMuniIssuesByClient;
|
|
44
|
-
/** One tracked issue, only if it belongs to the client. */
|
|
45
|
-
const getMuniIssueByIdForClient = async (id, clientId) => {
|
|
46
|
-
if (!mongodb_1.ObjectId.isValid(id))
|
|
47
|
-
return null;
|
|
48
|
-
return (0, exports.getMuniIssuesCollection)().findOne({
|
|
49
|
-
...clientIssuesFilter(clientId),
|
|
50
|
-
_id: new mongodb_1.ObjectId(id),
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
exports.getMuniIssueByIdForClient = getMuniIssueByIdForClient;
|
|
54
24
|
//# sourceMappingURL=muniIssues.getters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.getters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"muniIssues.getters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":";;;AAAA,qCAA+C;AAC/C,oCAAiC;AAEjC,iEAAgE;AAEzD,MAAM,uBAAuB,GAAG,GAA0B,EAAE;IACjE,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAY,6CAAsB,CAAC,CAAC;AAC/D,CAAC,CAAC;AAFW,QAAA,uBAAuB,2BAElC;AAEK,MAAM,mBAAmB,GAAG,GAAa,EAAE,CAAC,IAAI,kBAAQ,EAAE,CAAC;AAArD,QAAA,mBAAmB,uBAAkC;AAE3D,MAAM,gBAAgB,GAAG,KAAK,EACnC,EAAU,EACiB,EAAE;IAC7B,iFAAiF;IACjF,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AANW,QAAA,gBAAgB,oBAM3B;AAEK,MAAM,qBAAqB,GAAG,KAAK,EACxC,OAAe,EACY,EAAE;IAC7B,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;AACpE,CAAC,CAAC;AAJW,QAAA,qBAAqB,yBAIhC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.schema.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"muniIssues.schema.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAO1D,eAAO,MAAM,oBAAoB,EAAE,QAmDlC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAK/C,CAAC"}
|
|
@@ -52,24 +52,11 @@ exports.muniIssuesJsonSchema = {
|
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
54
|
createdAt: { bsonType: "date" },
|
|
55
|
-
status: { enum: [...muniIssues_constants_1.MUNI_ISSUE_STATUSES] },
|
|
56
|
-
response: {
|
|
57
|
-
bsonType: "object",
|
|
58
|
-
required: ["text", "createdAt"],
|
|
59
|
-
properties: {
|
|
60
|
-
text: { bsonType: "string", maxLength: muniIssues_constants_1.MUNI_ISSUE_TEXT_MAX_LENGTH },
|
|
61
|
-
imageUrl: { bsonType: "string" },
|
|
62
|
-
createdAt: { bsonType: "date" },
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
updatedAt: { bsonType: "date" },
|
|
66
55
|
},
|
|
67
56
|
};
|
|
68
57
|
exports.muniIssuesIndexes = [
|
|
69
58
|
{ key: { callSid: 1 }, name: "callSid_1" },
|
|
70
59
|
{ key: { createdAt: -1 }, name: "createdAt_-1" },
|
|
71
|
-
// Complaint list: one municipality's issues, newest first.
|
|
72
|
-
{ key: { clientId: 1, createdAt: -1 }, name: "clientId_1_createdAt_-1" },
|
|
73
60
|
// Unique: one stored document per Jira ticket, guarding against duplicate writes.
|
|
74
61
|
{ key: { "jira.key": 1 }, name: "jira_key_unique", unique: true },
|
|
75
62
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.schema.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":";;;AACA,
|
|
1
|
+
{"version":3,"file":"muniIssues.schema.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":";;;AACA,iEAIgC;AAEnB,QAAA,oBAAoB,GAAa;IAC5C,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE;QACR,SAAS;QACT,UAAU;QACV,UAAU;QACV,cAAc;QACd,MAAM;QACN,WAAW;KACZ;IACD,UAAU,EAAE;QACV,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAC/B,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,YAAY,EAAE;YACZ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE;gBACR,YAAY;gBACZ,YAAY;gBACZ,kBAAkB;gBAClB,iBAAiB;aAClB;YACD,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,gBAAgB,EAAE;oBAChB,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,eAAe,EAAE;oBACf,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;aACF;SACF;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;YAC/B,UAAU,EAAE;gBACV,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,+CAAwB,CAAC,EAAE;aACpD;SACF;QACD,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;KAChC;CACF,CAAC;AAEW,QAAA,iBAAiB,GAAuB;IACnD,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;IAC1C,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;IAChD,kFAAkF;IAClF,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE;CAClE,CAAC"}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { ObjectId } from "mongodb";
|
|
2
|
-
import { CreateMuniIssueInput
|
|
2
|
+
import { CreateMuniIssueInput } from "./muniIssues.types";
|
|
3
3
|
export declare const createMuniIssue: (issueData: CreateMuniIssueInput, id: ObjectId) => Promise<ObjectId>;
|
|
4
|
-
/** Changes the status of an unanswered issue. Returns false if none matched. */
|
|
5
|
-
export declare const updateMuniIssueStatus: (id: string, clientId: string, status: MuniIssueStatus) => Promise<boolean>;
|
|
6
|
-
/** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
|
|
7
|
-
export declare const setMuniIssueResponse: (id: string, clientId: string, { status, text, imageUrl }: SetMuniIssueResponseInput) => Promise<boolean>;
|
|
8
4
|
//# sourceMappingURL=muniIssues.setters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.setters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"muniIssues.setters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAa,MAAM,oBAAoB,CAAC;AAKrE,eAAO,MAAM,eAAe,GAC1B,WAAW,oBAAoB,EAC/B,IAAI,QAAQ,KACX,OAAO,CAAC,QAAQ,CAclB,CAAC"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const mongodb_1 = require("mongodb");
|
|
3
|
+
exports.createMuniIssue = void 0;
|
|
5
4
|
const muniIssues_getters_1 = require("./muniIssues.getters");
|
|
6
5
|
const muniIssues_setup_1 = require("./muniIssues.setup");
|
|
7
6
|
// Required `id`: MIS pre-generates it (generateMuniIssueId) and embeds it in the Jira ticket — the two-way link.
|
|
8
7
|
const createMuniIssue = async (issueData, id) => {
|
|
9
8
|
await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
|
|
10
|
-
const now = new Date();
|
|
11
9
|
const issue = {
|
|
12
10
|
_id: id,
|
|
13
11
|
...issueData,
|
|
@@ -15,45 +13,10 @@ const createMuniIssue = async (issueData, id) => {
|
|
|
15
13
|
...issueData.jira,
|
|
16
14
|
syncStatus: issueData.jira.syncStatus ?? "created",
|
|
17
15
|
},
|
|
18
|
-
|
|
19
|
-
createdAt: now,
|
|
20
|
-
updatedAt: now,
|
|
16
|
+
createdAt: new Date(),
|
|
21
17
|
};
|
|
22
18
|
const { insertedId } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().insertOne(issue);
|
|
23
19
|
return insertedId;
|
|
24
20
|
};
|
|
25
21
|
exports.createMuniIssue = createMuniIssue;
|
|
26
|
-
// An issue of this client that is tracked (has a status) and not yet answered.
|
|
27
|
-
// The `response` condition is the lock: once answered, no further writes match.
|
|
28
|
-
const openIssueFilter = (id, clientId) => ({
|
|
29
|
-
_id: new mongodb_1.ObjectId(id),
|
|
30
|
-
clientId,
|
|
31
|
-
status: { $exists: true },
|
|
32
|
-
response: { $exists: false },
|
|
33
|
-
});
|
|
34
|
-
/** Changes the status of an unanswered issue. Returns false if none matched. */
|
|
35
|
-
const updateMuniIssueStatus = async (id, clientId, status) => {
|
|
36
|
-
if (!mongodb_1.ObjectId.isValid(id))
|
|
37
|
-
return false;
|
|
38
|
-
await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
|
|
39
|
-
const { matchedCount } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().updateOne(openIssueFilter(id, clientId), { $set: { status, updatedAt: new Date() } });
|
|
40
|
-
return matchedCount > 0;
|
|
41
|
-
};
|
|
42
|
-
exports.updateMuniIssueStatus = updateMuniIssueStatus;
|
|
43
|
-
/** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
|
|
44
|
-
const setMuniIssueResponse = async (id, clientId, { status, text, imageUrl }) => {
|
|
45
|
-
if (!mongodb_1.ObjectId.isValid(id))
|
|
46
|
-
return false;
|
|
47
|
-
await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
|
|
48
|
-
const now = new Date();
|
|
49
|
-
const { matchedCount } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().updateOne(openIssueFilter(id, clientId), {
|
|
50
|
-
$set: {
|
|
51
|
-
status,
|
|
52
|
-
response: { text, ...(imageUrl && { imageUrl }), createdAt: now },
|
|
53
|
-
updatedAt: now,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
return matchedCount > 0;
|
|
57
|
-
};
|
|
58
|
-
exports.setMuniIssueResponse = setMuniIssueResponse;
|
|
59
22
|
//# sourceMappingURL=muniIssues.setters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.setters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"muniIssues.setters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":";;;AAEA,6DAA+D;AAC/D,yDAAoE;AAEpE,iHAAiH;AAC1G,MAAM,eAAe,GAAG,KAAK,EAClC,SAA+B,EAC/B,EAAY,EACO,EAAE;IACrB,MAAM,IAAA,iDAA8B,GAAE,CAAC;IAEvC,MAAM,KAAK,GAAc;QACvB,GAAG,EAAE,EAAE;QACP,GAAG,SAAS;QACZ,IAAI,EAAE;YACJ,GAAG,SAAS,CAAC,IAAI;YACjB,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,SAAS;SACnD;QACD,SAAS,EAAE,IAAI,IAAI,EAAE;KACtB,CAAC;IACF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,4CAAuB,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxE,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AAjBW,QAAA,eAAe,mBAiB1B"}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { ObjectId } from "mongodb";
|
|
2
2
|
import { CityName } from "../utils/types";
|
|
3
|
-
import {
|
|
3
|
+
import { MUNI_ISSUE_SYNC_STATUSES } from "./muniIssues.constants";
|
|
4
4
|
export type MuniIssueSyncStatus = (typeof MUNI_ISSUE_SYNC_STATUSES)[number];
|
|
5
|
-
export type MuniIssueStatus = (typeof MUNI_ISSUE_STATUSES)[number];
|
|
6
|
-
/** The single TalkPilot response; once set, the complaint is locked. */
|
|
7
|
-
export type MuniIssueResponse = {
|
|
8
|
-
text: string;
|
|
9
|
-
imageUrl?: string;
|
|
10
|
-
createdAt: Date;
|
|
11
|
-
};
|
|
12
5
|
export type MuniIssueContent = {
|
|
13
6
|
issuerName: string;
|
|
14
7
|
issuerRole: string;
|
|
@@ -27,25 +20,11 @@ export type MuniIssue = {
|
|
|
27
20
|
issueContent: MuniIssueContent;
|
|
28
21
|
jira: MuniIssueJira;
|
|
29
22
|
createdAt: Date;
|
|
30
|
-
status?: MuniIssueStatus;
|
|
31
|
-
response?: MuniIssueResponse;
|
|
32
|
-
updatedAt?: Date;
|
|
33
23
|
};
|
|
34
|
-
export type CreateMuniIssueInput = Omit<MuniIssue, "_id" | "createdAt" | "jira"
|
|
24
|
+
export type CreateMuniIssueInput = Omit<MuniIssue, "_id" | "createdAt" | "jira"> & {
|
|
35
25
|
jira: {
|
|
36
26
|
key: string;
|
|
37
27
|
syncStatus?: MuniIssueSyncStatus;
|
|
38
28
|
};
|
|
39
29
|
};
|
|
40
|
-
export type SetMuniIssueResponseInput = {
|
|
41
|
-
status: MuniIssueStatus;
|
|
42
|
-
text: string;
|
|
43
|
-
imageUrl?: string;
|
|
44
|
-
};
|
|
45
|
-
/** `answered` filters by whether a TalkPilot response exists; omit it for all issues. */
|
|
46
|
-
export type FindMuniIssuesOptions = {
|
|
47
|
-
answered?: boolean;
|
|
48
|
-
skip?: number;
|
|
49
|
-
limit?: number;
|
|
50
|
-
};
|
|
51
30
|
//# sourceMappingURL=muniIssues.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muniIssues.types.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,
|
|
1
|
+
{"version":3,"file":"muniIssues.types.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,QAAQ,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAIF,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,SAAS,EACT,KAAK,GAAG,WAAW,GAAG,MAAM,CAC7B,GAAG;IACF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;KAAE,CAAC;CACzD,CAAC"}
|
|
@@ -32,4 +32,11 @@ export declare const CallStatusValues: {
|
|
|
32
32
|
readonly Canceled: "canceled";
|
|
33
33
|
};
|
|
34
34
|
export declare const ALL_CALL_STATUSES: ("in-progress" | "answered" | "no-answer" | "completed" | "busy" | "failed" | "canceled" | "initiated" | "ringing")[];
|
|
35
|
+
/** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
|
|
36
|
+
export declare const CallEndedByValues: {
|
|
37
|
+
readonly System: "system";
|
|
38
|
+
readonly Agent: "agent";
|
|
39
|
+
readonly User: "user";
|
|
40
|
+
readonly Human: "human";
|
|
41
|
+
};
|
|
35
42
|
//# sourceMappingURL=calls.constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.constants.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAG,UAAmB,CAAC;AAE5D,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,EAAG,YAAqB,CAAC;AAEhE,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AAErE,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mEAMjB,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,eAAO,MAAM,iBAAiB,uHAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"calls.constants.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAG,UAAmB,CAAC;AAE5D,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,EAAG,YAAqB,CAAC;AAEhE,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AAErE,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mEAMjB,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,eAAO,MAAM,iBAAiB,uHAAkC,CAAC;AAEjE,uGAAuG;AACvG,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ALL_CALL_STATUSES = exports.CallStatusValues = exports.TOOL_EXECUTIONS_DEFAULT_LIMIT = exports.TOOL_EXECUTIONS_DEFAULT_SKIP = exports.TREND_WEEK_BUCKET_MIN_MONTHS = exports.TREND_MONTH_BUCKET_MIN_MONTHS = exports.STATS_MAX_TIME_MS = exports.HOURS_PER_DAY = exports.FINAL_STATUSES = exports.IN_CALL_STATUSES = exports.CONFERENCE_ROLE_SUPERVISOR = exports.CONFERENCE_ROLE_CUSTOMER = void 0;
|
|
3
|
+
exports.CallEndedByValues = exports.ALL_CALL_STATUSES = exports.CallStatusValues = exports.TOOL_EXECUTIONS_DEFAULT_LIMIT = exports.TOOL_EXECUTIONS_DEFAULT_SKIP = exports.TREND_WEEK_BUCKET_MIN_MONTHS = exports.TREND_MONTH_BUCKET_MIN_MONTHS = exports.STATS_MAX_TIME_MS = exports.HOURS_PER_DAY = exports.FINAL_STATUSES = exports.IN_CALL_STATUSES = exports.CONFERENCE_ROLE_SUPERVISOR = exports.CONFERENCE_ROLE_CUSTOMER = void 0;
|
|
4
4
|
/** Customer role within a conference call. */
|
|
5
5
|
exports.CONFERENCE_ROLE_CUSTOMER = "customer";
|
|
6
6
|
/** Supervisor role within a conference call. */
|
|
@@ -41,4 +41,11 @@ exports.CallStatusValues = {
|
|
|
41
41
|
Canceled: "canceled",
|
|
42
42
|
};
|
|
43
43
|
exports.ALL_CALL_STATUSES = Object.values(exports.CallStatusValues);
|
|
44
|
+
/** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
|
|
45
|
+
exports.CallEndedByValues = {
|
|
46
|
+
System: "system",
|
|
47
|
+
Agent: "agent",
|
|
48
|
+
User: "user",
|
|
49
|
+
Human: "human",
|
|
50
|
+
};
|
|
44
51
|
//# sourceMappingURL=calls.constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.constants.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AACjC,QAAA,wBAAwB,GAAG,UAAmB,CAAC;AAE5D,gDAAgD;AACnC,QAAA,0BAA0B,GAAG,YAAqB,CAAC;AAEhE,wEAAwE;AAC3D,QAAA,gBAAgB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAU,CAAC;AAErE,4EAA4E;AAC/D,QAAA,cAAc,GAAG;IAC5B,WAAW;IACX,WAAW;IACX,MAAM;IACN,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,6BAA6B;AAChB,QAAA,aAAa,GAAG,EAAE,CAAC;AAEhC,iEAAiE;AACpD,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAExC;;;;;GAKG;AACU,QAAA,6BAA6B,GAAG,CAAC,CAAC;AAClC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AAEjC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AACjC,QAAA,6BAA6B,GAAG,EAAE,CAAC;AAEnC,QAAA,gBAAgB,GAAG;IAC9B,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,aAAa;IACzB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"calls.constants.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AACjC,QAAA,wBAAwB,GAAG,UAAmB,CAAC;AAE5D,gDAAgD;AACnC,QAAA,0BAA0B,GAAG,YAAqB,CAAC;AAEhE,wEAAwE;AAC3D,QAAA,gBAAgB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAU,CAAC;AAErE,4EAA4E;AAC/D,QAAA,cAAc,GAAG;IAC5B,WAAW;IACX,WAAW;IACX,MAAM;IACN,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,6BAA6B;AAChB,QAAA,aAAa,GAAG,EAAE,CAAC;AAEhC,iEAAiE;AACpD,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAExC;;;;;GAKG;AACU,QAAA,6BAA6B,GAAG,CAAC,CAAC;AAClC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AAEjC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AACjC,QAAA,6BAA6B,GAAG,EAAE,CAAC;AAEnC,QAAA,gBAAgB,GAAG;IAC9B,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,aAAa;IACzB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,CAAC;AAEjE,uGAAuG;AAC1F,QAAA,iBAAiB,GAAG;IAC/B,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACN,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Call, CallDoc, CallQueryOptions, CallUpdateParams } from "../index";
|
|
2
|
-
import type { CountOpts, DateRange, ToolExecution, CallStatus } from "./calls.types";
|
|
2
|
+
import type { CountOpts, DateRange, ToolExecution, CallStatus, CallEndedBy } from "./calls.types";
|
|
3
3
|
import { Filter, ObjectId } from "mongodb";
|
|
4
4
|
import { DashboardHeatmapMetric } from "./dashboard/calls.dashboard.types";
|
|
5
5
|
export declare const getCallsCollection: () => import("mongodb").Collection<Call>;
|
|
@@ -13,6 +13,7 @@ export declare const getToolExecutionsByCallSid: (callSid: string, opts?: Pick<C
|
|
|
13
13
|
clientId?: string;
|
|
14
14
|
}) => Promise<ToolExecution[]>;
|
|
15
15
|
export declare const updateCallStatusByCallSid: (callSid: string, status: CallStatus) => Promise<CallDoc | null>;
|
|
16
|
+
export declare const setCallEndedBy: (callSid: string, endedBy: CallEndedBy) => Promise<boolean>;
|
|
16
17
|
export declare const pushToolExecution: (callSid: string, execution: ToolExecution) => Promise<void>;
|
|
17
18
|
export declare const getCallsByClientAndDateRange: (clientId: string, startDate: Date, endDate: Date) => Promise<import("mongodb").WithId<Call>[]>;
|
|
18
19
|
export declare const findCallsByQuery: (query: Filter<Call>, options?: CallQueryOptions) => Promise<CallDoc[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"calls.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.getters.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.range = exports.countCalls = exports.findCallsByQuery = exports.getCallsByClientAndDateRange = exports.pushToolExecution = exports.updateCallStatusByCallSid = exports.getToolExecutionsByCallSid = exports.updateCallByCallSid = exports.createCallDoc = exports.getCallsByFlow = exports.getCallsByClient = exports.getCallsByPhoneNumber = exports.getCallByCallSid = exports.getCallsCollection = void 0;
|
|
36
|
+
exports.range = exports.countCalls = exports.findCallsByQuery = exports.getCallsByClientAndDateRange = exports.pushToolExecution = exports.setCallEndedBy = exports.updateCallStatusByCallSid = exports.getToolExecutionsByCallSid = exports.updateCallByCallSid = exports.createCallDoc = exports.getCallsByFlow = exports.getCallsByClient = exports.getCallsByPhoneNumber = exports.getCallByCallSid = exports.getCallsCollection = void 0;
|
|
37
37
|
exports.countCallsByPhoneInRange = countCallsByPhoneInRange;
|
|
38
38
|
exports.startOfDay = startOfDay;
|
|
39
39
|
exports.addDays = addDays;
|
|
@@ -95,6 +95,11 @@ const getToolExecutionsByCallSid = async (callSid, opts) => {
|
|
|
95
95
|
exports.getToolExecutionsByCallSid = getToolExecutionsByCallSid;
|
|
96
96
|
const updateCallStatusByCallSid = async (callSid, status) => (0, exports.getCallsCollection)().findOneAndUpdate({ callSid }, { $set: { status, updatedAt: new Date() } }, { returnDocument: "after" });
|
|
97
97
|
exports.updateCallStatusByCallSid = updateCallStatusByCallSid;
|
|
98
|
+
const setCallEndedBy = async (callSid, endedBy) => {
|
|
99
|
+
const result = await (0, exports.getCallsCollection)().updateOne({ callSid, endedBy: { $exists: false } }, { $set: { endedBy, updatedAt: new Date() } });
|
|
100
|
+
return result.modifiedCount > 0;
|
|
101
|
+
};
|
|
102
|
+
exports.setCallEndedBy = setCallEndedBy;
|
|
98
103
|
const pushToolExecution = async (callSid, execution) => {
|
|
99
104
|
await (0, exports.getCallsCollection)().updateOne({ callSid }, { $push: { toolExecutions: execution } });
|
|
100
105
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.getters.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"calls.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.getters.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { ObjectId, Sort, WithId } from "mongodb";
|
|
2
2
|
import { TranscriptionSegment } from "../results";
|
|
3
3
|
import { LeadProperty } from "../leads";
|
|
4
|
-
import { CallStatusValues, CONFERENCE_ROLE_CUSTOMER, CONFERENCE_ROLE_SUPERVISOR } from "./calls.constants";
|
|
4
|
+
import { CallEndedByValues, CallStatusValues, CONFERENCE_ROLE_CUSTOMER, CONFERENCE_ROLE_SUPERVISOR } from "./calls.constants";
|
|
5
5
|
export type ConferenceRole = typeof CONFERENCE_ROLE_CUSTOMER | typeof CONFERENCE_ROLE_SUPERVISOR | null;
|
|
6
6
|
export type CallStatus = (typeof CallStatusValues)[keyof typeof CallStatusValues];
|
|
7
|
+
export type CallEndedBy = (typeof CallEndedByValues)[keyof typeof CallEndedByValues];
|
|
8
|
+
/**
|
|
9
|
+
* Represents the call usage information with details about charging segments and quota impact.
|
|
10
|
+
*/
|
|
11
|
+
export type CallUsage = {
|
|
12
|
+
/** Length in minutes of a segment the call is charged by. */
|
|
13
|
+
minutesPerSegment: number;
|
|
14
|
+
/** Segments the call adds to the customer's quota. */
|
|
15
|
+
segments: number;
|
|
16
|
+
};
|
|
7
17
|
export type Call = {
|
|
8
18
|
callSid: string;
|
|
9
19
|
flowId: ObjectId;
|
|
@@ -16,6 +26,7 @@ export type Call = {
|
|
|
16
26
|
isIncomingCall: boolean;
|
|
17
27
|
isOutgoingCall: boolean;
|
|
18
28
|
callLength: number;
|
|
29
|
+
usage?: CallUsage;
|
|
19
30
|
transcription?: TranscriptionSegment[];
|
|
20
31
|
status?: CallStatus;
|
|
21
32
|
leads?: LeadProperty[];
|
|
@@ -27,6 +38,7 @@ export type Call = {
|
|
|
27
38
|
isAnsweredByAnsweringMachine?: boolean;
|
|
28
39
|
agentHungUp?: boolean;
|
|
29
40
|
endReason?: string;
|
|
41
|
+
endedBy?: CallEndedBy;
|
|
30
42
|
conferenceName?: string | null;
|
|
31
43
|
conferenceSid?: string | null;
|
|
32
44
|
conferenceParticipantSid?: string | null;
|
|
@@ -100,10 +112,12 @@ export type CallsFilterParams = {
|
|
|
100
112
|
runId?: string;
|
|
101
113
|
sessionId?: string;
|
|
102
114
|
isIncoming?: boolean;
|
|
115
|
+
billableCallsFrom?: number;
|
|
116
|
+
billableCallsTo?: number;
|
|
103
117
|
search?: string;
|
|
104
118
|
};
|
|
105
119
|
export type ImmutableCallFields = "customerPhoneNumber" | "agentPhoneNumber" | "isIncomingCall" | "isOutgoingCall" | "sessionId" | "callSid" | "flowId" | "clientId" | "runId" | "resultId" | "env" | "createdAt";
|
|
106
|
-
export type CallUpdateParams = Partial<Omit<Call, ImmutableCallFields>>;
|
|
120
|
+
export type CallUpdateParams = Partial<Omit<Call, ImmutableCallFields | "endedBy">>;
|
|
107
121
|
export type CallDoc = WithId<Call>;
|
|
108
122
|
/** @deprecated use DashboardHeatmapMetric instead */
|
|
109
123
|
export type CallsByHour = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"calls.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createMuniIssue,
|
|
3
|
-
setMuniIssueResponse,
|
|
4
|
-
updateMuniIssueStatus,
|
|
5
|
-
} from "../muniIssues.setters";
|
|
1
|
+
import { createMuniIssue } from "../muniIssues.setters";
|
|
6
2
|
import {
|
|
7
3
|
generateMuniIssueId,
|
|
8
4
|
getMuniIssueById,
|
|
@@ -29,18 +25,6 @@ describe("muniIssues setters", () => {
|
|
|
29
25
|
expect(saved?.createdAt).toBeInstanceOf(Date);
|
|
30
26
|
});
|
|
31
27
|
|
|
32
|
-
it("should start the issue as in_review with updatedAt and no response", async () => {
|
|
33
|
-
const insertedId = await createMuniIssue(
|
|
34
|
-
createMuniIssueInput(),
|
|
35
|
-
generateMuniIssueId(),
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
const saved = await getMuniIssueById(insertedId.toString());
|
|
39
|
-
expect(saved?.status).toBe("in_review");
|
|
40
|
-
expect(saved?.updatedAt).toBeInstanceOf(Date);
|
|
41
|
-
expect(saved?.response).toBeUndefined();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
28
|
it("should default jira.syncStatus to created when not provided", async () => {
|
|
45
29
|
const id = generateMuniIssueId();
|
|
46
30
|
|
|
@@ -107,61 +91,4 @@ describe("muniIssues setters", () => {
|
|
|
107
91
|
expect(await getMuniIssueByJiraKey("CP-nope")).toBeNull();
|
|
108
92
|
});
|
|
109
93
|
});
|
|
110
|
-
|
|
111
|
-
describe("updateMuniIssueStatus", () => {
|
|
112
|
-
it("should change the status of an unanswered issue", async () => {
|
|
113
|
-
const input = createMuniIssueInput();
|
|
114
|
-
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
115
|
-
|
|
116
|
-
expect(await updateMuniIssueStatus(id, input.clientId, "in_progress")).toBe(true);
|
|
117
|
-
expect((await getMuniIssueById(id))?.status).toBe("in_progress");
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should not touch another client's issue or a malformed id", async () => {
|
|
121
|
-
const id = (
|
|
122
|
-
await createMuniIssue(createMuniIssueInput(), generateMuniIssueId())
|
|
123
|
-
).toString();
|
|
124
|
-
|
|
125
|
-
expect(await updateMuniIssueStatus(id, "other-client", "resolved")).toBe(false);
|
|
126
|
-
expect(await updateMuniIssueStatus("not-a-valid-id", "any", "resolved")).toBe(false);
|
|
127
|
-
expect((await getMuniIssueById(id))?.status).toBe("in_review");
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("setMuniIssueResponse", () => {
|
|
132
|
-
it("should save the response and status", async () => {
|
|
133
|
-
const input = createMuniIssueInput();
|
|
134
|
-
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
135
|
-
|
|
136
|
-
const saved = await setMuniIssueResponse(id, input.clientId, {
|
|
137
|
-
status: "resolved",
|
|
138
|
-
text: "Fixed",
|
|
139
|
-
imageUrl: "https://example.com/a.png",
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
expect(saved).toBe(true);
|
|
143
|
-
const issue = await getMuniIssueById(id);
|
|
144
|
-
expect(issue?.status).toBe("resolved");
|
|
145
|
-
expect(issue?.response).toMatchObject({
|
|
146
|
-
text: "Fixed",
|
|
147
|
-
imageUrl: "https://example.com/a.png",
|
|
148
|
-
});
|
|
149
|
-
expect(issue?.response?.createdAt).toBeInstanceOf(Date);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it("should lock the issue: no second response and no status change", async () => {
|
|
153
|
-
const input = createMuniIssueInput();
|
|
154
|
-
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
155
|
-
await setMuniIssueResponse(id, input.clientId, { status: "resolved", text: "First" });
|
|
156
|
-
|
|
157
|
-
expect(
|
|
158
|
-
await setMuniIssueResponse(id, input.clientId, { status: "in_progress", text: "Second" }),
|
|
159
|
-
).toBe(false);
|
|
160
|
-
expect(await updateMuniIssueStatus(id, input.clientId, "in_progress")).toBe(false);
|
|
161
|
-
|
|
162
|
-
const issue = await getMuniIssueById(id);
|
|
163
|
-
expect(issue?.status).toBe("resolved");
|
|
164
|
-
expect(issue?.response?.text).toBe("First");
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
94
|
});
|
|
@@ -3,7 +3,6 @@ export * from "./muniIssues.setters";
|
|
|
3
3
|
export * from "./muniIssues.setup";
|
|
4
4
|
export {
|
|
5
5
|
MUNI_ISSUES_COLLECTION,
|
|
6
|
-
MUNI_ISSUE_STATUSES,
|
|
7
6
|
MUNI_ISSUE_SYNC_STATUSES,
|
|
8
7
|
MUNI_ISSUE_TEXT_MAX_LENGTH,
|
|
9
8
|
MUNI_ISSUE_NAME_MAX_LENGTH,
|
|
@@ -14,9 +13,5 @@ export type {
|
|
|
14
13
|
MuniIssueContent,
|
|
15
14
|
MuniIssueJira,
|
|
16
15
|
MuniIssueSyncStatus,
|
|
17
|
-
MuniIssueStatus,
|
|
18
|
-
MuniIssueResponse,
|
|
19
16
|
CreateMuniIssueInput,
|
|
20
|
-
SetMuniIssueResponseInput,
|
|
21
|
-
FindMuniIssuesOptions,
|
|
22
17
|
} from "./muniIssues.types";
|
|
@@ -4,14 +4,6 @@ export const MUNI_ISSUES_COLLECTION = "muniIssues";
|
|
|
4
4
|
/** Sync state of the issue's Jira ticket at write time. */
|
|
5
5
|
export const MUNI_ISSUE_SYNC_STATUSES = ["created", "failed"] as const;
|
|
6
6
|
|
|
7
|
-
/** Customer-facing complaint status, set manually by the TalkPilot team. */
|
|
8
|
-
export const MUNI_ISSUE_STATUSES = [
|
|
9
|
-
"in_review",
|
|
10
|
-
"in_progress",
|
|
11
|
-
"resolved",
|
|
12
|
-
"no_issue_found",
|
|
13
|
-
] as const;
|
|
14
|
-
|
|
15
7
|
/** Max length for the long free-text fields — well above the ~2000-char target. */
|
|
16
8
|
export const MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
|
|
17
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Collection,
|
|
1
|
+
import { Collection, ObjectId } from "mongodb";
|
|
2
2
|
import { getDb } from "../index";
|
|
3
|
-
import {
|
|
3
|
+
import { MuniIssue } from "./muniIssues.types";
|
|
4
4
|
import { MUNI_ISSUES_COLLECTION } from "./muniIssues.constants";
|
|
5
5
|
|
|
6
6
|
export const getMuniIssuesCollection = (): Collection<MuniIssue> => {
|
|
@@ -22,47 +22,3 @@ export const getMuniIssueByJiraKey = async (
|
|
|
22
22
|
): Promise<MuniIssue | null> => {
|
|
23
23
|
return getMuniIssuesCollection().findOne({ "jira.key": jiraKey });
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
// Tracked issues of one client. Issues without a status predate complaint tracking and are excluded.
|
|
27
|
-
const clientIssuesFilter = (
|
|
28
|
-
clientId: string,
|
|
29
|
-
answered?: boolean,
|
|
30
|
-
): Filter<MuniIssue> => ({
|
|
31
|
-
clientId,
|
|
32
|
-
status: { $exists: true },
|
|
33
|
-
...(answered !== undefined && { response: { $exists: answered } }),
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
/** A client's tracked issues, newest first. `limit` 0 means no limit (Mongo). */
|
|
37
|
-
export const findMuniIssuesByClient = async (
|
|
38
|
-
clientId: string,
|
|
39
|
-
{ answered, skip = 0, limit = 0 }: FindMuniIssuesOptions = {},
|
|
40
|
-
): Promise<MuniIssue[]> => {
|
|
41
|
-
return getMuniIssuesCollection()
|
|
42
|
-
.find(clientIssuesFilter(clientId, answered))
|
|
43
|
-
.sort({ createdAt: -1 })
|
|
44
|
-
.skip(skip)
|
|
45
|
-
.limit(limit)
|
|
46
|
-
.toArray();
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export const countMuniIssuesByClient = async (
|
|
50
|
-
clientId: string,
|
|
51
|
-
{ answered }: Pick<FindMuniIssuesOptions, "answered"> = {},
|
|
52
|
-
): Promise<number> => {
|
|
53
|
-
return getMuniIssuesCollection().countDocuments(
|
|
54
|
-
clientIssuesFilter(clientId, answered),
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/** One tracked issue, only if it belongs to the client. */
|
|
59
|
-
export const getMuniIssueByIdForClient = async (
|
|
60
|
-
id: string,
|
|
61
|
-
clientId: string,
|
|
62
|
-
): Promise<MuniIssue | null> => {
|
|
63
|
-
if (!ObjectId.isValid(id)) return null;
|
|
64
|
-
return getMuniIssuesCollection().findOne({
|
|
65
|
-
...clientIssuesFilter(clientId),
|
|
66
|
-
_id: new ObjectId(id),
|
|
67
|
-
});
|
|
68
|
-
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Document, IndexDescription } from "mongodb";
|
|
2
2
|
import {
|
|
3
|
-
MUNI_ISSUE_STATUSES,
|
|
4
3
|
MUNI_ISSUE_SYNC_STATUSES,
|
|
5
4
|
MUNI_ISSUE_TEXT_MAX_LENGTH,
|
|
6
5
|
MUNI_ISSUE_NAME_MAX_LENGTH,
|
|
@@ -56,25 +55,12 @@ export const muniIssuesJsonSchema: Document = {
|
|
|
56
55
|
},
|
|
57
56
|
},
|
|
58
57
|
createdAt: { bsonType: "date" },
|
|
59
|
-
status: { enum: [...MUNI_ISSUE_STATUSES] },
|
|
60
|
-
response: {
|
|
61
|
-
bsonType: "object",
|
|
62
|
-
required: ["text", "createdAt"],
|
|
63
|
-
properties: {
|
|
64
|
-
text: { bsonType: "string", maxLength: MUNI_ISSUE_TEXT_MAX_LENGTH },
|
|
65
|
-
imageUrl: { bsonType: "string" },
|
|
66
|
-
createdAt: { bsonType: "date" },
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
updatedAt: { bsonType: "date" },
|
|
70
58
|
},
|
|
71
59
|
};
|
|
72
60
|
|
|
73
61
|
export const muniIssuesIndexes: IndexDescription[] = [
|
|
74
62
|
{ key: { callSid: 1 }, name: "callSid_1" },
|
|
75
63
|
{ key: { createdAt: -1 }, name: "createdAt_-1" },
|
|
76
|
-
// Complaint list: one municipality's issues, newest first.
|
|
77
|
-
{ key: { clientId: 1, createdAt: -1 }, name: "clientId_1_createdAt_-1" },
|
|
78
64
|
// Unique: one stored document per Jira ticket, guarding against duplicate writes.
|
|
79
65
|
{ key: { "jira.key": 1 }, name: "jira_key_unique", unique: true },
|
|
80
66
|
];
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
CreateMuniIssueInput,
|
|
4
|
-
MuniIssue,
|
|
5
|
-
MuniIssueStatus,
|
|
6
|
-
SetMuniIssueResponseInput,
|
|
7
|
-
} from "./muniIssues.types";
|
|
1
|
+
import { ObjectId } from "mongodb";
|
|
2
|
+
import { CreateMuniIssueInput, MuniIssue } from "./muniIssues.types";
|
|
8
3
|
import { getMuniIssuesCollection } from "./muniIssues.getters";
|
|
9
4
|
import { ensureMuniIssuesCollectionOnce } from "./muniIssues.setup";
|
|
10
5
|
|
|
@@ -15,7 +10,6 @@ export const createMuniIssue = async (
|
|
|
15
10
|
): Promise<ObjectId> => {
|
|
16
11
|
await ensureMuniIssuesCollectionOnce();
|
|
17
12
|
|
|
18
|
-
const now = new Date();
|
|
19
13
|
const issue: MuniIssue = {
|
|
20
14
|
_id: id,
|
|
21
15
|
...issueData,
|
|
@@ -23,58 +17,8 @@ export const createMuniIssue = async (
|
|
|
23
17
|
...issueData.jira,
|
|
24
18
|
syncStatus: issueData.jira.syncStatus ?? "created",
|
|
25
19
|
},
|
|
26
|
-
|
|
27
|
-
createdAt: now,
|
|
28
|
-
updatedAt: now,
|
|
20
|
+
createdAt: new Date(),
|
|
29
21
|
};
|
|
30
22
|
const { insertedId } = await getMuniIssuesCollection().insertOne(issue);
|
|
31
23
|
return insertedId;
|
|
32
24
|
};
|
|
33
|
-
|
|
34
|
-
// An issue of this client that is tracked (has a status) and not yet answered.
|
|
35
|
-
// The `response` condition is the lock: once answered, no further writes match.
|
|
36
|
-
const openIssueFilter = (id: string, clientId: string): Filter<MuniIssue> => ({
|
|
37
|
-
_id: new ObjectId(id),
|
|
38
|
-
clientId,
|
|
39
|
-
status: { $exists: true },
|
|
40
|
-
response: { $exists: false },
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
/** Changes the status of an unanswered issue. Returns false if none matched. */
|
|
44
|
-
export const updateMuniIssueStatus = async (
|
|
45
|
-
id: string,
|
|
46
|
-
clientId: string,
|
|
47
|
-
status: MuniIssueStatus,
|
|
48
|
-
): Promise<boolean> => {
|
|
49
|
-
if (!ObjectId.isValid(id)) return false;
|
|
50
|
-
await ensureMuniIssuesCollectionOnce();
|
|
51
|
-
|
|
52
|
-
const { matchedCount } = await getMuniIssuesCollection().updateOne(
|
|
53
|
-
openIssueFilter(id, clientId),
|
|
54
|
-
{ $set: { status, updatedAt: new Date() } },
|
|
55
|
-
);
|
|
56
|
-
return matchedCount > 0;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
|
|
60
|
-
export const setMuniIssueResponse = async (
|
|
61
|
-
id: string,
|
|
62
|
-
clientId: string,
|
|
63
|
-
{ status, text, imageUrl }: SetMuniIssueResponseInput,
|
|
64
|
-
): Promise<boolean> => {
|
|
65
|
-
if (!ObjectId.isValid(id)) return false;
|
|
66
|
-
await ensureMuniIssuesCollectionOnce();
|
|
67
|
-
|
|
68
|
-
const now = new Date();
|
|
69
|
-
const { matchedCount } = await getMuniIssuesCollection().updateOne(
|
|
70
|
-
openIssueFilter(id, clientId),
|
|
71
|
-
{
|
|
72
|
-
$set: {
|
|
73
|
-
status,
|
|
74
|
-
response: { text, ...(imageUrl && { imageUrl }), createdAt: now },
|
|
75
|
-
updatedAt: now,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
);
|
|
79
|
-
return matchedCount > 0;
|
|
80
|
-
};
|
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { ObjectId } from "mongodb";
|
|
2
2
|
|
|
3
3
|
import { CityName } from "../utils/types";
|
|
4
|
-
import {
|
|
5
|
-
MUNI_ISSUE_STATUSES,
|
|
6
|
-
MUNI_ISSUE_SYNC_STATUSES,
|
|
7
|
-
} from "./muniIssues.constants";
|
|
4
|
+
import { MUNI_ISSUE_SYNC_STATUSES } from "./muniIssues.constants";
|
|
8
5
|
|
|
9
6
|
export type MuniIssueSyncStatus = (typeof MUNI_ISSUE_SYNC_STATUSES)[number];
|
|
10
7
|
|
|
11
|
-
export type MuniIssueStatus = (typeof MUNI_ISSUE_STATUSES)[number];
|
|
12
|
-
|
|
13
|
-
/** The single TalkPilot response; once set, the complaint is locked. */
|
|
14
|
-
export type MuniIssueResponse = {
|
|
15
|
-
text: string;
|
|
16
|
-
imageUrl?: string;
|
|
17
|
-
createdAt: Date;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
8
|
export type MuniIssueContent = {
|
|
21
9
|
issuerName: string;
|
|
22
10
|
issuerRole: string;
|
|
@@ -37,32 +25,13 @@ export type MuniIssue = {
|
|
|
37
25
|
issueContent: MuniIssueContent;
|
|
38
26
|
jira: MuniIssueJira;
|
|
39
27
|
createdAt: Date;
|
|
40
|
-
// Complaint tracking (CP-1888). Optional: issues created before it have none
|
|
41
|
-
// of these, which is how they are kept out of tracking.
|
|
42
|
-
status?: MuniIssueStatus;
|
|
43
|
-
response?: MuniIssueResponse;
|
|
44
|
-
updatedAt?: Date;
|
|
45
28
|
};
|
|
46
29
|
|
|
47
|
-
// _id/createdAt
|
|
48
|
-
//
|
|
49
|
-
// ticket exists (CP-1115).
|
|
30
|
+
// _id/createdAt are set on insert; jira.syncStatus defaults to "created"
|
|
31
|
+
// because the issue is only stored after its Jira ticket exists (CP-1115).
|
|
50
32
|
export type CreateMuniIssueInput = Omit<
|
|
51
33
|
MuniIssue,
|
|
52
|
-
"_id" | "createdAt" | "jira"
|
|
34
|
+
"_id" | "createdAt" | "jira"
|
|
53
35
|
> & {
|
|
54
36
|
jira: { key: string; syncStatus?: MuniIssueSyncStatus };
|
|
55
37
|
};
|
|
56
|
-
|
|
57
|
-
export type SetMuniIssueResponseInput = {
|
|
58
|
-
status: MuniIssueStatus;
|
|
59
|
-
text: string;
|
|
60
|
-
imageUrl?: string;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/** `answered` filters by whether a TalkPilot response exists; omit it for all issues. */
|
|
64
|
-
export type FindMuniIssuesOptions = {
|
|
65
|
-
answered?: boolean;
|
|
66
|
-
skip?: number;
|
|
67
|
-
limit?: number;
|
|
68
|
-
};
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
pushToolExecution,
|
|
12
12
|
getToolExecutionsByCallSid,
|
|
13
13
|
updateCallStatusByCallSid,
|
|
14
|
+
setCallEndedBy,
|
|
14
15
|
} from "../calls.getters";
|
|
15
16
|
import type { ToolExecution, ToolExecutionStep } from "../calls.types";
|
|
16
17
|
import { ObjectId } from "mongodb";
|
|
@@ -74,6 +75,53 @@ describe("db.calls", () => {
|
|
|
74
75
|
});
|
|
75
76
|
});
|
|
76
77
|
|
|
78
|
+
describe("setCallEndedBy()", () => {
|
|
79
|
+
it("should set endedBy when it is not set yet", async () => {
|
|
80
|
+
const call = createOutGoingCallDoc();
|
|
81
|
+
await createCallDoc(call);
|
|
82
|
+
|
|
83
|
+
const written = await setCallEndedBy(call.callSid, "user");
|
|
84
|
+
|
|
85
|
+
expect(written).toBe(true);
|
|
86
|
+
expect(await getCallByCallSid(call.callSid)).toMatchObject({
|
|
87
|
+
endedBy: "user",
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should keep the first value when called again", async () => {
|
|
92
|
+
const call = createOutGoingCallDoc();
|
|
93
|
+
await createCallDoc(call);
|
|
94
|
+
|
|
95
|
+
await setCallEndedBy(call.callSid, "user");
|
|
96
|
+
const written = await setCallEndedBy(call.callSid, "agent");
|
|
97
|
+
|
|
98
|
+
expect(written).toBe(false);
|
|
99
|
+
expect(await getCallByCallSid(call.callSid)).toMatchObject({
|
|
100
|
+
endedBy: "user",
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should let only one of two concurrent writers win", async () => {
|
|
105
|
+
const call = createOutGoingCallDoc();
|
|
106
|
+
await createCallDoc(call);
|
|
107
|
+
|
|
108
|
+
const results = await Promise.all([
|
|
109
|
+
setCallEndedBy(call.callSid, "user"),
|
|
110
|
+
setCallEndedBy(call.callSid, "human"),
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
expect(results.filter(Boolean)).toHaveLength(1);
|
|
114
|
+
const stored = await getCallByCallSid(call.callSid);
|
|
115
|
+
expect(stored?.endedBy).toBe(results[0] ? "user" : "human");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("should return false when the call does not exist", async () => {
|
|
119
|
+
await expect(setCallEndedBy("nonexistent-sid", "system")).resolves.toBe(
|
|
120
|
+
false,
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
77
125
|
describe("findCallsByQuery()", () => {
|
|
78
126
|
it("should find calls by status with limit and sort", async () => {
|
|
79
127
|
const clientId = "client123";
|
|
@@ -47,3 +47,11 @@ export const CallStatusValues = {
|
|
|
47
47
|
} as const;
|
|
48
48
|
|
|
49
49
|
export const ALL_CALL_STATUSES = Object.values(CallStatusValues);
|
|
50
|
+
|
|
51
|
+
/** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
|
|
52
|
+
export const CallEndedByValues = {
|
|
53
|
+
System: "system",
|
|
54
|
+
Agent: "agent",
|
|
55
|
+
User: "user",
|
|
56
|
+
Human: "human",
|
|
57
|
+
} as const;
|
|
@@ -5,7 +5,13 @@ import {
|
|
|
5
5
|
CallUpdateParams,
|
|
6
6
|
getDb,
|
|
7
7
|
} from "../index";
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
CountOpts,
|
|
10
|
+
DateRange,
|
|
11
|
+
ToolExecution,
|
|
12
|
+
CallStatus,
|
|
13
|
+
CallEndedBy,
|
|
14
|
+
} from "./calls.types";
|
|
9
15
|
import {
|
|
10
16
|
TOOL_EXECUTIONS_DEFAULT_LIMIT,
|
|
11
17
|
TOOL_EXECUTIONS_DEFAULT_SKIP,
|
|
@@ -89,6 +95,18 @@ export const updateCallStatusByCallSid = async (
|
|
|
89
95
|
{ returnDocument: "after" },
|
|
90
96
|
);
|
|
91
97
|
|
|
98
|
+
|
|
99
|
+
export const setCallEndedBy = async (
|
|
100
|
+
callSid: string,
|
|
101
|
+
endedBy: CallEndedBy,
|
|
102
|
+
): Promise<boolean> => {
|
|
103
|
+
const result = await getCallsCollection().updateOne(
|
|
104
|
+
{ callSid, endedBy: { $exists: false } },
|
|
105
|
+
{ $set: { endedBy, updatedAt: new Date() } },
|
|
106
|
+
);
|
|
107
|
+
return result.modifiedCount > 0;
|
|
108
|
+
};
|
|
109
|
+
|
|
92
110
|
export const pushToolExecution = async (
|
|
93
111
|
callSid: string,
|
|
94
112
|
execution: ToolExecution,
|
|
@@ -3,6 +3,7 @@ import { TranscriptionSegment } from "../results";
|
|
|
3
3
|
import { LeadProperty } from "../leads";
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
CallEndedByValues,
|
|
6
7
|
CallStatusValues,
|
|
7
8
|
CONFERENCE_ROLE_CUSTOMER,
|
|
8
9
|
CONFERENCE_ROLE_SUPERVISOR,
|
|
@@ -15,6 +16,18 @@ export type ConferenceRole =
|
|
|
15
16
|
|
|
16
17
|
export type CallStatus = (typeof CallStatusValues)[keyof typeof CallStatusValues];
|
|
17
18
|
|
|
19
|
+
export type CallEndedBy = (typeof CallEndedByValues)[keyof typeof CallEndedByValues];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents the call usage information with details about charging segments and quota impact.
|
|
23
|
+
*/
|
|
24
|
+
export type CallUsage = {
|
|
25
|
+
/** Length in minutes of a segment the call is charged by. */
|
|
26
|
+
minutesPerSegment: number;
|
|
27
|
+
/** Segments the call adds to the customer's quota. */
|
|
28
|
+
segments: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
18
31
|
export type Call = {
|
|
19
32
|
callSid: string;
|
|
20
33
|
flowId: ObjectId;
|
|
@@ -27,6 +40,7 @@ export type Call = {
|
|
|
27
40
|
isIncomingCall: boolean;
|
|
28
41
|
isOutgoingCall: boolean;
|
|
29
42
|
callLength: number;
|
|
43
|
+
usage?: CallUsage;
|
|
30
44
|
transcription?: TranscriptionSegment[];
|
|
31
45
|
status?: CallStatus;
|
|
32
46
|
leads?: LeadProperty[];
|
|
@@ -38,6 +52,7 @@ export type Call = {
|
|
|
38
52
|
isAnsweredByAnsweringMachine?: boolean;
|
|
39
53
|
agentHungUp?: boolean;
|
|
40
54
|
endReason?: string;
|
|
55
|
+
endedBy?: CallEndedBy;
|
|
41
56
|
conferenceName?: string | null;
|
|
42
57
|
conferenceSid?: string | null;
|
|
43
58
|
conferenceParticipantSid?: string | null;
|
|
@@ -116,6 +131,8 @@ export type CallsFilterParams = {
|
|
|
116
131
|
runId?: string;
|
|
117
132
|
sessionId?: string;
|
|
118
133
|
isIncoming?: boolean;
|
|
134
|
+
billableCallsFrom?: number;
|
|
135
|
+
billableCallsTo?: number;
|
|
119
136
|
search?: string;
|
|
120
137
|
};
|
|
121
138
|
|
|
@@ -133,7 +150,7 @@ export type ImmutableCallFields =
|
|
|
133
150
|
| "env"
|
|
134
151
|
| "createdAt";
|
|
135
152
|
|
|
136
|
-
export type CallUpdateParams = Partial<Omit<Call, ImmutableCallFields>>;
|
|
153
|
+
export type CallUpdateParams = Partial<Omit<Call, ImmutableCallFields | "endedBy">>;
|
|
137
154
|
|
|
138
155
|
export type CallDoc = WithId<Call>;
|
|
139
156
|
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { ObjectId } from "mongodb";
|
|
2
|
-
import { createMuniIssue, setMuniIssueResponse } from "../muniIssues.setters";
|
|
3
|
-
import {
|
|
4
|
-
countMuniIssuesByClient,
|
|
5
|
-
findMuniIssuesByClient,
|
|
6
|
-
generateMuniIssueId,
|
|
7
|
-
getMuniIssueByIdForClient,
|
|
8
|
-
getMuniIssuesCollection,
|
|
9
|
-
} from "../muniIssues.getters";
|
|
10
|
-
import { createMuniIssueInput } from "../../../test-utils/factories";
|
|
11
|
-
|
|
12
|
-
const CLIENT = "client-a";
|
|
13
|
-
|
|
14
|
-
const createIssue = async (clientId = CLIENT) =>
|
|
15
|
-
(await createMuniIssue(createMuniIssueInput({ clientId }), generateMuniIssueId())).toString();
|
|
16
|
-
|
|
17
|
-
describe("muniIssues getters (complaint tracking)", () => {
|
|
18
|
-
describe("findMuniIssuesByClient / countMuniIssuesByClient", () => {
|
|
19
|
-
it("should return only the client's tracked issues, newest first", async () => {
|
|
20
|
-
const older = await createIssue();
|
|
21
|
-
const newer = await createIssue();
|
|
22
|
-
// Both can land in the same millisecond; make the order explicit.
|
|
23
|
-
await getMuniIssuesCollection().updateOne(
|
|
24
|
-
{ _id: new ObjectId(older) },
|
|
25
|
-
{ $set: { createdAt: new Date(Date.now() - 60_000) } },
|
|
26
|
-
);
|
|
27
|
-
await createIssue("client-b");
|
|
28
|
-
// An issue created before complaint tracking has no status.
|
|
29
|
-
await getMuniIssuesCollection().insertOne({
|
|
30
|
-
...createMuniIssueInput({ clientId: CLIENT }),
|
|
31
|
-
_id: generateMuniIssueId(),
|
|
32
|
-
jira: { key: "CP-legacy", syncStatus: "created" },
|
|
33
|
-
createdAt: new Date(),
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const issues = await findMuniIssuesByClient(CLIENT);
|
|
37
|
-
|
|
38
|
-
expect(issues.map((i) => i._id.toString())).toEqual([newer, older]);
|
|
39
|
-
expect(await countMuniIssuesByClient(CLIENT)).toBe(2);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("should filter by answered and apply skip/limit", async () => {
|
|
43
|
-
const answered = await createIssue();
|
|
44
|
-
await createIssue();
|
|
45
|
-
await createIssue();
|
|
46
|
-
await setMuniIssueResponse(answered, CLIENT, { status: "resolved", text: "Done" });
|
|
47
|
-
|
|
48
|
-
expect(await countMuniIssuesByClient(CLIENT, { answered: true })).toBe(1);
|
|
49
|
-
expect(await countMuniIssuesByClient(CLIENT, { answered: false })).toBe(2);
|
|
50
|
-
expect(
|
|
51
|
-
(await findMuniIssuesByClient(CLIENT, { answered: true }))[0]._id.toString(),
|
|
52
|
-
).toBe(answered);
|
|
53
|
-
expect(await findMuniIssuesByClient(CLIENT, { skip: 1, limit: 1 })).toHaveLength(1);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe("getMuniIssueByIdForClient", () => {
|
|
58
|
-
it("should return the issue only for its own client", async () => {
|
|
59
|
-
const id = await createIssue();
|
|
60
|
-
|
|
61
|
-
expect((await getMuniIssueByIdForClient(id, CLIENT))?._id.toString()).toBe(id);
|
|
62
|
-
expect(await getMuniIssueByIdForClient(id, "client-b")).toBeNull();
|
|
63
|
-
expect(await getMuniIssueByIdForClient("not-a-valid-id", CLIENT)).toBeNull();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
});
|