Skip to content

Commit 5e84db9

Browse files
authored
LYNX-817 Cannot return null for non-nullable field "SelectedShippingMethod.carrier_code"
1 parent 94d372b commit 5e84db9

File tree

3 files changed

+371
-49
lines changed

3 files changed

+371
-49
lines changed

app/code/Magento/QuoteGraphQl/Model/Resolver/EstimateTotals.php

+39-49
Original file line numberDiff line numberDiff line change
@@ -8,75 +8,80 @@
88
namespace Magento\QuoteGraphQl\Model\Resolver;
99

1010
use Magento\Checkout\Api\Data\TotalsInformationInterface;
11-
use Magento\Checkout\Api\Data\TotalsInformationInterfaceFactory;
1211
use Magento\Checkout\Api\TotalsInformationManagementInterface;
1312
use Magento\Framework\Exception\NoSuchEntityException;
1413
use Magento\Framework\GraphQl\Config\Element\Field;
1514
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1615
use Magento\Framework\GraphQl\Query\ResolverInterface;
1716
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1817
use Magento\Quote\Api\CartRepositoryInterface;
19-
use Magento\Quote\Api\Data\AddressInterface;
2018
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
21-
use Magento\Quote\Model\Quote\Address;
22-
use Magento\Quote\Model\Quote\AddressFactory;
19+
use Magento\QuoteGraphQl\Model\Cart\AssignShippingMethodToCart;
2320
use Magento\QuoteGraphQl\Model\ErrorMapper;
21+
use Magento\QuoteGraphQl\Model\TotalsBuilder;
22+
use Psr\Log\LoggerInterface;
2423

2524
/**
2625
* Apply address and shipping method to totals estimate and return the quote
2726
*/
2827
class EstimateTotals implements ResolverInterface
2928
{
3029
/**
30+
* EstimateTotals Constructor
31+
*
3132
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
3233
* @param CartRepositoryInterface $cartRepository
33-
* @param AddressFactory $addressFactory
3434
* @param TotalsInformationManagementInterface $totalsInformationManagement
35-
* @param TotalsInformationInterfaceFactory $totalsInformationFactory
3635
* @param ErrorMapper $errorMapper
36+
* @param AssignShippingMethodToCart $assignShippingMethodToCart
37+
* @param LoggerInterface $logger
38+
* @param TotalsBuilder $totalsBuilder
3739
*/
3840
public function __construct(
3941
private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
4042
private readonly CartRepositoryInterface $cartRepository,
41-
private readonly AddressFactory $addressFactory,
4243
private readonly TotalsInformationManagementInterface $totalsInformationManagement,
43-
private readonly TotalsInformationInterfaceFactory $totalsInformationFactory,
44-
private readonly ErrorMapper $errorMapper
44+
private readonly ErrorMapper $errorMapper,
45+
private readonly AssignShippingMethodToCart $assignShippingMethodToCart,
46+
private readonly LoggerInterface $logger,
47+
private readonly TotalsBuilder $totalsBuilder
4548
) {
4649
}
4750

4851
/**
4952
* @inheritdoc
50-
*
51-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
5253
*/
5354
public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null)
5455
{
55-
if (empty($args['input']['cart_id'])) {
56+
$input = $args['input'] ?? [];
57+
58+
if (empty($input['cart_id'])) {
5659
throw new GraphQlInputException(__('Required parameter "cart_id" is missing'));
5760
}
5861

5962
try {
60-
$cartId = $this->maskedQuoteIdToQuoteId->execute($args['input']['cart_id']);
63+
$cartId = $this->maskedQuoteIdToQuoteId->execute($input['cart_id']);
6164
} catch (NoSuchEntityException $exception) {
6265
throw new GraphQlInputException(
6366
__(
6467
'Could not find a cart with ID "%masked_id"',
6568
[
66-
'masked_id' => $args['input']['cart_id']
69+
'masked_id' => $input['cart_id']
6770
]
6871
),
6972
$exception,
7073
$this->errorMapper->getErrorMessageId('Could not find a cart with ID')
7174
);
7275
}
7376

74-
if (empty($args['input']['address']['country_code'])) {
77+
$addressData = $input['address'] ?? [];
78+
if (empty($addressData['country_code'])) {
7579
throw new GraphQlInputException(__('Required parameter "country_code" is missing'));
7680
}
7781

78-
$data = $this->getTotalsInformation($args['input']);
79-
$this->totalsInformationManagement->calculate($cartId, $data);
82+
$totalsInfo = $this->totalsBuilder->execute($addressData, $input['shipping_method'] ?? []);
83+
$this->totalsInformationManagement->calculate($cartId, $totalsInfo);
84+
$this->updateShippingMethod($totalsInfo, $cartId);
8085

8186
return [
8287
'cart' => [
@@ -86,41 +91,26 @@ public function resolve(Field $field, $context, ResolveInfo $info, ?array $value
8691
}
8792

8893
/**
89-
* Retrieve an instance of totals information based on input data
94+
* Update shipping method if provided
9095
*
91-
* @param array $input
92-
* @return TotalsInformationInterface
96+
* @param TotalsInformationInterface $totalsInfo
97+
* @param int $cartId
98+
* @return void
99+
* @throws GraphQlInputException
93100
*/
94-
private function getTotalsInformation(array $input): TotalsInformationInterface
101+
private function updateShippingMethod(TotalsInformationInterface $totalsInfo, int $cartId): void
95102
{
96-
$data = [TotalsInformationInterface::ADDRESS => $this->getAddress($input['address'])];
97-
98-
$shippingMethod = $input['shipping_method'] ?? [];
99-
100-
if (isset($shippingMethod['carrier_code']) && isset($shippingMethod['method_code'])) {
101-
$data[TotalsInformationInterface::SHIPPING_CARRIER_CODE] = $shippingMethod['carrier_code'];
102-
$data[TotalsInformationInterface::SHIPPING_METHOD_CODE] = $shippingMethod['method_code'];
103+
try {
104+
if ($totalsInfo->getShippingCarrierCode() && $totalsInfo->getShippingMethodCode()) {
105+
$this->assignShippingMethodToCart->execute(
106+
$this->cartRepository->get($cartId),
107+
$totalsInfo->getAddress(),
108+
$totalsInfo->getShippingCarrierCode(),
109+
$totalsInfo->getShippingMethodCode()
110+
);
111+
}
112+
} catch (NoSuchEntityException $e) {
113+
$this->logger->error($e->getMessage());
103114
}
104-
105-
return $this->totalsInformationFactory->create(['data' => $data]);
106-
}
107-
108-
/**
109-
* Retrieve an instance of address based on address data
110-
*
111-
* @param array $data
112-
* @return AddressInterface
113-
*/
114-
private function getAddress(array $data): AddressInterface
115-
{
116-
/** @var Address $address */
117-
$address = $this->addressFactory->create();
118-
$address->setCountryId($data['country_code']);
119-
$address->setRegion($data['region'][AddressInterface::KEY_REGION] ?? null);
120-
$address->setRegionId($data['region'][AddressInterface::KEY_REGION_ID] ?? null);
121-
$address->setRegionCode($data['region'][AddressInterface::KEY_REGION_CODE] ?? null);
122-
$address->setPostcode($data[AddressInterface::KEY_POSTCODE] ?? null);
123-
124-
return $address;
125115
}
126116
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\QuoteGraphQl\Model;
9+
10+
use Magento\Checkout\Api\Data\TotalsInformationInterface;
11+
use Magento\Checkout\Api\Data\TotalsInformationInterfaceFactory;
12+
use Magento\Quote\Api\Data\AddressInterface;
13+
use Magento\Quote\Model\Quote\AddressFactory;
14+
15+
class TotalsBuilder
16+
{
17+
/**
18+
* TotalsBuilder Constructor
19+
*
20+
* @param AddressFactory $addressFactory
21+
* @param TotalsInformationInterfaceFactory $totalsInformationFactory
22+
*/
23+
public function __construct(
24+
private readonly AddressFactory $addressFactory,
25+
private readonly TotalsInformationInterfaceFactory $totalsInformationFactory
26+
) {
27+
}
28+
29+
/**
30+
* Build totals information with address data
31+
*
32+
* @param array $addressData
33+
* @param array $shippingMethod
34+
* @return TotalsInformationInterface
35+
*/
36+
public function execute(array $addressData, array $shippingMethod): TotalsInformationInterface
37+
{
38+
$address = $this->addressFactory->create();
39+
$region = $addressData['region'] ?? [];
40+
41+
$address->setCountryId($addressData['country_code']);
42+
$address->setRegionId($region[AddressInterface::KEY_REGION_ID] ?? null);
43+
$address->setRegion($region[AddressInterface::KEY_REGION] ?? null);
44+
$address->setPostcode($addressData[AddressInterface::KEY_POSTCODE] ?? null);
45+
$address->setRegionCode($region[AddressInterface::KEY_REGION_CODE] ?? null);
46+
47+
$data = [TotalsInformationInterface::ADDRESS => $address];
48+
49+
if (isset($shippingMethod['carrier_code'], $shippingMethod['method_code'])) {
50+
$data[TotalsInformationInterface::SHIPPING_METHOD_CODE] = $shippingMethod['method_code'];
51+
$data[TotalsInformationInterface::SHIPPING_CARRIER_CODE] = $shippingMethod['carrier_code'];
52+
}
53+
54+
return $this->totalsInformationFactory->create(['data' => $data]);
55+
}
56+
}

0 commit comments

Comments
 (0)