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

465 lines
17 KiB
PHP

<?php
declare(strict_types=1);
usesApiSuite();
function vehicles_without_customer_vehicles_deleted_at(callable $callback): void
{
$db = api_test_runtime()->db();
$column = $db->query("SHOW COLUMNS FROM `customer_vehicles` LIKE 'deleted_at'");
if ($column === false) {
throw new RuntimeException('Unable to inspect customer_vehicles.deleted_at test column.');
}
$hadColumn = (int)$column->num_rows > 0;
if ($hadColumn) {
$db->query('ALTER TABLE `customer_vehicles` DROP COLUMN `deleted_at`');
}
try {
$callback();
} finally {
if ($hadColumn) {
$db->query('ALTER TABLE `customer_vehicles` ADD COLUMN `deleted_at` DATETIME NULL');
}
}
}
it('defaults wash subscriptions to false when a customer creates a vehicle without the field', function (): void {
api_test_covers('POST /vehicles', 'happy');
$session = api_fixtures()->createUserSession(['add_vehicle']);
$response = api_client()->post('/vehicles', [
'type' => 53,
'reg' => 'DEFAULTOWN',
], $session['headers']);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$vehicleId = (int)($response->data()['id'] ?? 0);
expect($vehicleId)->toBeGreaterThan(0);
$row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
expect($row)->not->toBeNull();
expect((int)$row['customer_id'])->toBe((int)$session['user']['customer_number']);
expect((int)$row['wash_subscription'])->toBe(0);
expect($response->data())->toMatchArray([
'id' => $vehicleId,
'customer_id' => (int)$session['user']['customer_number'],
'reg' => 'DEFAULTOWN',
'wash_subscription' => false,
]);
api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});
it('defaults wash subscriptions to false when a superuser creates a vehicle for another customer without the field', function (): void {
api_test_covers('POST /vehicles', 'happy');
$targetCustomer = api_fixtures()->createUser(['display_name' => 'Vehicle Default Target Customer']);
$session = api_fixtures()->createUserSession(['add_vehicle_other']);
$response = api_client()->post('/vehicles', [
'customer_id' => $targetCustomer['customer_number'],
'type' => 53,
'reg' => 'DEFAULTSU',
], $session['headers']);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$vehicleId = (int)($response->data()['id'] ?? 0);
expect($vehicleId)->toBeGreaterThan(0);
$row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
expect($row)->not->toBeNull();
expect((int)$row['customer_id'])->toBe((int)$targetCustomer['customer_number']);
expect((int)$row['wash_subscription'])->toBe(0);
expect($response->data())->toMatchArray([
'id' => $vehicleId,
'customer_id' => (int)$targetCustomer['customer_number'],
'reg' => 'DEFAULTSU',
'wash_subscription' => false,
]);
api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});
it('still honors an explicit wash subscription true value on vehicle create', function (): void {
api_test_covers('POST /vehicles', 'happy');
$session = api_fixtures()->createUserSession(['add_vehicle']);
$response = api_client()->post('/vehicles', [
'type' => 53,
'reg' => 'EXPLICITON',
'wash_subscription' => true,
], $session['headers']);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$vehicleId = (int)($response->data()['id'] ?? 0);
expect($vehicleId)->toBeGreaterThan(0);
$row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
expect($row)->not->toBeNull();
expect((int)$row['wash_subscription'])->toBe(1);
expect($response->data())->toMatchArray([
'id' => $vehicleId,
'reg' => 'EXPLICITON',
'wash_subscription' => true,
]);
api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});
it('returns the newest vehicle last_order_id that still has order items', function (): void {
api_test_covers('GET /vehicles', 'happy');
$session = api_fixtures()->createUserSession(['list_own_vehicles']);
$department = api_fixtures()->createDepartment(['name' => 'Vehicle API Department']);
$vehicle = api_fixtures()->createVehicle([
'customer_id' => $session['user']['customer_number'],
'type' => 53,
'reg' => 'SIDSTEV1',
'reference' => 'VEHICLE-LAST-WASH',
]);
$olderOrder = api_fixtures()->createOrder([
'customer_id' => $session['user']['customer_number'],
'cashier_id' => $session['user']['id'],
'department_id' => $department['id'],
'reference' => 'OLDER-ORDER',
'reg_1' => $vehicle['reg'],
]);
api_fixtures()->createOrderItem([
'order_id' => $olderOrder['id'],
'product_id' => 53,
'cashier_id' => $session['user']['id'],
'price' => 599,
'quantity' => 1,
]);
$newerOrder = api_fixtures()->createOrder([
'customer_id' => $session['user']['customer_number'],
'cashier_id' => $session['user']['id'],
'department_id' => $department['id'],
'reference' => 'NEWER-ORDER',
'reg_1' => $vehicle['reg'],
]);
$response = api_client()->get('/vehicles?id=' . $vehicle['id'], $session['headers']);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
expect($newerOrder['id'])->toBeGreaterThan($olderOrder['id']);
expect($response->data())->toMatchArray([
'id' => $vehicle['id'],
'reg' => $vehicle['reg'],
'last_order_id' => $olderOrder['id'],
]);
});
it('returns a null vehicle last_order_id when no order with items exists', function (): void {
api_test_covers('GET /vehicles', 'happy');
$session = api_fixtures()->createUserSession(['list_own_vehicles']);
$department = api_fixtures()->createDepartment(['name' => 'Vehicle API Department Null']);
$vehicle = api_fixtures()->createVehicle([
'customer_id' => $session['user']['customer_number'],
'type' => 53,
'reg' => 'SIDSTEV2',
'reference' => 'VEHICLE-NO-LAST-WASH',
]);
api_fixtures()->createOrder([
'customer_id' => $session['user']['customer_number'],
'cashier_id' => $session['user']['id'],
'department_id' => $department['id'],
'reference' => 'EMPTY-ORDER-1',
'reg_1' => $vehicle['reg'],
]);
api_fixtures()->createOrder([
'customer_id' => $session['user']['customer_number'],
'cashier_id' => $session['user']['id'],
'department_id' => $department['id'],
'reference' => 'EMPTY-ORDER-2',
'reg_1' => $vehicle['reg'],
]);
$response = api_client()->get('/vehicles?id=' . $vehicle['id'], $session['headers']);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
expect($response->data())->toMatchArray([
'id' => $vehicle['id'],
'reg' => $vehicle['reg'],
'last_order_id' => null,
]);
});
it('lists and summarizes vehicles through the user-scoped superuser route', function (): void {
api_test_covers('GET /superuser/users/{user_id}/vehicles', 'happy');
api_test_covers('GET /superuser/users/{user_id}/vehicles/summary', 'happy');
$targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Customer']);
$otherUser = api_fixtures()->createUser(['display_name' => 'Other Vehicle Customer']);
$vehicle = api_fixtures()->createVehicle([
'customer_id' => $targetUser['customer_number'],
'type' => 53,
'reg' => 'SCOPEDV1',
'wash_subscription' => 1,
'reference' => 'Scoped fleet',
]);
api_fixtures()->createVehicle([
'customer_id' => $otherUser['customer_number'],
'type' => 53,
'reg' => 'OTHERV1',
'wash_subscription' => 1,
]);
$session = api_fixtures()->createUserSession(['list_vehicles_other']);
$response = api_client()->get(
'/superuser/users/' . $targetUser['id'] . '/vehicles?page=1&limit=20',
$session['headers']
);
$summary = api_client()->get(
'/superuser/users/' . $targetUser['id'] . '/vehicles/summary',
$session['headers']
);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$summary
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$rows = $response->data();
expect(array_column($rows, 'reg'))->toContain('SCOPEDV1');
expect(array_column($rows, 'reg'))->not->toContain('OTHERV1');
expect($rows[0])->toMatchArray([
'id' => $vehicle['id'],
'customer_id' => $targetUser['customer_number'],
'reg' => 'SCOPEDV1',
]);
expect($response->meta()['user_context'])->toMatchArray([
'user_id' => $targetUser['id'],
'customer_number' => $targetUser['customer_number'],
]);
expect($summary->data())->toMatchArray([
'total' => 1,
'wash_subscription' => 1,
'self_service' => 0,
]);
});
it('lists and summarizes user-scoped superuser vehicles when customer vehicles has no deleted at column', function (): void {
vehicles_without_customer_vehicles_deleted_at(function (): void {
api_test_covers('GET /superuser/users/{user_id}/vehicles', 'happy');
api_test_covers('GET /superuser/users/{user_id}/vehicles/summary', 'happy');
$customerVehiclesDeletedAtColumn = api_test_runtime()->db()->query(
"SHOW COLUMNS FROM `customer_vehicles` LIKE 'deleted_at'"
);
expect($customerVehiclesDeletedAtColumn)->not->toBeFalse();
expect((int)$customerVehiclesDeletedAtColumn->num_rows)->toBe(0);
$targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Legacy Schema Customer']);
$otherUser = api_fixtures()->createUser(['display_name' => 'Other Vehicle Legacy Schema Customer']);
$vehicle = api_fixtures()->createVehicle([
'customer_id' => $targetUser['customer_number'],
'type' => 53,
'reg' => 'LEGACYV1',
'wash_subscription' => 1,
'reference' => 'Legacy schema fleet',
]);
api_fixtures()->createVehicle([
'customer_id' => $otherUser['customer_number'],
'type' => 53,
'reg' => 'LEGACYOTHER',
'wash_subscription' => 1,
]);
$session = api_fixtures()->createUserSession(['list_vehicles_other']);
$response = api_client()->get(
'/superuser/users/' . $targetUser['id'] . '/vehicles?page=1&limit=20',
$session['headers']
);
$summary = api_client()->get(
'/superuser/users/' . $targetUser['id'] . '/vehicles/summary',
$session['headers']
);
$response
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$summary
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$rows = $response->data();
expect(array_column($rows, 'reg'))->toContain('LEGACYV1');
expect(array_column($rows, 'reg'))->not->toContain('LEGACYOTHER');
expect($rows[0])->toMatchArray([
'id' => $vehicle['id'],
'customer_id' => $targetUser['customer_number'],
'reg' => 'LEGACYV1',
]);
expect($response->meta()['user_context'])->toMatchArray([
'user_id' => $targetUser['id'],
'customer_number' => $targetUser['customer_number'],
]);
expect($summary->data())->toMatchArray([
'total' => 1,
'wash_subscription' => 1,
'self_service' => 0,
]);
});
});
it('creates vehicles through the user-scoped superuser route and rejects mismatched customer ids', function (): void {
api_test_covers('POST /superuser/users/{user_id}/vehicles', 'happy');
api_test_covers('POST /superuser/users/{user_id}/vehicles', 'failure');
$targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Create Customer']);
$otherUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Mismatch Customer']);
$session = api_fixtures()->createUserSession(['add_vehicle_other']);
$created = api_client()->post('/superuser/users/' . $targetUser['id'] . '/vehicles', [
'type' => 53,
'reg' => 'SCOPEDADD',
'wash_subscription' => true,
'reference' => 'Created from user detail',
], $session['headers']);
$mismatch = api_client()->post('/superuser/users/' . $targetUser['id'] . '/vehicles', [
'customer_id' => $otherUser['customer_number'],
'type' => 53,
'reg' => 'BADSCOPED',
], $session['headers']);
$created
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$mismatch
->assertStatus(400)
->assertEnvelope()
->assertError();
$vehicleId = (int)($created->data()['id'] ?? 0);
expect($vehicleId)->toBeGreaterThan(0);
expect($created->data())->toMatchArray([
'customer_id' => $targetUser['customer_number'],
'reg' => 'SCOPEDADD',
'wash_subscription' => true,
'reference' => 'Created from user detail',
]);
api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});
it('edits and deletes only matching customer vehicles through the user-scoped superuser route', function (): void {
api_test_covers('PUT /superuser/users/{user_id}/vehicles', 'happy');
api_test_covers('PUT /superuser/users/{user_id}/vehicles', 'failure');
api_test_covers('DELETE /superuser/users/{user_id}/vehicles', 'happy');
api_test_covers('DELETE /superuser/users/{user_id}/vehicles', 'failure');
$targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Edit Customer']);
$otherUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Guard Customer']);
$vehicle = api_fixtures()->createVehicle([
'customer_id' => $targetUser['customer_number'],
'type' => 53,
'reg' => 'SCOPEDIT',
'wash_subscription' => 0,
]);
$otherVehicle = api_fixtures()->createVehicle([
'customer_id' => $otherUser['customer_number'],
'type' => 53,
'reg' => 'SCOPEBAD',
'wash_subscription' => 0,
]);
$deletableVehicle = api_fixtures()->createVehicle([
'customer_id' => $targetUser['customer_number'],
'type' => 53,
'reg' => 'SCOPEDEL',
'wash_subscription' => 0,
]);
$session = api_fixtures()->createUserSession(['edit_vehicle_other', 'delete_vehicle_other']);
$edited = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
'id' => $vehicle['id'],
'reg' => 'SCOPEDOK',
'reference' => 'Updated reference',
], $session['headers']);
$moved = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
'id' => $vehicle['id'],
'customer_id' => $otherUser['customer_number'],
], $session['headers']);
$foreignEdit = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
'id' => $otherVehicle['id'],
'reg' => 'SHOULDFAIL',
], $session['headers']);
$deleted = api_client()->delete(
'/superuser/users/' . $targetUser['id'] . '/vehicles?id=' . $deletableVehicle['id'],
null,
$session['headers']
);
$foreignDelete = api_client()->delete(
'/superuser/users/' . $targetUser['id'] . '/vehicles?id=' . $otherVehicle['id'],
null,
$session['headers']
);
$edited
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$moved
->assertStatus(400)
->assertEnvelope()
->assertError();
$foreignEdit
->assertStatus(404)
->assertEnvelope()
->assertError();
$deleted
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$foreignDelete
->assertStatus(404)
->assertEnvelope()
->assertError();
expect($edited->data())->toMatchArray([
'id' => $vehicle['id'],
'customer_id' => $targetUser['customer_number'],
'reg' => 'SCOPEDOK',
'reference' => 'Updated reference',
]);
});