Добрый день!
Демонстрируется применение универсального алгоритма распределения суммы по позициям и решения известной "проблемы копеек". Также демонстрируется одна из задач адаптации программы - финансовая модель из эксель перекочевала в 1С. Что из этого для вас будет более интересным - решать вам.
* * *
В конце каждого месяца подводятся итоги по продажам магазинов. На основе этой информации расходы Администрации распределяются по магазинам пропорционально продажам. Реализован механизм "закрытия месяца" в УТ 10.3 (на платформе 8.3.11.3034 на конфигурации версии УТ 10.3.36.1.).
Для кого статья:
- для финансового директора - показать, что в 1С можно реализовать свой финансовый расчет и учет, реализовать свою финансовую модель.
- для программиста 1С - показать, как реализовать подобный расчет.
Представлено пошаговое внедрение финмодели в УТ 10.3, при которой общие административные расходы текущего месяца распределяются по подразделениям (магазинам) пропорционально продажам каждого подразделения за текущий месяц.
Подобная финансовая модель не реализована типовым функционалом в УТ 10.3, поэтому потребовалась доработка УТ 10.3. Как и любая модель имеет свои допущения и ограничения. Внедрялась на конкретном предприятии с конкретными бизнес-процессами, и поэтому не претендует на универсальность.
Архитектура решения
1. Представьте 4 розничных магазина и 1 бэк-офис администрации. Магазины учитываются как подразделения организации (справочник "Подразделения") (см. рисунок).
В УТ 10.3 не так много разрезов учета: справочники Склады, Подразделения, Организации, Проекты, Кассы, Контрагенты, Договора и т.д. - для каждого вида учета (товарный, финансовый) имеется свой набор так называемых измерений, относительно которых накапливаются показатели в соответствующих регистрах накопления. Для модели был выбран справочник "Подразделения" в качестве разреза учета - достаточно "популярный" разрез учета (см. рисунок).
2. Для учета расходов (финансовых) по подразделениям (магазинам) используется регистр накопления "ДвиженияДенежныхСредств". Распределение административных расходов также учитывается движениями по регистру "Движения денежных средств".
Ни один "денежный" регистр накопления не содержит в своем наборе измерений разрез учета "Подразделение", поэтому был расширен тип значений измерения "Проект" на соответствующий справочник. При этом в настройках учета отключен параметр "Вести учет по проектам" - еще раз, учет по проектам не ведется в программе.
3. В соответствующих документах "Платежное Поручение Исходящее", "Платежный Ордер Списание Денежных Средств", "Расходный Кассовый Ордер" - к имеющемуся типовому полю "Подразделение" была добавлена табличная часть "Распределение Расходов По Подразделениям" с единственным полем "Подразделение" (см. рисунок).
4. Модель строится на следующем принципе:
- если расход денежных средств (далее ДС) относится на конкретное подразделение, то соответствующее подразделение указывается только в шапке документа в типовом поле документа "Подразделение",
- если расход ДС необходимо распределить, то в типовом поле "Подразделение" необходимо выбрать подразделение "Администрация", а в табличной части "Распределение Расходов По Подразделениям" указать все подразделения (заполняются автоматом по кнопке на основе месячных продаж). Предполагается, что расходы относятся или только к одному подразделению, или сразу ко всем.
Создан флажок "По всем подразделениям", помогающий заполнить подразделения (магазины) в соответствующей таблице "Распределения расходов по магазинам". При открытии документов выводятся колонки ПродажиЗаМесяц, РаспределениеРасходов для проверки корректности распределения. Данные показатели рассчитываются по алгоритмам определения долей распределения расходов (см. рисунок).
Разработка
5. В модуле объекта каждого документа проведение доработано следующим образом - в процедуру общего модуля передается массив подразделений:
Процедура ДвиженияПоРегистрамУпр(Режим, Отказ, Заголовок, СтруктураШапкиДокумента)
...
//доработка+
УправлениеДенежнымиСредствами.ПровестиСписаниеДенежныхСредствУпр(
СтруктураШапкиДокумента, мСтруктураПараметровДенежныхСредств, ТаблицаПлатежейУпр,
Движения, Отказ, Заголовок, РаспределениеРасходовПоПодразделениям.ВыгрузитьКолонку("Подразделение"));
КонецПроцедуры // ДвиженияПоРегистрамУпр()
6. В соответствующей процедуре общего модуля были внесены следующие правки:
Если Оплачено И (ОтраженоВОперУчете ИЛИ ПоРасчетномуДокументу) Тогда
// Проводим по фактическим взаиморасчетам
// По регистру "Движения денежных средств"
ТаблицаДвиженияДенежныхСредств = Движения.ДвиженияДенежныхСредств.ВыгрузитьКолонки();
... // здесь код не менялся
// Недостающие поля.
ТаблицаДвиженияДенежныхСредств.ЗаполнитьЗначения(ВидДенежныхСредств, "ВидДенежныхСредств");
... // здесь код не менялся
//доработка+ начало
Если МассивПодразделений <> Неопределено И МассивПодразделений.Количество()>0 Тогда
СоответствиеТаблиц = Новый Соответствие;
Для кол = 1 По МассивПодразделений.Количество() Цикл
Если кол = 1 Тогда
СоответствиеТаблиц.Вставить(МассивПодразделений.Получить(кол-1), ТаблицаДвиженияДенежныхСредств);
Продолжить;
КонецЕсли;
СоответствиеТаблиц.Вставить(МассивПодразделений.Получить(кол-1), ТаблицаДвиженияДенежныхСредств.Скопировать());
КонецЦикла;
ТаблицаДолей = МодульДоработок.ПолучитьТаблицуДолей(Дата, МассивПодразделений);
времТаблицаДвиженияДенежныхСредств = ТаблицаДвиженияДенежныхСредств.СкопироватьКолонки();
Для Каждого Эл Из МассивПодразделений Цикл
ТЗ = СоответствиеТаблиц.Получить(Эл);
Для Каждого Стр Из ТЗ Цикл
НоваяСтрока = времТаблицаДвиженияДенежныхСредств.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
НоваяСтрока.Проект = Эл;
//расходы распределяются пропорционально продажам за месяц
СтрокаДолей = ТаблицаДолей.Найти(Эл, "Подразделение");
НоваяСтрока.Сумма = Стр.Сумма * СтрокаДолей.Доля;
НоваяСтрока.СуммаУпр = Стр.СуммаУпр * СтрокаДолей.Доля;
КонецЦикла;
КонецЦикла;
//было
//Движения.ДвиженияДенежныхСредств.мПериод = ДатаДвижений;
//Движения.ДвиженияДенежныхСредств.мТаблицаДвижений = ТаблицаДвиженияДенежныхСредств;
//Движения.ДвиженияДенежныхСредств.ВыполнитьДвижения();
//стало
Движения.ДвиженияДенежныхСредств.мПериод = ДатаДвижений;
Движения.ДвиженияДенежныхСредств.мТаблицаДвижений = времТаблицаДвиженияДенежныхСредств;
Движения.ДвиженияДенежныхСредств.ВыполнитьДвижения();
Иначе
//доработка+
ТаблицаДвиженияДенежныхСредств.ЗаполнитьЗначения(Ссылка.Подразделение, "Проект");
Движения.ДвиженияДенежныхСредств.мПериод = ДатаДвижений;
Движения.ДвиженияДенежныхСредств.мТаблицаДвижений = ТаблицаДвиженияДенежныхСредств;
Движения.ДвиженияДенежныхСредств.ВыполнитьДвижения();
КонецЕсли;
//доработка+ завершена
... // здесь код не менялся
КонецЕсли;
7. Таблица долей (коэффициентов) реализована следующим образом:
Функция ПолучитьТаблицуДолей(ТекДата, СписокПодразделений) Экспорт
Если Не ЗначениеЗаполнено(ТекДата) Тогда
ТекДата = ТекущаяДата();
КонецЕсли;
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Подразделение");
ТЗ.Колонки.Добавить("Доля");
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ПродажиОбороты.Подразделение,
| ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , Подразделение В (&СписокПодразделений)) КАК ПродажиОбороты
|
|УПОРЯДОЧИТЬ ПО
| СтоимостьОборот УБЫВ
|АВТОУПОРЯДОЧИВАНИЕ";
Запрос.УстановитьПараметр("СписокПодразделений", СписокПодразделений);
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекДата));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекДата));
ОбщиеПродажиЗаМесяц = МодульДоработок.ПолучитьОбщиеПродажиЗаМесяц(ТекДата, СписокПодразделений);
К = 1;
СуммаДолей = 0;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Если К = СписокПодразделений.Количество() Тогда
Доля = 1 - СуммаДолей;
Иначе
ПродажиЗаМесяц = Выборка.СтоимостьОборот;
Доля = Окр(ПродажиЗаМесяц/ОбщиеПродажиЗаМесяц,7);
СуммаДолей = СуммаДолей + Доля;
КонецЕсли;
Стр = ТЗ.Добавить();
Стр.Подразделение = Выборка.Подразделение;
Стр.Доля = Доля;
КонецЦикла;
Возврат ТЗ;
КонецФункции
В данной модели реализован расчет долей так: первые три по сумме продаж магазина (подразделения) получают долю делением ПродажЗаМесяц на ОбщиеПродажиЗаМесяц, четвертый магазин получает долю = 1-СуммаДолей - так называемый, остаточный принцип. Реализовано упорядочивание по суммам продаж по подразделениям - остаток долей садится на магазин с минимальными продажами.
Округления долей производится до 7 знака после запятой - что позволит избежать расхождений при умножении на семизначные суммы расходов.
Алгоритм расчета долей является универсальным в том плане, что подобный алгоритм можно применять в любой области, где нужно учитывать распределение суммы по неким позициям и нужно учесть копейки. Проблема копеек - известная задача - например, возникает при распределении суммы НДС по товарам, при распределении суммы скидки по товарам.
Пользовательский интерфейс
8. Распределение административных расходов по подразделениям проводится в момент проведения документа (список документов далее). В конце месяца необходимо запустить групповое перепроведение документов. Для этого разработана обработка группового проведения документов - "Перепроведение документов за месяц" - перепроводятся только документы по административным расходам и имеющие заполненную таблицу "Распределение по подразделениям". В групповом перепроведении участвуют только документы вида Платежное Поручение Исходящее, Платежный Ордер Списание Денежных Средств, Расходный Кассовый Ордер.
9. Отчет по движению денежных средств строится по группировкам "Проект", "Статья движения денежных средств", остальные настройки - опционально при необходимости - "Вид денежных средств" (наличные, безналичные), "Приход, расход".
Представленный механизм был реализован на платформе 8.3.11.3034 на конфигурации версии УТ 10.3.36.1. Механизм был реализован в декабре 2017 года, опубликован в мае 2018 г, актуален в марте 2024 г.
* * *
На этом все. Всем добра! С пользой для клиентов, Rustig