admin / 01.05.2020

Как считать налог на прибыль нарастающим итогом?

Нарастающим итогом налог на прибыль рассчитывается в течение всего года (налогового периода) в соответствии с требованиями НК РФ. Также нарастающими показателями заполняется и декларация по налогу на прибыль.

Что значит «нарастающий итог»?

Пример расчета показателей нарастающим итогом

Как отражаются показатели в декларации по прибыли?

Что значит «нарастающий итог»?

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

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

К концу года в результате такого сложения вырисовывается окончательная картина по налогооблагаемой базе по прибыли. Четко видны все доходы:

  • сколько их было получено от ведения обычной деятельности;
  • объем доходов от внереализационных операций;
  • после сложения предыдущих двух пунктов — весь доход, включаемый в налоговую базу.

Аналогично по расходам можно проследить:

  • сколько произведено косвенных расходов;
  • объем прямых расходов, уменьшающих налогооблагаемую базу;
  • в результате получается сумма всех произведенных и принятых к учету в налоговом периоде расходов.

Получив все данные по доходам и расходам сначала в 1-м квартале, а затем нарастающим итогом по полугодию, за 9 месяцев и, наконец, за год, с полученной таким образом налоговой базы рассчитывается налог на прибыль или выявляется налоговый убыток.

Пример расчета показателей нарастающим итогом

Все налогоплательщики формируют налоговую базу по прибыли нарастающим итогом.

Рассмотрим пример расчета показателей нарастающим итогом.

Пример:

Предприятие, отчитывающееся по прибыли за квартал, полугодие, 9 месяцев и год, в течение года получило следующие доходы и понесло указанные расходы:

Показатель

1-й квартал

Полугодие

9 месяцев

Год

Полученные доходы, руб.

400 000

400 000 + 650 000 = 1 050 000

1 050 000 + 590 000 = 1 640 000

1 640 000 + 250 000 = 1 890 000

Понесенные расходы, руб.

420 000

420 000 + 480 000 = 900 000

900 000 + 460 000 = 1 360 000

1 360 000 + 240 000 = 1 600 000

Финансовый результат, руб.

-20 000

150 000

280 000

290 000

Рассчитывая базу подобным образом и, например, получив прибыль в 1-м квартале, по итогам полугодия можно выйти на убыток. А за 9 месяцев и год снова получить прибыль. Тогда авансовые платежи по налогу на прибыль будут рассчитаны за 1-й квартал и 9 месяцев. По итогам полугодия авансов по налогу на прибыль не будет, а суммы, уплаченные за 1-й квартал, зачтутся при расчете по налогу по итогам 9 месяцев и за год.

Как отражаются показатели в декларации по прибыли?

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

В результате полученные доходы предыдущего отчетного периода складываются с доходами текущего квартала, аналогично — по расходам.

К уплате за квартал, полугодие и 9 месяцев показывается сумма аванса по налогу на прибыль за вычетом сумм, уплаченных за предыдущие отчетные периоды. А при получении убытка сумма налога к уплате будет уменьшена на сумму, уплаченную в бюджет ранее авансом.

Нарастающий (накопительный) итог долго считался одним из вызовов SQL. Что удивительно, даже после появления оконных функций он продолжает быть пугалом (во всяком случае, для новичков). Сегодня мы рассмотрим механику 10 самых интересных решений этой задачи – от оконных функций до весьма специфических хаков.
В электронных таблицах вроде Excel нарастающий итог вычисляется очень просто: результат в первой записи совпадает с её значением:

… а затем мы суммируем текущее значение и предыдущий итог.

Иными словами,

… или:
Появление в таблице двух и более групп несколько усложняет задачу: теперь мы считаем несколько итогов (для каждой группы отдельно). Впрочем, и здесь решение лежит на поверхности: необходимо каждый раз проверять, к какой группе принадлежит текущая запись. Click and drag, и работа выполнена:

Как можно заметить, подсчёт нарастающего итога связан с двумя неизменными составляющими:
(а) сортировкой данных по дате и
(б) обращением к предыдущей строке.
Но что SQL? Очень долго в нём не было нужного функционала. Необходимый инструмент – оконные функции – впервые появился только стандарте SQL:2003. К этому моменту они уже были в Oracle (версия 8i). А вот реализация в других СУБД задержалась на 5-10 лет: SQL Server 2012, MySQL 8.0.2 (2018 год), MariaDB 10.2.0 (2017 год), PostgreSQL 8.4 (2009 год), DB2 9 для z/OS (2007 год), и даже SQLite 3.25 (2018 год).
Тестовые данные — создание таблиц и наполнение их данными — — простейший случай create table test_simple (dt date null, val int null ); — используем формат дат своей СУБД (или меняем настройки, напр. через NLS_DATE_FORMAT в Oracle) insert into test_simple (dt, val) values (‘2019-11-01’, 6); insert into test_simple (dt, val) values (‘2019-11-02’, 3); insert into test_simple (dt, val) values (‘2019-11-03’, 3); insert into test_simple (dt, val) values (‘2019-11-04’, 4); insert into test_simple (dt, val) values (‘2019-11-05’, 2); insert into test_simple (dt, val) values (‘2019-11-06’, 4); insert into test_simple (dt, val) values (‘2019-11-07’, 8); insert into test_simple (dt, val) values (‘2019-11-08’, 0); insert into test_simple (dt, val) values (‘2019-11-09’, 6); insert into test_simple (dt, val) values (‘2019-11-10’, 0); insert into test_simple (dt, val) values (‘2019-11-11’, 8); insert into test_simple (dt, val) values (‘2019-11-12’, 8); insert into test_simple (dt, val) values (‘2019-11-13’, 0); insert into test_simple (dt, val) values (‘2019-11-14’, 2); insert into test_simple (dt, val) values (‘2019-11-15’, 8); insert into test_simple (dt, val) values (‘2019-11-16’, 7); — случай с группами create table test_groups (grp varchar null, — varchar2(1) in Oracle dt date null, val int null ); — используем формат дат своей СУБД (или меняем настройки, напр. через NLS_DATE_FORMAT в Oracle) insert into test_groups (grp, dt, val) values (‘a’, ‘2019-11-06’, 1); insert into test_groups (grp, dt, val) values (‘a’, ‘2019-11-07’, 3); insert into test_groups (grp, dt, val) values (‘a’, ‘2019-11-08’, 4); insert into test_groups (grp, dt, val) values (‘a’, ‘2019-11-09’, 1); insert into test_groups (grp, dt, val) values (‘a’, ‘2019-11-10’, 7); insert into test_groups (grp, dt, val) values (‘b’, ‘2019-11-06’, 9); insert into test_groups (grp, dt, val) values (‘b’, ‘2019-11-07’, 10); insert into test_groups (grp, dt, val) values (‘b’, ‘2019-11-08’, 9); insert into test_groups (grp, dt, val) values (‘b’, ‘2019-11-09’, 1); insert into test_groups (grp, dt, val) values (‘b’, ‘2019-11-10’, 10); insert into test_groups (grp, dt, val) values (‘c’, ‘2019-11-06’, 4); insert into test_groups (grp, dt, val) values (‘c’, ‘2019-11-07’, 10); insert into test_groups (grp, dt, val) values (‘c’, ‘2019-11-08’, 9); insert into test_groups (grp, dt, val) values (‘c’, ‘2019-11-09’, 4); insert into test_groups (grp, dt, val) values (‘c’, ‘2019-11-10’, 4); — проверяем данные — select * from test_simple order by dt; select * from test_groups order by grp, dt;

1. Оконные функции

Оконные функции – вероятно, самый простой способ. В базовом случае (таблица без групп) мы рассматриваем данные, отсортированные по дате:
order by dt
… но нас интересуют только строки до текущей:
rows between unbounded preceding and current row
В конечном итоге, нам нужна сумма с этими параметрами:
sum(val) over (order by dt rows between unbounded preceding and current row)
А полный запрос будет выглядеть так:
select s.*, coalesce(sum(s.val) over (order by s.dt rows between unbounded preceding and current row), 0) as total from test_simple s order by s.dt;
В случае нарастающего итога по группам (поле grp) нам требуется только одна небольшая правка. Теперь мы рассматриваем данные как разделённые на «окна» по признаку группы:

Чтобы учесть это разделение необходимо использовать ключевое слово partition by :
partition by grp
И, соответственно, считать сумму по этим окнам:
sum(val) over (partition by grp order by dt rows between unbounded preceding and current row)
Тогда весь запрос преобразуется таким образом:
select tg.*, coalesce(sum(tg.val) over (partition by tg.grp order by tg.dt rows between unbounded preceding and current row), 0) as total from test_groups tg order by tg.grp, tg.dt;
Производительность оконных функций будет зависеть от специфики вашей СУБД (и её версии!), размеров таблицы, и наличия индексов. Но в большинстве случаев этот метод будет самым эффективным. Тем не менее, оконные функции недоступны в старых версиях СУБД (которые ещё в ходу). Кроме того, их нет в таких СУБД как Microsoft Access и SAP/Sybase ASE. Если необходимо вендоро-независимое решение, следует обратить внимание на альтернативы.

2. Подзапрос

Как было сказано выше, оконные функции были очень поздно введены в основных СУБД. Эта задержка не должна удивлять: в реляционной теории данные не упорядочены. Куда больше духу реляционной теории соответствует решение через подзапрос.
Такой подзапрос должен считать сумму значений с датой до текущей (и включая текущую): .
Что в коде выглядит так:
select s.*, (select coalesce(sum(t2.val), 0) from test_simple t2 where t2.dt <= s.dt) as total from test_simple s order by s.dt;
Чуть более эффективным будет решение, в котором подзапрос считает итог до текущей даты (но не включая её), а затем суммирует его со значением в строке:
select s.*, s.val + (select coalesce(sum(t2.val), 0) from test_simple t2 where t2.dt < s.dt) as total from test_simple s order by s.dt;
В случае нарастающего итога по нескольким группам нам необходимо использовать коррелированный подзапрос:
select g.*, (select coalesce(sum(t2.val), 0) as total from test_groups t2 where g.grp = t2.grp and t2.dt <= g.dt) as total from test_groups g order by g.grp, g.dt;
Условие g.grp = t2.grp проверяет строки на вхождение в группу (что, в принципе, сходно с работой partition by grp в оконных функциях).

3. Внутреннее соединение

Поскольку подзапросы и джойны взаимозаменяемы, мы легко можем заменить одно на другое. Для этого необходимо использовать Self Join, соединив два экземпляра одной и той же таблицы:

select s.*, coalesce(sum(t2.val), 0) as total from test_simple s inner join test_simple t2 on t2.dt <= s.dt group by s.dt, s.val order by s.dt;
Как можно заметить, условие фильтрации в подзапросе t2.dt <= s.dt стало условием соединения. Кроме того, чтобы использовать агрегирующую функцию sum() нам необходима группировка по дате и значению group by s.dt, s.val.
Точно также можно сделать для случая с разными группами grp:
select g.*, coalesce(sum(t2.val), 0) as total from test_groups g inner join test_groups t2 on g.grp = t2.grp and t2.dt <= g.dt group by g.grp, g.dt, g.val order by g.grp, g.dt;

4. Декартово произведение

Раз уж мы заменили подзапрос на join, то почему бы не попробовать декартово произведение? Это решение потребует только минимальных правок:
select s.*, coalesce(sum(t2.val), 0) as total from test_simple s, test_simple t2 where t2.dt <= s.dt group by s.dt, s.val order by s.dt;
Или для случая с группами:
select g.*, coalesce(sum(t2.val), 0) as total from test_groups g, test_groups t2 where g.grp = t2.grp and t2.dt <= g.dt group by g.grp, g.dt, g.val order by g.grp, g.dt;
Перечисленные решения (подзапрос, inner join, cartesian join) соответсвуют SQL-92 и SQL:1999, а потому будут доступны практически в любой СУБД. Основная проблема всех этих решений в низкой производительности. Это не велика беда, если мы материализуем таблицу с результатом (но ведь всё равно хочется большей скорости!). Дальнейшие методы куда более эффективны (с поправкой на уже указанные специфику конкретных СУБД и их версий, размер таблицы, индексы).

5. Рекурсивный запрос

Один из более специфических подходов – это рекурсивный запрос в common table expression. Для этого нам необходим «якорь» – запрос, возвращающий самую первую строку:
select dt, val, val as total from test_simple where dt = (select min(dt) from test_simple)
Затем к «якорю» с помощью union all присоединяются результаты рекурсивного запроса. Для этого можно опереться на поле даты dt, прибавляя у нему по одному дню:
select r.dt, r.val, cte.total + r.val from cte inner join test_simple r on r.dt = dateadd(day, 1, cte.dt) — + 1 день в SQL Server
Часть кода, добавляющая один день, не универсальна. Например, это r.dt = dateadd(day, 1, cte.dt) для SQL Server, r.dt = cte.dt + 1 для Oracle, и т.д.
Совместив «якорь» и основной запрос, мы получим окончательный результат:
with cte (dt, val, total) as (select dt, val, val as total from test_simple where dt = (select min(dt) from test_simple) union all select r.dt, r.val, cte.total + r.val from cte inner join test_simple r on r.dt = dateadd(day, 1, cte.dt) — r.dt = cte.dt + 1 в Oracle, и т.п. ) select dt, val, total from cte order by dt;
Решение для случая с группами будет ненамного сложнее:
with cte (dt, grp, val, total) as (select g.dt, g.grp, g.val, g.val as total from test_groups g where g.dt = (select min(dt) from test_groups where grp = g.grp) union all select r.dt, r.grp, r.val, cte.total + r.val from cte inner join test_groups r on r.dt = dateadd(day, 1, cte.dt) — r.dt = cte.dt + 1 в Oracle, и т.п. and cte.grp = r.grp ) select dt, grp, val, total from cte order by grp, dt;

6. Рекурсивный запрос с функцией row_number()

Предыдущее решение опиралось на непрерывность поля даты dt с последовательным приростом на 1 день. Мы избежать этого, используя оконную функцию row_number(), которая нумерует строки. Конечно, это нечестно – ведь мы собрались рассматривать альтернативы оконным функциям. Тем не менее, это решение может быть своего рода proof of concept: ведь на практике может быть поле, заменяющее номера строк (id записи). Кроме того, в SQL Server функция row_number() появилась раньше, чем была введена полноценная поддержка оконных функций (включая sum()).
Итак, для рекурсивного запроса с row_number() нам понадобится два СТЕ. В первом мы только нумеруем строки:
with cte1 (dt, val, rn) as (select dt, val, row_number() over (order by dt) as rn from test_simple)
… и если номер строки уже есть в таблице, то можно без него обойтись. В следующем запросе обращаемся уже к cte1:
cte2 (dt, val, rn, total) as (select dt, val, rn, val as total from cte1 where rn = 1 union all select cte1.dt, cte1.val, cte1.rn, cte2.total + cte1.val from cte2 inner join cte1 on cte1.rn = cte2.rn + 1 )
А целиком запрос выглядит так:
with cte1 (dt, val, rn) as (select dt, val, row_number() over (order by dt) as rn from test_simple), cte2 (dt, val, rn, total) as (select dt, val, rn, val as total from cte1 where rn = 1 union all select cte1.dt, cte1.val, cte1.rn, cte2.total + cte1.val from cte2 inner join cte1 on cte1.rn = cte2.rn + 1 ) select dt, val, total from cte2 order by dt;
… или для случая с группами:
with cte1 (dt, grp, val, rn) as (select dt, grp, val, row_number() over (partition by grp order by dt) as rn from test_groups), cte2 (dt, grp, val, rn, total) as (select dt, grp, val, rn, val as total from cte1 where rn = 1 union all select cte1.dt, cte1.grp, cte1.val, cte1.rn, cte2.total + cte1.val from cte2 inner join cte1 on cte1.grp = cte2.grp and cte1.rn = cte2.rn + 1 ) select dt, grp, val, total from cte2 order by grp, dt;

7. Оператор CROSS APPLY / LATERAL

Один из самых экзотических способов расчёта нарастающего итога – это использование оператора CROSS APPLY (SQL Server, Oracle) или эквивалентного ему LATERAL (MySQL, PostgreSQL). Эти операторы появились довольно поздно (например, в Oracle только с версии 12c). А в некоторых СУБД (например, MariaDB) их и вовсе нет. Поэтому это решение представляет чисто эстетический интерес.
Функционально использование CROSS APPLY или LATERAL идентично подзапросу: мы присоединяем к основному запросу результат вычисления:
cross apply (select coalesce(sum(t2.val), 0) as total from test_simple t2 where t2.dt <= s.dt ) t2
… что целиком выглядит так:
select s.*, t2.total from test_simple s cross apply (select coalesce(sum(t2.val), 0) as total from test_simple t2 where t2.dt <= s.dt ) t2 order by s.dt;
Похожим будет и решение для случая с группами:
select g.*, t2.total from test_groups g cross apply (select coalesce(sum(t2.val), 0) as total from test_groups t2 where g.grp = t2.grp and t2.dt <= g.dt ) t2 order by g.grp, g.dt;

Итого: мы рассмотрели основные платформо-независимые решения. Но остаются решения, специфичные для конкретных СУБД! Поскольку здесь возможно очень много вариантов, остановимся на нескольких наиболее интересных.

8. Оператор MODEL (Oracle)

Оператор MODEL в Oracle даёт одно из самых элегантных решений. В начале статьи мы рассмотрели общую формулу нарастающего итога:

MODEL позволяет реализовать эту формулу буквально один к одному! Для этого мы сначала заполняем поле total значениями текущей строки
select dt, val, val as total from test_simple
… затем рассчитываем номер строки как row_number() over (order by dt) as rn (или используем готовое поле с номером, если оно есть). И, наконец, вводим правило для всех строк, кроме первой: total = total + val.
Функция cv() здесь отвечает за значение текущей строки. А весь запрос будет выглядеть так:
select dt, val, total from (select dt, val, val as total from test_simple) t model dimension by (row_number() over (order by dt) as rn) measures (dt, val, total) rules (total = total + val) order by dt;

9. Курсор (SQL Server)

Нарастающий итог – один из немногих случаев, когда курсор в SQL Server не только полезен, но и предпочтителен другим решениям (как минимум до версии 2012, где появились оконные функции).
Реализация через курсор довольно тривиальна. Сначала необходимо создать временную таблицу и заполнить её датами и значениями из основной:
create table #temp (dt date primary key, val int null, total int null ); insert #temp (dt, val) select dt, val from test_simple order by dt;
Затем задаём локальные переменные, через которые будет происходить обновление:
declare @VarTotal int, @VarDT date, @VarVal int; set @VarTotal = 0;
После этого обновляем временную таблицу через курсор:
declare cur cursor local static read_only forward_only for select dt, val from #temp order by dt; open cur; fetch cur into @VarDT, @VarVal; while @@fetch_status = 0 begin set @VarTotal = @VarTotal + @VarVal; update #temp set total = @VarTotal where dt = @VarDT; fetch cur into @VarDT, @VarVal; end; close cur; deallocate cur;
И, наконец, получем нужный результат:
select dt, val, total from #temp order by dt; drop table #temp;

10. Обновление через локальную переменную (SQL Server)

Обновление через локальную переменную в SQL Server основано на недокументированном поведении, поэтому его нельзя считать надёжным. Тем не менее, это едва ли не самое быстрое решение, и этим оно интересно.
Создадим две переменные: одну для нарастающих итогов и табличную переменную:
declare @VarTotal int = 0; declare @tv table (dt date null, val int null, total int null );
Сначала заполним @tv данным из основной таблицы
insert @tv (dt, val, total) select dt, val, 0 as total from test_simple order by dt;
Затем табличную переменную @tv обновим, используя @VarTotal:

Что такое нарастающий итог при расчете налога на прибыль?

Пример расчета налоговой базы

Что в декларации?

Итоги

Что такое нарастающий итог при расчете налога на прибыль?

Налоговой базой по налогу на прибыль является денежное выражение прибыли организации (п. 1 ст. 274 НК РФ).

При определении налоговой базы облагаемая прибыль определяется нарастающим итогом с начала налогового периода (п. 7 ст. 274 НК РФ). Исходя из базы за год исчисляется налог.

Авансы по итогам отчетных периодов исчисляются исходя из прибыли, рассчитанной нарастающим итогом с начала налогового периода до окончания отчетного периода (п. 2 ст. 286 НК РФ). Нарастающий итог означает, что прибыль отчетного квартала определяется исходя из доходов и расходов, полученных/понесенных с начала года до отчетной даты. То есть она фактически включает в себя и прибыль/убыток прошлого отчетного периода, и прибыль/убыток текущего.

Как правильно считать авансовые платежи по налогу на прибыль, узнайте в КонсультантПлюс. Если у вас нет доступа к системе, получите пробный онлайн-доступ бесплатно.

Про нарастающий итог в другом отчете читайте в материале «6-НДФЛ заполняется нарастающим итогом с начала года».

Пример расчета налоговой базы

Поясним сказанное на примере.

Допустим, отчетными периодами для организации являются квартал, полугодие и 9 месяцев.

За I квартал ее доходы составили 900 тыс. рублей, а расходы — 750 тыс. рублей.

За II квартал: доходы — 600 тыс., расходы 800 тыс. рублей соответственно.

За III квартал: 1 млн и 700 тыс. рублей.

За IV квартал — 700 тыс. и 800 тыс.

Представим расчет налоговой базы в таблице:

Таким образом, в течение года организация получала как прибыль, так и убыток, но в результате нарастающим итогом получена прибыль.

См. также: «Как рассчитывается прибыль до налогообложения (формула)?».

Что в декларации?

Декларация по налогу на прибыль также составляется нарастающим итогом с начала года (п. 2.1 Порядка заполнения, утв. приказом ФНС России от 23.09.2019 № ММВ-7-3/475@).

В ней вы отражаете доходы и расходы, накопленные с 1 января по дату отчета, и исчисленную из них сумму налога или авансового платежа.

Сумма налога (аванса) к уплате показывается за вычетом платежей предыдущего отчетного периода. В итоге в бюджет идет разница между текущим платежом и платежом предыдущего отчетного периода.

Если у вас есть доступ к КонсультантПлюс, проверьте правильно ли вы заполнили декларацию по налогу на прибыль. Если доступа нет, получите пробный онлайн-доступ к правовой системе бесплатно.

Рекомендации по составлению и пример заполнения декларации по налогу на прибыль ищите .

Итоги

Исчисление налога нарастающим итогом означает, что расчет нужно вести исходя из доходов и расходов, полученных (осуществленных) с 1 января по отчетную дату. По этому же принципу заполняется налоговая декларация. Нарастает и сумма налога к уплате, т. к. при ее определении учитываются платежи предыдущих отчетных периодов.

Более полную информацию по теме вы можете найти в КонсультантПлюс.
Полный и бесплатный доступ к системе на 2 дня.

FILED UNDER : Статьи

Submit a Comment

Must be required * marked fields.

:*
:*