Transitioned from obsolete gateway object classes (`edge_gateway_shell_action_jobs_o`, `edge_gateway_shell_events_o`, `edge_gateway_shell_sessions_o`, `edge_gateway_update_jobs_o`) to the new agent implementation (`edge-gateway-agent/agent.php`).
325 lines
11 KiB
PHP
325 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use classes\email;
|
|
use classes\stripe;
|
|
use classes\stripe_fake_http_client;
|
|
|
|
putenv('STRIPE_FAKE_MODE=1');
|
|
putenv('STRIPE_FAKE_STORE_PATH=' . sys_get_temp_dir() . '/truckwash-stripe-api-tests.json');
|
|
putenv('EMAIL_FAKE_MODE=1');
|
|
|
|
usesApiSuite();
|
|
|
|
beforeEach(function (): void {
|
|
stripe_fake_http_client::resetStore();
|
|
email::resetFakeDeliveries();
|
|
|
|
if (api_tests_enabled()) {
|
|
api_test_runtime()->db()->query("DELETE FROM stripe_module_orders WHERE invoice_id LIKE 'in_fake_%'");
|
|
api_test_runtime()->db()->query("DELETE FROM stripe_module_customers WHERE customer_id LIKE 'cus_fake_%' OR email LIKE 'stripe-%@example.com'");
|
|
}
|
|
});
|
|
|
|
it('returns a setup required error when department terminal readers are requested without terminal setup', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Setup Pending Department',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_department_terminal_readers_list',
|
|
'department_access_' . $department['id'],
|
|
]);
|
|
|
|
$response = api_client()->get(
|
|
'/modules/stripe/department/terminal/readers?id=' . $department['id'],
|
|
$session['headers']
|
|
);
|
|
|
|
$response
|
|
->assertStatus(409)
|
|
->assertEnvelope()
|
|
->assertSuccess(false)
|
|
->assertMessage('Card payments are not ready for this department. Open Stripe setup and choose a terminal location.');
|
|
|
|
expect($response->data())
|
|
->toBeArray()
|
|
->toHaveKey('code', 'stripe_terminal_setup_required');
|
|
});
|
|
|
|
it('sends a Stripe invoice by email and persists the hosted invoice association', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Email Payments Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Hosted Invoice Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-EMAIL-SEND',
|
|
'reg_1' => 'EMAIL01',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_invoice_send',
|
|
]);
|
|
$emailAddress = sprintf('stripe-email-%d@example.com', (int)$order['id']);
|
|
|
|
$response = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$response
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess(true);
|
|
|
|
expect($response->data())
|
|
->toBeArray()
|
|
->toHaveKey('id')
|
|
->toHaveKey('hosted_invoice_url')
|
|
->toHaveKey('metadata');
|
|
|
|
expect($response->data()['metadata'] ?? [])
|
|
->toMatchArray([
|
|
'order_id' => (string)$order['id'],
|
|
'customer_id' => (string)$customer['customer_number'],
|
|
'department_id' => (string)$department['id'],
|
|
'reference' => 'STRIPE-EMAIL-SEND',
|
|
'reg_1' => 'EMAIL01',
|
|
])
|
|
->and(($response->data()['metadata']['stripe_customer_id'] ?? null))
|
|
->toBe((string)($response->data()['customer'] ?? ''));
|
|
|
|
$retrievedInvoice = (new stripe())->invoice->retrieve((string)$response->data()['id']);
|
|
$retrievedMetadata = json_decode(json_encode($retrievedInvoice->metadata), true);
|
|
if (!is_array($retrievedMetadata)) {
|
|
$retrievedMetadata = [];
|
|
}
|
|
|
|
expect($retrievedMetadata)
|
|
->toMatchArray([
|
|
'order_id' => (string)$order['id'],
|
|
'customer_id' => (string)$customer['customer_number'],
|
|
'department_id' => (string)$department['id'],
|
|
'reference' => 'STRIPE-EMAIL-SEND',
|
|
'reg_1' => 'EMAIL01',
|
|
])
|
|
->and(($retrievedMetadata['stripe_customer_id'] ?? null))
|
|
->toBe((string)($response->data()['customer'] ?? ''));
|
|
|
|
$stored = api_test_runtime()->queryOne(
|
|
'SELECT invoice_id, customer_id, url FROM stripe_module_orders WHERE id = ' . (int)$order['id']
|
|
);
|
|
|
|
expect($stored)
|
|
->not->toBeNull()
|
|
->and($stored['invoice_id'] ?? null)->toBe((string)$response->data()['id'])
|
|
->and($stored['customer_id'] ?? null)->not->toBe('')
|
|
->and($stored['url'] ?? null)->toBe((string)$response->data()['hosted_invoice_url']);
|
|
});
|
|
|
|
it('returns a conflict when a Stripe hosted invoice is already active for the order', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Email Guard Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Duplicate Guard Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-EMAIL-GUARD',
|
|
'reg_1' => 'EMAIL02',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_invoice_send',
|
|
]);
|
|
$emailAddress = sprintf('stripe-duplicate-%d@example.com', (int)$order['id']);
|
|
|
|
api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers'])->assertStatus(200);
|
|
|
|
$response = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$response
|
|
->assertStatus(409)
|
|
->assertEnvelope()
|
|
->assertSuccess(false)
|
|
->assertMessage('A Stripe payment link is already active for this order.');
|
|
|
|
expect($response->data())
|
|
->toBeArray()
|
|
->toHaveKey('code', 'stripe_invoice_exists');
|
|
});
|
|
|
|
it('allows sending a new Stripe hosted invoice when the existing association is already terminal', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Email Terminal Guard Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Terminal Guard Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-EMAIL-TERMINAL',
|
|
'reg_1' => 'EMAIL05',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_invoice_send',
|
|
]);
|
|
$emailAddress = sprintf('stripe-terminal-%d@example.com', (int)$order['id']);
|
|
|
|
$firstResponse = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$firstInvoiceId = (string)($firstResponse->data()['id'] ?? '');
|
|
stripe_fake_http_client::setInvoiceState($firstInvoiceId, [
|
|
'status' => 'void',
|
|
'paid' => false,
|
|
]);
|
|
|
|
$secondResponse = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$secondResponse
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess(true);
|
|
|
|
expect((string)($secondResponse->data()['id'] ?? ''))
|
|
->not->toBe('')
|
|
->not->toBe($firstInvoiceId);
|
|
});
|
|
|
|
it('voids an unpaid Stripe hosted invoice and clears the local order association', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Email Cancel Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Cancel Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-EMAIL-CANCEL',
|
|
'reg_1' => 'EMAIL03',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_invoice_send',
|
|
]);
|
|
$emailAddress = sprintf('stripe-cancel-%d@example.com', (int)$order['id']);
|
|
|
|
$sendResponse = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
$invoiceId = (string)($sendResponse->data()['id'] ?? '');
|
|
|
|
$response = api_client()->delete('/modules/stripe/invoice', [
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$response
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess(true);
|
|
|
|
expect(api_test_runtime()->queryOne(
|
|
'SELECT invoice_id FROM stripe_module_orders WHERE id = ' . (int)$order['id']
|
|
))->toBeNull();
|
|
|
|
expect((new stripe())->invoice->retrieve($invoiceId)->status)->toBe('void');
|
|
});
|
|
|
|
it('refuses to cancel a paid Stripe hosted invoice', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Email Paid Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Paid Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-EMAIL-PAID',
|
|
'reg_1' => 'EMAIL04',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'modules_stripe_invoice_send',
|
|
]);
|
|
$emailAddress = sprintf('stripe-paid-%d@example.com', (int)$order['id']);
|
|
|
|
$sendResponse = api_client()->post('/modules/stripe/invoice', [
|
|
'email' => $emailAddress,
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
$invoiceId = (string)($sendResponse->data()['id'] ?? '');
|
|
|
|
stripe_fake_http_client::setInvoiceState($invoiceId, [
|
|
'status' => 'paid',
|
|
'paid' => true,
|
|
'amount_due' => 0,
|
|
'amount_paid' => 1000,
|
|
]);
|
|
|
|
$response = api_client()->delete('/modules/stripe/invoice', [
|
|
'order_id' => $order['id'],
|
|
], $session['headers']);
|
|
|
|
$response
|
|
->assertStatus(409)
|
|
->assertEnvelope()
|
|
->assertSuccess(false)
|
|
->assertMessage('A paid Stripe payment link cannot be cancelled.');
|
|
|
|
expect(api_test_runtime()->queryOne(
|
|
'SELECT invoice_id FROM stripe_module_orders WHERE id = ' . (int)$order['id']
|
|
))->not->toBeNull();
|
|
});
|
|
|
|
it('returns a setup required error when creating a payment intent for a department without terminal setup', function (): void {
|
|
$department = api_fixtures()->createDepartment([
|
|
'name' => 'Stripe Payment Intent Pending Department',
|
|
]);
|
|
$customer = api_fixtures()->createUser([
|
|
'display_name' => 'Stripe Payment Intent Customer',
|
|
]);
|
|
$order = api_fixtures()->createOrder([
|
|
'customer_id' => $customer['customer_number'],
|
|
'department_id' => $department['id'],
|
|
'reference' => 'STRIPE-SETUP-REQUIRED',
|
|
'reg_1' => 'STRIPE01',
|
|
]);
|
|
$session = api_fixtures()->createUserSession([
|
|
'charge_order',
|
|
]);
|
|
|
|
$response = api_client()->post('/orders/module/stripe/payment_intent', [
|
|
'id' => $order['id'],
|
|
'reader' => 'reader_pending_setup',
|
|
'tax_percentage' => 25,
|
|
], $session['headers']);
|
|
|
|
$response
|
|
->assertStatus(409)
|
|
->assertEnvelope()
|
|
->assertSuccess(false)
|
|
->assertMessage('Card payments are not ready for this department. Open Stripe setup and choose a terminal location.');
|
|
|
|
expect($response->data())
|
|
->toBeArray()
|
|
->toHaveKey('code', 'stripe_terminal_setup_required');
|
|
});
|