Задать вопрос
@KZulfiyye

Написала код расчета отпускных, но результат неправильный. Что я не учитываю?

Расчет должен быть такой: По новому законодательству при расчёте отпускных сравниваются результаты начислений среднегодового поделённый на 30.4 умноженный на кол-во календарных отпускных дней и результаты начислений, где оклад делится на кол-во рабочих дней по производственному календарю в месяц отпуска умноженное на кол-во рабочих дней в период отпуска. Если сотрудник работал не полный год, то среднегодовой рассчитывается по полным рабочим месяцам. Если результаты начислений по окладу больше результата начислений по среднегодовому подсчету сотрудник получает результат по окладу и наоборот. То есть, какой результат больше, та и оплачивается. То есть, выбираем начисление, который выгоден сотруднику.
Код по подсчету среднегодового готовый-там проблем нет.
Например, отпуск от 15.01.26 по 12.02.26. В данном периоде: 16 кд в январе, 12 кд в феврале - всего 28кд; 24 рд в январе, 24 рд в феврале - всего 48 рд; 14 рд в январе в отпускной период, 11 рд в феврале в отпускной период; оклад на момент подсчета 520 азн, а годовой или неполный годовой подсчитанный по полным месяцам 5228,89азн. Проведем подсчеты: 1) по среднегодовому - за январь - 5228,89/12/30,4*16кд=229,34 азн. За февраль - 5228,89/12/30,4*12кд=172азн. Результат по среднегодовому - 229,34+172=401,34азн. 2) по окладу - за январь - 520/24*14рд в отпускной период=303,34 азн. За февраль - 520/24*11рд в отпускной период=238,33 азн. Результат по окладу- 303,34+238,33=541,67азн. Сравниваем 401,34<541.67. ВСЕ! ОПЛАЧИВАЕМ 541,67. Второй момент: какие цифры войдут в январский расчетный лист, а какой в февраль? Тут вступает в силу еще один подсчет: 541,67/28 кд отпуска*16кд в январе в период отпуска=309,52 (эта цифра войдет в январскую расчетную таблицу); 541,67/28 кд отпуска*12кд в феврале в период отпуска=232,14 (эта цифра войдет в февральскую расчетную таблицу). Такой должен быть расчет в 1С.
На выходе в 1С 535,05 вместо 541,67
Что я не учитываю?

Для Каждого СтрокаТЧ Из Начисления Цикл

    // 1. пропускаем старые отпуска и компенсации
    Если СтрокаТЧ.ДатаНачала < '20260101' 
        ИЛИ Найти(НРег(СтрокаТЧ.ВидРасчета.Наименование), "компенсация") > 0 Тогда
        Продолжить;
    КонецЕсли;

    // -----------------------------------------------------
    // 2. ПОЛУЧАЕМ ОКЛАД
    // -----------------------------------------------------

    ЗапросОклад = Новый Запрос;

    ЗапросОклад.Текст =
    "ВЫБРАТЬ ПЕРВЫЕ 1
    | ПлановыеНачисленияСрезПоследних.Показатель1 КАК Оклад
    |ИЗ
    | РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций.СрезПоследних(
    |   &ДатаСреза,
    |   Сотрудник = &Сотрудник) КАК ПлановыеНачисленияСрезПоследних
    |ГДЕ
    | ПлановыеНачисленияСрезПоследних.Показатель1 > 0";

    ЗапросОклад.УстановитьПараметр("ДатаСреза", СтрокаТЧ.ДатаНачала);
    ЗапросОклад.УстановитьПараметр("Сотрудник", Сотрудник);

    ВыборкаОклад = ЗапросОклад.Выполнить().Выбрать();

    Если НЕ ВыборкаОклад.Следующий() Тогда
        Продолжить;
    КонецЕсли;

    ТекущийОклад = ВыборкаОклад.Оклад;

    // -----------------------------------------------------
    // 3. НОРМА РАБОЧИХ ДНЕЙ МЕСЯЦА
    // -----------------------------------------------------

    НачалоМесяцаРасчета = НачалоМесяца(СтрокаТЧ.ДатаНачала);
    КонецМесяцаРасчета  = КонецМесяца(СтрокаТЧ.ДатаНачала);

    ЗапросНорма = Новый Запрос;

    ЗапросНорма.Текст =
    "ВЫБРАТЬ
    | КОЛИЧЕСТВО(*) КАК РабочиеДни
    |ИЗ
    | РегистрСведений.РегламентированныйПроизводственныйКалендарь
    |ГДЕ
    | ДатаКалендаря МЕЖДУ &Начало И &Конец
    | И ВидДня = ЗНАЧЕНИЕ(
    |   Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)";

    ЗапросНорма.УстановитьПараметр("Начало", НачалоМесяцаРасчета);
    ЗапросНорма.УстановитьПараметр("Конец", КонецМесяцаРасчета);

    ВыборкаНорма = ЗапросНорма.Выполнить().Выбрать();
    Если ВыборкаНорма.Следующий() Тогда
        ВсегоРабочихДнейНорма = ВыборкаНорма.РабочиеДни;
    Иначе
        ВсегоРабочихДнейНорма = 0;
    КонецЕсли;

    // -----------------------------------------------------
    // 4. РАБОЧИЕ ДНИ В ПЕРИОДЕ ОТПУСКА
    // -----------------------------------------------------

    ЗапросОтпуск = Новый Запрос;

    ЗапросОтпуск.Текст =
    "ВЫБРАТЬ
    | КОЛИЧЕСТВО(*) КАК РабочиеДни
    |ИЗ
    | РегистрСведений.РегламентированныйПроизводственныйКалендарь
    |ГДЕ
    | ДатаКалендаря МЕЖДУ &Начало И &Конец
    | И ВидДня = ЗНАЧЕНИЕ(
    |   Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)";

    ЗапросОтпуск.УстановитьПараметр("Начало", СтрокаТЧ.ДатаНачала);
    ЗапросОтпуск.УстановитьПараметр("Конец", СтрокаТЧ.ДатаОкончания);

    ВыборкаОтпуск = ЗапросОтпуск.Выполнить().Выбрать();
    Если ВыборкаОтпуск.Следующий() Тогда
        ВсегоРабочихДнейОтпуска = ВыборкаОтпуск.РабочиеДни;
    Иначе
        ВсегоРабочихДнейОтпуска = 0;
    КонецЕсли;

    // -----------------------------------------------------
    // 5. РАСЧЕТ ПО ОКЛАДУ
    // -----------------------------------------------------

    Если ВсегоРабочихДнейНорма > 0 Тогда

        СуммаПоОкладу = 
        (ТекущийОклад / ВсегоРабочихДнейНорма)
        * ВсегоРабочихДнейОтпуска;

    Иначе

        СуммаПоОкладу = 0;

    КонецЕсли;

    // -----------------------------------------------------
    // 6. СРАВНЕНИЕ СО СРЕДНИМ (уже рассчитанным 1С)
    // -----------------------------------------------------

    СреднийРасчет = СтрокаТЧ.Результат;

    Если СуммаПоОкладу > СреднийРасчет Тогда
        ИтогОтпуска = СуммаПоОкладу;
    Иначе
        ИтогОтпуска = СреднийРасчет;
    КонецЕсли;

    // -----------------------------------------------------
    // 7. КАЛЕНДАРНЫЕ ДНИ
    // -----------------------------------------------------

    ВсегоКДОтпуска = 
    (КонецДня(СтрокаТЧ.ДатаОкончания) - НачалоДня(СтрокаТЧ.ДатаНачала)) / 86400 + 1;

    КДТекущейСтроки = 
    (КонецДня(СтрокаТЧ.ДатаОкончания) - НачалоДня(СтрокаТЧ.ДатаНачала)) / 86400 + 1;

    // -----------------------------------------------------
    // 8. РАСПРЕДЕЛЕНИЕ ПО МЕСЯЦАМ
    // -----------------------------------------------------

    Если ВсегоКДОтпуска > 0 Тогда

        СуммаВДень = ИтогОтпуска / ВсегоКДОтпуска;

        СтрокаТЧ.Результат = 
        СуммаВДень * КДТекущейСтроки;

    Иначе

        СтрокаТЧ.Результат = ИтогОтпуска;

    КонецЕсли;

КонецЦикла;

69b6e51a9ef0d425565738.png
  • Вопрос задан
  • 163 просмотра
Подписаться 1 Простой 1 комментарий
Помогут разобраться в теме Все курсы
  • Skillbox
    Главный бухгалтер
    8 месяцев
    Далее
  • Яндекс Практикум
    Подготовка к экзамену 1С:Специалист
    3 месяца
    Далее
  • Академия Эдюсон
    Бухгалтер: тариф Мастер
    4 месяца
    Далее
Пригласить эксперта
Ответы на вопрос 1
@Dementor
программист, архитектор, аналитик
Одно из двух - или вы допустили ошибку в кодинге или в предварительных расчетах. Проще всего запустить в режиме отладки и, посмотрев на значение переменных на каждом шаге вычисленый, вы бы поняли в чем причина быстрее чем писали бы этот вопрос!

Теперь к коду.

1) Тут три запроса в одном и том же цикле. Таблицу цикла можно было подать как параметр для единого запроса, где сначала подтянуть во временную таблицу, а потом делать с нею левые соединения прокидывая во все результаты номер строки или какой еще там у вас есть уникальный идентификатор строк. Если сотрудников много, то это поле можно проиндексировать после выгрузки в таблицы с данными. Далее в цикле найти строки или найти строку - будет работать точно намного быстрее (особенно, если где-то выше у вас открыта транзакция)

2) поиск по наименованию - плохая идея даже для тестов - лучше выносите нужный вид расчет компенсаций на фому вашей обработки, а потом прокидывайте в функцию расчета (или ориентируйтесь на значения его свойств). Названия меняются намного чаще чем код.

3) Не знаю вашу конфигурацию, но кажется, что в РегламентированныйПроизводственныйКалендарь можно задавать разные графики - 5-дневки, 6-дневки, 4-дневки, сутки-двое, сутки-трое и так далее. Если у вас более одного графика, то результат будет непрогнозируемым (норма из одного графика, а количество дней отпуска из другого)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы