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