Add Payment module: contracts, payments/refunds tables, KBZ gateway, factory, orchestrator (T5.1-T5.7)
- T5.1 PaymentGatewayInterface, DTOs, PaymentMethod/PaymentStatus/RefundStatus enums - T5.2 payments/refunds tables, models, factories - T5.3-T5.5 KbzMiniAppGateway: initiate()/verify()/refund(), ported KBZ signing scheme, wired refund_amount through for partial refunds, mTLS options for refund - T5.6 PaymentGatewayFactory resolving gateways by PaymentMethod - T5.7 PaymentService orchestrator delegating to the resolved gateway
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Modules\Payment\Data\PaymentRequestData;
|
||||
use Modules\Payment\Enums\PaymentMethod;
|
||||
use Modules\Payment\Enums\PaymentStatus;
|
||||
use Modules\Payment\Gateways\KbzMiniAppGateway;
|
||||
use Modules\Payment\Support\KbzSignature;
|
||||
|
||||
$config = [
|
||||
'app_id' => 'APPID123',
|
||||
'merchant_code' => 'MERCH001',
|
||||
'merchant_key' => 'test-merchant-key',
|
||||
'base_url' => 'https://kbz.test/gateway',
|
||||
'notify_url' => 'https://app.test/api/v1/webhooks/kbz',
|
||||
];
|
||||
|
||||
$paymentRequest = new PaymentRequestData(
|
||||
bookingId: 1,
|
||||
merchantOrderId: 'EVB-FIXTURE-001',
|
||||
amount: '15000',
|
||||
currency: 'MMK',
|
||||
method: PaymentMethod::KbzMiniApp,
|
||||
);
|
||||
|
||||
test('initiate posts a correctly signed precreate request to the configured base_url', function () use ($config, $paymentRequest) {
|
||||
Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'SUCCESS', 'prepay_id' => 'PREPAY123']])]);
|
||||
|
||||
(new KbzMiniAppGateway($config))->initiate($paymentRequest);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data()['Request'];
|
||||
|
||||
return $request->url() === 'https://kbz.test/gateway'
|
||||
&& $body['method'] === 'kbz.payment.precreate'
|
||||
&& $body['sign_type'] === 'SHA256'
|
||||
&& $body['biz_content']['appid'] === 'APPID123'
|
||||
&& $body['biz_content']['merch_code'] === 'MERCH001'
|
||||
&& $body['biz_content']['merch_order_id'] === 'EVB-FIXTURE-001'
|
||||
&& $body['biz_content']['trade_type'] === 'MINIAPP'
|
||||
&& $body['biz_content']['total_amount'] === '15000'
|
||||
&& $body['biz_content']['trans_currency'] === 'MMK'
|
||||
&& $body['sign'] === KbzSignature::sign($body, 'test-merchant-key');
|
||||
});
|
||||
});
|
||||
|
||||
test('initiate returns a pending PaymentResultData on a successful precreate', function () use ($config, $paymentRequest) {
|
||||
Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'SUCCESS', 'prepay_id' => 'PREPAY123']])]);
|
||||
|
||||
$result = (new KbzMiniAppGateway($config))->initiate($paymentRequest);
|
||||
|
||||
expect($result->status)->toBe(PaymentStatus::Pending)
|
||||
->and($result->gatewayTransactionId)->toBe('EVB-FIXTURE-001')
|
||||
->and($result->gatewayPayload)->toBe(['result' => 'SUCCESS', 'prepay_id' => 'PREPAY123']);
|
||||
});
|
||||
|
||||
test('initiate returns a failed PaymentResultData when KBZ rejects the request', function () use ($config, $paymentRequest) {
|
||||
Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'FAIL', 'msg' => 'Invalid merchant']])]);
|
||||
|
||||
$result = (new KbzMiniAppGateway($config))->initiate($paymentRequest);
|
||||
|
||||
expect($result->status)->toBe(PaymentStatus::Failed)
|
||||
->and($result->gatewayTransactionId)->toBeNull()
|
||||
->and($result->message)->toBe('Invalid merchant');
|
||||
});
|
||||
|
||||
test('initiate returns a failed PaymentResultData when the connection fails', function () use ($config, $paymentRequest) {
|
||||
Http::fake(['kbz.test/*' => fn () => throw new ConnectionException('Connection refused')]);
|
||||
|
||||
$result = (new KbzMiniAppGateway($config))->initiate($paymentRequest);
|
||||
|
||||
expect($result->status)->toBe(PaymentStatus::Failed)
|
||||
->and($result->gatewayTransactionId)->toBeNull()
|
||||
->and($result->gatewayPayload)->toBe([])
|
||||
->and($result->message)->toBe('Connection refused');
|
||||
});
|
||||
Reference in New Issue
Block a user