Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
banulakwin/laravel-pricing
claude-code
cursor
pricing
engine
tax
laravel
shipping
discount
coupon

Portable Laravel package: a small rule-based pricing engine with config toggles, injectable coupon validation, and defaults for coupon (percent), tax, and flat shipping.

Install
php artisan boost:add-skill banulakwin/laravel-pricing

Save this content to: AGENTS.md

# Agent guide: `banulakwin/laravel-pricing`

Portable Laravel package: a small rule-based pricing engine with config toggles, injectable coupon validation, and defaults for coupon (percent), tax, and flat shipping.

## Mental model

- **`PricingEngine`**: Central class that runs `PriceRule` instances in sequence. It builds a `PriceContext` containing the running subtotal, discount, tax, shipping, and total.
- **`PriceContext`**: State object passed through the engine pipeline. Contains line items, metadata (e.g., `user_id`), and running totals.
- **`PriceRule`**: Interface for rules (e.g., `CouponRule`, `TaxRule`, `ShippingRule`) that mutate the `PriceContext`.

## Multi-Item/Multi-User Coupons

- **Pivot Tables**: `coupon_items` (for targeted item matching) and `coupon_users` (for user redemption restrictions).
- **Global vs. Targeted**:
  - A coupon is **Global** if the `items` relation is empty. It applies its discount to the full subtotal.
  - A coupon is **Targeted** if `items` has entries. It calculates the eligible subtotal based on line items matching the `couponable_type` and optionally `couponable_id` and `item_subtype`.
  - A coupon is restricted to specific users if the `users` relation has entries. Unrestricted if empty.
- **`CouponRule` mechanics**:
  - The constructor expects the `$coupon` array to contain eagerly loaded `items` and `users`.
  - The `$mapping` constructor parameter maps the database columns to the structure of the incoming cart line items.
  - Validates `first_time_only` coupons dynamically by querying the `user_orders_relation` configured in `pricing.php`.
  - Validates `once_per_user` coupons by checking if the user has already redeemed the same coupon code.
  - Guest users are allowed through for `first_time_only` and `once_per_user` checks — server-side checkout re-validates once authenticated.
  - An optional `user_orders_scope` config can be set to apply a scope (e.g., `captured`) to order queries.

## Do

- Use `pricing()->engine()` or `Pricing::engine()` for a fresh mutable engine per calculation.
- Pass user context in `$meta` so user restrictions can be evaluated.
- Compose rules explicitly in your app — rule order matters.
- Define your `orders` relation to return only the orders you want counted (e.g., captured/paid orders) instead of using `user_orders_scope`.

## Do not

- Import `App\*` from the package.
- Cache a mutable engine — always get a new one per calculation.
- Hardcode API keys — use config/env.

## Testing & Quality

```bash
composer test          # PHPUnit
composer pint          # Laravel Pint code style fix
composer pint:check    # Pint check only (no fix)
composer phpstan       # PHPStan level max on src/
composer quality       # All: pint + phpstan + test
```

## CI

GitHub Actions runs tests, Pint, and PHPStan on push/PR (`.github/workflows/tests.yml`).

Agent guide: banulakwin/laravel-pricing

Portable Laravel package: a small rule-based pricing engine with config toggles, injectable coupon validation, and defaults for coupon (percent), tax, and flat shipping.

Mental model

  • PricingEngine: Central class that runs PriceRule instances in sequence. It builds a PriceContext containing the running subtotal, discount, tax, shipping, and total.
  • PriceContext: State object passed through the engine pipeline. Contains line items, metadata (e.g., user_id), and running totals.
  • PriceRule: Interface for rules (e.g., CouponRule, TaxRule, ShippingRule) that mutate the PriceContext.

Multi-Item/Multi-User Coupons

  • Pivot Tables: coupon_items (for targeted item matching) and coupon_users (for user redemption restrictions).
  • Global vs. Targeted:
    • A coupon is Global if the items relation is empty. It applies its discount to the full subtotal.
    • A coupon is Targeted if items has entries. It calculates the eligible subtotal based on line items matching the couponable_type and optionally couponable_id and item_subtype.
    • A coupon is restricted to specific users if the users relation has entries. Unrestricted if empty.
  • CouponRule mechanics:
    • The constructor expects the $coupon array to contain eagerly loaded items and users.
    • The $mapping constructor parameter maps the database columns to the structure of the incoming cart line items.
    • Validates first_time_only coupons dynamically by querying the user_orders_relation configured in pricing.php.
    • Validates once_per_user coupons by checking if the user has already redeemed the same coupon code.
    • Guest users are allowed through for first_time_only and once_per_user checks — server-side checkout re-validates once authenticated.
    • An optional user_orders_scope config can be set to apply a scope (e.g., captured) to order queries.

Do

  • Use pricing()->engine() or Pricing::engine() for a fresh mutable engine per calculation.
  • Pass user context in $meta so user restrictions can be evaluated.
  • Compose rules explicitly in your app — rule order matters.
  • Define your orders relation to return only the orders you want counted (e.g., captured/paid orders) instead of using user_orders_scope.

Do not

  • Import App\* from the package.
  • Cache a mutable engine — always get a new one per calculation.
  • Hardcode API keys — use config/env.

Testing & Quality

composer test          # PHPUnit
composer pint          # Laravel Pint code style fix
composer pint:check    # Pint check only (no fix)
composer phpstan       # PHPStan level max on src/
composer quality       # All: pint + phpstan + test

CI

GitHub Actions runs tests, Pint, and PHPStan on push/PR (.github/workflows/tests.yml).

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib