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.
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/PKG-INFO +31 -12
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/README.md +30 -11
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/pyproject.toml +1 -1
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/extract.py +9 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +7 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/baseline/20-accounts.yaml +0 -18
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +6 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +6 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +6 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/baseline/90-uoms.yaml +0 -5
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/company.yaml +9 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +11 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/bootstrap/features.yaml +10 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +34 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +15 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +6 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/40-posting-classes.yaml +0 -12
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/50-warehouse.yaml +8 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +18 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +8 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +5 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/54-item-classes.yaml +23 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +8 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +7 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/58-order-types.yaml +8 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +5 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +5 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +7 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/63-cash-account.yaml +10 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +17 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +11 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +24 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +14 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/75-vendors.yaml +0 -16
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/76-customers.yaml +0 -9
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/80-stock-items-parts.yaml +0 -18
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +24 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/config/master/85-kit-specifications.yaml +0 -14
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +8 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +11 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +11 -0
- acumatica_cli-0.15.2/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +15 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/10-seed-capital.yaml +0 -5
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/20-buy.yaml +0 -32
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/30-build.yaml +0 -20
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/scenario/40-sell.yaml +0 -12
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +0 -15
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +0 -15
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +0 -18
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +0 -27
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/company.yaml +0 -15
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +0 -17
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/bootstrap/features.yaml +0 -26
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +0 -49
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +0 -34
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +0 -16
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/50-warehouse.yaml +0 -23
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +0 -28
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +0 -13
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +0 -14
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/54-item-classes.yaml +0 -43
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +0 -21
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +0 -21
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/58-order-types.yaml +0 -21
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +0 -15
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +0 -14
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +0 -18
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/63-cash-account.yaml +0 -23
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +0 -27
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +0 -23
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +0 -38
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +0 -28
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +0 -40
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +0 -27
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +0 -28
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +0 -33
- acumatica_cli-0.15.0/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +0 -20
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/__init__.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap_plugin.cs +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/bootstrap_project.xml +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/cli.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/client.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/config.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/firstlogin.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/models.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/output.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/run.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/seed.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/seed_catalog.yaml +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/state.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/target.py +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/README.md +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/env +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/gitignore +0 -0
- {acumatica_cli-0.15.0 → acumatica_cli-0.15.2}/src/acumatica_cli/templates/target +0 -0
- {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.
|
|
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.
|
|
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).
|
|
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/`.
|
|
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.
|
|
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).
|
|
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.
|
|
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`.
|
|
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.
|
|
243
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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).
|
|
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/`.
|
|
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.
|
|
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).
|
|
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.
|
|
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`.
|
|
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.
|
|
225
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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 = [
|
|
@@ -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:
|
|
@@ -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,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
|
|
@@ -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,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,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,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,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:
|