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.