Сводный менеджер: Настройка бух.себестоимости

Материал из wiki.standart-n.ru
Перейти к: навигация, поиск

Себестоимость товара это суммовое значение закупочной суммы за вычетом суммы ндс Себестоимость товара по данным стандарта храниться в колонках summa_o, sum_ndso, quant По причине погрешностей округления данная себестоимость не устривает бухгалтерию Была разработана новая бухгалтерская себестоимость, которая хранится в колонках summa_o_account, sum_ndso_account, quant_account Для решения проблем: 1. При списании последнего остатка товара, списывать остаточную себестоиомсть. 2. Идентичное (до копейки (тьин)) отражение отчетов в программе сводный менеджер и 1с бухгалтерия.

Расчет бух. себестоимости запускается 1. Ежедневно с назначенным заданием запускается процедура pr_set_sum_account_gl. Проводит исправление/заполнение себестоимости за поледние 15 дней 2. Перед каждой автозагрузкой в 1с бухгалтерию запускается процедура pr_set_sum_account_gl. Проводит исправление/заполнение себестоимости за поледние 15 дней

Описание алгоритма PR_SET_SUM_ACCOUNT_GL: первоначально колонки заполняются приблизительно равными стандарту данными, только с учетом округления

summa_o_account = round(summa_o,2)
sum_ndso_account = round(sum_ndso,2)
quant_account = round(quant,3)

Если процедура была запущена только на исправление ошибок, то сначала формируем список партий, по которым остатка нет, а себестоимость "зависла" и вызываем PR_SET_SUM_ACCOUNT для определенной партии Иначе выполняем PR_SET_SUM_ACCOUNT за весь указанный период

Описание алгоритма PR_SET_SUM_ACCOUNT выложено в виде комментариев к процедуре

SET TERM ^ ;

create or alter procedure PR_SET_SUM_ACCOUNT (

   BEG_DATE DM_DATE,
   END_DATE DM_DATE,
   G$PROFILE_ID DM_ID,
   IN_PART_ID DM_ID_NULL,
   ITER DM_ID_NULL = 0,
   SUSPEND_MODE DM_STATUS = 0)

returns (

   OUT_ID DM_ID_NULL,
   OUT_DOC_ID DM_ID_NULL,
   OUT_DOC_COMMITDATE DM_DATE,
   PROFILE_ID DM_ID_NULL)

as declare variable QUANT DM_DOUBLE; declare variable DOC_ID DM_ID; declare variable CUR_QUANT DM_ACCOUNT_QUANT; declare variable DD1_ID DM_ID_NULL; declare variable PRICE_O DM_DOUBLE; declare variable M_UUID DM_UUID_NULL; declare variable FOR_PART_ID DM_ID_NULL; declare variable FOR_PROFILE_ID DM_ID_NULL; declare variable PART_ID DM_ID_NULL; declare variable KON_SUMMA_O_ACCOUNT DM_DOUBLE; declare variable KON_SUM_NDSO_ACCOUNT DM_DOUBLE; declare variable KON_SUM_NDSO DM_DOUBLE; declare variable KON_SUMMA_O DM_DOUBLE; declare variable CUR_SUM_NDSO DM_ACCOUNT; declare variable TEK_OST DM_DOUBLE; declare variable TEK_OST_SUM_NDSO DM_ACCOUNT; declare variable DD_ID DM_ID_NULL; declare variable TEK_OST_SUMMA_O DM_ACCOUNT; declare variable CUR_SUMMA_O DM_ACCOUNT; declare variable DOC_TYPE DM_ID_NULL; declare variable AGENT_ID DM_ID_NULL; declare variable BASE_TYPE DM_ID_NULL; declare variable FOR_S_O_A DM_ACCOUNT; declare variable FOR_S_N_A DM_ACCOUNT; declare variable FOR_DOC_ID DM_ID_NULL; declare variable DOCNUM DM_TEXT; declare variable FOR_Q_A DM_ACCOUNT_QUANT; declare variable AVG_QUANT DM_DOUBLE; declare variable TEK_OST_REAL DM_DOUBLE; begin

 -- выбираем документы движения за период или по партии
 -- так же расчитывает предыдущий остаток по кол-ву сумме закупа и сумме ндс до момента текущего движения
 for select d.doc_type,d.agent_id,p.price_o,d.vnum,dd.g$profile_id,dd.doc_id,dd.quant,
 dd.id,dd.sum_ndso_account,dd.summa_o_account,dd.part_id,dd.quant_account,

(select sum(dd1.quant_account) from doc_detail dd1 where dd1.part_id=dd.part_id and ( (dd1.doc_commitdate<=dd.doc_commitdate) or (dd1.doc_commitdate=dd.doc_commitdate and dd1.id<=dd.id)) and dd1.g$profile_id=dd.g$profile_id), (select sum(dd1.quant) from doc_detail dd1 where dd1.part_id=dd.part_id and ( (dd1.doc_commitdate<=dd.doc_commitdate) or (dd1.doc_commitdate=dd.doc_commitdate and dd1.id<=dd.id)) and dd1.g$profile_id=dd.g$profile_id), (select sum(dd1.sum_ndso_account) from doc_detail dd1 where dd1.part_id=dd.part_id and ( (dd1.doc_commitdate<=dd.doc_commitdate) or (dd1.doc_commitdate=dd.doc_commitdate and dd1.id<=dd.id)) and dd1.g$profile_id=dd.g$profile_id), (select sum(dd1.summa_o_account) from doc_detail dd1 where dd1.part_id=dd.part_id and ( (dd1.doc_commitdate<=dd.doc_commitdate) or (dd1.doc_commitdate=dd.doc_commitdate and dd1.id<=dd.id)) and dd1.g$profile_id=dd.g$profile_id), (select avg(-dd1.quant_account) from doc_detail dd1 where dd1.part_id=dd.part_id and dd1.quant<0 and dd1.g$profile_id=dd.g$profile_id), coalesce(dt.base_type,0)

from doc_detail dd
left join docs d on d.id=dd.doc_id and d.g$profile_id=dd.g$profile_id
left join doc_types dt on dt.id=d.doc_type
left join parts p on p.id=dd.part_id and p.g$profile_id=dd.g$profile_id where
((doc_commitdate between :beg_date and :end_date) or (part_id=:in_part_id) )
and dd.g$profile_id=:g$profile_id
into
:DOC_TYPE,:agent_id,:price_o,:DOCNUM,:PROFILE_ID,:doc_id,:quant,:dd_id,:cur_sum_ndso,
:cur_summa_o,:part_id,:cur_quant,:tek_ost,:TEK_OST_REAL,:tek_ost_sum_ndso,:tek_ost_summa_o,:avg_quant,:base_type do
--ДАННЫЕ СТАНДАРТА
--quant - количество в детализации
--TEK_OST_REAL - остаток по количеству до детализации
--БУХГАЛТЕРСКИЕ ДАННЫЕ
--cur_sum_ndso - сумма НДС в детализации
--cur_summa_o - сумма закупочная в детализации
--cur_quant - количество в детализации
--tek_ost - остаток по количеству до детализации
--tek_ost_sum_ndso - остаток суммы НДС до детализации
--tek_ost_summa_o- остаток суммы закупочной до детализации
--ПРОЧИЕ
--dd_id - идентификатор детализации
--avg_quant - средний размер кол-ва списания
begin
   if ( (doc_type not in (1) ) or (doc_type is null)) then --and (BASE_TYPE<>3)
   begin
   --Если эта детализации соответвует последней продаже по данной партии,
   --то пытаемся в детализации в колонках бухгалтерских данных проставить
   --остаточное значение кол-ва, суммы закупочной и НДС
   if (abs(:tek_ost) >0 and  abs(:tek_ost_real)<0.0001) then --abs(:tek_ost)<:avg_quant/10
   begin
     update doc_detail set quant_account=:cur_quant-:tek_ost,
     dcard='1' ||'-'||:G$PROFILE_ID ||'-'|| :IN_PART_ID||'-'||:ITER||'-'||:SUSPEND_MODE||'part_id '||:part_id
      where id=:dd_id and g$profile_id=:profile_id and
      (quant_account<>:cur_quant-:tek_ost ) RETURNING new.id,new.doc_id,new.doc_commitdate into
       :OUT_ID, :OUT_DOC_ID,:OUT_DOC_COMMITDATE ;
      if (:SUSPEND_MODE=1) then suspend;
  end
   if ((abs(:tek_ost)<0.1 or (abs(:tek_ost_real)<0.01)) and
   ((abs(:tek_ost_sum_ndso) > 0.001) or (abs(:tek_ost_summa_o) between 0.001 and 10) ) and
   ((:base_type<>3 or (:quant<0)) )) then
   --Если до детализации остаток партии по количеству уже меньше 0.01,
   --но сумма бухгалтерской себестоимости еще осталась на остатках,
   --то нужно эту остаточную себестоимость списать в текущем движении
   -- Условие :base_type<>3 or (:quant<0) показывает, что в корр-ках и переоценках правим,
   --только строку списания товара
   begin
     select sum(summa_o),sum(summa_o_account),sum(sum_ndso),sum(sum_ndso_account) from doc_detail where part_id=:part_id and
      g$profile_id=:profile_id into :kon_summa_o,:kon_summa_o_account,:kon_sum_ndso,:kon_sum_ndso_account;
     if  ((abs(KON_Summa_o_account)>=0.001 ) or (abs(kon_sum_ndso_account)>=0.001 ) ) then     --(abs(KON_SUM_NDSO)>=0.001 or (abs(KON_Summa_o)>=0.001 ) or
     --исправление проводим только если за весь период движения по партии
     --сохранился не нулевой остаток бух.себестоимости
     update doc_detail set sum_ndso_account=:cur_sum_ndso-:tek_ost_sum_ndso,
     summa_o_account=:cur_summa_o-:tek_ost_summa_o, dcard='2' ||'-'||:G$PROFILE_ID ||'-'|| :IN_PART_ID||'-'||:ITER||'-'||:SUSPEND_MODE||'part_id '||:part_id
      where id=:dd_id and g$profile_id=:profile_id and
      (sum_ndso_account<>:cur_sum_ndso-:tek_ost_sum_ndso or (summa_o_account<>:cur_summa_o-:tek_ost_summa_o) )
      RETURNING new.id,new.doc_id,new.doc_commitdate into
       :OUT_ID, :OUT_DOC_ID,:OUT_DOC_COMMITDATE ;
      if (:SUSPEND_MODE=1) then suspend; --and doc_commitdate>='01.06.2017'
   end
   end
   else
   --Действия при приходе
   begin
     for select id from doc_detail where id=:dd_id and g$profile_id=:profile_id and
      (abs(summa_o_account-round(summa_o, 2))>0.1 or (abs(sum_ndso_account-round(sum_ndso, 2))>0.1) ) into :DD1_ID do
      --при наличии большой разницы в приходах от поставщика (более 0.1 тенге)
      -- в закупочноу сумме или сумме НДС
      --возвращаем значения Стандарта
      begin
         update doc_detail set summa_o_account=round(summa_o, 2),sum_ndso_account=round(sum_ndso, 2),
          dcard='3' ||'-'||:G$PROFILE_ID ||'-'|| :IN_PART_ID||'-'||:ITER||'-'||:SUSPEND_MODE||'part_id '||:part_id
          where id=:DD1_ID and g$profile_id=:profile_id
          RETURNING new.id,new.doc_id,new.doc_commitdate into
       :OUT_ID, :OUT_DOC_ID,:OUT_DOC_COMMITDATE ;
      if (:SUSPEND_MODE=1) then suspend;
         --Если исправление в приходе прошло, то необходимо пересчиать/проверить
         --бух.себестоимость для всех движений по данной партии
         for select OUT_ID,OUT_DOC_ID,OUT_DOC_COMMITDATE from PR_SET_SUM_ACCOUNT(null,null,:profile_id,:part_id,:ITER+1,:suspend_mode)into
         :OUT_ID,:OUT_DOC_ID,:OUT_DOC_COMMITDATE do
            if (:suspend_mode=1) then suspend;
      end
      -- в случае если это не первый приход партии и остаток на момент второго прихода
      --был почти 0, но имел зависшую себестоимость, то нужно это исправить в текущей детализации
      if (abs(:tek_ost)<0.01 and ((abs(:tek_ost_sum_ndso) > 0.001) or (abs(:tek_ost_summa_o) between 0.001 and 10) )) then
      for select first 1 id from  doc_detail where g$profile_id=:g$profile_id  and part_id=:part_id and quant<0 order by id desc into :dd1_id do
      begin
        update doc_detail set sum_ndso_account=sum_ndso_account-:tek_ost_sum_ndso,
        summa_o_account=summa_o_account-:tek_ost_summa_o , dcard='4' ||'-'||:G$PROFILE_ID ||'-'|| :IN_PART_ID||'-'||:ITER||'-'||:SUSPEND_MODE||'part_id '||:part_id
        where id=:dd1_id and g$profile_id=:profile_id RETURNING new.id,new.doc_id,new.doc_commitdate into
       :OUT_ID, :OUT_DOC_ID,:OUT_DOC_COMMITDATE ;
      if (:SUSPEND_MODE=1) then suspend;
      end
   end
   --Отдельно рассмотрим переоценки и корр-ки
   if (doc_type=8 or doc_type=7) then
   begin
     if (quant<0) then
     begin
       select summa_o_account,sum_ndso_account,quant_account from doc_detail dd where
       dd.g$profile_id=:g$profile_id and dd.id=:dd_id into  :FOR_S_O_A,:FOR_S_N_A,:for_q_a;
       for select id from parts where MOTHERPART_ID=:part_id and doc_id=:doc_id and g$profile_id=:g$profile_id and abs(price_o-:price_o)<0.01 into :for_part_id do
         --принудительно переписываем бух. себестоимость детализации оприходования
         --соответвующую текущей детализации списания на значения идентичные текущей детализации
         -- а процедура PR_SET_SUM_ACCOUNT_REC так же дополнительно запустит проверку/заполнение
         -- бух.себестоимости по партии оприходования в случае исправления сумм
         for select OUT_ID,OUT_DOC_ID,OUT_DOC_COMMITDATE
          from PR_SET_SUM_ACCOUNT_REC(:for_part_id,:profile_id,:FOR_S_N_A,:FOR_S_O_A,:for_q_a,:doc_id,:ITER,:suspend_mode) into
          :OUT_ID,:OUT_DOC_ID,:OUT_DOC_COMMITDATE do
            if (:suspend_mode=1) then suspend;
     end
   end
   --Отдельно рассмотрим расход пермещением
   if (doc_type=6) then
      begin
        if (exists (select id from doc_detail where id=:dd_id and g$profile_id=:profile_id and
        (summa_o_account<>round(summa_o, 2) or (sum_ndso_account<>round(sum_ndso, 2))) )) then
        --проверяем только те детализации, которые мы в текущей процедуре исправляли
        begin
        select summa_o_account,sum_ndso_account,quant_account from doc_detail dd
        where dd.g$profile_id=:g$profile_id and dd.id=:dd_id into  :FOR_S_O_A,:FOR_S_N_A,:for_q_a;
        select d$uuid from parts where id=:part_id and g$profile_id=:profile_id into :m_uuid;
        if ((select coalesce(email,) from agents where id=:agent_id)<>) then
        begin
          select first 1 cast(email as dm_id_null) from agents where id=:agent_id into :for_profile_id;
          for select first 1 p.id,p.g$profile_id,p.doc_id from parts p left join docs d on d.id=p.doc_id
          and p.g$profile_id=d.g$profile_id where p.motherpart_uuid=:m_uuid and p.g$profile_id=:for_profile_id
           and p.d$uuid<>:m_uuid  and abs(price_o-:price_o)<0.01  order by abs(:quant-p.quant) into :for_part_id,:for_profile_id,:for_doc_id do
           --находим партию их прихода пермещения с другого профиля,
           --соответвующую партии из текущего расхода пермещением
           --и запускаем процедуру PR_SET_SUM_ACCOUNT_REC исправления бух.себестоимости
           for select OUT_ID,OUT_DOC_ID,OUT_DOC_COMMITDATE
            from PR_SET_SUM_ACCOUNT_REC(:for_part_id,:for_profile_id,:FOR_S_N_A,:FOR_S_O_A,:for_q_a,:for_doc_id,:ITER)
           into
          :OUT_ID,:OUT_DOC_ID,:OUT_DOC_COMMITDATE do
            if (:suspend_mode=1) then suspend;
         end
        end
      end
 end

end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT,UPDATE ON DOC_DETAIL TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT SELECT ON DOCS TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT SELECT ON DOC_TYPES TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT SELECT ON PARTS TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT_REC TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT SELECT ON AGENTS TO PROCEDURE PR_SET_SUM_ACCOUNT;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT TO PROCEDURE PR_SET_SUM_ACCOUNT; GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT TO PROCEDURE PR_SET_SUM_ACCOUNT_REC; GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT TO PROCEDURE PR_SET_WAREBASE_DATE; GRANT EXECUTE ON PROCEDURE PR_SET_SUM_ACCOUNT TO SYSDBA;