acumatica-cli 0.15.0__tar.gz → 0.15.2__tar.gz

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 (97) hide show
  1. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/PKG-INFO +31 -12
  2. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/README.md +30 -11
  3. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/pyproject.toml +1 -1
  4. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/extract.py +9 -0
  5. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +7 -0
  6. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/baseline/20-accounts.yaml +0 -18
  7. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +6 -0
  8. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +6 -0
  9. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +6 -0
  10. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/baseline/90-uoms.yaml +0 -5
  11. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/company.yaml +9 -0
  12. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +11 -0
  13. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/features.yaml +10 -0
  14. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +34 -0
  15. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +15 -0
  16. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +6 -0
  17. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/40-posting-classes.yaml +0 -12
  18. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/50-warehouse.yaml +8 -0
  19. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +18 -0
  20. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +8 -0
  21. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +5 -0
  22. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/54-item-classes.yaml +23 -0
  23. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +8 -0
  24. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +7 -0
  25. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/58-order-types.yaml +8 -0
  26. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +5 -0
  27. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +5 -0
  28. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +7 -0
  29. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/63-cash-account.yaml +10 -0
  30. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +17 -0
  31. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +11 -0
  32. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +24 -0
  33. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +14 -0
  34. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/75-vendors.yaml +0 -16
  35. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/76-customers.yaml +0 -9
  36. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/80-stock-items-parts.yaml +0 -18
  37. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +24 -0
  38. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/85-kit-specifications.yaml +0 -14
  39. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +8 -0
  40. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +11 -0
  41. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +11 -0
  42. acumatica_cli-0.15.2/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +15 -0
  43. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/10-seed-capital.yaml +0 -5
  44. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/20-buy.yaml +0 -32
  45. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/30-build.yaml +0 -20
  46. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/40-sell.yaml +0 -12
  47. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +0 -15
  48. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +0 -15
  49. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +0 -18
  50. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +0 -27
  51. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/company.yaml +0 -15
  52. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +0 -17
  53. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/features.yaml +0 -26
  54. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +0 -49
  55. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +0 -34
  56. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +0 -16
  57. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/50-warehouse.yaml +0 -23
  58. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +0 -28
  59. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +0 -13
  60. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +0 -14
  61. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/54-item-classes.yaml +0 -43
  62. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +0 -21
  63. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +0 -21
  64. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/58-order-types.yaml +0 -21
  65. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +0 -15
  66. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +0 -14
  67. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +0 -18
  68. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/63-cash-account.yaml +0 -23
  69. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +0 -27
  70. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +0 -23
  71. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +0 -38
  72. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +0 -28
  73. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +0 -40
  74. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +0 -27
  75. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +0 -28
  76. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +0 -33
  77. acumatica_cli-0.15.0/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +0 -20
  78. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/__init__.py +0 -0
  79. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap.py +0 -0
  80. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap_plugin.cs +0 -0
  81. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap_project.xml +0 -0
  82. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/cli.py +0 -0
  83. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/client.py +0 -0
  84. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/config.py +0 -0
  85. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/firstlogin.py +0 -0
  86. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/models.py +0 -0
  87. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/output.py +0 -0
  88. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/run.py +0 -0
  89. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/seed.py +0 -0
  90. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/seed_catalog.yaml +0 -0
  91. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/state.py +0 -0
  92. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/target.py +0 -0
  93. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/README.md +0 -0
  94. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/env +0 -0
  95. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/gitignore +0 -0
  96. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/target +0 -0
  97. {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/tenant.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acumatica-cli
3
- Version: 0.15.0
3
+ Version: 0.15.2
4
4
  Summary: Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data
5
5
  Author: Konstantin Borovik
6
6
  Author-email: Konstantin Borovik <kb@lab5.ca>
@@ -108,7 +108,8 @@ Run `acu <command> --help` for details on any command.
108
108
  ## The data repo
109
109
 
110
110
  Your configuration lives in its own git repo.
111
- `acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README. There is no `--flavor`.
111
+ `acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README.
112
+ There is no `--flavor`.
112
113
 
113
114
  | Path | What it holds |
114
115
  | ---- | ------------- |
@@ -129,7 +130,10 @@ The scaffolded `.gitignore` keeps `.env` out of git — store it encrypted (for
129
130
  Commit `target.yaml` with the seeds so every clone knows the verified ERP line and Default API generation.
130
131
 
131
132
  Seed YAML is state: `apply` upserts it, `diff` proves it.
132
- `acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut). Packaged `seed_catalog.yaml` is the sole extract registry (entity, endpoint, keys, file, strip/include, filter-split); the demo entity map in [docs/demo-seed.md](docs/demo-seed.md) mirrors those catalog paths. Features synthesize to `config/bootstrap/features.yaml`. Existing files skip unless `--force`; empty live sets skip; row failures continue (exit 1 only if any row failed — drift stays with `diff`).
133
+ `acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut).
134
+ Packaged `seed_catalog.yaml` is the sole extract registry (entity, endpoint, keys, file, strip/include, filter-split); the demo entity map in [docs/demo-seed.md](docs/demo-seed.md) mirrors those catalog paths.
135
+ Features synthesize to `config/bootstrap/features.yaml`.
136
+ Existing files skip unless `--force`; empty live sets skip; row failures continue (exit 1 only if any row failed — drift stays with `diff`).
133
137
 
134
138
  ```sh
135
139
  acu --tenant DEV extract --out . --force # refresh config/** from live tenant
@@ -138,15 +142,24 @@ acu --tenant DEV apply config/ # replay extracted seed
138
142
  acu --tenant DEV diff config/ # expect exit 0
139
143
  ```
140
144
 
141
- **Migration (T115–T120 extract hard-cut):** extract no longer writes root `bootstrap/` / `baseline/` / `setup/` / `master/`. Paths are always `config/…`. There is no `--layout`. Move any root-layout extract output under `config/`, or re-extract into a modern data repo. Catalog rename: `extract_manifest.yaml` becomes `seed_catalog.yaml` (package data only; operators do not author it).
145
+ **Migration (T115–T120 extract hard-cut):** extract no longer writes root `bootstrap/` / `baseline/` / `setup/` / `master/`.
146
+ Paths are always `config/…`.
147
+ There is no `--layout`.
148
+ Move any root-layout extract output under `config/`, or re-extract into a modern data repo.
149
+ Catalog rename: `extract_manifest.yaml` becomes `seed_catalog.yaml` (package data only; operators do not author it).
142
150
 
143
151
  Scenario YAML is different — it describes transactions that flow forward (not extractable seed).
144
152
  `acu run` executes each step in order (`put`, `action`, `wait`, `get`), captures server-assigned document numbers into `${var}` references for later steps, and checks `expect:` assertions as deltas against a pre-run snapshot, so additive scenarios re-run safely on a warm tenant.
145
153
  `once: true` scenarios declare a `present` inquire-absolute gate; when the probe already holds, the CLI prints `skip <path> (once: already present)` and runs neither steps nor expects (Owner Capital does not restack).
146
154
 
147
- `acu state` is the third observation path: it captures live derived state (balances) into `state/` for git review. It is not `extract` (config seed) and not `diff` (desired vs actual config). Packaged golden is trial-balance via contract `inquire:` (`EndingBalance` fixed-point); inventory-summary is not golden this pass. `gi:` stays optional when a GI is V12-verified and **Expose via OData** is on (`params` fail-closed vs `$metadata`). After a cold `acu run scenario/ && acu state`, warm `acu run scenario/10-seed-capital.yaml && acu state --assert-unchanged` is the once-class gate (full scenario re-run is additive and moves cash observations on the TB).
155
+ `acu state` is the third observation path: it captures live derived state (balances) into `state/` for git review.
156
+ It is not `extract` (config seed) and not `diff` (desired vs actual config).
157
+ Packaged golden is trial-balance via contract `inquire:` (`EndingBalance` fixed-point); inventory-summary is not golden this pass. `gi:` stays optional when a GI is V12-verified and **Expose via OData** is on (`params` fail-closed vs `$metadata`).
158
+ After a cold `acu run scenario/ && acu state`, warm `acu run scenario/10-seed-capital.yaml && acu state --assert-unchanged` is the once-class gate (full scenario re-run is additive and moves cash observations on the TB).
148
159
 
149
- **Migration (T112–T114 hard-cut):** CLI verb is `state` only (no `snapshot` alias). Bare defaults are `config/views/` (views) and `state/` (observations). Prior `config/snapshot/` and root `snapshot/` / `snapshots/` are not fallbacks — move views to `config/views/` or pass explicit path args.
160
+ **Migration (T112–T114 hard-cut):** CLI verb is `state` only (no `snapshot` alias).
161
+ Bare defaults are `config/views/` (views) and `state/` (observations).
162
+ Prior `config/snapshot/` and root `snapshot/` / `snapshots/` are not fallbacks — move views to `config/views/` or pass explicit path args.
150
163
 
151
164
  ### Seed `endpoint:` symbols
152
165
 
@@ -169,7 +182,8 @@ Requires Python 3.14 or newer.
169
182
  uv tool install acumatica-cli
170
183
  ```
171
184
 
172
- `pipx install acumatica-cli` and `pip install acumatica-cli` work too. For the latest development version straight from the main branch:
185
+ `pipx install acumatica-cli` and `pip install acumatica-cli` work too.
186
+ For the latest development version straight from the main branch:
173
187
 
174
188
  ```sh
175
189
  uv tool install git+https://github.com/kborovik/acumatica-cli.git
@@ -237,10 +251,13 @@ On a hosted instance, publish AcuBootstrap with `acu bootstrap`, then seed with
237
251
 
238
252
  ## SSH setup (control plane)
239
253
 
240
- `acu tenant` runs commands on the Windows guest through plain `ssh`. Two things about this setup are not obvious, and both are hard requirements.
254
+ `acu tenant` runs commands on the Windows guest through plain `ssh`.
255
+ Two things about this setup are not obvious, and both are hard requirements.
241
256
 
242
- **1. The default SSH shell on the Windows guest must be PowerShell.**
243
- `acu` sends PowerShell syntax over the wire, and every one of those commands fails under `cmd.exe`, the Windows OpenSSH default. Switch it once, in an elevated PowerShell on the guest:
257
+ **1.
258
+ The default SSH shell on the Windows guest must be PowerShell.**
259
+ `acu` sends PowerShell syntax over the wire, and every one of those commands fails under `cmd.exe`, the Windows OpenSSH default.
260
+ Switch it once, in an elevated PowerShell on the guest:
244
261
 
245
262
  ```powershell
246
263
  New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
@@ -248,9 +265,11 @@ New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
248
265
  -PropertyType String -Force
249
266
  ```
250
267
 
251
- **2. Authentication must be key-based and non-interactive.**
268
+ **2.
269
+ Authentication must be key-based and non-interactive.**
252
270
  `acu` connects with `BatchMode=yes`, so it will never answer a password prompt.
253
- Because the default user is `Administrator` (an administrators-group member), Windows OpenSSH reads the key from the *machine-wide* file `C:\ProgramData\ssh\administrators_authorized_keys` — **not** from `~\.ssh\authorized_keys` like on Linux. On the guest:
271
+ Because the default user is `Administrator` (an administrators-group member), Windows OpenSSH reads the key from the *machine-wide* file `C:\ProgramData\ssh\administrators_authorized_keys` — **not** from `~\.ssh\authorized_keys` like on Linux.
272
+ On the guest:
254
273
 
255
274
  Install + start the server (once):
256
275
 
@@ -90,7 +90,8 @@ Run `acu <command> --help` for details on any command.
90
90
  ## The data repo
91
91
 
92
92
  Your configuration lives in its own git repo.
93
- `acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README. There is no `--flavor`.
93
+ `acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README.
94
+ There is no `--flavor`.
94
95
 
95
96
  | Path | What it holds |
96
97
  | ---- | ------------- |
@@ -111,7 +112,10 @@ The scaffolded `.gitignore` keeps `.env` out of git — store it encrypted (for
111
112
  Commit `target.yaml` with the seeds so every clone knows the verified ERP line and Default API generation.
112
113
 
113
114
  Seed YAML is state: `apply` upserts it, `diff` proves it.
114
- `acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut). Packaged `seed_catalog.yaml` is the sole extract registry (entity, endpoint, keys, file, strip/include, filter-split); the demo entity map in [docs/demo-seed.md](docs/demo-seed.md) mirrors those catalog paths. Features synthesize to `config/bootstrap/features.yaml`. Existing files skip unless `--force`; empty live sets skip; row failures continue (exit 1 only if any row failed — drift stays with `diff`).
115
+ `acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut).
116
+ Packaged `seed_catalog.yaml` is the sole extract registry (entity, endpoint, keys, file, strip/include, filter-split); the demo entity map in [docs/demo-seed.md](docs/demo-seed.md) mirrors those catalog paths.
117
+ Features synthesize to `config/bootstrap/features.yaml`.
118
+ Existing files skip unless `--force`; empty live sets skip; row failures continue (exit 1 only if any row failed — drift stays with `diff`).
115
119
 
116
120
  ```sh
117
121
  acu --tenant DEV extract --out . --force # refresh config/** from live tenant
@@ -120,15 +124,24 @@ acu --tenant DEV apply config/ # replay extracted seed
120
124
  acu --tenant DEV diff config/ # expect exit 0
121
125
  ```
122
126
 
123
- **Migration (T115–T120 extract hard-cut):** extract no longer writes root `bootstrap/` / `baseline/` / `setup/` / `master/`. Paths are always `config/…`. There is no `--layout`. Move any root-layout extract output under `config/`, or re-extract into a modern data repo. Catalog rename: `extract_manifest.yaml` becomes `seed_catalog.yaml` (package data only; operators do not author it).
127
+ **Migration (T115–T120 extract hard-cut):** extract no longer writes root `bootstrap/` / `baseline/` / `setup/` / `master/`.
128
+ Paths are always `config/…`.
129
+ There is no `--layout`.
130
+ Move any root-layout extract output under `config/`, or re-extract into a modern data repo.
131
+ Catalog rename: `extract_manifest.yaml` becomes `seed_catalog.yaml` (package data only; operators do not author it).
124
132
 
125
133
  Scenario YAML is different — it describes transactions that flow forward (not extractable seed).
126
134
  `acu run` executes each step in order (`put`, `action`, `wait`, `get`), captures server-assigned document numbers into `${var}` references for later steps, and checks `expect:` assertions as deltas against a pre-run snapshot, so additive scenarios re-run safely on a warm tenant.
127
135
  `once: true` scenarios declare a `present` inquire-absolute gate; when the probe already holds, the CLI prints `skip <path> (once: already present)` and runs neither steps nor expects (Owner Capital does not restack).
128
136
 
129
- `acu state` is the third observation path: it captures live derived state (balances) into `state/` for git review. It is not `extract` (config seed) and not `diff` (desired vs actual config). Packaged golden is trial-balance via contract `inquire:` (`EndingBalance` fixed-point); inventory-summary is not golden this pass. `gi:` stays optional when a GI is V12-verified and **Expose via OData** is on (`params` fail-closed vs `$metadata`). After a cold `acu run scenario/ && acu state`, warm `acu run scenario/10-seed-capital.yaml && acu state --assert-unchanged` is the once-class gate (full scenario re-run is additive and moves cash observations on the TB).
137
+ `acu state` is the third observation path: it captures live derived state (balances) into `state/` for git review.
138
+ It is not `extract` (config seed) and not `diff` (desired vs actual config).
139
+ Packaged golden is trial-balance via contract `inquire:` (`EndingBalance` fixed-point); inventory-summary is not golden this pass. `gi:` stays optional when a GI is V12-verified and **Expose via OData** is on (`params` fail-closed vs `$metadata`).
140
+ After a cold `acu run scenario/ && acu state`, warm `acu run scenario/10-seed-capital.yaml && acu state --assert-unchanged` is the once-class gate (full scenario re-run is additive and moves cash observations on the TB).
130
141
 
131
- **Migration (T112–T114 hard-cut):** CLI verb is `state` only (no `snapshot` alias). Bare defaults are `config/views/` (views) and `state/` (observations). Prior `config/snapshot/` and root `snapshot/` / `snapshots/` are not fallbacks — move views to `config/views/` or pass explicit path args.
142
+ **Migration (T112–T114 hard-cut):** CLI verb is `state` only (no `snapshot` alias).
143
+ Bare defaults are `config/views/` (views) and `state/` (observations).
144
+ Prior `config/snapshot/` and root `snapshot/` / `snapshots/` are not fallbacks — move views to `config/views/` or pass explicit path args.
132
145
 
133
146
  ### Seed `endpoint:` symbols
134
147
 
@@ -151,7 +164,8 @@ Requires Python 3.14 or newer.
151
164
  uv tool install acumatica-cli
152
165
  ```
153
166
 
154
- `pipx install acumatica-cli` and `pip install acumatica-cli` work too. For the latest development version straight from the main branch:
167
+ `pipx install acumatica-cli` and `pip install acumatica-cli` work too.
168
+ For the latest development version straight from the main branch:
155
169
 
156
170
  ```sh
157
171
  uv tool install git+https://github.com/kborovik/acumatica-cli.git
@@ -219,10 +233,13 @@ On a hosted instance, publish AcuBootstrap with `acu bootstrap`, then seed with
219
233
 
220
234
  ## SSH setup (control plane)
221
235
 
222
- `acu tenant` runs commands on the Windows guest through plain `ssh`. Two things about this setup are not obvious, and both are hard requirements.
236
+ `acu tenant` runs commands on the Windows guest through plain `ssh`.
237
+ Two things about this setup are not obvious, and both are hard requirements.
223
238
 
224
- **1. The default SSH shell on the Windows guest must be PowerShell.**
225
- `acu` sends PowerShell syntax over the wire, and every one of those commands fails under `cmd.exe`, the Windows OpenSSH default. Switch it once, in an elevated PowerShell on the guest:
239
+ **1.
240
+ The default SSH shell on the Windows guest must be PowerShell.**
241
+ `acu` sends PowerShell syntax over the wire, and every one of those commands fails under `cmd.exe`, the Windows OpenSSH default.
242
+ Switch it once, in an elevated PowerShell on the guest:
226
243
 
227
244
  ```powershell
228
245
  New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
@@ -230,9 +247,11 @@ New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
230
247
  -PropertyType String -Force
231
248
  ```
232
249
 
233
- **2. Authentication must be key-based and non-interactive.**
250
+ **2.
251
+ Authentication must be key-based and non-interactive.**
234
252
  `acu` connects with `BatchMode=yes`, so it will never answer a password prompt.
235
- Because the default user is `Administrator` (an administrators-group member), Windows OpenSSH reads the key from the *machine-wide* file `C:\ProgramData\ssh\administrators_authorized_keys` — **not** from `~\.ssh\authorized_keys` like on Linux. On the guest:
253
+ Because the default user is `Administrator` (an administrators-group member), Windows OpenSSH reads the key from the *machine-wide* file `C:\ProgramData\ssh\administrators_authorized_keys` — **not** from `~\.ssh\authorized_keys` like on Linux.
254
+ On the guest:
236
255
 
237
256
  Install + start the server (once):
238
257
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "acumatica-cli"
3
- version = "0.15.0"
3
+ version = "0.15.2"
4
4
  description = "Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data"
5
5
  authors = [{ name = "Konstantin Borovik", email = "kb@lab5.ca" }]
6
6
  license = "PolyForm-Noncommercial-1.0.0"
@@ -509,6 +509,11 @@ class _Extraction:
509
509
  """The --only filter: row name (entity or kind) or file stem."""
510
510
  return not self.only or name in self.only or Path(file).stem in self.only
511
511
 
512
+ def _progress(self, target: Path, name: str) -> None:
513
+ """Per-row progress banner matching apply/diff (V9 / I.cmd extract)."""
514
+ inst = self.client.instance
515
+ output.data(f"{target} -> {inst.tenant} on {inst.base_url} ({name})")
516
+
512
517
  def _skip(self, target: Path, reason: str) -> None:
513
518
  """Report one clean per-file skip and tally it."""
514
519
  output.data(f"skip {target} ({reason})")
@@ -553,6 +558,8 @@ class _Extraction:
553
558
  if not self._selected(spec.entity, spec.file):
554
559
  continue
555
560
  target = self.out_dir / spec.file
561
+ # Banner before any outcome (write/skip/would write) — apply shape
562
+ self._progress(target, spec.entity)
556
563
  if self._skip_existing(target):
557
564
  continue
558
565
  # Hybrid contract (T69/T81): a bootstrap-endpoint row for an
@@ -584,6 +591,7 @@ class _Extraction:
584
591
  if not self._selected(synth.kind, synth.file):
585
592
  continue
586
593
  target = self.out_dir / synth.file
594
+ self._progress(target, synth.kind)
587
595
  if self._skip_existing(target):
588
596
  continue
589
597
  synthesize, skip_reason = SYNTHESIZERS[synth.kind]
@@ -614,6 +622,7 @@ class _Extraction:
614
622
  if not self._selected("features", FEATURES_FILE):
615
623
  return
616
624
  target = self.out_dir / FEATURES_FILE
625
+ self._progress(target, "features")
617
626
  if self._skip_existing(target):
618
627
  return
619
628
  gates = [
@@ -0,0 +1,7 @@
1
+ entity: Subaccount
2
+ key: SubaccountCD
3
+ records:
4
+ - Active: true
5
+ Description: Default
6
+ Secured: false
7
+ SubaccountCD: '000000'
@@ -1,21 +1,3 @@
1
- # Chart of accounts (GL202500), designed for LAB5 Electronics Inc. (lab5.ca demo tenant seed) - 23 accounts covering GL foundation plus the
2
- # AP/AR/IN/SO/PO posting resolution the buy-build-sell scenario needs.
3
- # Field shape live-verified on 26.101.0225 by the earlier SalesDemo
4
- # replay (T24). Stripped per that work: internal AccountID, AccountClass
5
- # (no Default-endpoint entity), AccountGroup (PM - absent on a fresh
6
- # tenant, PUT 422s), RevaluationRateType, and the server-derived
7
- # ChartOfAccountsOrder + CashAccount (PUT-tolerated but the server keeps
8
- # its own derivation, so any sourced value diffs dirty forever - B11).
9
- # CurrencyID only on denominated cash accounts (the SalesDemo extract
10
- # carried it on 11 cash accounts only). Equity accounts are Type:
11
- # Liability - the Account.Type list has no Equity value.
12
- #
13
- # APPLY ORDER (dir expansion sorts *.yaml alphabetically; numbered
14
- # prefixes encode order): after 10-subaccounts.yaml; before
15
- # 32-gl-preferences.yaml, which references 32000/33000 below. FX
16
- # gain/loss accounts (83xxx/84000) intentionally absent - USD-only
17
- # tenant; add them only if AR/AP release proves to need a financial
18
- # currency row (plan risk R4).
19
1
  entity: Account
20
2
  key: AccountCD
21
3
  records:
@@ -0,0 +1,6 @@
1
+ entity: Ledger
2
+ key: LedgerID
3
+ records:
4
+ - LedgerID: ACTUAL
5
+ Description: Actual Ledger
6
+ Type: Actual
@@ -0,0 +1,6 @@
1
+ entity: GLPreferences
2
+ key: RetEarnAccountID
3
+ endpoint: bootstrap
4
+ records:
5
+ - RetEarnAccountID: '32000'
6
+ YtdNetIncAccountID: '33000'
@@ -0,0 +1,6 @@
1
+ entity: LedgerCompany
2
+ key: [LedgerCD, OrganizationID]
3
+ endpoint: bootstrap
4
+ records:
5
+ - LedgerCD: ACTUAL
6
+ OrganizationID: LAB5
@@ -1,8 +1,3 @@
1
- # Units of measure (CS203500) via the Default endpoint - EA for stock
2
- # items; BOX second unit; PIECE/HOUR retained from scaffold.
3
- # KG + LITER: company packaging base UOMs (Companies Weight/Volume UOM;
4
- # Stock Items Packaging tab inherits them). Must exist before
5
- # 91-company-packaging.yaml sets them on the org.
6
1
  entity: UnitsOfMeasure
7
2
  key: UnitID
8
3
  records:
@@ -0,0 +1,9 @@
1
+ entity: Company
2
+ key: AcctCD
3
+ endpoint: bootstrap
4
+ records:
5
+ - AcctCD: LAB5
6
+ AcctName: LAB5 Electronics Inc.
7
+ OrganizationType: Without Branches
8
+ BaseCuryID: USD
9
+ CountryID: US
@@ -0,0 +1,11 @@
1
+ entity: CreditTerms
2
+ key: TermsID
3
+ endpoint: bootstrap
4
+ records:
5
+ - TermsID: NET30
6
+ Descr: Net 30 Days
7
+ VisibleTo: All
8
+ DueType: Fixed Number of Days
9
+ DayDue00: 30
10
+ DiscType: Fixed Number of Days
11
+ DiscPercent: 0
@@ -0,0 +1,10 @@
1
+ - FinancialModule
2
+ - FinancialStandard
3
+ - DistributionModule
4
+ - Inventory
5
+ - Branch
6
+ - MultiCompany
7
+ - SubAccount
8
+ - KitAssemblies
9
+ - Warehouse
10
+ - WarehouseLocation
@@ -0,0 +1,34 @@
1
+ entity: ReasonCode
2
+ key: ReasonCodeID
3
+ endpoint: bootstrap
4
+ records:
5
+ - ReasonCodeID: INISSUE
6
+ Descr: Inventory issue
7
+ Usage: Issue
8
+ AccountID: '50300'
9
+ SubID: '000000'
10
+ - ReasonCodeID: INRECEIPT
11
+ Descr: Inventory receipt
12
+ Usage: Receipt
13
+ AccountID: '50300'
14
+ SubID: '000000'
15
+ - ReasonCodeID: INADJUST
16
+ Descr: Inventory adjustment
17
+ Usage: Adjustment
18
+ AccountID: '50300'
19
+ SubID: '000000'
20
+ - ReasonCodeID: INPI
21
+ Descr: Physical inventory variance
22
+ Usage: Adjustment
23
+ AccountID: '50300'
24
+ SubID: '000000'
25
+ - ReasonCodeID: INASSEMBLY
26
+ Descr: Kit assembly
27
+ Usage: Assembly/Disassembly
28
+ AccountID: '50300'
29
+ SubID: '000000'
30
+ - ReasonCodeID: PORETURN
31
+ Descr: Vendor return
32
+ Usage: Vendor Return
33
+ AccountID: '50300'
34
+ SubID: '000000'
@@ -0,0 +1,15 @@
1
+ entity: INPreferences
2
+ key: HoldEntry
3
+ endpoint: bootstrap
4
+ records:
5
+ - HoldEntry: false
6
+ INProgressAcctID: '12300'
7
+ INProgressSubID: '000000'
8
+ INTransitAcctID: '12400'
9
+ INTransitSubID: '000000'
10
+ TransitBranchID: LAB5
11
+ UpdateGL: true
12
+ IssuesReasonCode: INISSUE
13
+ ReceiptReasonCode: INRECEIPT
14
+ AdjustmentReasonCode: INADJUST
15
+ PIReasonCode: INPI
@@ -0,0 +1,6 @@
1
+ entity: AvailabilityCalculationRule
2
+ key: AvailabilitySchemeID
3
+ endpoint: bootstrap
4
+ records:
5
+ - AvailabilitySchemeID: DEFAULT
6
+ Description: Default availability calculation rule
@@ -1,15 +1,3 @@
1
- # Posting classes (IN206000) via the custom Bootstrap endpoint (symbolic endpoint: bootstrap)
2
- # (acumatica-cli#10, T61) - no Default-endpoint entity, and StockItem
3
- # posting resolution needs a class. PARTS books inventory to 12100,
4
- # KITS to 12200; both share sales 40000, COGS 50000, PO accrual 20200,
5
- # PPV 50100, LCV 50200, subaccount 000000 everywhere. The *AcctDefault
6
- # source combos are left to their server defaults on first save - if
7
- # posting resolution surprises during the scenario, claim them here
8
- # with the live-read stored words.
9
- #
10
- # APPLY ORDER (dir expansion sorts *.yaml alphabetically; numbered
11
- # prefixes encode order): after 20-accounts.yaml (all six accounts) and
12
- # 10-subaccounts.yaml; before 54-item-classes.yaml.
13
1
  entity: PostingClass
14
2
  key: PostClassID
15
3
  endpoint: bootstrap
@@ -0,0 +1,8 @@
1
+ entity: Warehouse
2
+ key: SiteCD
3
+ endpoint: bootstrap
4
+ records:
5
+ - SiteCD: WH01
6
+ Descr: Main warehouse
7
+ Active: true
8
+ CountryID: US
@@ -0,0 +1,18 @@
1
+ entity: Warehouse
2
+ key: WarehouseID
3
+ endpoint: default
4
+ detail_keys:
5
+ Locations: LocationID
6
+ records:
7
+ - WarehouseID: WH01
8
+ ReceivingLocationID: MAIN
9
+ ShippingLocationID: MAIN
10
+ RMALocationID: MAIN
11
+ Locations:
12
+ - LocationID: MAIN
13
+ Description: Main storage
14
+ Active: true
15
+ ReceiptsAllowed: true
16
+ SalesAllowed: true
17
+ TransfersAllowed: true
18
+ AssemblyAllowed: true
@@ -0,0 +1,8 @@
1
+ entity: Warehouse
2
+ key: WarehouseID
3
+ endpoint: default
4
+ records:
5
+ - WarehouseID: WH01
6
+ ReceivingLocationID: MAIN
7
+ ShippingLocationID: MAIN
8
+ RMALocationID: MAIN
@@ -0,0 +1,5 @@
1
+ entity: TaxCategory
2
+ key: TaxCategoryID
3
+ records:
4
+ - TaxCategoryID: EXEMPT
5
+ Description: Tax exempt
@@ -0,0 +1,23 @@
1
+ entity: ItemClass
2
+ key: ClassID
3
+ records:
4
+ - ClassID: PARTS
5
+ Description: Purchased components
6
+ StockItem: true
7
+ ItemType: Finished Good
8
+ ValuationMethod: Average
9
+ BaseUOM: EA
10
+ AvailabilityCalculationRule: DEFAULT
11
+ PostingClass: PARTS
12
+ TaxCategoryID: EXEMPT
13
+ DefaultWarehouseID: WH01
14
+ - ClassID: KITS
15
+ Description: Assembled gateway kits
16
+ StockItem: true
17
+ ItemType: Finished Good
18
+ ValuationMethod: Average
19
+ BaseUOM: EA
20
+ AvailabilityCalculationRule: DEFAULT
21
+ PostingClass: KITS
22
+ TaxCategoryID: EXEMPT
23
+ DefaultWarehouseID: WH01
@@ -0,0 +1,8 @@
1
+ entity: SOPreferences
2
+ key: DefaultOrderType
3
+ endpoint: bootstrap
4
+ records:
5
+ - DefaultOrderType: SO
6
+ HoldShipments: false
7
+ RequireShipmentTotal: false
8
+ AutoReleaseIN: true
@@ -0,0 +1,7 @@
1
+ entity: POPreferences
2
+ key: HoldReceipts
3
+ endpoint: bootstrap
4
+ records:
5
+ - HoldReceipts: false
6
+ RCReturnReasonCodeID: PORETURN
7
+ AutoReleaseIN: true
@@ -0,0 +1,8 @@
1
+ entity: OrderType
2
+ key: OrderType
3
+ endpoint: bootstrap
4
+ records:
5
+ - OrderType: SO
6
+ Active: true
7
+ FreightAcctID: '40100'
8
+ FreightSubID: '000000'
@@ -0,0 +1,5 @@
1
+ entity: ARPreferences
2
+ key: HoldEntry
3
+ endpoint: bootstrap
4
+ records:
5
+ - HoldEntry: false
@@ -0,0 +1,5 @@
1
+ entity: APPreferences
2
+ key: HoldEntry
3
+ endpoint: bootstrap
4
+ records:
5
+ - HoldEntry: false
@@ -0,0 +1,7 @@
1
+ entity: CAPreferences
2
+ key: TransitAcctId
3
+ endpoint: bootstrap
4
+ records:
5
+ - TransitAcctId: '10200'
6
+ TransitSubID: '000000'
7
+ HoldEntry: false
@@ -0,0 +1,10 @@
1
+ entity: CashAccount
2
+ key: CashAccountCD
3
+ endpoint: bootstrap
4
+ records:
5
+ - CashAccountCD: '10100'
6
+ Descr: Checking Account
7
+ AccountID: '10100'
8
+ SubID: '000000'
9
+ BranchID: LAB5
10
+ Active: true
@@ -0,0 +1,17 @@
1
+ entity: PaymentMethod
2
+ key: PaymentMethodID
3
+ detail_keys:
4
+ AllowedCashAccounts: CashAccount
5
+ records:
6
+ - PaymentMethodID: WIRE
7
+ Description: Wire transfer
8
+ Active: true
9
+ MeansOfPayment: Cash/Check
10
+ UseInAP: true
11
+ UseInAR: true
12
+ AllowedCashAccounts:
13
+ - CashAccount: '10100'
14
+ UseInAP: true
15
+ UseInAR: true
16
+ APDefault: true
17
+ ARDefault: true
@@ -0,0 +1,11 @@
1
+ entity: StatementCycle
2
+ key: StatementCycleId
3
+ endpoint: bootstrap
4
+ records:
5
+ - StatementCycleId: MONTHLY
6
+ Descr: Monthly statements
7
+ PrepareOn: Fixed Day of Month
8
+ Day00: 1
9
+ AgeDays00: 30
10
+ AgeDays01: 60
11
+ AgeDays02: 90
@@ -0,0 +1,24 @@
1
+ entity: VendorClass
2
+ key: VendorClassID
3
+ endpoint: bootstrap
4
+ records:
5
+ - VendorClassID: SUPPLIER
6
+ Descr: Component suppliers
7
+ TermsID: NET30
8
+ APAcctID: '20100'
9
+ APSubID: '000000'
10
+ DiscTakenAcctID: '49100'
11
+ DiscTakenSubID: '000000'
12
+ ExpenseAcctID: '50000'
13
+ ExpenseSubID: '000000'
14
+ POAccrualAcctID: '20200'
15
+ POAccrualSubID: '000000'
16
+ - VendorClassID: SERVICE
17
+ Descr: Service providers
18
+ TermsID: NET30
19
+ APAcctID: '20100'
20
+ APSubID: '000000'
21
+ DiscTakenAcctID: '49100'
22
+ DiscTakenSubID: '000000'
23
+ ExpenseAcctID: '61000'
24
+ ExpenseSubID: '000000'
@@ -0,0 +1,14 @@
1
+ entity: CustomerClass
2
+ key: ClassID
3
+ records:
4
+ - ClassID: B2B
5
+ Description: B2B customers
6
+ Terms: NET30
7
+ CurrencyID: USD
8
+ ARAccount: '11000'
9
+ ARSubaccount: '000000'
10
+ SalesAccount: '40000'
11
+ SalesSubaccount: '000000'
12
+ CashDiscountAccount: '49000'
13
+ CashDiscountSubaccount: '000000'
14
+ StatementCycleID: MONTHLY
@@ -1,19 +1,3 @@
1
- # Vendors (AP303000) via the Default endpoint - reachable once AP
2
- # preferences exist (61-ap-preferences.yaml; P1 probe 500'd before it).
3
- # Four component suppliers + two service vendors (AP variety for later
4
- # scenario legs; buy-build-sell v1 bills only component vendors). Terms
5
- # ride each vendor: the Default VendorClass contract is skeletal
6
- # (ClassID/Description only - P1 schema read), so terms stay per vendor
7
- # while GL accounts default from the Bootstrap VendorClass (T64). The
8
- # nested MainContact/Address/Country is required at insert - the
9
- # vendor's auto-created Address 422s "'Country' cannot be empty"
10
- # (T65 linked-entity support; live-verified 2026-07-13). PrintOrders/
11
- # SendOrdersbyEmail false: either flag parks a PO at 'Pending Printing'
12
- # where receipts cannot add it (P5 probe).
13
- #
14
- # APPLY ORDER (dir expansion sorts *.yaml alphabetically; numbered
15
- # prefixes encode order): after 70-vendor-classes.yaml and bootstrap
16
- # credit terms (NET30).
17
1
  entity: Vendor
18
2
  key: VendorID
19
3
  records: