@@ -0,0 +1,179 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user