*/ public array $product_numbers = []; /** @var array */ public array $discount_responses = []; public function __construct() { } public function getCustomerProducts(int $customer_number, int $limit = 10, int $page = 1): object { return (object)[ 'collection' => array_map( fn (int|string $product_number): object => (object)[ 'product' => (object)[ 'productNumber' => (string)$product_number, ], ], $this->product_numbers ), ]; } public function getCustomerProductDiscount(int $customer_number, int $product_id) { $response = $this->discount_responses[$product_id] ?? (object)[ 'discountPercentage' => 0, ]; if ($response instanceof \RuntimeException) { throw $response; } return $response; } } it('falls back to a later customer template product when earlier probes fail on missing currency prices', function (): void { $economic = new economicCustomersDiscountFallbackTestDouble(); $economic->product_numbers = [1, 5, 9]; $economic->discount_responses = [ 1 => new RuntimeException('e-conomic request failed with HTTP 400: No price in currency EUR can be found for the product. | details={"httpStatusCode":400}'), 5 => (object)['discountPercentage' => 12], ]; expect($economic->getCustomerDiscountPercentage(23152645))->toBe(12); }); it('returns zero when every customer template lookup fails due to missing currency prices', function (): void { $economic = new economicCustomersDiscountFallbackTestDouble(); $economic->product_numbers = [1, 2, 3]; $economic->discount_responses = [ 1 => new RuntimeException('e-conomic request failed with HTTP 400: No price in currency EUR can be found for the product. | details={"httpStatusCode":400}'), 2 => new RuntimeException('e-conomic request failed with HTTP 400: No price in currency EUR can be found for the product. | details={"httpStatusCode":400}'), 3 => new RuntimeException('e-conomic request failed with HTTP 400: No price in currency EUR can be found for the product. | details={"httpStatusCode":400}'), ]; expect($economic->getCustomerDiscountPercentage(23152645))->toBe(0); }); it('rethrows unrelated discount lookup failures', function (): void { $economic = new economicCustomersDiscountFallbackTestDouble(); $economic->product_numbers = [1]; $economic->discount_responses = [ 1 => new RuntimeException('HTTP 503 upstream unavailable'), ]; expect(fn () => $economic->getCustomerDiscountPercentage(23152645)) ->toThrow(RuntimeException::class, 'HTTP 503 upstream unavailable'); });