lan_kiosk/tests/Feature/SwishCallbackTest.php
Anna-Sara Sélea df9f1cf17e Swish feature
2026-08-22 16:13:42 +02:00

185 lines
7.3 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Deposit;
use App\Models\Transaction;
/**
* The callback is where money is created out of an HTTP request, so this is the
* file to read first if something about the payment flow ever feels uncertain.
*/
class SwishCallbackTest extends SwishTestCase
{
public function test_a_paid_callback_credits_the_customer(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload())->assertNoContent();
$customer->refresh();
$this->assertSame(800, $customer->deposit);
$this->assertSame(800, $customer->amount_left);
$this->assertSame('PAID', Transaction::first()->status);
$this->assertSame(1, Deposit::where('customer_id', $customer->id)->count());
}
public function test_it_rejects_a_callback_without_the_identifier(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id]);
$this->postCallback($this->paidPayload(), null)->assertStatus(403);
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame('pending', Transaction::first()->status);
}
public function test_it_rejects_a_callback_with_the_wrong_identifier(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id]);
$this->postCallback($this->paidPayload(), 'ffffffff-ffff-ffff-ffff-ffffffffffff')
->assertStatus(403);
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame('pending', Transaction::first()->status);
}
public function test_it_rejects_a_callback_for_a_transaction_that_was_never_registered(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'callback_identifier' => null]);
$this->postCallback($this->paidPayload())->assertStatus(403);
$this->assertSame(700, $customer->refresh()->deposit);
}
public function test_a_repeated_callback_only_credits_once(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload())->assertNoContent();
$this->postCallback($this->paidPayload())->assertNoContent();
$this->postCallback($this->paidPayload())->assertNoContent();
$this->assertSame(800, $customer->refresh()->deposit);
$this->assertSame(1, Deposit::count());
}
public function test_it_refuses_an_amount_that_differs_from_the_payment_request(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload(['amount' => 5000]))->assertNoContent();
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame('amount_mismatch', Transaction::first()->status);
$this->assertSame(0, Deposit::count());
}
public function test_it_does_not_round_an_amount_with_ore(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload(['amount' => 99.50]))->assertNoContent();
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame('amount_mismatch', Transaction::first()->status);
}
public function test_a_declined_payment_is_recorded_but_not_credited(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id]);
$this->postCallback($this->paidPayload([
'status' => 'DECLINED',
'errorCode' => 'BANKIDCL',
]))->assertNoContent();
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame('DECLINED', Transaction::first()->status);
}
public function test_an_unknown_reference_changes_nothing(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->postCallback($this->paidPayload(['payeePaymentReference' => 'LAN-NOSUCHREF']))
->assertNoContent();
$this->assertSame(700, $customer->refresh()->deposit);
$this->assertSame(0, Deposit::count());
}
public function test_a_group_member_payment_lands_on_the_group_account(): void
{
$group = $this->customer([
'lan_id' => 10, 'name' => 'Klanen', 'deposit' => 500, 'amount_left' => 500,
'is_in_group' => 0, 'customer_group_id' => 7,
]);
$member = $this->customer([
'lan_id' => 11, 'name' => 'Anna', 'deposit' => 0, 'amount_left' => 0,
'is_in_group' => 1, 'customer_group_id' => 7,
]);
$this->transaction(['customer_id' => $member->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload())->assertNoContent();
$this->assertSame(600, $group->refresh()->deposit);
$this->assertSame(600, $group->amount_left);
$this->assertSame(0, $member->refresh()->deposit);
}
public function test_a_payment_to_a_customer_of_their_own_lands_on_themselves(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700, 'is_in_group' => 0]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$this->postCallback($this->paidPayload())->assertNoContent();
$this->assertSame(800, $customer->refresh()->deposit);
}
public function test_a_late_callback_on_an_expired_transaction_is_still_booked(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100, 'status' => 'expired']);
$this->postCallback($this->paidPayload())->assertNoContent();
$this->assertSame(800, $customer->refresh()->deposit);
$this->assertSame('PAID', Transaction::first()->status);
}
public function test_the_leftover_choice_from_the_payment_follows_along(): void
{
$customer = $this->customer(['deposit' => 0, 'amount_left' => 0, 'give_leftover' => 0]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100, 'give_leftover' => 1]);
$this->postCallback($this->paidPayload())->assertNoContent();
$this->assertSame(1, (int) $customer->refresh()->give_leftover);
}
public function test_it_still_understands_the_old_reference_in_the_message_field(): void
{
$customer = $this->customer(['deposit' => 700, 'amount_left' => 700]);
$this->transaction(['customer_id' => $customer->id, 'expected_amount' => 100]);
$payload = $this->paidPayload(['message' => 'kiosk|LAN-TEST0001']);
unset($payload['payeePaymentReference']);
$this->postCallback($payload)->assertNoContent();
$this->assertSame(800, $customer->refresh()->deposit);
}
}