Resolve merge conflict with master in SelfserveLaneCommandApiTest.php
This commit is contained in:
@@ -5874,6 +5874,32 @@ paths:
|
|||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
|
||||||
|
/order-bookings/booking-confirmation/resend:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Bookings
|
||||||
|
summary: Resend order booking confirmation
|
||||||
|
description: Resends the customer booking confirmation email for an order booking. Requires `resend_booking_confirmations` and access to the booking's department.
|
||||||
|
operationId: resendOrderBookingConfirmation
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id: {type: integer}
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Booking confirmation resent successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
'400': { $ref: '#/components/responses/BadRequest' }
|
||||||
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||||
|
'403': { $ref: '#/components/responses/Forbidden' }
|
||||||
|
|
||||||
/order-bookings/complete:
|
/order-bookings/complete:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
+18
-1
@@ -51,6 +51,23 @@ collect_logs() {
|
|||||||
docker compose $compose_files cp php1:/var/log/php "$log_dir/php-logs" >/dev/null 2>&1 || true
|
docker compose $compose_files cp php1:/var/log/php "$log_dir/php-logs" >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry_command() {
|
||||||
|
max_attempts="$1"
|
||||||
|
shift
|
||||||
|
attempt=1
|
||||||
|
while :; do
|
||||||
|
"$@" && return 0
|
||||||
|
status="$?"
|
||||||
|
if [ "$attempt" -ge "$max_attempts" ]; then
|
||||||
|
return "$status"
|
||||||
|
fi
|
||||||
|
sleep_seconds=$((attempt * 5))
|
||||||
|
echo "Command failed with status $status; retrying in ${sleep_seconds}s (attempt $((attempt + 1))/$max_attempts): $*" >&2
|
||||||
|
sleep "$sleep_seconds"
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
status="$?"
|
status="$?"
|
||||||
collect_logs "$status"
|
collect_logs "$status"
|
||||||
@@ -70,7 +87,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
docker compose $compose_files up -d redis mysql-debug php1
|
retry_command "${PHP_CI_DOCKER_RETRIES:-3}" docker compose $compose_files up -d redis mysql-debug php1
|
||||||
|
|
||||||
docker compose $compose_files exec -T php1 sh -lc '
|
docker compose $compose_files exec -T php1 sh -lc '
|
||||||
set -eu
|
set -eu
|
||||||
|
|||||||
@@ -6239,6 +6239,32 @@ paths:
|
|||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
|
||||||
|
/order-bookings/booking-confirmation/resend:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Bookings
|
||||||
|
summary: Resend order booking confirmation
|
||||||
|
description: Resends the customer booking confirmation email for an order booking. Requires `resend_booking_confirmations` and access to the booking's department.
|
||||||
|
operationId: resendOrderBookingConfirmation
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id: {type: integer}
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Booking confirmation resent successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
'400': { $ref: '#/components/responses/BadRequest' }
|
||||||
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||||
|
'403': { $ref: '#/components/responses/Forbidden' }
|
||||||
|
|
||||||
/order-bookings/complete:
|
/order-bookings/complete:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace routes;
|
namespace routes;
|
||||||
|
|
||||||
use classes\authentication;
|
use classes\authentication;
|
||||||
|
use classes\email;
|
||||||
use classes\order_bookings_counts_cache;
|
use classes\order_bookings_counts_cache;
|
||||||
use classes\order_bookings_list_cache;
|
use classes\order_bookings_list_cache;
|
||||||
use classes\redis;
|
use classes\redis;
|
||||||
@@ -368,6 +369,29 @@ class orderBookingRoute
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->post('/order-bookings/booking-confirmation/resend', function () {
|
||||||
|
global $response;
|
||||||
|
|
||||||
|
$object = self::getTargetObject();
|
||||||
|
if (!$object || !$object->exists()) {
|
||||||
|
$response->error('Order booking does not exist.', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::requirePermission('resend_booking_confirmations');
|
||||||
|
self::requireDepartmentAccess((int)$object->department->value());
|
||||||
|
|
||||||
|
(new email())->sendOrderBookingConfirmationEmail($object);
|
||||||
|
|
||||||
|
$response->success([
|
||||||
|
'message' => 'Booking confirmation resent successfully.',
|
||||||
|
'booking' => $object->asArray(),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
[
|
||||||
|
'resend_booking_confirmations' => 'Permission for department admins to resend order booking confirmation emails.'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
$this->post('/order-bookings/complete', function () {
|
$this->post('/order-bookings/complete', function () {
|
||||||
// Require the user to be logged in
|
// Require the user to be logged in
|
||||||
global $response;
|
global $response;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
putenv('EMAIL_FAKE_MODE=1');
|
||||||
|
|
||||||
|
usesApiSuite();
|
||||||
|
|
||||||
|
it('allows department admins to resend order booking confirmations', function (): void {
|
||||||
|
$customer = api_fixtures()->createUser([
|
||||||
|
'display_name' => 'Resend Booking Confirmation Customer',
|
||||||
|
'email' => 'resend-booking-confirmation@example.test',
|
||||||
|
]);
|
||||||
|
$branding = api_fixtures()->createBranding([
|
||||||
|
'name' => 'Resend Booking Confirmation Brand',
|
||||||
|
'address' => 'Resend Booking Confirmation Address 1',
|
||||||
|
]);
|
||||||
|
$department = api_fixtures()->createDepartment([
|
||||||
|
'name' => 'Resend Booking Confirmation Department',
|
||||||
|
'branding' => $branding['id'],
|
||||||
|
]);
|
||||||
|
$booking = api_fixtures()->createOrderBooking([
|
||||||
|
'customer_number' => $customer['customer_number'],
|
||||||
|
'department' => $department['id'],
|
||||||
|
'reference' => 'RESEND-CONFIRMATION',
|
||||||
|
'reg_1' => 'RESEND1',
|
||||||
|
]);
|
||||||
|
$session = api_fixtures()->createUserSession([
|
||||||
|
'resend_booking_confirmations',
|
||||||
|
'department_access_' . $department['id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = api_client()->post('/order-bookings/booking-confirmation/resend', [
|
||||||
|
'id' => $booking['id'],
|
||||||
|
], $session['headers']);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertStatus(200)
|
||||||
|
->assertEnvelope()
|
||||||
|
->assertSuccess();
|
||||||
|
|
||||||
|
expect($response->data())
|
||||||
|
->toBeArray()
|
||||||
|
->toHaveKey('message', 'Booking confirmation resent successfully.')
|
||||||
|
->toHaveKey('booking')
|
||||||
|
->and($response->data()['booking'])
|
||||||
|
->toBeArray()
|
||||||
|
->and($response->data()['booking']['id'] ?? null)
|
||||||
|
->toBe($booking['id'])
|
||||||
|
->and($response->data()['booking']['reference'] ?? null)
|
||||||
|
->toBe('RESEND-CONFIRMATION');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requires department access when resending order booking confirmations', function (): void {
|
||||||
|
$customer = api_fixtures()->createUser([
|
||||||
|
'display_name' => 'Resend Booking Confirmation Foreign Customer',
|
||||||
|
]);
|
||||||
|
$department = api_fixtures()->createDepartment([
|
||||||
|
'name' => 'Resend Booking Confirmation Foreign Department',
|
||||||
|
]);
|
||||||
|
$booking = api_fixtures()->createOrderBooking([
|
||||||
|
'customer_number' => $customer['customer_number'],
|
||||||
|
'department' => $department['id'],
|
||||||
|
]);
|
||||||
|
$session = api_fixtures()->createUserSession([
|
||||||
|
'resend_booking_confirmations',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = api_client()->post('/order-bookings/booking-confirmation/resend', [
|
||||||
|
'id' => $booking['id'],
|
||||||
|
], $session['headers']);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertStatus(403)
|
||||||
|
->assertEnvelope()
|
||||||
|
->assertSuccess(false)
|
||||||
|
->assertMissingPermissions(['department_access_' . $department['id']]);
|
||||||
|
});
|
||||||
@@ -64,6 +64,7 @@ it('allows customer self-serve permission to execute START without department ac
|
|||||||
'lane_id' => (int)$scenario['lane']['id'],
|
'lane_id' => (int)$scenario['lane']['id'],
|
||||||
'command' => 'START',
|
'command' => 'START',
|
||||||
'license_plate' => (string)$scenario['vehicle']['reg'],
|
'license_plate' => (string)$scenario['vehicle']['reg'],
|
||||||
|
'defer_relay_side_effects' => true,
|
||||||
], api_fixtures()->bearerHeaders($token));
|
], api_fixtures()->bearerHeaders($token));
|
||||||
|
|
||||||
$response
|
$response
|
||||||
@@ -169,6 +170,7 @@ it('still allows elevated operators with department access to execute lane comma
|
|||||||
'lane_id' => (int)$scenario['lane']['id'],
|
'lane_id' => (int)$scenario['lane']['id'],
|
||||||
'command' => 'START',
|
'command' => 'START',
|
||||||
'license_plate' => 'OP' . (int)$scenario['lane']['id'],
|
'license_plate' => 'OP' . (int)$scenario['lane']['id'],
|
||||||
|
'defer_relay_side_effects' => true,
|
||||||
], $session['headers']);
|
], $session['headers']);
|
||||||
|
|
||||||
$response
|
$response
|
||||||
|
|||||||
Reference in New Issue
Block a user