Settings Groups and Entitlements
This page covers the entitlement model that gates every apply flow in this guide, and gives
per-property depth on the four settings groups most relevant to starter setup (ProductSettings,
CashierAppsSettings, FinancialSettings, CostCenterSettings) that the
Business Onboarding chapter
documents at the group level but not the individual-property level.
The entitlement model
A SubscriptionFeature (real, admin-CRUD-managed row, key like Features.AccountManagement) links out
to four independent entitlement dimensions — MenuClaims, report actions, settings groups, and (future)
feature-rule limits. This guide is only concerned with the settings groups link.
ISubscriptionFeatureEntitlementService
Task<List<string>> GetTenantAllowedFeatureKeysAsync(string tenantId, CancellationToken ct = default);
Task<bool> IsFeatureAllowedAsync(string tenantId, string featureKey, CancellationToken ct = default);
Every apply flow in this guide calls IsFeatureAllowedAsync before doing anything else.
ISubscriptionSettingsGroupEntitlementService
Task<List<string>> GetFeatureSettingsGroupsAsync(Guid featureId, CancellationToken ct = default);
Task<List<string>> GetTenantAllowedSettingsGroupsAsync(string tenantId, CancellationToken ct = default);
Task<bool> IsSettingsGroupAllowedAsync(string tenantId, string settingsGroupKey, CancellationToken ct = default);
Resolution chain: ITenantFeatureService.TenantFeaturesIDs(tenantId) → filter
SubscriptionFeatureSettingsGroup rows by those feature Ids (IsActive only) → distinct
SettingsGroupKey. Returns an empty list (never null) for a tenant with no active subscription.
Confirmed feature keys
The real, admin-CRUD-entered feature keys (queried live from the dev database):
Features.ProductsManagement Features.InventoryManagement Features.PointofSalesApp
Features.SalesManagement Features.PurchaseInvoices Features.PurchaseManagement
Features.PayablesManagement Features.ReceivablesManagement Features.AccountManagement
Features.Tables Features.KitchenDisplayScreen Features.OrdersDisplayScreen
Features.WaitersApp Features.OnlineMenuQR Features.Loyality
Features.StoreMobileApp Features.OnlineStore Features.CustomerService
Features.Bookings Features.DeliveryAggregators Features.ProjectManagement
Features.MarketingManagement
Features.ProjectManagement and Features.MarketingManagement were added later (below) specifically to
give ProjectSettings/MarketerSettings real owners. There is no generic Features.Accounting /
Features.Projects / Features.Salesmen / Features.Marketers key — always use the exact strings
above.
Settings-group → owning-feature ownership table
The 11 settings groups known to the onboarding whitelist (SettingsGroupKeys.Known), and which feature
currently owns each:
| Settings group | Owning feature(s) |
|---|---|
ProductSettings | Features.ProductsManagement, Features.InventoryManagement |
CashierAppsSettings | Features.PointofSalesApp, Features.Tables, Features.WaitersApp, Features.KitchenDisplayScreen, Features.OrdersDisplayScreen |
DiscountSettings | Features.PointofSalesApp, Features.SalesManagement |
TaxSettings | Features.PointofSalesApp, Features.SalesManagement |
FinancialSettings | Features.AccountManagement, Features.PayablesManagement, Features.ReceivablesManagement |
CostCenterSettings | Features.AccountManagement |
LoyaltySettings | Features.Loyality |
NotificationSettings | Features.InventoryManagement, Features.KitchenDisplayScreen, Features.OrdersDisplayScreen, Features.OnlineMenuQR, Features.StoreMobileApp, Features.OnlineStore, Features.CustomerService, Features.Bookings, Features.DeliveryAggregators |
ProjectSettings | Features.ProjectManagement (added later — see below) |
SalesmanSettings | Features.SalesManagement (added later — see below) |
MarketerSettings | Features.MarketingManagement (added later — see below) |
Features.PurchaseInvoices/Features.PurchaseManagement deliberately own no settings group.
The ProjectSettings/SalesmanSettings/MarketerSettings gap and its close
When the settings-group entitlement link first shipped, these three groups had no owning feature at
all among the 20 then-existing features — meaning they were unreachable for every tenant, regardless
of subscription. A follow-up phase resolved this per a formal rule: every group in SettingsGroupKeys.Known
must have (a) a real feature owner, (b) a documented "intentionally unavailable" decision, or (c) a
newly-seeded feature owner.
| Settings group | Resolution | Reasoning |
|---|---|---|
SalesmanSettings | Owned by the existing Features.SalesManagement | The Salesman menu claim already lives inside the Sales menu structure in legacy config, available at every historical tier — not a separately-sold add-on |
ProjectSettings | New feature Features.ProjectManagement | A real, fully independent module (own MenuClaims system, own sub-entities), no legacy tiering overlap with Sales |
MarketerSettings | New feature Features.MarketingManagement | Legacy config excluded Marketer from the cheapest tier historically — a real, commercially-distinguished capability, not bundled with base sales |
No SubscriptionPackageFeature row was created for either new feature — whether/which package(s)
include them is left as a deliberate, separate admin/commercial decision through the existing admin UI.
Until an admin makes that assignment, ProjectSettings/MarketerSettings remain unreachable for every
existing tenant (a correctable admin decision now, not a structural code gap).
The onboarding settings-patch whitelist — three independent layers, never trusting the layer above
Onboarding apply is never a free patch of arbitrary AppSettings — three independent layers narrow
every incoming patch, and none of them trusts the layer above it to have already done its job correctly:
- Static whitelist (
SettingsPatchService.Validate, MultiTenancyApi side) — a manually-maintained snapshot of the 11 known groups and their supported properties (MultiTenancyApi has no compile-time visibility into BackEnd's real settings classes, so this dictionary can drift and must be kept in sync by hand). An unknown group → warning, dropped. A Guid-typed FK property (e.g.WarehouseId,CashAccountId,CostCenterId) → warning, dropped — entity references are never settable through onboarding. A property not in the whitelist → warning, dropped. A JSON value of the wrong kind for the declared type → warning, dropped. - Recommendation-time entitlement filter (Phase 3) — after the whitelist produces a clean patch,
every group not in
GetTenantAllowedSettingsGroupsAsync(...)is removed. - Apply-time entitlement re-check (Phase 3, deliberately independent) — re-checked fresh at apply time, since a tenant's subscription can change between recommendation generation and apply. If nothing remains after filtering, the request fails before ever calling the HTTP applier.
- BackEnd's own third, independent guard (
InternalOnboardingSettingsPatchService) — re-validates everything again on its own side: an unknown group name →IgnoredGroupswith a warning; an unknown property name on a known group → reflection lookup fails, skipped, warned; a Guid-typed property → independently blocked and warned (GuidPropertyIgnored); a wrong-type value → warned, skipped; and — its own subscription-eligibility guard — a group name that is one of the 11 known groups but is not in the tenant's currently-allowed set is rejected before it's ever applied (SettingsGroupNotAllowedBySubscription). A genuinely-unrecognized group name is never mislabeled as a subscription problem — it falls through to the ordinary "not part of the whitelist" path instead.
Net behavior: an unsupported/unentitled property or group is silently dropped from the applied
patch (never throws) — each drop is recorded as a warning string in the response, but nothing fails the
whole request unless zero groups end up with anything applied, in which case the response reports
NoValidSettingsToApply.
ProductSettings
Item-catalog behavior configuration — not the same thing as
Product Catalog Templates (see the distinction box below).
Confirmed properties (real class, Shumoul.Application/Settings/ProductSettings.cs): item-attribute
toggles (ExpireDate, BatchNumber, SerialNumbers, ScaleSettings, BranchSettings, MultiImages,
MandatoryMainImages, Description, FreeQuantity, Booking, Map, Tags, PromotionName,
SubName, AttachFiles, Properties, Ingredients, AdditionalData); unit-related flags
(Modifiers, MandatoryPriceForMainUnit, MultiUnits, MultiPricelListForUnits,
MandatoryCostForMainUnit, ImagesForUnit, MultiImagesForUnit, PackagingInfo, ColorForUnit,
ShapForUnit); kitchen flags (KitchenPreparationTime, EnableCalories); promo flags
(EnablePromotions, EnableTimeEvents, EnableDiscount); coding/sequence settings per level
(Business/Department/Category/Product: *SequenceType, *CodeLength, *CodeStartNo,
SegmentSeparator, AddZeroToRightOfCodeStartNo); scale settings (ScaleBarcodeDigits,
ScaleProductCodeDigits, ScaleIntDigits, ScaleDecimalDigits, ScaleProductCodeFirstInBracode).
Owning features: Features.ProductsManagement, Features.InventoryManagement.
ProductSettings is configuration. Product Catalog Templates are starter/master data. They are related — both concern "products" — but distinct:
ProductSettingscontrols how the product module behaves (coding scheme, mandatory fields, multi-unit support); Product Catalog Templates create the actual Products/Categories/Units rows. Neither reads or writes the other.
CashierAppsSettings
POS/cashier terminal behavior. 57 real properties on Shumoul.Application/Settings/CashierAppsSettings.cs.
Confirmed present (against a commonly-cited property list): Enable_Cash_Sales,
Enable_CreditCard_Sales, Enable_Customer_Sales, Enable_Free_Quantity, Enable_Edit_ItemName,
Enable_Change_Price, Enable_Product_Packages, Enable_Tables_System, Table_GuestCount_Required,
Table_Required, Active_Tips, Return_Require_Customer_Info, Require_Cancel_Reason — all real.
Two commonly-assumed property names do not exist on this class — Enable_Sales_Discount (the
real discount toggles live on DiscountSettings, not here) and Discount_Require_Customer_Info (the
real, similarly-named property is Coupon_Require_Customer_Info). Always verify a property name against
the real class before referencing it in a patch or a client integration.
Other real properties include default-linkage Guid fields (SalesInvoiceTemplateId, GroupId,
PriceListId, WarehouseId, CashAccountId, BankAccountId, LocalCardAccountId,
InternationalCardAccountId, CostCenterId — all blocked from onboarding patching as entity
references, see the whitelist rules above), rounding (Rounding_Type, Round_Digits), kitchen/print
sorting, session limits, and inventory/return-policy flags. Owning features: Features.PointofSalesApp,
Features.Tables, Features.WaitersApp, Features.KitchenDisplayScreen, Features.OrdersDisplayScreen.
FinancialSettings
Accounting/financial behavior configuration — distinct from the starter data layers below it. ~90 real properties, grouped:
- 9 intermediate-account Guid pointers (
CurrencyDifferencesAccountId,LostItemsAccountId,ExcessItemsAccountId,PayableNotesAccountId,ReceivableNotesAccountId,CreditDifferencesAccountId,RoundingDifferencesAccountId,CostDifferencesAccountId,IntermediateAccountsCostCenterId) — not a generic Cash/Bank/AR/AP account map; those live onInventoryAccountCategoryinstead (see Accounting Chart Templates). - System-level bool flags (
AllowModifyDocumentDate,RoundingDecimals(default 2),DailyTransferCurrencyDifferences,AllowSaveZeroDocument, budget/limit check flags per document category). - Account-tree-shape settings (
AccountTreeLevelsdefault 5,ParentAccountCodeLength,SubAccountCodeLength,MandatoryParentAccountCodeInSubAccountCode, severalEnable*ForAccountsflags). - 18
MandatoryCostCenterIn*flags, one per document type (PaymentVoucher, ReceiptVoucher, JournalEntry, CreditMemo, DebitMemo, DiscountInvoice, SalesInvoice, and 11 purchase/inventory document types), plus matchingMultiCostCenterIn*flags. This is the exact field group the onboardingneedsCostCentersanswer patches (see Tenant Starter Kit Orchestration):Mandatorysets these true for the curated onboarding-reachable subset (sales invoice, payment voucher, receipt voucher, journal entry);No/Simpleset them false.
Owning features: Features.AccountManagement, Features.PayablesManagement,
Features.ReceivablesManagement.
Layering, spelled out:
FinancialSettingsis configuration (how vouchers behave). Accounting Chart Templates create the chart of accounts (starter data). Inventory Account Category Templates map specific inventory-related GL accounts. All three are different layers that happen to all concern "accounting" — none of them writes to either of the others.
CostCenterSettings
The real class (Shumoul.Application/Settings/CostCenterSettings.cs) is much broader than what
onboarding can touch: 3 code-format properties (CostCenterTreeLevels, ParentCostCenterCodeLength,
SubCostCenterCodeLength, MandatoryParentCostCenterCodeInSubCostCenterCode) plus, for every
document type across Vouchers/Sales/Purchasing/Inventory, a trio of EnableCostCenterIn{Doc},
MultiCostCenterIn{Doc}, MandatoryCostCenterIn{Doc} flags — roughly 63 properties total.
The onboarding whitelist exposes only a curated 6-property subset:
EnableCostCenterInSalesInvoice MandatoryCostCenterInSalesInvoice
EnableCostCenterInPurchaseInvoice MandatoryCostCenterInPurchaseInvoice
EnableCostCenterInJournalEntry MandatoryCostCenterInJournalEntry
Everything else on the real class — every Multi* flag, and Enable/Mandatory for every other document
type (returns, credit/debit memos, all the purchasing/inventory document types) — is unreachable through
onboarding entirely; it can only be set through direct admin configuration of CostCenterSettings
itself. Owning feature: Features.AccountManagement.
CostCenterSettings is configuration (which documents require/allow a cost center). Cost Center Templates are separate starter data — the actual
dbo.CostCentersrows, created only through an explicit apply.needsCostCenters(an onboarding question) drives someCostCenterSettingsandFinancialSettingsfields directly, and separately drives whether the Tenant Starter Kit includes the CostCenters step by default — two different mechanisms reading the same one answer.
