Skip to content

Commit e21fb1d

Browse files
committed
Merge remote-tracking branch 'origin/MC-30323' into 2.4-develop-pr8
2 parents 063dae8 + 8abeb71 commit e21fb1d

File tree

4 files changed

+172
-31
lines changed

4 files changed

+172
-31
lines changed

app/code/Magento/CustomerImportExport/Model/Import/Customer.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ protected function _prepareDataForUpdate(array $rowData)
408408
$createdAt = (new \DateTime())->setTimestamp(strtotime($rowData['created_at']));
409409
}
410410

411-
$emailInLowercase = strtolower($rowData[self::COLUMN_EMAIL]);
411+
$emailInLowercase = strtolower(trim($rowData[self::COLUMN_EMAIL]));
412412
$newCustomer = false;
413413
$entityId = $this->_getCustomerId($emailInLowercase, $rowData[self::COLUMN_WEBSITE]);
414414
if (!$entityId) {
@@ -478,6 +478,8 @@ protected function _prepareDataForUpdate(array $rowData)
478478
$entityRow['updated_at'] = $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
479479
if (!empty($rowData[self::COLUMN_STORE])) {
480480
$entityRow['store_id'] = $this->_storeCodeToId[$rowData[self::COLUMN_STORE]];
481+
} else {
482+
$entityRow['store_id'] = $this->getCustomerStoreId($emailInLowercase, $rowData[self::COLUMN_WEBSITE]);
481483
}
482484
$entitiesToUpdate[] = $entityRow;
483485
}
@@ -666,4 +668,22 @@ public function getValidColumnNames()
666668
)
667669
);
668670
}
671+
672+
/**
673+
* Get customer store ID by email and website ID.
674+
*
675+
* @param string $email
676+
* @param string $websiteCode
677+
* @return bool|int
678+
*/
679+
private function getCustomerStoreId(string $email, string $websiteCode)
680+
{
681+
$websiteId = (int) $this->getWebsiteId($websiteCode);
682+
$storeId = $this->getCustomerStorage()->getCustomerStoreId($email, $websiteId);
683+
if ($storeId === null || $storeId === false) {
684+
$defaultStore = $this->_storeManager->getWebsite($websiteId)->getDefaultStore();
685+
$storeId = $defaultStore ? $defaultStore->getId() : \Magento\Store\Model\Store::DEFAULT_STORE_ID;
686+
}
687+
return $storeId;
688+
}
669689
}

app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
*/
66
namespace Magento\CustomerImportExport\Model\ResourceModel\Import\Customer;
77

8-
use Magento\CustomerImportExport\Test\Unit\Model\Import\CustomerCompositeTest;
8+
use Magento\Customer\Model\ResourceModel\Customer\Collection as CustomerCollection;
9+
use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory;
910
use Magento\Framework\DataObject;
1011
use Magento\Framework\DB\Select;
11-
use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory;
12-
use Magento\Customer\Model\ResourceModel\Customer\Collection as CustomerCollection;
13-
use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory;
1412
use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIterator;
13+
use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory;
1514

1615
/**
1716
* Storage to check existing customers.
@@ -56,6 +55,20 @@ class Storage
5655
*/
5756
public $_customerCollection;
5857

58+
/**
59+
* Existing customers store IDs. In form of:
60+
*
61+
* [customer email] => array(
62+
* [website id 1] => store id 1,
63+
* [website id 2] => store id 2,
64+
* ... => ... ,
65+
* [website id n] => store id n,
66+
* )
67+
*
68+
* @var array
69+
*/
70+
private $customerStoreIds = [];
71+
5972
/**
6073
* @param CustomerCollectionFactory $collectionFactory
6174
* @param CollectionByPagesIteratorFactory $colIteratorFactory
@@ -91,7 +104,7 @@ private function prepareCollection(array $customerIdentifiers): CustomerCollecti
91104
$select = $collection->getSelect();
92105
$customerTableId = array_keys($select->getPart(Select::FROM))[0];
93106
$select->where(
94-
$customerTableId .'.email in (?)',
107+
$customerTableId . '.email in (?)',
95108
array_map(
96109
function (array $customer) {
97110
return $customer['email'];
@@ -127,11 +140,15 @@ private function loadCustomersData(array $customerIdentifiers)
127140
*/
128141
public function addCustomerByArray(array $customer): Storage
129142
{
130-
$email = strtolower(trim($customer['email']));
143+
$email = mb_strtolower(trim($customer['email']));
131144
if (!isset($this->_customerIds[$email])) {
132145
$this->_customerIds[$email] = [];
133146
}
147+
if (!isset($this->customerStoreIds[$email])) {
148+
$this->customerStoreIds[$email] = [];
149+
}
134150
$this->_customerIds[$email][$customer['website_id']] = $customer['entity_id'];
151+
$this->customerStoreIds[$email][$customer['website_id']] = $customer['store_id'] ?? null;
135152

136153
return $this;
137154
}
@@ -164,11 +181,7 @@ public function addCustomer(DataObject $customer): Storage
164181
public function getCustomerId(string $email, int $websiteId)
165182
{
166183
$email = mb_strtolower($email);
167-
//Trying to load the customer.
168-
if (!array_key_exists($email, $this->_customerIds) || !array_key_exists($websiteId, $this->_customerIds[$email])
169-
) {
170-
$this->loadCustomersData([['email' => $email, 'website_id' => $websiteId]]);
171-
}
184+
$this->loadCustomerData($email, $websiteId);
172185

173186
if (isset($this->_customerIds[$email][$websiteId])) {
174187
return $this->_customerIds[$email][$websiteId];
@@ -177,6 +190,25 @@ public function getCustomerId(string $email, int $websiteId)
177190
return false;
178191
}
179192

193+
/**
194+
* Find customer store ID for unique pair of email and website ID.
195+
*
196+
* @param string $email
197+
* @param int $websiteId
198+
* @return bool|int
199+
*/
200+
public function getCustomerStoreId(string $email, int $websiteId)
201+
{
202+
$email = mb_strtolower($email);
203+
$this->loadCustomerData($email, $websiteId);
204+
205+
if (isset($this->customerStoreIds[$email][$websiteId])) {
206+
return $this->customerStoreIds[$email][$websiteId];
207+
}
208+
209+
return false;
210+
}
211+
180212
/**
181213
* Pre-load customers for future checks.
182214
*
@@ -189,21 +221,21 @@ public function prepareCustomers(array $customersToFind): void
189221
foreach ($customersToFind as $customerToFind) {
190222
$email = mb_strtolower($customerToFind['email']);
191223
$websiteId = $customerToFind['website_id'];
192-
if (!array_key_exists($email, $this->_customerIds)
193-
|| !array_key_exists($websiteId, $this->_customerIds[$email])
194-
) {
224+
if (!$this->isLoadedCustomerData($email, $websiteId)) {
195225
//Only looking for customers we don't already have ID for.
196226
//We need unique identifiers.
197-
$uniqueKey = $email .'_' .$websiteId;
227+
$uniqueKey = $email . '_' . $websiteId;
198228
$identifiers[$uniqueKey] = [
199229
'email' => $email,
200230
'website_id' => $websiteId,
201231
];
202232
//Recording that we've searched for a customer.
203233
if (!array_key_exists($email, $this->_customerIds)) {
204234
$this->_customerIds[$email] = [];
235+
$this->customerStoreIds[$email] = [];
205236
}
206237
$this->_customerIds[$email][$websiteId] = null;
238+
$this->customerStoreIds[$email][$websiteId] = null;
207239
}
208240
}
209241
if (!$identifiers) {
@@ -213,4 +245,31 @@ public function prepareCustomers(array $customersToFind): void
213245
//Loading customers data.
214246
$this->loadCustomersData($identifiers);
215247
}
248+
249+
/**
250+
* Load customer data if it's not loaded.
251+
*
252+
* @param string $email
253+
* @param int $websiteId
254+
* @return void
255+
*/
256+
private function loadCustomerData(string $email, int $websiteId): void
257+
{
258+
if (!$this->isLoadedCustomerData($email, $websiteId)) {
259+
$this->loadCustomersData([['email' => $email, 'website_id' => $websiteId]]);
260+
}
261+
}
262+
263+
/**
264+
* Check if customer data is loaded
265+
*
266+
* @param string $email
267+
* @param int $websiteId
268+
* @return bool
269+
*/
270+
private function isLoadedCustomerData(string $email, int $websiteId): bool
271+
{
272+
return array_key_exists($email, $this->_customerIds)
273+
&& array_key_exists($websiteId, $this->_customerIds[$email]);
274+
}
216275
}

dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerTest.php

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66

77
namespace Magento\CustomerImportExport\Model\Import;
88

9+
use Magento\Customer\Api\CustomerRepositoryInterface;
10+
use Magento\Customer\Api\Data\CustomerInterface;
911
use Magento\Framework\App\Filesystem\DirectoryList;
12+
use Magento\Framework\Exception\NoSuchEntityException;
1013
use Magento\ImportExport\Model\Import;
1114

1215
/**
1316
* Test for class \Magento\CustomerImportExport\Model\Import\Customer which covers validation logic
17+
*
18+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
19+
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
1420
*/
1521
class CustomerTest extends \PHPUnit\Framework\TestCase
1622
{
@@ -82,6 +88,8 @@ public function testImportData()
8288
$this->directoryWrite
8389
);
8490

91+
$existingCustomer = $this->getCustomer('CharlesTAlston@teleworm.us', 1);
92+
8593
/** @var $customersCollection \Magento\Customer\Model\ResourceModel\Customer\Collection */
8694
$customersCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
8795
\Magento\Customer\Model\ResourceModel\Customer\Collection::class
@@ -107,13 +115,6 @@ public function testImportData()
107115

108116
$this->assertEquals($expectAddedCustomers, $addedCustomers, 'Added unexpected amount of customers');
109117

110-
/** @var $objectManager \Magento\TestFramework\ObjectManager */
111-
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
112-
113-
$existingCustomer = $objectManager->get(
114-
\Magento\Framework\Registry::class
115-
)->registry('_fixture/Magento_ImportExport_Customer');
116-
117118
$updatedCustomer = $customers[$existingCustomer->getId()];
118119

119120
$this->assertNotEquals(
@@ -154,6 +155,12 @@ public function testImportDataWithOneAdditionalColumn(): void
154155
$this->directoryWrite
155156
);
156157

158+
$existingCustomer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
159+
\Magento\Customer\Model\Customer::class
160+
);
161+
$existingCustomer->setWebsiteId(1);
162+
$existingCustomer = $existingCustomer->loadByEmail('CharlesTAlston@teleworm.us');
163+
157164
/** @var $customersCollection \Magento\Customer\Model\ResourceModel\Customer\Collection */
158165
$customersCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
159166
\Magento\Customer\Model\ResourceModel\Customer\Collection::class
@@ -171,12 +178,6 @@ public function testImportDataWithOneAdditionalColumn(): void
171178

172179
$customers = $customersCollection->getItems();
173180

174-
/** @var $objectManager \Magento\TestFramework\ObjectManager */
175-
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
176-
177-
$existingCustomer = $objectManager->get(\Magento\Framework\Registry::class)
178-
->registry('_fixture/Magento_ImportExport_Customer');
179-
180181
$updatedCustomer = $customers[$existingCustomer->getId()];
181182

182183
$this->assertNotEquals(
@@ -210,8 +211,8 @@ public function testImportDataWithOneAdditionalColumn(): void
210211
);
211212

212213
$this->assertEquals(
213-
$existingCustomer->getCustomerGroupId(),
214-
$updatedCustomer->getCustomerGroupId(),
214+
$existingCustomer->getGroupId(),
215+
$updatedCustomer->getGroupId(),
215216
'Customer group must not be changed'
216217
);
217218
}
@@ -352,4 +353,61 @@ public function testValidateEmailForDeleteBehavior()
352353
$this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_CUSTOMER_NOT_FOUND])
353354
);
354355
}
356+
357+
/**
358+
* Test import existing customers
359+
*
360+
* @magentoDataFixture Magento/Customer/_files/import_export/customers.php
361+
* @return void
362+
*/
363+
public function testUpdateExistingCustomers(): void
364+
{
365+
$this->doImport(__DIR__ . '/_files/customers_to_update.csv', Import::BEHAVIOR_ADD_UPDATE);
366+
$customer = $this->getCustomer('customer@example.com', 1);
367+
$this->assertEquals('Firstname-updated', $customer->getFirstname());
368+
$this->assertEquals('Lastname-updated', $customer->getLastname());
369+
$this->assertEquals(1, $customer->getStoreId());
370+
$customer = $this->getCustomer('julie.worrell@example.com', 1);
371+
$this->assertEquals('Julie-updated', $customer->getFirstname());
372+
$this->assertEquals('Worrell-updated', $customer->getLastname());
373+
$this->assertEquals(1, $customer->getStoreId());
374+
$customer = $this->getCustomer('david.lamar@example.com', 1);
375+
$this->assertEquals('David-updated', $customer->getFirstname());
376+
$this->assertEquals('Lamar-updated', $customer->getLastname());
377+
$this->assertEquals(1, $customer->getStoreId());
378+
}
379+
380+
/**
381+
* Gets customer entity.
382+
*
383+
* @param string $email
384+
* @param int $websiteId
385+
* @return CustomerInterface
386+
* @throws NoSuchEntityException
387+
* @throws \Magento\Framework\Exception\LocalizedException
388+
*/
389+
private function getCustomer(string $email, int $websiteId): CustomerInterface
390+
{
391+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
392+
/** @var CustomerRepositoryInterface $repository */
393+
$repository = $objectManager->get(CustomerRepositoryInterface::class);
394+
return $repository->get($email, $websiteId);
395+
}
396+
397+
/**
398+
* Import using given file and behavior
399+
*
400+
* @param string $file
401+
* @param string $behavior
402+
*/
403+
private function doImport(string $file, string $behavior): void
404+
{
405+
$source = new \Magento\ImportExport\Model\Import\Source\Csv($file, $this->directoryWrite);
406+
$this->_model
407+
->setParameters(['behavior' => $behavior])
408+
->setSource($source)
409+
->validateData()
410+
->hasToBeTerminated();
411+
$this->_model->importData();
412+
}
355413
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
email,_website,_store,confirmation,created_at,created_in,default_billing,default_shipping,disable_auto_group_change,dob,firstname,gender,group_id,lastname,middlename,password_hash,prefix,rp_token,rp_token_created_at,store_id,suffix,taxvat,website_id,password
2+
customer@example.com,base,"default",,5/6/2012 16:15,Admin,"1","1",0,,"Firstname-updated",Male,1,"Lastname-updated",T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,"1",
3+
julie.worrell@example.com,base,"",,5/6/2012 16:19,Admin,"1","1",0,,"Julie-updated",Female,1,"Worrell-updated",T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,"1",
4+
david.lamar@example.com,base,"",,5/6/2012 16:25,Admin,"1","1",0,,"David-updated",Male,1,"Lamar-updated",T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,"1",

0 commit comments

Comments
 (0)