CustomerOrderRestTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Feature\Rest;
  3. use Webkul\BagistoApi\Tests\RestApiTestCase;
  4. use Webkul\Checkout\Models\Cart;
  5. use Webkul\Core\Models\Channel;
  6. use Webkul\Product\Models\Product;
  7. use Webkul\BagistoApi\Models\GuestCartTokens;
  8. use Webkul\Sales\Models\Order;
  9. use Webkul\Sales\Models\OrderItem;
  10. use Webkul\Sales\Models\OrderPayment;
  11. class CustomerOrderRestTest extends RestApiTestCase
  12. {
  13. /**
  14. * Create test data — customer with orders
  15. */
  16. private function createTestData(): array
  17. {
  18. $this->seedRequiredData();
  19. $customer = $this->createCustomer();
  20. $channel = Channel::first();
  21. $product = Product::factory()->create();
  22. $order1 = Order::factory()->create([
  23. 'customer_id' => $customer->id,
  24. 'customer_email' => $customer->email,
  25. 'customer_first_name' => $customer->first_name,
  26. 'customer_last_name' => $customer->last_name,
  27. 'channel_id' => $channel->id,
  28. 'status' => 'pending',
  29. ]);
  30. OrderItem::factory()->create([
  31. 'order_id' => $order1->id,
  32. 'product_id' => $product->id,
  33. 'sku' => 'TEST-SKU-001',
  34. 'type' => 'simple',
  35. 'name' => 'Test Product One',
  36. ]);
  37. OrderPayment::factory()->create([
  38. 'order_id' => $order1->id,
  39. ]);
  40. $order2 = Order::factory()->create([
  41. 'customer_id' => $customer->id,
  42. 'customer_email' => $customer->email,
  43. 'customer_first_name' => $customer->first_name,
  44. 'customer_last_name' => $customer->last_name,
  45. 'channel_id' => $channel->id,
  46. 'status' => 'completed',
  47. ]);
  48. OrderItem::factory()->create([
  49. 'order_id' => $order2->id,
  50. 'product_id' => $product->id,
  51. 'sku' => 'TEST-SKU-002',
  52. 'type' => 'simple',
  53. 'name' => 'Test Product Two',
  54. ]);
  55. OrderPayment::factory()->create([
  56. 'order_id' => $order2->id,
  57. ]);
  58. return compact('customer', 'channel', 'product', 'order1', 'order2');
  59. }
  60. /**
  61. * Create guest order with payment additional cart_token/cart_id.
  62. */
  63. private function createGuestOrderData(): array
  64. {
  65. $this->seedRequiredData();
  66. $channel = Channel::first();
  67. $product = Product::factory()->create();
  68. $cart = Cart::factory()->create(['customer_id' => null]);
  69. $guestToken = 'guest-token-'.uniqid();
  70. GuestCartTokens::query()->create([
  71. 'token' => $guestToken,
  72. 'cart_id' => $cart->id,
  73. ]);
  74. $order = Order::factory()->create([
  75. 'customer_id' => null,
  76. 'customer_type' => null,
  77. 'is_guest' => 1,
  78. 'customer_email'=> 'guest@example.com',
  79. 'channel_id' => $channel->id,
  80. 'status' => 'pending',
  81. ]);
  82. OrderItem::factory()->create([
  83. 'order_id' => $order->id,
  84. 'product_id' => $product->id,
  85. 'sku' => 'GUEST-TEST-SKU-001',
  86. 'type' => 'simple',
  87. 'name' => 'Guest Test Product',
  88. ]);
  89. OrderPayment::factory()->create([
  90. 'order_id' => $order->id,
  91. 'additional' => [
  92. 'cart_token' => $guestToken,
  93. 'cart_id' => $cart->id,
  94. ],
  95. ]);
  96. return compact('order', 'guestToken');
  97. }
  98. // ── Collection ────────────────────────────────────────────
  99. /**
  100. * Test: GET /api/shop/customer-orders returns collection
  101. */
  102. public function test_get_customer_orders_collection(): void
  103. {
  104. $testData = $this->createTestData();
  105. $response = $this->authenticatedGet($testData['customer'], '/api/shop/customer-orders');
  106. $response->assertOk();
  107. $json = $response->json();
  108. expect($json)->toBeArray();
  109. expect(count($json))->toBeGreaterThanOrEqual(2);
  110. }
  111. /**
  112. * Test: GET /api/shop/customer-orders without auth returns error
  113. */
  114. public function test_get_customer_orders_requires_auth(): void
  115. {
  116. $this->seedRequiredData();
  117. $response = $this->publicGet('/api/shop/customer-orders');
  118. expect(in_array($response->getStatusCode(), [401, 403, 500]))->toBeTrue();
  119. }
  120. /**
  121. * Test: Customer only sees own orders
  122. */
  123. public function test_customer_only_sees_own_orders(): void
  124. {
  125. $testData = $this->createTestData();
  126. /** Create another customer with their own order */
  127. $otherCustomer = $this->createCustomer();
  128. $channel = Channel::first();
  129. Order::factory()->create([
  130. 'customer_id' => $otherCustomer->id,
  131. 'customer_email' => $otherCustomer->email,
  132. 'customer_first_name' => $otherCustomer->first_name,
  133. 'customer_last_name' => $otherCustomer->last_name,
  134. 'channel_id' => $channel->id,
  135. 'status' => 'pending',
  136. ]);
  137. $response = $this->authenticatedGet($testData['customer'], '/api/shop/customer-orders');
  138. $response->assertOk();
  139. $json = $response->json();
  140. /** Should only see the 2 orders belonging to testData customer */
  141. expect(count($json))->toBe(2);
  142. }
  143. /**
  144. * Test: Customer with no orders returns empty collection
  145. */
  146. public function test_customer_with_no_orders_returns_empty(): void
  147. {
  148. $this->seedRequiredData();
  149. $customer = $this->createCustomer();
  150. $response = $this->authenticatedGet($customer, '/api/shop/customer-orders');
  151. $response->assertOk();
  152. $json = $response->json();
  153. expect($json)->toBeArray();
  154. expect(count($json))->toBe(0);
  155. }
  156. // ── Single Item ───────────────────────────────────────────
  157. /**
  158. * Test: GET /api/shop/customer-orders/{id} returns single order
  159. */
  160. public function test_get_single_customer_order(): void
  161. {
  162. $testData = $this->createTestData();
  163. $response = $this->authenticatedGet(
  164. $testData['customer'],
  165. '/api/shop/customer-orders/'.$testData['order1']->id
  166. );
  167. $response->assertOk();
  168. $json = $response->json();
  169. expect($json)->toHaveKey('id');
  170. expect($json)->toHaveKey('incrementId');
  171. expect($json)->toHaveKey('status');
  172. expect($json)->toHaveKey('customerEmail');
  173. expect($json)->toHaveKey('customerFirstName');
  174. expect($json)->toHaveKey('customerLastName');
  175. expect($json)->toHaveKey('grandTotal');
  176. expect($json)->toHaveKey('subTotal');
  177. expect($json)->toHaveKey('shippingMethod');
  178. expect($json)->toHaveKey('shippingTitle');
  179. expect($json)->toHaveKey('baseCurrencyCode');
  180. expect($json)->toHaveKey('orderCurrencyCode');
  181. expect($json)->toHaveKey('totalItemCount');
  182. expect($json)->toHaveKey('totalQtyOrdered');
  183. expect($json)->toHaveKey('createdAt');
  184. expect($json['id'])->toBe($testData['order1']->id);
  185. expect($json['status'])->toBe('pending');
  186. expect($json['customerEmail'])->toBe($testData['customer']->email);
  187. }
  188. /**
  189. * Test: GET /api/shop/customer-orders/{id} with invalid id returns 404
  190. */
  191. public function test_get_customer_order_not_found(): void
  192. {
  193. $this->seedRequiredData();
  194. $customer = $this->createCustomer();
  195. $response = $this->authenticatedGet($customer, '/api/shop/customer-orders/999999');
  196. expect(in_array($response->getStatusCode(), [404, 500]))->toBeTrue();
  197. }
  198. /**
  199. * Test: Cannot access another customer's order by ID
  200. */
  201. public function test_cannot_access_other_customers_order(): void
  202. {
  203. $testData = $this->createTestData();
  204. $otherCustomer = $this->createCustomer();
  205. $response = $this->authenticatedGet(
  206. $otherCustomer,
  207. '/api/shop/customer-orders/'.$testData['order1']->id
  208. );
  209. /** Should return 404/500 because the order doesn't belong to otherCustomer */
  210. expect(in_array($response->getStatusCode(), [404, 500]))->toBeTrue();
  211. }
  212. /**
  213. * Test: Single order without auth returns error
  214. */
  215. public function test_get_single_order_requires_auth(): void
  216. {
  217. $testData = $this->createTestData();
  218. $response = $this->publicGet(
  219. '/api/shop/customer-orders/'.$testData['order1']->id
  220. );
  221. expect(in_array($response->getStatusCode(), [401, 403, 500]))->toBeTrue();
  222. }
  223. /**
  224. * Test: Guest can access own order detail with guest token.
  225. */
  226. public function test_guest_can_get_own_order_detail(): void
  227. {
  228. $guestData = $this->createGuestOrderData();
  229. $response = $this->guestGet(
  230. $guestData['guestToken'],
  231. '/api/shop/customer-orders/'.$guestData['order']->id
  232. );
  233. $response->assertOk();
  234. $json = $response->json();
  235. expect($json['id'])->toBe($guestData['order']->id);
  236. expect($json['isGuest'])->toBeTrue();
  237. }
  238. /**
  239. * Test: Guest cannot access others order detail.
  240. */
  241. public function test_guest_cannot_get_other_order_detail(): void
  242. {
  243. $guestData = $this->createGuestOrderData();
  244. $response = $this->guestGet(
  245. 'guest-token-wrong',
  246. '/api/shop/customer-orders/'.$guestData['order']->id
  247. );
  248. expect(in_array($response->getStatusCode(), [401, 403, 404, 500]))->toBeTrue();
  249. }
  250. // ── Response Shape ────────────────────────────────────────
  251. /**
  252. * Test: Order response includes financial fields
  253. */
  254. public function test_order_response_includes_financial_fields(): void
  255. {
  256. $testData = $this->createTestData();
  257. $response = $this->authenticatedGet(
  258. $testData['customer'],
  259. '/api/shop/customer-orders/'.$testData['order1']->id
  260. );
  261. $response->assertOk();
  262. $json = $response->json();
  263. expect($json)->toHaveKey('grandTotal');
  264. expect($json)->toHaveKey('baseGrandTotal');
  265. expect($json)->toHaveKey('subTotal');
  266. expect($json)->toHaveKey('baseSubTotal');
  267. expect($json)->toHaveKey('taxAmount');
  268. expect($json)->toHaveKey('shippingAmount');
  269. expect($json)->toHaveKey('discountAmount');
  270. }
  271. /**
  272. * Test: Collection returns orders with correct statuses
  273. */
  274. public function test_collection_returns_orders_with_correct_statuses(): void
  275. {
  276. $testData = $this->createTestData();
  277. $response = $this->authenticatedGet($testData['customer'], '/api/shop/customer-orders');
  278. $response->assertOk();
  279. $json = $response->json();
  280. $statuses = array_column($json, 'status');
  281. expect($statuses)->toContain('pending');
  282. expect($statuses)->toContain('completed');
  283. }
  284. }