7. Onboarding Integration & Warning Behavior
7.1 Call sequence
OnboardingService.ApplyRecommendationAsync (MultiTenancyApi), after the defensive subscription-entitlement
re-filter of the generated settings patch and before the generic settings-patch bridge call:
1. ITenantOperationalDefaultsService.ApplyAsync(session.TenantId) — best-effort, in-process
→ creates missing Warehouse/CashAccount/BankAccount/SalesInvoiceTemplate (entitlement-filtered)
→ wires CashierAppsSettings.{WarehouseId,CashAccountId,BankAccountId,SalesInvoiceTemplateId}
(only when currently null — an admin-set value is never overwritten)
→ wires exactly one UserCashierSetting row for the tenant admin + first active branch
(only if none exists yet for that pair)
2. IOnboardingTenantSettingsApplier.ApplyAsync(session) — the existing bridge, unchanged
→ still cannot set any Guid property (WarehouseId/CashAccountId/etc.) on CashierAppsSettings itself
via the JSON patch — that guard is untouched, see §7.2
A failure in step 1 (bridge disabled, BackEnd error, or an unhandled exception) is caught, logged as a
warning, and never blocks step 2 — the settings-patch apply (the part onboarding actually requires to
succeed) still proceeds. This mirrors the existing ITenantEntitlementProvisioningService best-effort
call already in InternalOnboardingSettingsPatchService.
7.2 The generic patch engine's Guid-block is never weakened
SettingsPatchService/InternalOnboardingSettingsPatchService's rule — never set a Guid/Guid?
property from an onboarding-generated JSON patch, regardless of whether a valid target exists — is
left completely untouched by this phase. CashierAppsSettings.WarehouseId etc. are instead set
directly, in BackEnd, through IAppSettingService.SetAppSetting<CashierAppsSettings>() — a dedicated,
purpose-built code path operating only on Ids this same request just resolved/created itself, never on an
externally-supplied value from the wire. This satisfies the constraint against weakening onboarding
settings validation while still resolving the warnings.
7.3 Two different "the setting is applied" targets
| Target | What it is | Read by |
|---|---|---|
CashierAppsSettings.{WarehouseId,CashAccountId,BankAccountId,SalesInvoiceTemplateId} | Tenant-wide settings-store blob (IAppSettingService) | The onboarding warning/UI only — not consumed by real POS/cashier code today |
UserCashierSetting row (UserId, BranchId) | Real per-user/per-branch table row | UserCashierSettingService.GetForSyncDataAsync — the actual POS-device sync endpoint |
This phase wires both, per the confirmed decision: resolving only CashierAppsSettings would silence
the onboarding warning cosmetically without making POS/cashier sync actually pick up the defaults;
resolving only UserCashierSetting would fix real behavior but leave the warning showing. Both together
give a coherent result: the warning-implied state and the real POS state agree.
7.4 Warnings before and after
The recommendation's warning text (GeneratedWarningsJson, computed once at POST .../recommendation
time, before any defaults exist) is not retroactively rewritten by a later apply — it remains the
"Phase 1" wording from when it was generated. What changes is the tenant's real state after POST .../apply: GET api/v1/AppSettings/GetCashierApps now returns real, non-null Ids for every entitled
kind, and GET api/v1/onboarding/status reports isRequired: false, status: "Applied" — dashboard-ready,
exactly as before this phase, with the added benefit that the operational records now genuinely exist.
A future enhancement (not part of this phase) could regenerate the recommendation's warning text once defaults are known to exist, or word it as a live entitlement/dependency check rather than a fixed "Phase 1" string — see Chapter 10 §10.4 for this as a tracked suggestion.
Warning wording actually observed (live-verified)
Structurally, warnings fall into two categories, confirmed unchanged by this phase and correctly non-blocking in both cases:
- Missing-master-data (
Onboarding.Validation.EntityReferencePropertyIgnored/GuidPropertyIgnored) — aGuidreference property is never auto-assigned, regardless of whether a record exists. Resolved for the four kinds this phase covers by the directCashierAppsSettings/UserCashierSettingwiring in §7.1–7.3, not by changing this rule. - Subscription-entitlement (
Onboarding.Validation.SettingsGroupNotAllowedBySubscription, and this phase's own"{Kind} default was skipped — tenant does not have any of the required subscription feature entitlements ({FeatureKeys}).") — clear, specific, names the exact missing feature key(s), never vague "Phase 1" wording. Live-verified: a Shumoul Starter tenant's apply produced exactly"BankAccount default was skipped — tenant does not have any of the required subscription feature entitlements (Features.AccountManagement)."— see Chapter 9.
Both categories are warnings, never errors — apply still returns succeeded: true with every entitled
kind resolved.
