@datarails-ai/dr-cli 0.0.1-locked → 1.6.71

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 (58) hide show
  1. package/README.md +608 -0
  2. package/dist/chunk-DWMCBGQH.js +242 -0
  3. package/dist/cli.js +64468 -0
  4. package/dist/kb-6UWI7Q32.js +21 -0
  5. package/dist/scopes-map.json +4412 -0
  6. package/dist/skills/connector-sandbox/SKILL.md +95 -0
  7. package/dist/skills/datarails-connect-workato/SKILL.md +140 -0
  8. package/dist/skills/datarails-connectors-onboard-connector/SKILL.md +813 -0
  9. package/dist/skills/dr-cli/SKILL.md +659 -0
  10. package/dist/skills/dr-cli/reference/admin.md +796 -0
  11. package/dist/skills/dr-cli/reference/budget-builder.md +151 -0
  12. package/dist/skills/dr-cli/reference/calc-vals.md +73 -0
  13. package/dist/skills/dr-cli/reference/calcmodels.md +76 -0
  14. package/dist/skills/dr-cli/reference/cash.md +61 -0
  15. package/dist/skills/dr-cli/reference/dashboards-widgets.md +85 -0
  16. package/dist/skills/dr-cli/reference/datamappers.md +150 -0
  17. package/dist/skills/dr-cli/reference/desk.md +472 -0
  18. package/dist/skills/dr-cli/reference/filebox-documents.md +373 -0
  19. package/dist/skills/dr-cli/reference/forecast.md +51 -0
  20. package/dist/skills/dr-cli/reference/integrations.md +57 -0
  21. package/dist/skills/dr-cli/reference/lookups.md +168 -0
  22. package/dist/skills/dr-cli/reference/metrics.md +512 -0
  23. package/dist/skills/dr-cli/reference/multi-product.md +180 -0
  24. package/dist/skills/dr-cli/reference/reconciliation-mec.md +76 -0
  25. package/dist/skills/dr-cli/reference/rh-config.md +84 -0
  26. package/dist/skills/dr-cli/reference/safety.md +143 -0
  27. package/dist/skills/dr-cli/reference/spend-control.md +206 -0
  28. package/dist/skills/dr-cli/reference/templates.md +163 -0
  29. package/dist/skills/dr-cli/reference/workflows.md +137 -0
  30. package/dist/skills/dr-error-enrichment/SKILL.md +80 -0
  31. package/dist/skills/dr-error-enrichment/reference/core.md +257 -0
  32. package/dist/skills/dr-error-enrichment/reference/groundcover.md +84 -0
  33. package/dist/skills/dr-error-enrichment/reference/jira-bugs.md +219 -0
  34. package/dist/skills/dr-error-enrichment/reference/safety-backup.md +122 -0
  35. package/dist/skills/dr-error-enrichment-author/SKILL.md +219 -0
  36. package/dist/skills/dr-error-enrichment-improve/SKILL.md +218 -0
  37. package/dist/skills/dr-error-enrichment-maintain/SKILL.md +237 -0
  38. package/dist/skills/dr-error-enrichment-reconcile/SKILL.md +167 -0
  39. package/dist/skills/dr-filebox-api-setup/SKILL.md +170 -0
  40. package/dist/skills/dr-switch-user/SKILL.md +395 -0
  41. package/dist/skills/dr-validate/SKILL.md +392 -0
  42. package/dist/skills/dr-validate/report-template.html +950 -0
  43. package/dist/skills/fx-conversion-matrix/SKILL.md +763 -0
  44. package/dist/skills/fx-conversion-matrix/scripts/_args.mjs +52 -0
  45. package/dist/skills/fx-conversion-matrix/scripts/_xlsx.mjs +241 -0
  46. package/dist/skills/fx-conversion-matrix/scripts/build-matrix.mjs +366 -0
  47. package/dist/skills/fx-conversion-matrix/scripts/gen-mappers.mjs +171 -0
  48. package/dist/skills/fx-conversion-matrix/scripts/rates-to-xlsx.mjs +172 -0
  49. package/dist/skills/fx-onboard/SKILL.md +325 -0
  50. package/dist/skills/mec-table-validation/SKILL.md +383 -0
  51. package/dist/skills/plugins.json +24 -0
  52. package/dist/skills/validate-workato-migration/SKILL.md +167 -0
  53. package/dist/skills/validate-workato-migration/reference/gotchas.md +16 -0
  54. package/dist/skills/validate-workato-migration/reference/staging-orgs.md +26 -0
  55. package/dist/skills/validate-workato-migration/scripts/compare_files.py +255 -0
  56. package/dist/zendeskKb-JPSHVOPH.js +243 -0
  57. package/package.json +56 -9
  58. package/scripts/postinstall.mjs +91 -0
@@ -0,0 +1,151 @@
1
+ # Budget Builder (Budget management templates)
2
+
3
+ Create/preview budget templates and manage their custom rows from the CLI.
4
+ A Budget Builder template is one report-definition JSON (the `tree_to_report`
5
+ envelope); every command here takes it via `--payload-file`.
6
+
7
+ Commands:
8
+
9
+ - `budget-builder build --payload-file <f>` — rebuild/preview (the call behind
10
+ every UI change). Flags: `--design compact|tabular|repetitive`,
11
+ `--legacy-design`, `--option k=v` (repeatable), `--timeframe-label`,
12
+ `--out-file`, `--json`.
13
+ - `budget-builder validate-row --payload-file <f> --name <s> --formula <s>
14
+ --position <row-name> [--format <s>] [--before]` — pre-check a custom-row
15
+ formula; surfaces the server's verdict reason on failure and prints a
16
+ warning for `hidden_dependency` (truncated-preview) verdicts.
17
+ `--position` is REQUIRED — the server rejects an empty anchor with
18
+ "Position does not exist in choices." (verified live); `build` prints the
19
+ valid anchor names.
20
+ - `budget-builder add-row` — validate, then merge the row and rebuild
21
+ (`--out-file` writes the updated definition for a later `save`).
22
+ - `budget-builder save --payload-file <f>` — persist to Budget management
23
+ (new template → `id: -1` in the payload).
24
+ - `documents split create|list|status|undo` — split a saved budget file into
25
+ per-dimension-value child files (see
26
+ [reference/filebox-documents.md](filebox-documents.md) for the documents
27
+ group generally). `create` and `undo` are two-step confirms.
28
+
29
+ ## Pre-flight questionnaire — ask BEFORE building a template
30
+
31
+ Values inherited from a scaffold report (actuals-ending date, fill mode,
32
+ design) are the #1 source of silently-wrong templates. Ask in one batch; items
33
+ with a stated default may proceed, but say aloud which default was applied.
34
+
35
+ 1. **Environment + tenant** — verify with `dr whoami --server <key>`, echo the
36
+ org back. Production requires explicit confirmation.
37
+ 2. **Template name** — and is it a keep-or-delete test artifact?
38
+ 3. **Budget year** → `budget_info.year` (string). The year of the budget
39
+ CONTEXT the user started from — identical to the file-system /
40
+ planning-cycle year (2027 cycle → `"2027"`). NOT derived from the calendar;
41
+ never default to the current year.
42
+ 4. **Budget cycle name** → `budget_info.cycle`. **NO DEFAULT — always ask.**
43
+ (API: key must be PRESENT and a non-null string; the value is the user's.)
44
+ 5. **Function** → `functions: [{id, name}]` + `template_id` (the function's
45
+ own template). Not mandatory — without an answer pick `Value` or another
46
+ relevant EXISTING function from `dr functions list`; never invent one;
47
+ state the pick.
48
+ 6. **Actuals ending** → `date_picker` (unix seconds, end of the last actuals
49
+ month). **BLOCKING — always ask; never silently apply a computed value.**
50
+ The auto-detect is the PROPOSAL inside the question, not the answer:
51
+ query the function's table for the latest month with Actuals data
52
+ (`dr templates aggregate` filtered to Scenario = Actuals, grouped by the
53
+ date field, take max), **clamp to before the current month** (running in
54
+ Jul-26 with Jul-26 data → propose Jun-26; the running month is still
55
+ open), then ask: "Actuals data runs through <max>; I propose actuals
56
+ ending <clamped>. Confirm or give another month." Only proceed on an
57
+ explicit confirmation or an explicit month.
58
+ 7. **Missing actuals filled from — Manual, Forecast, or Budget?**
59
+ → `budget_info.scenario` (`scenario_for_non_actuals_dates` server-side).
60
+ No safe default.
61
+ 8. **Column-section fields** → `cols[]` (+ column totals/subtotals).
62
+ 9. **Row-section fields + grouping order** → `rows[]`. OPEX default when
63
+ unspecified: **`Dept > Report field > Account`** — resolve each against
64
+ the function's template fields and confirm the exact names.
65
+ 10. **Scope filters** → `global_filters` / `referenceFields[].includes`.
66
+ OPEX default (unless asked otherwise): filter on **`Account Group L2`**
67
+ (the field differentiating OPEX / Income / etc.); list its values and
68
+ propose the in-scope ones.
69
+ 11. **Layout** (defaults ok, state them) — `options.design` (CLI default
70
+ repetitive), New design ON (`options.standardDesign: false` — INVERTED
71
+ name — AND `budget_info.new_design: true` — NOT inverted),
72
+ totals/subtotals/zero-suppression toggles.
73
+ 12. **Custom calculated rows** — each needs name (must be UNIQUE among
74
+ `calculatedRows` — the CLI refuses duplicates because the verdict map is
75
+ name-keyed), formula (bracket ROW-NAME refs like `[1000 Cash]`, never
76
+ period labels like `[Feb-26]`), a REQUIRED anchor (`--position
77
+ <row-name>` — `build` prints the valid anchor names), and `--before` vs
78
+ default after.
79
+ 13. **Split intent** — will the template be split per department afterwards?
80
+ If yes, confirm the split field + values now (`documents split`).
81
+ 14. **Scaffold review** — when building from an existing report's payload
82
+ (`dr reports get <id> --json`, definition under `.payload`), list every
83
+ inherited value the questionnaire covers and confirm each explicitly.
84
+
85
+ ## Workflow
86
+
87
+ ```
88
+ dr whoami --server <key>
89
+ dr functions list --server <key> # function id + template_id
90
+ dr templates list --server <key> # field names for rows/cols/filters
91
+ # (Q6 unanswered) auto-detect last actuals month; echo it back
92
+ dr reports get <scaffold-id> --server <key> --json # optional scaffold (.payload)
93
+ # edit payload per answers; id: -1, type: "budget"
94
+ dr budget-builder build --payload-file def.json --server <key> # must succeed first
95
+ dr budget-builder add-row … --out-file def.json # per custom row
96
+ dr budget-builder save --payload-file def.json --server <key>
97
+ dr reports get <new-id> --server <key> --json # round-trip check; echo settings
98
+ ```
99
+
100
+ ## Wire-shape gotchas (live-verified)
101
+
102
+ - `type: "budget"` requires `budget_info`:
103
+ `{year, scenario, cycle: <non-null string>, new_design: <bool>}`. Missing
104
+ `cycle` key → server `KeyError`; explicit `cycle: null` → `.title()` crash.
105
+ - `budget_info.scenario` wire values are lowercase: `budget` | `forecast` |
106
+ `manual` (the UI's "leave empty / manual" option = `manual`).
107
+ - Budget COLUMNS are auto-generated server-side from `budget_info` +
108
+ `date_picker` — leave `cols: []`; only rows are authored.
109
+ - Row HIERARCHY is encoded by nesting, NOT by flat array order: the child
110
+ field node goes in the parent node's `children: [...]` array (recursive).
111
+ Flat siblings in `rows[]` render as independent top-level row fields.
112
+ Top-level row nodes of a budget report also carry
113
+ `is_budget_output: <bool>` (false unless the "budget year data" toggle
114
+ applies to that field).
115
+ - A `global_filters` entry must carry BOTH a `fields` array and the values:
116
+ `{name, field: <id>, fields: [{id, name, template_id}], values: ["…"],
117
+ is_excluded: false, show_in_graph: false, override_global_filter: false}` —
118
+ the server reads `fields[0].id` AND each `fields[].template_id`
119
+ unconditionally (`field`-only shape crashes with `KeyError: 'fields'`).
120
+ Filter VALUES must match the table exactly — check with
121
+ `dr templates distinct <tid> --field "<name>"` (e.g. `Operating Expense`,
122
+ singular, not "operating expenses").
123
+ - Two new-design flags point OPPOSITE ways: `options.standardDesign: false` =
124
+ ON (inverted); `budget_info.new_design: true` = ON (not inverted).
125
+ - Custom rows must ALWAYS carry `positionValue` (a REAL anchor row name — the
126
+ server 500s with a KeyError when the key is missing and rejects `''` with
127
+ "Position does not exist in choices.") and `afterPositionValue` (boolean).
128
+ The CLI's required `--position` + `--before` handle this, and the CLI also
129
+ normalizes scaffold-payload rows that lack the keys so old files don't 500.
130
+ - Validation verdicts: `custom_value_validation.rows[<name>].status/reason`
131
+ (`ok` | `broken` | `hidden_dependency` — exhaustive at the source,
132
+ `custom_value_validation_service.py`). The CLI fails CLOSED: only
133
+ `ok`/`hidden_dependency` pass; `hidden_dependency` (truncated preview,
134
+ refs unverifiable) prints a warning; `broken`, an unknown status, or a
135
+ missing per-row entry all reject.
136
+ - Calculated-row conventions (match the tenant's own P&L rows): absolute
137
+ rows use format `''`/`'#,###'`; percentage rows use `'#,###%'`. A calc row
138
+ may anchor to ANOTHER calc row (e.g. Gross Margin `[Gross Profit]/[Revenue]`
139
+ positioned after Gross Profit). Chain multiple `add-row` calls by passing
140
+ the same file to `--payload-file` and `--out-file`.
141
+ - Revenue-model defaults (unless the user asks otherwise): scope
142
+ `Account Group L2 = Income` (ask whether `Other Income` and
143
+ `Cost of Goods Sold` are in scope); when COGS is included, offer
144
+ `Gross Profit = [<revenue group>]-[<COGS group>]` and
145
+ `Gross Margin = [Gross Profit]/[<revenue group>]` (`'#,###%'`) calc rows.
146
+ Formula refs target the top-level GROUP row names — `build` prints them
147
+ ("Row anchors for --position: …").
148
+ - Payload files may carry a UTF-8 BOM — `--payload-file` strips it (all
149
+ commands, since the PR that added this doc). On OLDER dr-cli versions a
150
+ BOM breaks parsing; there, write with `[IO.File]::WriteAllText` +
151
+ `UTF8Encoding($false)` instead of `Out-File -Encoding utf8`.
@@ -0,0 +1,73 @@
1
+ # Calculated Values (per-table)
2
+
3
+ Commands (alias `calcvals`): `calc-vals list --table <tid>`,
4
+ `calc-vals get <id> --table <tid>`,
5
+ `calc-vals create --table <tid> --name <n> --formula <f> [--format <mask>]`,
6
+ `calc-vals update <id> --table <tid> [--name|--formula|--format]`,
7
+ `calc-vals delete <id> --table <tid>`. `delete` is two-step confirm. `get` is a
8
+ client-side filter over `list` (there is no per-id GET).
9
+
10
+ These are the FE's **Setup → Tables → row kebab → "Calculated values"** — a
11
+ per-table (template) list of named formula values. They are **not**
12
+ `dr calcmodels`, **not** `dr functions`, **not** semantic-layer `dr metrics`,
13
+ and **not** datamapper calculated fields. Every subcommand is template-scoped,
14
+ so `--table <id>` is **required** on all of them (get the id from
15
+ `dr templates list`).
16
+
17
+ ## Endpoint surface
18
+
19
+ All under `/api/templates/<tid>/calc_vals` on the monolith. `update`/`delete`
20
+ append the calc-value id: `/api/templates/<tid>/calc_vals/<id>`. Read shape is
21
+ exactly four keys: `{id, name, formula, format}`.
22
+
23
+ ## Field semantics
24
+
25
+ - **formula** — bracketed, quoted `{source}.member` tokens joined by `+ - * /`,
26
+ e.g. `["{DR_CVS}.Gross"]` or `["{Category}.Revenue"]+["{Category}.COGS"]`.
27
+ Sources: `{DR_CVS}` (other calculated values) and dimension / account-group
28
+ fields (`{Category}`, `{Account Group L1}`, …). The server returns formulas
29
+ **HTML-entity-encoded** (`&quot;` for `"`); the CLI decodes on every read
30
+ (table + `--json`) and decodes write input too, so a `formula` you read back
31
+ pastes straight into `--formula`. Send raw double-quotes on write.
32
+ - **format** — a bare number-format **mask string** (e.g. `"####.##%"`), or
33
+ `null` when unset (it is NOT an object). On `update`, `--format ""` clears it.
34
+ - **field** — the write-only FE "From" picker selection; never echoed on read.
35
+ The BE treats it as picker metadata (it does not have to match the formula
36
+ source). The CLI handles it for you: `create` sends the safe default
37
+ `{name:"DR_CVS",label:"Calculated Values"}`; `update` (flag mode)
38
+ **omits it**, so a flag-only update never resets the source of a value created
39
+ in the FE. Set it explicitly only via `--file`.
40
+
41
+ ## Write semantics
42
+
43
+ - `create` / `update` have two modes: **flags** (`--name`/`--formula`/`--format`)
44
+ or **`--file <path>`** (a full JSON object body, POST/PUT verbatim). The two
45
+ are mutually exclusive.
46
+ - `update` is read-modify-write: it fetches the current value (filtering `list`),
47
+ splices the provided flags, and PUTs. `--file` update guards `body.id` against
48
+ the URL `<id>` to catch pointing the wrong file at the wrong id.
49
+ - `--file` rejects a non-object body (array/primitive) before any HTTP.
50
+ - `delete` uses the standard two-step confirm token (resource `calcval`); the FE
51
+ only has a click-confirm, but the CLI gates it because it runs on prod tenants.
52
+
53
+ ## Building from plain-English intent
54
+
55
+ The operator describes the value ("on the Financials table, a Gross Margin =
56
+ Revenue − COGS, shown as a 2-decimal percent"). You resolve the table name to a
57
+ `template_id` (`dr templates list`), express the formula in the bracketed-ref
58
+ syntax above, and run:
59
+
60
+ ```
61
+ dr calc-vals create --table <tid> --name "Gross Margin" \
62
+ --formula '["{Category}.Revenue"]-["{Category}.COGS"]' --format "####.##%" --server <S>
63
+ ```
64
+
65
+ For an account-group source, reference the dimension field by its FE label
66
+ (e.g. `{Account Group L1}`). For a rare explicit `field`, build a full body and
67
+ use `--file`.
68
+
69
+ ## Customer-facing docs (KB)
70
+
71
+ Help Center → table setup / "Calculated values". Find current articles with
72
+ `dr kb search "calculated values table"` (or browse `dr kb categories` /
73
+ `dr kb sections`). Cite the article; don't paraphrase from memory.
@@ -0,0 +1,76 @@
1
+ # Calc models
2
+
3
+ Commands (alias `calc-models`): `calcmodels list`, `calcmodels get <id>`,
4
+ `calcmodels create --file <p>`, `calcmodels update <id> --file <p>`,
5
+ `calcmodels set-flow <id> --flow Auto|Daily`, `calcmodels recalculate <id>`,
6
+ `calcmodels delete <id>`. `set-flow`, `recalculate`, and `delete` are two-step
7
+ confirm. `get` is a client-side filter over `list` (there is no per-id GET);
8
+ `update`/`delete` take the **calc-model id** in the path.
9
+
10
+ ## Types
11
+
12
+ Three types (schema is identical across them; only defaults differ):
13
+
14
+ - `BEGINNING_BALANCE_Y_TO_M`
15
+ - `BEGINNING_BALANCE_ONE_TO_M` — note `ONE_TO_M`, **not** `ONETIME_TO_M`
16
+ - `CUMULATIVE_TO_M`
17
+
18
+ Default `custom_columns[0].formula` is `"Beginning Balance"` for the two
19
+ beginning-balance types, `"Activity"` for cumulative (plus differing name /
20
+ description text).
21
+
22
+ ## Field semantics
23
+
24
+ - `status` — last-run state; observed `ACTIVE`, `PROCESSING` (loose-typed to
25
+ tolerate enum drift).
26
+ - `update_flow` — `AUTO` or `DAILY` only. There is no `MANUAL`; manual
27
+ recalculation is the separate `recalculate` action.
28
+ - **Self-loop guard:** when `destination_template_id == config.source_template_id`
29
+ (the model writes back into its own source — typical for Beginning-Balance-into-
30
+ Financials), `create`/`update` refuse `AUTO` client-side. Use `DAILY` for
31
+ self-loop models — `AUTO` triggers a recursive recalc that drives the model to
32
+ ERROR with duplicate rows.
33
+ - `description` — capped at 256 characters; the CLI refuses longer values.
34
+ - `data_model` — asymmetric on the wire: numeric org id on POST, slug string
35
+ (e.g. `"acme.com"`) on GET/PUT. The CLI passes whatever's on the wire.
36
+
37
+ ## Write semantics
38
+
39
+ - `update --file` PUTs the full body verbatim. The CLI guards `body.id` against
40
+ the URL `<id>` to catch pointing the wrong file at the wrong id.
41
+ - `set-flow` and `recalculate` fetch the current model, splice (or not), and PUT.
42
+ The server retriggers a recalc task on **every** PUT regardless of diff — there
43
+ is no force flag.
44
+ - There is no server-side optimistic concurrency (no `If-Match`/ETag). A
45
+ concurrent edit during the pause between plan and confirm is silently
46
+ overwritten when the PUT lands — coordinate with anyone else editing the same
47
+ model before confirming.
48
+
49
+ ## Building a `create` body from plain-English intent
50
+
51
+ The operator describes the model in plain English (type, source table, run
52
+ dates, filter values, group-by fields, custom output columns). You resolve all
53
+ names to integer IDs against the tenant — never ask the operator for IDs:
54
+
55
+ 1. `dr templates list --server <S>` → resolve the source table name to its
56
+ `template_id`.
57
+ 2. `dr templates get <template_id> --server <S>` → resolve every named field
58
+ (value field, date field, each filter field, each group-by field, each
59
+ custom-column target, plus the system slots `Calc Model ID`,
60
+ `Calc Model Name`, `Data Type`) to its integer field id.
61
+ 3. Construct the 6-key body in memory: `name`, `description`, `data_model`,
62
+ `type`, `destination_template_id`, `config`. The `config` sub-object carries
63
+ `source_template_id`, `date_field` (with `time_range = [unix_seconds, null]`),
64
+ `agg_field`, `data_type_field`, `calc_model_id_field`, `calc_model_name_field`,
65
+ `group_by[]`, `filters[]`, `custom_columns[]`.
66
+ 4. `dr whoami --server <S>` → derive the numeric `data_model` org id.
67
+ 5. Write the body to a tmpfile, then `dr calcmodels create --file <tmpfile> --server <S>`.
68
+
69
+ For `update`: `dr calcmodels get <id> --server <S> --json` → splice the requested
70
+ change → write to a tmpfile → `dr calcmodels update <id> --file <tmpfile> --server <S>`.
71
+
72
+ ## Customer-facing docs (KB)
73
+
74
+ Help Center → **"Getting Data into Datarails"** → Data Management. Find current articles with `dr kb search "calc model beginning balance"` (or
75
+ browse `dr kb categories` / `dr kb sections`). Cite the article; don't
76
+ paraphrase from memory.
@@ -0,0 +1,61 @@
1
+ # Cash module
2
+
3
+ Datarails Cash is its own FinanceOS application (cash management / liquidity), not
4
+ part of Planning.
5
+
6
+ Read:
7
+
8
+ - `cash currencies list [--detailed]` (server-supported codes),
9
+ `cash currencies prefs` (the org's saved currency list + default).
10
+ - `cash rules list <template_id|alias> [--archived]`,
11
+ `cash rules get <template_id|alias> <rule_id>`.
12
+ - `cash tags list <template_id|alias>` — distinct values in the template's
13
+ `dr_acc_l3` field. **Discovery only** — `output` on `cash rules create` is a
14
+ free-form string and is not constrained by this list. 404s on tenants where the
15
+ cash-category field is aliased differently (surfaced verbatim).
16
+
17
+ Write:
18
+
19
+ - `cash currencies set-prefs --currencies USD,EUR,…` (admin-only; uppercased +
20
+ deduped server-side).
21
+ - `cash transactions <template_id|alias>` — search; `--fields N,M` required;
22
+ `--page` / `--page-size` / `--manual-only` / `--search "text" --search-fields
23
+ f1,f2` / `--sort name:asc|desc` (repeatable) / `--filters-file <path>`;
24
+ `--alias bank_balances|bank_transactions` resolves the template.
25
+ - `cash rescan-rules <template_id|alias>` (surfaces a 409 "already running"
26
+ verbatim).
27
+ - `cash rules create <template_id|alias> --file <path>` — file is a single rule
28
+ object or an array (bulk); server auto-assigns `order` if omitted and rejects
29
+ duplicate condition-sets with 400. Each condition's `input_field` accepts the
30
+ field name **or** its alias. `output` is free-form.
31
+ - `cash rules update <template_id|alias> <rule_id> --file <path>` — PUT = full
32
+ replace; two-step (plan diffs current vs new).
33
+ - `cash rules delete <template_id|alias> <rule_id>` — two-step.
34
+ - `cash rules delete-all <template_id|alias> --all | --ids 1,2,3
35
+ [--include-archived] [--quiet]` — bulk delete under a single two-step;
36
+ continue-on-error with a `K of N failed` final throw.
37
+ - `cash rules import-csv <template_id|alias> --file <path>` — parses a
38
+ `Detailed Rule,Parameters,Category` CSV (inverse of `export-csv`).
39
+ - `cash rules reorder <template_id|alias>` — `--file {rules:[{id,order}]}` or
40
+ `--order 101:1,102:2,…` (mutually exclusive); atomic; two-step.
41
+ - `cash rules export-csv <template_id|alias> [-o <path>|-]` (`-o -` = stdout).
42
+ - `cash rules ai-trigger` — auto-discovers `bank_transactions` + `coa`;
43
+ support-user only + `cash_ai_rules` flag-gated; two-step.
44
+ - `cash set-default-currency <code>` (empty string clears).
45
+ - `cash hidden-rules upsert <template_id|alias> --file <path>` — array of
46
+ `{customer_transaction_id, conditions, output, …}`; upsert by
47
+ `customer_transaction_id`; two-step. There is no native list/get for hidden
48
+ rules.
49
+ - `cash hidden-rules delete <template_id|alias> --transactions <id1,id2,…>` —
50
+ two-step (server returns 204 even on misses).
51
+
52
+ **Rule condition schema:** `{input_field, operation, args, is_falsy?}`.
53
+ Operations: `EQ` (any), `GT`/`GTE`/`LT`/`LTE` (number), `RANGE` (`[n,n]`), `IN`
54
+ (array), `STARTSWITH`/`ENDSWITH`/`CONTAINS`/`REGEX`/`WILDCARD` (string).
55
+ `is_falsy: true` negates the match (default false).
56
+
57
+ ## Customer-facing docs (KB)
58
+
59
+ Help Center → **"Cash"** category. Find current articles with
60
+ `dr kb search "cash management rules"` (or browse `dr kb categories` /
61
+ `dr kb sections`). Cite the article; don't paraphrase from memory.
@@ -0,0 +1,85 @@
1
+ # Dashboards, widgets, storyboards, reports, extables
2
+
3
+ ## Dashboards
4
+
5
+ - `dashboards list`, `dashboards get`.
6
+ - `dashboards create`, `dashboards delete` (two-step confirm), `dashboards prepare`.
7
+ - `dashboards set-date-picker <id>` — five mutually-exclusive flag groups
8
+ mirroring the FE picker:
9
+ - `--mode <today|yesterday|this_month|prev_month>` (strict enum), or
10
+ - `--day YYYY-MM-DD` / `--month YYYY-MM` / `--quarter YYYY-Qn` / `--year YYYY`
11
+ (custom date flags compute a UTC end-of-period epoch).
12
+ - `--payload-file` is an escape hatch for `name`/`palette`/etc., with the
13
+ typed flags overlaid. No confirm token (non-destructive config). A 403
14
+ surfaces verbatim when the operator lacks `modify_dashboard`.
15
+
16
+ ### Push a dashboard to other organizations
17
+
18
+ `dashboards push <id> --to <orgs> [--override]` — two-step confirm.
19
+
20
+ 1. `organizations push-targets` lists the eligible destinations. `--to` takes
21
+ their ids or names, comma-separated or repeated (`--to 4412,4413`,
22
+ `--to "Acme Corp" --to 4413`), max 50 per run. A destination that isn't on
23
+ that list is rejected and **nothing** is pushed.
24
+ - An all-digit token is only ever matched against ids, so an organization
25
+ *named* e.g. `2024` must be addressed by its id. Same for a name
26
+ containing a comma — `--to` splits on commas before matching.
27
+ 2. Run the command without `--confirm-token` to see the plan (source name,
28
+ resolved destinations as `name (id)`, mode), then re-run with the token.
29
+
30
+ `--override` reuses the dashboard a previous push created in each destination,
31
+ **discarding its widgets and filters** before re-cloning. Without it a new
32
+ dashboard is added, with `' Copy'` appended if the name is taken.
33
+
34
+ The push is queued and returns no job id — results arrive as in-app
35
+ notifications. Confirm with `dashboards list --account <destination>`.
36
+
37
+ ## Widgets
38
+
39
+ - `widgets list`, `widgets get <id>`, `widgets data <id>` (alias `widget`).
40
+ - `widgets data` applies the dashboard's saved filter bar and global date
41
+ picker **by default** (one extra `GET /api/dashboards/<id>`), so its answer
42
+ matches what the product renders — including widgets configured relative to
43
+ the dashboard's date picker (e.g. "last 12 months as of the dashboard
44
+ date"). Presets (`today`/`yesterday`/`this_month`/`prev_month`) resolve to
45
+ end-of-period UTC epochs; saved filters without values are skipped. Human
46
+ output prints the applied context (`dashboard context: N filters, reference
47
+ date …`); `--json` stays the verbatim server body. Pass
48
+ `--no-dashboard-context` for the widget-only computation. Per-user saved
49
+ views (view-scoped filter/sort/aggregation
50
+ overrides) are not applied — parity is with the dashboard's saved state,
51
+ same as scheduled report emails.
52
+ - `widgets create --file` (power mode), `widgets update <id> --file`,
53
+ `widgets delete <id>` (two-step confirm).
54
+ - Flag-driven builders:
55
+ - `widgets chart --type column|bar|line|area` + modifiers `--stacked`
56
+ `--percent` `--smooth`.
57
+ - `widgets kpi` — single tile.
58
+ - `widgets pie` — optional `--drilldown`.
59
+ - `widgets table` — pivot.
60
+ - `widgets text` — rich-text section header.
61
+ - `widgets gauge --type enhanced|dynamic-goal` — enhanced = single value vs
62
+ target; dynamic-goal splits the goal by one `--time-by` field.
63
+ - `widgets waterfall --type breakdown|walkthrough` — breakdown needs one
64
+ `--group-by` row dim and one `--time-by` col dim; walkthrough is cols-only.
65
+ - `widgets published-item` — a stub that throws on invocation; use
66
+ `widgets create --file` with `chart_type: "published_item"` to reference a
67
+ published item.
68
+ - **Chart `--type`** accepts either a composite literal
69
+ (`column-stacked-percent`) **or** flags (`--type column --stacked --percent`)
70
+ — pick one form.
71
+
72
+ ## Storyboards / reports / extables
73
+
74
+ - `storyboards list|get|slides`; `storyboards prepare`, `storyboards delete`
75
+ (two-step confirm).
76
+ - `reports list|get`; `reports clone`, `reports delete` (two-step confirm).
77
+ - `extables list|get`; `extables clone`, `extables delete` (two-step confirm).
78
+ To inject an ExTable's data into a raw `.xlsx`, that's `documents add-extables`
79
+ (see reference/filebox-documents.md), **not** an `extables` subcommand.
80
+
81
+ ## Customer-facing docs (KB)
82
+
83
+ Help Center → the **"Reports & Analysis"** category (Report Builder / Dashboards / Storyboards). Find current articles with `dr kb search "dashboard widget report"` (or
84
+ browse `dr kb categories` / `dr kb sections`). Cite the article; don't
85
+ paraphrase from memory.
@@ -0,0 +1,150 @@
1
+ # Datamappers + mapper recipes
2
+
3
+ ## Read
4
+
5
+ - `datamappers list`, `datamappers get <id>`.
6
+ - `datamappers list --table <id> --full --json` — adds each mapper's compiled
7
+ `mapping_rules` (the SSDL JSON the ETL engine actually runs; `config` is only
8
+ the UI definition it was built from). HTML entities are decoded, so
9
+ `mapping_rules` is directly JSON-parseable. The server leaves out mappers
10
+ whose source filebox is archived.
11
+ - `datamappers custom-functions` — the authoritative formula-language function
12
+ list (names + signatures + descriptions). Copy from here when authoring
13
+ calc-field formulas.
14
+ - `datamappers processed-versions <mapper_id>` — which doc-versions the mapper
15
+ has extracted.
16
+ - `datamappers connected-fileboxes <mapper_id>` — filebox metadata for the docs
17
+ the mapper covers.
18
+
19
+ ## Create — type required up-front
20
+
21
+ Ask the operator "Flat table, Dimension table, or Multiple tables?" then pick
22
+ the matching subcommand. `datamappers create <flat|dimension|multiple|from-file>
23
+ <table_id>`:
24
+
25
+ - `flat` requires `--name --doc-version --sheet`. Use `--doc-version`, **not**
26
+ `--version` — `--version` is reserved by the global `dr --version` and silently
27
+ no-ops the subcommand.
28
+ - `dimension` adds required `--dim Coord=Label` (≥1).
29
+ - `multiple` adds required `--dim` and `--table-id-cell Coord=Label` (≥1).
30
+ - `from-file --file <path>` is the power mode — it ships the JSON body without
31
+ the convenience-flag validation, but **not** strictly verbatim. Three things
32
+ still rewrite it: `--rescan`/`--no-rescan` set or strip `rescan`; a source
33
+ `template_id` in the body is resolved to `fields_to_change` and then removed
34
+ (see below); and repeatable `--field NAME:TYPE` upserts `fields_to_change`.
35
+ Required body fields: `name`, `document_version_id`, `selected_document_ids`
36
+ (GET returns this renamed as `mapped_documents_ids`), `config`, `sheet_name`.
37
+
38
+ **Schema-bootstrap shortcut:** mapping `map_to: "<field>"` to a column the target
39
+ template doesn't have yet auto-adds that field on the table (plus 4 system
40
+ scenario fields on the first mapper). This is the documented way to declare
41
+ fields on a freshly-created template — there is no separate "add field" API.
42
+
43
+ **Bootstrapped field types are value-inferred, not copied (DR-51801).** When
44
+ the body carries no explicit type, the server infers each new field's type from
45
+ the sample values (`Tables/models.py update_mapper` → `ssdl_infer_field_types`).
46
+ A small/loose sample often yields `Text` (occasionally `Integer`). The inference
47
+ does **not** consult a sibling table's field of the same name, so duplicating a
48
+ mapper onto a sibling table would **not** carry the source types — field type
49
+ lives on the template field, never in the mapper `config`, so a byte-identical
50
+ `config` cannot transmit it.
51
+
52
+ **Automatic type resolution when duplicating a mapper (DR-51801).**
53
+ `datamappers get --json` injects the source `template_id` into its output (the
54
+ mapper API omits it — DR-51821). When a `from-file` body carries a `template_id`,
55
+ `create from-file` reads it as the **source** template, looks up every `map_to`
56
+ target's type on that template's fields, and sends them as `fields_to_change` —
57
+ so a mapper learned via `get` and re-created on a sibling table keeps its types
58
+ with no manual step. The source `template_id` is consumed by the CLI and stripped
59
+ before POST (the target template is the positional arg). If **any** `map_to`
60
+ target has no field of that name on the source template, the command **fails**
61
+ rather than let the server silently mis-infer it. Override or supplement the
62
+ resolved types with `--field NAME:TYPE` (`Text|Float|Date|Integer`, repeatable),
63
+ which wins over the auto-resolved value; a `template_id`-free body keeps the old
64
+ value-inference behavior. `NAME` is the target **table field** name (the
65
+ `map_to`), not the source column header.
66
+
67
+ ## Update / preview / bind / delete
68
+
69
+ - `datamappers update`, `datamappers delete` (two-step confirm).
70
+ - `datamappers preview --payload-file <p>` — renders mapper output for sample
71
+ input ("what would this extract?") before saving.
72
+ - `datamappers bind <mapper_id> --doc <id> [--rescan latest|all]` — change which
73
+ docs a mapper is bound to.
74
+
75
+ ### `update --field NAME:TYPE` — set column types (materialising calc columns)
76
+
77
+ `datamappers update <id> --payload-file <p> [--field NAME:TYPE ...]`. Repeatable;
78
+ `TYPE` is `Text|Float|Date|Integer`. Each `--field` becomes a `fields_to_change`
79
+ entry on the PUT body, telling the server to set that column's type **explicitly**
80
+ instead of inferring it — this is exactly what the web UI's "Publish and scan"
81
+ does (same `PUT api/templates/mappers/<id>` endpoint; the only payload difference
82
+ is `fields_to_change`).
83
+
84
+ **When you need it:** adding a calc column that multiplies/divides by a
85
+ **LUT-injected column**. LUT columns land as **Text**; the server infers Text for
86
+ them, so a formula like `[Posting Amount] * [Sign]` fails to materialise and the
87
+ PUT returns a bare `HTTP 500` (`ETLError: … incorrect formula syntax`) — even
88
+ though the formula is valid. Fixing the LUT column's type up-front lets it
89
+ materialise:
90
+
91
+ ```
92
+ dr datamappers update 496476 --payload-file body.json \
93
+ --field DR_ACCT_Sign_FPA:Integer --rescan all
94
+ ```
95
+
96
+ Merge semantics: `--field` upserts by name into any `fields_to_change` already in
97
+ the payload (type replaced, the entry's other keys preserved); a new name appends
98
+ a minimal `{name, type}`. The server applies only the keys present, so unrelated
99
+ field attributes are left untouched (it does default `is_hidden`→false and
100
+ `ignore_hours`→true for the changed field).
101
+
102
+ **Caveat:** the server **rejects the type change with HTTP 400** when the template
103
+ has more than one mapper ("Changing the type field … might break some widgets").
104
+ Single-mapper templates (the common onboarding case) are fine.
105
+
106
+ ## Calc-field formulas
107
+
108
+ `create`/`update` run a client-side guard on `config.calculated_fields[].formula`
109
+ before any HTTP call. It catches the obvious cases — empty/whitespace, bare
110
+ unquoted English text, single `=` instead of `==`, unbalanced `[]`/`()`/`"`, and
111
+ the `EOMONTH` arity foot-gun (Datarails `EOMONTH` is single-arg; Excel's 2-arg
112
+ form fails). It does **not** catch every server-side failure: a syntactically
113
+ valid formula the ETL compiler can't resolve (unknown/wrong-cased function,
114
+ unresolvable `[field]` reference, a string-constant that happens to be quoted)
115
+ still returns a bare 500.
116
+
117
+ After `create`, the CLI polls the template's `fields[]` for up to 30s for every
118
+ declared calc field to materialise, and warns (pointing at `mapper-recipes get`
119
+ for working formulas) if any are missing — this catches the EOMONTH failure
120
+ mode. Skipped when `--no-rescan` is set.
121
+
122
+ On a PUT 500, the CLI writes a `dr-cli-error-<timestamp>.md` to the cwd capturing
123
+ URL + status + request/response bodies; the path is named in the stderr error.
124
+
125
+ Formula syntax:
126
+
127
+ - Equality is `==` (single `=` is rejected).
128
+ - String literals use double quotes (`"Actuals"`). `&quot;`-encoded quotes
129
+ round-trip too — the CLI auto-decodes HTML entities (`&quot; &amp; &lt; &gt;`)
130
+ in the body before send — but raw `"` is preferred.
131
+ - Function names are case-tolerant (`IF`/`If`/`if`); when unsure, copy from
132
+ `datamappers get` output.
133
+ - `[bracketed]` field references must resolve to a header `map_to`, another
134
+ calc-field `name`, or a system field (`[FileBox_ID]`, `[System_Year]`,
135
+ `[System_Date_Tag_Label]`, `[Posting Date]`, …).
136
+
137
+ ## Mapper recipes
138
+
139
+ - `mapper-recipes list`, `mapper-recipes get <id>` — a library of known-good
140
+ mapper configs; `get` is a good source of working formulas.
141
+ - `mapper-recipes save --name <n> --from-version <id> --config-file <p>
142
+ --fields-file <p> [--description <s>]` — the CLI takes plain JSON files and
143
+ stringifies `config` / `fields_to_change` on the way out (the server stores
144
+ them as JSON strings).
145
+
146
+ ## Customer-facing docs (KB)
147
+
148
+ Help Center → **"Getting Data into Datarails"** → Data Mapper. Find current articles with `dr kb search "data mapper"` (or
149
+ browse `dr kb categories` / `dr kb sections`). Cite the article; don't
150
+ paraphrase from memory.