@tellescope/sdk 1.253.0 → 1.254.0

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.
Files changed (98) hide show
  1. package/lib/cjs/sdk.d.ts +4 -0
  2. package/lib/cjs/sdk.d.ts.map +1 -1
  3. package/lib/cjs/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
  4. package/lib/cjs/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
  5. package/lib/cjs/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
  6. package/lib/cjs/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  8. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  9. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js +256 -0
  10. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  11. package/lib/cjs/tests/api_tests/field_redaction.test.d.ts.map +1 -1
  12. package/lib/cjs/tests/api_tests/field_redaction.test.js +112 -99
  13. package/lib/cjs/tests/api_tests/field_redaction.test.js.map +1 -1
  14. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  15. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  16. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js +168 -0
  17. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  18. package/lib/cjs/tests/api_tests/journey_error_branching.test.js +7 -2
  19. package/lib/cjs/tests/api_tests/journey_error_branching.test.js.map +1 -1
  20. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  21. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  22. package/lib/cjs/tests/api_tests/resource_access_tags.test.js +488 -0
  23. package/lib/cjs/tests/api_tests/resource_access_tags.test.js.map +1 -0
  24. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  25. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  26. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +325 -0
  27. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  28. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts +8 -0
  29. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  30. package/lib/cjs/tests/api_tests/time_tracks.test.js +638 -1
  31. package/lib/cjs/tests/api_tests/time_tracks.test.js.map +1 -1
  32. package/lib/cjs/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  33. package/lib/cjs/tests/api_tests/user_portal_settings.test.js +104 -28
  34. package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
  35. package/lib/cjs/tests/tests.d.ts.map +1 -1
  36. package/lib/cjs/tests/tests.js +878 -200
  37. package/lib/cjs/tests/tests.js.map +1 -1
  38. package/lib/esm/sdk.d.ts +4 -0
  39. package/lib/esm/sdk.d.ts.map +1 -1
  40. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts +2 -0
  41. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
  42. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js +120 -0
  43. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js.map +1 -0
  44. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts +2 -0
  45. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
  46. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js +200 -0
  47. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js.map +1 -0
  48. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts +2 -0
  49. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
  50. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js +194 -0
  51. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js.map +1 -0
  52. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts +2 -0
  53. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
  54. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js +115 -0
  55. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js.map +1 -0
  56. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  57. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  58. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js +252 -0
  59. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  60. package/lib/esm/tests/api_tests/field_redaction.test.d.ts.map +1 -1
  61. package/lib/esm/tests/api_tests/field_redaction.test.js +112 -99
  62. package/lib/esm/tests/api_tests/field_redaction.test.js.map +1 -1
  63. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  64. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  65. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js +164 -0
  66. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  67. package/lib/esm/tests/api_tests/journey_error_branching.test.js +7 -2
  68. package/lib/esm/tests/api_tests/journey_error_branching.test.js.map +1 -1
  69. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  70. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  71. package/lib/esm/tests/api_tests/resource_access_tags.test.js +484 -0
  72. package/lib/esm/tests/api_tests/resource_access_tags.test.js.map +1 -0
  73. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  74. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  75. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +321 -0
  76. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  77. package/lib/esm/tests/api_tests/time_tracks.test.d.ts +8 -0
  78. package/lib/esm/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  79. package/lib/esm/tests/api_tests/time_tracks.test.js +635 -0
  80. package/lib/esm/tests/api_tests/time_tracks.test.js.map +1 -1
  81. package/lib/esm/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  82. package/lib/esm/tests/api_tests/user_portal_settings.test.js +104 -28
  83. package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
  84. package/lib/esm/tests/tests.d.ts.map +1 -1
  85. package/lib/esm/tests/tests.js +879 -201
  86. package/lib/esm/tests/tests.js.map +1 -1
  87. package/lib/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +10 -10
  89. package/src/tests/api_tests/beluga_manual_sync.test.ts +159 -0
  90. package/src/tests/api_tests/field_redaction.test.ts +13 -0
  91. package/src/tests/api_tests/gcal_sync_retry.test.ts +104 -0
  92. package/src/tests/api_tests/journey_error_branching.test.ts +5 -1
  93. package/src/tests/api_tests/resource_access_tags.test.ts +303 -0
  94. package/src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts +214 -0
  95. package/src/tests/api_tests/time_tracks.test.ts +420 -0
  96. package/src/tests/api_tests/user_portal_settings.test.ts +71 -1
  97. package/src/tests/tests.ts +520 -11
  98. package/test_generated.pdf +0 -0
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,6 +46,17 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
46
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
47
  }
37
48
  };
49
+ var __rest = (this && this.__rest) || function (s, e) {
50
+ var t = {};
51
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
52
+ t[p] = s[p];
53
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
54
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
55
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
56
+ t[p[i]] = s[p[i]];
57
+ }
58
+ return t;
59
+ };
38
60
  var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
61
  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
62
  if (ar || !(i in from)) {
@@ -45,7 +67,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
45
67
  return to.concat(ar || Array.prototype.slice.call(from));
46
68
  };
47
69
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.time_tracks_edge_case_tests = exports.time_tracks_lock_tests = exports.time_tracks_review_tests = exports.time_tracks_correction_tests = exports.time_tracks_historical_tests = exports.time_tracks_tests = void 0;
70
+ exports.time_tracks_appointment_duration_tests = exports.time_tracks_resubmit_tests = exports.time_tracks_edge_case_tests = exports.time_tracks_lock_tests = exports.time_tracks_review_tests = exports.time_tracks_correction_tests = exports.time_tracks_historical_tests = exports.time_tracks_tests = void 0;
49
71
  require('source-map-support').install();
50
72
  var sdk_1 = require("../../sdk");
51
73
  var testing_1 = require("@tellescope/testing");
@@ -952,6 +974,615 @@ var time_tracks_edge_case_tests = function (_a) {
952
974
  });
953
975
  };
954
976
  exports.time_tracks_edge_case_tests = time_tracks_edge_case_tests;
977
+ // ============================================================
978
+ // Group F: Rejection Notification + Correct & Resubmit
979
+ // ============================================================
980
+ var time_tracks_resubmit_tests = function (_a) {
981
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
982
+ return __awaiter(void 0, void 0, void 0, function () {
983
+ var trackIds, nonAdminTrackIds, notificationIds, resubmit_payload, now_2, oneHourAgo_1, twoHoursAgo_2, create_historical, track_2, rejectionNote, notifications, rejectionNotification, resubmitted, refetched, track3_1, _b, _omitted, payloadWithoutClear_1, track5_1, nonAdminTrack_1, rejectedAgain, afterSecondResubmit, pendingMatches, rejectedMatches, _i, trackIds_6, id, e_9, _c, nonAdminTrackIds_1, id, e_10, _d, notificationIds_1, id, e_11, remaining, _e, remaining_1, n, e_12, e_13;
984
+ var _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
985
+ return __generator(this, function (_r) {
986
+ switch (_r.label) {
987
+ case 0:
988
+ (0, testing_1.log_header)("Time Tracks - Rejection Notification + Resubmit Tests");
989
+ trackIds = [];
990
+ nonAdminTrackIds = [];
991
+ notificationIds = [];
992
+ resubmit_payload = function (track, byUserId, newDurationMS) { return ({
993
+ correctedAt: new Date(),
994
+ correctedByUserId: byUserId,
995
+ correctionNote: "Corrected after rejection",
996
+ originalTotalDurationInMS: track.totalDurationInMS || 0,
997
+ totalDurationInMS: newDurationMS,
998
+ lockedAt: new Date(),
999
+ lockedByUserId: byUserId,
1000
+ reviewedAt: '',
1001
+ reviewedByUserId: '',
1002
+ reviewNote: '',
1003
+ }); };
1004
+ _r.label = 1;
1005
+ case 1:
1006
+ _r.trys.push([1, , 23, 51]);
1007
+ now_2 = new Date();
1008
+ oneHourAgo_1 = new Date(now_2.getTime() - 3600000);
1009
+ twoHoursAgo_2 = new Date(now_2.getTime() - 7200000);
1010
+ create_historical = function (title) { return sdk.api.time_tracks.createOne({
1011
+ title: title,
1012
+ isHistorical: true,
1013
+ closedAt: now_2,
1014
+ lockedAt: now_2,
1015
+ lockedByUserId: sdk.userInfo.id,
1016
+ totalDurationInMS: 3600000,
1017
+ timestamps: [
1018
+ { type: 'start', timestamp: twoHoursAgo_2 },
1019
+ { type: 'pause', timestamp: oneHourAgo_1 },
1020
+ ],
1021
+ }); };
1022
+ // F1: Rejection creates a notification for the owner
1023
+ log("F1: Rejection creates timeTrackRejected notification for owner...");
1024
+ return [4 /*yield*/, create_historical("Track for Rejection Notification")];
1025
+ case 2:
1026
+ track_2 = _r.sent();
1027
+ trackIds.push(track_2.id);
1028
+ rejectionNote = "Duration looks wrong, please correct";
1029
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track_2.id, {
1030
+ reviewedAt: new Date(),
1031
+ reviewedByUserId: sdkNonAdmin.userInfo.id,
1032
+ reviewApproved: false,
1033
+ reviewNote: rejectionNote,
1034
+ })];
1035
+ case 3:
1036
+ _r.sent();
1037
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 2000)]; // allow side-effect handler to run
1038
+ case 4:
1039
+ _r.sent(); // allow side-effect handler to run
1040
+ return [4 /*yield*/, sdk.api.user_notifications.getSome({
1041
+ filter: { userId: sdk.userInfo.id, type: 'timeTrackRejected' }
1042
+ })];
1043
+ case 5:
1044
+ notifications = _r.sent();
1045
+ rejectionNotification = notifications.find(function (n) { var _a; return (_a = n.relatedRecords) === null || _a === void 0 ? void 0 : _a.find(function (r) { return r.type === 'time_track' && r.id === track_2.id; }); });
1046
+ (0, testing_1.assert)(!!rejectionNotification, "F1: timeTrackRejected notification should exist for owner");
1047
+ (0, testing_1.assert)(rejectionNotification.message.includes(rejectionNote), "F1: notification message should include rejection note");
1048
+ notificationIds.push(rejectionNotification.id);
1049
+ log("F1: Rejection notification created for owner");
1050
+ // F2: Resubmit happy path
1051
+ log("F2: Owner resubmits rejected entry...");
1052
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track_2.id, resubmit_payload(track_2, sdk.userInfo.id, 1800000))];
1053
+ case 6:
1054
+ resubmitted = _r.sent();
1055
+ (0, testing_1.assert)(!resubmitted.reviewedAt, "F2: reviewedAt should be cleared after resubmit");
1056
+ return [4 /*yield*/, sdk.api.time_tracks.getOne(track_2.id)];
1057
+ case 7:
1058
+ refetched = _r.sent();
1059
+ (0, testing_1.assert)(!refetched.reviewedAt, "F2: reviewedAt should be falsy on refetch");
1060
+ (0, testing_1.assert)(((_f = refetched.reviewHistory) === null || _f === void 0 ? void 0 : _f.length) === 1, "F2: reviewHistory should have 1 entry, got ".concat((_g = refetched.reviewHistory) === null || _g === void 0 ? void 0 : _g.length));
1061
+ (0, testing_1.assert)(((_h = refetched.reviewHistory) === null || _h === void 0 ? void 0 : _h[0].reviewApproved) === false, "F2: reviewHistory should preserve reviewApproved false");
1062
+ (0, testing_1.assert)(((_j = refetched.reviewHistory) === null || _j === void 0 ? void 0 : _j[0].reviewNote) === rejectionNote, "F2: reviewHistory should preserve original reviewNote");
1063
+ (0, testing_1.assert)(((_k = refetched.reviewHistory) === null || _k === void 0 ? void 0 : _k[0].reviewedByUserId) === sdkNonAdmin.userInfo.id, "F2: reviewHistory should preserve reviewedByUserId");
1064
+ (0, testing_1.assert)(!!((_l = refetched.reviewHistory) === null || _l === void 0 ? void 0 : _l[0].resubmittedAt), "F2: reviewHistory should record resubmittedAt");
1065
+ (0, testing_1.assert)(((_m = refetched.reviewHistory) === null || _m === void 0 ? void 0 : _m[0].resubmittedByUserId) === sdk.userInfo.id, "F2: reviewHistory should record resubmittedByUserId");
1066
+ log("F2: Resubmit succeeded with reviewHistory audit trail");
1067
+ // F3: Resubmit without clearing reviewedAt - expect 400
1068
+ log("F3: Resubmit without reviewedAt: '' (should fail)...");
1069
+ return [4 /*yield*/, create_historical("Track for F3")];
1070
+ case 8:
1071
+ track3_1 = _r.sent();
1072
+ trackIds.push(track3_1.id);
1073
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track3_1.id, {
1074
+ reviewedAt: new Date(),
1075
+ reviewedByUserId: sdkNonAdmin.userInfo.id,
1076
+ reviewApproved: false,
1077
+ })];
1078
+ case 9:
1079
+ _r.sent();
1080
+ _b = resubmit_payload(track3_1, sdk.userInfo.id, 1800000), _omitted = _b.reviewedAt, payloadWithoutClear_1 = __rest(_b, ["reviewedAt"]);
1081
+ return [4 /*yield*/, assert_throws(function () { return sdk.api.time_tracks.updateOne(track3_1.id, payloadWithoutClear_1); }, "F3: resubmit without clearing reviewedAt")];
1082
+ case 10:
1083
+ _r.sent();
1084
+ log("F3: Correctly rejected resubmit without reviewedAt: ''");
1085
+ // F4: Resubmit with self-approval - expect 400
1086
+ log("F4: Resubmit with reviewApproved: true (should fail)...");
1087
+ return [4 /*yield*/, assert_throws(function () { return sdk.api.time_tracks.updateOne(track3_1.id, __assign(__assign({}, resubmit_payload(track3_1, sdk.userInfo.id, 1800000)), { reviewApproved: true })); }, "F4: resubmit with self-approval")];
1088
+ case 11:
1089
+ _r.sent();
1090
+ log("F4: Correctly rejected self-approval during resubmit");
1091
+ // F5: Correction payload on locked, non-rejected entry - expect 400
1092
+ log("F5: Correction payload on locked non-rejected entry (should fail)...");
1093
+ return [4 /*yield*/, create_historical("Track for F5")];
1094
+ case 12:
1095
+ track5_1 = _r.sent();
1096
+ trackIds.push(track5_1.id);
1097
+ return [4 /*yield*/, assert_throws(function () { return sdk.api.time_tracks.updateOne(track5_1.id, resubmit_payload(track5_1, sdk.userInfo.id, 1800000)); }, "F5: correction on locked non-rejected entry")];
1098
+ case 13:
1099
+ _r.sent();
1100
+ log("F5: Correctly rejected correction on locked non-rejected entry");
1101
+ // F6: Non-owner resubmit attempt - expect 400
1102
+ log("F6: Non-owner resubmit attempt (should fail)...");
1103
+ return [4 /*yield*/, sdkNonAdmin.api.time_tracks.createOne({
1104
+ title: "Non-Admin Track for F6",
1105
+ isHistorical: true,
1106
+ closedAt: now_2,
1107
+ lockedAt: now_2,
1108
+ lockedByUserId: sdkNonAdmin.userInfo.id,
1109
+ totalDurationInMS: 3600000,
1110
+ timestamps: [
1111
+ { type: 'start', timestamp: twoHoursAgo_2 },
1112
+ { type: 'pause', timestamp: oneHourAgo_1 },
1113
+ ],
1114
+ })];
1115
+ case 14:
1116
+ nonAdminTrack_1 = _r.sent();
1117
+ nonAdminTrackIds.push(nonAdminTrack_1.id);
1118
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(nonAdminTrack_1.id, {
1119
+ reviewedAt: new Date(),
1120
+ reviewedByUserId: sdk.userInfo.id,
1121
+ reviewApproved: false,
1122
+ reviewNote: "Rejected for F6",
1123
+ })];
1124
+ case 15:
1125
+ _r.sent();
1126
+ return [4 /*yield*/, assert_throws(function () { return sdk.api.time_tracks.updateOne(nonAdminTrack_1.id, resubmit_payload(nonAdminTrack_1, sdk.userInfo.id, 1800000)); }, "F6: non-owner resubmit")];
1127
+ case 16:
1128
+ _r.sent();
1129
+ log("F6: Correctly rejected non-owner resubmit");
1130
+ // F7: Second rejection + resubmit appends to reviewHistory
1131
+ log("F7: Reject again after resubmit, resubmit again...");
1132
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track_2.id, {
1133
+ reviewedAt: new Date(),
1134
+ reviewedByUserId: sdkNonAdmin.userInfo.id,
1135
+ reviewApproved: false,
1136
+ reviewNote: "Still not right",
1137
+ })];
1138
+ case 17:
1139
+ _r.sent();
1140
+ return [4 /*yield*/, sdk.api.time_tracks.getOne(track_2.id)];
1141
+ case 18:
1142
+ rejectedAgain = _r.sent();
1143
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track_2.id, resubmit_payload(rejectedAgain, sdk.userInfo.id, 2700000))];
1144
+ case 19:
1145
+ _r.sent();
1146
+ return [4 /*yield*/, sdk.api.time_tracks.getOne(track_2.id)];
1147
+ case 20:
1148
+ afterSecondResubmit = _r.sent();
1149
+ (0, testing_1.assert)(((_o = afterSecondResubmit.reviewHistory) === null || _o === void 0 ? void 0 : _o.length) === 2, "F7: reviewHistory should have 2 entries, got ".concat((_p = afterSecondResubmit.reviewHistory) === null || _p === void 0 ? void 0 : _p.length));
1150
+ (0, testing_1.assert)(((_q = afterSecondResubmit.reviewHistory) === null || _q === void 0 ? void 0 : _q[1].reviewNote) === "Still not right", "F7: second reviewHistory entry should preserve second rejection note");
1151
+ log("F7: Second rejection/resubmit cycle appended to reviewHistory");
1152
+ // F8: Status filters treat reviewedAt: '' as Pending
1153
+ log("F8: Status mdbFilters handle reviewedAt: ''...");
1154
+ return [4 /*yield*/, sdk.api.time_tracks.getSome({
1155
+ mdbFilter: { $or: [{ reviewedAt: { $exists: false } }, { reviewedAt: '' }] }
1156
+ })];
1157
+ case 21:
1158
+ pendingMatches = _r.sent();
1159
+ (0, testing_1.assert)(!!pendingMatches.find(function (t) { return t.id === track_2.id; }), "F8: Pending filter should match resubmitted track");
1160
+ return [4 /*yield*/, sdk.api.time_tracks.getSome({
1161
+ mdbFilter: { reviewedAt: { $exists: true, $ne: '' }, reviewApproved: false }
1162
+ })];
1163
+ case 22:
1164
+ rejectedMatches = _r.sent();
1165
+ (0, testing_1.assert)(!rejectedMatches.find(function (t) { return t.id === track_2.id; }), "F8: Rejected filter should exclude resubmitted track");
1166
+ log("F8: Status filters behave correctly with cleared reviewedAt");
1167
+ log("All rejection notification + resubmit tests passed!");
1168
+ return [3 /*break*/, 51];
1169
+ case 23:
1170
+ _i = 0, trackIds_6 = trackIds;
1171
+ _r.label = 24;
1172
+ case 24:
1173
+ if (!(_i < trackIds_6.length)) return [3 /*break*/, 29];
1174
+ id = trackIds_6[_i];
1175
+ _r.label = 25;
1176
+ case 25:
1177
+ _r.trys.push([25, 27, , 28]);
1178
+ return [4 /*yield*/, sdk.api.time_tracks.deleteOne(id)];
1179
+ case 26:
1180
+ _r.sent();
1181
+ return [3 /*break*/, 28];
1182
+ case 27:
1183
+ e_9 = _r.sent();
1184
+ return [3 /*break*/, 28];
1185
+ case 28:
1186
+ _i++;
1187
+ return [3 /*break*/, 24];
1188
+ case 29:
1189
+ _c = 0, nonAdminTrackIds_1 = nonAdminTrackIds;
1190
+ _r.label = 30;
1191
+ case 30:
1192
+ if (!(_c < nonAdminTrackIds_1.length)) return [3 /*break*/, 35];
1193
+ id = nonAdminTrackIds_1[_c];
1194
+ _r.label = 31;
1195
+ case 31:
1196
+ _r.trys.push([31, 33, , 34]);
1197
+ return [4 /*yield*/, sdkNonAdmin.api.time_tracks.deleteOne(id)];
1198
+ case 32:
1199
+ _r.sent();
1200
+ return [3 /*break*/, 34];
1201
+ case 33:
1202
+ e_10 = _r.sent();
1203
+ return [3 /*break*/, 34];
1204
+ case 34:
1205
+ _c++;
1206
+ return [3 /*break*/, 30];
1207
+ case 35:
1208
+ _d = 0, notificationIds_1 = notificationIds;
1209
+ _r.label = 36;
1210
+ case 36:
1211
+ if (!(_d < notificationIds_1.length)) return [3 /*break*/, 41];
1212
+ id = notificationIds_1[_d];
1213
+ _r.label = 37;
1214
+ case 37:
1215
+ _r.trys.push([37, 39, , 40]);
1216
+ return [4 /*yield*/, sdk.api.user_notifications.deleteOne(id)];
1217
+ case 38:
1218
+ _r.sent();
1219
+ return [3 /*break*/, 40];
1220
+ case 39:
1221
+ e_11 = _r.sent();
1222
+ return [3 /*break*/, 40];
1223
+ case 40:
1224
+ _d++;
1225
+ return [3 /*break*/, 36];
1226
+ case 41:
1227
+ _r.trys.push([41, 49, , 50]);
1228
+ return [4 /*yield*/, sdk.api.user_notifications.getSome({
1229
+ filter: { userId: sdk.userInfo.id, type: 'timeTrackRejected' }
1230
+ })];
1231
+ case 42:
1232
+ remaining = _r.sent();
1233
+ _e = 0, remaining_1 = remaining;
1234
+ _r.label = 43;
1235
+ case 43:
1236
+ if (!(_e < remaining_1.length)) return [3 /*break*/, 48];
1237
+ n = remaining_1[_e];
1238
+ _r.label = 44;
1239
+ case 44:
1240
+ _r.trys.push([44, 46, , 47]);
1241
+ return [4 /*yield*/, sdk.api.user_notifications.deleteOne(n.id)];
1242
+ case 45:
1243
+ _r.sent();
1244
+ return [3 /*break*/, 47];
1245
+ case 46:
1246
+ e_12 = _r.sent();
1247
+ return [3 /*break*/, 47];
1248
+ case 47:
1249
+ _e++;
1250
+ return [3 /*break*/, 43];
1251
+ case 48: return [3 /*break*/, 50];
1252
+ case 49:
1253
+ e_13 = _r.sent();
1254
+ return [3 /*break*/, 50];
1255
+ case 50: return [7 /*endfinally*/];
1256
+ case 51: return [2 /*return*/];
1257
+ }
1258
+ });
1259
+ });
1260
+ };
1261
+ exports.time_tracks_resubmit_tests = time_tracks_resubmit_tests;
1262
+ // ============================================================
1263
+ // Group F: Appointment Duration from Tracked Time
1264
+ // ============================================================
1265
+ var time_tracks_appointment_duration_tests = function (_a) {
1266
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
1267
+ return __awaiter(void 0, void 0, void 0, function () {
1268
+ var businessId, trackIds, formResponseIds, eventIds, formId, enduserId, enduser, form, event_1, response1, track1, eventAfterClose, response2, track2, eventAfterSecond, response3, track3, eventBeforeLink, eventAfterLink, eventAfterCorrection, event2, response4, track4, event2AfterClose, _i, trackIds_7, id, e_14, _b, formResponseIds_1, id, e_15, _c, eventIds_1, id, e_16, e_17, e_18, e_19;
1269
+ return __generator(this, function (_d) {
1270
+ switch (_d.label) {
1271
+ case 0:
1272
+ (0, testing_1.log_header)("Time Tracks - Appointment Duration from Tracked Time Tests");
1273
+ businessId = sdk.userInfo.businessId;
1274
+ trackIds = [];
1275
+ formResponseIds = [];
1276
+ eventIds = [];
1277
+ _d.label = 1;
1278
+ case 1:
1279
+ _d.trys.push([1, , 35, 65]);
1280
+ // Enable time tracking + appointment duration setting
1281
+ log("F0: Enabling timeTracking.setAppointmentDurationOnTimeTrackClose...");
1282
+ return [4 /*yield*/, sdk.api.organizations.updateOne(businessId, {
1283
+ settings: { timeTracking: { enabled: true, setAppointmentDurationOnTimeTrackClose: true } }
1284
+ })
1285
+ // Shared records
1286
+ ];
1287
+ case 2:
1288
+ _d.sent();
1289
+ return [4 /*yield*/, sdk.api.endusers.createOne({ email: "tt-duration-".concat(Date.now(), "@test.com") })];
1290
+ case 3:
1291
+ enduser = _d.sent();
1292
+ enduserId = enduser.id;
1293
+ return [4 /*yield*/, sdk.api.forms.createOne({ title: 'Appointment Duration Form' })];
1294
+ case 4:
1295
+ form = _d.sent();
1296
+ formId = form.id;
1297
+ return [4 /*yield*/, sdk.api.calendar_events.createOne({
1298
+ title: 'Appointment for Tracked Time',
1299
+ durationInMinutes: 30,
1300
+ startTimeInMS: Date.now(),
1301
+ attendees: [{ type: 'enduser', id: enduser.id }],
1302
+ })];
1303
+ case 5:
1304
+ event_1 = _d.sent();
1305
+ eventIds.push(event_1.id);
1306
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1307
+ formId: form.id,
1308
+ enduserId: enduser.id,
1309
+ formTitle: form.title,
1310
+ calendarEventId: event_1.id,
1311
+ })];
1312
+ case 6:
1313
+ response1 = _d.sent();
1314
+ formResponseIds.push(response1.id);
1315
+ // Test F1: Close a linked time track -> actualDuration set from tracked time
1316
+ log("F1: Closing linked time track sets appointment actualDuration...");
1317
+ return [4 /*yield*/, sdk.api.time_tracks.createOne({
1318
+ title: "Tracked Form Completion",
1319
+ activity: { type: 'form_response', id: response1.id },
1320
+ })];
1321
+ case 7:
1322
+ track1 = _d.sent();
1323
+ trackIds.push(track1.id);
1324
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 2000)];
1325
+ case 8:
1326
+ _d.sent();
1327
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track1.id, {
1328
+ closedAt: new Date(),
1329
+ totalDurationInMS: 1800000, // 30 minutes
1330
+ })];
1331
+ case 9:
1332
+ _d.sent();
1333
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)]; // allow side effects to run
1334
+ case 10:
1335
+ _d.sent(); // allow side effects to run
1336
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event_1.id)];
1337
+ case 11:
1338
+ eventAfterClose = _d.sent();
1339
+ (0, testing_1.assert)(eventAfterClose.actualDuration === 30, "F1: actualDuration should be 30, got ".concat(eventAfterClose.actualDuration));
1340
+ log("F1: actualDuration set from closed time track");
1341
+ // Test F2: Second closed track on same appointment -> durations are summed
1342
+ log("F2: Second closed track sums durations...");
1343
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1344
+ formId: form.id,
1345
+ enduserId: enduser.id,
1346
+ formTitle: form.title,
1347
+ calendarEventId: event_1.id,
1348
+ })];
1349
+ case 12:
1350
+ response2 = _d.sent();
1351
+ formResponseIds.push(response2.id);
1352
+ return [4 /*yield*/, sdk.api.time_tracks.createOne({
1353
+ title: "Second Tracked Form Completion",
1354
+ activity: { type: 'form_response', id: response2.id },
1355
+ })];
1356
+ case 13:
1357
+ track2 = _d.sent();
1358
+ trackIds.push(track2.id);
1359
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track2.id, {
1360
+ closedAt: new Date(),
1361
+ totalDurationInMS: 600000, // 10 minutes
1362
+ })];
1363
+ case 14:
1364
+ _d.sent();
1365
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)];
1366
+ case 15:
1367
+ _d.sent();
1368
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event_1.id)];
1369
+ case 16:
1370
+ eventAfterSecond = _d.sent();
1371
+ (0, testing_1.assert)(eventAfterSecond.actualDuration === 40, "F2: actualDuration should be 40 (30 + 10), got ".concat(eventAfterSecond.actualDuration));
1372
+ log("F2: actualDuration correctly summed across tracks");
1373
+ // Test F3: Linking activity after close triggers recompute
1374
+ log("F3: Post-close activity link triggers recompute...");
1375
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1376
+ formId: form.id,
1377
+ enduserId: enduser.id,
1378
+ formTitle: form.title,
1379
+ calendarEventId: event_1.id,
1380
+ })];
1381
+ case 17:
1382
+ response3 = _d.sent();
1383
+ formResponseIds.push(response3.id);
1384
+ return [4 /*yield*/, sdk.api.time_tracks.createOne({
1385
+ title: "Track Linked After Close",
1386
+ })];
1387
+ case 18:
1388
+ track3 = _d.sent();
1389
+ trackIds.push(track3.id);
1390
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track3.id, {
1391
+ closedAt: new Date(),
1392
+ totalDurationInMS: 300000, // 5 minutes
1393
+ })];
1394
+ case 19:
1395
+ _d.sent();
1396
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)
1397
+ // no activity yet -> actualDuration unchanged
1398
+ ];
1399
+ case 20:
1400
+ _d.sent();
1401
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event_1.id)];
1402
+ case 21:
1403
+ eventBeforeLink = _d.sent();
1404
+ (0, testing_1.assert)(eventBeforeLink.actualDuration === 40, "F3: actualDuration should still be 40 before activity link, got ".concat(eventBeforeLink.actualDuration));
1405
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track3.id, {
1406
+ activity: { type: 'form_response', id: response3.id },
1407
+ })];
1408
+ case 22:
1409
+ _d.sent();
1410
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)];
1411
+ case 23:
1412
+ _d.sent();
1413
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event_1.id)];
1414
+ case 24:
1415
+ eventAfterLink = _d.sent();
1416
+ (0, testing_1.assert)(eventAfterLink.actualDuration === 45, "F3: actualDuration should be 45 (30 + 10 + 5) after post-close link, got ".concat(eventAfterLink.actualDuration));
1417
+ log("F3: Post-close activity link recomputed actualDuration");
1418
+ // Test F4: Correction recomputes actualDuration
1419
+ log("F4: Correction recomputes actualDuration...");
1420
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track2.id, {
1421
+ correctedAt: new Date(),
1422
+ correctedByUserId: sdk.userInfo.id,
1423
+ correctionNote: "Adjusting tracked time",
1424
+ originalTotalDurationInMS: 600000,
1425
+ totalDurationInMS: 1200000,
1426
+ lockedAt: new Date(),
1427
+ lockedByUserId: sdk.userInfo.id,
1428
+ })];
1429
+ case 25:
1430
+ _d.sent();
1431
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)];
1432
+ case 26:
1433
+ _d.sent();
1434
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event_1.id)];
1435
+ case 27:
1436
+ eventAfterCorrection = _d.sent();
1437
+ (0, testing_1.assert)(eventAfterCorrection.actualDuration === 55, "F4: actualDuration should be 55 (30 + 20 + 5) after correction, got ".concat(eventAfterCorrection.actualDuration));
1438
+ log("F4: Correction recomputed actualDuration");
1439
+ // Test F5: Setting disabled -> actualDuration not set
1440
+ log("F5: Setting disabled leaves actualDuration unset...");
1441
+ return [4 /*yield*/, sdk.api.organizations.updateOne(businessId, {
1442
+ settings: { timeTracking: { enabled: true, setAppointmentDurationOnTimeTrackClose: false } }
1443
+ })];
1444
+ case 28:
1445
+ _d.sent();
1446
+ return [4 /*yield*/, sdk.api.calendar_events.createOne({
1447
+ title: 'Appointment Without Duration Sync',
1448
+ durationInMinutes: 30,
1449
+ startTimeInMS: Date.now(),
1450
+ attendees: [{ type: 'enduser', id: enduser.id }],
1451
+ })];
1452
+ case 29:
1453
+ event2 = _d.sent();
1454
+ eventIds.push(event2.id);
1455
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1456
+ formId: form.id,
1457
+ enduserId: enduser.id,
1458
+ formTitle: form.title,
1459
+ calendarEventId: event2.id,
1460
+ })];
1461
+ case 30:
1462
+ response4 = _d.sent();
1463
+ formResponseIds.push(response4.id);
1464
+ return [4 /*yield*/, sdk.api.time_tracks.createOne({
1465
+ title: "Track With Setting Disabled",
1466
+ activity: { type: 'form_response', id: response4.id },
1467
+ })];
1468
+ case 31:
1469
+ track4 = _d.sent();
1470
+ trackIds.push(track4.id);
1471
+ return [4 /*yield*/, sdk.api.time_tracks.updateOne(track4.id, {
1472
+ closedAt: new Date(),
1473
+ totalDurationInMS: 1800000,
1474
+ })];
1475
+ case 32:
1476
+ _d.sent();
1477
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1500)];
1478
+ case 33:
1479
+ _d.sent();
1480
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event2.id)];
1481
+ case 34:
1482
+ event2AfterClose = _d.sent();
1483
+ (0, testing_1.assert)(!event2AfterClose.actualDuration, "F5: actualDuration should stay unset when setting is disabled, got ".concat(event2AfterClose.actualDuration));
1484
+ log("F5: actualDuration correctly unset with setting disabled");
1485
+ log("All appointment duration tests passed!");
1486
+ return [3 /*break*/, 65];
1487
+ case 35:
1488
+ _i = 0, trackIds_7 = trackIds;
1489
+ _d.label = 36;
1490
+ case 36:
1491
+ if (!(_i < trackIds_7.length)) return [3 /*break*/, 41];
1492
+ id = trackIds_7[_i];
1493
+ _d.label = 37;
1494
+ case 37:
1495
+ _d.trys.push([37, 39, , 40]);
1496
+ return [4 /*yield*/, sdk.api.time_tracks.deleteOne(id)];
1497
+ case 38:
1498
+ _d.sent();
1499
+ return [3 /*break*/, 40];
1500
+ case 39:
1501
+ e_14 = _d.sent();
1502
+ return [3 /*break*/, 40];
1503
+ case 40:
1504
+ _i++;
1505
+ return [3 /*break*/, 36];
1506
+ case 41:
1507
+ _b = 0, formResponseIds_1 = formResponseIds;
1508
+ _d.label = 42;
1509
+ case 42:
1510
+ if (!(_b < formResponseIds_1.length)) return [3 /*break*/, 47];
1511
+ id = formResponseIds_1[_b];
1512
+ _d.label = 43;
1513
+ case 43:
1514
+ _d.trys.push([43, 45, , 46]);
1515
+ return [4 /*yield*/, sdk.api.form_responses.deleteOne(id)];
1516
+ case 44:
1517
+ _d.sent();
1518
+ return [3 /*break*/, 46];
1519
+ case 45:
1520
+ e_15 = _d.sent();
1521
+ return [3 /*break*/, 46];
1522
+ case 46:
1523
+ _b++;
1524
+ return [3 /*break*/, 42];
1525
+ case 47:
1526
+ _c = 0, eventIds_1 = eventIds;
1527
+ _d.label = 48;
1528
+ case 48:
1529
+ if (!(_c < eventIds_1.length)) return [3 /*break*/, 53];
1530
+ id = eventIds_1[_c];
1531
+ _d.label = 49;
1532
+ case 49:
1533
+ _d.trys.push([49, 51, , 52]);
1534
+ return [4 /*yield*/, sdk.api.calendar_events.deleteOne(id)];
1535
+ case 50:
1536
+ _d.sent();
1537
+ return [3 /*break*/, 52];
1538
+ case 51:
1539
+ e_16 = _d.sent();
1540
+ return [3 /*break*/, 52];
1541
+ case 52:
1542
+ _c++;
1543
+ return [3 /*break*/, 48];
1544
+ case 53:
1545
+ if (!formId) return [3 /*break*/, 57];
1546
+ _d.label = 54;
1547
+ case 54:
1548
+ _d.trys.push([54, 56, , 57]);
1549
+ return [4 /*yield*/, sdk.api.forms.deleteOne(formId)];
1550
+ case 55:
1551
+ _d.sent();
1552
+ return [3 /*break*/, 57];
1553
+ case 56:
1554
+ e_17 = _d.sent();
1555
+ return [3 /*break*/, 57];
1556
+ case 57:
1557
+ if (!enduserId) return [3 /*break*/, 61];
1558
+ _d.label = 58;
1559
+ case 58:
1560
+ _d.trys.push([58, 60, , 61]);
1561
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enduserId)];
1562
+ case 59:
1563
+ _d.sent();
1564
+ return [3 /*break*/, 61];
1565
+ case 60:
1566
+ e_18 = _d.sent();
1567
+ return [3 /*break*/, 61];
1568
+ case 61:
1569
+ _d.trys.push([61, 63, , 64]);
1570
+ return [4 /*yield*/, sdk.api.organizations.updateOne(businessId, {
1571
+ settings: { timeTracking: { setAppointmentDurationOnTimeTrackClose: false } }
1572
+ })];
1573
+ case 62:
1574
+ _d.sent();
1575
+ return [3 /*break*/, 64];
1576
+ case 63:
1577
+ e_19 = _d.sent();
1578
+ return [3 /*break*/, 64];
1579
+ case 64: return [7 /*endfinally*/];
1580
+ case 65: return [2 /*return*/];
1581
+ }
1582
+ });
1583
+ });
1584
+ };
1585
+ exports.time_tracks_appointment_duration_tests = time_tracks_appointment_duration_tests;
955
1586
  // Allow running this test file independently
956
1587
  if (require.main === module) {
957
1588
  var sdk_2 = new sdk_1.Session({ host: host });
@@ -984,6 +1615,12 @@ if (require.main === module) {
984
1615
  _a.sent();
985
1616
  return [4 /*yield*/, (0, exports.time_tracks_edge_case_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
986
1617
  case 7:
1618
+ _a.sent();
1619
+ return [4 /*yield*/, (0, exports.time_tracks_resubmit_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
1620
+ case 8:
1621
+ _a.sent();
1622
+ return [4 /*yield*/, (0, exports.time_tracks_appointment_duration_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
1623
+ case 9:
987
1624
  _a.sent();
988
1625
  return [2 /*return*/];
989
1626
  }