Чистка учётных записей - неактивные, дубли, обезличивание
Убираем мусор из базы пользователей: неактивные записи, дубли, обезличивание тех, у кого есть заказы, и аккуратное удаление остальных.
Что нужно знать заранее
Удаление записи с заказами ломает историю продаж. Заказ теряет покупателя, отчёты за прошлые периоды меняются, а бухгалтерия задаёт вопросы, на которые никто уже не ответит.
Поэтому чистка учётных записей на сайте всегда делится на две принципиально разные части. Записи без следов деятельности удаляют, записи с заказами обезличивают: имя, почта и телефон заменяются, а связи с документами остаются.
Обезличивание - не то же самое, что удаление по запросу человека. Второе выполняется по обращению субъекта данных, и его состав согласуют с юристом, а не придумывают в коде.
Шаги
- Договориться с заказчиком, что именно считается мусором: срок, входы, заказы, подписки.
- Собрать список кандидатов отдельной выборкой и посчитать их число до любых правок.
- Развести кандидатов на две разные группы: кого удалять совсем, а кого обезличивать.
- Выполнить чистку порциями, записывая в журнал каждое выполненное над записью действие.
- Повторять чистку по расписанию небольшими порциями, а не раз в три года авралом.
Решение
Ищем записи без следов деятельности:
$rs = \Bitrix\Main\UserTable::getList(['filter' => [ '=LAST_LOGIN' => null, '<DATE_REGISTER' => (new \Bitrix\Main\Type\DateTime())->add('-2 years'), '=ACTIVE' => 'Y'], 'select' => ['ID', 'LOGIN', 'EMAIL', 'DATE_REGISTER'], 'limit' => 500]);$candidates = $rs->fetchAll();printf("кандидатов: %d\n", count($candidates));Ни одного входа за два года - разумный первый признак. Дальше его уточняют: отсутствие заказов, подписок и заявок делает запись безусловным кандидатом на удаление.
Отсеиваем тех, у кого есть заказы:
$withOrders = array_column(\Bitrix\Sale\Internals\OrderTable::getList([ 'filter' => ['@USER_ID' => array_column($candidates, 'ID')], 'select' => ['USER_ID'], 'group' => ['USER_ID']])->fetchAll(), 'USER_ID');$toDelete = array_diff(array_column($candidates, 'ID'), $withOrders);$toAnonymize = $withOrders; // этих не удаляем, а обезличиваемИщем дубли по почте:
SELECT EMAIL, COUNT(*) cnt, GROUP_CONCAT(ID) idsFROM b_user WHERE EMAIL <> '' GROUP BY EMAIL HAVING cnt > 1 ORDER BY cnt DESC LIMIT 50;-- дубли обычно появляются при импортах и при входе через внешние сервисыДубли разводят вручную или по правилу. Правило простое: живой считается запись с последним входом или с заказами, остальные обезличивают и выключают.
Обезличиваем запись с заказами:
$cuser = new \CUser();$cuser->Update($id, [ 'NAME' => 'Удалённый', 'LAST_NAME' => 'пользователь', 'SECOND_NAME' => '', 'EMAIL' => 'deleted-' . $id . '@example.invalid', 'PERSONAL_PHONE' => '', 'PERSONAL_BIRTHDAY' => '', 'ACTIVE' => 'N',]);// заказы, оплаты и документы остаются на месте вместе со своими номерамиУдаляем записи без следов деятельности:
foreach (array_slice($toDelete, 0, 200) as $id) { \Bitrix\Main\Diag\Debug::writeToFile(['удаление' => $id], date('H:i:s'), 'users-clean.log'); \CUser::Delete($id); // порция за запуск, журнал обязателен}Журнал чистки хранят дольше самой чистки. Через полгода вопрос «куда делся этот пользователь» задаст либо заказчик, либо проверяющий, и ответ должен находиться за минуту.
Типичные проблемы
После чистки часть заказов осталась без покупателя.
Удалялись подряд записи, у которых были заказы, без всякого предварительного отбора. Записи с заказами обезличивают, а удаляют только те, где следов деятельности нет.
Чистка удалила активных покупателей.
Признаком мусора считалось одно лишь отсутствие входов, без учёта заказов и подписок. Критерий чистки согласуют с заказчиком и проверяют на выборке до удаления.
Скрипт чистки падает по времени на большой базе.
Удаление идёт одним сплошным проходом сразу по всем десяткам тысяч учётных записей. Чистку ведут порциями по паре сотен записей с обязательным сохранением места остановки.
Дубли появляются снова через месяц.
Причина дублей не устранена: импорт или внешний вход заводят новую запись вместо поиска существующей. Чистка без исправления самого источника дублей рано или поздно оказывается работой впустую.
На запрос об удалении данных нечего показать.
Чистка выполнялась без журнала прохода, и подтвердить факт удаления теперь нечем. Журнал каждого действия чистки хранят заметно дольше, чем сами удалённые записи.
Частые вопросы
Что считать неактивной записью?
Обычно это отсутствие входов и заказов за согласованный срок. Точный критерий определяет заказчик, а разработчик проверяет его на выборке до чистки.
Удалять или обезличивать?
Записи без следов деятельности удаляют, записи с заказами обезличивают. Второе сохраняет документы и отчёты, а персональные данные при этом исчезают.
Что делать с дублями?
Оставить живую запись с последними входами или заказами, остальные обезличить и выключить. Заодно устранить причину: импорт или внешний вход, заводящий новые записи.
Как часто чистить базу?
По расписанию, хотя бы раз в квартал, небольшими порциями. Разовая чистка через три года превращается в отдельный проект с большим риском.
Нужно ли согласовывать чистку?
Да, и критерий, и состав обезличивания. Это решение владельца данных, а не разработчика, и его фиксируют письменно.
Смежное
-
Импорт пользователей - оглавление подтемы
-
Синхронизация пользователей с внешней системой: ключ, группы, увольнения - как не плодить дубли при обмене
-
Выгрузка пользователей: отбор, поля, персональные данные - что выгружают перед чисткой
-
Пользователь не создался при импорте: разбор причин - соседний разбор по импорту
-
Согласие на обработку данных: соглашение, компонент, запись факта - основание для хранения данных
-
База растёт: журналы, статистика, старые данные и чистка - чистка остальных таблиц
-
Долгая операция шагами: порции, состояние, прогресс - как устроена чистка порциями
-
Пользователи, группы и права доступа - устройство учётных записей целиком
-
Персональные данные на сайте: где лежат, выгрузка, удаление - что и где хранится о человеке