Skip to content

Commit 66ed0d2

Browse files
committed
Merge branch 'MC-42704' of https://github.com/magento-l3/magento2ce into PR-2021-20-08
2 parents b3bafe4 + 7dc9c60 commit 66ed0d2

File tree

7 files changed

+294
-28
lines changed

7 files changed

+294
-28
lines changed

app/code/Magento/Sales/Model/AdminOrder/Create.php

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,8 @@ public function initFromOrder(\Magento\Sales\Model\Order $order)
561561

562562
$quote = $this->getQuote();
563563
if (!$quote->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) {
564-
$quote->getBillingAddress()->setCustomerAddressId(
565-
$quote->getShippingAddress()->getCustomerAddressId()
564+
$quote->getShippingAddress()->setCustomerAddressId(
565+
$quote->getBillingAddress()->getCustomerAddressId()
566566
);
567567
$this->setShippingAsBilling(1);
568568
}
@@ -679,32 +679,9 @@ public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $q
679679
$buyRequest->setQty($qty);
680680
}
681681
$productOptions = $orderItem->getProductOptions();
682-
if ($productOptions !== null && !empty($productOptions['options'])) {
683-
$formattedOptions = [];
684-
foreach ($productOptions['options'] as $option) {
685-
if (in_array($option['option_type'], ['date', 'date_time', 'time', 'file'])) {
686-
$product->setSkipCheckRequiredOption(false);
687-
if ($option['option_type'] === 'file') {
688-
try {
689-
$formattedOptions[$option['option_id']] =
690-
$this->serializer->unserialize($option['option_value']);
691-
continue;
692-
} catch (\InvalidArgumentException $exception) {
693-
//log the exception as warning
694-
$this->_logger->warning($exception);
695-
}
696-
}
697-
$formattedOptions[$option['option_id']] =
698-
$buyRequest->getDataByKey('options')[$option['option_id']];
699-
continue;
700-
}
701682

702-
$formattedOptions[$option['option_id']] = $option['option_value'];
703-
}
704-
if (!empty($formattedOptions)) {
705-
$buyRequest->setData('options', $formattedOptions);
706-
}
707-
}
683+
$this->formattedOptions($product, $buyRequest, $productOptions);
684+
708685
$item = $this->getQuote()->addProduct($product, $buyRequest);
709686
if (is_string($item)) {
710687
return $item;
@@ -2181,4 +2158,43 @@ private function isAddressesAreEqual(Order $order)
21812158

21822159
return $shippingData == $billingData;
21832160
}
2161+
2162+
/**
2163+
* Set $buyRequest with formatted product options.
2164+
*
2165+
* @param \Magento\Catalog\Model\Product $product
2166+
* @param object $buyRequest
2167+
* @param array $productOptions
2168+
* @return $this
2169+
*/
2170+
private function formattedOptions(\Magento\Catalog\Model\Product $product, $buyRequest, $productOptions)
2171+
{
2172+
if ($productOptions !== null && !empty($productOptions['options'])) {
2173+
$formattedOptions = [];
2174+
foreach ($productOptions['options'] as $option) {
2175+
if (in_array($option['option_type'], ['date', 'date_time', 'time', 'file'])) {
2176+
$product->setSkipCheckRequiredOption(false);
2177+
if ($option['option_type'] === 'file') {
2178+
try {
2179+
$formattedOptions[$option['option_id']] =
2180+
$this->serializer->unserialize($option['option_value']);
2181+
continue;
2182+
} catch (\InvalidArgumentException $exception) {
2183+
//log the exception as warning
2184+
$this->_logger->warning($exception);
2185+
}
2186+
}
2187+
$formattedOptions[$option['option_id']] =
2188+
$buyRequest->getDataByKey('options')[$option['option_id']];
2189+
continue;
2190+
}
2191+
2192+
$formattedOptions[$option['option_id']] = $option['option_value'];
2193+
}
2194+
if (!empty($formattedOptions)) {
2195+
$buyRequest->setData('options', $formattedOptions);
2196+
}
2197+
}
2198+
return $this;
2199+
}
21842200
}

app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,14 @@ define([
274274
data['reset_shipping'] = true;
275275
}
276276

277+
if (name !== 'customer_address_id' && this.selectAddressEvent === false) {
278+
if (this.shippingAsBilling) {
279+
$('order-shipping_address_customer_address_id').value = '';
280+
}
281+
282+
$('order-' + type + '_address_customer_address_id').value = '';
283+
}
284+
277285
data['order[' + type + '_address][customer_address_id]'] = null;
278286
data['shipping_as_billing'] = +this.shippingAsBilling;
279287

@@ -418,6 +426,9 @@ define([
418426
data = data.toObject();
419427
data['shipping_as_billing'] = flag ? 1 : 0;
420428
data['reset_shipping'] = 1;
429+
// set customer_address_id to null for shipping address in order to treat it as new from backend
430+
// Checkbox(Same As Billing Address) uncheck event
431+
data['order[shipping_address][customer_address_id]'] = null;
421432
this.loadArea(areasToLoad, true, data);
422433
},
423434

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* this fixture update customer_address `input_validation` to `alphanum-with-spaces` for `street` field.
4+
*
5+
* Copyright © Magento, Inc. All rights reserved.
6+
* See COPYING.txt for license details.
7+
*/
8+
$attributeCode = 'street';
9+
$entityType = \Magento\Customer\Model\Metadata\AddressMetadata::ENTITY_TYPE_ADDRESS;
10+
11+
//@codingStandardsIgnoreFile
12+
/** @var \Magento\Customer\Model\Attribute $model */
13+
$model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Attribute::class);
14+
$model->loadByCode($entityType, $attributeCode);
15+
16+
$validationRules = array_replace_recursive($model->getValidationRules(),['input_validation'=>'alphanum-with-spaces']);
17+
$model->setValidationRules($validationRules);
18+
19+
$model->save();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
/** @var \Magento\Framework\Registry $registry */
9+
$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
10+
$registry->unregister('isSecureArea');
11+
$registry->register('isSecureArea', true);
12+
13+
$attributeCode = 'street';
14+
$entityType = \Magento\Customer\Model\Metadata\AddressMetadata::ENTITY_TYPE_ADDRESS;
15+
//@codingStandardsIgnoreFile
16+
/** @var \Magento\Customer\Model\Attribute $model */
17+
$model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Attribute::class);
18+
$model->loadByCode($entityType, $attributeCode);
19+
$validationRules = $model->getValidationRules();
20+
21+
try {
22+
if(!empty($validationRules['input_validation'])){
23+
if(in_array('alphanum-with-spaces', $validationRules)){
24+
unset($validationRules['input_validation']);
25+
}
26+
}
27+
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
28+
// Specified validation already rolled back
29+
}
30+
31+
$model->setValidationRules($validationRules);
32+
$model->save();
33+
34+
$registry->unregister('isSecureArea');
35+
$registry->register('isSecureArea', false);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
/**
3+
* Customer default address fixture with entity_id = 2,
4+
* this fixture also inherit other fixtures for creating simple product, a customer with entity_id=1
5+
* and default customer address.
6+
* It also call a new fixture to update customer address `input_validation` rule for `street` field.
7+
*
8+
* Copyright © Magento, Inc. All rights reserved.
9+
* See COPYING.txt for license details.
10+
*/
11+
use Magento\Customer\Model\CustomerRegistry;
12+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
13+
14+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php');
15+
Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer.php');
16+
Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_address.php');
17+
18+
/** @var \Magento\Customer\Model\Address $customerAddress */
19+
$customerAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
20+
->create(\Magento\Customer\Model\Address::class);
21+
/** @var CustomerRegistry $customerRegistry */
22+
$customerRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
23+
->get(CustomerRegistry::class);
24+
$customerAddress->isObjectNew(true);
25+
$customerAddress->setData(
26+
[
27+
'entity_id' => 2,
28+
'attribute_set_id' => 2,
29+
'telephone' => 3234676,
30+
'postcode' => 47676,
31+
'country_id' => 'US',
32+
'city' => 'CityX',
33+
'street' => ['Black str 48'],
34+
'lastname' => 'Smith',
35+
'firstname' => 'John',
36+
'parent_id' => 1,
37+
'region_id' => 1,
38+
]
39+
)->setCustomerId(
40+
1
41+
);
42+
43+
$customerAddress->save();
44+
$customerRegistry->remove($customerAddress->getCustomerId());
45+
46+
Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_address_attribute_update.php');
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
9+
use Magento\Customer\Api\AddressRepositoryInterface;
10+
use Magento\Framework\Exception\NoSuchEntityException;
11+
use Magento\Framework\Registry;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
14+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php');
15+
Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_rollback.php');
16+
17+
$objectManager = Bootstrap::getObjectManager();
18+
/** @var Registry $registry */
19+
$registry = $objectManager->get(Registry::class);
20+
21+
$registry->unregister('isSecureArea');
22+
$registry->register('isSecureArea', true);
23+
24+
/** @var AddressRepositoryInterface $addressRepository */
25+
$addressRepository = $objectManager->get(AddressRepositoryInterface::class);
26+
27+
foreach ([1, 2] as $addressId) {
28+
try {
29+
$addressRepository->deleteById($addressId);
30+
} catch (NoSuchEntityException $e) {
31+
/**
32+
* Tests which are wrapped with MySQL transaction clear all data by transaction rollback.
33+
*/
34+
}
35+
}
36+
37+
$registry->unregister('isSecureArea');
38+
$registry->register('isSecureArea', false);
39+
40+
Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_address_attribute_update_rollback.php');

dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,9 @@ private function preparePreconditionsForCreateOrder(
732732
/** Unset fake IDs for default billing and shipping customer addresses */
733733
/** @var Customer $customer */
734734
$customer = $this->objectManager->create(Customer::class);
735-
$customer->load($customerIdFromFixture)->setDefaultBilling(null)->setDefaultShipping(null)->save();
735+
if (empty($orderData['checkForDefaultStreet'])) {
736+
$customer->load($customerIdFromFixture)->setDefaultBilling(null)->setDefaultShipping(null)->save();
737+
}
736738
} else {
737739
/**
738740
* Customer ID must be set to session to pass \Magento\Sales\Model\AdminOrder\Create::_validate()
@@ -840,4 +842,101 @@ private function getValidAddressData()
840842
'vat_id' => ''
841843
];
842844
}
845+
846+
/**
847+
* @magentoDataFixture Magento/Customer/_files/customer.php
848+
* @magentoDataFixture Magento/Customer/_files/customer_address_attribute_update.php
849+
* @magentoDbIsolation disabled
850+
*/
851+
public function testSetBillingAddressStreetValidationErrors()
852+
{
853+
$customerIdFromFixture = 1;
854+
/** @var SessionQuote $session */
855+
$session = $this->objectManager->create(SessionQuote::class);
856+
$session->setCustomerId($customerIdFromFixture);
857+
$invalidAddressData = array_merge($this->getValidAddressData(), ['street' => [0 => 'Whit`e', 1 => 'Lane']]);
858+
/**
859+
* Note that validation errors are collected during setBillingAddress() call in the internal class variable,
860+
* but they are not set to message manager at this step.
861+
* They are set to message manager only during createOrder() call.
862+
*/
863+
$this->model->setIsValidate(true)->setBillingAddress($invalidAddressData);
864+
try {
865+
$this->model->createOrder();
866+
$this->fail('Validation errors are expected to lead to exception during createOrder() call.');
867+
} catch (\Magento\Framework\Exception\LocalizedException $e) {
868+
/** createOrder is expected to throw exception with empty message when validation error occurs */
869+
}
870+
$errorMessages = [];
871+
/** @var $validationError \Magento\Framework\Message\Error */
872+
foreach ($this->messageManager->getMessages()->getItems() as $validationError) {
873+
$errorMessages[] = $validationError->getText();
874+
}
875+
self::assertTrue(
876+
in_array(
877+
'Billing Address: "Street Address" contains non-alphabetic or non-numeric characters.',
878+
$errorMessages
879+
),
880+
'Expected validation message is absent.'
881+
);
882+
self::assertTrue(
883+
in_array(
884+
'Shipping Address: "Street Address" contains non-alphabetic or non-numeric characters.',
885+
$errorMessages
886+
),
887+
'Expected validation message is absent.'
888+
);
889+
}
890+
891+
/**
892+
* If the current street address for a customer differs with the default one (saved in customer address book)
893+
* then the updated validation rule (`input_validation`) should applied on current one while placing a new order.
894+
*
895+
* @magentoDataFixture Magento/Customer/_files/customer_address_street_attribute.php
896+
* @magentoDbIsolation disabled
897+
* @magentoAppIsolation enabled
898+
*/
899+
public function testCreateOrderExistingCustomerWhenDefaultAddressDiffersWithNew()
900+
{
901+
$productIdFromFixture = 1;
902+
$customerIdFromFixture = 1;
903+
$customerEmailFromFixture = 'customer@example.com';
904+
$shippingMethod = 'freeshipping_freeshipping';
905+
$paymentMethod = 'checkmo';
906+
$shippingAddressAsBilling = 1;
907+
$invalidAddressData = array_merge($this->getValidAddressData(), ['street' => [0 => 'White', 1 => 'Lane']]);
908+
909+
// Any change in default customer address should be treated as new address by setting up
910+
// `customer_address_id` to `null` in billing and shipping addresses.
911+
$address = array_merge($invalidAddressData, ['save_in_address_book' => '1', 'customer_address_id' => null]);
912+
$orderData = [
913+
'currency' => 'USD',
914+
'billing_address' => $address,
915+
'shipping_method' => $shippingMethod,
916+
'comment' => ['customer_note' => ''],
917+
'send_confirmation' => false,
918+
'checkForDefaultStreet' => true,
919+
];
920+
$paymentData = ['method' => $paymentMethod];
921+
922+
$this->preparePreconditionsForCreateOrder(
923+
$productIdFromFixture,
924+
$customerEmailFromFixture,
925+
$shippingMethod,
926+
$shippingAddressAsBilling,
927+
$paymentData,
928+
$orderData,
929+
$paymentMethod,
930+
$customerIdFromFixture
931+
);
932+
$this->model->setBillingAddress($orderData['billing_address']);
933+
try {
934+
$order =$this->model->createOrder();
935+
$orderData = $order->getData();
936+
self::assertNotEmpty($orderData['increment_id'], 'Order increment ID is empty.');
937+
} catch (\Magento\Framework\Exception\LocalizedException $e) {
938+
/** createOrder is expected to throw exception with empty message when validation error occurs */
939+
self::assertEquals('Validation is failed.', $e->getRawMessage());
940+
}
941+
}
843942
}

0 commit comments

Comments
 (0)