feat(enums): add SERVICE product type; fix flaky multi-product checkout test

- ProductType::SERVICE for intangible/served products (subscriptions, licences,
  consulting) — no stock, behaves like SIMPLE for cart purposes. Lets hosts
  whose catalogue includes services adopt the package without a value clash.
- it_creates_separate_line_items_for_multiple_products pinned its two prices to
  one_time; without a type the factory randomised it and could mix recurring +
  one-time, tripping MixedCheckoutModeException intermittently.
This commit is contained in:
Fabian @ Blax Software 2026-06-03 09:49:12 +02:00
parent d4ae9339ac
commit db827bbb8c
3 changed files with 12 additions and 2 deletions

View File

@ -4,7 +4,7 @@
[![Tests](https://github.com/blax-software/laravel-shop/actions/workflows/tests.yml/badge.svg)](https://github.com/blax-software/laravel-shop/actions/workflows/tests.yml) [![Tests](https://github.com/blax-software/laravel-shop/actions/workflows/tests.yml/badge.svg)](https://github.com/blax-software/laravel-shop/actions/workflows/tests.yml)
[![Tests Count](https://img.shields.io/badge/tests-1409%20passing-success?style=flat-square)](#testing) [![Tests Count](https://img.shields.io/badge/tests-1409%20passing-success?style=flat-square)](#testing)
[![Assertions](https://img.shields.io/badge/assertions-3772-blue?style=flat-square)](#testing) [![Assertions](https://img.shields.io/badge/assertions-3773-blue?style=flat-square)](#testing)
[![Latest Version](https://img.shields.io/packagist/v/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop) [![Latest Version](https://img.shields.io/packagist/v/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop)
[![License](https://img.shields.io/packagist/l/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop) [![License](https://img.shields.io/packagist/l/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop)
[![PHP Version](https://img.shields.io/packagist/php-v/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop) [![PHP Version](https://img.shields.io/packagist/php-v/blax-software/laravel-shop.svg?style=flat-square)](https://packagist.org/packages/blax-software/laravel-shop)
@ -192,7 +192,7 @@ booking, Stripe sync and the event surface — so host applications can lean
on the behaviour with confidence. on the behaviour with confidence.
``` ```
Tests: 1409, Assertions: 3772 Tests: 1409, Assertions: 3773
``` ```
CI runs the full suite on every push (see the badge above). To run it CI runs the full suite on every push (see the badge above). To run it

View File

@ -19,6 +19,13 @@ enum ProductType: string
* the borrow extend return flow. * the borrow extend return flow.
*/ */
case LOANABLE = 'loanable'; case LOANABLE = 'loanable';
/**
* Service: an intangible/served product (subscriptions, access licences,
* consulting) with no physical stock. Behaves like SIMPLE for cart/stock
* purposes; the distinct type just lets hosts and reporting tell goods
* from services apart.
*/
case SERVICE = 'service';
public function label(): string public function label(): string
{ {
@ -31,6 +38,7 @@ enum ProductType: string
self::VARIATION => 'Variation', self::VARIATION => 'Variation',
self::POOL => 'Pool', self::POOL => 'Pool',
self::LOANABLE => 'Loanable', self::LOANABLE => 'Loanable',
self::SERVICE => 'Service',
}; };
} }
} }

View File

@ -234,6 +234,7 @@ class CartCheckoutSessionTest extends TestCase
'unit_amount' => 1000, 'unit_amount' => 1000,
'currency' => 'USD', 'currency' => 'USD',
'is_default' => true, 'is_default' => true,
'type' => 'one_time',
]); ]);
ProductPrice::factory()->create([ ProductPrice::factory()->create([
@ -242,6 +243,7 @@ class CartCheckoutSessionTest extends TestCase
'unit_amount' => 2000, 'unit_amount' => 2000,
'currency' => 'USD', 'currency' => 'USD',
'is_default' => true, 'is_default' => true,
'type' => 'one_time',
]); ]);
$this->cart->addToCart($product1, 2); $this->cart->addToCart($product1, 2);