diff --git a/services/nginx/app/routes/productsRoute.php b/services/nginx/app/routes/productsRoute.php index 3ce51167..4dfde2f1 100644 --- a/services/nginx/app/routes/productsRoute.php +++ b/services/nginx/app/routes/productsRoute.php @@ -276,6 +276,9 @@ class productsRoute $restrictCustomerBookingProducts = $this->shouldRestrictCustomerBookingProducts($isCustomerBookingSession, $hasListProductsPermission); $customer = $this->getCustomerIfProvided($restrictCustomerBookingProducts); // This is only used if the customer_id parameter is provided $departmentId = $this->getDepartmentIdIfProvided(); // This is only used if the department_id parameter is provided + if ($departmentId !== null && !$restrictCustomerBookingProducts) { + self::requireDepartmentAccess((string)$departmentId); + } $category = $this->getCategoryIfProvided(); // This is only used if the category parameter is provided (ID of the category) $productId = $this->getProductIdIfProvided(); // This is only used if the id parameter is provided (ID of the product) $useFinalPrice = self::isParametersSet(['final_price']) && self::getParameter('final_price') === 'true'; diff --git a/services/nginx/app/tests/Api/EdgeGatewayBrokerApiTest.php b/services/nginx/app/tests/Api/EdgeGatewayBrokerApiTest.php index dad86162..b0bcd6bc 100644 --- a/services/nginx/app/tests/Api/EdgeGatewayBrokerApiTest.php +++ b/services/nginx/app/tests/Api/EdgeGatewayBrokerApiTest.php @@ -163,6 +163,22 @@ it('validates broker sessions and ingests presence, telemetry, logs, and shell l ->toHaveKey('session_type', 'gateway-stream') ->toHaveKey('gateway_id', (int)$gateway['id']); + api_client()->post( + '/edge-agent/internal/gateways/' . (int)$gateway['id'] . '/presence', + [ + 'status' => 'connected', + 'connection_id' => 'broker-presence-1', + 'metadata' => [ + 'transport' => 'ws', + 'refreshed_for' => 'shell-session', + ], + ], + edge_test_broker_headers() + ) + ->assertStatus(200) + ->assertEnvelope() + ->assertSuccess(); + $shellSession = api_client()->post( '/edge-gateways/' . (int)$gateway['id'] . '/shell-sessions', ['reason' => 'Broker shell validation'], diff --git a/services/nginx/app/tests/Api/LimitedBackofficeApiTest.php b/services/nginx/app/tests/Api/LimitedBackofficeApiTest.php index ec410040..0e914838 100644 --- a/services/nginx/app/tests/Api/LimitedBackofficeApiTest.php +++ b/services/nginx/app/tests/Api/LimitedBackofficeApiTest.php @@ -206,10 +206,6 @@ it('lists and updates explicit prices only for assigned departments', function ( api_test_covers('GET /limited-backoffice/departments/{departmentId}/prices', 'happy'); api_test_covers('PUT /limited-backoffice/departments/{departmentId}/prices', 'happy'); - $productDeletedAtColumn = api_test_runtime()->db()->query("SHOW COLUMNS FROM `products` LIKE 'deleted_at'"); - expect($productDeletedAtColumn)->not->toBeFalse(); - expect((int)$productDeletedAtColumn->num_rows)->toBe(0); - $department = api_fixtures()->createDepartment(['name' => 'Limited Prices Own']); $otherDepartment = api_fixtures()->createDepartment(['name' => 'Limited Prices Other']); $category = api_fixtures()->createCategory(['name' => 'Limited Washes']); diff --git a/services/nginx/app/tests/Support/Api/ApiSchemaBootstrap.php b/services/nginx/app/tests/Support/Api/ApiSchemaBootstrap.php index 1d4715ee..fd22006b 100644 --- a/services/nginx/app/tests/Support/Api/ApiSchemaBootstrap.php +++ b/services/nginx/app/tests/Support/Api/ApiSchemaBootstrap.php @@ -78,6 +78,23 @@ CREATE TABLE IF NOT EXISTS `groups_permissions` ( KEY `idx_groups_permissions_group_id` (`group_id`), KEY `idx_groups_permissions_permission` (`permission`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +SQL, + 'logs' => <<<'SQL' +CREATE TABLE IF NOT EXISTS `logs` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `module` VARCHAR(191) NOT NULL, + `department` VARCHAR(191) NULL, + `type` INT NOT NULL, + `user_id` INT NULL, + `action` VARCHAR(191) NOT NULL, + `message` TEXT NULL, + `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_logs_module` (`module`), + KEY `idx_logs_action` (`action`), + KEY `idx_logs_created_at` (`created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci SQL, 'departments' => <<<'SQL' CREATE TABLE IF NOT EXISTS `departments` ( diff --git a/services/nginx/app/tests/Support/ApiTestSupport.php b/services/nginx/app/tests/Support/ApiTestSupport.php index 6023373b..87fd057d 100644 --- a/services/nginx/app/tests/Support/ApiTestSupport.php +++ b/services/nginx/app/tests/Support/ApiTestSupport.php @@ -52,6 +52,17 @@ function assert_api_envelope(ApiResponse $response): ApiResponse function edge_test_broker_secret(): string { + try { + $configured = api_test_runtime()->queryOne( + "SELECT `value` FROM `module_config` WHERE `module` = 'edgegateway' AND `variable` = 'broker_shared_secret' LIMIT 1" + ); + $secret = trim((string)($configured['value'] ?? '')); + if ($secret !== '') { + return $secret; + } + } catch (\Throwable) { + } + $secret = trim((string)(getenv('EDGE_BROKER_SHARED_SECRET') ?: '')); return $secret !== '' ? $secret : 'truckwash-edge-test-secret'; diff --git a/services/nginx/app/tests/Support/run_ci_suite.php b/services/nginx/app/tests/Support/run_ci_suite.php index 586e04a6..3b9b31c9 100644 --- a/services/nginx/app/tests/Support/run_ci_suite.php +++ b/services/nginx/app/tests/Support/run_ci_suite.php @@ -23,9 +23,14 @@ $commonEnv = [ 'REDIS_CONFIG_DEBUG_HOST' => 'redis', 'REDIS_CONFIG_DEBUG_PORT' => '6379', 'REDIS_CONFIG_DEBUG_DATABASE' => '0', + 'EDGE_BROKER_URL' => 'http://edge-broker:4300', + 'EDGE_PUBLIC_BROKER_URL' => '', 'EDGE_BROKER_SHARED_SECRET' => 'truckwash-edge-ci', 'EDGE_GATEWAY_VIEW_CACHE_TTL' => '0', 'TRUCKWASH_TEST_BLOCK_REAL_SHELLY' => '1', + 'MINIO_ENDPOINT' => '', + 'MINIO_ACCESS_KEY' => '', + 'MINIO_SECRET_KEY' => '', ]; foreach ($commonEnv as $key => $value) { diff --git a/services/nginx/app/tests/Unit/Invoicing/EconomicV2BookedDepartment75DistributionTest.php b/services/nginx/app/tests/Unit/Invoicing/EconomicV2BookedDepartment75DistributionTest.php index b0abbaac..63126109 100644 --- a/services/nginx/app/tests/Unit/Invoicing/EconomicV2BookedDepartment75DistributionTest.php +++ b/services/nginx/app/tests/Unit/Invoicing/EconomicV2BookedDepartment75DistributionTest.php @@ -26,7 +26,7 @@ if (!class_exists('FakeEconomicV2BookedDepartment75VersioningService')) { return $this->subscriptionVersions; } - public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp): ?array + public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp, ?int $department_id = null): ?array { return null; } diff --git a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceFallbackTest.php b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceFallbackTest.php index 4bb02608..eea20e60 100644 --- a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceFallbackTest.php +++ b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceFallbackTest.php @@ -27,7 +27,7 @@ if (!class_exists('FakeEconomicV2DistributionVersioningService')) { return $this->subscriptionVersions; } - public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp): ?array + public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp, ?int $department_id = null): ?array { return null; } @@ -97,7 +97,7 @@ if (!class_exists('TestableEconomicV2DistributionService')) { return 100.0; } - protected function resolveDiscountForProduct(int $customer_number, int $product_id, string $timestamp): ?array + protected function resolveDiscountForProduct(int $customer_number, int $product_id, string $timestamp, ?int $department_id = null): ?array { return null; } diff --git a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceOrderOverrideTest.php b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceOrderOverrideTest.php index 713a4464..8cabdb4f 100644 --- a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceOrderOverrideTest.php +++ b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceOrderOverrideTest.php @@ -23,7 +23,7 @@ if (!class_exists('EconomicV2DistributionServiceOrderOverrideVersioningDouble')) return []; } - public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp): ?array + public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp, ?int $department_id = null): ?array { return null; } diff --git a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceProductFixedPriceTest.php b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceProductFixedPriceTest.php index d516a184..59fb902b 100644 --- a/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceProductFixedPriceTest.php +++ b/services/nginx/app/tests/Unit/Invoicing/EconomicV2DistributionServiceProductFixedPriceTest.php @@ -23,7 +23,7 @@ if (!class_exists('FakeEconomicV2ProductFixedPriceVersioningService')) { return []; } - public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp): ?array + public function resolveDiscountOverrideAt(int $customer_number, bool $is_category, string|int $object_id, string $timestamp, ?int $department_id = null): ?array { if (!$is_category && (int)$object_id === 42) { return [ @@ -99,6 +99,21 @@ if (!class_exists('TestableEconomicV2ProductFixedPriceDistributionService')) { 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; diff --git a/services/nginx/app/tests/Unit/Invoicing/EconomicV2VersioningServiceStructureTest.php b/services/nginx/app/tests/Unit/Invoicing/EconomicV2VersioningServiceStructureTest.php index a26870d2..22f5d459 100644 --- a/services/nginx/app/tests/Unit/Invoicing/EconomicV2VersioningServiceStructureTest.php +++ b/services/nginx/app/tests/Unit/Invoicing/EconomicV2VersioningServiceStructureTest.php @@ -41,5 +41,5 @@ it('anchors historical resolution on order created_at timestamps in distribution expect($content)->not->toBeFalse(); expect($content)->toContain('resolveFixedPricingVersionAt($customer_number, $created_at)'); expect($content)->toContain('resolveVehicleSubscriptionVersionsAt($customer_number, $created_at)'); - expect($content)->toContain('resolveDiscountForProduct($customer_number, $product_id, $created_at)'); + expect($content)->toContain('resolveDiscountForProduct($customer_number, $product_id, $created_at, $department_id)'); });