acumatica-cli 0.4.0__tar.gz → 0.6.0__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.4.0 → acumatica_cli-0.6.0}/PKG-INFO +47 -10
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/README.md +46 -9
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/pyproject.toml +1 -1
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/bootstrap_project.xml +438 -2
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/client.py +52 -9
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/seed.py +199 -10
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/50-gl-preferences.yaml +2 -2
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/60-ledger-company.yaml +2 -2
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/company.yaml +2 -2
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/credit-terms.yaml +2 -2
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/setup/10-financial-year.yaml +1 -1
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/setup/20-master-calendar.yaml +1 -1
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/setup/30-open-periods.yaml +1 -1
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/__init__.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/bootstrap.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/bootstrap_plugin.cs +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/cli.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/config.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/extract.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/extract_manifest.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/firstlogin.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/models.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/output.py +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/10-subaccounts.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/20-accounts.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/40-ledger.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/90-uoms.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/features.yaml +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/env +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/gitignore +0 -0
- {acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/tenant.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: acumatica-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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>
|
|
@@ -15,23 +15,27 @@ Project-URL: Homepage, https://lab5.ca
|
|
|
15
15
|
Project-URL: Repository, https://github.com/kborovik/acumatica-cli
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
|
|
18
|
-
# Acumatica Config-as-Code
|
|
18
|
+
# Acumatica GitOps (Config-as-Code)
|
|
19
19
|
|
|
20
|
-
**`acu`** configures Acumatica ERP from YAML files in a git repo.
|
|
20
|
+
**`acu`** configures Acumatica ERP from YAML files in a git repo (GitOps).
|
|
21
21
|
|
|
22
22
|
**No UI clicks, no Configuration Wizard.**
|
|
23
23
|
|
|
24
24
|
## How it works
|
|
25
25
|
|
|
26
|
-
1. **
|
|
26
|
+
1. **Extract** the target Acumatica deployment with `acu extract` — its configuration becomes YAML, config as code.
|
|
27
27
|
2. **Develop** changes in the YAML, in git: edit, review, version.
|
|
28
28
|
3. **Re-deploy** with `acu apply`, then prove the live tenant matches the code with `acu diff`.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Four commands do the work, and every one is safe to re-run:
|
|
31
31
|
|
|
32
|
-
- **`acu tenant create`** — creates a tenant and bootstraps it in one step, ready for `apply`.
|
|
33
|
-
-
|
|
32
|
+
- **`acu tenant create`** — creates a tenant and bootstraps it in one step, ready for `apply`.
|
|
33
|
+
Re-running it against an existing tenant republishes the bootstrap package instead of failing.
|
|
34
|
+
- **`acu apply`** — pushes your YAML into the tenant as keyed upserts.
|
|
35
|
+
Running it twice changes nothing.
|
|
34
36
|
- **`acu diff`** — compares your YAML against the live tenant and exits with code 2 on drift.
|
|
37
|
+
- **`acu extract`** — reads a configured tenant and writes the YAML file set back out, the inverse of `apply`.
|
|
38
|
+
Existing files are skipped unless `--force`.
|
|
35
39
|
|
|
36
40
|
> **Tested against** Acumatica ERP **26.101.0225** on Windows Server 2025,
|
|
37
41
|
> contract REST endpoint **25.200.001**. Other versions will likely work,
|
|
@@ -61,16 +65,18 @@ acu --tenant DEV diff # prove zero drift (exit 2 on drift)
|
|
|
61
65
|
|
|
62
66
|
```text
|
|
63
67
|
acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
64
|
-
[--username U] [--password P]
|
|
68
|
+
[--username U] [--password P] [--version] [--completion [SHELL]]
|
|
65
69
|
│
|
|
66
70
|
├── tenant tenant CRUD (ac.exe over SSH — control plane)
|
|
67
71
|
│ ├── list CompanyID, sign-in name, internal CD, type
|
|
68
72
|
│ ├── create --id N --login NAME create + bootstrap; re-run to republish
|
|
69
|
-
│ │ [--type SalesDemo] [--parent N] [--hidden] [--no-init]
|
|
73
|
+
│ │ [--type SalesDemo|T100|U100] [--parent N] [--hidden] [--no-init]
|
|
70
74
|
│ └── delete --id N [--yes] delete the tenant and its data, recycle app pool
|
|
71
75
|
│
|
|
72
76
|
├── apply [--dry-run] [FILES...] push YAML via REST (idempotent PUT upserts)
|
|
73
77
|
├── diff [FILES...] drift check vs the live tenant (exit 2 on drift)
|
|
78
|
+
├── extract [--out DIR] [--only NAME]... [--force] [--dry-run]
|
|
79
|
+
│ dump live tenant state as seed YAML (inverse of apply)
|
|
74
80
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
75
81
|
│
|
|
76
82
|
└── config configuration ops
|
|
@@ -79,7 +85,9 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
79
85
|
└── check read-only preflight: discovery, secrets, REST, SSH
|
|
80
86
|
```
|
|
81
87
|
|
|
82
|
-
`apply` and `diff` called without FILES default to the scaffolded directories, in order: `bootstrap/`, then `baseline/`, then `setup/`.
|
|
88
|
+
`apply` and `diff` called without FILES default to the scaffolded directories, in order: `bootstrap/`, then `baseline/`, then `setup/`.
|
|
89
|
+
`acu --completion` emits a completion script for bash, zsh, or fish — source it from your shell profile.
|
|
90
|
+
Run `acu <command> --help` for details on any command.
|
|
83
91
|
|
|
84
92
|
## The data repo
|
|
85
93
|
|
|
@@ -186,3 +194,32 @@ Then verify from your workstation — this one test proves both requirements at
|
|
|
186
194
|
```sh
|
|
187
195
|
ssh -o BatchMode=yes Administrator@acu-dev1.vm.internal '$PSVersionTable.PSVersion'
|
|
188
196
|
```
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
git clone https://github.com/kborovik/acumatica-cli.git
|
|
202
|
+
cd acumatica-cli
|
|
203
|
+
make install # editable install as a global uv tool
|
|
204
|
+
make check # offline gate: ruff, basedpyright strict, pytest
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The default test suite is fully offline.
|
|
208
|
+
REST is faked with `httpx.MockTransport`, SSH with a monkeypatched `subprocess.run` — no live instance is needed.
|
|
209
|
+
`make check` must pass before every commit.
|
|
210
|
+
|
|
211
|
+
### Live end-to-end tier
|
|
212
|
+
|
|
213
|
+
`make e2e` runs the opt-in live tier against a real Acumatica instance (pytest marker `e2e`, deselected by the default suite).
|
|
214
|
+
|
|
215
|
+
Configuration is one file: a decrypted `.env` at the repo root names the instance — `ACU_BASE_URL`, `ACU_SSH`, `ACU_TENANT`, `ACU_PASSWORD`.
|
|
216
|
+
`make e2e` refuses to start without it.
|
|
217
|
+
|
|
218
|
+
The tier is self-contained.
|
|
219
|
+
Each run scaffolds a synthetic single-org company from the packaged `acu config init` templates into a temporary directory, copies the real `.env` into it, and runs the installed `acu` binary from there — no data repo, no pre-existing fixtures on the instance.
|
|
220
|
+
Scratch tenants (`E2E`, `E2EA`, `E2EB`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
make e2e # whole tier, about 20 minutes
|
|
224
|
+
make e2e FILE=test_provision_lifecycle # one file, by stem or path
|
|
225
|
+
```
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
# Acumatica Config-as-Code
|
|
1
|
+
# Acumatica GitOps (Config-as-Code)
|
|
2
2
|
|
|
3
|
-
**`acu`** configures Acumatica ERP from YAML files in a git repo.
|
|
3
|
+
**`acu`** configures Acumatica ERP from YAML files in a git repo (GitOps).
|
|
4
4
|
|
|
5
5
|
**No UI clicks, no Configuration Wizard.**
|
|
6
6
|
|
|
7
7
|
## How it works
|
|
8
8
|
|
|
9
|
-
1. **
|
|
9
|
+
1. **Extract** the target Acumatica deployment with `acu extract` — its configuration becomes YAML, config as code.
|
|
10
10
|
2. **Develop** changes in the YAML, in git: edit, review, version.
|
|
11
11
|
3. **Re-deploy** with `acu apply`, then prove the live tenant matches the code with `acu diff`.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Four commands do the work, and every one is safe to re-run:
|
|
14
14
|
|
|
15
|
-
- **`acu tenant create`** — creates a tenant and bootstraps it in one step, ready for `apply`.
|
|
16
|
-
-
|
|
15
|
+
- **`acu tenant create`** — creates a tenant and bootstraps it in one step, ready for `apply`.
|
|
16
|
+
Re-running it against an existing tenant republishes the bootstrap package instead of failing.
|
|
17
|
+
- **`acu apply`** — pushes your YAML into the tenant as keyed upserts.
|
|
18
|
+
Running it twice changes nothing.
|
|
17
19
|
- **`acu diff`** — compares your YAML against the live tenant and exits with code 2 on drift.
|
|
20
|
+
- **`acu extract`** — reads a configured tenant and writes the YAML file set back out, the inverse of `apply`.
|
|
21
|
+
Existing files are skipped unless `--force`.
|
|
18
22
|
|
|
19
23
|
> **Tested against** Acumatica ERP **26.101.0225** on Windows Server 2025,
|
|
20
24
|
> contract REST endpoint **25.200.001**. Other versions will likely work,
|
|
@@ -44,16 +48,18 @@ acu --tenant DEV diff # prove zero drift (exit 2 on drift)
|
|
|
44
48
|
|
|
45
49
|
```text
|
|
46
50
|
acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
47
|
-
[--username U] [--password P]
|
|
51
|
+
[--username U] [--password P] [--version] [--completion [SHELL]]
|
|
48
52
|
│
|
|
49
53
|
├── tenant tenant CRUD (ac.exe over SSH — control plane)
|
|
50
54
|
│ ├── list CompanyID, sign-in name, internal CD, type
|
|
51
55
|
│ ├── create --id N --login NAME create + bootstrap; re-run to republish
|
|
52
|
-
│ │ [--type SalesDemo] [--parent N] [--hidden] [--no-init]
|
|
56
|
+
│ │ [--type SalesDemo|T100|U100] [--parent N] [--hidden] [--no-init]
|
|
53
57
|
│ └── delete --id N [--yes] delete the tenant and its data, recycle app pool
|
|
54
58
|
│
|
|
55
59
|
├── apply [--dry-run] [FILES...] push YAML via REST (idempotent PUT upserts)
|
|
56
60
|
├── diff [FILES...] drift check vs the live tenant (exit 2 on drift)
|
|
61
|
+
├── extract [--out DIR] [--only NAME]... [--force] [--dry-run]
|
|
62
|
+
│ dump live tenant state as seed YAML (inverse of apply)
|
|
57
63
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
58
64
|
│
|
|
59
65
|
└── config configuration ops
|
|
@@ -62,7 +68,9 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
62
68
|
└── check read-only preflight: discovery, secrets, REST, SSH
|
|
63
69
|
```
|
|
64
70
|
|
|
65
|
-
`apply` and `diff` called without FILES default to the scaffolded directories, in order: `bootstrap/`, then `baseline/`, then `setup/`.
|
|
71
|
+
`apply` and `diff` called without FILES default to the scaffolded directories, in order: `bootstrap/`, then `baseline/`, then `setup/`.
|
|
72
|
+
`acu --completion` emits a completion script for bash, zsh, or fish — source it from your shell profile.
|
|
73
|
+
Run `acu <command> --help` for details on any command.
|
|
66
74
|
|
|
67
75
|
## The data repo
|
|
68
76
|
|
|
@@ -169,3 +177,32 @@ Then verify from your workstation — this one test proves both requirements at
|
|
|
169
177
|
```sh
|
|
170
178
|
ssh -o BatchMode=yes Administrator@acu-dev1.vm.internal '$PSVersionTable.PSVersion'
|
|
171
179
|
```
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
git clone https://github.com/kborovik/acumatica-cli.git
|
|
185
|
+
cd acumatica-cli
|
|
186
|
+
make install # editable install as a global uv tool
|
|
187
|
+
make check # offline gate: ruff, basedpyright strict, pytest
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The default test suite is fully offline.
|
|
191
|
+
REST is faked with `httpx.MockTransport`, SSH with a monkeypatched `subprocess.run` — no live instance is needed.
|
|
192
|
+
`make check` must pass before every commit.
|
|
193
|
+
|
|
194
|
+
### Live end-to-end tier
|
|
195
|
+
|
|
196
|
+
`make e2e` runs the opt-in live tier against a real Acumatica instance (pytest marker `e2e`, deselected by the default suite).
|
|
197
|
+
|
|
198
|
+
Configuration is one file: a decrypted `.env` at the repo root names the instance — `ACU_BASE_URL`, `ACU_SSH`, `ACU_TENANT`, `ACU_PASSWORD`.
|
|
199
|
+
`make e2e` refuses to start without it.
|
|
200
|
+
|
|
201
|
+
The tier is self-contained.
|
|
202
|
+
Each run scaffolds a synthetic single-org company from the packaged `acu config init` templates into a temporary directory, copies the real `.env` into it, and runs the installed `acu` binary from there — no data repo, no pre-existing fixtures on the instance.
|
|
203
|
+
Scratch tenants (`E2E`, `E2EA`, `E2EB`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
204
|
+
|
|
205
|
+
```sh
|
|
206
|
+
make e2e # whole tier, about 20 minutes
|
|
207
|
+
make e2e FILE=test_provision_lifecycle # one file, by stem or path
|
|
208
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "acumatica-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
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
|
readme = "README.md"
|
|
@@ -146,13 +146,81 @@
|
|
|
146
146
|
PXAction member on the graph; the name literal confirmed
|
|
147
147
|
in the PX.Data.dll string heap) and processes every grid
|
|
148
148
|
row matching the filter - no Selected flags involved.
|
|
149
|
+
T61 distribution setup chain (screen->graph->PrimaryView read off the
|
|
150
|
+
live box aspx files 2026-07-13; LAB5 probe evidence in gh issue #10 -
|
|
151
|
+
five prefs screens gate Vendor/Customer/Warehouse/SalesOrder/
|
|
152
|
+
PurchaseOrder/Bill/SalesInvoice/Payment/Shipment with
|
|
153
|
+
PXSetupNotEnteredException 500s until each singleton exists):
|
|
154
|
+
- INPreferences IN101000 -> INSetupMaint, PrimaryView setup (DAC
|
|
155
|
+
PX.Objects.IN.INSetup). Numbering fields default
|
|
156
|
+
(INREGISTER etc.), but the live insert 500 named six
|
|
157
|
+
fields with no server default (read off the LAB5 PUT
|
|
158
|
+
2026-07-13): INProgressAcctID/INProgressSubID (the WIP
|
|
159
|
+
account) + the four reason codes (Issues/Receipt/
|
|
160
|
+
Adjustment/PI) - all exposed; HoldEntry = the echo flag.
|
|
161
|
+
- ReasonCode CS211000 -> ReasonCodeMaint, PrimaryView reasoncode
|
|
162
|
+
(PX.Objects.CS.ReasonCode) - no Default-endpoint entity,
|
|
163
|
+
and the INSetup reason-code fields above hard-require
|
|
164
|
+
rows. Usage takes the stored-word list; AccountID/SubID
|
|
165
|
+
= the code's GL posting target.
|
|
166
|
+
- APPreferences AP101000 -> APSetupMaint, PrimaryView Setup (APSetup);
|
|
167
|
+
HoldEntry echo field, same singleton pattern.
|
|
168
|
+
- ARPreferences AR101000 -> ARSetupMaint, PrimaryView ARSetupRecord
|
|
169
|
+
(ARSetup); HoldEntry echo field.
|
|
170
|
+
- SOPreferences SO101000 -> SOSetupMaint, PrimaryView sosetup (SOSetup);
|
|
171
|
+
DefaultOrderType doubles as the echo field and the R1
|
|
172
|
+
probe (does order type SO pre-exist on an empty tenant).
|
|
173
|
+
- POPreferences PO101000 -> POSetupMaint, PrimaryView Setup (POSetup);
|
|
174
|
+
HoldReceipts echo field + RCReturnReasonCodeID (the one
|
|
175
|
+
POSetup field the live insert named as required - a
|
|
176
|
+
Vendor Return usage reason code, 2026-07-13).
|
|
177
|
+
- AvailabilityCalculationRule IN201500 -> INAvailabilitySchemeMaint,
|
|
178
|
+
PrimaryView Schemes (INAvailabilityScheme) - an empty
|
|
179
|
+
tenant has zero scheme rows and ItemClass 422s
|
|
180
|
+
"'Availability Calculation Rule' cannot be empty"; the
|
|
181
|
+
Incl* booleans all carry defaults, so the entity exposes
|
|
182
|
+
the key + Description only.
|
|
183
|
+
- PostingClass IN206000 -> INPostClassMaint, PrimaryView postclass
|
|
184
|
+
(INPostClass) - no Default-endpoint entity; StockItem
|
|
185
|
+
posting resolution needs it. Exposes id + descr, the six
|
|
186
|
+
acct-source combos (stored-word lists), the six acct/sub
|
|
187
|
+
segment-mask pairs, and the six sub masks - grid/form
|
|
188
|
+
bindings read off IN206000.aspx.
|
|
189
|
+
- CAPreferences CA101000 -> CASetupMaint, PrimaryView CASetupRecord
|
|
190
|
+
(PX.Objects.CA.CASetup) - CashAccount answers 500
|
|
191
|
+
PXSetupNotEnteredException until the singleton exists
|
|
192
|
+
(live-read 2026-07-13). TransitAcctId (DAC spelling off
|
|
193
|
+
the aspx - lowercase d) + TransitSubID = the cash-in-
|
|
194
|
+
transit pair; HoldEntry = the echo flag.
|
|
195
|
+
- VendorClass AP201000 -> VendorClassMaint, PrimaryView
|
|
196
|
+
VendorClassRecord (PX.Objects.AP.VendorClass) - the
|
|
197
|
+
Default endpoint's VendorClass is skeletal (ClassID/
|
|
198
|
+
Description/Attributes) and Vendor carries no discount
|
|
199
|
+
fields, so vendor inserts 422 on the cash-discount pair
|
|
200
|
+
the class should default (T64, gh issue #13). Exposes
|
|
201
|
+
id + descr + TermsID + the GL-account pairs off the
|
|
202
|
+
screen's GL Accounts tab (aspx-verified 2026-07-13).
|
|
203
|
+
- StatementCycle AR202800 -> ARStatementMaint, PrimaryView
|
|
204
|
+
ARStatementCycleRecord (PX.Objects.AR.ARStatementCycle) -
|
|
205
|
+
no Default-endpoint entity, and Customer inserts 422
|
|
206
|
+
"'Statement Cycle ID' cannot be empty" (T64 follow-up
|
|
207
|
+
proven live 2026-07-13; the class defaults it). PrepareOn
|
|
208
|
+
takes the stored-word list; Day00 rides the
|
|
209
|
+
fixed-day-of-month choice; the AgeDays00-02 aging bounds
|
|
210
|
+
default inconsistently at raw insert ("end day earlier
|
|
211
|
+
than its start day" 422) so the seed supplies them.
|
|
212
|
+
- CashAccount CA202000 -> CashAccountMaint, PrimaryView CashAccount
|
|
213
|
+
(PX.Objects.CA.CashAccount) - Default endpoint answers
|
|
214
|
+
404. CuryID stays out (derived from the GL account,
|
|
215
|
+
B11 server-derived class); payment-method links are the
|
|
216
|
+
conditional PaymentMethodAccount follow-up, not here.
|
|
149
217
|
Contract field names = DAC property names verbatim (no rename layer).
|
|
150
218
|
Features (CS100000) stays OUT of the endpoint - writes through any
|
|
151
219
|
contract endpoint do not persist (T3 verdict); the plugin owns features.
|
|
152
220
|
-->
|
|
153
|
-
<Customization level="" description="acu bootstrap: CustomizationPlugin enables features on publish; Bootstrap endpoint exposes company + credit terms + financial currency + GL preferences + ledger-company link + financial year + calendars + period activation" product-version="26.101">
|
|
221
|
+
<Customization level="" description="acu bootstrap: CustomizationPlugin enables features on publish; Bootstrap endpoint exposes company + credit terms + financial currency + GL preferences + ledger-company link + financial year + calendars + period activation + module preferences (IN/AP/AR/SO/PO) + availability rule + posting class + cash account + vendor class + statement cycle" product-version="26.101">
|
|
154
222
|
<EntityEndpoint>
|
|
155
|
-
<Endpoint xmlns="http://www.acumatica.com/entity/maintenance/5.31" name="Bootstrap" version="1.
|
|
223
|
+
<Endpoint xmlns="http://www.acumatica.com/entity/maintenance/5.31" name="Bootstrap" version="1.6.0" systemContractVersion="4">
|
|
156
224
|
<TopLevelEntity name="Company" screen="CS101500">
|
|
157
225
|
<Fields>
|
|
158
226
|
<Field name="AcctCD" type="StringValue" />
|
|
@@ -455,6 +523,374 @@
|
|
|
455
523
|
</Mapping>
|
|
456
524
|
</Mappings>
|
|
457
525
|
</TopLevelEntity>
|
|
526
|
+
<TopLevelEntity name="INPreferences" screen="IN101000">
|
|
527
|
+
<Fields>
|
|
528
|
+
<Field name="HoldEntry" type="BooleanValue" />
|
|
529
|
+
<Field name="INProgressAcctID" type="StringValue" />
|
|
530
|
+
<Field name="INProgressSubID" type="StringValue" />
|
|
531
|
+
<Field name="IssuesReasonCode" type="StringValue" />
|
|
532
|
+
<Field name="ReceiptReasonCode" type="StringValue" />
|
|
533
|
+
<Field name="AdjustmentReasonCode" type="StringValue" />
|
|
534
|
+
<Field name="PIReasonCode" type="StringValue" />
|
|
535
|
+
</Fields>
|
|
536
|
+
<Mappings>
|
|
537
|
+
<Mapping field="HoldEntry">
|
|
538
|
+
<To object="setup" field="HoldEntry" />
|
|
539
|
+
</Mapping>
|
|
540
|
+
<Mapping field="INProgressAcctID">
|
|
541
|
+
<To object="setup" field="INProgressAcctID" />
|
|
542
|
+
</Mapping>
|
|
543
|
+
<Mapping field="INProgressSubID">
|
|
544
|
+
<To object="setup" field="INProgressSubID" />
|
|
545
|
+
</Mapping>
|
|
546
|
+
<Mapping field="IssuesReasonCode">
|
|
547
|
+
<To object="setup" field="IssuesReasonCode" />
|
|
548
|
+
</Mapping>
|
|
549
|
+
<Mapping field="ReceiptReasonCode">
|
|
550
|
+
<To object="setup" field="ReceiptReasonCode" />
|
|
551
|
+
</Mapping>
|
|
552
|
+
<Mapping field="AdjustmentReasonCode">
|
|
553
|
+
<To object="setup" field="AdjustmentReasonCode" />
|
|
554
|
+
</Mapping>
|
|
555
|
+
<Mapping field="PIReasonCode">
|
|
556
|
+
<To object="setup" field="PIReasonCode" />
|
|
557
|
+
</Mapping>
|
|
558
|
+
</Mappings>
|
|
559
|
+
</TopLevelEntity>
|
|
560
|
+
<TopLevelEntity name="ReasonCode" screen="CS211000">
|
|
561
|
+
<Fields>
|
|
562
|
+
<Field name="ReasonCodeID" type="StringValue" />
|
|
563
|
+
<Field name="Descr" type="StringValue" />
|
|
564
|
+
<Field name="Usage" type="StringValue" />
|
|
565
|
+
<Field name="AccountID" type="StringValue" />
|
|
566
|
+
<Field name="SubID" type="StringValue" />
|
|
567
|
+
</Fields>
|
|
568
|
+
<Mappings>
|
|
569
|
+
<Mapping field="ReasonCodeID">
|
|
570
|
+
<To object="reasoncode" field="ReasonCodeID" />
|
|
571
|
+
</Mapping>
|
|
572
|
+
<Mapping field="Descr">
|
|
573
|
+
<To object="reasoncode" field="Descr" />
|
|
574
|
+
</Mapping>
|
|
575
|
+
<Mapping field="Usage">
|
|
576
|
+
<To object="reasoncode" field="Usage" />
|
|
577
|
+
</Mapping>
|
|
578
|
+
<Mapping field="AccountID">
|
|
579
|
+
<To object="reasoncode" field="AccountID" />
|
|
580
|
+
</Mapping>
|
|
581
|
+
<Mapping field="SubID">
|
|
582
|
+
<To object="reasoncode" field="SubID" />
|
|
583
|
+
</Mapping>
|
|
584
|
+
</Mappings>
|
|
585
|
+
</TopLevelEntity>
|
|
586
|
+
<TopLevelEntity name="APPreferences" screen="AP101000">
|
|
587
|
+
<Fields>
|
|
588
|
+
<Field name="HoldEntry" type="BooleanValue" />
|
|
589
|
+
</Fields>
|
|
590
|
+
<Mappings>
|
|
591
|
+
<Mapping field="HoldEntry">
|
|
592
|
+
<To object="Setup" field="HoldEntry" />
|
|
593
|
+
</Mapping>
|
|
594
|
+
</Mappings>
|
|
595
|
+
</TopLevelEntity>
|
|
596
|
+
<TopLevelEntity name="ARPreferences" screen="AR101000">
|
|
597
|
+
<Fields>
|
|
598
|
+
<Field name="HoldEntry" type="BooleanValue" />
|
|
599
|
+
</Fields>
|
|
600
|
+
<Mappings>
|
|
601
|
+
<Mapping field="HoldEntry">
|
|
602
|
+
<To object="ARSetupRecord" field="HoldEntry" />
|
|
603
|
+
</Mapping>
|
|
604
|
+
</Mappings>
|
|
605
|
+
</TopLevelEntity>
|
|
606
|
+
<TopLevelEntity name="SOPreferences" screen="SO101000">
|
|
607
|
+
<Fields>
|
|
608
|
+
<Field name="DefaultOrderType" type="StringValue" />
|
|
609
|
+
</Fields>
|
|
610
|
+
<Mappings>
|
|
611
|
+
<Mapping field="DefaultOrderType">
|
|
612
|
+
<To object="sosetup" field="DefaultOrderType" />
|
|
613
|
+
</Mapping>
|
|
614
|
+
</Mappings>
|
|
615
|
+
</TopLevelEntity>
|
|
616
|
+
<TopLevelEntity name="POPreferences" screen="PO101000">
|
|
617
|
+
<Fields>
|
|
618
|
+
<Field name="HoldReceipts" type="BooleanValue" />
|
|
619
|
+
<Field name="RCReturnReasonCodeID" type="StringValue" />
|
|
620
|
+
</Fields>
|
|
621
|
+
<Mappings>
|
|
622
|
+
<Mapping field="HoldReceipts">
|
|
623
|
+
<To object="Setup" field="HoldReceipts" />
|
|
624
|
+
</Mapping>
|
|
625
|
+
<Mapping field="RCReturnReasonCodeID">
|
|
626
|
+
<To object="Setup" field="RCReturnReasonCodeID" />
|
|
627
|
+
</Mapping>
|
|
628
|
+
</Mappings>
|
|
629
|
+
</TopLevelEntity>
|
|
630
|
+
<TopLevelEntity name="AvailabilityCalculationRule" screen="IN201500">
|
|
631
|
+
<Fields>
|
|
632
|
+
<Field name="AvailabilitySchemeID" type="StringValue" />
|
|
633
|
+
<Field name="Description" type="StringValue" />
|
|
634
|
+
</Fields>
|
|
635
|
+
<Mappings>
|
|
636
|
+
<Mapping field="AvailabilitySchemeID">
|
|
637
|
+
<To object="Schemes" field="AvailabilitySchemeID" />
|
|
638
|
+
</Mapping>
|
|
639
|
+
<Mapping field="Description">
|
|
640
|
+
<To object="Schemes" field="Description" />
|
|
641
|
+
</Mapping>
|
|
642
|
+
</Mappings>
|
|
643
|
+
</TopLevelEntity>
|
|
644
|
+
<TopLevelEntity name="PostingClass" screen="IN206000">
|
|
645
|
+
<Fields>
|
|
646
|
+
<Field name="PostClassID" type="StringValue" />
|
|
647
|
+
<Field name="Descr" type="StringValue" />
|
|
648
|
+
<Field name="InvtAcctDefault" type="StringValue" />
|
|
649
|
+
<Field name="SalesAcctDefault" type="StringValue" />
|
|
650
|
+
<Field name="COGSAcctDefault" type="StringValue" />
|
|
651
|
+
<Field name="POAccrualAcctDefault" type="StringValue" />
|
|
652
|
+
<Field name="PPVAcctDefault" type="StringValue" />
|
|
653
|
+
<Field name="LCVarianceAcctDefault" type="StringValue" />
|
|
654
|
+
<Field name="InvtSubMask" type="StringValue" />
|
|
655
|
+
<Field name="SalesSubMask" type="StringValue" />
|
|
656
|
+
<Field name="COGSSubMask" type="StringValue" />
|
|
657
|
+
<Field name="POAccrualSubMask" type="StringValue" />
|
|
658
|
+
<Field name="PPVSubMask" type="StringValue" />
|
|
659
|
+
<Field name="LCVarianceSubMask" type="StringValue" />
|
|
660
|
+
<Field name="InvtAcctID" type="StringValue" />
|
|
661
|
+
<Field name="InvtSubID" type="StringValue" />
|
|
662
|
+
<Field name="SalesAcctID" type="StringValue" />
|
|
663
|
+
<Field name="SalesSubID" type="StringValue" />
|
|
664
|
+
<Field name="COGSAcctID" type="StringValue" />
|
|
665
|
+
<Field name="COGSSubID" type="StringValue" />
|
|
666
|
+
<Field name="POAccrualAcctID" type="StringValue" />
|
|
667
|
+
<Field name="POAccrualSubID" type="StringValue" />
|
|
668
|
+
<Field name="PPVAcctID" type="StringValue" />
|
|
669
|
+
<Field name="PPVSubID" type="StringValue" />
|
|
670
|
+
<Field name="LCVarianceAcctID" type="StringValue" />
|
|
671
|
+
<Field name="LCVarianceSubID" type="StringValue" />
|
|
672
|
+
</Fields>
|
|
673
|
+
<Mappings>
|
|
674
|
+
<Mapping field="PostClassID">
|
|
675
|
+
<To object="postclass" field="PostClassID" />
|
|
676
|
+
</Mapping>
|
|
677
|
+
<Mapping field="Descr">
|
|
678
|
+
<To object="postclass" field="Descr" />
|
|
679
|
+
</Mapping>
|
|
680
|
+
<Mapping field="InvtAcctDefault">
|
|
681
|
+
<To object="postclass" field="InvtAcctDefault" />
|
|
682
|
+
</Mapping>
|
|
683
|
+
<Mapping field="SalesAcctDefault">
|
|
684
|
+
<To object="postclass" field="SalesAcctDefault" />
|
|
685
|
+
</Mapping>
|
|
686
|
+
<Mapping field="COGSAcctDefault">
|
|
687
|
+
<To object="postclass" field="COGSAcctDefault" />
|
|
688
|
+
</Mapping>
|
|
689
|
+
<Mapping field="POAccrualAcctDefault">
|
|
690
|
+
<To object="postclass" field="POAccrualAcctDefault" />
|
|
691
|
+
</Mapping>
|
|
692
|
+
<Mapping field="PPVAcctDefault">
|
|
693
|
+
<To object="postclass" field="PPVAcctDefault" />
|
|
694
|
+
</Mapping>
|
|
695
|
+
<Mapping field="LCVarianceAcctDefault">
|
|
696
|
+
<To object="postclass" field="LCVarianceAcctDefault" />
|
|
697
|
+
</Mapping>
|
|
698
|
+
<Mapping field="InvtSubMask">
|
|
699
|
+
<To object="postclass" field="InvtSubMask" />
|
|
700
|
+
</Mapping>
|
|
701
|
+
<Mapping field="SalesSubMask">
|
|
702
|
+
<To object="postclass" field="SalesSubMask" />
|
|
703
|
+
</Mapping>
|
|
704
|
+
<Mapping field="COGSSubMask">
|
|
705
|
+
<To object="postclass" field="COGSSubMask" />
|
|
706
|
+
</Mapping>
|
|
707
|
+
<Mapping field="POAccrualSubMask">
|
|
708
|
+
<To object="postclass" field="POAccrualSubMask" />
|
|
709
|
+
</Mapping>
|
|
710
|
+
<Mapping field="PPVSubMask">
|
|
711
|
+
<To object="postclass" field="PPVSubMask" />
|
|
712
|
+
</Mapping>
|
|
713
|
+
<Mapping field="LCVarianceSubMask">
|
|
714
|
+
<To object="postclass" field="LCVarianceSubMask" />
|
|
715
|
+
</Mapping>
|
|
716
|
+
<Mapping field="InvtAcctID">
|
|
717
|
+
<To object="postclass" field="InvtAcctID" />
|
|
718
|
+
</Mapping>
|
|
719
|
+
<Mapping field="InvtSubID">
|
|
720
|
+
<To object="postclass" field="InvtSubID" />
|
|
721
|
+
</Mapping>
|
|
722
|
+
<Mapping field="SalesAcctID">
|
|
723
|
+
<To object="postclass" field="SalesAcctID" />
|
|
724
|
+
</Mapping>
|
|
725
|
+
<Mapping field="SalesSubID">
|
|
726
|
+
<To object="postclass" field="SalesSubID" />
|
|
727
|
+
</Mapping>
|
|
728
|
+
<Mapping field="COGSAcctID">
|
|
729
|
+
<To object="postclass" field="COGSAcctID" />
|
|
730
|
+
</Mapping>
|
|
731
|
+
<Mapping field="COGSSubID">
|
|
732
|
+
<To object="postclass" field="COGSSubID" />
|
|
733
|
+
</Mapping>
|
|
734
|
+
<Mapping field="POAccrualAcctID">
|
|
735
|
+
<To object="postclass" field="POAccrualAcctID" />
|
|
736
|
+
</Mapping>
|
|
737
|
+
<Mapping field="POAccrualSubID">
|
|
738
|
+
<To object="postclass" field="POAccrualSubID" />
|
|
739
|
+
</Mapping>
|
|
740
|
+
<Mapping field="PPVAcctID">
|
|
741
|
+
<To object="postclass" field="PPVAcctID" />
|
|
742
|
+
</Mapping>
|
|
743
|
+
<Mapping field="PPVSubID">
|
|
744
|
+
<To object="postclass" field="PPVSubID" />
|
|
745
|
+
</Mapping>
|
|
746
|
+
<Mapping field="LCVarianceAcctID">
|
|
747
|
+
<To object="postclass" field="LCVarianceAcctID" />
|
|
748
|
+
</Mapping>
|
|
749
|
+
<Mapping field="LCVarianceSubID">
|
|
750
|
+
<To object="postclass" field="LCVarianceSubID" />
|
|
751
|
+
</Mapping>
|
|
752
|
+
</Mappings>
|
|
753
|
+
</TopLevelEntity>
|
|
754
|
+
<TopLevelEntity name="CAPreferences" screen="CA101000">
|
|
755
|
+
<Fields>
|
|
756
|
+
<Field name="HoldEntry" type="BooleanValue" />
|
|
757
|
+
<Field name="TransitAcctId" type="StringValue" />
|
|
758
|
+
<Field name="TransitSubID" type="StringValue" />
|
|
759
|
+
</Fields>
|
|
760
|
+
<Mappings>
|
|
761
|
+
<Mapping field="HoldEntry">
|
|
762
|
+
<To object="CASetupRecord" field="HoldEntry" />
|
|
763
|
+
</Mapping>
|
|
764
|
+
<Mapping field="TransitAcctId">
|
|
765
|
+
<To object="CASetupRecord" field="TransitAcctId" />
|
|
766
|
+
</Mapping>
|
|
767
|
+
<Mapping field="TransitSubID">
|
|
768
|
+
<To object="CASetupRecord" field="TransitSubID" />
|
|
769
|
+
</Mapping>
|
|
770
|
+
</Mappings>
|
|
771
|
+
</TopLevelEntity>
|
|
772
|
+
<TopLevelEntity name="VendorClass" screen="AP201000">
|
|
773
|
+
<Fields>
|
|
774
|
+
<Field name="VendorClassID" type="StringValue" />
|
|
775
|
+
<Field name="Descr" type="StringValue" />
|
|
776
|
+
<Field name="TermsID" type="StringValue" />
|
|
777
|
+
<Field name="APAcctID" type="StringValue" />
|
|
778
|
+
<Field name="APSubID" type="StringValue" />
|
|
779
|
+
<Field name="ExpenseAcctID" type="StringValue" />
|
|
780
|
+
<Field name="ExpenseSubID" type="StringValue" />
|
|
781
|
+
<Field name="DiscTakenAcctID" type="StringValue" />
|
|
782
|
+
<Field name="DiscTakenSubID" type="StringValue" />
|
|
783
|
+
<Field name="POAccrualAcctID" type="StringValue" />
|
|
784
|
+
<Field name="POAccrualSubID" type="StringValue" />
|
|
785
|
+
<Field name="PrepaymentAcctID" type="StringValue" />
|
|
786
|
+
<Field name="PrepaymentSubID" type="StringValue" />
|
|
787
|
+
</Fields>
|
|
788
|
+
<Mappings>
|
|
789
|
+
<Mapping field="VendorClassID">
|
|
790
|
+
<To object="VendorClassRecord" field="VendorClassID" />
|
|
791
|
+
</Mapping>
|
|
792
|
+
<Mapping field="Descr">
|
|
793
|
+
<To object="VendorClassRecord" field="Descr" />
|
|
794
|
+
</Mapping>
|
|
795
|
+
<Mapping field="TermsID">
|
|
796
|
+
<To object="VendorClassRecord" field="TermsID" />
|
|
797
|
+
</Mapping>
|
|
798
|
+
<Mapping field="APAcctID">
|
|
799
|
+
<To object="VendorClassRecord" field="APAcctID" />
|
|
800
|
+
</Mapping>
|
|
801
|
+
<Mapping field="APSubID">
|
|
802
|
+
<To object="VendorClassRecord" field="APSubID" />
|
|
803
|
+
</Mapping>
|
|
804
|
+
<Mapping field="ExpenseAcctID">
|
|
805
|
+
<To object="VendorClassRecord" field="ExpenseAcctID" />
|
|
806
|
+
</Mapping>
|
|
807
|
+
<Mapping field="ExpenseSubID">
|
|
808
|
+
<To object="VendorClassRecord" field="ExpenseSubID" />
|
|
809
|
+
</Mapping>
|
|
810
|
+
<Mapping field="DiscTakenAcctID">
|
|
811
|
+
<To object="VendorClassRecord" field="DiscTakenAcctID" />
|
|
812
|
+
</Mapping>
|
|
813
|
+
<Mapping field="DiscTakenSubID">
|
|
814
|
+
<To object="VendorClassRecord" field="DiscTakenSubID" />
|
|
815
|
+
</Mapping>
|
|
816
|
+
<Mapping field="POAccrualAcctID">
|
|
817
|
+
<To object="VendorClassRecord" field="POAccrualAcctID" />
|
|
818
|
+
</Mapping>
|
|
819
|
+
<Mapping field="POAccrualSubID">
|
|
820
|
+
<To object="VendorClassRecord" field="POAccrualSubID" />
|
|
821
|
+
</Mapping>
|
|
822
|
+
<Mapping field="PrepaymentAcctID">
|
|
823
|
+
<To object="VendorClassRecord" field="PrepaymentAcctID" />
|
|
824
|
+
</Mapping>
|
|
825
|
+
<Mapping field="PrepaymentSubID">
|
|
826
|
+
<To object="VendorClassRecord" field="PrepaymentSubID" />
|
|
827
|
+
</Mapping>
|
|
828
|
+
</Mappings>
|
|
829
|
+
</TopLevelEntity>
|
|
830
|
+
<TopLevelEntity name="StatementCycle" screen="AR202800">
|
|
831
|
+
<Fields>
|
|
832
|
+
<Field name="StatementCycleId" type="StringValue" />
|
|
833
|
+
<Field name="Descr" type="StringValue" />
|
|
834
|
+
<Field name="PrepareOn" type="StringValue" />
|
|
835
|
+
<Field name="Day00" type="ShortValue" />
|
|
836
|
+
<Field name="AgeDays00" type="ShortValue" />
|
|
837
|
+
<Field name="AgeDays01" type="ShortValue" />
|
|
838
|
+
<Field name="AgeDays02" type="ShortValue" />
|
|
839
|
+
</Fields>
|
|
840
|
+
<Mappings>
|
|
841
|
+
<Mapping field="StatementCycleId">
|
|
842
|
+
<To object="ARStatementCycleRecord" field="StatementCycleId" />
|
|
843
|
+
</Mapping>
|
|
844
|
+
<Mapping field="Descr">
|
|
845
|
+
<To object="ARStatementCycleRecord" field="Descr" />
|
|
846
|
+
</Mapping>
|
|
847
|
+
<Mapping field="PrepareOn">
|
|
848
|
+
<To object="ARStatementCycleRecord" field="PrepareOn" />
|
|
849
|
+
</Mapping>
|
|
850
|
+
<Mapping field="Day00">
|
|
851
|
+
<To object="ARStatementCycleRecord" field="Day00" />
|
|
852
|
+
</Mapping>
|
|
853
|
+
<Mapping field="AgeDays00">
|
|
854
|
+
<To object="ARStatementCycleRecord" field="AgeDays00" />
|
|
855
|
+
</Mapping>
|
|
856
|
+
<Mapping field="AgeDays01">
|
|
857
|
+
<To object="ARStatementCycleRecord" field="AgeDays01" />
|
|
858
|
+
</Mapping>
|
|
859
|
+
<Mapping field="AgeDays02">
|
|
860
|
+
<To object="ARStatementCycleRecord" field="AgeDays02" />
|
|
861
|
+
</Mapping>
|
|
862
|
+
</Mappings>
|
|
863
|
+
</TopLevelEntity>
|
|
864
|
+
<TopLevelEntity name="CashAccount" screen="CA202000">
|
|
865
|
+
<Fields>
|
|
866
|
+
<Field name="CashAccountCD" type="StringValue" />
|
|
867
|
+
<Field name="Descr" type="StringValue" />
|
|
868
|
+
<Field name="AccountID" type="StringValue" />
|
|
869
|
+
<Field name="SubID" type="StringValue" />
|
|
870
|
+
<Field name="BranchID" type="StringValue" />
|
|
871
|
+
<Field name="Active" type="BooleanValue" />
|
|
872
|
+
</Fields>
|
|
873
|
+
<Mappings>
|
|
874
|
+
<Mapping field="CashAccountCD">
|
|
875
|
+
<To object="CashAccount" field="CashAccountCD" />
|
|
876
|
+
</Mapping>
|
|
877
|
+
<Mapping field="Descr">
|
|
878
|
+
<To object="CashAccount" field="Descr" />
|
|
879
|
+
</Mapping>
|
|
880
|
+
<Mapping field="AccountID">
|
|
881
|
+
<To object="CashAccount" field="AccountID" />
|
|
882
|
+
</Mapping>
|
|
883
|
+
<Mapping field="SubID">
|
|
884
|
+
<To object="CashAccount" field="SubID" />
|
|
885
|
+
</Mapping>
|
|
886
|
+
<Mapping field="BranchID">
|
|
887
|
+
<To object="CashAccount" field="BranchID" />
|
|
888
|
+
</Mapping>
|
|
889
|
+
<Mapping field="Active">
|
|
890
|
+
<To object="CashAccount" field="Active" />
|
|
891
|
+
</Mapping>
|
|
892
|
+
</Mappings>
|
|
893
|
+
</TopLevelEntity>
|
|
458
894
|
</Endpoint>
|
|
459
895
|
</EntityEndpoint>
|
|
460
896
|
</Customization>
|
|
@@ -14,15 +14,52 @@ from .config import Instance
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def wrap(record: dict[str, Any]) -> dict[str, Any]:
|
|
17
|
-
"""Plain dict -> contract-API body: {"Field": {"value": ...}}.
|
|
18
|
-
|
|
17
|
+
"""Plain dict -> contract-API body: {"Field": {"value": ...}}.
|
|
18
|
+
|
|
19
|
+
A list value is a detail array (T60): the list itself is NEVER
|
|
20
|
+
value-wrapped, each dict row wraps recursively — the shape the live
|
|
21
|
+
JournalTransaction PUT proved (T50/T37 e2e payload). A dict value is
|
|
22
|
+
a linked entity (T65): a bare nested object, wrapped recursively —
|
|
23
|
+
live-verified Vendor MainContact/Address/Country PUT. The contract's
|
|
24
|
+
OWN control fields travel bare, never value-wrapped: `id` (row GUID —
|
|
25
|
+
the only handle that makes a detail-row PUT an update instead of an
|
|
26
|
+
insert) and `delete` (row-removal marker).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def _value(v: Any) -> Any:
|
|
30
|
+
if isinstance(v, list):
|
|
31
|
+
return [wrap(row) if isinstance(row, dict) else row for row in v]
|
|
32
|
+
if isinstance(v, dict):
|
|
33
|
+
return wrap(v)
|
|
34
|
+
return {"value": v}
|
|
35
|
+
|
|
36
|
+
return {k: v if k in ("id", "delete") else _value(v) for k, v in record.items()}
|
|
19
37
|
|
|
20
38
|
|
|
21
39
|
def unwrap(entity: dict[str, Any]) -> dict[str, Any]:
|
|
22
|
-
"""Contract-API entity -> plain dict (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
"""Contract-API entity -> plain dict (value fields + detail arrays).
|
|
41
|
+
|
|
42
|
+
Inverse of wrap (T60/T65): a list of dicts unwraps row by row; lists
|
|
43
|
+
that are empty or whose rows carry no value fields are elided (a
|
|
44
|
+
detail array the source never claimed must not surface, and expanded
|
|
45
|
+
`files` descriptors are plain dicts that would unwrap to noise). A
|
|
46
|
+
non-value dict is a linked entity — unwrapped recursively, kept only
|
|
47
|
+
when something survives, so bookkeeping dicts (custom, _links, note)
|
|
48
|
+
stay excluded exactly as before.
|
|
49
|
+
"""
|
|
50
|
+
out: dict[str, Any] = {}
|
|
51
|
+
for k, v in entity.items():
|
|
52
|
+
if isinstance(v, dict) and "value" in v:
|
|
53
|
+
out[k] = v["value"]
|
|
54
|
+
elif isinstance(v, dict):
|
|
55
|
+
nested = unwrap(v)
|
|
56
|
+
if nested:
|
|
57
|
+
out[k] = nested
|
|
58
|
+
elif isinstance(v, list) and v and all(isinstance(row, dict) for row in v):
|
|
59
|
+
rows = [unwrap(row) for row in v]
|
|
60
|
+
if any(rows):
|
|
61
|
+
out[k] = rows
|
|
62
|
+
return out
|
|
26
63
|
|
|
27
64
|
|
|
28
65
|
# The list GET's optimized-export failure (B9): the contract API's list GET
|
|
@@ -159,7 +196,11 @@ class AcumaticaClient:
|
|
|
159
196
|
).json()
|
|
160
197
|
|
|
161
198
|
def get_record(
|
|
162
|
-
self,
|
|
199
|
+
self,
|
|
200
|
+
entity: str,
|
|
201
|
+
keys: Sequence[Any],
|
|
202
|
+
endpoint: str | None = None,
|
|
203
|
+
params: dict[str, str] | None = None,
|
|
163
204
|
) -> dict[str, Any] | None:
|
|
164
205
|
"""GET one record by key URL — the delegate-view-safe read (B9).
|
|
165
206
|
|
|
@@ -167,10 +208,12 @@ class AcumaticaClient:
|
|
|
167
208
|
scope maps to a BQL-delegate view; the key-URL form skips the
|
|
168
209
|
optimizer and returns the full record (verified vs 26.101.0225).
|
|
169
210
|
Returns None when no record matches — the server answers that with
|
|
170
|
-
a 500 NoEntitySatisfiesTheConditionException, not a 404.
|
|
211
|
+
a 500 NoEntitySatisfiesTheConditionException, not a 404. Detail
|
|
212
|
+
arrays only travel under a $expand param (T60), same as the list
|
|
213
|
+
GET.
|
|
171
214
|
"""
|
|
172
215
|
path = "/".join(quote(str(k), safe="") for k in keys)
|
|
173
|
-
r = self._http.get(f"{self._url(entity, endpoint)}/{path}")
|
|
216
|
+
r = self._http.get(f"{self._url(entity, endpoint)}/{path}", params=params)
|
|
174
217
|
if r.status_code == 500:
|
|
175
218
|
try:
|
|
176
219
|
missing = "NoEntitySatisfiesTheCondition" in r.json().get(
|
|
@@ -7,18 +7,34 @@ Baseline file format:
|
|
|
7
7
|
|
|
8
8
|
entity: Currency # entity name in the contract endpoint
|
|
9
9
|
key: CurrencyID # key field(s), string or list
|
|
10
|
-
endpoint: Bootstrap/1.
|
|
10
|
+
endpoint: Bootstrap/1.6.0 # optional: override the instance endpoint
|
|
11
11
|
records:
|
|
12
12
|
- CurrencyID: "CAD"
|
|
13
13
|
Description: Canadian Dollar
|
|
14
14
|
|
|
15
|
+
A record field holding a LIST is a detail array (T60) - each row a field
|
|
16
|
+
map, PUT with the whole record (the list itself never value-wrapped).
|
|
17
|
+
Every list field needs a detail_keys entry naming the field that
|
|
18
|
+
identifies its rows; diff matches rows by that key, order-insensitive,
|
|
19
|
+
and unlike top-level records an extra live detail row IS drift - the
|
|
20
|
+
record owns its list:
|
|
21
|
+
|
|
22
|
+
entity: KitSpecification
|
|
23
|
+
key: [KitInventoryID, RevisionID]
|
|
24
|
+
detail_keys: { StockComponents: ComponentID }
|
|
25
|
+
records:
|
|
26
|
+
- KitInventoryID: GW-EDGE
|
|
27
|
+
RevisionID: V1
|
|
28
|
+
StockComponents:
|
|
29
|
+
- { ComponentID: MB-CM4, ComponentQty: 1 }
|
|
30
|
+
|
|
15
31
|
Action file format (setup/*.yaml) - desired state realized by a contract
|
|
16
32
|
action plus a done_when live-state probe, for setup verbs a keyed PUT
|
|
17
33
|
cannot express (calendar generation and the like):
|
|
18
34
|
|
|
19
35
|
action: GenerateCalendar # action name on the endpoint entity
|
|
20
36
|
entity: MasterCalendar # entity the action hangs off
|
|
21
|
-
endpoint: Bootstrap/1.
|
|
37
|
+
endpoint: Bootstrap/1.6.0 # optional: override the instance endpoint
|
|
22
38
|
record: { FinancialYear: 2026 }
|
|
23
39
|
parameters: { FromYear: 2026, ToYear: 2026 } # optional
|
|
24
40
|
done_when: { filter: "FinancialYear eq '2026'" }
|
|
@@ -85,6 +101,7 @@ class BaselineFile(Model):
|
|
|
85
101
|
keys: list[str] = Field(alias="key")
|
|
86
102
|
records: list[dict[str, Any]]
|
|
87
103
|
endpoint: str | None = None # bootstrap YAML targets the custom endpoint
|
|
104
|
+
detail_keys: dict[str, str] | None = None # {ListField: RowKeyField} (T60)
|
|
88
105
|
|
|
89
106
|
@field_validator("keys", mode="before")
|
|
90
107
|
@classmethod
|
|
@@ -109,8 +126,40 @@ class BaselineFile(Model):
|
|
|
109
126
|
"identify each record"
|
|
110
127
|
)
|
|
111
128
|
seen.add(ident)
|
|
129
|
+
self._check_details(i, record)
|
|
112
130
|
return self
|
|
113
131
|
|
|
132
|
+
def _check_details(self, i: int, record: dict[str, Any]) -> None:
|
|
133
|
+
# T60, the V25 sibling for detail arrays: every list field needs a
|
|
134
|
+
# detail_keys entry (diff cannot match rows without one) and that
|
|
135
|
+
# key must identify each source row - a dup diffs as permanent
|
|
136
|
+
# false drift exactly like B21's top-level class
|
|
137
|
+
for field, value in record.items():
|
|
138
|
+
if not isinstance(value, list):
|
|
139
|
+
continue
|
|
140
|
+
key = (self.detail_keys or {}).get(field)
|
|
141
|
+
if key is None:
|
|
142
|
+
raise ValueError(
|
|
143
|
+
f"entity '{self.entity}': records[{i}].{field} is a "
|
|
144
|
+
"detail list but has no detail_keys entry - add "
|
|
145
|
+
f"detail_keys: {{{field}: <RowKeyField>}}"
|
|
146
|
+
)
|
|
147
|
+
seen_rows: set[str] = set()
|
|
148
|
+
for j, row in enumerate(value):
|
|
149
|
+
if not isinstance(row, dict) or key not in row:
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"entity '{self.entity}': records[{i}].{field}[{j}] "
|
|
152
|
+
f"missing detail key field '{key}'"
|
|
153
|
+
)
|
|
154
|
+
ident = str(row[key])
|
|
155
|
+
if ident in seen_rows:
|
|
156
|
+
raise ValueError(
|
|
157
|
+
f"entity '{self.entity}': records[{i}].{field}[{j}] "
|
|
158
|
+
f"duplicates detail key [{ident}] - the detail key "
|
|
159
|
+
"must identify each row"
|
|
160
|
+
)
|
|
161
|
+
seen_rows.add(ident)
|
|
162
|
+
|
|
114
163
|
|
|
115
164
|
class DoneProbe(Model):
|
|
116
165
|
"""The done_when live-state probe: entity/endpoint default to the action's."""
|
|
@@ -169,8 +218,37 @@ def _norm(value: Any) -> str:
|
|
|
169
218
|
def _filter_for(record: dict[str, Any], keys: list[str]) -> str:
|
|
170
219
|
# callers pass single-view key sets only: a conjunction spanning the
|
|
171
220
|
# entity's views answers 200 [] (B14), so _fetch filters on the first
|
|
172
|
-
# key alone and matches the rest client-side
|
|
173
|
-
|
|
221
|
+
# key alone and matches the rest client-side. Literal typing follows
|
|
222
|
+
# the YAML scalar type: bools and numbers travel bare - a quoted
|
|
223
|
+
# 'false' against Edm.Boolean answers 500 "binary operator with
|
|
224
|
+
# incompatible types" (T61 - INPreferences keyed on HoldEntry), and
|
|
225
|
+
# numeric Edm types are the same class. Strings stay quoted, so
|
|
226
|
+
# numeric-looking codes ('000000') are unaffected.
|
|
227
|
+
def literal(value: Any) -> str:
|
|
228
|
+
if isinstance(value, bool):
|
|
229
|
+
return str(value).lower()
|
|
230
|
+
if isinstance(value, int | float):
|
|
231
|
+
return str(value)
|
|
232
|
+
return f"'{value}'"
|
|
233
|
+
|
|
234
|
+
return " and ".join(f"{k} eq {literal(record[k])}" for k in keys)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _expand_paths(record: dict[str, Any], prefix: str = "") -> list[str]:
|
|
238
|
+
"""$expand paths a record's shape demands (T60/T65).
|
|
239
|
+
|
|
240
|
+
A list field is a detail array - expands by name; a dict field is a
|
|
241
|
+
linked entity - expands by name plus the slash path of every nested
|
|
242
|
+
dict (`MainContact`, `MainContact/Address`).
|
|
243
|
+
"""
|
|
244
|
+
paths: list[str] = []
|
|
245
|
+
for field, value in record.items():
|
|
246
|
+
if isinstance(value, list):
|
|
247
|
+
paths.append(f"{prefix}{field}")
|
|
248
|
+
elif isinstance(value, dict):
|
|
249
|
+
paths.append(f"{prefix}{field}")
|
|
250
|
+
paths.extend(_expand_paths(value, f"{prefix}{field}/"))
|
|
251
|
+
return sorted(paths)
|
|
174
252
|
|
|
175
253
|
|
|
176
254
|
def _probe(client: AcumaticaClient, action: ActionFile) -> bool:
|
|
@@ -223,11 +301,50 @@ def apply(
|
|
|
223
301
|
if dry_run:
|
|
224
302
|
output.data(f" would PUT {baseline.entity} [{label}]")
|
|
225
303
|
else:
|
|
226
|
-
|
|
304
|
+
body = record
|
|
305
|
+
if any(isinstance(v, list) for v in record.values()):
|
|
306
|
+
body = _with_detail_ids(client, baseline, record)
|
|
307
|
+
client.put(baseline.entity, body, endpoint=baseline.endpoint)
|
|
227
308
|
output.data(f" PUT {baseline.entity} [{label}]")
|
|
228
309
|
return len(baseline.records)
|
|
229
310
|
|
|
230
311
|
|
|
312
|
+
def _with_detail_ids(
|
|
313
|
+
client: AcumaticaClient, baseline: BaselineFile, record: dict[str, Any]
|
|
314
|
+
) -> dict[str, Any]:
|
|
315
|
+
"""Source record + live detail-row ids — the detail upsert handle (T60).
|
|
316
|
+
|
|
317
|
+
The contract API matches detail rows by row GUID only: a re-PUT
|
|
318
|
+
without ids re-INSERTS every row (live-verified on KitSpecification —
|
|
319
|
+
500 "Component Item must be unique"). So apply pre-fetches the live
|
|
320
|
+
record, injects each matching live row's `id` (matched by the
|
|
321
|
+
detail_keys field), and appends `{id, delete: true}` rows for live
|
|
322
|
+
rows the source no longer claims — the record owns its list (V4
|
|
323
|
+
detail semantics), so apply converges exactly what diff would flag.
|
|
324
|
+
Record absent live → first PUT creates, rows travel id-less.
|
|
325
|
+
"""
|
|
326
|
+
live = _fetch(client, baseline, record)
|
|
327
|
+
if live is None:
|
|
328
|
+
return record
|
|
329
|
+
out = dict(record)
|
|
330
|
+
for field, rows in record.items():
|
|
331
|
+
if not isinstance(rows, list):
|
|
332
|
+
continue
|
|
333
|
+
key = (baseline.detail_keys or {})[field] # load-validated
|
|
334
|
+
live_ids: dict[str, Any] = {}
|
|
335
|
+
for live_row in live.get(field) or []:
|
|
336
|
+
value = live_row.get(key)
|
|
337
|
+
if isinstance(value, dict) and "value" in value and "id" in live_row:
|
|
338
|
+
live_ids[_norm(value["value"])] = live_row["id"]
|
|
339
|
+
merged: list[dict[str, Any]] = []
|
|
340
|
+
for row in rows:
|
|
341
|
+
row_id = live_ids.pop(_norm(row[key]), None)
|
|
342
|
+
merged.append({**row, "id": row_id} if row_id is not None else row)
|
|
343
|
+
merged.extend({"id": row_id, "delete": True} for row_id in live_ids.values())
|
|
344
|
+
out[field] = merged
|
|
345
|
+
return out
|
|
346
|
+
|
|
347
|
+
|
|
231
348
|
def _fetch(
|
|
232
349
|
client: AcumaticaClient, baseline: BaselineFile, record: dict[str, Any]
|
|
233
350
|
) -> dict[str, Any] | None:
|
|
@@ -244,18 +361,30 @@ def _fetch(
|
|
|
244
361
|
CuryRecords, B9) 500 on that optimized export; the key-URL
|
|
245
362
|
single-record GET skips the optimizer, so diff falls back to it on
|
|
246
363
|
exactly that error (V4: read-back must survive delegate-view entities).
|
|
364
|
+
|
|
365
|
+
Detail arrays and linked entities only travel under $expand
|
|
366
|
+
(T60/T65): without it every GET answers top-level scalars alone,
|
|
367
|
+
diff would report each source detail row or nested field missing
|
|
368
|
+
and apply's id-injection would see nothing to match. The expand set
|
|
369
|
+
derives from the record's own shape - a list field expands by name,
|
|
370
|
+
a dict field by its slash path (`MainContact/Address`).
|
|
247
371
|
"""
|
|
372
|
+
params = {"$filter": _filter_for(record, baseline.keys[:1])}
|
|
373
|
+
expand = _expand_paths(record)
|
|
374
|
+
if expand:
|
|
375
|
+
params["$expand"] = ",".join(expand)
|
|
248
376
|
try:
|
|
249
377
|
live = client.get_list(
|
|
250
|
-
baseline.entity,
|
|
251
|
-
params={"$filter": _filter_for(record, baseline.keys[:1])},
|
|
252
|
-
endpoint=baseline.endpoint,
|
|
378
|
+
baseline.entity, params=params, endpoint=baseline.endpoint
|
|
253
379
|
)
|
|
254
380
|
except RuntimeError as err:
|
|
255
381
|
if OPTIMIZATION_500 not in str(err):
|
|
256
382
|
raise
|
|
257
383
|
return client.get_record(
|
|
258
|
-
baseline.entity,
|
|
384
|
+
baseline.entity,
|
|
385
|
+
[record[k] for k in baseline.keys],
|
|
386
|
+
baseline.endpoint,
|
|
387
|
+
params={"$expand": params["$expand"]} if expand else None,
|
|
259
388
|
)
|
|
260
389
|
for row in live:
|
|
261
390
|
actual = unwrap(row)
|
|
@@ -290,10 +419,70 @@ def diff(client: AcumaticaClient, baseline: BaselineFile | ActionFile) -> list[s
|
|
|
290
419
|
continue
|
|
291
420
|
actual = unwrap(live)
|
|
292
421
|
for field, expected in record.items():
|
|
293
|
-
if
|
|
422
|
+
if isinstance(expected, list):
|
|
423
|
+
key = (baseline.detail_keys or {})[field] # load-validated
|
|
424
|
+
live_rows = actual.get(field, [])
|
|
425
|
+
drifts.extend(_diff_details(label, field, key, expected, live_rows))
|
|
426
|
+
elif isinstance(expected, dict):
|
|
427
|
+
drifts.extend(
|
|
428
|
+
_diff_nested(f"{label}.{field}", expected, actual.get(field))
|
|
429
|
+
)
|
|
430
|
+
elif field not in actual:
|
|
294
431
|
drifts.append(f"{label}.{field}: not returned by endpoint")
|
|
295
432
|
elif _norm(actual[field]) != _norm(expected):
|
|
296
433
|
drifts.append(
|
|
297
434
|
f"{label}.{field}: source={expected!r} live={actual[field]!r}"
|
|
298
435
|
)
|
|
299
436
|
return drifts
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _diff_nested(path: str, expected: dict[str, Any], live: Any) -> list[str]:
|
|
440
|
+
"""Linked-entity drift (T65): recurse source-side fields only."""
|
|
441
|
+
if not isinstance(live, dict):
|
|
442
|
+
return [f"{path}: not returned by endpoint"]
|
|
443
|
+
drifts: list[str] = []
|
|
444
|
+
for field, want in expected.items():
|
|
445
|
+
if isinstance(want, dict):
|
|
446
|
+
drifts.extend(_diff_nested(f"{path}.{field}", want, live.get(field)))
|
|
447
|
+
elif field not in live:
|
|
448
|
+
drifts.append(f"{path}.{field}: not returned by endpoint")
|
|
449
|
+
elif _norm(live[field]) != _norm(want):
|
|
450
|
+
drifts.append(f"{path}.{field}: source={want!r} live={live[field]!r}")
|
|
451
|
+
return drifts
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def _diff_details(
|
|
455
|
+
label: str,
|
|
456
|
+
field: str,
|
|
457
|
+
key: str,
|
|
458
|
+
expected: list[dict[str, Any]],
|
|
459
|
+
live_rows: list[dict[str, Any]],
|
|
460
|
+
) -> list[str]:
|
|
461
|
+
"""Detail-array drift (T60): rows matched by detail key, order-insensitive.
|
|
462
|
+
|
|
463
|
+
Unlike top-level records (V4 exemption), an extra live detail row IS
|
|
464
|
+
drift - the record owns its list, apply cannot converge a live row the
|
|
465
|
+
source never claimed. Within a matched row only source-side fields
|
|
466
|
+
compare (server-derived LineNbr and ids stay omitted from source).
|
|
467
|
+
"""
|
|
468
|
+
drifts: list[str] = []
|
|
469
|
+
live_by_key = {_norm(row[key]): row for row in live_rows if key in row}
|
|
470
|
+
for row in expected:
|
|
471
|
+
ident = _norm(row[key])
|
|
472
|
+
live_row = live_by_key.pop(ident, None)
|
|
473
|
+
if live_row is None:
|
|
474
|
+
drifts.append(f"{label}.{field}[{row[key]}]: missing on tenant")
|
|
475
|
+
continue
|
|
476
|
+
for sub, want in row.items():
|
|
477
|
+
if sub not in live_row:
|
|
478
|
+
drifts.append(
|
|
479
|
+
f"{label}.{field}[{row[key]}].{sub}: not returned by endpoint"
|
|
480
|
+
)
|
|
481
|
+
elif _norm(live_row[sub]) != _norm(want):
|
|
482
|
+
drifts.append(
|
|
483
|
+
f"{label}.{field}[{row[key]}].{sub}: "
|
|
484
|
+
f"source={want!r} live={live_row[sub]!r}"
|
|
485
|
+
)
|
|
486
|
+
for ident in live_by_key:
|
|
487
|
+
drifts.append(f"{label}.{field}[{ident}]: extra on tenant")
|
|
488
|
+
return drifts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# General Ledger preferences (GL102000) via the custom Bootstrap/1.
|
|
1
|
+
# General Ledger preferences (GL102000) via the custom Bootstrap/1.6.0
|
|
2
2
|
# endpoint (the per-file endpoint: override) - the Default endpoint has
|
|
3
3
|
# no GL-setup entity, and every Finance screen throws
|
|
4
4
|
# PXSetupNotEnteredException until the GLSetup singleton row exists. The
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# referenced here must exist.
|
|
13
13
|
entity: GLPreferences
|
|
14
14
|
key: RetEarnAccountID
|
|
15
|
-
endpoint: Bootstrap/1.
|
|
15
|
+
endpoint: Bootstrap/1.6.0
|
|
16
16
|
records:
|
|
17
17
|
- RetEarnAccountID: '32000'
|
|
18
18
|
YtdNetIncAccountID: '33000'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Org-ledger link (GL201500) via the custom Bootstrap/1.
|
|
1
|
+
# Org-ledger link (GL201500) via the custom Bootstrap/1.6.0 endpoint (the
|
|
2
2
|
# per-file endpoint: override). The Default endpoint's Ledger.Companies
|
|
3
3
|
# detail is write-tolerated then silently dropped (PUT answers 200 and
|
|
4
4
|
# echoes the row, the link table stays empty), so the link writes through
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# (company.yaml).
|
|
22
22
|
entity: LedgerCompany
|
|
23
23
|
key: [LedgerCD, OrganizationID]
|
|
24
|
-
endpoint: Bootstrap/1.
|
|
24
|
+
endpoint: Bootstrap/1.6.0
|
|
25
25
|
records:
|
|
26
26
|
- LedgerCD: ACTUAL
|
|
27
27
|
OrganizationID: COMPANY
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/company.yaml
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Company (CS101500) via the custom Bootstrap/1.
|
|
1
|
+
# Company (CS101500) via the custom Bootstrap/1.6.0 endpoint (the per-file
|
|
2
2
|
# endpoint: override) - built-in endpoints cannot create the first
|
|
3
3
|
# organization on a virgin tenant. List values are the EXTERNAL labels
|
|
4
4
|
# ('Without Branches', not the DAC's 'WithoutBranches'); CountryID feeds
|
|
5
5
|
# the org's Main Address - required on first save.
|
|
6
6
|
entity: Company
|
|
7
7
|
key: AcctCD
|
|
8
|
-
endpoint: Bootstrap/1.
|
|
8
|
+
endpoint: Bootstrap/1.6.0
|
|
9
9
|
records:
|
|
10
10
|
- AcctCD: COMPANY
|
|
11
11
|
AcctName: Example Company
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/credit-terms.yaml
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Credit terms (CS206500) via the custom Bootstrap/1.
|
|
1
|
+
# Credit terms (CS206500) via the custom Bootstrap/1.6.0 endpoint (the
|
|
2
2
|
# per-file endpoint: override) - the Default endpoint has no credit-terms
|
|
3
3
|
# entity. List values are the EXTERNAL labels: VisibleTo = All, Vendors,
|
|
4
4
|
# Customers, Disabled; DueType/DiscType = Fixed Number of Days, Day of
|
|
5
5
|
# Next Month, End of Month, ...
|
|
6
6
|
entity: CreditTerms
|
|
7
7
|
key: TermsID
|
|
8
|
-
endpoint: Bootstrap/1.
|
|
8
|
+
endpoint: Bootstrap/1.6.0
|
|
9
9
|
records:
|
|
10
10
|
- TermsID: NET30
|
|
11
11
|
Descr: Net 30 Days
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/10-subaccounts.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/20-accounts.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/40-ledger.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/baseline/90-uoms.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.4.0 → acumatica_cli-0.6.0}/src/acumatica_cli/templates/bootstrap/features.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|