## ADDED Requirements ### Requirement: Least-privilege ACLs for group order models `group.order` and `group.order.slot` SHALL NOT grant write, create or unlink to portal, public or unassigned internal users. Write/create/unlink SHALL be limited to the group-order manager group (`website_sale_aplicoop.group_group_order_manager`) and ERP admins. Read MAY be granted to internal users and portal users through explicit, group-scoped ACLs (no empty `group_id` rows). Controller mutations continue to run via `sudo()` and MUST NOT depend on broad ACLs. #### Scenario: Portal user cannot mutate group orders - **WHEN** a portal user calls the external API to `create`, `write` or `unlink` on `group.order` or `group.order.slot` - **THEN** the operation is denied with an `AccessError` #### Scenario: Manager retains full access - **WHEN** a user in `group_group_order_manager` creates or edits a `group.order` of their company - **THEN** the operation succeeds #### Scenario: Controllers still operate - **WHEN** an authenticated portal member confirms a cart through the eskaera controller (which uses `sudo()`) - **THEN** the underlying `sale.order`/`group.order` writes succeed despite the tighter ACLs ### Requirement: Supplier cost not broadly exposed to portal Portal users SHALL NOT read `product.supplierinfo` cost/price rows for products or vendors unrelated to them. The unrestricted record rule (`domain=[(1,'=',1)]`) granting portal read on `product.supplierinfo` SHALL NOT exist. The product **origin** and **main seller** shown in the eskaera shop — currently painted from `supplierinfo` — MUST keep working, either by preparing those values server-side (via `sudo()` in the controller, per the repo's "no logic in QWeb" rule) or via a record rule scoped to the products the user can access, exposing no supplier cost/price fields. #### Scenario: Portal user cannot list unrelated supplier cost - **WHEN** a portal user calls `search_read` on `product.supplierinfo` via the external API - **THEN** the result does not include supplier cost/price rows of products/vendors unrelated to the user #### Scenario: Origin and main seller still render - **WHEN** a portal member opens the eskaera shop - **THEN** each product's origin and main seller display correctly, without exposing supplier cost/price across all vendors ### Requirement: CSRF protection on state-changing eskaera endpoints State-changing eskaera endpoints SHALL be protected against cross-site request forgery. The endpoints `/eskaera/save-order`, `/eskaera/confirm`, `/eskaera/clear-cart` and `/eskaera/save-cart` (which create, confirm, merge or cancel `sale.order` records) SHALL NOT be `type="http"` with `csrf=False`; they SHALL be `type="json"` (or otherwise validate a CSRF token) so that a cross-site HTML form POST cannot trigger them. #### Scenario: Cross-site form POST is rejected - **WHEN** a logged-in user's browser is induced to submit a cross-site form POST to `/eskaera/clear-cart` or `/eskaera/confirm` - **THEN** the request is rejected and no order is cancelled/confirmed #### Scenario: Legitimate same-origin call works - **WHEN** the eskaera frontend submits the JSON-RPC request from the same origin - **THEN** the order is created/confirmed as before ### Requirement: Consumer-group membership enforced on group-order endpoints Every eskaera endpoint that resolves a `group.order` from a request id SHALL verify that the requesting user belongs to a consumer group of that order before returning data. This applies to `load_eskaera_page`, `load_products_ajax`, `add_to_eskaera_cart`, `eskaera_checkout` and `check_group_order_status`, reusing `_validate_user_group_access` / `_get_consumer_group_for_user`. Internal users MAY be exempt (matching `eskaera_shop`). #### Scenario: Non-member gets no cross-group data - **WHEN** a portal user who is not a member of a group order requests `/eskaera//load-products-ajax` for that order - **THEN** the endpoint returns empty/redirect and discloses no catalog or pricing of that order #### Scenario: Member accesses own group order - **WHEN** a portal member of the order's consumer group requests the same endpoint - **THEN** the products and pricing are returned normally ### Requirement: Safe template output in inline scripts QWeb templates SHALL NOT inject data into inline `