Files
alrahma_sunday_school/tests/app/Controllers/View/RefundControllerRegressionTest.php
T
root a30c1398a1
Tests / PHPUnit (push) Failing after 1m21s
fix financials
2026-07-18 22:57:40 -04:00

180 lines
5.3 KiB
PHP

<?php
namespace Tests\App\Controllers\View;
use App\Controllers\View\RefundController;
use App\Libraries\RefundEligibilityService;
use CodeIgniter\Test\CIUnitTestCase;
class RefundRequestStub
{
public function __construct(private array $post = [])
{
}
public function getPost(?string $key = null)
{
if ($key === null) {
return $this->post;
}
return $this->post[$key] ?? null;
}
public function getFile(string $name)
{
return null;
}
}
class TestableRefundController extends RefundController
{
public function __construct()
{
}
public function setRequestObject($request): self
{
$this->request = $request;
return $this;
}
public function setResponseObject($response): self
{
$this->response = $response;
return $this;
}
}
class RefundEligibilityForControllerHarness extends RefundEligibilityService
{
public function __construct(private int $completedPayoutCents)
{
}
public function getCompletedPayoutTotalCentsForRefund(int $refundId): int
{
return $this->completedPayoutCents;
}
}
class RefundControllerRegressionTest extends CIUnitTestCase
{
public function testRequestRefundReadsRequestTypeFromPostBody(): void
{
$controller = $this->controllerWithPost([
'parent_id' => '123',
'amount' => '25.00',
'request_type' => 'unsupported',
]);
$response = $controller->requestRefund();
$this->assertSame(['error' => 'Invalid refund request type.'], $this->jsonResponse($response));
}
public function testPayRefundRouteArgumentIsAcceptedBeforePostRefundId(): void
{
$controller = $this->controllerWithPost([
'paid_amount' => '10.00',
'payment_method' => 'Wire',
]);
$response = $controller->payRefund(77);
$this->assertSame(['error' => 'Invalid refund payment method.'], $this->jsonResponse($response));
}
public function testCheckRefundRequiresCheckNumberBeforeDatabaseWrite(): void
{
$controller = $this->controllerWithPost([
'refund_id' => '77',
'paid_amount' => '10.00',
'payment_method' => 'Check',
]);
$response = $controller->updatePayment();
$this->assertSame(['error' => 'Check number is required for check refunds.'], $this->jsonResponse($response));
}
public function testUpdateStatusAcceptsRouteRefundId(): void
{
$controller = $this->controllerWithPost([
'status' => 'Voided',
'reason' => 'duplicate request',
]);
$response = $controller->updateStatus(77);
$this->assertSame(['error' => 'Invalid status update request.'], $this->jsonResponse($response));
}
public function testReversePayoutRequiresReasonBeforeDatabaseWrite(): void
{
$controller = $this->controllerWithPost([
'idempotency_key' => 'reverse-77',
]);
$response = $controller->reversePayout(77);
$this->assertSame(['error' => 'Reversal reason is required.'], $this->jsonResponse($response));
}
public function testReversePayoutRequiresIdempotencyKeyBeforeDatabaseWrite(): void
{
$controller = $this->controllerWithPost([
'reason' => 'wrong payout amount',
]);
$response = $controller->reversePayout(77);
$this->assertSame(['error' => 'Missing reversal idempotency key.'], $this->jsonResponse($response));
}
public function testReversePayoutRejectsNonPositiveAmountBeforeDatabaseWrite(): void
{
$controller = $this->controllerWithPost([
'reason' => 'wrong payout amount',
'idempotency_key' => 'reverse-77',
'amount' => '0.00',
]);
$response = $controller->reversePayout(77);
$this->assertSame(['error' => 'Reversal amount must be greater than zero.'], $this->jsonResponse($response));
}
public function testApprovedRefundRecalculationCannotDropBelowCompletedPayouts(): void
{
$controller = $this->controllerWithPost([]);
$property = (new \ReflectionClass(RefundController::class))->getProperty('refundEligibilityService');
$property->setAccessible(true);
$property->setValue($controller, new RefundEligibilityForControllerHarness(2500));
$method = (new \ReflectionClass(RefundController::class))->getMethod('buildRefundRecalculationUpdate');
$method->setAccessible(true);
$update = $method->invoke($controller, [
'id' => 55,
'status' => 'Approved',
], 10.00);
$this->assertEqualsWithDelta(25.0, (float)$update['refund_amount'], 0.0001);
$this->assertSame(2500, $update['approved_amount_cents']);
$this->assertSame('requires_review', $update['reconciliation_status']);
$this->assertStringContainsString('Completed payouts', $update['reconciliation_reason']);
}
private function controllerWithPost(array $post): TestableRefundController
{
return (new TestableRefundController())
->setRequestObject(new RefundRequestStub($post))
->setResponseObject(service('response'));
}
private function jsonResponse($response): array
{
return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
}
}