node-autotask 0.10.0 → 0.12.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 (41) hide show
  1. package/MCP_TOOL_CATALOG.json +27 -9
  2. package/MCP_TOOL_MANIFEST.md +13 -12
  3. package/N8N_MCP_MANIFEST.json +3 -3
  4. package/N8N_MCP_MANIFEST.md +4 -4
  5. package/README.md +1 -1
  6. package/capabilities.json +1460 -1250
  7. package/dist/capabilities.cjs +2 -2
  8. package/dist/capabilities.js +1 -1
  9. package/dist/{chunk-NVJ2PTN3.js → chunk-3WIDDEHP.js} +2 -2
  10. package/dist/{chunk-6KFP5HV3.js → chunk-4A6XLQHE.js} +1459 -1249
  11. package/dist/{chunk-WTVLHMZA.cjs → chunk-5N6DYKXO.cjs} +519 -39
  12. package/dist/{chunk-HWC2WPX2.js → chunk-GD4JRPYF.js} +498 -18
  13. package/dist/{chunk-WTVD2JZN.cjs → chunk-JKZVCFRY.cjs} +1459 -1249
  14. package/dist/{chunk-3VB6N44U.js → chunk-MY7ZSXY3.js} +1075 -6
  15. package/dist/{chunk-QUM74WLQ.cjs → chunk-SRJI5XUZ.cjs} +135 -135
  16. package/dist/{chunk-S7VMY5KN.cjs → chunk-TELBX6HK.cjs} +1462 -393
  17. package/dist/{index-DGgMD8aq.d.ts → index-D8I6taEo.d.cts} +200 -2
  18. package/dist/{index-BOyh7S65.d.cts → index-uAxAcRol.d.ts} +200 -2
  19. package/dist/index.cjs +19 -19
  20. package/dist/index.d.cts +4 -4
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.js +4 -4
  23. package/dist/operations/index.cjs +213 -529
  24. package/dist/operations/index.d.cts +24 -6
  25. package/dist/operations/index.d.ts +24 -6
  26. package/dist/operations/index.js +102 -418
  27. package/dist/pool.cjs +8 -8
  28. package/dist/pool.d.cts +2 -2
  29. package/dist/pool.d.ts +2 -2
  30. package/dist/pool.js +4 -4
  31. package/dist/resources/index.cjs +4 -4
  32. package/dist/resources/index.d.cts +2 -2
  33. package/dist/resources/index.d.ts +2 -2
  34. package/dist/resources/index.js +3 -3
  35. package/dist/types/index.d.cts +1 -1
  36. package/dist/types/index.d.ts +1 -1
  37. package/docs/API.md +192 -2
  38. package/docs/N8N-ADAPTER.md +1 -1
  39. package/package.json +1 -1
  40. package/dist/{index-cQ6CRexR.d.cts → index-BXtKN1M5.d.cts} +201 -201
  41. package/dist/{index-cQ6CRexR.d.ts → index-BXtKN1M5.d.ts} +201 -201
package/docs/API.md CHANGED
@@ -847,7 +847,7 @@ be cross-mode-refused.
847
847
  whose MCP annotation is `readOnlyHint !== true` — today exactly **254
848
848
  tools**: the 252 dedicated write/delete tools (198 `effect=write` + 54
849
849
  `effect=destructive`, every one of them has a dedicated tool) +
850
- `autotask_write` + `autotask_delete`. The remaining **600 tools** (the 587
850
+ `autotask_write` + `autotask_delete`. The remaining **601 tools** (the 588
851
851
  dedicated read tools + the 10 core read tools + `autotask_read` +
852
852
  `autotask_catalog` + `autotask_describe`) all carry `readOnlyHint: true`
853
853
  and are safe ungated: every op they can route is `effect=read` (zero
@@ -1145,7 +1145,7 @@ Standard methods (every resource, `BaseResource`): `query` (stream, 1000-page gu
1145
1145
  | `contract_service_units` | ContractServiceUnit | entity | extended | yes (contracts) | query, count, get, resolve | getEntityInfo, getFieldInfo, getUdfInfo | autotask_contractServiceUnit_get |
1146
1146
  | `contract_services` | ContractService | entity | extended | yes (contracts) | query, count, get, create, update, resolve | createIfNotExists, getEntityInfo, getFieldInfo, getUdfInfo | autotask_contractService_get |
1147
1147
  | `contract_ticket_purchases` | ContractTicketPurchases | entity | extended | yes (contracts) | query, count, get, create, update, resolve | getEntityInfo, getFieldInfo, getUdfInfo | autotask_contractTicketPurchase_get |
1148
- | `contracts` | Contract | entity | extended | no | query, count, get, create, update, resolve, search | createIfNotExists, getEntityInfo, getFieldInfo, getUdfInfo | autotask_contract_get |
1148
+ | `contracts` | Contract | entity | extended | no | query, count, get, create, update, resolve, search | createIfNotExists, getEntityInfo, getFieldInfo, getUdfInfo, profitability | autotask_contract_get |
1149
1149
  | `countries` | Country | entity | advanced | no | query, count, get, update, resolve, search | getEntityInfo, getFieldInfo, getUdfInfo | autotask_country_get |
1150
1150
  | `departments` | Department | entity | extended | no | query, count, get, create, update, resolve, search | getEntityInfo, getFieldInfo, getUdfInfo | autotask_department_get |
1151
1151
  | `domain_registrars` | DomainRegistrar | entity | extended | no | query, count, get, create, update, resolve, search | getEntityInfo, getFieldInfo, getUdfInfo | autotask_DomainRegistrar_get |
@@ -2601,6 +2601,196 @@ resource's query surface is pinned blind), and `next` (concrete next steps; the
2601
2601
  remedy names the authority op). Hit paths carry no `miss` key. Thrown outcomes
2602
2602
  (`NOT_FOUND` by numeric id, `RESOLUTION_AMBIGUOUS`, `RESOLUTION_TRUNCATED`) are unchanged.
2603
2603
 
2604
+ ### 11.26 The contract P&L composite — `contracts.profitability` (issue #100)
2605
+
2606
+ Issue #100 adds the contract profit-and-loss composite op (an additive read;
2607
+ the plan change — a new registry op — is a minor at publish). One call
2608
+ returns the contract's reconciled P&L over a date window:
2609
+
2610
+ - **`contracts.profitability(contractId, opts)` — the closed opts bag.**
2611
+ `dateFrom`/`dateTo` are required (`YYYY-MM-DD`, `dateTo >= dateFrom`) and
2612
+ the window is capped at 36 calendar months (the per-month windowing budget
2613
+ stays bounded; OQ1). `labourCostMethod` (default
2614
+ `billing_item_our_cost`; the closed 4-set
2615
+ `billing_item_our_cost` / `contract_role_cost` / `resource_internal_cost` /
2616
+ `provided`) selects the START rung of the cost-rate ladder;
2617
+ `labourRatePerHour` (finite `>= 0`) is the `provided` catch-all rung and is
2618
+ REQUIRED when `labourCostMethod` is `provided`. `includeRecurringCosts` /
2619
+ `includeUnbilledRevenue` (default true) gate the charges/units folds and
2620
+ the expected-revenue basis; `externalMonthlyCosts` (finite `>= 0`, indexed
2621
+ by month from `dateFrom`, at most one entry per window month) is the
2622
+ caller-supplied non-vendor tooling cost, surfaced in
2623
+ `tooling_cost.caller_supplied` (stamped non-vendor — never folded into the
2624
+ vendor figure); `groupByActivity` (default true) gates the
2625
+ `ticketCategory` activity fold; `staleAfterDays` (default 30, integer `>=
2626
+ 1`) is the open-stale horizon; `maxTicketsForJoin` (default 500, integer
2627
+ 1..500) caps the ticket join set fed to the expenses + miscoding probe
2628
+ (sorted, first N, the `N of M` note); `limit` (default 50, clamped 500) is
2629
+ every part's `MaxRecords` + the capped lists. Validation collects the
2630
+ COMPLETE problem list and throws ONE typed `CONFIG_ERROR` pre-request —
2631
+ zero wire on any malformed bag (the refusal table is house style: every
2632
+ message names the key + the valid values).
2633
+ - **Wire plan: ≤18 bounded reads, zero mutating, all pre-existing ops.**
2634
+ Issue order: contract `get` → customer `GET /V1.0/Companies/{companyID}` →
2635
+ `ContractServices` / `ContractServiceUnits` / `ContractCharges` /
2636
+ `ContractRoleCosts` / `ContractRates` / `BillingItems` queries → invoices
2637
+ (fetch-by-ids on the distinct billed `invoiceID`s; skipped on none) →
2638
+ `TimeEntries` query → in-window `Tickets` query (the activity population) →
2639
+ the tickets `entityInformation/fields` metadata read (the open-status
2640
+ picklist) → open `Tickets` query (`status in` the open set) → resources
2641
+ (fetch-by-ids on the distinct time-row `resourceID`s; skipped on none) →
2642
+ `ExpenseItems` query + the ONE extra bounded miscoding probe
2643
+ (`TimeEntries` with `ticketID in join` + `or[contractID noteq, contractID
2644
+ notExist]`; skipped on an empty ticket set) → `ConfigurationItems` query
2645
+ (default-on) → `Subscriptions` query (CI join; skipped on no CIs). The
2646
+ `time_entries.getPosted` / `getUnposted` endpoints are NEVER called (the
2647
+ pinned vendor 500 on AU03); posted/unposted derives from the
2648
+ `billingItems.timeEntryID` join (unposted = no billing item exists yet).
2649
+ The structural exclusions (`/Services/`, `/ExpenseReports/`,
2650
+ `/BillingCodes/` list reads, getPosted/getUnposted) are pinned by the
2651
+ recorded-request test. Baseline = 12 (a resolvable contract); the
2652
+ typical busy contract = 17; the full fixture = 18. `wires: { issued,
2653
+ budget: 18, note? }` rides the result as the honesty stamp (actual vs
2654
+ budget).
2655
+ - **Per-month windowing (parts `billingItems` + `timeEntries`).** One
2656
+ full-window page (`MaxRecords: limit`); when it comes back FULL with a
2657
+ live next cursor, the part re-queries PER CALENDAR MONTH intersecting the
2658
+ window (one page per month, the date field bounded to that month, in
2659
+ month order; rows deduped by `id`). A still-full month stamps
2660
+ `hasMore`/`capped` + the truncation note (`month YYYY-MM hit the limit of
2661
+ N — figures cover the returned rows only; widen with a narrower window or
2662
+ higher limit`) — NO cursor walk (the house single-page rule; the composite
2663
+ owns its own windowing so per-month figures stay correct by construction).
2664
+ Every expansion read counts toward `wires.issued` (the note says why);
2665
+ the 36-month cap bounds the worst case.
2666
+ - **The cost-rate ladder (per time entry, zero extra wire).** Rung 1
2667
+ `billing_item.ourCost`: a LINE cost, not a rate — Σ the finite `>= 0`
2668
+ `ourCost` over the entry's billed lines (partial billing across months
2669
+ sums naturally; an entry whose billed lines carry NO finite `ourCost`
2670
+ falls THROUGH — the rung is unusable, not zero). Rung 2
2671
+ `contract_role_costs.rate`: the `resourceID:roleID` row is preferred over
2672
+ the role-only row (`matched: 'resource+role' | 'role'`); `rate × hours`.
2673
+ Rung 3 `resource.internalCost`: the fetch-by-ids GET-fallback rows only
2674
+ (a `NOT_FOUND` miss makes the rung unavailable for that resource — the
2675
+ ww29 resources list-scoping is seen through by get-by-id, live-verified
2676
+ 2026-10-15; the quirk is cited in the part note when the chunk queries
2677
+ 0-rowed and the gets resolved). Rung 4 `provided`: `labourRatePerHour ×
2678
+ hours` (in the ladder only when the rate is finite). `hours(entry)` =
2679
+ `hoursWorked` when finite and `> 0`, else 0. A row resolving to
2680
+ `missing` contributes 0 to `labour_cost.total` but is audited:
2681
+ `costRateResolution.sources` (per-rung `entries`/`hours`/`cost`, ALWAYS
2682
+ including `missing`), `unresolvedHours` (= the `missing` hours — the
2683
+ lower-bound honesty number; `total_cost` is a LOWER BOUND exactly when it
2684
+ is `> 0`), and the pinned note lines (the `N hours unresolved (missing
2685
+ rate) — total_cost is a lower bound` line; the per-resource NOT_FOUND
2686
+ line; the no-billing-item line). NEVER a silent zero. `contract_rates`
2687
+ is NOT a ladder rung (the customer billing rate — the wrong side of the
2688
+ P&L).
2689
+ - **Monthly P&L (one row per calendar month in the window).**
2690
+ `revenue_invoiced` (Σ `extendedPrice` of the month's items on
2691
+ non-voided invoices) · `revenue_voided_excluded` (Σ on voided invoices) ·
2692
+ `revenue_expected` (Σ `service.unitPrice × units` of the units effective
2693
+ in the month; `null` when the services/units basis is absent) ·
2694
+ `revenue_expected_unbilled = max(0, expected − billed)` · `labour_hours`
2695
+ (Σ raw `hoursWorked`) · `labour_cost { total, unresolvedHours,
2696
+ rateSources }` (the per-month mirror of the ladder audit) ·
2697
+ `tooling_cost { vendor, caller_supplied }` (vendor = Σ subscription
2698
+ `periodCost` per active month in the window; `null` when the
2699
+ subscriptions part is skipped; caller-supplied = the bag value, `0` when
2700
+ absent) · `recurring_cost` (charges `billableAmount` + units `cost`,
2701
+ when included) · `expense_cost` (Σ local-currency expense amounts) ·
2702
+ `total_cost` · `profit = revenue_invoiced − total_cost` ·
2703
+ `margin = profit / revenue_invoiced` when `> 0`, else `null` (the
2704
+ division is refused, not zeroed) · `break_even_hours`
2705
+ (`(total_cost − labour) / (Σcost / Σhours over resolved rows)`, `0` when
2706
+ fixed `<= 0`, `null` with no resolved hours — including an empty month).
2707
+ All amounts are the tenant's LOCAL currency fields
2708
+ (`extendedPrice`, `expenseCurrencyExpenseAmount`).
2709
+ - **The 11 data-quality checks (always present, order-stable, `count: 0` =
2710
+ a passed check).** Typed `{ code, count, sample_ids }` warnings
2711
+ (`count` = the full in-memory/fetched-set count, never capped;
2712
+ `sample_ids` = first `limit`, deduped + sorted): `miscoded_time_out` (the
2713
+ ONE extra bounded probe — time worked on THIS contract's tickets coded to
2714
+ another contract or to none) · `cross_contract_ticket_time` (a fetched
2715
+ ticket says it belongs elsewhere) · `duplicate_entries` (exact
2716
+ `resourceID+dateWorked+ticketID+hoursWorked` tuple; `count` = all copies,
2717
+ samples = copies beyond the lowest `id`) · `zero_negative_hours` ·
2718
+ `time_outside_ticket_period` (`dateWorked < ticket.createDate` or after
2719
+ the earlier of `resolvedDateTime`/`completedDate` — a fetched ticket's
2720
+ whole post-resolution life, not just the first late entry) ·
2721
+ `missing_cost_rate` (the ladder's `missing` rows; the resource NOT_FOUND
2722
+ misses ride the note) · `recurring_cost_drift` (month-over-month beyond
2723
+ the 0.005 float dust; samples the charge/unit ids whose monthly
2724
+ contribution changed) · `expected_unbilled_revenue` (expected >
2725
+ billed + 0.005; the pure "expected with nothing billed" case carries the
2726
+ EMPTY sample — that is the assertion) · `cross_contract_tickets` (the
2727
+ ticket-side drift + the entry-side unresolvable set) ·
2728
+ `open_stale_tickets` (`now − lastActivityDate > staleAfterDays`, `now` =
2729
+ the run's wall clock stamped `period.asOf`; absent `lastActivityDate` is
2730
+ unknown, not zero) · `estimate_vs_actual` (both estimates prorated to the
2731
+ window — `estimate × overlapDays / termDays` over the contract term — and
2732
+ flagged at `> 10%` deviation; samples `[contractId]`). 10 of 11 are pure
2733
+ in-memory folds (zero extra wire).
2734
+ - **The response-side folds.** `activity_categories` (by `ticketCategory`:
2735
+ hours, cost = labour + that category's expenses, ticketCount, entryCount,
2736
+ sample ticket numbers) · `highest_cost_tickets` (cost desc, capped at
2737
+ `limit`; a missing-rate ticket prices 0 and is flagged via the audit —
2738
+ never silently dropped) · `possible_miscoding` (the probe rows + the
2739
+ confirmed cross-contract entries, closed reason set
2740
+ `no_contract_on_entry` / `ticket_of_other_contract` /
2741
+ `ticket_not_in_fetched_set`) · `open_renewal_items` (open tickets with
2742
+ the stale-days detail, subscription expirations, the contract end, the
2743
+ per-month `included_hours_burn` row). The probe rows are EXCLUDED from
2744
+ the P&L folds (diagnostic — time not coded to this contract).
2745
+ - **Degradation (per part typed `ok` / `blind` / `skipped`; the op NEVER
2746
+ fails the call on a degraded part).** Every tickets call is
2747
+ `contractID`-filtered, so the pinned `unfiltered-blind` tickets class
2748
+ never stamps a filtered empty (a filtered 0 is a TRUE zero with the
2749
+ honest note); the 0-row parts carry the pinned
2750
+ `tenant-empty-for-user` `emptyReason` stamp where attached. A dangling
2751
+ customer FK (`companies.get` 404) degrades to `customer: null` +
2752
+ `parts.customer: 'skipped'` — NOT an error (the CIs read still fires on
2753
+ the contract row's `companyID`). A field-catalog fault degrades the open
2754
+ pass to a typed skip (the fault read still counts in `wires.issued`).
2755
+ fetch-by-ids per-item faults (invoices/resources) are typed partial
2756
+ misses named in the part note — a miss never aborts the rest. An empty
2757
+ tenant (the ww29 shape) degrades EVERY part — 13 wires, all-zero monthly
2758
+ rows with the divisions refused (`margin: null`, `break_even_hours:
2759
+ null`, `tooling_cost.vendor: null`, `revenue_expected: null`), all 11
2760
+ warnings at `count: 0`, zero tool failure.
2761
+ - **Registration surface.** The plan row (`capabilities.plan.json` →
2762
+ re-derived hash) carries `kind: 'helper'`, `helperBasis: 'composite'`,
2763
+ `effect: 'read'`, `dryRun: false`, the closed-bag `inputSchema` (the
2764
+ signature-audited arg map in `scripts/lib/args-derive.mjs`); the emitted
2765
+ method delegates to the hand-written special module
2766
+ (`src/resources/special/contracts.ts`). The MCP projection serves
2767
+ `autotask_contract_profitability` (catalog + manifest); the N8N
2768
+ manifests legitimately EXCLUDE the op — `contracts` is not an n8n
2769
+ curated entity (the curation rule is evidence-based: the daily support
2770
+ subset is ticket/contact/company/resource/time_entry only).
2771
+ - **Test pins.** `test/resources/contracts.profitability.test.ts`: the
2772
+ hand-computed 2-month synthetic fixture (every figure derived from the
2773
+ fixture rows; `wires.issued = 18` with the exact queue; every wire pinned
2774
+ in issue order; the structural exclusions + zero-mutating recorded paths;
2775
+ the ladder audit incl. the per-month `rateSources`; the 11 checks with
2776
+ exact counts/samples; the activity/highest-cost/miscoding/renewal folds;
2777
+ the per-month windowing (exact extra month queries, id-dedup, the
2778
+ still-full month note; `wires.issued` counts the expansion); the
2779
+ join-set/`limit` caps; the malformed-bag refusal table (one complete
2780
+ problem list, zero wire); the contract NOT_FOUND).
2781
+ `test/resources/profitability-degradation.test.ts`: the empty-tenant
2782
+ 13-wire suite (every part degrades, zero tool failure), the dangling
2783
+ customer FK, the resources blind-list get-fallback (rung 3 from the
2784
+ gets, the quirk note), the per-item invoice fault (retries off — the
2785
+ fault semantics are the pin, not the transport's 5xx budget), the
2786
+ fieldCatalog-fault open-pass skip, the status-helper sentinel
2787
+ portability (the `unfiltered-blind` predicate stamps the unfiltered call
2788
+ only), and the §6.4 rate-ladder branch table over synthetic entry sets
2789
+ (rung-1 line-cost sum, rung-1 fall-through, resource+role preference,
2790
+ role-only, rung-3 get-fallback, the resource miss, the provided
2791
+ catch-all/start, the provided-without-rate and fully-missing `missing`
2792
+ — never a silent zero — and `internalCost: 0` as a RESOLVED zero).
2793
+
2604
2794
  ## 12. Untrusted-content projection (issue #1)
2605
2795
 
2606
2796
  The agent/MCP projection marks EXTERNALLY-SOURCED free text as untrusted,
@@ -82,7 +82,7 @@ Two sources in, markdown table out: the node repo (the ops column is re-derived
82
82
  | `contractServiceUnits` | ContractServiceUnit | yes | get, getMany, count | — | count, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve |
83
83
  | `contractServices` | ContractService | yes | create, update, get, getMany, count, createIfNotExists | createIfNotExists → `contract_services.createIfNotExists` | count, create, createIfNotExists, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, update |
84
84
  | `contractTicketPurchases` | ContractTicketPurchases | yes | create, update, get, getMany, count | — | count, create, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, update |
85
- | `contracts` | Contract | no | create, update, get, getMany, count, createIfNotExists | createIfNotExists → `contracts.createIfNotExists` | count, create, createIfNotExists, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, search, update |
85
+ | `contracts` | Contract | no | create, update, get, getMany, count, createIfNotExists | createIfNotExists → `contracts.createIfNotExists` | count, create, createIfNotExists, get, getEntityInfo, getFieldInfo, getUdfInfo, profitability, query, resolve, search, update |
86
86
  | `countries` | Country | no | get, getMany, update, count | — | count, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, search, update |
87
87
  | `departments` | Department | no | count, create, get, getMany, update | — | count, create, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, search, update |
88
88
  | `domainRegistrar` | DomainRegistrar | no | create, update, get, getMany, count | — | count, create, get, getEntityInfo, getFieldInfo, getUdfInfo, query, resolve, search, update |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-autotask",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Fully-typed TypeScript SDK for the Autotask (Datto) PSA REST API. Zero runtime dependencies. Built for building MCP servers and integrations.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -3306,6 +3306,207 @@ type ContractServiceUnitUpdate = ContractServiceUnitCreate;
3306
3306
  */
3307
3307
  type ContractServiceUnitSummary = ContractServiceUnit;
3308
3308
 
3309
+ /**
3310
+ * Invoice — API model types (G4 batch A).
3311
+ * GENERATED by scripts/generate-batch.mjs from api-docs.json (InvoiceModel). Do not hand-edit.
3312
+ * Field names keep the exact API casing; returned fields are optional (the vendor
3313
+ * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
3314
+ */
3315
+ /** Invoice record as returned by the API (swagger InvoiceModel). */
3316
+ interface Invoice {
3317
+ id: number;
3318
+ batchID?: number;
3319
+ comments?: string;
3320
+ companyID?: number;
3321
+ createDateTime?: string;
3322
+ creatorResourceID?: number;
3323
+ dueDate?: string;
3324
+ fromDate?: string;
3325
+ invoiceDateTime?: string;
3326
+ invoiceEditorTemplateID?: number;
3327
+ invoiceNumber?: string;
3328
+ invoiceTotal?: number;
3329
+ isVoided?: boolean;
3330
+ orderNumber?: string;
3331
+ paidDate?: string;
3332
+ paymentTerm?: number;
3333
+ taxGroup?: number;
3334
+ taxRegionName?: string;
3335
+ toDate?: string;
3336
+ totalTaxValue?: number;
3337
+ voidedByResourceID?: number;
3338
+ voidedDate?: string;
3339
+ webServiceDate?: string;
3340
+ }
3341
+ /** Create input for Invoice (writable fields; accepts id or itemId). */
3342
+ interface InvoiceCreate {
3343
+ id?: number;
3344
+ batchID?: number;
3345
+ comments?: string;
3346
+ companyID?: number;
3347
+ createDateTime?: string;
3348
+ creatorResourceID?: number;
3349
+ dueDate?: string;
3350
+ fromDate?: string;
3351
+ invoiceDateTime?: string;
3352
+ invoiceEditorTemplateID?: number;
3353
+ invoiceNumber?: string;
3354
+ invoiceTotal?: number;
3355
+ isVoided?: boolean;
3356
+ orderNumber?: string;
3357
+ paidDate?: string;
3358
+ paymentTerm?: number;
3359
+ taxGroup?: number;
3360
+ taxRegionName?: string;
3361
+ toDate?: string;
3362
+ totalTaxValue?: number;
3363
+ voidedByResourceID?: number;
3364
+ voidedDate?: string;
3365
+ webServiceDate?: string;
3366
+ }
3367
+ /** Update input (same writable surface; id identifies the record in the path). */
3368
+ type InvoiceUpdate = InvoiceCreate;
3369
+ /** Compact helper shape for Invoice (resolve/search/getContext): structural alias of the
3370
+ * full record — the registry outputSchema names the fields the MCP projection keeps.
3371
+ */
3372
+ type InvoiceSummary = Invoice;
3373
+
3374
+ /**
3375
+ * ExpenseItem — API model types (G5 batch B).
3376
+ * GENERATED by scripts/generate-batch.mjs from api-docs.json (ExpenseItemModel). Do not hand-edit.
3377
+ * Field names keep the exact API casing; returned fields are optional (the vendor
3378
+ * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
3379
+ */
3380
+
3381
+ /** ExpenseItem record as returned by the API (swagger ExpenseItemModel). */
3382
+ interface ExpenseItem {
3383
+ id: number;
3384
+ companyID?: number;
3385
+ description?: string;
3386
+ destination?: string;
3387
+ entertainmentLocation?: string;
3388
+ expenseCategory?: number;
3389
+ expenseCurrencyExpenseAmount?: number;
3390
+ expenseCurrencyID?: number;
3391
+ expenseDate?: string;
3392
+ expenseReportID?: number;
3393
+ glCode?: string;
3394
+ haveReceipt?: boolean;
3395
+ internalCurrencyExpenseAmount?: number;
3396
+ internalCurrencyReimbursementAmount?: number;
3397
+ isBillableToCompany?: boolean;
3398
+ isReimbursable?: boolean;
3399
+ isRejected?: boolean;
3400
+ miles?: number;
3401
+ odometerEnd?: number;
3402
+ odometerStart?: number;
3403
+ origin?: string;
3404
+ paymentType?: number;
3405
+ projectID?: number;
3406
+ purchaseOrderNumber?: string;
3407
+ reimbursementCurrencyReimbursementAmount?: number;
3408
+ taskID?: number;
3409
+ ticketID?: number;
3410
+ workType?: number;
3411
+ soapParentPropertyId?: unknown;
3412
+ }
3413
+ /** Create input for ExpenseItem (writable fields; accepts id or itemId). */
3414
+ interface ExpenseItemCreate {
3415
+ id?: number;
3416
+ companyID?: number;
3417
+ description?: string;
3418
+ destination?: string;
3419
+ entertainmentLocation?: string;
3420
+ expenseCategory?: number;
3421
+ expenseCurrencyExpenseAmount?: number;
3422
+ expenseCurrencyID?: number;
3423
+ expenseDate?: string;
3424
+ expenseReportID?: number;
3425
+ glCode?: string;
3426
+ haveReceipt?: boolean;
3427
+ internalCurrencyExpenseAmount?: number;
3428
+ internalCurrencyReimbursementAmount?: number;
3429
+ isBillableToCompany?: boolean;
3430
+ isReimbursable?: boolean;
3431
+ isRejected?: boolean;
3432
+ miles?: number;
3433
+ odometerEnd?: number;
3434
+ odometerStart?: number;
3435
+ origin?: string;
3436
+ paymentType?: number;
3437
+ projectID?: number;
3438
+ purchaseOrderNumber?: string;
3439
+ reimbursementCurrencyReimbursementAmount?: number;
3440
+ taskID?: number;
3441
+ ticketID?: number;
3442
+ workType?: number;
3443
+ /** UDF map (name → value) or UdfField[] — normalised to the vendor array on the wire. */
3444
+ userDefinedFields?: UdfField[];
3445
+ }
3446
+ /** Update input (same writable surface; id identifies the record in the path). */
3447
+ type ExpenseItemUpdate = ExpenseItemCreate;
3448
+ /** Compact helper shape for ExpenseItem (resolve/search/getContext): structural alias of the
3449
+ * full record — the registry outputSchema names the fields the MCP projection keeps.
3450
+ */
3451
+ type ExpenseItemSummary = ExpenseItem;
3452
+
3453
+ /**
3454
+ * Subscription — API model types (G4 batch A).
3455
+ * GENERATED by scripts/generate-batch.mjs from api-docs.json (SubscriptionModel). Do not hand-edit.
3456
+ * Field names keep the exact API casing; returned fields are optional (the vendor
3457
+ * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
3458
+ */
3459
+
3460
+ /** Subscription record as returned by the API (swagger SubscriptionModel). */
3461
+ interface Subscription {
3462
+ id: number;
3463
+ configurationItemID?: number;
3464
+ description?: string;
3465
+ effectiveDate?: string;
3466
+ expirationDate?: string;
3467
+ impersonatorCreatorResourceID?: number;
3468
+ materialCodeID?: number;
3469
+ organizationalLevelAssociationID?: number;
3470
+ periodCost?: number;
3471
+ periodPrice?: number;
3472
+ periodType?: number;
3473
+ purchaseOrderNumber?: string;
3474
+ status?: number;
3475
+ subscriptionName?: string;
3476
+ totalCost?: number;
3477
+ totalPrice?: number;
3478
+ vendorID?: number;
3479
+ userDefinedFields?: UdfField[];
3480
+ }
3481
+ /** Create input for Subscription (writable fields; accepts id or itemId). */
3482
+ interface SubscriptionCreate {
3483
+ id?: number;
3484
+ configurationItemID?: number;
3485
+ description?: string;
3486
+ effectiveDate?: string;
3487
+ expirationDate?: string;
3488
+ impersonatorCreatorResourceID?: number;
3489
+ materialCodeID?: number;
3490
+ organizationalLevelAssociationID?: number;
3491
+ periodCost?: number;
3492
+ periodPrice?: number;
3493
+ periodType?: number;
3494
+ purchaseOrderNumber?: string;
3495
+ status?: number;
3496
+ subscriptionName?: string;
3497
+ totalCost?: number;
3498
+ totalPrice?: number;
3499
+ vendorID?: number;
3500
+ /** UDF map (name → value) or UdfField[] — normalised to the vendor array on the wire. */
3501
+ userDefinedFields?: UdfField[];
3502
+ }
3503
+ /** Update input (same writable surface; id identifies the record in the path). */
3504
+ type SubscriptionUpdate = SubscriptionCreate;
3505
+ /** Compact helper shape for Subscription (resolve/search/getContext): structural alias of the
3506
+ * full record — the registry outputSchema names the fields the MCP projection keeps.
3507
+ */
3508
+ type SubscriptionSummary = Subscription;
3509
+
3309
3510
  /**
3310
3511
  * ContractTicketPurchases — API model types (G4 batch A).
3311
3512
  * GENERATED by scripts/generate-batch.mjs from api-docs.json (ContractTicketPurchaseModel). Do not hand-edit.
@@ -3517,85 +3718,6 @@ type ExpenseItemAttachmentUpdate = ExpenseItemAttachmentCreate;
3517
3718
  */
3518
3719
  type ExpenseItemAttachmentSummary = ExpenseItemAttachment;
3519
3720
 
3520
- /**
3521
- * ExpenseItem — API model types (G5 batch B).
3522
- * GENERATED by scripts/generate-batch.mjs from api-docs.json (ExpenseItemModel). Do not hand-edit.
3523
- * Field names keep the exact API casing; returned fields are optional (the vendor
3524
- * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
3525
- */
3526
-
3527
- /** ExpenseItem record as returned by the API (swagger ExpenseItemModel). */
3528
- interface ExpenseItem {
3529
- id: number;
3530
- companyID?: number;
3531
- description?: string;
3532
- destination?: string;
3533
- entertainmentLocation?: string;
3534
- expenseCategory?: number;
3535
- expenseCurrencyExpenseAmount?: number;
3536
- expenseCurrencyID?: number;
3537
- expenseDate?: string;
3538
- expenseReportID?: number;
3539
- glCode?: string;
3540
- haveReceipt?: boolean;
3541
- internalCurrencyExpenseAmount?: number;
3542
- internalCurrencyReimbursementAmount?: number;
3543
- isBillableToCompany?: boolean;
3544
- isReimbursable?: boolean;
3545
- isRejected?: boolean;
3546
- miles?: number;
3547
- odometerEnd?: number;
3548
- odometerStart?: number;
3549
- origin?: string;
3550
- paymentType?: number;
3551
- projectID?: number;
3552
- purchaseOrderNumber?: string;
3553
- reimbursementCurrencyReimbursementAmount?: number;
3554
- taskID?: number;
3555
- ticketID?: number;
3556
- workType?: number;
3557
- soapParentPropertyId?: unknown;
3558
- }
3559
- /** Create input for ExpenseItem (writable fields; accepts id or itemId). */
3560
- interface ExpenseItemCreate {
3561
- id?: number;
3562
- companyID?: number;
3563
- description?: string;
3564
- destination?: string;
3565
- entertainmentLocation?: string;
3566
- expenseCategory?: number;
3567
- expenseCurrencyExpenseAmount?: number;
3568
- expenseCurrencyID?: number;
3569
- expenseDate?: string;
3570
- expenseReportID?: number;
3571
- glCode?: string;
3572
- haveReceipt?: boolean;
3573
- internalCurrencyExpenseAmount?: number;
3574
- internalCurrencyReimbursementAmount?: number;
3575
- isBillableToCompany?: boolean;
3576
- isReimbursable?: boolean;
3577
- isRejected?: boolean;
3578
- miles?: number;
3579
- odometerEnd?: number;
3580
- odometerStart?: number;
3581
- origin?: string;
3582
- paymentType?: number;
3583
- projectID?: number;
3584
- purchaseOrderNumber?: string;
3585
- reimbursementCurrencyReimbursementAmount?: number;
3586
- taskID?: number;
3587
- ticketID?: number;
3588
- workType?: number;
3589
- /** UDF map (name → value) or UdfField[] — normalised to the vendor array on the wire. */
3590
- userDefinedFields?: UdfField[];
3591
- }
3592
- /** Update input (same writable surface; id identifies the record in the path). */
3593
- type ExpenseItemUpdate = ExpenseItemCreate;
3594
- /** Compact helper shape for ExpenseItem (resolve/search/getContext): structural alias of the
3595
- * full record — the registry outputSchema names the fields the MCP projection keeps.
3596
- */
3597
- type ExpenseItemSummary = ExpenseItem;
3598
-
3599
3721
  /**
3600
3722
  * ExpenseReport — API model types (G5 batch B).
3601
3723
  * GENERATED by scripts/generate-batch.mjs from api-docs.json (ExpenseReportModel). Do not hand-edit.
@@ -3794,71 +3916,6 @@ interface InventoryStockedItemTransfer {
3794
3916
  soapParentPropertyId?: unknown;
3795
3917
  }
3796
3918
 
3797
- /**
3798
- * Invoice — API model types (G4 batch A).
3799
- * GENERATED by scripts/generate-batch.mjs from api-docs.json (InvoiceModel). Do not hand-edit.
3800
- * Field names keep the exact API casing; returned fields are optional (the vendor
3801
- * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
3802
- */
3803
- /** Invoice record as returned by the API (swagger InvoiceModel). */
3804
- interface Invoice {
3805
- id: number;
3806
- batchID?: number;
3807
- comments?: string;
3808
- companyID?: number;
3809
- createDateTime?: string;
3810
- creatorResourceID?: number;
3811
- dueDate?: string;
3812
- fromDate?: string;
3813
- invoiceDateTime?: string;
3814
- invoiceEditorTemplateID?: number;
3815
- invoiceNumber?: string;
3816
- invoiceTotal?: number;
3817
- isVoided?: boolean;
3818
- orderNumber?: string;
3819
- paidDate?: string;
3820
- paymentTerm?: number;
3821
- taxGroup?: number;
3822
- taxRegionName?: string;
3823
- toDate?: string;
3824
- totalTaxValue?: number;
3825
- voidedByResourceID?: number;
3826
- voidedDate?: string;
3827
- webServiceDate?: string;
3828
- }
3829
- /** Create input for Invoice (writable fields; accepts id or itemId). */
3830
- interface InvoiceCreate {
3831
- id?: number;
3832
- batchID?: number;
3833
- comments?: string;
3834
- companyID?: number;
3835
- createDateTime?: string;
3836
- creatorResourceID?: number;
3837
- dueDate?: string;
3838
- fromDate?: string;
3839
- invoiceDateTime?: string;
3840
- invoiceEditorTemplateID?: number;
3841
- invoiceNumber?: string;
3842
- invoiceTotal?: number;
3843
- isVoided?: boolean;
3844
- orderNumber?: string;
3845
- paidDate?: string;
3846
- paymentTerm?: number;
3847
- taxGroup?: number;
3848
- taxRegionName?: string;
3849
- toDate?: string;
3850
- totalTaxValue?: number;
3851
- voidedByResourceID?: number;
3852
- voidedDate?: string;
3853
- webServiceDate?: string;
3854
- }
3855
- /** Update input (same writable surface; id identifies the record in the path). */
3856
- type InvoiceUpdate = InvoiceCreate;
3857
- /** Compact helper shape for Invoice (resolve/search/getContext): structural alias of the
3858
- * full record — the registry outputSchema names the fields the MCP projection keeps.
3859
- */
3860
- type InvoiceSummary = Invoice;
3861
-
3862
3919
  /**
3863
3920
  * modules integration endpoint — raw vendor model types (G5 batch B, plan key 'modules').
3864
3921
  * Hand-written thin integration surface (plan kind=integration): the model is
@@ -5387,63 +5444,6 @@ type SubscriptionPeriodUpdate = SubscriptionPeriodCreate;
5387
5444
  */
5388
5445
  type SubscriptionPeriodSummary = SubscriptionPeriod;
5389
5446
 
5390
- /**
5391
- * Subscription — API model types (G4 batch A).
5392
- * GENERATED by scripts/generate-batch.mjs from api-docs.json (SubscriptionModel). Do not hand-edit.
5393
- * Field names keep the exact API casing; returned fields are optional (the vendor
5394
- * answers partial records) except the always-present id. Cross-model refs degrade to unknown.
5395
- */
5396
-
5397
- /** Subscription record as returned by the API (swagger SubscriptionModel). */
5398
- interface Subscription {
5399
- id: number;
5400
- configurationItemID?: number;
5401
- description?: string;
5402
- effectiveDate?: string;
5403
- expirationDate?: string;
5404
- impersonatorCreatorResourceID?: number;
5405
- materialCodeID?: number;
5406
- organizationalLevelAssociationID?: number;
5407
- periodCost?: number;
5408
- periodPrice?: number;
5409
- periodType?: number;
5410
- purchaseOrderNumber?: string;
5411
- status?: number;
5412
- subscriptionName?: string;
5413
- totalCost?: number;
5414
- totalPrice?: number;
5415
- vendorID?: number;
5416
- userDefinedFields?: UdfField[];
5417
- }
5418
- /** Create input for Subscription (writable fields; accepts id or itemId). */
5419
- interface SubscriptionCreate {
5420
- id?: number;
5421
- configurationItemID?: number;
5422
- description?: string;
5423
- effectiveDate?: string;
5424
- expirationDate?: string;
5425
- impersonatorCreatorResourceID?: number;
5426
- materialCodeID?: number;
5427
- organizationalLevelAssociationID?: number;
5428
- periodCost?: number;
5429
- periodPrice?: number;
5430
- periodType?: number;
5431
- purchaseOrderNumber?: string;
5432
- status?: number;
5433
- subscriptionName?: string;
5434
- totalCost?: number;
5435
- totalPrice?: number;
5436
- vendorID?: number;
5437
- /** UDF map (name → value) or UdfField[] — normalised to the vendor array on the wire. */
5438
- userDefinedFields?: UdfField[];
5439
- }
5440
- /** Update input (same writable surface; id identifies the record in the path). */
5441
- type SubscriptionUpdate = SubscriptionCreate;
5442
- /** Compact helper shape for Subscription (resolve/search/getContext): structural alias of the
5443
- * full record — the registry outputSchema names the fields the MCP projection keeps.
5444
- */
5445
- type SubscriptionSummary = Subscription;
5446
-
5447
5447
  /**
5448
5448
  * SurveyResults — API model types (G5 batch B).
5449
5449
  * GENERATED by scripts/generate-batch.mjs from api-docs.json (SurveyResultsModel). Do not hand-edit.