Опираясь на опыт реализации учета акцизов в УПП, решили реализовывать как можно меньшим изменением кода конфигурации.
Задание:
При продаже подакцизных товаров рассчитывать и накапливать суммы акцизов, отражая их печатных формах СЧЕТ-ФАКТУРА и ТОРГ-12(особая форма). В дальнейшем собирать эти сведения для заполнения Налоговой декларации по акцизам на табачные изделия.
План решения:
В документе РеализацияТоваровУслуг добавить колонку «Акциз» в таблице "Товары", проработать ее заполнение. Сформировать проводку по акцизу. Изменить печатные формы.
Итак, приступим.
1. Создание и вывод столбца "Акциз" в закладке «Товары» на форме документа.
Снимаем с поддержки только корень документа «РеализацияТоваровУслуг»
Добавляем реквизит «Акциз» в табличную часть «Товары». На форму его будем выводить программным способом, благо 1С позаботилась и добавила специальный общий модуль для шаловливых ручек, вроде наших.
Снимаем с поддержки общий модуль «МодификацияКонфигурацииПереопределяемый». В нем в процедуру «ПриСозданииНаСервере» добавляем код вызова нашей процедуры для модернизации формы документа:
Процедура ПриСозданииНаСервере(Форма, Отказ, СтандартнаяОбработка) Экспорт
Если Форма.ИмяФормы = "Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента" Тогда
ИТ_РаботаСДиалогами.РеализацияТоваровУслуг_ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка);
КонецЕсли;
КонецПроцедуры
Создаем общий модуль «ИТ_РаботаСДиалогами» с флагами «Сервер», «ВызовСервера».
Добавляем в него процедуру:
Процедура РеализацияТоваровУслуг_ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка) Экспорт
Элемент = Форма.Элементы.Добавить("ТоварАкциз", Тип("ПолеФормы"), Форма.Элементы.Товары);
Элемент.Вид = ВидПоляФормы.ПолеВвода;
Элемент.ПутьКДанным = "Объект.Товары.Акциз";
КонецПроцедуры
2. Расчет и заполнение поля «Акциз» при работе на форме документа с табличной частью «Товары».
Согласно правилам расчета акцизов на табачные изделия, сумма акциза в каждой строке зависит от вида товара и его количества. В прошлой раз, при внедрении учета акцизов в 1С УПП, мы ввели регистр сведений для сохранения суммы акциза на единицу номенклатуры. Как показал практика, это было хоть и гибкое, но ошибочное решение. В этот раз пойдем другим путем, сумма акциза будет вычисляется «с нуля» каждый раз по законодательно определенным правилам уже на общее количество товара в строке.
Приступаем к форме документа «РеализацияТоваровУслуг».
Нужно выявить события, которые вызываются при изменении в табличной части «Товары», а вернее ее реквизитов: «Номенклатура», «Характеристика», «Количество упаковок», «Единица упаковки». Разбор полетов показал, что 1С нам приготовила всего два переопределяемых обработчика событий, это «НоменклатураПриИзмененииПереопределяемый» и «ХарактеристикаПриИзмененииПереопределяемый». К сожалению я не нашел никаких переопределяемых процедур для перехвата события при изменений упаковки или количества упаковок (если я неправ, поправите меня в комментариях). Значит придется снимать с поддержки форму документа и вставлять вызов функции пересчета акциза в каждое из четырех событий формы:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзмененииВопросПользователюЗавершение(Результат, ДополнительныеПараметры) Экспорт
//…
ИТ_АкцизКлиент.ПересчитатьАкцизВСтрокеТЧ(ТекущаяСтрока, Объект.Дата);
КонецПроцедуры
&НаКлиенте
Процедура ТоварыХарактеристикаПриИзмененииВопросПользователюЗавершение(Результат, ДополнительныеПараметры) Экспорт
//…
ИТ_АкцизКлиент.ПересчитатьАкцизВСтрокеТЧ(ТекущаяСтрока, Объект.Дата);
КонецПроцедуры
&НаКлиенте
Процедура ТоварыУпаковкаПриИзменении(Элемент)
//…
ИТ_АкцизКлиент.ПересчитатьАкцизВСтрокеТЧ(ТекущаяСтрока, Объект.Дата);
КонецПроцедуры
&НаКлиенте
Процедура ТоварыКоличествоУпаковокПриИзменении(Элемент)
//…
ИТ_АкцизКлиент.ПересчитатьАкцизВСтрокеТЧ(ТекущаяСтрока, Объект.Дата);
КонецПроцедуры
Теперь пропишем функции, которую мы вызываем из формы документа, для расчета акциза. Для этого в глобальном модуле создаем «ИТ_АкцизКлиент». В свойствах модуля ставим флаг «Клиент (управляемое приложение)». Создаем процедуру:
Процедура ПересчитатьАкцизВСтрокеТЧ(ТекущаяСтрока, Дата) Экспорт
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущаяСтрока.Акциз = 0;
ОНоменклатуре = ИТ_АкцизСервер.СведенияОПодакцизнойНоменклатуре(ТекущаяСтрока.Номенклатура,ТекущаяСтрока.Характеристика);
Если НЕ ОНоменклатуре.ЕстьСведенияОНоменклатуре Тогда
Возврат;
ИначеЕсли НЕ ОНоменклатуре.ПодакцизныйТовар Тогда
Возврат;
ИначеЕсли ПустаяСтрока(ОНоменклатуре.КодОКП) Тогда
//не определен ОКП номенклатуры, нельзя понять по какому способу расчитывать акциз.
Сообщить("У номенклатуры "+ТекущаяСтрока.Номенклатура+" установлен флаг ""Подакцизный товар"", но не определен код ОКП, расчет акциза невозможен.");
Возврат;
КонецЕсли;
//Расчет акциза
//Определяем вид товара
Если ОНоменклатуре.КодОКП="919024" Тогда //Сигареты с фильтром
Если НЕ ОНоменклатуре.ЕстьСведенияОХарактеристике Тогда
Сообщить("У номенклатуры "+ТекущаяСтрока.Номенклатура+" не выбрана характеристика для выделения МРЦ.");
Возврат;
Иначе
РазмерМРЦ = ВытащитьМРЦИзХарактеристикиНоменклатуры(ОНоменклатуре.НаименованиеХарактеристика,Истина);
КонецЕсли;
АкцизТНС = ПолучитьТвердуюСтавкуДляСигарет(Дата) * (ТекущаяСтрока.Количество*20/1000);
АкцизАНС = РазмерМРЦ * (ПолучитьАдвалорнуюСтавкуДляСигарет(Дата)/100) * ТекущаяСтрока.Количество;
АкцизСумма = АкцизТНС+АкцизАНС;
АкцизМин = ПолучитьМинимальнуюСтавкуДляСигарет(Дата) * (ТекущаяСтрока.Количество*20/1000);
ТекущаяСтрока.Акциз = МАКС(АкцизСумма,АкцизМин);
//ИначеЕсли ОНоменклатуре.КодОКП="…" для других видов подакцизных товаров
КонецЕсли;
КонецПроцедуры
Дополнительные функции «ПолучитьТвердуюСтавкуДляСигарет», «ПолучитьАдвалорнуюСтавкуДляСигарет», «ПолучитьМинимальнуюСтавкуДляСигарет», «СведенияОПодакцизнойНоменклатуре» и «ВытащитьМРЦИзХарактеристикиНоменклатуры» описывать в этой статье не буду. По их названию и так понятно что они делают.
3. Формирование дополнительной проводки Дт 90.04 Кт 68.03 в документе РеализацияТоваровУслуг на сумму акциза.
Все проводки в ЕРП2 формируются при помощи запроса.
Любой документ в ЕРП, генерирующий проводки, в модуле менеджера содержит экспортную функцию «ТекстОтраженияВРеглУчете()» . Эта функция всегда возвращает текст запроса, который при выполнении должен вернуть таблицу проводок.
Формат запроса можно подглядеть вот здесь: РеглУчетВыборкиСерверПовтИсп .ТекстИнициализации()
Более того, формируя запрос для проводок, можно обращаться к разным данным во временных таблицах. Они формируются в РеглУчетВыборкиСерверПовтИсп.ЗапросДанных(). Если быть честным, то именно эта процедура вызывается при проведении документа, а уже она собирает все необходимые данные для отражения проводок в виде запроса. (Советую посмотреть ее содержимое).
Возвращаемся к нашей функции «ТекстОтраженияВРеглУчете()» в менеджере документа «РеализацияТоваровУслуг». Добавляем строку:
ТекстыОтражения.Добавить(ИТ_АкцизСервер.ТекстАкцизСРеализации());
В общий модуль «ИТ_АкцизСервер» добавляем функцию формирования текста запроса для нашей проводки.
Функция ТекстАкцизСРеализации() Экспорт
ТекстАкцизСРеализации = "
|ВЫБРАТЬ //// Акциз с релизации (Дт 90.04 :: Кт 68.03)
| Операция.Ссылка КАК Ссылка,
| Операция.Дата КАК Период,
| Операция.Организация КАК Организация,
| НЕОПРЕДЕЛЕНО КАК ИдентификаторСтроки,
|
| СтрокиТовары.Акциз КАК Сумма,
| СтрокиТовары.Акциз / КурсВалютыУпрУчета.Курс КАК СуммаУУ,
|
| ЗНАЧЕНИЕ(Перечисление.ВидыСчетовРеглУчета.ПустаяСсылка) КАК ВидСчетаДт,
| Аналитика.Номенклатура.ГруппаФинансовогоУчета КАК АналитикаУчетаДт,
| Аналитика.Склад КАК МестоУчетаДт,
|
| ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка) КАК ВалютаДт,
| Операция.Подразделение КАК ПодразделениеДт,
| Операция.НаправлениеДеятельности КАК НаправлениеДеятельностиДт,
|
| ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.Продажи_Акцизы) КАК СчетДт,
|
| Аналитика.Номенклатура.ГруппаФинансовогоУчета КАК СубконтоДт1,
| НЕОПРЕДЕЛЕНО КАК СубконтоДт2,
| НЕОПРЕДЕЛЕНО КАК СубконтоДт3,
|
| 0 КАК ВалютнаяСуммаДт,
| 0 КАК КоличествоДт,
| 0 КАК СуммаНУДт,
| 0 КАК СуммаПРДт,
| 0 КАК СуммаВРДт,
|
| НЕОПРЕДЕЛЕНО КАК ВидСчетаКт,
| НЕОПРЕДЕЛЕНО КАК АналитикаУчетаКт,
| НЕОПРЕДЕЛЕНО КАК МестоУчетаКт,
|
| &ВалютаРеглУчета КАК ВалютаКт,
| ЗНАЧЕНИЕ(Справочник.СтруктураПредприятия.ПустаяСсылка) КАК ПодразделениеКт,
| ЗНАЧЕНИЕ(Справочник.НаправленияДеятельности.ПустаяСсылка) КАК НаправлениеДеятельностиКт,
|
| ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.Акцизы) КАК СчетКт,
|
| ЗНАЧЕНИЕ(Перечисление.ВидыПлатежейВГосБюджет.Налог) КАК СубконтоКт1,
| Операция.Организация.РегистрацияВНалоговомОргане КАК СубконтоКт2,
| НЕОПРЕДЕЛЕНО КАК СубконтоКт3,
|
| СтрокиТовары.Акциз КАК ВалютнаяСуммаКт,
| 0 КАК КоличествоКт,
| 0 КАК СуммаНУКт,
| 0 КАК СуммаПРКт,
| 0 КАК СуммаВРКт,
| ""Акциз с релизации"" КАК Содержание
|
|ИЗ
| ДокументыКОтражению КАК ДокументыКОтражению
|
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ
| Документ.РеализацияТоваровУслуг КАК Операция
| ПО
| ДокументыКОтражению.Ссылка = Операция.Ссылка
|
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ
| Документ.РеализацияТоваровУслуг.Товары КАК СтрокиТовары
| ПО
| (СтрокиТовары.Ссылка = Операция.Ссылка)
|
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ
| РегистрСведений.АналитикаУчетаНоменклатуры КАК Аналитика
| ПО
| СтрокиТовары.АналитикаУчетаНоменклатуры = Аналитика.КлючАналитики
|
| ЛЕВОЕ СОЕДИНЕНИЕ
| КурсыВалют КАК КурсВалютыУпрУчета
| ПО
| КурсВалютыУпрУчета.Валюта = &ВалютаУпрУчета
| И КурсВалютыУпрУчета.Дата = НАЧАЛОПЕРИОДА(Операция.Дата, День)
|
|ГДЕ
| СтрокиТовары.Акциз > 0
| И Операция.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыРеализацийТоваровУслуг.КПредоплате)
| И Операция.ХозяйственнаяОперация В (
| ЗНАЧЕНИЕ(Перечисление.ХозяйственныеОперации.РеализацияКлиенту),
| ЗНАЧЕНИЕ(Перечисление.ХозяйственныеОперации.РеализацияКлиентуРеглУчет))
| И (
| ВЫБОР КОГДА Операция.ВернутьМногооборотнуюТару ТОГДА
| Аналитика.Номенклатура.ТипНоменклатуры <> ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.МногооборотнаяТара)
| ИНАЧЕ
| ИСТИНА
| КОНЕЦ)
|";
Возврат ТекстАкцизСРеализации;
КонецФункции
Все, проводка готова.
4. Дорабатываем печатную форму С/Ф.
Такие печатные формы как Счет-Фактура или Торг-12 вынесены в отдельную обработку «ПечатьОбщихФорм». Для ее доработки снимаем ее корень с поддержки.
Находим в модуле менеджера процедуру «ЗаполнитьТабличныйДокументСчетФактура()». Там ищем часть кода, где заполняется параметр печатной формы «акциз» примерно такой:
СтруктураПараметров.Вставить("Акциз", НСтр("ru='без акциза'"));
и меняем участок кода на:
Акциз = ИТ_АкцизСервер.ПолучитьСуммуАкцизаСтрокиДокумента(СтрокаТовары,НомерСтроки); // Получение акциза из документа основания
Если Не НаборыСервер.ВыводитьТолькоЗаголовок(СтрокаТовары, ИспользоватьНаборы) Тогда
Если ДействующиеПостановления.Постановление914
ИЛИ ОпцииПечатиСчетаФактуры.СчетФактураНаАванс
ИЛИ ОпцииПечатиСчетаФактуры.СчетФактураНалоговыйАгент Тогда
СтруктураПараметров.Вставить("Акциз", Формат(Акциз,"ЧЦ=15; ЧДЦ=2; ЧН='--'")); //Подстановка акциза
Иначе
СтруктураПараметров.Вставить("Акциз", Формат(Акциз,"ЧЦ=15; ЧДЦ=2; ЧН='без акциза'")); //Подстановка акциза
КонецЕсли;
КонецЕсли;
И тут есть небольшая проблема. В качестве передаваемой переменной «СтрокаТовары» передается не строка из табличной части «Товары», а строка результата запроса с выборкой из табличной части «ВидыЗапасов».
Сначала я хотел вклиниться в этот запрос, формирующий список строк, но этот запрос использовался во многих местах и количество вмешательств в конфигурацию было слишком велико. Решил эту проблему путем преобразования строки «ВидыЗапасов» в строку «Товары» в своей процедуре. Уверен, что так делать не правильно, но нашу задачу это решило. Итак, добавляем в наш общий модуль «ИТ_АкцизСервер» функцию:
Функция ПолучитьСуммуАкцизаСтрокиДокумента(СтрокаТовары,НомерСтроки) Экспорт
СсылкаНаДокументСАкцизом = СтрокаТовары.Ссылка;
Если СсылкаНаДокументСАкцизом.Ссылка.Метаданные().ПолноеИмя()="Документ.СчетФактураВыданный" Тогда
СсылкаНаДокументСАкцизом = СтрокаТовары.Ссылка.ДокументОснование;
КонецЕсли;
Если НЕ СсылкаНаДокументСАкцизом.Ссылка.Метаданные().ПолноеИмя()="Документ.РеализацияТоваровУслуг" Тогда
Возврат 0;
КонецЕсли;
Если СсылкаНаДокументСАкцизом.Пустая()
ИЛИ СтрокаТовары.Номенклатура.Пустая()
ИЛИ СтрокаТовары.ЭтоКомплектующие Тогда
Возврат 0;
КонецЕсли;
//Поскольку 1С передает в строку не таблицу товаров а таблицу видов товаров приходится находить соответствия в нужой нам табличной части.
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура",СтрокаТовары.Номенклатура.Ссылка);
Отбор.Вставить("Характеристика",СтрокаТовары.Характеристика.Ссылка);
МассивСНоменклатурой = СсылкаНаДокументСАкцизом.Товары.НайтиСтроки(Отбор);
ИтогоАкциз = 0;
ИтогоКоличествоАкциз = 0;
Для Каждого СтрокаМассива Из МассивСНоменклатурой Цикл
Если СтрокаМассива.Количество = СтрокаТовары.Количество
И СтрокаМассива.СуммаСНДС = СтрокаТовары.СуммаСНДС Тогда
Возврат СтрокаМассива.Акциз;
КонецЕсли;
ИтогоАкциз=ИтогоАкциз+СтрокаМассива.Акциз;
ИтогоКоличествоАкциз=ИтогоКоличествоАкциз+СтрокаМассива.Количество;
КонецЦикла;
Если ИтогоКоличествоАкциз=СтрокаТовары.Количество Тогда
Возврат ИтогоАкциз;
ИначеЕсли ИтогоКоличествоАкциз>0 Тогда
Возврат ИтогоАкциз/ИтогоКоличествоАкциз*СтрокаТовары.Количество;
КонецЕсли;
Возврат 0;
КонецФункции
Аналогичным способом меняет ТОРГ-12., правда в унифицированной форме акциза нет, пришлось дорисовывать в отдельный макет.
Задача решена.