Skip to main content
Version: Latest

16. Tenant Setup Wizard — Frontend Integration Guide

معالج إعداد المستأجر — دليل تكامل الواجهة الأمامية

العربية: هذا الفصل يوثّق العقد التقني المتوقع لمعالج إعداد المستأجر (Tenant Setup Wizard) — شاشة تجمع بيانات المنشأة والعنوان وإعدادات المستأجر الافتراضية وإعدادات الضريبة، وتنتهي — عند تفعيل المرحلة الثانية من الفوترة الإلكترونية — بربط المستأجر بمنصة فاتورة (ZATCA/FATOORA).

English: This chapter documents the expected integration contract for the Tenant Setup Wizard — a UI flow that collects organization profile, address, tenant default settings, and tax settings, ending — only when ZATCA Phase 2 is enabled — in connecting the tenant to the ZATCA Fatoora platform.

Implementation status note / ملاحظة حالة التنفيذ: Frontend implementation was reported as committed and pushed in Shumoul.Portal commit 65b1dd1b ("Add tenant setup wizard with organization profile, address, defaults, and ZATCA Phase 2 onboarding"). This documentation describes the expected integration contract and user flow against the verified backend source. Shumoul.Portal is not inspected or modified by this documentation task — nothing below should be read as a claim that the Angular implementation was verified against this guide.

Who it's for: Frontend/Angular Developers · Backend Developers · QA Engineers

16.1 Three Flows — Do Not Confuse Them

There are three distinct, unrelated onboarding-style flows on the platform. This wizard combines the first two; it must never be confused with the third's name even though it configures the data the third flow uses.

#FlowWhat it doesWhere it's documented
1Tenant Setup Wizard (this chapter)Collects organization profile, address, tenant defaults, and tax settings (VAT + ZATCA Phase 2) via AppSettingsController and EInvoicingSettingsController/EInvoicingOnboardingControllerThis chapter
2First-Login Onboarding QuestionnaireAnswers → recommendation → apply business-activity questionnaire, shown once after first loginBusiness Onboarding & Smart Configuration
3E-Invoicing (ZATCA/FATOORA) OnboardingThe Compliance CSID → compliance checks → Production CSID device-onboarding sequence this wizard's Step 6 triggersChapter 9 — Onboarding, Chapter 5 — Controllers & Endpoints § 5.3

The Tenant Setup Wizard is a UI composition over flows the backend already exposes — it introduces no new backend model, table, or endpoint. Steps 1–3 read/write the existing TenantSettings/TaxSettings AppSetting groups; Steps 5–7 read/write the existing E-Invoicing AppSetting groups documented in Chapter 6 — Configuration.

16.2 Flow Table

StepTitle (AR / EN)Endpoint(s)MethodNotes
1بيانات المنشأة / Organization Profileapi/v1/AppSettings/GetTenant, api/v1/AppSettings/SetTenantGET, POSTFull-form load-merge-save; must not null hidden fields
2العنوان / Addresssame as Step 1 (TenantSettings is one model)GET, POSTCountry saved as Guid, not display text
3إعدادات المنشأة / Tenant Defaultssame as Step 1GET, POSTCurrency fields saved as Guid/Guid? IDs
4.1تفعيل الضريبة / Enable VATapi/v1/AppSettings/GetTax, api/v1/AppSettings/SetTaxGET, POSTReuses existing TaxSettings.Enable_Sales_Tax — no new field
4.2تفعيل المرحلة الثانية / Enable ZATCA Phase 2(no endpoint — client-side visibility toggle only)Gates Steps 5–7; not itself a persisted setting
5بيانات الوحدة الضريبية / Fiscal Unit Registration Dataapi/EInvoicing/Settings/VatRegistrationGET, POSTExisting VatRegistrationSettings model + validator, unchanged
6ربط منصة فاتورة / Connect to FATOORA Platformapi/EInvoicing/OnboardingPOSTHeaders only, no body; OTP obtained by the tenant admin from ZATCA's portal
7حالة الربط / Connection Resultapi/EInvoicing/Settings/IntegrationGETSafe reload only — OTP is always null in the response

On the route prefix: the E-Invoicing endpoints above are documented here as api/EInvoicing/... (no /Saas/ segment) because that is the variant this platform's Shumoul.Api host actually wires up — see Chapter 5 § 5.5 for why a /Saas/-prefixed duplicate of the same three controllers exists in the TenancyApi package but is not the one mounted here. If a task brief or ticket references api/Saas/EInvoicing/Onboarding, that is the unwired duplicate route, not the live one — use api/EInvoicing/Onboarding.

16.3 Step 1 — Organization Profile / بيانات المنشأة

Purpose: collect and save the tenant organization profile using the existing TenantSettings model — no new model, no new table.

Fields: CompanyName, F_Company_Name, Activity, F_Activity, PhoneNumber, FaxNumber, WebSite, Email, Tax_Registration_Name, CRNo, TaxNo, Zakat_Registration_Number, Municipal_License_Number, Gulf_Council_Identification_Number, SAGIA_License_Number.

Backend storage: the shared AppSetting table, keyed by GroupName = "TenantSettings" — the same generic mechanism documented in Chapter 6 § 6.3 for E-Invoicing settings.

GET api/v1/AppSettings/GetTenant → Result<TenantSettings> [MustHavePermission: AppSetting.View]
POST api/v1/AppSettings/SetTenant → Result [MustHavePermission: AppSetting.Edit]

Important: the wizard must call GetTenant first, merge only the fields shown in Steps 1–3 into the loaded object, and submit the entire merged TenantSettings object on SetTenant. TenantSettings also carries fields the wizard never shows (e.g. LogoUrl) — because SetTenant persists the whole object, any field the wizard didn't load-and-preserve will be silently wiped. This is the same full-form pattern the platform's existing settings screen already uses; it is not a new convention invented for this wizard.

16.4 Step 2 — Address / العنوان

Fields: Country, Postal_Code, Province, FProvince, City, FCity, District, FDistrict, Street, FStreet, Building_No, Floor_No, Office_No, Additional_No — all part of the same TenantSettings object as Step 1; same endpoints, same load-merge-save rule.

Important: Country is a Guid foreign key on TenantSettings, not free text — the wizard must submit the selected country's ID, never its display name. Reuse the platform's existing country/city dropdown endpoints; do not introduce a new lookup source for this wizard.

16.5 Step 3 — Tenant Defaults / إعدادات المنشأة

Fields: LocalCurrencyId, SalesPriceCurrencyId, InventoryCostCurrencyId, PayrollCurrencyId (optional), InventoryCalculateCostMethod, StockInventoryType, Default_Language, Second_Language, Print_language, Invoice_Round_Factor, Item_Quantity_Round_Factor — same TenantSettings object, same endpoints.

Important: currency fields are Guid/Guid? IDs, not display names — LocalCurrencyId, SalesPriceCurrencyId, and InventoryCostCurrencyId are required; PayrollCurrencyId is optional and must be left null (never Guid.Empty) when not selected.

16.6 Step 4 — Tax Settings / إعدادات الضرائب

This step is a strict branching flow — each toggle gates what the next sub-step is allowed to do.

GET api/v1/AppSettings/GetTax → Result<TaxSettings> [MustHavePermission: AppSetting.View]
POST api/v1/AppSettings/SetTax → Result [MustHavePermission: AppSetting.Edit]

4.1 VAT toggle — تفعيل الضريبة / Enable VAT

Reuses the existing TaxSettings.Enable_Sales_Tax boolean field — no new backend field was needed, this field already exists and already carries exactly this meaning on the platform.

VAT stateBehavior
DisabledHide ZATCA Phase 2 options. Do not call any E-Invoicing endpoint, including api/EInvoicing/Onboarding. Do not clear previously saved E-Invoicing settings without the user's explicit confirmation.
EnabledValidate TenantSettings.TaxNo per existing business rules before allowing the ZATCA Phase 2 toggle to appear.

4.2 ZATCA Phase 2 toggle — تفعيل المرحلة الثانية من الفوترة الإلكترونية / Enable ZATCA Phase 2 E-Invoicing Integration

Only shown when VAT is enabled. This toggle has no backend persistence of its own — it is a client-side gate deciding whether Steps 5–7 render at all; the actual "is this tenant onboarded" state lives in FatooraSecretSettings.Onboarded (see Chapter 6 § 6.6), which the wizard never reads or writes directly.

ZATCA Phase 2 stateBehavior
DisabledHide Fiscal Unit Registration Data (Step 5) and the OTP connection panel (Step 6). Do not call api/EInvoicing/Onboarding. Do not clear previously saved VatRegistrationSettings without the user's explicit confirmation.
EnabledContinue to Step 5.

16.7 Step 5 — Fiscal Unit Registration Data / بيانات الوحدة الضريبية

Uses the existing VatRegistrationSettings model — do not duplicate the model or create a duplicate endpoint.

Fields: CommonName, SerialNumber, OrganizationIdentifier, OrganizationUnitName, OrganizationName, CountryName, InvoiceType, LocationAddress, IndustryBusinessCategory — see Chapter 6 § 6.2 for the full field list.

GET api/EInvoicing/Settings/VatRegistration → Result<VatRegistrationSettings>
POST api/EInvoicing/Settings/VatRegistration → Result (validated)

Important:

  • Reuse the existing VatRegistrationSettingsValidator (FluentValidation) server-side; do not re-implement the same rules only in Angular as a substitute for the server check.
  • The wizard may prefill fields from TenantSettings only where safe (e.g. a company name), but must not silently guess formats the validator enforces — OrganizationIdentifier (15-digit Saudi VAT number pattern), CountryName (must match CountryISO.GetList()), and InvoiceType (2-digit invoice-subscription-type pattern) all have specific required formats; if the wizard cannot derive a valid value confidently, leave the field blank for the user to fill rather than submitting a guessed value.
  • Do not allow the user to proceed to Step 6 until this POST succeeds.

16.8 Step 6 — ZATCA OTP / FATOORA Connection — ربط منصة فاتورة / Connect to FATOORA Platform

Only shown after Step 5's VatRegistration POST has succeeded.

Business rule: the OTP is obtained by the tenant admin manually from ZATCA's own portal, out of band. The platform does not generate it and does not read it back from GET .../Integration — see Chapter 9 § 9.1.

POST api/EInvoicing/Onboarding
Headers:
OnboardingRequestType: FirstTime | Renewal | StartOver
Otp: <value the user entered>
(no request body)

Controller signature (EInvoicingOnboardingController):

InitializeAsync([FromHeader, BindRequired] OnboardingRequestType type, [FromHeader, BindRequired] string Otp)

which delegates to IOnboardingProcessFlowService.Initialize(type, Otp).

OnboardingRequestType values (Shumoul.Framework.EInvoicing.Onboarding.OnboardingRequestType):

public enum OnboardingRequestType
{
FirstTime,
Renewal,
StartOver
}

Use these exact three values (or their ordinal/serialized form as the API contract defines) — do not hard-code a different value set in the frontend; if the Angular project uses a generated API client, import the enum from that contract instead of re-declaring it by hand.

Important:

  • OTP must not be displayed anywhere after submission.
  • OTP must not be persisted in frontend state (memory, storage, or otherwise) any longer than the single request needs it — clear it immediately once the call is made, regardless of the result.

16.9 Step 7 — Connection Result / حالة الربط

After the api/EInvoicing/Onboarding call resolves:

  • Show success or failure clearly to the user. Do not auto-retry.
  • Optionally reload safe integration status:
GET api/EInvoicing/Settings/Integration → Result<IntegrationSettings>

Important: IntegrationSettings.OTP is always null in this response by design (redacted since Phase 0.2 — see Chapter 5 § 5.2). Only display ExpiresOn/Invalid from this response. Never expect or display an OTP value from this endpoint.

16.10 Do / Do Not

Do:

  • Load full TenantSettings before saving any of Steps 1–3, and submit the full merged object each time.
  • Save Country and every currency field as a Guid/Guid? ID, never a display name.
  • Validate TaxNo before allowing VAT to be marked enabled.
  • Require a successful VatRegistration save before showing the OTP panel.
  • Clear the OTP value from frontend state immediately after the onboarding call, win or lose.

Do not:

  1. Mix this wizard's flow or naming with the First-Login Onboarding Questionnaire (§16.1, flow 2).
  2. Call api/EInvoicing/Settings/ConfigrationMode (POST — publishes SwitchToProductionModeEvent) or any SwitchToProductionMode-style action automatically from this wizard.
  3. Call api/EInvoicing/Generate (invoice generation) from the setup wizard.
  4. Erase hidden TenantSettings fields (e.g. LogoUrl) by submitting a partial object.
  5. Erase previously saved E-Invoicing settings just because the VAT or ZATCA Phase 2 toggle was switched off — only do so with the user's explicit confirmation.
  6. Create a duplicate API endpoint or a duplicate settings model for anything this wizard needs — every field it touches already exists on TenantSettings, TaxSettings, or VatRegistrationSettings.
  7. Save country/currency display names where a Guid ID is required.
  8. Display or persist the OTP value after it has been submitted.
  9. Rely on GET .../Integration to return the OTP — it is always null.
  10. Allow the OTP connection step to proceed before VatRegistrationSettings has been validated and saved.

16.11 Manual Verification Checklist

  1. Open the tenant setup wizard.
  2. Complete Organization Profile (Step 1) and confirm SetTenant preserves fields not shown in the wizard.
  3. Complete Address (Step 2) and confirm Country is submitted as a Guid.
  4. Complete Tenant Defaults (Step 3) and confirm currency fields are submitted as Guid/Guid? IDs.
  5. Open Tax Settings (Step 4).
  6. With VAT disabled: confirm ZATCA Phase 2 options are hidden and no E-Invoicing endpoint is called.
  7. Enable VAT: confirm the ZATCA Phase 2 toggle appears and TaxNo is validated.
  8. With ZATCA Phase 2 disabled: confirm Fiscal Unit and OTP panels are hidden and api/EInvoicing/Onboarding is not called.
  9. Enable ZATCA Phase 2: confirm Fiscal Unit Registration Data fields (Step 5) appear.
  10. Save VatRegistrationSettings and confirm the POST succeeds before the OTP panel appears.
  11. Confirm the OTP panel appears only after a successful VatRegistration save.
  12. Enter an OTP obtained from the ZATCA portal.
  13. Confirm POST api/EInvoicing/Onboarding is called with OnboardingRequestType and Otp headers, no body.
  14. Confirm the OTP value is cleared from frontend state immediately after submission.
  15. Confirm GET api/EInvoicing/Settings/Integration never displays an OTP value.
  16. Confirm ConfigrationMode is never called automatically anywhere in this flow.
  17. Confirm api/EInvoicing/Generate is never called from this wizard.
  18. Confirm existing tenant settings pages (outside this wizard) remain compatible and unaffected.