acumatica-cli 0.28.0__tar.gz → 0.29.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.28.0 → acumatica_cli-0.29.0}/PKG-INFO +2 -2
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/README.md +1 -1
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/pyproject.toml +1 -1
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/pyproject.toml.orig +1 -1
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/bootstrap.py +2 -2
- acumatica_cli-0.29.0/src/acumatica_cli/bootstrap_plugin.cs +147 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/bootstrap_project.xml +42 -11
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/config.py +5 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/extract.py +7 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/seed.py +59 -1
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/seed_catalog.yaml +37 -12
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/README.md +1 -1
- acumatica_cli-0.29.0/src/acumatica_cli/templates/config/baseline/91-company-packaging.yaml +8 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/91-users.yaml +0 -1
- acumatica_cli-0.29.0/src/acumatica_cli/templates/config/master/92-role-users.yaml +9 -0
- acumatica_cli-0.28.0/src/acumatica_cli/bootstrap_plugin.cs +0 -74
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/__init__.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/cli.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/client.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/firstlogin.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/inventory.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/models.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/output.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/reconcile.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/run.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/snapshot_map.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/state.py +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/20-accounts.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/baseline/90-uoms.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/bootstrap/company.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/bootstrap/features.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/bootstrap/segmented-key.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/05-numbering-sequences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/40-posting-classes.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/50-warehouse.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/54-item-classes.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/58-order-types.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/63-cash-account.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/75-vendors.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/76-customers.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/80-stock-items-parts.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/85-kit-specifications.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/master/90-roles.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/env +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/gitignore +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/overlays/README.md +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/overlays/default-24.200.001/README.md +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/overlays/default-24.200.001/scenario/30-build.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/10-seed-capital.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/20-buy.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/30-build.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/40-sell.yaml +0 -0
- {acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/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.
|
|
3
|
+
Version: 0.29.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>
|
|
@@ -196,7 +196,7 @@ There is no `--flavor`.
|
|
|
196
196
|
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms (no `project.xml`) |
|
|
197
197
|
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs |
|
|
198
198
|
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
199
|
-
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users`) |
|
|
199
|
+
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users` then `92-role-users`) |
|
|
200
200
|
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
201
201
|
| `config/views/` | observer views for `acu state` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
202
202
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
@@ -178,7 +178,7 @@ There is no `--flavor`.
|
|
|
178
178
|
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms (no `project.xml`) |
|
|
179
179
|
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs |
|
|
180
180
|
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
181
|
-
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users`) |
|
|
181
|
+
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users` then `92-role-users`) |
|
|
182
182
|
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
183
183
|
| `config/views/` | observer views for `acu state` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
184
184
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "acumatica-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.29.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
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
@@ -9,7 +9,7 @@ cannot write CS100000 at all (T3 verdict) — and whose Bootstrap contract
|
|
|
9
9
|
endpoint exposes the seeding surface (serialization verified T12).
|
|
10
10
|
|
|
11
11
|
Bootstrap endpoint contract is package SoT (V2/V21/T178): always the
|
|
12
|
-
packaged full company ``bootstrap_project.xml`` (``Bootstrap/1.
|
|
12
|
+
packaged full company ``bootstrap_project.xml`` (``Bootstrap/1.10.0``).
|
|
13
13
|
Data-repo ``config/bootstrap/project.xml`` or ``bootstrap/project.xml`` is
|
|
14
14
|
not a seed — present → hard error naming package SoT (no dual contract line).
|
|
15
15
|
|
|
@@ -68,7 +68,7 @@ def _bootstrap_file(root: Path, name: str) -> Path | None:
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
def packaged_contract_xml() -> bytes:
|
|
71
|
-
"""The CLI-shipped full company Bootstrap contract (``Bootstrap/1.
|
|
71
|
+
"""The CLI-shipped full company Bootstrap contract (``Bootstrap/1.10.0``)."""
|
|
72
72
|
return (resources.files("acumatica_cli") / "bootstrap_project.xml").read_bytes()
|
|
73
73
|
|
|
74
74
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// acu bootstrap CustomizationPlugin (SPEC T11).
|
|
2
|
+
//
|
|
3
|
+
// Runs in-process on customization publish - the one write path to
|
|
4
|
+
// FeaturesSet that works: the contract API cannot persist features no
|
|
5
|
+
// matter what endpoint fronts CS100000 (T3 verdict, docs/rest-api.md).
|
|
6
|
+
//
|
|
7
|
+
// Deliberately writes through PXDatabase, not FeaturesMaint: the graph
|
|
8
|
+
// save collides with the publish pipeline's concurrent plugin invocations
|
|
9
|
+
// ("Another process has added the 'FeaturesSet' record" - observed live,
|
|
10
|
+
// 26.101.0225) and nothing persists. A keyed row write is deterministic
|
|
11
|
+
// and idempotent: update the existing row, insert when absent. All 205
|
|
12
|
+
// NOT NULL bit columns are filled reflectively (only ~136 carry DB
|
|
13
|
+
// defaults); Status = 0 means Validated (PXIntList, verified vs live).
|
|
14
|
+
//
|
|
15
|
+
// The Enabled set is NOT authored here (SPEC V2: feature flags are config
|
|
16
|
+
// "what", never tool source - B6): package_zip() substitutes the
|
|
17
|
+
// ACU_FEATURES sentinel below with the data repo's bootstrap/features.yaml
|
|
18
|
+
// list (built-in six when the file is absent) at package-build time.
|
|
19
|
+
using System;
|
|
20
|
+
using System.Collections;
|
|
21
|
+
using System.Collections.Generic;
|
|
22
|
+
using System.Reflection;
|
|
23
|
+
using PX.Data;
|
|
24
|
+
using PX.Objects.CS;
|
|
25
|
+
using PX.SM;
|
|
26
|
+
|
|
27
|
+
namespace AcuBootstrap
|
|
28
|
+
{
|
|
29
|
+
public class AcuBootstrapPlugin : Customization.CustomizationPlugin
|
|
30
|
+
{
|
|
31
|
+
private static readonly HashSet<string> Enabled = new HashSet<string>
|
|
32
|
+
{
|
|
33
|
+
/*ACU_FEATURES*/
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
public override void UpdateDatabase()
|
|
37
|
+
{
|
|
38
|
+
var flags = new List<PXDataFieldAssign>();
|
|
39
|
+
var known = new HashSet<string>();
|
|
40
|
+
foreach (PropertyInfo prop in typeof(FeaturesSet).GetProperties())
|
|
41
|
+
{
|
|
42
|
+
if (prop.PropertyType == typeof(bool?))
|
|
43
|
+
{
|
|
44
|
+
known.Add(prop.Name);
|
|
45
|
+
flags.Add(new PXDataFieldAssign(
|
|
46
|
+
prop.Name, PXDbType.Bit, Enabled.Contains(prop.Name)));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
foreach (string name in Enabled)
|
|
50
|
+
{
|
|
51
|
+
if (!known.Contains(name))
|
|
52
|
+
{
|
|
53
|
+
// silent-typo guard (T24): a misspelled features.yaml
|
|
54
|
+
// entry enables nothing - say so in the publish log
|
|
55
|
+
WriteLog("AcuBootstrap: unknown feature name '" + name
|
|
56
|
+
+ "' - no FeaturesSet property, nothing enabled");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
flags.Add(new PXDataFieldAssign("Status", PXDbType.Int, 0)); // Validated
|
|
60
|
+
|
|
61
|
+
using (var tx = new PXTransactionScope())
|
|
62
|
+
{
|
|
63
|
+
bool updated = PXDatabase.Update<FeaturesSet>(flags.ToArray());
|
|
64
|
+
if (!updated)
|
|
65
|
+
{
|
|
66
|
+
PXDatabase.Insert<FeaturesSet>(flags.ToArray());
|
|
67
|
+
WriteLog("AcuBootstrap: FeaturesSet row inserted (features enabled)");
|
|
68
|
+
}
|
|
69
|
+
else
|
|
70
|
+
{
|
|
71
|
+
WriteLog("AcuBootstrap: FeaturesSet row updated (features enabled)");
|
|
72
|
+
}
|
|
73
|
+
tx.Complete();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// V53/B33: mapped Role.Users / User.Roles PUT never writes
|
|
78
|
+
// UsersInRoles. Persist is a keyed PXDatabase write (same
|
|
79
|
+
// FeaturesSet idiom): ApplicationName='/' (ASP.NET membership).
|
|
80
|
+
public static void AssignUserToRole(string username, string rolename)
|
|
81
|
+
{
|
|
82
|
+
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(rolename))
|
|
83
|
+
{
|
|
84
|
+
throw new PXException(
|
|
85
|
+
"AssignUser requires Username and Rolename");
|
|
86
|
+
}
|
|
87
|
+
Guid userId = PXAccess.GetUserID();
|
|
88
|
+
DateTime now = DateTime.Now;
|
|
89
|
+
var update = new List<PXDataFieldParam>
|
|
90
|
+
{
|
|
91
|
+
new PXDataFieldRestrict("Username", PXDbType.NVarChar, username),
|
|
92
|
+
new PXDataFieldRestrict("Rolename", PXDbType.NVarChar, rolename),
|
|
93
|
+
new PXDataFieldRestrict("ApplicationName", PXDbType.VarChar, "/"),
|
|
94
|
+
new PXDataFieldAssign("LastModifiedByID", PXDbType.UniqueIdentifier, userId),
|
|
95
|
+
new PXDataFieldAssign("LastModifiedByScreenID", PXDbType.Char, "SM201005"),
|
|
96
|
+
new PXDataFieldAssign("LastModifiedDateTime", PXDbType.DateTime, now),
|
|
97
|
+
};
|
|
98
|
+
bool updated = PXDatabase.Update<UsersInRoles>(update.ToArray());
|
|
99
|
+
if (!updated)
|
|
100
|
+
{
|
|
101
|
+
var insert = new List<PXDataFieldAssign>
|
|
102
|
+
{
|
|
103
|
+
new PXDataFieldAssign("Username", PXDbType.NVarChar, username),
|
|
104
|
+
new PXDataFieldAssign("Rolename", PXDbType.NVarChar, rolename),
|
|
105
|
+
new PXDataFieldAssign("ApplicationName", PXDbType.VarChar, "/"),
|
|
106
|
+
new PXDataFieldAssign("CreatedByID", PXDbType.UniqueIdentifier, userId),
|
|
107
|
+
new PXDataFieldAssign("CreatedByScreenID", PXDbType.Char, "SM201005"),
|
|
108
|
+
new PXDataFieldAssign("CreatedDateTime", PXDbType.DateTime, now),
|
|
109
|
+
new PXDataFieldAssign("LastModifiedByID", PXDbType.UniqueIdentifier, userId),
|
|
110
|
+
new PXDataFieldAssign("LastModifiedByScreenID", PXDbType.Char, "SM201005"),
|
|
111
|
+
new PXDataFieldAssign("LastModifiedDateTime", PXDbType.DateTime, now),
|
|
112
|
+
};
|
|
113
|
+
PXDatabase.Insert<UsersInRoles>(insert.ToArray());
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public class AssignUserFilter : PXBqlTable, IBqlTable
|
|
119
|
+
{
|
|
120
|
+
[PXString(256, IsUnicode = true, InputMask = "")]
|
|
121
|
+
[PXUIField(DisplayName = "Username")]
|
|
122
|
+
public virtual string Username { get; set; }
|
|
123
|
+
public abstract class username : PX.Data.BQL.BqlString.Field<username> { }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Action lives on RoleAccess so Base.Roles.Current is the SM201005 header.
|
|
127
|
+
public class AcuRoleAccessExt : PXGraphExtension<RoleAccess>
|
|
128
|
+
{
|
|
129
|
+
public static bool IsActive() => true;
|
|
130
|
+
|
|
131
|
+
public PXFilter<AssignUserFilter> AssignUserParams;
|
|
132
|
+
|
|
133
|
+
public PXAction<Roles> assignUser;
|
|
134
|
+
|
|
135
|
+
[PXButton(CommitChanges = true)]
|
|
136
|
+
[PXUIField(DisplayName = "Assign User", Visible = false)]
|
|
137
|
+
protected virtual IEnumerable AssignUser(PXAdapter adapter)
|
|
138
|
+
{
|
|
139
|
+
string username = AssignUserParams.Current != null
|
|
140
|
+
? AssignUserParams.Current.Username : null;
|
|
141
|
+
Roles role = Base.Roles.Current;
|
|
142
|
+
string rolename = role != null ? role.Rolename : null;
|
|
143
|
+
AcuBootstrapPlugin.AssignUserToRole(username, rolename);
|
|
144
|
+
return adapter.Get();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
T204 bumps 1.4.0 -> 1.5.0 for SegmentedKey, gh #30 / V50;
|
|
9
9
|
T207 bumps 1.5.0 -> 1.6.0 for SegmentedKey Detail view (B28);
|
|
10
10
|
gh #34 bumps 1.6.0 -> 1.7.0 for Company DecPlQty + WeightUOM/VolumeUOM
|
|
11
|
-
(CS101500 commonsetup; kit BOM milligram-scale KG needs qty precision 3)
|
|
11
|
+
(CS101500 commonsetup; kit BOM milligram-scale KG needs qty precision 3);
|
|
12
|
+
gh #35 bumps 1.7.0 -> 1.8.0 for User.Roles -> RolesByUser (UsersInRoles)
|
|
13
|
+
and drops Selected (AllowedRoles was EPLoginTypeAllowsRole / EP202500);
|
|
14
|
+
T228 bumps 1.8.0 -> 1.9.0 for Role.Users -> UsersByRole (SM201005
|
|
15
|
+
Users tab; mapped-detail PUT is a no-op — B33) and 1.9.0 -> 1.10.0
|
|
16
|
+
for Role AssignUser action (PXDatabase UsersInRoles persist).
|
|
12
17
|
|
|
13
18
|
package_zip() (bootstrap.py) prefers data-repo bootstrap/project.xml when
|
|
14
19
|
present; otherwise this packaged template is the fallback so config init,
|
|
@@ -48,9 +53,13 @@
|
|
|
48
53
|
Username; identity FirstName/LastName/Email + IsApproved +
|
|
49
54
|
PasswordNeverExpires + PasswordChangeOnNextLogin; Password write-only
|
|
50
55
|
(extract/diff policy = V39/T147).
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
- User detail Roles -> RolesByUser (GET/diff shape; PUT never
|
|
57
|
+
writes UsersInRoles — B31/B32/B33). Persist = Role action
|
|
58
|
+
AssignUser -> PXDatabase UsersInRoles (ApplicationName='/').
|
|
59
|
+
Role.Users -> UsersByRole is the mapped-detail fixture (silent
|
|
60
|
+
200). Apply order Role then User then Role.Users
|
|
61
|
+
(V22 prefixes 90/91/92). Never AllowedRoles
|
|
62
|
+
(EPLoginTypeAllowsRole / EP202500 allow-list; gh #35 / V53).
|
|
54
63
|
|
|
55
64
|
T150 NumberingSequence (gh #25) - Default endpoint has no numbering
|
|
56
65
|
surface; CS201010 Numbering Sequences (NumberingMaint — NOT the
|
|
@@ -112,7 +121,7 @@
|
|
|
112
121
|
-->
|
|
113
122
|
<Customization level="" description="acu bootstrap: CustomizationPlugin enables features on publish; Bootstrap endpoint exposes full company surface (company + credit terms + financial currency + GL chain + module preferences + vendor class + statement cycle + warehouse + order type + cash account + role + user + membership + numbering sequence + segmented key)" product-version="26.101">
|
|
114
123
|
<EntityEndpoint>
|
|
115
|
-
<Endpoint xmlns="http://www.acumatica.com/entity/maintenance/5.31" name="Bootstrap" version="1.
|
|
124
|
+
<Endpoint xmlns="http://www.acumatica.com/entity/maintenance/5.31" name="Bootstrap" version="1.10.0" systemContractVersion="4">
|
|
116
125
|
<TopLevelEntity name="Company" screen="CS101500">
|
|
117
126
|
<Fields>
|
|
118
127
|
<Field name="AcctCD" type="StringValue" />
|
|
@@ -1019,6 +1028,7 @@
|
|
|
1019
1028
|
<Fields>
|
|
1020
1029
|
<Field name="Rolename" type="StringValue" />
|
|
1021
1030
|
<Field name="Descr" type="StringValue" />
|
|
1031
|
+
<Field name="Users" type="RoleUser[]" />
|
|
1022
1032
|
</Fields>
|
|
1023
1033
|
<Mappings>
|
|
1024
1034
|
<Mapping field="Rolename">
|
|
@@ -1027,8 +1037,33 @@
|
|
|
1027
1037
|
<Mapping field="Descr">
|
|
1028
1038
|
<To object="Roles" field="Descr" />
|
|
1029
1039
|
</Mapping>
|
|
1040
|
+
<Mapping field="Users">
|
|
1041
|
+
<To object="UsersByRole" field="" />
|
|
1042
|
+
</Mapping>
|
|
1030
1043
|
</Mappings>
|
|
1044
|
+
<Actions>
|
|
1045
|
+
<Action name="AssignUser" mappedTo="assignUser" isDefault="false">
|
|
1046
|
+
<Fields>
|
|
1047
|
+
<Field name="Username" type="StringValue" />
|
|
1048
|
+
</Fields>
|
|
1049
|
+
<Mappings>
|
|
1050
|
+
<Mapping field="Username">
|
|
1051
|
+
<To object="AssignUserParams" field="Username" />
|
|
1052
|
+
</Mapping>
|
|
1053
|
+
</Mappings>
|
|
1054
|
+
</Action>
|
|
1055
|
+
</Actions>
|
|
1031
1056
|
</TopLevelEntity>
|
|
1057
|
+
<Detail name="RoleUser">
|
|
1058
|
+
<Fields>
|
|
1059
|
+
<Field name="Username" type="StringValue" />
|
|
1060
|
+
</Fields>
|
|
1061
|
+
<Mappings>
|
|
1062
|
+
<Mapping field="Username">
|
|
1063
|
+
<To object="UsersByRole" field="Username" />
|
|
1064
|
+
</Mapping>
|
|
1065
|
+
</Mappings>
|
|
1066
|
+
</Detail>
|
|
1032
1067
|
<TopLevelEntity name="User" screen="SM201010">
|
|
1033
1068
|
<Fields>
|
|
1034
1069
|
<Field name="Username" type="StringValue" />
|
|
@@ -1067,21 +1102,17 @@
|
|
|
1067
1102
|
<To object="UserList" field="Password" />
|
|
1068
1103
|
</Mapping>
|
|
1069
1104
|
<Mapping field="Roles">
|
|
1070
|
-
<To object="
|
|
1105
|
+
<To object="RolesByUser" field="" />
|
|
1071
1106
|
</Mapping>
|
|
1072
1107
|
</Mappings>
|
|
1073
1108
|
</TopLevelEntity>
|
|
1074
1109
|
<Detail name="UserRole">
|
|
1075
1110
|
<Fields>
|
|
1076
1111
|
<Field name="Rolename" type="StringValue" />
|
|
1077
|
-
<Field name="Selected" type="BooleanValue" />
|
|
1078
1112
|
</Fields>
|
|
1079
1113
|
<Mappings>
|
|
1080
1114
|
<Mapping field="Rolename">
|
|
1081
|
-
<To object="
|
|
1082
|
-
</Mapping>
|
|
1083
|
-
<Mapping field="Selected">
|
|
1084
|
-
<To object="AllowedRoles" field="Selected" />
|
|
1115
|
+
<To object="RolesByUser" field="Rolename" />
|
|
1085
1116
|
</Mapping>
|
|
1086
1117
|
</Mappings>
|
|
1087
1118
|
</Detail>
|
|
@@ -70,6 +70,10 @@ INIT_TEMPLATES = (
|
|
|
70
70
|
"config/baseline/60-ledger-company.yaml",
|
|
71
71
|
),
|
|
72
72
|
("config/baseline/90-uoms.yaml", "config/baseline/90-uoms.yaml"),
|
|
73
|
+
(
|
|
74
|
+
"config/baseline/91-company-packaging.yaml",
|
|
75
|
+
"config/baseline/91-company-packaging.yaml",
|
|
76
|
+
),
|
|
73
77
|
("config/setup/10-financial-year.yaml", "config/setup/10-financial-year.yaml"),
|
|
74
78
|
("config/setup/20-master-calendar.yaml", "config/setup/20-master-calendar.yaml"),
|
|
75
79
|
("config/setup/30-open-periods.yaml", "config/setup/30-open-periods.yaml"),
|
|
@@ -128,6 +132,7 @@ INIT_TEMPLATES = (
|
|
|
128
132
|
),
|
|
129
133
|
("config/master/90-roles.yaml", "config/master/90-roles.yaml"),
|
|
130
134
|
("config/master/91-users.yaml", "config/master/91-users.yaml"),
|
|
135
|
+
("config/master/92-role-users.yaml", "config/master/92-role-users.yaml"),
|
|
131
136
|
(
|
|
132
137
|
"config/views/10-trial-balance.yaml",
|
|
133
138
|
"config/views/10-trial-balance.yaml",
|
|
@@ -590,6 +590,13 @@ class _Extraction:
|
|
|
590
590
|
if not live:
|
|
591
591
|
self._skip(target, "no records")
|
|
592
592
|
continue
|
|
593
|
+
# V53: Role.Users GET may stay empty; do not emit identity-only
|
|
594
|
+
# 92-role-users.yaml that would drop authored AssignUser rows.
|
|
595
|
+
if spec.include == ["Users"] and not any(
|
|
596
|
+
isinstance(r.get("Users"), list) and r["Users"] for r in records
|
|
597
|
+
):
|
|
598
|
+
self._skip(target, "Users GET empty")
|
|
599
|
+
continue
|
|
593
600
|
self._emit(target, _render(spec, records), len(records))
|
|
594
601
|
produced.add(spec.file)
|
|
595
602
|
return produced
|
|
@@ -397,6 +397,10 @@ def apply(
|
|
|
397
397
|
records in the same file. Returns ``(ok_count, error_messages)`` —
|
|
398
398
|
never silent partial; caller exits 1 when any errors remain. Exit 2
|
|
399
399
|
stays drift (``diff`` only).
|
|
400
|
+
|
|
401
|
+
Role.Users mapped-detail PUT is a no-op (V53/B33). After the Role PUT,
|
|
402
|
+
apply invokes contract action ``AssignUser`` per Username so persist
|
|
403
|
+
is PXDatabase UsersInRoles, not the mapped detail.
|
|
400
404
|
"""
|
|
401
405
|
if isinstance(baseline, ActionFile):
|
|
402
406
|
return _apply_action(client, baseline, dry_run)
|
|
@@ -406,14 +410,23 @@ def apply(
|
|
|
406
410
|
label = ", ".join(str(record[k]) for k in baseline.keys)
|
|
407
411
|
if dry_run:
|
|
408
412
|
output.data(f" would PUT {baseline.entity} [{label}]")
|
|
409
|
-
|
|
413
|
+
try:
|
|
414
|
+
_assign_role_users(client, baseline, record, dry_run=True)
|
|
415
|
+
ok += 1
|
|
416
|
+
except RuntimeError as err:
|
|
417
|
+
msg = f"{baseline.entity} [{label}]: {err}"
|
|
418
|
+
output.error(msg)
|
|
419
|
+
errors.append(msg)
|
|
410
420
|
continue
|
|
411
421
|
try:
|
|
412
422
|
body = _put_body(client, baseline, record)
|
|
423
|
+
if baseline.entity == "Role":
|
|
424
|
+
body.pop("Users", None)
|
|
413
425
|
_put(client, baseline.entity, body, baseline.endpoint)
|
|
414
426
|
if baseline.entity == "Company":
|
|
415
427
|
client.refresh_after_company()
|
|
416
428
|
output.data(f" PUT {baseline.entity} [{label}]")
|
|
429
|
+
_assign_role_users(client, baseline, record, dry_run=False)
|
|
417
430
|
ok += 1
|
|
418
431
|
except RuntimeError as err:
|
|
419
432
|
msg = f"{baseline.entity} [{label}]: {err}"
|
|
@@ -422,6 +435,51 @@ def apply(
|
|
|
422
435
|
return ok, errors
|
|
423
436
|
|
|
424
437
|
|
|
438
|
+
def _assign_role_users(
|
|
439
|
+
client: AcumaticaClient,
|
|
440
|
+
baseline: BaselineFile,
|
|
441
|
+
record: dict[str, Any],
|
|
442
|
+
*,
|
|
443
|
+
dry_run: bool,
|
|
444
|
+
) -> None:
|
|
445
|
+
"""V53/B33: persist Role.Users via AssignUser, not mapped-detail PUT.
|
|
446
|
+
|
|
447
|
+
Additive-only: ``delete: true`` merge rows are skipped. Mapped GET of
|
|
448
|
+
Users may be empty, so extra live members are not a persist delete.
|
|
449
|
+
Role PUT strips ``Users`` so additive-only does not depend on B33.
|
|
450
|
+
"""
|
|
451
|
+
if baseline.entity != "Role":
|
|
452
|
+
return
|
|
453
|
+
users = record.get("Users")
|
|
454
|
+
if not isinstance(users, list):
|
|
455
|
+
return
|
|
456
|
+
rolename = record.get("Rolename")
|
|
457
|
+
if not isinstance(rolename, str) or not rolename:
|
|
458
|
+
return
|
|
459
|
+
to_assign: list[str] = []
|
|
460
|
+
for i, row in enumerate(users):
|
|
461
|
+
if isinstance(row, dict) and row.get("delete") is True:
|
|
462
|
+
continue
|
|
463
|
+
if not isinstance(row, dict):
|
|
464
|
+
raise RuntimeError(f"Users[{i}] is not a mapping")
|
|
465
|
+
username = row.get("Username")
|
|
466
|
+
if not isinstance(username, str) or not username:
|
|
467
|
+
raise RuntimeError(f"Users[{i}] missing Username")
|
|
468
|
+
to_assign.append(username)
|
|
469
|
+
for username in to_assign:
|
|
470
|
+
if dry_run:
|
|
471
|
+
output.data(f" would invoke AssignUser [{rolename}/{username}]")
|
|
472
|
+
continue
|
|
473
|
+
client.invoke(
|
|
474
|
+
"Role",
|
|
475
|
+
"AssignUser",
|
|
476
|
+
{"Rolename": rolename},
|
|
477
|
+
{"Username": username},
|
|
478
|
+
baseline.endpoint,
|
|
479
|
+
)
|
|
480
|
+
output.data(f" invoke AssignUser [{rolename}/{username}]")
|
|
481
|
+
|
|
482
|
+
|
|
425
483
|
def _put(
|
|
426
484
|
client: AcumaticaClient,
|
|
427
485
|
entity: str,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# entity contract entity name (the GET source and the emitted `entity:`)
|
|
7
7
|
# endpoint omitted = the instance Default endpoint; the symbolic name
|
|
8
8
|
# `bootstrap` stays symbolic in emitted files and resolves to
|
|
9
|
-
# the packaged full company Bootstrap/1.
|
|
9
|
+
# the packaged full company Bootstrap/1.10.0 at HTTP/load time
|
|
10
10
|
# (package SoT - V20/V21/T178; data-repo project.xml forbidden)
|
|
11
11
|
# keys key fields: the emitted `key:`, the record sort order, and
|
|
12
12
|
# the B9 fallback's $select projection; the tuple must
|
|
@@ -44,10 +44,9 @@ entities:
|
|
|
44
44
|
|
|
45
45
|
# config/bootstrap/ - the virgin-tenant phase via the custom Bootstrap
|
|
46
46
|
# endpoint: built-in endpoints cannot create the first organization (C).
|
|
47
|
-
# Company
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# fields that GET returns stay in include.
|
|
47
|
+
# Company identity first (bootstrap). Packaging qty/UOMs are a second
|
|
48
|
+
# Company PUT after 90-uoms.yaml (see that row). StockItem WeightUOM
|
|
49
|
+
# /VolumeUOM stay GET-omit (B26).
|
|
51
50
|
|
|
52
51
|
- entity: Company
|
|
53
52
|
endpoint: bootstrap
|
|
@@ -58,9 +57,6 @@ entities:
|
|
|
58
57
|
- OrganizationType
|
|
59
58
|
- BaseCuryID
|
|
60
59
|
- CountryID
|
|
61
|
-
- DecPlQty
|
|
62
|
-
- WeightUOM
|
|
63
|
-
- VolumeUOM
|
|
64
60
|
|
|
65
61
|
- entity: CreditTerms
|
|
66
62
|
endpoint: bootstrap
|
|
@@ -167,6 +163,20 @@ entities:
|
|
|
167
163
|
- Description
|
|
168
164
|
- L3Code
|
|
169
165
|
|
|
166
|
+
# Company packaging (gh #34 / V52): second PUT after UOMs so KG/LITER
|
|
167
|
+
# exist for CommonSetup_RowPersisting when DistributionModule is on.
|
|
168
|
+
# Include-partition of the same live Company row (warehouse-phase idiom).
|
|
169
|
+
# Mapped fields GET-return stay in include.
|
|
170
|
+
|
|
171
|
+
- entity: Company
|
|
172
|
+
endpoint: bootstrap
|
|
173
|
+
keys: [AcctCD]
|
|
174
|
+
file: config/baseline/91-company-packaging.yaml
|
|
175
|
+
include:
|
|
176
|
+
- DecPlQty
|
|
177
|
+
- WeightUOM
|
|
178
|
+
- VolumeUOM
|
|
179
|
+
|
|
170
180
|
# config/master/ - full packaged seed (T117). Multi-file Warehouse uses
|
|
171
181
|
# include field-partition (same live warehouse row, three apply phases).
|
|
172
182
|
# Multi-file StockItem uses OData filter-split on ItemClass.
|
|
@@ -522,10 +532,12 @@ entities:
|
|
|
522
532
|
- Active
|
|
523
533
|
- StockComponents
|
|
524
534
|
|
|
525
|
-
# config/master/ Role then User (V22 prefixes
|
|
526
|
-
# only — Default has no Role/User surface.
|
|
527
|
-
#
|
|
528
|
-
#
|
|
535
|
+
# config/master/ Role then User then Role.Users (V22 prefixes 90/91/92;
|
|
536
|
+
# T145/T146/T148/T228). Bootstrap only — Default has no Role/User surface.
|
|
537
|
+
# Persist = Role action AssignUser (PXDatabase UsersInRoles; T228/B33).
|
|
538
|
+
# User detail Roles is GET/diff shape (PUT never writes UsersInRoles —
|
|
539
|
+
# B31/B32/B33). Package 90-roles = full pre-build CompanyID=1
|
|
540
|
+
# Roles dump; 91-users demo soadmin identity; 92-role-users membership.
|
|
529
541
|
# Password is write-only on apply (V39/T147): include omits Password so
|
|
530
542
|
# extract never emits hashes (b64__Password also out of include).
|
|
531
543
|
|
|
@@ -551,6 +563,19 @@ entities:
|
|
|
551
563
|
- PasswordChangeOnNextLogin
|
|
552
564
|
- Roles
|
|
553
565
|
|
|
566
|
+
# Persist membership (T228/V53): apply Role.Users invokes AssignUser.
|
|
567
|
+
# Filter-split from 90-roles (Descr-only identity dump). Mapped-detail
|
|
568
|
+
# PUT never writes UsersInRoles (B31/B32/B33).
|
|
569
|
+
- entity: Role
|
|
570
|
+
endpoint: bootstrap
|
|
571
|
+
keys: [Rolename]
|
|
572
|
+
file: config/master/92-role-users.yaml
|
|
573
|
+
filter: Rolename eq 'SO Admin'
|
|
574
|
+
detail_keys:
|
|
575
|
+
Users: Username
|
|
576
|
+
include:
|
|
577
|
+
- Users
|
|
578
|
+
|
|
554
579
|
# config/setup/ - the GL action chain (T36/T37): financial-year setup,
|
|
555
580
|
# then calendar generation, then period activation; numbered prefixes
|
|
556
581
|
# mirror the verified apply order.
|
|
@@ -48,7 +48,7 @@ Bare `acu apply` / `acu diff` also prefer `config/` when those trees exist.
|
|
|
48
48
|
| `config/bootstrap/` | Company, features, credit terms (Bootstrap contract is package SoT — never scaffolded) |
|
|
49
49
|
| `config/baseline/` | GL foundation (COA, ledger, subaccounts, UOMs) |
|
|
50
50
|
| `config/setup/` | Financial year, master calendar, open periods |
|
|
51
|
-
| `config/master/` | Numbering (`05-numbering-sequences`) before module prefs; inventory, warehouse, items, vendors, customers; roles/users (`90-roles` then `91-users`) |
|
|
51
|
+
| `config/master/` | Numbering (`05-numbering-sequences`) before module prefs; inventory, warehouse, items, vendors, customers; roles/users (`90-roles` then `91-users` then `92-role-users`) |
|
|
52
52
|
| `scenario/10-seed-capital.yaml` | Once-class owner capital JE (skip-if-present when present); Period = `${current_period}` |
|
|
53
53
|
| `scenario/20-buy.yaml` | Additive component PO → receipt → bill → AP pay |
|
|
54
54
|
| `scenario/30-build.yaml` | Additive kit assembly |
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// acu bootstrap CustomizationPlugin (SPEC T11).
|
|
2
|
-
//
|
|
3
|
-
// Runs in-process on customization publish - the one write path to
|
|
4
|
-
// FeaturesSet that works: the contract API cannot persist features no
|
|
5
|
-
// matter what endpoint fronts CS100000 (T3 verdict, docs/rest-api.md).
|
|
6
|
-
//
|
|
7
|
-
// Deliberately writes through PXDatabase, not FeaturesMaint: the graph
|
|
8
|
-
// save collides with the publish pipeline's concurrent plugin invocations
|
|
9
|
-
// ("Another process has added the 'FeaturesSet' record" - observed live,
|
|
10
|
-
// 26.101.0225) and nothing persists. A keyed row write is deterministic
|
|
11
|
-
// and idempotent: update the existing row, insert when absent. All 205
|
|
12
|
-
// NOT NULL bit columns are filled reflectively (only ~136 carry DB
|
|
13
|
-
// defaults); Status = 0 means Validated (PXIntList, verified vs live).
|
|
14
|
-
//
|
|
15
|
-
// The Enabled set is NOT authored here (SPEC V2: feature flags are config
|
|
16
|
-
// "what", never tool source - B6): package_zip() substitutes the
|
|
17
|
-
// ACU_FEATURES sentinel below with the data repo's bootstrap/features.yaml
|
|
18
|
-
// list (built-in six when the file is absent) at package-build time.
|
|
19
|
-
using System.Collections.Generic;
|
|
20
|
-
using System.Reflection;
|
|
21
|
-
using PX.Data;
|
|
22
|
-
using PX.Objects.CS;
|
|
23
|
-
|
|
24
|
-
namespace AcuBootstrap
|
|
25
|
-
{
|
|
26
|
-
public class AcuBootstrapPlugin : Customization.CustomizationPlugin
|
|
27
|
-
{
|
|
28
|
-
private static readonly HashSet<string> Enabled = new HashSet<string>
|
|
29
|
-
{
|
|
30
|
-
/*ACU_FEATURES*/
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
public override void UpdateDatabase()
|
|
34
|
-
{
|
|
35
|
-
var flags = new List<PXDataFieldAssign>();
|
|
36
|
-
var known = new HashSet<string>();
|
|
37
|
-
foreach (PropertyInfo prop in typeof(FeaturesSet).GetProperties())
|
|
38
|
-
{
|
|
39
|
-
if (prop.PropertyType == typeof(bool?))
|
|
40
|
-
{
|
|
41
|
-
known.Add(prop.Name);
|
|
42
|
-
flags.Add(new PXDataFieldAssign(
|
|
43
|
-
prop.Name, PXDbType.Bit, Enabled.Contains(prop.Name)));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
foreach (string name in Enabled)
|
|
47
|
-
{
|
|
48
|
-
if (!known.Contains(name))
|
|
49
|
-
{
|
|
50
|
-
// silent-typo guard (T24): a misspelled features.yaml
|
|
51
|
-
// entry enables nothing - say so in the publish log
|
|
52
|
-
WriteLog("AcuBootstrap: unknown feature name '" + name
|
|
53
|
-
+ "' - no FeaturesSet property, nothing enabled");
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
flags.Add(new PXDataFieldAssign("Status", PXDbType.Int, 0)); // Validated
|
|
57
|
-
|
|
58
|
-
using (var tx = new PXTransactionScope())
|
|
59
|
-
{
|
|
60
|
-
bool updated = PXDatabase.Update<FeaturesSet>(flags.ToArray());
|
|
61
|
-
if (!updated)
|
|
62
|
-
{
|
|
63
|
-
PXDatabase.Insert<FeaturesSet>(flags.ToArray());
|
|
64
|
-
WriteLog("AcuBootstrap: FeaturesSet row inserted (features enabled)");
|
|
65
|
-
}
|
|
66
|
-
else
|
|
67
|
-
{
|
|
68
|
-
WriteLog("AcuBootstrap: FeaturesSet row updated (features enabled)");
|
|
69
|
-
}
|
|
70
|
-
tx.Complete();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/overlays/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/20-buy.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/30-build.yaml
RENAMED
|
File without changes
|
{acumatica_cli-0.28.0 → acumatica_cli-0.29.0}/src/acumatica_cli/templates/scenario/40-sell.yaml
RENAMED
|
File without changes
|
|
File without changes
|