PaymentServiceCancelStrategyTest.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Unit\Services;
  3. use Illuminate\Support\Facades\Event;
  4. use Mockery;
  5. use Tests\TestCase;
  6. use Webkul\BagistoApi\Repositories\PaymentAttemptRepository;
  7. use Webkul\BagistoApi\Services\CartTokenService;
  8. use Webkul\BagistoApi\Services\PaymentService;
  9. use Webkul\Checkout\Repositories\CartRepository;
  10. use Webkul\Sales\Repositories\InvoiceRepository;
  11. use Webkul\Sales\Repositories\OrderRepository;
  12. use Webkul\Sales\Repositories\OrderTransactionRepository;
  13. /**
  14. * Coverage for the cancel-order strategy branches required by the
  15. * "支付流程" spec:
  16. *
  17. * - userManual -> always cancel immediately (overrides keep_pending)
  18. * - guest -> immediate cancel + reactivate old cart
  19. * - customer + addr -> keep order pending
  20. * - customer + !addr + config=cancel -> cancel
  21. * - customer + !addr + config=keep_pending -> keep pending
  22. * - !addr branch ALWAYS dispatches the no-address event
  23. */
  24. class PaymentServiceCancelStrategyTest extends TestCase
  25. {
  26. protected function tearDown(): void
  27. {
  28. Mockery::close();
  29. parent::tearDown();
  30. }
  31. private function makeService(): PaymentService
  32. {
  33. return new PaymentService(
  34. Mockery::mock(OrderRepository::class),
  35. Mockery::mock(CartRepository::class),
  36. Mockery::mock(CartTokenService::class),
  37. Mockery::mock(InvoiceRepository::class),
  38. Mockery::mock(OrderTransactionRepository::class),
  39. Mockery::mock(PaymentAttemptRepository::class),
  40. );
  41. }
  42. private function fakeOrder(?array $shippingFields, array $additional = []): object
  43. {
  44. $payment = (object) ['additional' => $additional];
  45. $shipping = $shippingFields ? (object) $shippingFields : null;
  46. return new class($payment, $shipping)
  47. {
  48. public function __construct(
  49. public object $payment,
  50. public ?object $shipping_address,
  51. ) {}
  52. };
  53. }
  54. public function test_user_manual_cancel_overrides_keep_pending(): void
  55. {
  56. Event::fake();
  57. $order = $this->fakeOrder([
  58. 'city' => 'San Francisco',
  59. 'postcode' => '94016',
  60. ]);
  61. $result = $this->makeService()->decideCancelStrategy($order, isGuest: false, userManual: true);
  62. $this->assertSame('cancel', $result['action']);
  63. $this->assertSame('user_manual', $result['reason']);
  64. Event::assertNotDispatched('bagistoapi.express.cancel.no-address');
  65. }
  66. public function test_user_manual_guest_cancel_still_reactivates_cart(): void
  67. {
  68. Event::fake();
  69. $order = $this->fakeOrder([
  70. 'city' => 'NYC',
  71. 'postcode' => '10001',
  72. ], ['cart_id' => 42]);
  73. $result = $this->makeService()->decideCancelStrategy($order, isGuest: true, userManual: true);
  74. $this->assertSame('cancel', $result['action']);
  75. $this->assertSame('user_manual', $result['reason']);
  76. $this->assertSame(42, $result['reactivate_cart']);
  77. }
  78. public function test_guest_cancel_reactivates_old_cart(): void
  79. {
  80. Event::fake();
  81. $order = $this->fakeOrder([
  82. 'city' => 'NYC',
  83. 'postcode' => '10001',
  84. ], ['cart_id' => 42]);
  85. $result = $this->makeService()->decideCancelStrategy($order, isGuest: true);
  86. $this->assertSame('cancel', $result['action']);
  87. $this->assertSame('guest', $result['reason']);
  88. $this->assertSame(42, $result['reactivate_cart']);
  89. }
  90. public function test_customer_with_real_shipping_address_keeps_pending(): void
  91. {
  92. Event::fake();
  93. $order = $this->fakeOrder([
  94. 'city' => 'San Francisco',
  95. 'postcode' => '94016',
  96. ]);
  97. $result = $this->makeService()->decideCancelStrategy($order, isGuest: false);
  98. $this->assertSame('keep_pending', $result['action']);
  99. $this->assertSame('customer_has_shipping_address', $result['reason']);
  100. Event::assertNotDispatched('bagistoapi.express.cancel.no-address');
  101. }
  102. public function test_customer_without_shipping_address_default_cancel_strategy(): void
  103. {
  104. config(['bagistoapi.express_checkout.cancel_without_address' => 'cancel']);
  105. Event::fake();
  106. $order = $this->fakeOrder(null);
  107. $result = $this->makeService()->decideCancelStrategy($order, isGuest: false);
  108. $this->assertSame('cancel', $result['action']);
  109. $this->assertSame('customer_no_shipping_address', $result['reason']);
  110. Event::assertDispatched('bagistoapi.express.cancel.no-address');
  111. }
  112. public function test_customer_without_shipping_address_keep_pending_strategy(): void
  113. {
  114. config(['bagistoapi.express_checkout.cancel_without_address' => 'keep_pending']);
  115. Event::fake();
  116. $order = $this->fakeOrder(null);
  117. $result = $this->makeService()->decideCancelStrategy($order, isGuest: false);
  118. $this->assertSame('keep_pending', $result['action']);
  119. $this->assertSame('customer_no_shipping_address', $result['reason']);
  120. Event::assertDispatched('bagistoapi.express.cancel.no-address');
  121. }
  122. public function test_customer_with_placeholder_address_is_treated_as_no_address(): void
  123. {
  124. config([
  125. 'bagistoapi.express_checkout.cancel_without_address' => 'cancel',
  126. 'bagistoapi.express_checkout.placeholder_address' => [
  127. 'city' => 'Pending',
  128. 'postcode' => '00000',
  129. ],
  130. ]);
  131. Event::fake();
  132. $order = $this->fakeOrder([
  133. 'city' => 'Pending',
  134. 'postcode' => '00000',
  135. ]);
  136. $result = $this->makeService()->decideCancelStrategy($order, isGuest: false);
  137. $this->assertSame('cancel', $result['action']);
  138. $this->assertSame('customer_no_shipping_address', $result['reason']);
  139. }
  140. }