$customer_number, 'is_category' => 0, 'object_id' => '42', 'discount' => 10, 'fixed_price' => 350, ]; } if ($is_category) { return [ 'customer_number' => $customer_number, 'is_category' => 1, 'object_id' => (string)$object_id, 'discount' => 80, 'fixed_price' => null, ]; } return null; } public function runBestEffortBackfill(): array { return []; } } } if (!class_exists('TestableEconomicV2ProductFixedPriceDistributionService')) { class TestableEconomicV2ProductFixedPriceDistributionService extends economic_v2_distribution_service { public function __construct() { parent::__construct(new FakeEconomicV2ProductFixedPriceVersioningService()); } public function exposeCalculateOrderOriginalPrice(array $order_items, int $customer_number, int $department_id, string $timestamp): float { return $this->calculateOrderOriginalPrice($order_items, $customer_number, $department_id, $timestamp); } protected function ensureVersionHistoryAvailable(array $areas): void { } protected function fetchOrdersInRange(string $from_ts, string $to_ts): array { return [[ 'id' => 1001, 'customer_id' => 35131752, 'department_id' => 7, 'created_at' => '2026-01-05 12:00:00', 'include_in_invoice' => 1, ]]; } protected function fetchOrderItemsByOrderIds(array $order_ids): array { return [ 1001 => [[ 'product_id' => 42, 'quantity' => 2, 'price' => 0, ]], ]; } protected function getProductDepartmentPrice(int $product_id, int $department_id): float { return 1000.0; } protected function resolveDiscountForProduct(int $customer_number, int $product_id, string $timestamp, ?int $department_id = null): ?array { if ($product_id !== 42) { return null; } return [ 'customer_number' => $customer_number, 'is_category' => 0, 'object_id' => '42', 'discount' => 10, 'fixed_price' => 350, ]; } protected function isOrderEligible(array $order): bool { return true; } protected function shouldIncludeCustomerNumber(int $customer_number): bool { return $customer_number > 0; } protected function parseDepartmentMap(array $department_map): array { $parsed = []; foreach ($department_map as $department_id => $amount) { $parsed['Department ' . $department_id] = round((float)$amount, 5); } return $parsed; } protected function buildCustomerEnvelope(int $customer_number, array $transaction_map): array { return [ 'id' => $customer_number, 'customer_number' => $customer_number, 'customer_name' => 'Customer ' . $customer_number, 'transactions' => array_values($transaction_map), 'requires_action' => false, 'meta' => [], ]; } protected function buildTransactionObject(int $order_id, string $created_at, int $department_id, ?float $amount = null, ?bool $included = null): array { return [ 'id' => $order_id, 'date' => $created_at, 'amount' => round((float)($amount ?? 0.0), 5), 'booked' => true, 'department_id' => $department_id, 'excluded' => !($included ?? true), ]; } } } it('uses product fixed prices before discounts in customer price distributions', function (): void { $service = new TestableEconomicV2ProductFixedPriceDistributionService(); $result = $service->getCustomerPricesDistribution('2026-01-01', '2026-01-31'); expect($result['collective_results']['total_discount_amount'])->toBe(1300.0); expect($result['collective_results']['department_discount_totals'][7])->toBe(1300.0); expect($result['customers'][0]['meta']['customer_prices']['discount_total'])->toBe(1300.0); expect($result['customers'][0]['transactions'][0]['amount'])->toBe(1300.0); expect($service->exposeCalculateOrderOriginalPrice( [[ 'product_id' => 42, 'quantity' => 2, 'price' => 0, ]], 35131752, 7, '2026-01-05 12:00:00' ))->toBe(700.0); });