Files
api/services/nginx/app/tests/Api/SelfserveCustomerStartApiTest.php
T

514 lines
18 KiB
PHP

<?php
usesApiSuite();
function selfserve_customer_start_ensure_legacy_redis_constant(): void
{
if (defined('redis')) {
return;
}
global $REDIS_CONFIG;
$REDIS_CONFIG = [
'host' => getenv('REDIS_CONFIG_HOST') ?: getenv('REDIS_CONFIG_DEBUG_HOST') ?: 'redis',
'user' => getenv('REDIS_CONFIG_USER') ?: getenv('REDIS_CONFIG_DEBUG_USER') ?: 'default',
'database' => getenv('REDIS_CONFIG_DATABASE') ?: getenv('REDIS_CONFIG_DEBUG_DATABASE') ?: '0',
'password' => getenv('REDIS_CONFIG_PASSWORD') ?: getenv('REDIS_CONFIG_DEBUG_PASSWORD') ?: '',
'port' => getenv('REDIS_CONFIG_PORT') ?: getenv('REDIS_CONFIG_DEBUG_PORT') ?: '6379',
];
define('redis', (new \classes\redis())->connect());
}
function selfserve_customer_start_make_available(int $laneId): void
{
selfserve_customer_start_ensure_legacy_redis_constant();
$lane = (new \classes\selfserve())->lane($laneId);
$lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::AVAILABLE);
$lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IDLE);
$lane->setCustomerNumber(0);
$lane->setLicensePlate('');
$lane->setWashStartTime(0);
}
it('allows the customer self-serve start sequence without department access', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
selfserve_customer_start_make_available($laneId);
api_client()
->get('/department/selfserve/vehicle/allowed?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
->assertStatus(200)
->assertSuccess(true);
$summaryResponse = api_client()
->get('/department/selfserve/washes/summary?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
->assertStatus(200)
->assertSuccess(true);
expect($summaryResponse->data()['session']['customer_number'] ?? null)
->toBe((int)$scenario['customer']['customer_number']);
api_client()
->post('/modules/self-serve/lane/services/allowed', [
'lane_id' => $laneId,
'task_ids' => [(int)$scenario['tasks'][1]['id']],
], $headers)
->assertStatus(200)
->assertSuccess(true);
$startResponse = api_client()
->post('/modules/self-serve/lane/command', [
'lane_id' => $laneId,
'command' => 'START',
'license_plate' => $reg,
'wash_type' => 'Manual',
'defer_relay_side_effects' => true,
], $headers)
->assertStatus(200)
->assertSuccess(true);
expect($startResponse->data()['status'] ?? null)->toBe('OCCUPIED')
->and($startResponse->data()['customer_number'] ?? null)
->toBe((int)$scenario['customer']['customer_number']);
});
it('marks the active customer session relay-enabled after machine relay enable', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
'modules_selfserve_lane_relay_enable_machine',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
'session' => [
'status' => 'READY_FOR_MACHINE_START',
'machine_relay_enabled' => 0,
'machine_relay_enabled_at' => null,
'machine_start_triggered' => 0,
'machine_start_triggered_at' => null,
'wash_started_at' => null,
],
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
$machineTaskId = (int)$scenario['tasks'][1]['id'];
selfserve_customer_start_make_available($laneId);
api_client()
->get('/department/selfserve/vehicle/allowed?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
->assertStatus(200)
->assertSuccess(true);
api_client()
->post('/modules/self-serve/lane/services/allowed', [
'lane_id' => $laneId,
'task_ids' => [$machineTaskId],
], $headers)
->assertStatus(200)
->assertSuccess(true);
api_client()
->post('/modules/self-serve/lane/command', [
'lane_id' => $laneId,
'command' => 'START',
'license_plate' => $reg,
'wash_type' => 'Machine',
'defer_relay_side_effects' => true,
], $headers)
->assertStatus(200)
->assertSuccess(true);
api_client()
->post('/modules/self-serve/lane/relay/machine/enable', [
'lane_id' => $laneId,
], $headers)
->assertStatus(200)
->assertSuccess(true);
$activeResponse = api_client()
->get('/modules/self-serve/lane/wash/my-active-wash', $headers)
->assertStatus(200)
->assertSuccess(true);
expect($activeResponse->data()['session']['status'] ?? null)->toBe('MACHINE_RELAY_ENABLED')
->and($activeResponse->data()['session']['machine_relay_enabled'] ?? null)->toBeTrue()
->and($activeResponse->data()['session']['machine_start_triggered'] ?? null)->toBeFalse();
});
it('derives allowed services from v2 session task snapshots when task rows are not legacy records', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$v2TaskId = 900000 + $laneId;
$sessionTask = (new \objects\selfserve_wash_session_tasks_o())->addSnapshot(
(int)$scenario['session']['id'],
$v2TaskId,
'V2 path editor machine task',
'Task exists only in the session snapshot.',
['MACHINE', 'PROGRAM_PICKER'],
['program_picker', 6, 'start'],
(int)$scenario['product']['id'],
);
try {
$response = api_client()
->post('/modules/self-serve/lane/services/allowed', [
'lane_id' => $laneId,
'task_ids' => [$v2TaskId],
], $headers)
->assertStatus(200)
->assertSuccess(true);
expect($response->data()['allowed_services'] ?? [])->toBe([
'MACHINE',
'PROGRAM_PICKER',
]);
} finally {
$sessionTask->delete();
}
});
it('derives allowed services from published v2 config task snapshots when no session exists yet', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
'session' => [
'status' => 'COMPLETED',
'completed_at' => date('Y-m-d H:i:s'),
'wash_started_at' => date('Y-m-d H:i:s'),
],
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$departmentId = (int)$scenario['department']['id'];
$productId = (int)$scenario['product']['id'];
$v2TaskId = 910000 + $laneId;
$configVersion = (new \objects\selfserve_config_versions_o())->add(
$departmentId,
\modules\selfserve\classes\selfserve_config_versioning::STATUS_PUBLISHED,
1,
[
'schema_version' => 2,
'tasks' => [
[
'id' => $v2TaskId,
'department' => $departmentId,
'lane' => $laneId,
'product' => $productId,
'machine_type_id' => 0,
'task' => 'Published v2 machine task',
'description' => 'Task exists only in the published config snapshot.',
'order_priority' => 10,
'services' => ['MACHINE', 'PROGRAM_PICKER'],
],
],
],
null,
null,
null,
date('Y-m-d H:i:s'),
);
try {
$response = api_client()
->post('/modules/self-serve/lane/services/allowed', [
'lane_id' => $laneId,
'task_ids' => [$v2TaskId],
], $headers)
->assertStatus(200)
->assertSuccess(true);
expect($response->data()['allowed_services'] ?? [])->toBe([
'MACHINE',
'PROGRAM_PICKER',
]);
} finally {
$configVersion->delete();
}
});
it('keeps long generated task descriptions when refreshing vehicle eligibility snapshots', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
$productId = (int)$scenario['product']['id'];
$taskId = (int)$scenario['tasks'][1]['id'];
$longDescription = str_repeat('Hvis ja - vaelg tagboerste program (#6) og lift program (#2) / ', 6);
$statement = api_test_runtime()->db()->prepare(
'UPDATE department_selfserve_tasks SET description = ? WHERE id = ?'
);
$statement->bind_param('si', $longDescription, $taskId);
$statement->execute();
api_client()
->get(
'/department/selfserve/vehicle/allowed?lane_id=' . $laneId
. '&reg=' . urlencode($reg)
. '&vehicle_type=' . $productId,
$headers
)
->assertStatus(200)
->assertSuccess(true);
$sessionTask = api_test_runtime()->queryOne(
'SELECT description FROM selfserve_wash_session_tasks'
. ' WHERE session_id = ' . (int)$scenario['session']['id']
. ' AND task_id = ' . $taskId
. ' LIMIT 1'
);
expect($sessionTask['description'] ?? null)->toBe($longDescription);
});
it('does not create an active wash preview session from read-only eligibility checks', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
$productId = (int)$scenario['product']['id'];
$sessionId = (int)$scenario['session']['id'];
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_events WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_tasks WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_answers WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_sessions WHERE id = ' . $sessionId
);
selfserve_customer_start_make_available($laneId);
api_client()
->get(
'/department/selfserve/vehicle/allowed?lane_id=' . $laneId
. '&reg=' . urlencode($reg)
. '&vehicle_type=' . $productId,
$headers
)
->assertStatus(200)
->assertSuccess(true);
$openSession = api_test_runtime()->queryOne(
'SELECT id FROM selfserve_wash_sessions'
. ' WHERE lane_id = ' . $laneId
. ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
. ' AND completed_at IS NULL'
. ' AND deleted_at IS NULL'
. ' LIMIT 1'
);
expect($openSession)->toBeNull();
});
it('creates a durable wash session from customer start after read-only eligibility', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
$productId = (int)$scenario['product']['id'];
$sessionId = (int)$scenario['session']['id'];
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_events WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_tasks WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_session_answers WHERE session_id = ' . $sessionId
);
api_test_runtime()->db()->query(
'DELETE FROM selfserve_wash_sessions WHERE id = ' . $sessionId
);
selfserve_customer_start_make_available($laneId);
api_client()
->get(
'/department/selfserve/vehicle/allowed?lane_id=' . $laneId
. '&reg=' . urlencode($reg)
. '&vehicle_type=' . $productId,
$headers
)
->assertStatus(200)
->assertSuccess(true);
api_client()
->post('/modules/self-serve/lane/command', [
'lane_id' => $laneId,
'command' => 'START',
'license_plate' => $reg,
'defer_relay_side_effects' => true,
], $headers)
->assertStatus(200)
->assertSuccess(true);
$openSession = api_test_runtime()->queryOne(
'SELECT id, status, customer_number FROM selfserve_wash_sessions'
. ' WHERE lane_id = ' . $laneId
. ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
. ' AND completed_at IS NULL'
. ' AND deleted_at IS NULL'
. ' ORDER BY id DESC LIMIT 1'
);
expect($openSession)->not->toBeNull()
->and((int)$openSession['customer_number'])->toBe((int)$scenario['customer']['customer_number'])
->and($openSession['status'])->toBe('READY_FOR_MACHINE_START');
selfserve_customer_start_make_available($laneId);
});
it('refreshes an active wash summary with vehicle type without a namespace error', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
'session' => [
'status' => 'MACHINE_RELAY_ENABLED',
'machine_relay_enabled' => 1,
'machine_relay_enabled_at' => date('Y-m-d H:i:s'),
'completed_at' => null,
],
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$sessionId = (int)$scenario['session']['id'];
$productId = (int)$scenario['product']['id'];
$summaryResponse = api_client()
->get(
'/department/selfserve/washes/summary?session_id=' . $sessionId
. '&vehicle_type=' . $productId,
$headers
)
->assertStatus(200)
->assertSuccess(true);
expect($summaryResponse->data()['session']['id'] ?? null)->toBe($sessionId)
->and($summaryResponse->data()['session']['status'] ?? null)->toBe('MACHINE_RELAY_ENABLED');
});
it('does not create a replacement session when refreshing a completed summary with vehicle type', function (): void {
$group = api_fixtures()->createGroup([], [
'list_own_department_selfserve_vehicle_conditions',
]);
$scenario = api_fixtures()->createSelfServeScenario([
'customer' => ['group_id' => $group['id']],
'department_selfserve_enabled' => true,
'lane_selfserve_enabled' => true,
'session' => [
'status' => 'COMPLETED',
'completed_at' => date('Y-m-d H:i:s'),
],
]);
$headers = api_fixtures()->bearerHeaders(
api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
);
$laneId = (int)$scenario['lane']['id'];
$reg = (string)$scenario['vehicle']['reg'];
$productId = (int)$scenario['product']['id'];
$sessionId = (int)$scenario['session']['id'];
selfserve_customer_start_make_available($laneId);
$summaryResponse = api_client()
->get(
'/department/selfserve/washes/summary?lane_id=' . $laneId
. '&reg=' . urlencode($reg)
. '&vehicle_type=' . $productId,
$headers
)
->assertStatus(200)
->assertSuccess(true);
expect($summaryResponse->data()['session']['id'] ?? null)->toBe($sessionId)
->and($summaryResponse->data()['session']['status'] ?? null)->toBe('COMPLETED');
$openSession = api_test_runtime()->queryOne(
'SELECT id FROM selfserve_wash_sessions'
. ' WHERE lane_id = ' . $laneId
. ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
. ' AND completed_at IS NULL'
. ' AND deleted_at IS NULL'
. ' LIMIT 1'
);
expect($openSession)->toBeNull();
});