From 4b84afbc9289f85f617379c75adf386a7e19b49e Mon Sep 17 00:00:00 2001 From: Patrick McLain Date: Sun, 3 Feb 2019 16:34:04 -0500 Subject: [PATCH] Provide available shipping rates for addresses --- .../Cart/Address/AddressDataProvider.php | 54 ++++++++++++++- .../Model/Resolver/CartAddresses.php | 7 +- .../Magento/QuoteGraphQl/etc/schema.graphqls | 20 +++++- .../Quote/SetShippingAddressOnCartTest.php | 65 +++++++++++++++++++ 4 files changed, 140 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php b/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php index fb742477ec99..64032cae64b5 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php @@ -10,7 +10,9 @@ use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Api\Data\ShippingMethodInterface; use Magento\Quote\Model\Quote\Address as QuoteAddress; +use Magento\Quote\Model\Cart\ShippingMethodConverter; /** * Class AddressDataProvider @@ -24,24 +26,33 @@ class AddressDataProvider */ private $dataObjectConverter; + /** + * @var ShippingMethodConverter + */ + private $shippingMethodConverter; + /** * AddressDataProvider constructor. * * @param ExtensibleDataObjectConverter $dataObjectConverter + * @param ShippingMethodConverter $shippingMethodConverter */ public function __construct( - ExtensibleDataObjectConverter $dataObjectConverter + ExtensibleDataObjectConverter $dataObjectConverter, + ShippingMethodConverter $shippingMethodConverter ) { $this->dataObjectConverter = $dataObjectConverter; + $this->shippingMethodConverter = $shippingMethodConverter; } /** * Collect and return information about shipping and billing addresses * * @param CartInterface $cart + * @param bool $includeShippingMethods * @return array */ - public function getCartAddresses(CartInterface $cart): array + public function getCartAddresses(CartInterface $cart, $includeShippingMethods = false): array { $addressData = []; $shippingAddress = $cart->getShippingAddress(); @@ -50,6 +61,12 @@ public function getCartAddresses(CartInterface $cart): array if ($shippingAddress) { $shippingData = $this->dataObjectConverter->toFlatArray($shippingAddress, [], AddressInterface::class); $shippingData['address_type'] = 'SHIPPING'; + if ($includeShippingMethods) { + $shippingData['available_shipping_methods'] = $this->extractAvailableShippingRateData( + $cart, + $shippingAddress + ); + } $addressData[] = array_merge($shippingData, $this->extractAddressData($shippingAddress)); } @@ -84,11 +101,42 @@ private function extractAddressData(QuoteAddress $address): array 'code' => $address->getShippingMethod(), 'label' => $address->getShippingDescription(), 'free_shipping' => $address->getFreeShipping(), + 'amount' => $address->getShippingAmount(), + 'base_amount' => $address->getBaseShippingAmount(), + 'amount_incl_tax' => $address->getShippingInclTax(), + 'base_amount_incl_tax' => $address->getBaseShippingInclTax(), ], 'items_weight' => $address->getWeight(), - 'customer_notes' => $address->getCustomerNotes() + 'customer_notes' => $address->getCustomerNotes(), + 'quote_id' => $address->getQuoteId(), ]; return $addressData; } + + private function extractAvailableShippingRateData(CartInterface $cart, QuoteAddress $address): array + { + $output = []; + + // Allow shipping rates by setting country id for new addresses + if (!$address->getCountryId() && $address->getCountryCode()) { + $address->setCountryId($address->getCountryCode()); + } + + $address->setCollectShippingRates(true); + $address->collectShippingRates(); + + $shippingRates = $address->getGroupedAllShippingRates(); + foreach ($shippingRates as $carrierRates) { + foreach ($carrierRates as $rate) { + $output[] = $this->dataObjectConverter->toFlatArray( + $this->shippingMethodConverter->modelToDataObject($rate, $cart->getQuoteCurrencyCode()), + [], + ShippingMethodInterface::class + ); + } + } + + return $output; + } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php index 69544672bf12..96305f9713c3 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php @@ -43,6 +43,11 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $cart = $value['model']; - return $this->addressDataProvider->getCartAddresses($cart); + return $this->addressDataProvider->getCartAddresses($cart, $this->includeShippingMethods($info)); + } + + private function includeShippingMethods(ResolveInfo $info): bool + { + return $info->getFieldSelection()['available_shipping_methods'] ?? false; } } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 4c1101a5f90a..86688a360ccf 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -112,7 +112,7 @@ type CartAddress { telephone: String address_type: AdressTypeEnum selected_shipping_method: CheckoutShippingMethod - available_shipping_methods: [CheckoutShippingMethod] + available_shipping_methods: [CheckoutAvailableShippingMethod] items_weight: Float customer_notes: String cart_items: [CartItemQuantity] @@ -138,7 +138,23 @@ type CheckoutShippingMethod { label: String free_shipping: Boolean! error_message: String - # TODO: Add more complex structure for shipping rates + amount: Float! + base_amount: Float! + amount_incl_tax: Float! + base_amount_incl_tax: Float! +} + +type CheckoutAvailableShippingMethod { + carrier_code: String! + carrier_title: String! + method_code: String! + method_title: String! + error_message: String + amount: Float! + base_amount: Float! + price_excl_tax: Float! + price_incl_tax: Float! + available: Boolean! } enum AdressTypeEnum { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php index a023d37895c2..9fcaa894425c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php @@ -87,6 +87,18 @@ public function testSetNewGuestShippingAddressOnCart() city postcode telephone + available_shipping_methods { + amount + available + base_amount + carrier_code + carrier_title + error_message + method_code + method_title + price_excl_tax + price_incl_tax + } } } } @@ -99,6 +111,7 @@ public function testSetNewGuestShippingAddressOnCart() self::assertArrayHasKey('addresses', $cartResponse); $shippingAddressResponse = current($cartResponse['addresses']); $this->assertNewShippingAddressFields($shippingAddressResponse); + $this->assertAvailableShippingRates($shippingAddressResponse); } /** @@ -340,6 +353,18 @@ public function testSetNewRegisteredCustomerShippingAddressOnCart() city postcode telephone + available_shipping_methods { + amount + available + base_amount + carrier_code + carrier_title + error_message + method_code + method_title + price_excl_tax + price_incl_tax + } } } } @@ -352,6 +377,7 @@ public function testSetNewRegisteredCustomerShippingAddressOnCart() self::assertArrayHasKey('addresses', $cartResponse); $shippingAddressResponse = current($cartResponse['addresses']); $this->assertNewShippingAddressFields($shippingAddressResponse); + $this->assertAvailableShippingRates($shippingAddressResponse); } /** @@ -398,6 +424,18 @@ public function testSetSavedRegisteredCustomerShippingAddressOnCart() city postcode telephone + available_shipping_methods { + amount + available + base_amount + carrier_code + carrier_title + error_message + method_code + method_title + price_excl_tax + price_incl_tax + } } } } @@ -410,6 +448,7 @@ public function testSetSavedRegisteredCustomerShippingAddressOnCart() self::assertArrayHasKey('addresses', $cartResponse); $shippingAddressResponse = current($cartResponse['addresses']); $this->assertSavedShippingAddressFields($shippingAddressResponse); + $this->assertAvailableShippingRates($shippingAddressResponse); } /** @@ -452,6 +491,32 @@ private function assertSavedShippingAddressFields(array $shippingAddressResponse $this->assertResponseFields($shippingAddressResponse, $assertionMap); } + /** + * Verify the expected shipping method is available + * + * @param array $shippingAddressResponse + */ + private function assertAvailableShippingRates(array $shippingAddressResponse): void + { + $this->assertArrayHasKey('available_shipping_methods', $shippingAddressResponse); + $rate = current($shippingAddressResponse['available_shipping_methods']); + + $assertionMap = [ + ['response_field' => 'amount', 'expected_value' => 5], + ['response_field' => 'available', 'expected_value' => true], + ['response_field' => 'base_amount', 'expected_value' => 5], + ['response_field' => 'carrier_code', 'expected_value' => 'flatrate'], + ['response_field' => 'carrier_title', 'expected_value' => 'Flat Rate'], + ['response_field' => 'error_message', 'expected_value' => ''], + ['response_field' => 'method_code', 'expected_value' => 'flatrate'], + ['response_field' => 'method_title', 'expected_value' => 'Fixed'], + ['response_field' => 'price_incl_tax', 'expected_value' => 5], + ['response_field' => 'price_excl_tax', 'expected_value' => 5], + ]; + + $this->assertResponseFields($rate, $assertionMap); + } + /** * @param string $username * @return array