Сводный менеджер: Настройка бух.себестоимости
Себестоимость товара это суммовое значение закупочной суммы за вычетом суммы ндс Себестоимость товара по данным стандарта храниться в колонках 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;