Commit Graph

140 Commits

Author SHA1 Message Date
Fabian @ Blax Software d4ae9339ac feat(subscriptions): Cashier-backed subscription lifecycle with product link + events
Adds the package's missing subscription lifecycle so any host app gets
duration-aware, product-linked subscriptions without re-implementing billing:

- Models: Subscription (extends Laravel\Cashier\Subscription) + SubscriptionItem,
  in the package's UUID convention, resolved through shop.models/shop.tables.
  Subscription gains product()/resolveProduct(), callProductActions() (runs the
  product's ProductActions with the subscription + an access-expiry override),
  and recordStarted()/recordRenewed()/recordCanceled() lifecycle hooks.
- Events: SubscriptionStarted / SubscriptionRenewed / SubscriptionCanceled,
  carrying the Cashier subscription so host subclasses work too.
- Migration: UUID subscriptions / subscription_items tables (hasTable-guarded,
  config table names, nullable product_id + current_period_* columns).
- ShopServiceProvider points Cashier at these models by default; opt out via
  shop.subscriptions.register_cashier_models for apps that subclass Cashier.

Additive and backward-compatible (registration is config-gated, tables are
guarded). Adds SubscriptionLifecycleTest; full suite 1409 green. Docs + README.
2026-06-02 11:40:15 +02:00
Fabian @ Blax Software 96b9a19287 feat(fulfillment): add model-agnostic PurchaseCompleted event
Introduce a first-class PurchaseCompleted lifecycle event so host apps can run
fulfillment (grant access, send receipts, provision licences) without coupling
to the ProductAction table or to a concrete purchasable model. It fires when a
purchase is created already-COMPLETED and when one transitions into COMPLETED,
and is transition-guarded so it does not re-fire on unrelated saves of an
already-completed purchase.

Also generalise the built-in ProductAction fulfillment in ProductPurchase:
the actionable product is now resolved via config('shop.models.product') /
'...product_price' (instead of a hard instanceof the bundled Product), and
callActions() is only invoked when the resolved product exposes it — so apps
overriding the models, or using IsSimplePurchasable host models, complete
cleanly. Existing behaviour for the bundled Product is unchanged.

Adds 4 EventsWiredUpTest cases; full suite 1404 green. Docs + README updated.
2026-06-02 11:19:21 +02:00
Fabian @ Blax Software 30dc3755d2 test: pin clock in loan-vocabulary test; docs: bump suite counts to 1400/3755
PurchaseResourceTest::it_translates_e_commerce_columns_into_loan_vocabulary
relied on the real wall clock falling inside the fixture's loan window
(2026-05-14..2026-05-28); once that window passed, the loan resolved to
`overdue` and the test failed. Freeze the clock inside the window like its
sibling tests already do.

Update the README test/assertion badges and the Testing section to the current
suite size (1400 tests, 3755 assertions) after the subscription-checkout tests.
2026-06-02 09:48:26 +02:00
Fabian @ Blax Software d4008caec0 feat(checkout): support subscription/recurring carts in Stripe Checkout
Cart::checkoutSession() now inspects each line's price type and selects the
session mode automatically: `subscription` when the cart carries any recurring
price, `payment` otherwise. Recurring lines reuse a synced Stripe Price
(stripe_price_id) when present and fall back to dynamic price_data with a
`recurring` block otherwise; quarterly cadence maps to a 3-month interval since
Stripe has no native quarter. The cart id is propagated via subscription_data
metadata for webhook mapping.

Mixing recurring and one-time prices in one cart throws the new
MixedCheckoutModeException, since a Stripe Checkout session is single-mode.

The recurring resolver tolerates both the package's enum-cast price model and a
host model storing type/interval as plain strings, so it keeps working when
shop.models.product_price is overridden.
2026-06-02 09:34:32 +02:00
Fabian @ Blax Software 4712133eac IAM "max usage" feature 2026-05-19 14:01:52 +02:00
Fabian @ Blax Software 6d22e130ed A cart availability + test 2026-05-19 11:17:35 +02:00
Fabian @ Blax Software 0cfbdf221d BF edgecases, R structure, A tests 2026-05-18 13:05:38 +02:00
Fabian @ Blax Software ab8ea6afec BF stock calculation 2026-05-18 11:54:11 +02:00
Fabian @ Blax Software 0bb3b63a32 BF model methods 2026-05-18 08:16:09 +02:00
Fabian @ Blax Software 1ed301b759 R loan purchase to physical loan, A physical loan stuff 2026-05-17 15:20:58 +02:00
Fabian @ Blax Software da6d89f668 BFI commands, A test 2026-05-17 14:09:03 +02:00
Fabian @ Blax Software 2bc64c6369 BF stocks, A test 2026-05-17 13:57:20 +02:00
Fabian @ Blax Software 99fd71f4ae BF commands, A command tests, I traits
- Implement CommandReinstallTest to verify the behavior of the shop:reinstall command, including force and fresh flags, and confirmation prompts.
- Create CommandReleaseExpiredStocksTest to test the shop:release-expired-stocks command, ensuring it correctly releases expired stock claims based on configuration.
- Add CommandStatsTest to validate the shop:stats command, checking counts and revenue calculations for products, purchases, carts, and orders.
- Introduce LoanShopCommandsTest to cover loanable products in stock management, ensuring accurate reporting of assigned, used, and available stock.
- Implement LoanStockEventsTest to verify that stock events are dispatched correctly during loan operations, including checkouts and returns.
- Add NextAvailableAtTest to ensure the nextAvailableAt method behaves correctly for loanable products, considering loans and claims.
2026-05-17 13:25:34 +02:00
Fabian @ Blax Software ee64e86345 BF commands 2026-05-17 11:53:19 +02:00
Fabian @ Blax Software f55c7e11df A events, IA commands
- Introduced events for stock management including StockBecameLow, StockClaimed, StockClaimExpired, StockDecreased, StockDepleted, StockIncreased, StockReleased, StockReplenished, StockFullyAvailable, and StockFullyAvailable.
- Added events for Stripe payment processing: StripePaymentFailed, StripePaymentSucceeded, StripePriceSynced, StripeProductSynced, StripeRefundProcessed, and StripeWebhookReceived.
- Created tests for command availability, listing, stocks, and event dispatching to ensure proper functionality and integration.
2026-05-17 11:24:43 +02:00
Fabian @ Blax Software 8eb1802ef8 feat: promote IsLoanableProduct to MayBeLoanableProduct on Product
Renames the host-attached IsLoanableProduct trait to MayBeLoanableProduct
and mixes it directly into Product, matching the existing MayBePoolProduct
shape. Hosts opt in with a single DEFAULT_TYPE constant — no more manual
`use ...Trait` ceremony to forget:

    class Book extends Product
    {
        public const DEFAULT_TYPE = ProductType::LOANABLE;
    }

The boot hook reads DEFAULT_TYPE on the concrete class and only applies
the LOANABLE creating-defaults (type, status, is_visible, manage_stock)
when it matches; type-specific helpers (checkOutTo, total_quantity,
available_quantity) early-out via isLoanable() so they're harmless on
non-loanable products. checkOutTo now throws NotLoanableProductException
when called on the wrong type, mirroring NotPoolProductException.

Also fixes total_quantity for the loan lifecycle: previously summed every
INCREASE entry in product_stocks, which inflated the displayed total
after each loan cycle because returns fire increaseStock(). Now reports
physical inventory as availableStock + activeLoans.

README gains a Testing section that surfaces the current phpunit summary
line, plus passing and assertion-count badges linking to it.
2026-05-16 12:17:38 +02:00
Fabian @ Blax Software afdcd8bc75 feat: Enhance traits with strict types and improve method signatures
- Added strict types declaration to multiple traits for better type safety.
- Updated method signatures in traits to use nullable types where applicable.
- Improved documentation for traits, including host-model contracts and method descriptions.
- Added new tests to ensure correct behavior of loan checkout and stock management.
- Fixed regression in order number generation to ensure proper string formatting.
- Ensured that currency codes sent to Stripe are consistently lowercased.
2026-05-15 20:26:24 +02:00
Fabian @ Blax Software 7415da3531 I loanprovider 2026-05-15 12:17:58 +02:00
Fabian @ Blax Software d6a03f413a D unused files 2026-05-15 11:01:02 +02:00
Fabian @ Blax Software fe41475c84 I loanable product type, tiered pricing, lifecycle events, host helpers 2026-05-15 10:27:59 +02:00
Fabian @ Blax Software 80bc7293b1 I readme 2026-05-14 10:44:31 +02:00
Fabian @ Blax Software 3d66114163 BF lineitem currency 2026-01-25 11:11:55 +01:00
Fabian @ Blax Software 440be3a36f I order notes, BF checkout currency 2026-01-25 10:40:17 +01:00
Fabian @ Blax Software 1a8f111110 I order 2026-01-05 12:29:55 +01:00
Fabian @ Blax Software a66fd7ccb8 BFI cart / orders 2026-01-05 10:30:21 +01:00
Fabian @ Blax Software cbb4b84948 BF cart/pool/booking 2026-01-05 09:07:09 +01:00
Fabian @ Blax Software c0ae7c4927 BF pool cart bug, R structure 2025-12-30 10:56:03 +01:00
Fabian @ Blax Software 2ea8273c29 BF pool cart bug, R structure 2025-12-30 10:55:06 +01:00
Fabian @ Blax Software 136b7ade63 A prompts, I docs/readme, BF orders, R tests locations 2025-12-30 09:29:43 +01:00
Fabian @ Blax Software 7aeffd27a9 RI optimizations 2025-12-29 11:11:27 +01:00
Fabian @ Blax Software 6e9c9043ae I order, A handy methods 2025-12-29 10:26:51 +01:00
Fabian @ Blax Software 9c1fcd6cfd AM orders 2025-12-29 09:59:02 +01:00
Fabian @ Blax Software 1486424229 BF checkout session test 2025-12-29 08:26:09 +01:00
Fabian @ Blax Software adbc3d89bf BF checkout session 2025-12-29 08:14:58 +01:00
Fabian @ Blax Software 76d60c328b I cart/items 2025-12-28 12:19:56 +01:00
Fabian @ Blax Software 2f3c0dc61f IA stock attributes 2025-12-28 12:05:05 +01:00
Fabian @ Blax Software 7cd11728b1 BFRI cart 2025-12-28 11:12:58 +01:00
Fabian @ Blax Software 6beecf597c BF has_more, I hasprices->fromPrice 2025-12-28 10:48:22 +01:00
Fabian @ Blax Software 37b3e6bdc0 A cart->calendarAvailability, product->has_more 2025-12-28 10:29:23 +01:00
a6a2f5842 fc3ae3e756 A pool availabilities 2025-12-26 16:45:30 +01:00
a6a2f5842 5ac0229555 A stock methods calendarAvailability & dayAvailability 2025-12-26 16:10:40 +01:00
a6a2f5842 38e841a986 I test 2025-12-26 08:46:14 +01:00
a6a2f5842 70adf0b0c6 BFI cart availability 2025-12-26 08:42:59 +01:00
a6a2f5842 9e7812c70e BFI cart single item 2025-12-24 19:40:10 +01:00
Fabian @ Blax Software 816e8661e2 BF cart items 2025-12-20 15:08:08 +01:00
Fabian @ Blax Software 1398fd0c27 BF cart items 2025-12-20 12:43:28 +01:00
Fabian @ Blax Software 0e6b420297 BFI pool cart 2025-12-20 12:19:34 +01:00
Fabian @ Blax Software 20e6538626 BFI pool cart 2025-12-20 11:22:04 +01:00
Fabian @ Blax Software 145c629786 BFI cart stock, A exceptions 2025-12-19 14:26:57 +01:00
Fabian @ Blax Software 317b28af8a BFIM pool cart checkout, stocks/productpurchase 2025-12-19 13:32:00 +01:00