Перенос заказов и клиентов со старого сайта - порядок и сверка
Переносим клиентов и заказы со старого сайта так, чтобы покупатель нашёл свою историю, а бухгалтерия сошлась с прежними числами.
Механика
Переносят со старого сайта далеко не всё подряд. История заказов за десять лет чаще всего никому не нужна: покупателю интересны последние год-два, бухгалтерии - закрытый период, а маркетингу - активные клиенты. Решение о глубине переноса принимает магазин, и принимает его до разработки, потому что от него зависит и время работы, и объём базы.
Главный механизм всего переноса - это внешние коды старой системы. У каждого клиента и каждого заказа остаётся поле с идентификатором из старой системы. По нему связывают заказы с клиентами, повторный запуск не создаёт дублей, а спорные случаи разбираются сверкой, а не догадками.
Порядок шагов переноса жёсткий и менять его не стоит. Сначала клиенты, потом заказы, потом их состав и свойства: заказ без клиента создать можно, но связать потом сложнее, чем сделать сразу правильно. Каждый шаг должен переживать повторный запуск: перенос почти никогда не проходит с первого раза.
Часть данных не переносится вовсе по самому своему устройству. Пароли клиентов - это отпечатки, пригодные только для старой системы; история изменений заказа, чеки и платежи живут в своих подсистемах и переносятся отдельно, если переносятся вообще.
Наконец, отдельная история - это дата создания заказа и его номер. Платформа сама ставит дату создания заказа и его номер, поэтому старые значения либо кладут в отдельные поля, либо правят запросом после сохранения - и решают это заранее, а не в середине переноса.
Перенос почти всегда делают дважды: сначала пробный на копии, чтобы измерить время и найти неожиданности, потом боевой в час, согласованный с магазином. Между ними проходит неделя, за которую в старой системе появляются новые заказы, и поэтому боевой запуск обязан уметь донести только то, чего ещё нет.
Шаги
- Договориться о глубине переноса и о том, что именно из данных переносится.
- Завести поля для внешних кодов и у клиентов, и у самих заказов.
- Перенести клиентов порциями, отсекая дубли по почте и телефону.
- Перенести заказы вместе с составом, свойствами и сопоставленными статусами.
- Поправить даты и номера заказов, если старые значения важны самому магазину.
- Сверить числа, суммы и выборочные заказы до запуска сайта.
Код
Заводим внешние коды:
// у пользователя - пользовательское поле, у заказа - штатное поле связи$order->setField('XML_ID', 'old-' . $row['order_id']);$user = new \CUser();$user->Update($userId, ['UF_OLD_ID' => $row['client_id']]); // поле сущности USER// по этим значениям повторный запуск находит уже перенесённоеУ каждой записи остаётся код из старой системы. Это единственный способ повторно запустить перенос, не удваивая данные, и единственный способ потом объяснить, что откуда взялось.
Переносим клиентов порциями:
foreach (array_chunk($clients, 200) as $chunk) { foreach ($chunk as $row) { $exists = CUser::GetList('ID', 'ASC', ['UF_OLD_ID' => $row['id']])->Fetch(); if ($exists) { continue; } // уже перенесён $user = new CUser(); $user->Add(['EMAIL' => $row['email'], 'LOGIN' => $row['email'], 'NAME' => $row['name'], 'UF_OLD_ID' => $row['id'], 'PASSWORD' => randString(20), 'CONFIRM_PASSWORD' => null]); }}Клиентов переносят порциями и с проверкой на уже перенесённых. Пароли при этом задают случайные: старые отпечатки не годятся, а покупатель восстановит пароль обычным письмом.
Переносим заказ с составом:
$order = \Bitrix\Sale\Order::create(SITE_ID, $userId);$basket = \Bitrix\Sale\Basket::create(SITE_ID);foreach ($row['items'] as $line) { $item = $basket->createItem('catalog', $line['product_id']); $item->setFields(['QUANTITY' => $line['qty'], 'CURRENCY' => 'RUB', 'PRICE' => $line['price'], 'CUSTOM_PRICE' => 'Y']); // цена как была тогда}$order->setBasket($basket);$order->setField('XML_ID', 'old-' . $row['id']);$order->save();Цену позиции переносят как есть, а не пересчитывают по текущему каталогу. Товар мог подорожать, скидка - уйти, а заказ обязан остаться таким, каким его видел покупатель три года назад.
Сопоставляем статусы:
$map = ['new' => 'N', 'paid' => 'P', 'sent' => 'F', 'cancelled' => 'CANCELED'];$status = $map[$row['status']] ?? 'N';if (!isset($map[$row['status']])) { AddMessage2Log('неизвестный статус: ' . $row['status'], 'vendor.shop');}// неизвестный статус не молчит, а попадает в журнал и в отчёт о переносеСтатусы старой системы почти никогда не совпадают с новыми. Таблицу соответствия согласуют с магазином, а всё, что в неё не попало, отправляют в журнал: молчаливое приведение к «новому» портит отчёты.
Правим даты после сохранения:
$c = \Bitrix\Main\Application::getConnection();$c->queryExecute("UPDATE b_sale_order SET DATE_INSERT = '" . $c->getSqlHelper()->forSql($row['date']) . "' WHERE XML_ID = '" . $c->getSqlHelper()->forSql('old-' . $row['id']) . "'");// платформа ставит дату сама, поэтому старую возвращают отдельным шагомДату создания заказа платформа ставит сама, при его сохранении. Если старая дата важна для отчётов и для личного кабинета, её возвращают отдельным шагом после сохранения, а не пытаются подсунуть при создании.
Сверяем результат:
printf("клиентов: было %d, стало %d\n", $oldClients, $newClients);printf("заказов: было %d, стало %d, сумма %s против %s\n", $oldOrders, $newOrders, $oldSum, $newSum);// расхождение в одну запись разбирают так же внимательно, как в тысячуЧисла и суммы сверяют до запуска, а не после жалоб. Расхождение в сумме почти всегда означает потерянные позиции или неверно перенесённую цену, и найти это позже будет некому.
Ограничения
Пароли клиентов со старого сайта не переносятся вовсе. Отпечатки старой системы платформе не подходят, поэтому всем перенесённым клиентам пароль восстанавливают письмом, и об этом покупателей предупреждают заранее, а не постфактум.
История изменений заказа так и остаётся в старой системе магазина целиком. Платформа умеет вести свою историю, но заполнить её задним числом нельзя, и вопрос «кто менял статус в прошлом году» отвечается только выгрузкой из старой базы.
Платежи и фискальные чеки живут при этом своей совсем отдельной жизнью. Перенесённый заказ можно пометить оплаченным, но фискальные документы за прошлые периоды переносить нельзя и не нужно: за них отвечает прежняя система.
Отдельного внимания требуют заказы, оформленные без регистрации. У них нет клиента, к которому можно привязать историю, и решение об этом принимают заранее: либо заводить учётные записи по контактам, либо переносить такие заказы без владельца и мириться с тем, что в личном кабинете они не появятся.
Персональные данные переносят ровно в том объёме, на который есть согласие. Полная выгрузка клиентской базы «на всякий случай» - это не техническое решение, и согласовывать его нужно не с разработчиком.
Типичные проблемы
После повторного запуска заказы задвоились.
Внешний код старой системы нигде не сохраняется и не проверяется. Именно по нему повторный запуск переноса и находит уже перенесённые записи.
Суммы заказов не сошлись со старой системой.
Цены пересчитаны по текущему каталогу вместо переноса как есть. В перенесённом заказе цену позиции фиксируют явным признаком.
Все заказы получили сегодняшнюю дату.
Дату создания ставит платформа, а старая нигде не восстановлена. Её возвращают отдельным шагом уже после сохранения заказа.
Часть заказов оказалась в статусе «новый».
Статусы старой системы не были сопоставлены и приведены к значению по умолчанию. Все несопоставленные значения статусов обязательно пишут в журнал переноса.
Клиенты не могут войти на новый сайт.
Ожидалось, что пароли переедут вместе с самими учётными записями этих клиентов. Пароли восстанавливают обычным письмом, и об этом предупреждают самих клиентов заранее.
Частые вопросы
Насколько глубоко переносить историю?
Обычно два-три года: дальше данными почти не пользуются. Решает это магазин, а не разработчик.
Переносить ли брошенные корзины?
Нет: они устареют раньше, чем понадобятся. Переносят заказы и клиентов.
Как быть с товарами, которых больше нет?
Заказ переносят с названием и ценой позиции, даже если товара в каталоге нет. Иначе история теряет смысл.
Сколько времени занимает перенос?
Считается на копии: сто тысяч заказов идут часами. Это выясняют до назначения даты запуска.
Что делать с расхождением в пару заказов?
Разбирать: обычно это потерянные позиции или неизвестный статус. Пара заказов сегодня - это сотня при повторе.
Смежное
- Заказы - оглавление подтемы
- Заказ из кода: чтение, поиск по номеру, изменение состава - как заказ создаётся обычным путём
- Импорт пользователей из файла: связь, пароли, группы - половина задачи про клиентов
- Статусы заказов: смена из кода, события и сопоставление с 1С - куда сопоставлять статусы
- Каталог и продажи - устройство магазина целиком