Отказ от Excel и внедрение 1С:ERP: итоги через 6 месяцев

Предыстория: производство на Excel-костылях
Когда речь заходит о производственных компаниях среднего масштаба, Excel давно превратился в синоним «временного решения, которое стало постоянным». Именно в такой ситуации оказалась компания «МеталлПром», производитель металлоконструкций с годовым оборотом около 800 миллионов рублей, штатом 340 сотрудников и тремя производственными цехами.
До внедрения задачи по 1С:ERP решались по-старому: планово-экономический отдел вёл расчёты в 47 (!) связанных Excel-файлах. Производственные мастера заполняли сменные рапорты от руки, потом данные переносились в таблицы. Склад учитывал остатки в одном файле, бухгалтерия, в другом. Расхождения между ними достигали 12, 15% по ключевым позициям.
Проблемы копились годами:
- Потеря данных, однажды ключевой файл с плановыми показателями за квартал был случайно перезаписан, и три дня ушло на восстановление;
- Несинхронизированные данные, закупщик не видел реальных остатков на складе в режиме реального времени;
- Ручной расчёт себестоимости, занимал до 5 рабочих дней в конце каждого месяца;
- Отсутствие сквозного контроля, невозможно было быстро отследить, на каком этапе находится конкретный заказ.
Решение о внедрении 1С:ERP было принято после того, как компания потеряла крупного клиента из-за срыва сроков поставки, а причиной срыва стала банальная ошибка в Excel-формуле, которая занизила потребность в комплектующих.
Подготовка к внедрению: что сделали правильно, а что нет
Проект стартовал в январе. Компания наняла команду внедренцев и выделила внутреннего проектного менеджера, руководителя IT-отдела. На этапе обследования выяснилось, что бизнес-процессы не были формализованы: каждый отдел работал «как сложилось исторически».
Что сделали правильно
- Провели полное обследование, три недели ушло на интервью с руководителями всех подразделений и составление карты процессов «как есть»;
- Определили приоритеты, решили внедрять поэтапно: сначала производство и склад, затем финансы и бюджетирование;
- Назначили ключевых пользователей, в каждом отделе выделили «чемпиона», который обучался первым и потом помогал коллегам;
- Сохранили параллельный учёт, первые два месяца данные вносились и в старые Excel-файлы, и в 1С:ERP одновременно.
Что сделали неправильно
- Недооценили сопротивление персонала, часть сотрудников открыто саботировала внедрение, считая новую систему «очередной прихотью руководства»;
- Переоценили готовность данных, нормативно-справочная информация (НСИ) оказалась в ужасающем состоянии: дублирующиеся номенклатурные позиции, несогласованные единицы измерения, отсутствующие технологические карты;
- Сжали сроки обучения, вместо запланированных 40 часов на каждого пользователя получилось в среднем 22 часа.
«Мы думали, что самое сложное, это настроить систему. Оказалось, самое сложное, это заставить людей в неё поверить.», Директор по производству «МеталлПром»
Технические решения: что пришлось дорабатывать
Стандартный функционал 1С:ERP покрыл около 70% потребностей компании. Остальные 30% потребовали доработок. Вот ключевые из них.
Расчёт производственной себестоимости по переделам
Производство металлоконструкций включает несколько переделов: заготовительный, сварочный, покрасочный, сборочный. Стандартный механизм распределения затрат не учитывал специфику, нужно было распределять общецеховые расходы пропорционально машино-часам оборудования, а не нормо-часам персонала.
// Процедура распределения общецеховых расходов по переделам
// пропорционально фактическим машино-часам оборудования
Процедура РаспределитьОбщецеховыеРасходы(ПериодНачало, ПериодКонец, Подразделение) Экспорт
// Получаем суммарные машино-часы по каждому переделу за период
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РаботаОборудования.Передел КАК Передел,
| СУММА(РаботаОборудования.МашиноЧасы) КАК ИтогоМашиноЧасов
|ИЗ
| РегистрСведений.РаботаОборудования КАК РаботаОборудования
|ГДЕ
| РаботаОборудования.Период >= &ПериодНачало
| И РаботаОборудования.Период <= &ПериодКонец
| И РаботаОборудования.Подразделение = &Подразделение
|СГРУППИРОВАТЬ ПО
| РаботаОборудования.Передел";
Запрос.УстановитьПараметр("ПериодНачало", ПериодНачало);
Запрос.УстановитьПараметр("ПериодКонец", ПериодКонец);
Запрос.УстановитьПараметр("Подразделение", Подразделение);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// Считаем суммарные машино-часы для расчёта доли
ИтогоЧасов = 0;
ТаблицаПеределов = Новый ТаблицаЗначений;
ТаблицаПеределов.Колонки.Добавить("Передел");
ТаблицаПеределов.Колонки.Добавить("МашиноЧасы");
ТаблицаПеределов.Колонки.Добавить("Доля");
Пока Выборка.Следующий() Цикл
Строка = ТаблицаПеределов.Добавить();
Строка.Передел = Выборка.Передел;
Строка.МашиноЧасы = Выборка.ИтогоМашиноЧасов;
ИтогоЧасов = ИтогоЧасов + Выборка.ИтогоМашиноЧасов;
КонецЦикла;
// Рассчитываем долю каждого передела
Если ИтогоЧасов > 0 Тогда
Для Каждого СтрокаТаблицы Из ТаблицаПеределов Цикл
СтрокаТаблицы.Доля = СтрокаТаблицы.МашиноЧасы / ИтогоЧасов;
КонецЦикла;
КонецЕсли;
// Получаем общую сумму общецеховых расходов за период
СуммаОбщецеховых = ПолучитьСуммуОбщецеховыхРасходов(ПериодНачало, ПериодКонец, Подразделение);
// Распределяем расходы по переделам
Для Каждого СтрокаТаблицы Из ТаблицаПеределов Цикл
СуммаНаПередел = СуммаОбщецеховых * СтрокаТаблицы.Доля;
ЗаписатьРаспределениеРасходов(СтрокаТаблицы.Передел, СуммаНаПередел, ПериодКонец);
КонецЦикла;
КонецПроцедуры
// Функция получения суммы общецеховых расходов из регистра бухгалтерии
Функция ПолучитьСуммуОбщецеховыхРасходов(ПериодНачало, ПериодКонец, Подразделение)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(ОбщецеховыеОбороты.СуммаОборот, 0) КАК СуммаОбщецеховых
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(
| &ПериодНачало,
| &ПериодКонец,
| Регистратор,
| Счет В ИЕРАРХИИ (ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ОбщепроизводственныеРасходы)),
| ,
| Подразделение = &Подразделение,
| ,
| ) КАК ОбщецеховыеОбороты";
Запрос.УстановитьПараметр("ПериодНачало", ПериодНачало);
Запрос.УстановитьПараметр("ПериодКонец", ПериодКонец);
Запрос.УстановитьПараметр("Подразделение", Подразделение);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
Возврат Результат.СуммаОбщецеховых;
КонецЕсли;
Возврат 0;
КонецФункции
Интеграция со станками с ЧПУ
На заготовительном участке работали три станка с числовым программным управлением. Данные о фактической выработке нужно было передавать в 1С автоматически. Написали обработку, которая раз в 15 минут читала лог-файлы станков и создавала записи в регистре сведений «РаботаОборудования».
Первый месяц: хаос и адаптация
Февраль стал самым тяжёлым месяцем. Параллельный учёт создавал двойную нагрузку на сотрудников. Производственные мастера жаловались, что теперь им нужно вводить данные в систему, а не просто заполнять бумажный рапорт. Кладовщики путались в интерфейсе.
Ключевые проблемы первого месяца:
- Дублирование номенклатуры, при загрузке начальных остатков обнаружилось, что один и тот же материал числится под тремя разными наименованиями. Потребовалась ручная чистка 2 800 позиций;
- Некорректные спецификации, 34% производственных спецификаций содержали ошибки или устаревшие нормы расхода;
- Проблемы с правами доступа, изначально права были настроены слишком ограничительно, и пользователи не могли выполнять нужные операции;
- Медленная работа системы, сервер был недостаточно мощным, в пиковые часы система «тормозила».
Сервер пришлось срочно модернизировать, добавили оперативную память с 32 до 128 ГБ и перевели базу данных на SSD-накопители. После этого производительность выросла в 4 раза.
«В феврале я думал, что мы совершили огромную ошибку. Люди работали до девяти вечера, вводя данные в две системы сразу. Но мы держались.», Проектный менеджер
Месяцы два-четыре: система начинает работать
К марту ситуация стабилизировалась. Параллельный учёт в Excel был прекращён, это сразу сняло двойную нагрузку. Пользователи начали привыкать к интерфейсу. Появились первые ощутимые результаты.
Что заработало в первую очередь
Складской учёт стал прозрачным. Кладовщик теперь видел остатки в реальном времени, а не «вчерашние данные из Excel». Закупщик мог самостоятельно проверить, есть ли нужный материал на складе, не звоня кладовщику.
Производственные заказы начали отслеживаться сквозным образом. Менеджер по продажам мог зайти в систему и увидеть, на каком этапе находится заказ клиента, в заготовке, сварке или уже на покраске.
Закупки стали планироваться автоматически. Механизм MRP в 1С:ERP рассчитывал потребности в материалах на основе производственного плана и текущих остатков. Закупщик получал готовый список того, что нужно заказать, с рекомендуемыми количествами.
// Функция получения рекомендаций по закупкам на основе плана производства
// и текущих складских остатков
Функция ПолучитьРекомендацииПоЗакупкам(ДатаПлана, Склад) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Потребности.Номенклатура КАК Номенклатура,
| Потребности.ХарактеристикаНоменклатуры КАК Характеристика,
| Потребности.КоличествоПотребность КАК КоличествоПотребность,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Заказано.КоличествоЗаказано, 0) КАК КоличествоЗаказано,
| Потребности.КоличествоПотребность
| - ЕСТЬNULL(Остатки.КоличествоОстаток, 0)
| - ЕСТЬNULL(Заказано.КоличествоЗаказано, 0) КАК КоличествоКЗаказу
|ИЗ
| (
| ВЫБРАТЬ
| ПланПроизводства.Номенклатура КАК Номенклатура,
| ПланПроизводства.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СУММА(ПланПроизводства.КоличествоМатериала) КАК КоличествоПотребность
| ИЗ
| РегистрНакопления.ПотребностиВМатериалах КАК ПланПроизводства
| ГДЕ
| ПланПроизводства.ДатаПотребности <= &ДатаПлана
| СГРУППИРОВАТЬ ПО
| ПланПроизводства.Номенклатура,
| ПланПроизводства.ХарактеристикаНоменклатуры
| ) КАК Потребности
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Склад = &Склад
| ) КАК Остатки
| ПО Потребности.Номенклатура = Остатки.Номенклатура
| И Потребности.ХарактеристикаНоменклатуры = Остатки.ХарактеристикаНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ (
| ВЫБРАТЬ
| ЗаказыПоставщикам.Номенклатура КАК Номенклатура,
| ЗаказыПоставщикам.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СУММА(ЗаказыПоставщикам.КоличествоОстаток) КАК КоличествоЗаказано
| ИЗ
| РегистрНакопления.ЗаказыПоставщикам.Остатки() КАК ЗаказыПоставщикам
| СГРУППИРОВАТЬ ПО
| ЗаказыПоставщикам.Номенклатура,
| ЗаказыПоставщикам.ХарактеристикаНоменклатуры
| ) КАК Заказано
| ПО Потребности.Номенклатура = Заказано.Номенклатура
| И Потребности.ХарактеристикаНоменклатуры = Заказано.ХарактеристикаНоменклатуры
|ГДЕ
| Потребности.КоличествоПотребность
| - ЕСТЬNULL(Остатки.КоличествоОстаток, 0)
| - ЕСТЬNULL(Заказано.КоличествоЗаказано, 0) > 0
|УПОРЯДОЧИТЬ ПО
| Потребности.Номенклатура";
Запрос.УстановитьПараметр("ДатаПлана", ДатаПлана);
Запрос.УстановитьПараметр("Склад", Склад);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Неожиданные открытия
В апреле при анализе данных в системе выяснилось, что один из поставщиков систематически поставлял материалы с отклонением от нормы, на 3, 7% меньше заявленного количества. В Excel это было незаметно из-за погрешностей ручного учёта. В 1С:ERP данные о приёмке и списании в производство сопоставились автоматически, и отклонение стало очевидным. Претензия поставщику принесла компенсацию в размере 1,2 миллиона рублей.
Найдите специалиста для решения этой задачи на koderion.ru