node-autotask 0.28.0 → 0.29.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.
- package/CHANGELOG.md +13 -0
- package/MCP_TOOL_CATALOG.json +27 -8
- package/MCP_TOOL_MANIFEST.md +12 -11
- package/N8N_MCP_MANIFEST.json +34 -5
- package/N8N_MCP_MANIFEST.md +8 -7
- package/README.md +1 -2
- package/capabilities.json +1471 -1307
- package/dist/capabilities.cjs +2 -2
- package/dist/capabilities.js +1 -1
- package/dist/{chunk-GUY2KK7U.cjs → chunk-APXBBN3D.cjs} +143 -143
- package/dist/{chunk-WYKGD5UD.cjs → chunk-BNIOQEKP.cjs} +536 -491
- package/dist/{chunk-D5IVS6GY.cjs → chunk-IKWHRUQ5.cjs} +97 -6
- package/dist/{chunk-IRVZGW5K.js → chunk-KVT5V7SA.js} +93 -2
- package/dist/{chunk-ZEGMVEF3.cjs → chunk-PY45RBQ2.cjs} +1470 -1306
- package/dist/{chunk-SYX6EWMT.js → chunk-T4SZGOJB.js} +98 -53
- package/dist/{chunk-6EQSXYRW.js → chunk-WKP442HS.js} +1470 -1306
- package/dist/{chunk-O2D7KDDD.js → chunk-X4TUU2Y6.js} +2 -2
- package/dist/{index-DXuV04zM.d.ts → index-6_i-__sN.d.ts} +25 -2
- package/dist/{index-DQ9NgraW.d.cts → index-BGZ1Mhbh.d.cts} +105 -82
- package/dist/{index-DQ9NgraW.d.ts → index-BGZ1Mhbh.d.ts} +105 -82
- package/dist/{index-CORcZUNm.d.cts → index-BZkfUU59.d.cts} +25 -2
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/operations/index.cjs +112 -112
- package/dist/operations/index.d.cts +4 -4
- package/dist/operations/index.d.ts +4 -4
- package/dist/operations/index.js +2 -2
- package/dist/pool.cjs +9 -9
- package/dist/pool.d.cts +2 -2
- package/dist/pool.d.ts +2 -2
- package/dist/pool.js +4 -4
- package/dist/resources/index.cjs +4 -4
- package/dist/resources/index.d.cts +2 -2
- package/dist/resources/index.d.ts +2 -2
- package/dist/resources/index.js +3 -3
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/docs/API.md +1 -2
- package/package.json +1 -1
|
@@ -34,14 +34,16 @@ import {
|
|
|
34
34
|
parseVendorErrors,
|
|
35
35
|
resolveCompositeNames,
|
|
36
36
|
resolveFieldsPreset,
|
|
37
|
+
resolveLineOfBusinessChain,
|
|
37
38
|
truncateNoteChars,
|
|
38
39
|
unwrapItem,
|
|
39
40
|
unwrapItems,
|
|
40
|
-
unwrapOperation
|
|
41
|
-
|
|
41
|
+
unwrapOperation,
|
|
42
|
+
vendorId
|
|
43
|
+
} from "./chunk-KVT5V7SA.js";
|
|
42
44
|
import {
|
|
43
45
|
CAPABILITIES
|
|
44
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-WKP442HS.js";
|
|
45
47
|
|
|
46
48
|
// src/resources/appointments.ts
|
|
47
49
|
var AppointmentsResource = class extends BaseResource {
|
|
@@ -5299,7 +5301,7 @@ function appendWiresNote(wires, note) {
|
|
|
5299
5301
|
wires.note = (wires.note ? wires.note + " | " : "") + note;
|
|
5300
5302
|
}
|
|
5301
5303
|
function makeFetchCtx(rawHttp, v, contractId, budget) {
|
|
5302
|
-
const
|
|
5304
|
+
const OP10 = PROFITABILITY_OP;
|
|
5303
5305
|
const id = parseIdentifier(contractId, "contractId");
|
|
5304
5306
|
const idNum = typeof id === "number" ? id : Number(id);
|
|
5305
5307
|
const wires = { issued: 0, requests: 0, budget };
|
|
@@ -5311,19 +5313,19 @@ function makeFetchCtx(rawHttp, v, contractId, budget) {
|
|
|
5311
5313
|
} };
|
|
5312
5314
|
const readPart = (path, conditions, fields) => {
|
|
5313
5315
|
wires.issued += 1;
|
|
5314
|
-
return degradable(() => boundedPart(http, path, conditions, v.limit,
|
|
5316
|
+
return degradable(() => boundedPart(http, path, conditions, v.limit, OP10, fields));
|
|
5315
5317
|
};
|
|
5316
5318
|
const truncatedMonths = {};
|
|
5317
5319
|
const windowedPart = async (name, key, path, cond, fields, dateField) => {
|
|
5318
5320
|
const first = await readPart(path, cond, fields);
|
|
5319
5321
|
if (first.absent !== void 0 || !first.hasMore) return { part: stampPart(key, first, cond), rows: first.items };
|
|
5320
|
-
const wp = await degradable(() => expandByMonth(http, path, cond, v.limit,
|
|
5322
|
+
const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP10, fields, dateField, v.dateFrom, v.dateTo, wires));
|
|
5321
5323
|
if (!("truncatedMonths" in wp)) return { part: stampPart(key, wp, cond), rows: [] };
|
|
5322
5324
|
const { truncatedMonths: tm, ...part } = wp;
|
|
5323
5325
|
truncatedMonths[name] = tm;
|
|
5324
5326
|
return { part, rows: wp.items };
|
|
5325
5327
|
};
|
|
5326
|
-
return { v, OP:
|
|
5328
|
+
return { v, OP: OP10, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
|
|
5327
5329
|
}
|
|
5328
5330
|
|
|
5329
5331
|
// src/resources/special/contracts/profitability.stages.ts
|
|
@@ -12061,6 +12063,7 @@ async function addCompositeNames(http, ctx, entriesPart, result, opts) {
|
|
|
12061
12063
|
builder.addFk("contract", t["contractID"]);
|
|
12062
12064
|
builder.addFk("billingCode", t["billingCodeID"]);
|
|
12063
12065
|
builder.addFk("role", t["assignedResourceRoleID"]);
|
|
12066
|
+
builder.addLineOfBusiness(t["organizationalLevelAssociationID"]);
|
|
12064
12067
|
for (const e of entriesPart.items) {
|
|
12065
12068
|
builder.addResource(e["resourceID"]);
|
|
12066
12069
|
builder.addFk("role", e["roleID"]);
|
|
@@ -12084,6 +12087,12 @@ async function addCompositeNames(http, ctx, entriesPart, result, opts) {
|
|
|
12084
12087
|
return row;
|
|
12085
12088
|
});
|
|
12086
12089
|
result.names = names.section;
|
|
12090
|
+
result.lineOfBusiness = names.lineOfBusiness ?? {
|
|
12091
|
+
association: null,
|
|
12092
|
+
organizationalLevel2: null,
|
|
12093
|
+
organizationalLevel1: null,
|
|
12094
|
+
markers: { association: "missing", organizationalLevel2: "missing", organizationalLevel1: "missing" }
|
|
12095
|
+
};
|
|
12087
12096
|
result.truncated = result.truncated || names.section.truncated;
|
|
12088
12097
|
}
|
|
12089
12098
|
async function fullContext(resource, id, opts = {}, http) {
|
|
@@ -12257,6 +12266,38 @@ async function forResource(_resource, resourceIDIn, http, opts = {}) {
|
|
|
12257
12266
|
};
|
|
12258
12267
|
}
|
|
12259
12268
|
|
|
12269
|
+
// src/resources/special/tickets/lineOfBusiness.ts
|
|
12270
|
+
var OP5 = "tickets.lineOfBusiness";
|
|
12271
|
+
function positiveId2(value, name) {
|
|
12272
|
+
const n = typeof value === "string" && /^[0-9]+$/.test(value.trim()) ? Number(value) : value;
|
|
12273
|
+
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
|
|
12274
|
+
throw new AutotaskConfigError(OP5 + ": " + name + " must be a positive integer id (got " + String(value) + ")", { operation: OP5 });
|
|
12275
|
+
}
|
|
12276
|
+
return n;
|
|
12277
|
+
}
|
|
12278
|
+
async function lineOfBusiness(resource, ticketIdIn, http, associationIdIn) {
|
|
12279
|
+
const ticketId = positiveId2(ticketIdIn, "ticketId");
|
|
12280
|
+
let associationId;
|
|
12281
|
+
if (associationIdIn !== void 0) {
|
|
12282
|
+
associationId = positiveId2(associationIdIn, "associationId");
|
|
12283
|
+
} else {
|
|
12284
|
+
const ticket = await resource.get(ticketId);
|
|
12285
|
+
associationId = vendorId(ticket.organizationalLevelAssociationID);
|
|
12286
|
+
}
|
|
12287
|
+
if (associationId === void 0) {
|
|
12288
|
+
return {
|
|
12289
|
+
ticketId,
|
|
12290
|
+
association: null,
|
|
12291
|
+
organizationalLevel2: null,
|
|
12292
|
+
organizationalLevel1: null,
|
|
12293
|
+
markers: { association: "missing", organizationalLevel2: "missing", organizationalLevel1: "missing" }
|
|
12294
|
+
};
|
|
12295
|
+
}
|
|
12296
|
+
const chain = await resolveLineOfBusinessChain(http, associationId, { budget: 3, operation: OP5, onError: "propagate" });
|
|
12297
|
+
const { association, organizationalLevel2, organizationalLevel1, markers } = chain.lineOfBusiness;
|
|
12298
|
+
return { ticketId, association, organizationalLevel2, organizationalLevel1, markers };
|
|
12299
|
+
}
|
|
12300
|
+
|
|
12260
12301
|
// src/resources/special/tickets/statusSemantics.ts
|
|
12261
12302
|
async function statusSemantics(_resource, opts = {}, http) {
|
|
12262
12303
|
return resolveTicketStatusSemantics(http, opts);
|
|
@@ -12375,6 +12416,10 @@ var TicketsResource = class extends BaseResource {
|
|
|
12375
12416
|
forResource(resourceID, opts) {
|
|
12376
12417
|
return forResource(this, resourceID, this.http, opts);
|
|
12377
12418
|
}
|
|
12419
|
+
/** Node-parity special op (hand-written in src/resources/special/tickets.ts). */
|
|
12420
|
+
lineOfBusiness(ticketId, associationId) {
|
|
12421
|
+
return lineOfBusiness(this, ticketId, this.http, associationId);
|
|
12422
|
+
}
|
|
12378
12423
|
};
|
|
12379
12424
|
|
|
12380
12425
|
// src/resources/ticket_webhooks.ts
|
|
@@ -12503,12 +12548,12 @@ async function postedDateStatusQuery(_resource, mode, http, opts) {
|
|
|
12503
12548
|
return items;
|
|
12504
12549
|
}
|
|
12505
12550
|
async function postedWithin(_resource, from, to, http, opts, opLabel = "time_entries.postedWithin") {
|
|
12506
|
-
const
|
|
12507
|
-
if (opts?.tz !== void 0) validateZone(opts.tz,
|
|
12508
|
-
const fromB = customRangeDay(from, "from", void 0,
|
|
12509
|
-
const toB = customRangeDay(to, "to", void 0,
|
|
12551
|
+
const OP10 = opLabel;
|
|
12552
|
+
if (opts?.tz !== void 0) validateZone(opts.tz, OP10);
|
|
12553
|
+
const fromB = customRangeDay(from, "from", void 0, OP10);
|
|
12554
|
+
const toB = customRangeDay(to, "to", void 0, OP10);
|
|
12510
12555
|
if (fromB.ms > toB.ms) {
|
|
12511
|
-
throw new AutotaskConfigError(`${
|
|
12556
|
+
throw new AutotaskConfigError(`${OP10}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP10 });
|
|
12512
12557
|
}
|
|
12513
12558
|
const windowToMs = toB.ms + DAY_MS2 - 1;
|
|
12514
12559
|
const filter = [
|
|
@@ -12519,7 +12564,7 @@ async function postedWithin(_resource, from, to, http, opts, opLabel = "time_ent
|
|
|
12519
12564
|
else if (opts?.posted === false) filter.push({ field: "postedDate", op: "notExist" });
|
|
12520
12565
|
if (opts?.ticketID !== void 0) filter.push({ field: "ticketID", op: "eq", value: opts.ticketID });
|
|
12521
12566
|
if (opts?.resourceID !== void 0) filter.push({ field: "resourceID", op: "eq", value: opts.resourceID });
|
|
12522
|
-
const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit),
|
|
12567
|
+
const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP10, http);
|
|
12523
12568
|
let postedCount = 0;
|
|
12524
12569
|
for (const item of items) {
|
|
12525
12570
|
const postedDate = item.postedDate;
|
|
@@ -12729,7 +12774,7 @@ async function resolveCode(http, family, familyLabel2, pinnedId, departments, op
|
|
|
12729
12774
|
}
|
|
12730
12775
|
|
|
12731
12776
|
// src/resources/special/time_entries/createForResource.ts
|
|
12732
|
-
var
|
|
12777
|
+
var OP6 = "time_entries.createForResource";
|
|
12733
12778
|
var PARAM_KEYS = /* @__PURE__ */ new Set([
|
|
12734
12779
|
"internallAllocationCodeID",
|
|
12735
12780
|
"ticketID",
|
|
@@ -12765,30 +12810,30 @@ function validateCreateParams(params) {
|
|
|
12765
12810
|
if (pinCount > 1) {
|
|
12766
12811
|
throw new AutotaskConfigError(
|
|
12767
12812
|
"createForResource: exactly one linkage pin is honoured (internallAllocationCodeID | ticketID | taskID) \u2014 the vendor gate requires exactly one; pass one pin (or none for the default internal linkage)",
|
|
12768
|
-
{ operation:
|
|
12813
|
+
{ operation: OP6 }
|
|
12769
12814
|
);
|
|
12770
12815
|
}
|
|
12771
12816
|
if (pins.role !== void 0 && pins.code !== void 0) {
|
|
12772
12817
|
throw new AutotaskConfigError(
|
|
12773
12818
|
"createForResource: a pinned roleID is only meaningful with the task/ticket linkage (internallAllocationCodeID pins the internal linkage and owns the code) \u2014 drop one",
|
|
12774
|
-
{ operation:
|
|
12819
|
+
{ operation: OP6 }
|
|
12775
12820
|
);
|
|
12776
12821
|
}
|
|
12777
12822
|
if (params.hoursWorked !== void 0 && (typeof params.hoursWorked !== "number" || !Number.isFinite(params.hoursWorked) || params.hoursWorked <= 0)) {
|
|
12778
12823
|
throw new AutotaskConfigError(
|
|
12779
12824
|
`createForResource: hoursWorked must be a positive finite number (got ${String(params.hoursWorked)})`,
|
|
12780
|
-
{ operation:
|
|
12825
|
+
{ operation: OP6 }
|
|
12781
12826
|
);
|
|
12782
12827
|
}
|
|
12783
12828
|
return pins;
|
|
12784
12829
|
}
|
|
12785
12830
|
async function assertResourceActive(http, rid) {
|
|
12786
|
-
const rec = await fetchItem2(http, `/V1.0/Resources/${rid}`,
|
|
12831
|
+
const rec = await fetchItem2(http, `/V1.0/Resources/${rid}`, OP6);
|
|
12787
12832
|
if (rec === null) {
|
|
12788
12833
|
throw new ResourceInvalidError(`Resource ${rid} was not found \u2014 a time entry cannot attach to a missing resource`, {
|
|
12789
12834
|
resourceIds: [rid],
|
|
12790
12835
|
details: { idRefs: [{ entity: "resource", id: rid }] },
|
|
12791
|
-
operation:
|
|
12836
|
+
operation: OP6,
|
|
12792
12837
|
category: "not_found",
|
|
12793
12838
|
suggestedAction: "Resolve the resource id (resources.get / resources.search) and retry."
|
|
12794
12839
|
});
|
|
@@ -12797,7 +12842,7 @@ async function assertResourceActive(http, rid) {
|
|
|
12797
12842
|
throw new ResourceInvalidError(`Resource ${rid} is not active (isActive !== true) \u2014 the vendor would reject a time entry for an inactive resource`, {
|
|
12798
12843
|
resourceIds: [rid],
|
|
12799
12844
|
details: { idRefs: [{ entity: "resource", id: rid }] },
|
|
12800
|
-
operation:
|
|
12845
|
+
operation: OP6,
|
|
12801
12846
|
suggestedAction: "Activate the resource or pick an active one."
|
|
12802
12847
|
});
|
|
12803
12848
|
}
|
|
@@ -12807,11 +12852,11 @@ async function resolveAllocationCode(http, rid, linkage, pins, departments) {
|
|
|
12807
12852
|
const pinnedForCode = pins.code !== void 0 ? pins.code : pins.role;
|
|
12808
12853
|
let code = null;
|
|
12809
12854
|
const familiesTried = [];
|
|
12810
|
-
code = await resolveCode(http, familyOf(linkage), familyLabel(familyOf(linkage)), pinnedForCode, departments,
|
|
12855
|
+
code = await resolveCode(http, familyOf(linkage), familyLabel(familyOf(linkage)), pinnedForCode, departments, OP6);
|
|
12811
12856
|
familiesTried.push({ family: familyOf(linkage), label: familyLabel(familyOf(linkage)), filters: [{ field: "useType", op: "eq", value: familyOf(linkage) }, { field: "isActive", op: "eq", value: true }] });
|
|
12812
12857
|
if (code === null && linkage === "task" && pins.role === void 0) {
|
|
12813
12858
|
usedLinkage = "internal";
|
|
12814
|
-
code = await resolveCode(http, USE_TYPE_INTERNAL, familyLabel(USE_TYPE_INTERNAL), void 0, departments,
|
|
12859
|
+
code = await resolveCode(http, USE_TYPE_INTERNAL, familyLabel(USE_TYPE_INTERNAL), void 0, departments, OP6);
|
|
12815
12860
|
familiesTried.push({ family: USE_TYPE_INTERNAL, label: familyLabel(USE_TYPE_INTERNAL), filters: [{ field: "useType", op: "eq", value: USE_TYPE_INTERNAL }, { field: "isActive", op: "eq", value: true }] });
|
|
12816
12861
|
}
|
|
12817
12862
|
if (code === null) {
|
|
@@ -12821,7 +12866,7 @@ async function resolveAllocationCode(http, rid, linkage, pins, departments) {
|
|
|
12821
12866
|
families: familiesTried,
|
|
12822
12867
|
resourceDepartments: [...departments].sort((a, b) => a - b)
|
|
12823
12868
|
},
|
|
12824
|
-
{ operation:
|
|
12869
|
+
{ operation: OP6 }
|
|
12825
12870
|
);
|
|
12826
12871
|
}
|
|
12827
12872
|
const resolvedCode = codeInfo(code);
|
|
@@ -12860,7 +12905,7 @@ function createDryRun2(http, rid, body, linkage, usedLinkage, resolvedCode) {
|
|
|
12860
12905
|
}
|
|
12861
12906
|
return buildDryRunResult(
|
|
12862
12907
|
{
|
|
12863
|
-
operation:
|
|
12908
|
+
operation: OP6,
|
|
12864
12909
|
method: "POST",
|
|
12865
12910
|
path: "/V1.0/TimeEntries",
|
|
12866
12911
|
ids: [rid],
|
|
@@ -12902,7 +12947,7 @@ async function createWithAttempts(resource, http, opts, body, defaults, pins, us
|
|
|
12902
12947
|
const gate3 = ROLE_REJECTION_PATTERN.test(text);
|
|
12903
12948
|
if (usedLinkage !== "internal" && gate3) {
|
|
12904
12949
|
if (!taskRoleFetched && usedLinkage === "task" && pins.task !== void 0) {
|
|
12905
|
-
const task = await fetchItem2(http, `/V1.0/Tasks/${pins.task}`,
|
|
12950
|
+
const task = await fetchItem2(http, `/V1.0/Tasks/${pins.task}`, OP6);
|
|
12906
12951
|
taskRoleFetched = true;
|
|
12907
12952
|
if (task !== null) pushLadder(task.assignedResourceRoleID);
|
|
12908
12953
|
}
|
|
@@ -12928,7 +12973,7 @@ async function createForResource(resource, resourceID, params, opts = {}, http)
|
|
|
12928
12973
|
const pins = validateCreateParams(params);
|
|
12929
12974
|
await assertResourceActive(http, rid);
|
|
12930
12975
|
const linkage = pins.code !== void 0 ? "internal" : pins.ticket !== void 0 ? "ticket" : pins.task !== void 0 ? "task" : "internal";
|
|
12931
|
-
const roleRows = await resourceRoleRows(http, rid,
|
|
12976
|
+
const roleRows = await resourceRoleRows(http, rid, OP6);
|
|
12932
12977
|
const departments = roleRows.departments;
|
|
12933
12978
|
const { usedLinkage, resolvedCode } = await resolveAllocationCode(http, rid, linkage, pins, departments);
|
|
12934
12979
|
const defaults = windowDefaults(params);
|
|
@@ -12951,12 +12996,12 @@ function discoveryField(err, body, defaults) {
|
|
|
12951
12996
|
}
|
|
12952
12997
|
|
|
12953
12998
|
// src/resources/special/time_entries/move.ts
|
|
12954
|
-
var
|
|
12999
|
+
var OP7 = "time_entries.moveToTicket";
|
|
12955
13000
|
var COPY2 = ["resourceID", "roleID", "billingCodeID", "dateWorked", "startDateTime", "endDateTime", "hoursWorked", "offsetHours", "summaryNotes", "internalNotes", "isNonBillable", "showOnInvoice"];
|
|
12956
13001
|
var CONTRACT_SCOPED2 = ["contractID", "contractServiceID", "contractServiceBundleID"];
|
|
12957
13002
|
async function readTimeEntry(http, id, retries) {
|
|
12958
13003
|
try {
|
|
12959
|
-
const res = await http.request({ method: "GET", path: `/V1.0/TimeEntries/${id}`, operation:
|
|
13004
|
+
const res = await http.request({ method: "GET", path: `/V1.0/TimeEntries/${id}`, operation: OP7, maxRetries: retries });
|
|
12960
13005
|
return res?.item ?? null;
|
|
12961
13006
|
} catch (e) {
|
|
12962
13007
|
if (isAutotaskError(e) && (e.httpStatus === 404 || e.code === "NOT_FOUND")) return null;
|
|
@@ -12966,27 +13011,27 @@ async function readTimeEntry(http, id, retries) {
|
|
|
12966
13011
|
async function checkSource2({ http, source, sourceId, toTicketId, retries }) {
|
|
12967
13012
|
const ids2 = { sourceId, toTicketId };
|
|
12968
13013
|
if (source.taskID !== null && source.taskID !== void 0) {
|
|
12969
|
-
throw refuse("MOVE_SOURCE_UNSUPPORTED", `${
|
|
13014
|
+
throw refuse("MOVE_SOURCE_UNSUPPORTED", `${OP7}: time entry ${sourceId} is on a task \u2014 only ticket time entries are moved`, ids2, OP7);
|
|
12970
13015
|
}
|
|
12971
13016
|
if (source.billingApprovalDateTime || source.billingApprovalResourceID || source.billingApprovalLevelMostRecent) {
|
|
12972
|
-
throw refuse("MOVE_BLOCKED_APPROVED", `${
|
|
13017
|
+
throw refuse("MOVE_BLOCKED_APPROVED", `${OP7}: time entry ${sourceId} has billing approval set \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "approved entries are not moved by the API" } });
|
|
12973
13018
|
}
|
|
12974
13019
|
let billing;
|
|
12975
13020
|
try {
|
|
12976
|
-
billing = await queryRows(http, "BillingItems", [{ field: "timeEntryID", op: "eq", value: sourceId }],
|
|
13021
|
+
billing = await queryRows(http, "BillingItems", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP7, retries);
|
|
12977
13022
|
} catch {
|
|
12978
|
-
throw refuse("MOVE_BLOCKED_BILLED", `${
|
|
13023
|
+
throw refuse("MOVE_BLOCKED_BILLED", `${OP7}: the billing items of time entry ${sourceId} could not be read \u2014 refused (fails closed)`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billing state unreadable" } });
|
|
12979
13024
|
}
|
|
12980
13025
|
if (billing.some((b) => b.invoiceID || b.postedDate)) {
|
|
12981
|
-
throw refuse("MOVE_BLOCKED_BILLED", `${
|
|
13026
|
+
throw refuse("MOVE_BLOCKED_BILLED", `${OP7}: time entry ${sourceId} is billed or posted \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billed entries are not moved by the API" } });
|
|
12982
13027
|
}
|
|
12983
|
-
const attachments = await queryRows(http, "TimeEntryAttachments", [{ field: "timeEntryID", op: "eq", value: sourceId }],
|
|
13028
|
+
const attachments = await queryRows(http, "TimeEntryAttachments", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP7, retries);
|
|
12984
13029
|
if (attachments.length > 0) {
|
|
12985
|
-
throw refuse("MOVE_BLOCKED_ATTACHMENTS", `${
|
|
13030
|
+
throw refuse("MOVE_BLOCKED_ATTACHMENTS", `${OP7}: time entry ${sourceId} has attachments, which a delete would destroy \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "entries with attachments are not moved by the API" } });
|
|
12986
13031
|
}
|
|
12987
13032
|
}
|
|
12988
13033
|
var SPEC2 = {
|
|
12989
|
-
operation:
|
|
13034
|
+
operation: OP7,
|
|
12990
13035
|
entity: "time_entry",
|
|
12991
13036
|
readSource: readTimeEntry,
|
|
12992
13037
|
sourceTicketId: (s) => typeof s.ticketID === "number" ? s.ticketID : null,
|
|
@@ -13021,7 +13066,7 @@ function moveToTicket2(_resource, sourceId, toTicketId, opts, http) {
|
|
|
13021
13066
|
}
|
|
13022
13067
|
|
|
13023
13068
|
// src/resources/special/time_entries/approve.ts
|
|
13024
|
-
var
|
|
13069
|
+
var OP8 = "time_entries.approve";
|
|
13025
13070
|
var APPROVAL_LEVELS_PATH = "/V1.0/BillingItemApprovalLevels";
|
|
13026
13071
|
function toIso(value) {
|
|
13027
13072
|
if (value instanceof Date) {
|
|
@@ -13059,7 +13104,7 @@ async function approve(resource, id, opts = {}, http) {
|
|
|
13059
13104
|
if (opts.dryRun === true) {
|
|
13060
13105
|
return buildDryRunResult(
|
|
13061
13106
|
{
|
|
13062
|
-
operation:
|
|
13107
|
+
operation: OP8,
|
|
13063
13108
|
method: "POST",
|
|
13064
13109
|
path: APPROVAL_LEVELS_PATH,
|
|
13065
13110
|
ids: [numericId],
|
|
@@ -13082,10 +13127,10 @@ async function approve(resource, id, opts = {}, http) {
|
|
|
13082
13127
|
method: "POST",
|
|
13083
13128
|
path: APPROVAL_LEVELS_PATH,
|
|
13084
13129
|
body,
|
|
13085
|
-
operation:
|
|
13130
|
+
operation: OP8,
|
|
13086
13131
|
maxRetries: opts.maxRetries
|
|
13087
13132
|
});
|
|
13088
|
-
const levelId = toNumber(parseIdentifier(unwrapOperation(created,
|
|
13133
|
+
const levelId = toNumber(parseIdentifier(unwrapOperation(created, OP8).id, "billingItemApprovalLevelID"));
|
|
13089
13134
|
await resource.update(
|
|
13090
13135
|
numericId,
|
|
13091
13136
|
{ billingApprovalDateTime: approvalDateTime, billingApprovalResourceID: approvalResourceID },
|
|
@@ -13108,28 +13153,28 @@ async function approve(resource, id, opts = {}, http) {
|
|
|
13108
13153
|
}
|
|
13109
13154
|
|
|
13110
13155
|
// src/resources/special/time_entries/recentTickets.ts
|
|
13111
|
-
var
|
|
13156
|
+
var OP9 = "time_entries.recentTickets";
|
|
13112
13157
|
var DAY_MS3 = 864e5;
|
|
13113
13158
|
var TICKET_CHUNK2 = 100;
|
|
13114
13159
|
var TICKET_FIELDS3 = ["id", "ticketNumber", "title", "status", "assignedResourceID", "companyID"];
|
|
13115
|
-
function
|
|
13160
|
+
function positiveId3(value, name) {
|
|
13116
13161
|
const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
|
|
13117
13162
|
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
|
|
13118
|
-
throw new AutotaskConfigError(`${
|
|
13163
|
+
throw new AutotaskConfigError(`${OP9}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP9 });
|
|
13119
13164
|
}
|
|
13120
13165
|
return n;
|
|
13121
13166
|
}
|
|
13122
13167
|
async function recentTickets(_resource, from, to, http, opts) {
|
|
13123
13168
|
if (opts === void 0 || opts === null || typeof opts !== "object") {
|
|
13124
|
-
throw new AutotaskConfigError(`${
|
|
13169
|
+
throw new AutotaskConfigError(`${OP9}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP9 });
|
|
13125
13170
|
}
|
|
13126
|
-
const resourceID =
|
|
13127
|
-
const companyID = opts.companyID === void 0 ? void 0 :
|
|
13128
|
-
if (opts.tz !== void 0) validateZone(opts.tz,
|
|
13129
|
-
const fromB = customRangeDay(from, "from", void 0,
|
|
13130
|
-
const toB = customRangeDay(to, "to", void 0,
|
|
13171
|
+
const resourceID = positiveId3(opts.resourceID, "resourceID");
|
|
13172
|
+
const companyID = opts.companyID === void 0 ? void 0 : positiveId3(opts.companyID, "companyID");
|
|
13173
|
+
if (opts.tz !== void 0) validateZone(opts.tz, OP9);
|
|
13174
|
+
const fromB = customRangeDay(from, "from", void 0, OP9);
|
|
13175
|
+
const toB = customRangeDay(to, "to", void 0, OP9);
|
|
13131
13176
|
if (fromB.ms > toB.ms) {
|
|
13132
|
-
throw new AutotaskConfigError(`${
|
|
13177
|
+
throw new AutotaskConfigError(`${OP9}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP9 });
|
|
13133
13178
|
}
|
|
13134
13179
|
const windowToMs = toB.ms + DAY_MS3 - 1;
|
|
13135
13180
|
const { items: entries, hasMore } = await queryTimeEntries(
|
|
@@ -13140,7 +13185,7 @@ async function recentTickets(_resource, from, to, http, opts) {
|
|
|
13140
13185
|
{ field: "resourceID", op: "eq", value: resourceID }
|
|
13141
13186
|
],
|
|
13142
13187
|
clampWindowLimit(opts.limit),
|
|
13143
|
-
|
|
13188
|
+
OP9,
|
|
13144
13189
|
http
|
|
13145
13190
|
);
|
|
13146
13191
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -13166,9 +13211,9 @@ async function recentTickets(_resource, from, to, http, opts) {
|
|
|
13166
13211
|
idempotent: true,
|
|
13167
13212
|
path: "/V1.0/Tickets/query",
|
|
13168
13213
|
body: { MaxRecords: TICKET_CHUNK2, filter, IncludeFields: TICKET_FIELDS3 },
|
|
13169
|
-
operation:
|
|
13214
|
+
operation: OP9
|
|
13170
13215
|
});
|
|
13171
|
-
for (const t of unwrapItems(res,
|
|
13216
|
+
for (const t of unwrapItems(res, OP9).items) if (typeof t.id === "number") tickets.set(t.id, t);
|
|
13172
13217
|
}
|
|
13173
13218
|
const items = [];
|
|
13174
13219
|
const unresolvedTicketIDs = [];
|