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

Отказ от 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 минут читала лог-файлы станков и создавала записи в регистре сведений «РаботаОборудования».

Первый месяц: хаос и адаптация

Февраль стал самым тяжёлым месяцем. Параллельный учёт создавал двойную нагрузку на сотрудников. Производственные мастера жаловались, что теперь им нужно вводить данные в систему, а не просто заполнять бумажный рапорт. Кладовщики путались в интерфейсе.

Ключевые проблемы первого месяца:

  1. Дублирование номенклатуры, при загрузке начальных остатков обнаружилось, что один и тот же материал числится под тремя разными наименованиями. Потребовалась ручная чистка 2 800 позиций;
  2. Некорректные спецификации, 34% производственных спецификаций содержали ошибки или устаревшие нормы расхода;
  3. Проблемы с правами доступа, изначально права были настроены слишком ограничительно, и пользователи не могли выполнять нужные операции;
  4. Медленная работа системы, сервер был недостаточно мощным, в пиковые часы система «тормозила».

Сервер пришлось срочно модернизировать, добавили оперативную память с 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