# Wholesale Carton / Category Purchase Rule Specification

## Goal

Some categories represent wholesale products where ordering is only considered a complete carton when the cart contains a required number of DIFFERENT products from that same category.

Example business rule:
- select a wholesale category
- every product in that category participates in the rule
- a complete carton requires at least 5 distinct products from that category
- the current example says "حداقل ۴ تا جنس دیگه ... یک کارتن تکملی بشه", which implies 5 distinct SKUs total including the first item
- make the threshold configurable so the business can set 4, 5, etc. without code changes

## Important interpretation

Do not hardcode 5.

Implement configurable category-level rule fields:
- `wholesale_rule_enabled` boolean
- `wholesale_min_distinct_products` integer, minimum 1

Use the value configured by the admin.

If the business interpretation is instead "4 distinct products total", the admin should be able to configure 4.

## Scope

Rule is category-specific.

Example:
Category = "عمده فروشی"
Minimum distinct products = 5

If cart contains:
- product A from category
- product A quantity 10
- product B quantity 1

Distinct product count = 2, not 11.

Quantity does NOT replace product diversity.

## Exact eligibility logic

For a category with threshold N:

`distinct qualifying product count >= N`

Qualifying products:
- active purchasable products
- belonging to the selected category according to current product/category relationship rules

Define what happens with:
- inactive products already in cart
- deleted products
- out-of-stock products
- multiple variants
- products belonging to multiple categories

Prefer counting distinct purchasable SKU/variant IDs when variants are real purchasable units.

## Cart behavior

When rule is enabled:
- user can add products normally
- cart displays progress
- checkout is blocked while minimum is not met
- clear error message in Persian
- show remaining distinct products required
- link/button to browse missing category products

Example:
`برای تکمیل یک کارتن، حداقل ۵ محصول متفاوت از این دسته باید در سبد خرید باشد. ۳ محصول انتخاب شده و ۲ محصول دیگر نیاز است.`

If there are multiple rule-enabled categories in one cart:
- validate each category independently
- checkout allowed only if ALL required rules pass

## Admin settings

Category editor:
- enable wholesale/carton rule
- minimum distinct products
- optional custom message
- optional rule scope:
  - category only
  - descendants included

Default scope should be category only unless the existing business model indicates inheritance.

## UX

On category/product page for wholesale-enabled categories:
- show carton rule explanation
- show current selected count if cart context is available
- show relevant products

Cart:
- show progress per rule
- show missing count
- show CTA to category

Checkout:
- server-side validation must be authoritative

Do not rely only on JavaScript.

## Service design

Implement in a dedicated domain/service layer, e.g.:
`WholesaleCartRuleService`

Responsibilities:
- determine active rules
- calculate distinct qualifying products
- return validation result
- return user-facing progress data
- expose reusable API for cart/checkout/admin preview

Do not duplicate the same calculation in controller, Blade and JS.

## Validation timing

Validate:
- add to cart if appropriate
- update cart
- remove item
- before checkout
- before order creation/payment initiation

Race conditions and stale cart state must be handled.

## Order persistence

At order creation, store enough information to audit the rule result if business requires it.

At minimum, order creation must happen only after successful server-side validation.

Do not mutate cart to satisfy the rule automatically.

## Tests

Required tests:
- threshold 1
- threshold 4
- threshold 5
- duplicate quantity does not count as a distinct product
- N distinct products passes
- N-1 distinct products fails
- two different wholesale categories validate independently
- non-wholesale category unaffected
- category rule disabled
- product in multiple categories follows defined primary/qualifying category logic
- guest cart if guest checkout exists
- authenticated cart
- checkout cannot bypass validation
- concurrent/stale cart scenario where practical
