Skip to content

Commit 0a05fa3

Browse files
authored
Merge pull request magento#6931 from magento-honey-badgers/PWA-1506
[honey] PWA-1506: Billing address parameter 'same_as_shipping' cause error 'The shipping method is missing'
2 parents 6ee9c3a + 760d84c commit 0a05fa3

File tree

5 files changed

+478
-134
lines changed

5 files changed

+478
-134
lines changed

app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
1717
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1818
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
19+
use Magento\Quote\Api\Data\CartInterface;
1920
use Magento\Quote\Model\Quote\Address as QuoteAddress;
2021
use Magento\Quote\Model\Quote\AddressFactory as BaseQuoteAddressFactory;
2122

@@ -194,4 +195,21 @@ public function createBasedOnCustomerAddress(int $customerAddressId, int $custom
194195
}
195196
return $quoteAddress;
196197
}
198+
199+
/**
200+
* Create quote address based on the shipping address.
201+
*
202+
* @param CartInterface $quote
203+
* @return QuoteAddress
204+
*/
205+
public function createBasedOnShippingAddress(CartInterface $quote): QuoteAddress
206+
{
207+
$shippingAddressData = $quote->getShippingAddress()->exportCustomerAddress();
208+
209+
/** @var QuoteAddress $quoteAddress */
210+
$quoteAddress = $this->quoteAddressFactory->create();
211+
$quoteAddress->importCustomerAddressData($shippingAddressData);
212+
213+
return $quoteAddress;
214+
}
197215
}

app/code/Magento/QuoteGraphQl/Model/Cart/SetBillingAddressOnCart.php

Lines changed: 85 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -49,53 +49,58 @@ public function __construct(
4949
* @param array $billingAddressInput
5050
* @return void
5151
* @throws GraphQlAuthorizationException
52-
* @throws GraphQlInputException
53-
* @throws GraphQlNoSuchEntityException
5452
*/
5553
public function execute(ContextInterface $context, CartInterface $cart, array $billingAddressInput): void
5654
{
55+
$this->checkForInputExceptions($billingAddressInput);
56+
5757
$customerAddressId = $billingAddressInput['customer_address_id'] ?? null;
5858
$addressInput = $billingAddressInput['address'] ?? null;
59+
$useForShipping = $billingAddressInput['use_for_shipping'] ?? false;
60+
$sameAsShipping = $billingAddressInput['same_as_shipping'] ?? false;
5961

60-
if (!$customerAddressId && !isset($billingAddressInput['address']['save_in_address_book']) && $addressInput) {
62+
if (!$customerAddressId && $addressInput && !isset($addressInput['save_in_address_book'])) {
6163
$addressInput['save_in_address_book'] = true;
6264
}
6365

64-
// Need to keep this for BC of `use_for_shipping` field
65-
$sameAsShipping = isset($billingAddressInput['use_for_shipping'])
66-
? (bool)$billingAddressInput['use_for_shipping'] : false;
67-
$sameAsShipping = isset($billingAddressInput['same_as_shipping'])
68-
? (bool)$billingAddressInput['same_as_shipping'] : $sameAsShipping;
69-
70-
$this->checkForInputExceptions($billingAddressInput);
71-
72-
$addresses = $cart->getAllShippingAddresses();
73-
if ($sameAsShipping && count($addresses) > 1) {
74-
throw new GraphQlInputException(
75-
__('Using the "same_as_shipping" option with multishipping is not possible.')
66+
if ($sameAsShipping) {
67+
$this->validateCanUseShippingForBilling($cart);
68+
$billingAddress = $this->quoteAddressFactory->createBasedOnShippingAddress($cart);
69+
$useForShipping = false;
70+
} elseif ($customerAddressId) {
71+
$this->validateCanUseCustomerAddress($context);
72+
$billingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress(
73+
(int)$customerAddressId,
74+
(int)$context->getUserId()
7675
);
76+
} else {
77+
$billingAddress = $this->quoteAddressFactory->createBasedOnInputData($addressInput);
7778
}
7879

79-
$billingAddress = $this->createBillingAddress($context, $customerAddressId, $addressInput);
80+
if ($useForShipping) {
81+
$this->validateCanUseBillingForShipping($cart);
82+
}
8083

81-
$this->assignBillingAddressToCart->execute($cart, $billingAddress, $sameAsShipping);
84+
$this->validateBillingAddress($billingAddress);
85+
$this->assignBillingAddressToCart->execute($cart, $billingAddress, $useForShipping);
8286
}
8387

8488
/**
8589
* Check for the input exceptions
8690
*
87-
* @param array $billingAddressInput
91+
* @param array|null $billingAddressInput
8892
* @throws GraphQlInputException
8993
*/
9094
private function checkForInputExceptions(
9195
?array $billingAddressInput
9296
) {
9397
$customerAddressId = $billingAddressInput['customer_address_id'] ?? null;
9498
$addressInput = $billingAddressInput['address'] ?? null;
99+
$sameAsShipping = $billingAddressInput['same_as_shipping'] ?? null;
95100

96-
if (null === $customerAddressId && null === $addressInput) {
101+
if (null === $customerAddressId && null === $addressInput && empty($sameAsShipping)) {
97102
throw new GraphQlInputException(
98-
__('The billing address must contain either "customer_address_id" or "address".')
103+
__('The billing address must contain either "customer_address_id", "address", or "same_as_shipping".')
99104
);
100105
}
101106

@@ -107,41 +112,79 @@ private function checkForInputExceptions(
107112
}
108113

109114
/**
110-
* Create billing address
115+
* Validate that the quote is capable of using the shipping address as the billing address.
111116
*
112-
* @param ContextInterface $context
113-
* @param int|null $customerAddressId
114-
* @param array $addressInput
115-
* @return Address
116-
* @throws GraphQlAuthorizationException
117+
* @param CartInterface $quote
117118
* @throws GraphQlInputException
118-
* @throws GraphQlNoSuchEntityException
119119
*/
120-
private function createBillingAddress(
121-
ContextInterface $context,
122-
?int $customerAddressId,
123-
?array $addressInput
124-
): Address {
125-
if (null === $customerAddressId) {
126-
$billingAddress = $this->quoteAddressFactory->createBasedOnInputData($addressInput);
127-
} else {
128-
if (false === $context->getExtensionAttributes()->getIsCustomer()) {
129-
throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.'));
130-
}
120+
private function validateCanUseShippingForBilling(CartInterface $quote)
121+
{
122+
$shippingAddresses = $quote->getAllShippingAddresses();
131123

132-
$billingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress(
133-
(int)$customerAddressId,
134-
(int)$context->getUserId()
124+
if (count($shippingAddresses) > 1) {
125+
throw new GraphQlInputException(
126+
__('Could not use the "same_as_shipping" option, because multiple shipping addresses have been set.')
135127
);
136128
}
129+
130+
if (empty($shippingAddresses) || $shippingAddresses[0]->validate() !== true) {
131+
throw new GraphQlInputException(
132+
__('Could not use the "same_as_shipping" option, because the shipping address has not been set.')
133+
);
134+
}
135+
}
136+
137+
/**
138+
* Validate that the quote is capable of using the billing address as the shipping address.
139+
*
140+
* @param CartInterface $quote
141+
* @throws GraphQlInputException
142+
*/
143+
private function validateCanUseBillingForShipping(CartInterface $quote)
144+
{
145+
$shippingAddresses = $quote->getAllShippingAddresses();
146+
147+
if (count($shippingAddresses) > 1) {
148+
throw new GraphQlInputException(
149+
__('Could not use the "use_for_shipping" option, because multiple shipping addresses have already been set.')
150+
);
151+
}
152+
}
153+
154+
/**
155+
* Validate that the currently logged-in customer is authorized to use a customer address id as the billing address.
156+
*
157+
* @param ContextInterface $context
158+
* @throws GraphQlAuthorizationException
159+
*/
160+
private function validateCanUseCustomerAddress(ContextInterface $context)
161+
{
162+
if (false === $context->getExtensionAttributes()->getIsCustomer()) {
163+
throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.'));
164+
}
165+
}
166+
167+
/**
168+
* Validate the billing address to be set on the cart.
169+
*
170+
* @param Address $billingAddress
171+
* @return Address
172+
* @throws GraphQlInputException
173+
*/
174+
private function validateBillingAddress(Address $billingAddress)
175+
{
137176
$errors = $billingAddress->validate();
177+
138178
if (true !== $errors) {
139-
$e = new GraphQlInputException(__('Billing address errors'));
179+
$e = new GraphQlInputException(__('An error occurred while processing the billing address.'));
180+
140181
foreach ($errors as $error) {
141182
$e->addError(new GraphQlInputException($error));
142183
}
184+
143185
throw $e;
144186
}
187+
145188
return $billingAddress;
146189
}
147190
}

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ input SetBillingAddressOnCartInput {
104104
input BillingAddressInput {
105105
customer_address_id: Int
106106
address: CartAddressInput
107-
use_for_shipping: Boolean @doc(description: "Deprecated: use `same_as_shipping` field instead")
108-
same_as_shipping: Boolean @doc(description: "Set billing address same as shipping")
107+
use_for_shipping: Boolean @doc(description: "Indicates whether to additionally set the shipping address based on the provided billing address")
108+
same_as_shipping: Boolean @doc(description: "Indicates whether to set the billing address based on the existing shipping address on the cart")
109109
}
110110

111111
input CartAddressInput {

0 commit comments

Comments
 (0)