465 lines
17 KiB
PHP
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',
|
|
]);
|
|
});
|