Каким алгоритмом распределить товары в БД по заказам покупки, если допустимы расхождения?
Раньше вся эта аналитика выполнялась почти вручную. На текущий момент я уже автоматизировал это в нашей ERP-системе, но хочу спросить у экспертов: как бы вы подошли к решению этой задачи, если бы делали её сами?
Условия следующие:
1. По итогу анализа xml/dbf-накладных, присланных поставщиками, имеем таблицу такой структуры:
- номер накладной (часть первичного ключа)
- номер строчки в накладной (часть первичного ключа)
- код поставщика (ссылка на его профиль в нашей БД)
- название товара
- количество товара
- серия товара
- срок годности
2. По итогу работы приёмщиков склада в БД имеем другую таблицу такой структуры:
- id (первичный ключ, автоинкремент)
- идентификатор товара (ссылка на его карточку в каталоге с человеческим названием)
- количество товара
- серия
- срок годности
- производитель/страна происхождения/куча иных второстепенных характеристик товара
В этой же таблице есть два изначально пустых поля, которые нужно теперь заполнить:
- номер накладной, по которой этот товар вообще очутился на складе
- номер строчки в накладной
Собственно, два этих поля - это первичный ключ в первой таблице.
Сложностей, добавляющих "остроты" в решение, целая уйма. Приведу несколько:
- название товара у нас и у поставщика может не совпадать: "Термопаста ЕЕЕ 25 гр. 30 шт." и "Термопаста ЕЕЕ шприц 25 гр. в упак. 30 шт."
- поставщик может один и тот же товар, произведённый в разных странах, считать за один, а мы, например, как два разных
- поставщик может в электронной накладной не указать серию и срок годности, а может указать, но неверную
- один и тот же товар может одновременно прибыть от разных поставщиков
- один и тот же товар из одного заказа может прибывать частями в несколько дней
- какой-то товар могут вообще не привезти, а могут привезти лишний.
Строго говоря, получить 100% достоверного результата невозможно и погрешность будет у любого алгоритма, но ошибки были и при старой ручной работе (человеческий фактор).
Если вдруг кому-то будет интересно моё нехитрое решение:
1. Алгоритм циклом проходится по всем товарам в накладной и изо всех сил пытается определить тот код товара, который ему соответствует в нашей системе. Для этого можно использовать EAN-штрихкод, который есть (но не всегда) в накладных поставщика. Для анализа названий подходит модифицированный алгоритм Левенштейна. Если алгоритм не справляется, то присваивается служебный код "Товар не найден". Так получаем "Список 1".
2. По полученному списку вновь проходим циклом, пытаясь ориентироваться на количество товара в накладных и количество в приёмке на складе ("Список 2"). Если количества не совпали, есть варианты:
2.1. Товар не довезли/привезли излишек
2.2. Поставщик считает одним товаром то, что мы считаем двумя товарами.
По п. 2.1. нужно автоматически создавать претензию, либо просто ждать (товар могут довезти позже)
По п. 2.2. нужно модифицировать таблицу из п. 1, разделив одну строчку на две, указав в обеих правильный код товара. Чаще всего расхождения бывают из-за того, что один и тот же товар могут производить на разных заводах как в одной стране, так и в нескольких. В каких-то случаях это нельзя считать одним товаром.
3. Затем нужно проанализировать те элементы списков №1 и №2, которые не удалось сопоставить. Бывает такое, что один и тот же товар пришёл двух разных серий или сроков годности. В этом случае можно сгруппировать их без учёта этих параметров и снова вернуться к проверке количества.
4. Самая большая сложность - это когда один и тот же товар приходит в одно время от разных поставщиков. На складе его банально могут перемешать. В этом случае есть специальный журнал, в котором фиксируется прибытие каждой новой машины на склад. Ориентируясь на это время и на время добавления каждой записи в "Список 2" можно сделать косвенный вывод о том, какой товар к какому поставщику и накладной относится.
5. Анализ оставшихся несошедшихся товаров выдаётся пользователю для ручной обработки. Использовать здесь нейронную сеть или более простые самообучающиеся алгоритмы, с моей точки зрения, не получится - слишком небольшой объём данных. Максимум тысячи позиций в сутки. Однако, такой вариант доработки в этом году я ещё не исключаю.
На мой взгляд эта задача относится к менеджерским, а не айтишным. Есть хорошая поговорка: говно на входе - говно на выходе. И тогда задача формулируется иным образом: как построить процесс, чтобы он выдавал чистые данные. Описанный случай явно требует человеческого участия. И тогда остается лишь вопрос: кому и как отдать эту функцию. Жизнь "бедолаги" можно облегчить, если дать ему инструмент: рекомендательную систему что и с чем можно сопоставить. Ее можно построить любым подходящим способом. Например, через расстояние Левенштейна.
Таким образом, мой ответ такой: я бы менял процесс и вводил правила для сотрудников.