# Shop · Settings — Business Rules (numbered, implementable)

Demo ref: `portals/shop/Settings.tsx`, `types.ts`, `lib/schedule.ts`, `store/selectors.ts`.
Our ref: `common/models/ShopPaymentSettings.php`, `common/models/Shop.php`, the two views.

## Profile / General
1. **Commercial name, email, owner mobile are editable**; bank name + IBAN are **read-only**
   (set elsewhere / by Navagoo). Demo: `Settings.tsx:54–70` (bank/iban `disabled`).
   Ours: only `title`+`mobile`+`gender` editable; **no email, no bank/iban** field at all.
2. Saving General batches the three fields and confirms with a toast (demo) / flash (ours).

## Scheduling
3. **Overnight trading**: if `closeTime <= openTime` the shop closes the *next* day; UI must
   surface a "+1d / closes next day" hint. Demo: `Settings.tsx:96`, `lib/schedule.ts:93`.
   Ours: `Shop::isOvernight()` + hint (view L234, JS L713). ✅
4. **Slot size** is one of {5,10,15,30} minutes and drives calendar grid snapping.
   Demo: `Settings.tsx:120`. Ours: `Shop::getSlotSizeOptions()` (view L323). ✅
5. **Slot-size lock**: when an admin policy locks the slot step (`shop.slotStepLocked` /
   `Shop::isSlotTimeStepLocked()`), the shop owner cannot change it; admins/managers may.
   Demo: `Settings.tsx:118` (disabled). Ours: view L318. ✅ (ours has the role bypass.)
6. **Time format** is per-shop 12h or 24h, default 12h. Demo: `types.ts:70`, `Settings.tsx:131`.
   Ours: **no such setting** — display format not shop-configurable. ❌

## Payment methods
7. **At least one** payment method must be enabled; at most three. Demo: implied by always-on
   toggles. Ours: enforced — `validateAtLeastOneEnabled` (`ShopPaymentSettings.php:72`). ✅
8. Three methods: Pay 100% Online, Pay Deposit, Pay on Visit. Demo `Settings.tsx:159/172/186`;
   Ours `MODE_ONLINE/MODE_DEPOSIT/MODE_ON_VISIT` (`ShopPaymentSettings.php:37`). ✅
9. **When Pay Deposit is enabled, a deposit percentage is required** and must be an integer.
   Ours: `validateDepositPercentage` requires non-empty when deposit on (`...php:83`). ✅
10. **Deposit % effective cap** = per-shop override (`shop.maxDepositPct` /
    `Shop.max_deposit_percent_override`) if set, else the global cap
    (`config.maxDepositPct` / `Settings.max_deposit_percent`), hard ceiling 100.
    Demo: `Settings.tsx:198` clamp. Ours: `getEffectiveMaxDeposit()` (`...php:112`). ✅
11. **Deposit % is collected upfront** on deposit bookings; balance paid on visit (semantic).
    Demo `types.ts:47`. Ours: enforced downstream of payment settings, not in this view.
12. **Walk-in payment gating**: each method has a SEPARATE walk-in toggle
    (`walkinOnline/walkinDeposit/walkinOnVisit`) controlling which pricing a shop's walk-in
    booking flow may use, independent of the customer-app toggles. Demo: `types.ts:53–55`,
    `Settings.tsx:165/179/193`. Ours: **no walk-in toggles** — single toggle set applies to
    everything. ❌
13. **No-row default = online-only**: a shop with no payment-settings row is treated as
    online-only. Ours: `findForShop()` returns null ⇒ consumers default online
    (`ShopPaymentSettings.php` docblock L19–21; controller seeds `pay_online_enabled=1`). ✅

## Commercials (read-only, Navagoo-controlled)
14. Marketing fee rate, payment-processing fee rate + fixed, VAT-registered flag,
    minimum withdrawal amount, settlement hold days, subscription plan/status/next-billing
    are **read-only** to the shop ("set by Navagoo"; "changes apply to new charges only").
    Demo: `Settings.tsx:215–248`, `types.ts:25–31`, `selectors.ts:40/41`.
    Ours: **none surfaced** on shop settings; no `vat_registered`, `marketing_fee_rate`,
    `payment_processing_fee_*`, `min_withdrawal_amount`, `settlement_hold_days`,
    `subscription_plan` columns on `Shop`. ❌ (Settlement-hold/min-withdrawal exist only as
    earnings/withdrawal logic, migrations `m251019_213705/213708`, not as shop-settings fields.)
15. **Subscription status badge** mapping: active→teal, free_period→amber, else→slate; label
    underscores replaced with spaces. Demo `Settings.tsx:222–235`. Ours: ❌ (no surface).

## Notifications
16. Channels SMS / WhatsApp / Email / Push are toggleable; SMS & WhatsApp carry a per-message
    fee (`config.smsUnitFee` / `config.waUnitFee`), Email & Push are free. Demo: `Settings.tsx:254`.
    NOTE: in the demo these toggles are **local-only state** (not persisted) — so this is an
    unfinished/illustrative surface. Ours: ❌ (no channel-preference card).

## Permissions / scoping
17. All settings are **scoped to the active shop** (`activeShopId` in demo; `Yii::$app->user->
    identity->shop` in ours — controllers L124 / PaymentSettings L49). Both controllers require
    an authenticated shop owner (`roles=['@']`, PaymentSettings L27). ✅
18. Commercials are mutable only by Navagoo/admin, never the shop. Demo: read-only UI.
    Ours: N/A (not surfaced); enforce if/when these fields are added.
