Skip to main content
Version: Latest

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​

TargetWhat it isRead 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 rowUserCashierSettingService.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) — a Guid reference property is never auto-assigned, regardless of whether a record exists. Resolved for the four kinds this phase covers by the direct CashierAppsSettings/ UserCashierSetting wiring 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.