PayPlusCashierLogicTest.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. namespace Tests\Unit;
  3. use App\Http\logic\api\PayPlusCashierLogic;
  4. use App\Services\PayPlus;
  5. use Tests\TestCase;
  6. class PayPlusCashierLogicTest extends TestCase
  7. {
  8. /** @test */
  9. public function it_queries_existing_beneficiary_when_create_reports_duplicate()
  10. {
  11. $service = new FakePayPlusForCashier([
  12. ['code' => 4002001, 'message' => 'beneficiary exists'],
  13. ['code' => 200, 'data' => ['beneficiary_id' => 5006]],
  14. [
  15. 'code' => 200,
  16. 'data' => [
  17. 'transaction_status' => 'PROCESSING',
  18. 'transaction_id' => 'T100',
  19. ],
  20. ],
  21. ]);
  22. $logic = new PayPlusCashierLogic($service);
  23. $result = $logic->createBeneficiaryAndPayout([
  24. 'user_id' => 10001,
  25. 'amount' => 10,
  26. 'currency' => 'USD',
  27. 'order_id' => 'TX100',
  28. 'pix_type' => 1,
  29. 'cashapp_account' => 'cashuser',
  30. 'email' => 'user@example.com',
  31. ]);
  32. $this->assertSame('PROCESSING', $result['data']['transaction_status']);
  33. $this->assertSame('/rest/v2/beneficiaries/create', $service->calls[0]['path']);
  34. $this->assertSame('/rest/v2/beneficiaries/query', $service->calls[1]['path']);
  35. $this->assertSame('/rest/v2/payouts/cashApp', $service->calls[2]['path']);
  36. $this->assertSame('$cashuser', $service->calls[2]['payload']['cashapp_account']);
  37. }
  38. /** @test */
  39. public function it_does_not_payout_when_beneficiary_id_cannot_be_resolved()
  40. {
  41. $service = new FakePayPlusForCashier([
  42. ['code' => 4002001, 'message' => 'beneficiary exists'],
  43. ['code' => 200],
  44. ]);
  45. $logic = new PayPlusCashierLogic($service);
  46. $result = $logic->createBeneficiaryAndPayout([
  47. 'user_id' => 10001,
  48. 'amount' => 10,
  49. 'currency' => 'USD',
  50. 'order_id' => 'TX100',
  51. 'pix_type' => 2,
  52. 'email' => 'user@example.com',
  53. ]);
  54. $this->assertFalse($result);
  55. $this->assertCount(2, $service->calls);
  56. }
  57. /** @test */
  58. public function it_maps_payplus_payout_statuses()
  59. {
  60. $logic = new PayPlusCashierLogic(new PayPlus([]));
  61. $this->assertSame(1, $logic->resolvePayoutStatus('PAID'));
  62. $this->assertSame(2, $logic->resolvePayoutStatus('REJECTED'));
  63. $this->assertSame(2, $logic->resolvePayoutStatus('REFUNDED'));
  64. $this->assertSame(0, $logic->resolvePayoutStatus('PROCESSING'));
  65. }
  66. /** @test */
  67. public function it_queries_payout_detail_for_notify_and_uses_query_status()
  68. {
  69. $service = new FakePayPlusForCashier([
  70. [
  71. 'code' => 200,
  72. 'data' => [
  73. 'reference_id' => 'TX100',
  74. 'transaction_id' => 'T100',
  75. 'transaction_status' => 'PAID',
  76. 'description' => 'paid',
  77. ],
  78. ],
  79. ]);
  80. $logic = new PayPlusCashierLogic($service);
  81. $detail = $logic->queryPayoutDetailForNotify([
  82. 'reference_id' => 'TX100',
  83. 'transaction_id' => 'T100',
  84. 'status' => 'REJECTED',
  85. ]);
  86. $this->assertSame('/rest/v2/payouts/detail', $service->calls[0]['path']);
  87. $this->assertSame('TX100', $service->calls[0]['payload']['reference_id']);
  88. $this->assertSame('T100', $service->calls[0]['payload']['transaction_id']);
  89. $this->assertSame('PAID', $detail['transaction_status']);
  90. $this->assertSame(1, $logic->resolvePayoutStatus($detail['transaction_status']));
  91. }
  92. /** @test */
  93. public function it_returns_empty_notify_detail_when_query_has_no_order_data()
  94. {
  95. $service = new FakePayPlusForCashier([
  96. ['code' => 200],
  97. ]);
  98. $logic = new PayPlusCashierLogic($service);
  99. $detail = $logic->queryPayoutDetailForNotify([
  100. 'reference_id' => 'TX100',
  101. 'transaction_id' => 'T100',
  102. 'status' => 'PAID',
  103. ]);
  104. $this->assertSame([], $detail);
  105. $this->assertCount(1, $service->calls);
  106. }
  107. /** @test */
  108. public function it_keeps_processing_payout_notify_unhandled_after_query()
  109. {
  110. $service = new FakePayPlusForCashier([
  111. [
  112. 'code' => 200,
  113. 'data' => [
  114. 'reference_id' => 'TX100',
  115. 'transaction_id' => 'T100',
  116. 'transaction_status' => 'PROCESSING',
  117. ],
  118. ],
  119. ]);
  120. $logic = new PayPlusCashierLogic($service);
  121. $detail = $logic->queryPayoutDetailForNotify([
  122. 'reference_id' => 'TX100',
  123. 'transaction_id' => 'T100',
  124. 'status' => 'REJECTED',
  125. ]);
  126. $this->assertSame('PROCESSING', $detail['transaction_status']);
  127. $this->assertSame(0, $logic->resolvePayoutStatus($detail['transaction_status']));
  128. }
  129. }
  130. class FakePayPlusForCashier extends PayPlus
  131. {
  132. public $calls = [];
  133. private $responses;
  134. public function __construct(array $responses)
  135. {
  136. parent::__construct([
  137. 'appId' => 200000,
  138. 'appKey' => 'test-key',
  139. 'currency' => 'USD',
  140. ]);
  141. $this->responses = $responses;
  142. }
  143. public function postPayout(string $path, array $payload)
  144. {
  145. $this->calls[] = [
  146. 'path' => $path,
  147. 'payload' => $payload,
  148. ];
  149. return array_shift($this->responses);
  150. }
  151. }