CustomerOrderShipmentTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Feature\GraphQL;
  3. use Webkul\BagistoApi\Tests\GraphQLTestCase;
  4. use Webkul\Core\Models\Channel;
  5. use Webkul\Customer\Models\Customer;
  6. use Webkul\Product\Models\Product;
  7. use Webkul\Sales\Models\Order;
  8. use Webkul\Sales\Models\OrderAddress;
  9. use Webkul\Sales\Models\OrderItem;
  10. use Webkul\Sales\Models\OrderPayment;
  11. use Webkul\Sales\Models\Shipment;
  12. use Webkul\Sales\Models\ShipmentItem;
  13. class CustomerOrderShipmentTest extends GraphQLTestCase
  14. {
  15. /**
  16. * Create test data — customer with order and shipments
  17. */
  18. private function createTestData(): array
  19. {
  20. $this->seedRequiredData();
  21. $customer = $this->createCustomer();
  22. $channel = Channel::first();
  23. $product = Product::factory()->create();
  24. $order = Order::factory()->create([
  25. 'customer_id' => $customer->id,
  26. 'customer_email' => $customer->email,
  27. 'customer_first_name' => $customer->first_name,
  28. 'customer_last_name' => $customer->last_name,
  29. 'channel_id' => $channel->id,
  30. 'status' => 'completed',
  31. 'shipping_title' => 'Flat Rate - Flat Rate',
  32. ]);
  33. $orderItem = OrderItem::factory()->create([
  34. 'order_id' => $order->id,
  35. 'product_id' => $product->id,
  36. 'sku' => 'TEST-SHIP-SKU-001',
  37. 'type' => 'simple',
  38. 'name' => 'Test Shipment Product',
  39. 'qty_ordered' => 3,
  40. ]);
  41. OrderPayment::factory()->create([
  42. 'order_id' => $order->id,
  43. 'method' => 'money_transfer',
  44. 'method_title' => 'Money Transfer',
  45. ]);
  46. /** Create shipping address */
  47. $shippingAddress = OrderAddress::factory()->create([
  48. 'order_id' => $order->id,
  49. 'address_type' => 'shipping',
  50. 'first_name' => 'John',
  51. 'last_name' => 'Doe',
  52. 'email' => $customer->email,
  53. 'phone' => '+1-555-0123',
  54. 'address' => '123 Main St',
  55. 'city' => 'Springfield',
  56. 'state' => 'IL',
  57. 'country' => 'US',
  58. 'postcode' => '62701',
  59. ]);
  60. /** Create first shipment (partial) */
  61. $shipment1 = Shipment::factory()->create([
  62. 'order_id' => $order->id,
  63. 'order_address_id' => $shippingAddress->id,
  64. 'customer_id' => $customer->id,
  65. 'customer_type' => Customer::class,
  66. 'status' => 'shipped',
  67. 'total_qty' => 2,
  68. 'total_weight' => 10.5,
  69. 'carrier_code' => 'flat_rate',
  70. 'carrier_title' => 'Flat Rate',
  71. 'track_number' => 'TRACK123456789',
  72. 'email_sent' => true,
  73. ]);
  74. ShipmentItem::create([
  75. 'shipment_id' => $shipment1->id,
  76. 'order_item_id' => $orderItem->id,
  77. 'name' => 'Test Shipment Product',
  78. 'sku' => 'TEST-SHIP-SKU-001',
  79. 'qty' => 2,
  80. 'weight' => 10.5,
  81. ]);
  82. /** Create second shipment (remainder) */
  83. $shipment2 = Shipment::factory()->create([
  84. 'order_id' => $order->id,
  85. 'order_address_id' => $shippingAddress->id,
  86. 'customer_id' => $customer->id,
  87. 'customer_type' => Customer::class,
  88. 'status' => 'pending',
  89. 'total_qty' => 1,
  90. 'total_weight' => 5.25,
  91. 'carrier_code' => 'flat_rate',
  92. 'carrier_title' => 'Flat Rate',
  93. 'track_number' => null,
  94. 'email_sent' => false,
  95. ]);
  96. ShipmentItem::create([
  97. 'shipment_id' => $shipment2->id,
  98. 'order_item_id' => $orderItem->id,
  99. 'name' => 'Test Shipment Product',
  100. 'sku' => 'TEST-SHIP-SKU-001',
  101. 'qty' => 1,
  102. 'weight' => 5.25,
  103. ]);
  104. return compact(
  105. 'customer',
  106. 'channel',
  107. 'product',
  108. 'order',
  109. 'orderItem',
  110. 'shippingAddress',
  111. 'shipment1',
  112. 'shipment2'
  113. );
  114. }
  115. // ── Shipments in Order Query ──────────────────────────────
  116. /**
  117. * Test: Query order with shipments collection
  118. */
  119. public function test_query_order_includes_shipments(): void
  120. {
  121. $testData = $this->createTestData();
  122. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  123. dump($testData);
  124. $query = <<<GQL
  125. query getCustomerOrder {
  126. customerOrder(id: "{$orderId}") {
  127. _id
  128. incrementId
  129. shipments {
  130. edges {
  131. node {
  132. _id
  133. status
  134. totalQty
  135. carrierTitle
  136. trackNumber
  137. }
  138. }
  139. }
  140. }
  141. }
  142. GQL;
  143. $response = $this->graphQL($query);
  144. $response->assertOk();
  145. $data = $response->json('data.customerOrder');
  146. $errors = $response->json('errors');
  147. // For debugging: print any errors
  148. if ($errors) {
  149. dump($errors);
  150. }
  151. expect($data['incrementId'])->toBeTruthy();
  152. expect($data['shipments']['edges'])->toHaveCount(2);
  153. $edges = $data['shipments']['edges'];
  154. /** First shipment should be shipped */
  155. expect($edges[0]['node']['status'])->toBe('shipped');
  156. expect($edges[0]['node']['totalQty'])->toBe(2);
  157. expect($edges[0]['node']['carrierTitle'])->toBe('Flat Rate');
  158. expect($edges[0]['node']['trackNumber'])->toBe('TRACK123456789');
  159. /** Second shipment should be pending */
  160. expect($edges[1]['node']['status'])->toBe('pending');
  161. expect($edges[1]['node']['totalQty'])->toBe(1);
  162. expect($edges[1]['node']['trackNumber'])->toBeNull();
  163. }
  164. /**
  165. * Test: Query order shipments includes items
  166. */
  167. public function test_query_shipments_includes_items(): void
  168. {
  169. $testData = $this->createTestData();
  170. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  171. $query = <<<GQL
  172. query getCustomerOrder {
  173. customerOrder(id: "{$orderId}") {
  174. _id
  175. shipments {
  176. _id
  177. status
  178. items {
  179. _id
  180. sku
  181. name
  182. qty
  183. weight
  184. }
  185. }
  186. }
  187. }
  188. GQL;
  189. $response = $this->graphQL($query);
  190. $response->assertOk();
  191. $data = $response->json('data.customerOrder');
  192. expect($data['shipments'])->toHaveCount(2);
  193. /** First shipment items */
  194. expect($data['shipments'][0]['items'])->toHaveCount(1);
  195. $item1 = $data['shipments'][0]['items'][0];
  196. expect($item1['sku'])->toBe('TEST-SHIP-SKU-001');
  197. expect($item1['name'])->toBe('Test Shipment Product');
  198. expect($item1['qty'])->toBe(2);
  199. expect($item1['weight'])->toBe(10.5);
  200. /** Second shipment items */
  201. expect($data['shipments'][1]['items'])->toHaveCount(1);
  202. $item2 = $data['shipments'][1]['items'][0];
  203. expect($item2['sku'])->toBe('TEST-SHIP-SKU-001');
  204. expect($item2['qty'])->toBe(1);
  205. expect($item2['weight'])->toBe(5.25);
  206. }
  207. /**
  208. * Test: Query shipments includes shipping address
  209. */
  210. public function test_query_shipments_includes_shipping_address(): void
  211. {
  212. $testData = $this->createTestData();
  213. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  214. $query = <<<GQL
  215. query getCustomerOrder {
  216. customerOrder(id: "{$orderId}") {
  217. _id
  218. shipments {
  219. _id
  220. shippingAddress {
  221. _id
  222. firstName
  223. lastName
  224. email
  225. street
  226. city
  227. state
  228. postcode
  229. phone
  230. }
  231. }
  232. }
  233. }
  234. GQL;
  235. $response = $this->graphQL($query);
  236. $response->assertOk();
  237. $data = $response->json('data.customerOrder');
  238. expect($data['shipments'])->toHaveCount(2);
  239. /** First shipment address */
  240. $address = $data['shipments'][0]['shippingAddress'];
  241. if ($address) {
  242. expect($address['firstName'])->toBe('John');
  243. expect($address['lastName'])->toBe('Doe');
  244. expect($address['city'])->toBe('Springfield');
  245. expect($address['phone'])->toBe('+1-555-0123');
  246. }
  247. }
  248. /**
  249. * Test: Query shipments includes payment method
  250. */
  251. public function test_query_shipments_includes_payment_method(): void
  252. {
  253. $testData = $this->createTestData();
  254. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  255. $query = <<<GQL
  256. query getCustomerOrder {
  257. customerOrder(id: "{$orderId}") {
  258. _id
  259. shipments {
  260. _id
  261. paymentMethodTitle
  262. shippingMethodTitle
  263. }
  264. }
  265. }
  266. GQL;
  267. $response = $this->graphQL($query);
  268. $response->assertOk();
  269. $data = $response->json('data.customerOrder');
  270. expect($data['shipments'])->toHaveCount(2);
  271. /** Both shipments should have payment and shipping method */
  272. expect($data['shipments'][0]['paymentMethodTitle'])->toBe('Money Transfer');
  273. expect($data['shipments'][0]['shippingMethodTitle'])->toBe('Flat Rate - Flat Rate');
  274. expect($data['shipments'][1]['paymentMethodTitle'])->toBe('Money Transfer');
  275. expect($data['shipments'][1]['shippingMethodTitle'])->toBe('Flat Rate - Flat Rate');
  276. }
  277. /**
  278. * Test: Query shipment computed fields (shippingNumber)
  279. */
  280. public function test_query_shipment_computed_fields(): void
  281. {
  282. $testData = $this->createTestData();
  283. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  284. $query = <<<GQL
  285. query getCustomerOrder {
  286. customerOrder(id: "{$orderId}") {
  287. _id
  288. shipments {
  289. _id
  290. shippingNumber
  291. }
  292. }
  293. }
  294. GQL;
  295. $response = $this->graphQL($query);
  296. $response->assertOk();
  297. $data = $response->json('data.customerOrder');
  298. expect($data['shipments'])->toHaveCount(2);
  299. /** Shipping numbers should be formatted as #ID */
  300. $shipment1 = $data['shipments'][0];
  301. expect($shipment1['shippingNumber'])->toMatch('/^#\d+$/');
  302. }
  303. /**
  304. * Test: Query all shipment fields
  305. */
  306. public function test_query_all_shipment_fields(): void
  307. {
  308. $testData = $this->createTestData();
  309. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  310. $query = <<<GQL
  311. query getCustomerOrder {
  312. customerOrder(id: "{$orderId}") {
  313. _id
  314. shipments {
  315. _id
  316. status
  317. totalQty
  318. totalWeight
  319. carrierCode
  320. carrierTitle
  321. trackNumber
  322. emailSent
  323. shippingNumber
  324. paymentMethodTitle
  325. shippingMethodTitle
  326. createdAt
  327. }
  328. }
  329. }
  330. GQL;
  331. $response = $this->graphQL($query);
  332. $response->assertOk();
  333. $data = $response->json('data.customerOrder');
  334. expect($data['shipments'])->toHaveCount(2);
  335. $shipment = $data['shipments'][0];
  336. expect($shipment)->toHaveKeys([
  337. '_id',
  338. 'status',
  339. 'totalQty',
  340. 'totalWeight',
  341. 'carrierCode',
  342. 'carrierTitle',
  343. 'trackNumber',
  344. 'emailSent',
  345. 'shippingNumber',
  346. 'paymentMethodTitle',
  347. 'shippingMethodTitle',
  348. 'createdAt',
  349. ]);
  350. }
  351. // ── Access Control ────────────────────────────────────────
  352. /**
  353. * Test: Customer only sees their own shipments
  354. */
  355. public function test_customer_only_sees_own_shipments(): void
  356. {
  357. $testData = $this->createTestData();
  358. /** Create another customer with their own order/shipment */
  359. $otherCustomer = $this->createCustomer();
  360. $channel = Channel::first();
  361. $product = Product::factory()->create();
  362. $otherOrder = Order::factory()->create([
  363. 'customer_id' => $otherCustomer->id,
  364. 'customer_email' => $otherCustomer->email,
  365. 'customer_first_name' => $otherCustomer->first_name,
  366. 'customer_last_name' => $otherCustomer->last_name,
  367. 'channel_id' => $channel->id,
  368. 'status' => 'completed',
  369. ]);
  370. $otherOrderItem = OrderItem::factory()->create([
  371. 'order_id' => $otherOrder->id,
  372. 'product_id' => $product->id,
  373. 'sku' => 'OTHER-SKU',
  374. 'type' => 'simple',
  375. 'name' => 'Other Product',
  376. ]);
  377. $otherAddress = OrderAddress::factory()->create([
  378. 'order_id' => $otherOrder->id,
  379. 'address_type' => 'shipping',
  380. ]);
  381. Shipment::factory()->create([
  382. 'order_id' => $otherOrder->id,
  383. 'order_address_id' => $otherAddress->id,
  384. 'customer_id' => $otherCustomer->id,
  385. 'customer_type' => Customer::class,
  386. 'status' => 'shipped',
  387. 'total_qty' => 1,
  388. ]);
  389. ShipmentItem::create([
  390. 'shipment_id' => Shipment::where('order_id', $otherOrder->id)->first()->id,
  391. 'order_item_id' => $otherOrderItem->id,
  392. ]);
  393. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  394. $query = <<<GQL
  395. query getCustomerOrder {
  396. customerOrder(id: "{$orderId}") {
  397. _id
  398. shipments {
  399. _id
  400. }
  401. }
  402. }
  403. GQL;
  404. $response = $this->authenticatedGraphQL($testData['customer'], $query);
  405. $response->assertOk();
  406. $data = $response->json('data.customerOrder');
  407. /** Should only see 2 shipments from own order */
  408. expect($data['shipments'])->toHaveCount(2);
  409. }
  410. /**
  411. * Test: Unauthenticated request cannot access shipments
  412. */
  413. public function test_unauthenticated_cannot_access_shipments(): void
  414. {
  415. $testData = $this->createTestData();
  416. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  417. $query = <<<GQL
  418. query getCustomerOrder {
  419. customerOrder(id: "{$orderId}") {
  420. _id
  421. shipments {
  422. _id
  423. }
  424. }
  425. }
  426. GQL;
  427. $response = $this->graphQL($query);
  428. $response->assertOk();
  429. $errors = $response->json('errors');
  430. expect($errors)->not()->toBeEmpty();
  431. }
  432. // ── Shipment Status Filtering ─────────────────────────────
  433. /**
  434. * Test: Filter shipments by status (archived)
  435. */
  436. public function test_order_with_shipped_and_pending_shipments(): void
  437. {
  438. $testData = $this->createTestData();
  439. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  440. $query = <<<GQL
  441. query getCustomerOrder {
  442. customerOrder(id: "{$orderId}") {
  443. _id
  444. shipments {
  445. _id
  446. status
  447. }
  448. }
  449. }
  450. GQL;
  451. $response = $this->graphQL($query);
  452. $response->assertOk();
  453. $data = $response->json('data.customerOrder');
  454. expect($data['shipments'])->toHaveCount(2);
  455. $statuses = array_column($data['shipments'], 'status');
  456. expect($statuses)->toContain('shipped');
  457. expect($statuses)->toContain('pending');
  458. }
  459. // ── Shipment Item Details ────────────────────────────────
  460. /**
  461. * Test: Query shipment items with full details
  462. */
  463. public function test_query_shipment_items_full_details(): void
  464. {
  465. $testData = $this->createTestData();
  466. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  467. $query = <<<GQL
  468. query getCustomerOrder {
  469. customerOrder(id: "{$orderId}") {
  470. _id
  471. shipments {
  472. _id
  473. items {
  474. _id
  475. sku
  476. name
  477. qty
  478. weight
  479. }
  480. }
  481. }
  482. }
  483. GQL;
  484. $response = $this->graphQL($query);
  485. $response->assertOk();
  486. $data = $response->json('data.customerOrder');
  487. expect($data['shipments'])->toHaveCount(2);
  488. /** Each shipment has items */
  489. foreach ($data['shipments'] as $shipment) {
  490. expect($shipment['items'])->not()->toBeEmpty();
  491. foreach ($shipment['items'] as $item) {
  492. expect($item)->toHaveKeys(['_id', 'sku', 'name', 'qty', 'weight']);
  493. expect($item['sku'])->toBeTruthy();
  494. expect($item['qty'])->toBeGreaterThan(0);
  495. }
  496. }
  497. }
  498. /**
  499. * Test: Shipment item preserves order item details
  500. */
  501. public function test_shipment_item_preserves_order_item_details(): void
  502. {
  503. $testData = $this->createTestData();
  504. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  505. $query = <<<GQL
  506. query getCustomerOrder {
  507. customerOrder(id: "{$orderId}") {
  508. _id
  509. shipments {
  510. items {
  511. sku
  512. name
  513. }
  514. }
  515. }
  516. }
  517. GQL;
  518. $response = $this->graphQL($query);
  519. $response->assertOk();
  520. $data = $response->json('data.customerOrder');
  521. /** Verify SKU and name match original order item */
  522. $shipment = $data['shipments'][0];
  523. $item = $shipment['items'][0];
  524. expect($item['sku'])->toBe('TEST-SHIP-SKU-001');
  525. expect($item['name'])->toBe('Test Shipment Product');
  526. }
  527. // ── Tracking Information ──────────────────────────────────
  528. /**
  529. * Test: Shipment with tracking number
  530. */
  531. public function test_shipment_with_tracking_number(): void
  532. {
  533. $testData = $this->createTestData();
  534. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  535. $query = <<<GQL
  536. query getCustomerOrder {
  537. customerOrder(id: "{$orderId}") {
  538. _id
  539. shipments(filter: {status: ["shipped"]}) {
  540. _id
  541. trackNumber
  542. carrierCode
  543. carrierTitle
  544. emailSent
  545. }
  546. }
  547. }
  548. GQL;
  549. $response = $this->graphQL($query);
  550. $response->assertOk();
  551. $data = $response->json('data.customerOrder');
  552. expect($data['shipments'])->not()->toBeEmpty();
  553. $shipment = $data['shipments'][0];
  554. expect($shipment['trackNumber'])->toBe('TRACK123456789');
  555. expect($shipment['carriercode'])->toBe('flat_rate');
  556. expect($shipment['emailSent'])->toBeTrue();
  557. }
  558. /**
  559. * Test: Shipment without tracking number (pending)
  560. */
  561. public function test_shipment_without_tracking_number(): void
  562. {
  563. $testData = $this->createTestData();
  564. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  565. $query = <<<GQL
  566. query getCustomerOrder {
  567. customerOrder(id: "{$orderId}") {
  568. _id
  569. shipments {
  570. _id
  571. status
  572. trackNumber
  573. emailSent
  574. }
  575. }
  576. }
  577. GQL;
  578. $response = $this->graphQL($query);
  579. $response->assertOk();
  580. $data = $response->json('data.customerOrder');
  581. $pendingShipment = collect($data['shipments'])
  582. ->firstWhere('status', 'pending');
  583. expect($pendingShipment)->not()->toBeNull();
  584. expect($pendingShipment['trackNumber'])->toBeNull();
  585. expect($pendingShipment['emailSent'])->toBeFalse();
  586. }
  587. // ── Schema Introspection ──────────────────────────────────
  588. /**
  589. * Test: CustomerOrderShipment type has expected fields in schema
  590. */
  591. public function test_customer_order_shipment_schema_has_expected_fields(): void
  592. {
  593. $query = <<<'GQL'
  594. {
  595. __type(name: "CustomerOrderShipment") {
  596. name
  597. fields {
  598. name
  599. }
  600. }
  601. }
  602. GQL;
  603. $response = $this->graphQL($query);
  604. $response->assertSuccessful();
  605. $type = $response->json('data.__type');
  606. expect($type)->not->toBeNull()
  607. ->and($type['name'])->toBe('CustomerOrderShipment');
  608. $fieldNames = array_column($type['fields'], 'name');
  609. expect($fieldNames)
  610. ->toContain('_id')
  611. ->toContain('status')
  612. ->toContain('totalQty')
  613. ->toContain('totalWeight')
  614. ->toContain('carrierCode')
  615. ->toContain('carrierTitle')
  616. ->toContain('trackNumber')
  617. ->toContain('emailSent')
  618. ->toContain('shippingNumber')
  619. ->toContain('items')
  620. ->toContain('shippingAddress')
  621. ->toContain('createdAt');
  622. }
  623. /**
  624. * Test: CustomerOrderShipmentItem type has expected fields in schema
  625. */
  626. public function test_customer_order_shipment_item_schema_has_expected_fields(): void
  627. {
  628. $query = <<<'GQL'
  629. {
  630. __type(name: "CustomerOrderShipmentItem") {
  631. name
  632. fields {
  633. name
  634. }
  635. }
  636. }
  637. GQL;
  638. $response = $this->graphQL($query);
  639. $response->assertSuccessful();
  640. $type = $response->json('data.__type');
  641. expect($type)->not->toBeNull()
  642. ->and($type['name'])->toBe('CustomerOrderShipmentItem');
  643. $fieldNames = array_column($type['fields'], 'name');
  644. expect($fieldNames)
  645. ->toContain('_id')
  646. ->toContain('sku')
  647. ->toContain('name')
  648. ->toContain('qty')
  649. ->toContain('weight');
  650. }
  651. // ── Weight and Quantity ───────────────────────────────────
  652. /**
  653. * Test: Shipment total qty and weight calculations
  654. */
  655. public function test_shipment_total_qty_and_weight(): void
  656. {
  657. $testData = $this->createTestData();
  658. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  659. $query = <<<GQL
  660. query getCustomerOrder {
  661. customerOrder(id: "{$orderId}") {
  662. _id
  663. shipments {
  664. _id
  665. totalQty
  666. totalWeight
  667. }
  668. }
  669. }
  670. GQL;
  671. $response = $this->graphQL($query);
  672. $response->assertOk();
  673. $data = $response->json('data.customerOrder');
  674. expect($data['shipments'])->toHaveCount(2);
  675. /** First shipment */
  676. expect($data['shipments'][0]['totalQty'])->toBe(2);
  677. expect($data['shipments'][0]['totalWeight'])->toBe(10.5);
  678. /** Second shipment */
  679. expect($data['shipments'][1]['totalQty'])->toBe(1);
  680. expect($data['shipments'][1]['totalWeight'])->toBe(5.25);
  681. }
  682. /**
  683. * Test: Individual item qty and weight
  684. */
  685. public function test_shipment_item_qty_and_weight(): void
  686. {
  687. $testData = $this->createTestData();
  688. $orderId = "/api/shop/customer-orders/{$testData['order']->id}";
  689. $query = <<<GQL
  690. query getCustomerOrder {
  691. customerOrder(id: "{$orderId}") {
  692. shipments {
  693. items {
  694. qty
  695. weight
  696. }
  697. }
  698. }
  699. }
  700. GQL;
  701. $response = $this->graphQL($query);
  702. $response->assertOk();
  703. $data = $response->json('data.customerOrder');
  704. $items = collect($data['shipments'])
  705. ->pluck('items')
  706. ->flatten(1);
  707. expect($items)->not()->toBeEmpty();
  708. foreach ($items as $item) {
  709. expect($item['qty'])->toBeGreaterThan(0);
  710. expect($item['weight'])->toBeGreaterThan(0);
  711. }
  712. }
  713. }