Дублирование чека — различия между версиями

Материал из wiki.standart-n.ru
Перейти к: навигация, поиск
(Автоматическое исправление отмененных чеков)
(Процедура создание пропущенных Z отчетов)
 
(не показано 9 промежуточных версии 6 участников)
Строка 1: Строка 1:
 
=Ситуации которые бывают с чеками=
 
=Ситуации которые бывают с чеками=
 
'''#1.''' ККМ при отбитии выдал ошибку и АРМ Кассир решил, что чек не прошел и отменил его, а на самом деле чек в ккм прошел и суммы обновились. Возможно, была незавершенка, в которой нажали '''отменить'''. В z-отчете сумма больше, чем по базе. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:
 
'''#1.''' ККМ при отбитии выдал ошибку и АРМ Кассир решил, что чек не прошел и отменил его, а на самом деле чек в ккм прошел и суммы обновились. Возможно, была незавершенка, в которой нажали '''отменить'''. В z-отчете сумма больше, чем по базе. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:
  база - 0, ккм - 1, банк - 1
+
  база - 0, банк - 1, ккм - 1
 
'''Решение:''' в базе должен быть '''отмененный''' чек на сумму расхождений, который нужно продублировать. Ситуация должна выправиться:
 
'''Решение:''' в базе должен быть '''отмененный''' чек на сумму расхождений, который нужно продублировать. Ситуация должна выправиться:
  база - 1, ккм - 1, банк - 1
+
  база - 1, банк - 1, ккм - 1
  
  
 
'''#2.''' В ккм чек прошел дважды, а по базе - 1. Скорей всего возникла ситуация, как в первом случае, вышла незавершенка, но в ней на этот раз нажали '''завершить'''. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:  
 
'''#2.''' В ккм чек прошел дважды, а по базе - 1. Скорей всего возникла ситуация, как в первом случае, вышла незавершенка, но в ней на этот раз нажали '''завершить'''. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:  
  база - 1, ккм - 2, банк - 1
+
  база - 1, банк - 1, ккм - 2
 
'''Решение:''' сначала нужно продублировать чек. Получится:  
 
'''Решение:''' сначала нужно продублировать чек. Получится:  
  база - 2, ккм - 2, банк - 1
+
  база - 2, банк - 1, ккм - 2
 
Затем нужно сделать возврат с включенной ккм, но с несвязным терминалом. Получится:  
 
Затем нужно сделать возврат с включенной ккм, но с несвязным терминалом. Получится:  
  база - 1, ккм - 1, банк - 1
+
  база - 1, банк - 1, ккм - 1
  
  
 
'''#3.''' При оплате по безналу чек по банку не прошел, но в базе и ккм он записался как проведенный. Скорей всего была незавершенка на банковской операции, при которой нажали '''пропустить'''. В итоге:  
 
'''#3.''' При оплате по безналу чек по банку не прошел, но в базе и ккм он записался как проведенный. Скорей всего была незавершенка на банковской операции, при которой нажали '''пропустить'''. В итоге:  
  база - 1, ккм - 1, банк - 0
+
  база - 1, банк - 0, ккм - 1
 
Получается, что данный товар продавец отдал покупателю бесплатно.<br>
 
Получается, что данный товар продавец отдал покупателю бесплатно.<br>
 
'''Решение:''' сначала нужно сделать возврат с включенной ккм, но с несвязным терминалом. Получится:  
 
'''Решение:''' сначала нужно сделать возврат с включенной ккм, но с несвязным терминалом. Получится:  
  база - 0, ккм - 0, банк - 0
+
  база - 0, банк - 0, ккм - 0
 
Вроде все сходится, но т.к. как мы отдали товар покупателю, то нужно списать его с остатков. Для этого пробиваем данный чек по безналу в режиме без кмм и с несвязным терминалом.
 
Вроде все сходится, но т.к. как мы отдали товар покупателю, то нужно списать его с остатков. Для этого пробиваем данный чек по безналу в режиме без кмм и с несвязным терминалом.
  
  
 
'''#4.''' При оплает по безналу чек по банку прошел, а при проведении по ккм возникла незавершенка, в которой нажали '''пропустить'''. В результате чек по банку и по базе прошел, с остатков списался, а по ккм не прошел. Сумма по чекам будет больше, чем по z-отчету на сумму проблемного чека. Т.е.:  
 
'''#4.''' При оплает по безналу чек по банку прошел, а при проведении по ккм возникла незавершенка, в которой нажали '''пропустить'''. В результате чек по банку и по базе прошел, с остатков списался, а по ккм не прошел. Сумма по чекам будет больше, чем по z-отчету на сумму проблемного чека. Т.е.:  
  база - 1, ккм - 0, банк - 1
+
  база - 1, банк - 1, ккм - 0
 
'''Решение:''' сначала нужно сделать возврат по безналу в режиме без ккм и несвязного терминала. Получится:  
 
'''Решение:''' сначала нужно сделать возврат по безналу в режиме без ккм и несвязного терминала. Получится:  
  база - 0, ккм - 0, банк - 1
+
  база - 0, банк - 1, ккм - 0
 
Затем нужно пробить чек по безналу с включенной ккм, но с несвязным терминалом. Ситуация разрешится:  
 
Затем нужно пробить чек по безналу с включенной ккм, но с несвязным терминалом. Ситуация разрешится:  
  база - 1, ккм - 1, банк - 1
+
  база - 1, банк - 1, ккм - 1
  
  
Строка 507: Строка 507:
 
declare variable DOCNUM DM_TEXT;
 
declare variable DOCNUM DM_TEXT;
 
declare variable DOCDATE DM_DATETIME;
 
declare variable DOCDATE DM_DATETIME;
declare variable COMMITDATE DM_DATETIME;
 
 
declare variable SESSION_ID DM_ID;
 
declare variable SESSION_ID DM_ID;
 
declare variable PARAM_VALUE DM_TEXT1024;
 
declare variable PARAM_VALUE DM_TEXT1024;
Строка 523: Строка 522:
 
declare variable SUMMA DM_DOUBLE;
 
declare variable SUMMA DM_DOUBLE;
 
declare variable SUMMA_O DM_DOUBLE;
 
declare variable SUMMA_O DM_DOUBLE;
 +
declare variable INSERTDT DM_DATETIME;
 +
declare variable POSTDT DM_DATETIME;
 
begin
 
begin
I = 0;
+
-------------------------------------------------------------
 +
---- от 2017 04 11 ------------------------------------------
 +
-------------------------------------------------------------
  
/* Включаем режим расход в минус, предварительно запоминая значение режима 1-Разрешен, 0-Запрещен */
+
  i=0;
select PARAM_VALUE
+
  --Включаем режим расход в минус, предварительно запоминая значение режима 1-Разрешен, 0-Запрещен
from PARAMS
+
  select PARAM_VALUE from params where param_id = 'RASHOD_MINUS' into :PARAM_VALUE;
where PARAM_ID = 'RASHOD_MINUS'
+
  update params set param_value = '1' where param_id = 'RASHOD_MINUS';
into :PARAM_VALUE;
+
update PARAMS
+
set PARAM_VALUE = '1'
+
where PARAM_ID = 'RASHOD_MINUS';
+
  
select STATUS,
+
  select STATUS, DOC_TYPE, AGENT_ID, PARENT_ID, DOCNUM, DOCDATE, AUDIT_ID, coalesce(COMMENTS,''), SUMM1,SUMM2,SUMM3,SUMM4,VSHIFT,DEVICE_NUM,VNUM,BONUS,CAPTION, SUMMA, SUMMA_O, INSERTDT, POSTDT from docs where id = :DOC_ID into :STATUS, :DOC_TYPE, :AGENT_ID, :PARENT_ID, :DOCNUM, :DOCDATE, :SESSION_ID, :COMMENTS, :SUMM1,SUMM2,SUMM3,SUMM4,VSHIFT,DEVICE_NUM,VNUM,BONUS,CAPTION, :SUMMA, :SUMMA_O, :INSERTDT, :POSTDT;
        DOC_TYPE,
+
        AGENT_ID,
+
        PARENT_ID,
+
        DOCNUM,
+
        DOCDATE,
+
        COMMITDATE,
+
        AUDIT_ID,
+
        coalesce(COMMENTS, ''),
+
        SUMM1,
+
        SUMM2,
+
        SUMM3,
+
        SUMM4,
+
        VSHIFT,
+
        DEVICE_NUM,
+
        VNUM,
+
        BONUS,
+
        CAPTION,
+
        SUMMA,
+
        SUMMA_O
+
from DOCS
+
where ID = :DOC_ID
+
into :STATUS,
+
      :DOC_TYPE,
+
      :AGENT_ID,
+
      :PARENT_ID,
+
      :DOCNUM,
+
      :DOCDATE,
+
      :COMMITDATE,
+
      :SESSION_ID,
+
      :COMMENTS,
+
      :SUMM1,
+
      SUMM2,
+
      SUMM3,
+
      SUMM4,
+
      VSHIFT,
+
      DEVICE_NUM,
+
      VNUM,
+
      BONUS,
+
      CAPTION,
+
      :SUMMA,
+
      :SUMMA_O;
+
 
+
while (:DOC_QUANT > I) do
+
begin
+
  I = I + 1;
+
 
+
  /* Новый документ */
+
  select DOC_ID
+
  from PR_NEWDOC(:DOC_TYPE, :AGENT_ID, :PARENT_ID, :DOCNUM, :DOCDATE, :SESSION_ID)
+
  into :O$DOC_ID;
+
 
+
  /* Детализация */
+
  if (:STATUS = 1) then
+
  insert into DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT,
+
                                  DISCOUNT, SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE,
+
                                  BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT, KEMVSERT, SDSERT, REGN, NGTD,
+
                                  EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID,
+
                                  ORIG_COUNTRY_ID, Z_ID, SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY,
+
                                  INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT, SUM_DSC, CUSTOMDRAW,
+
                                  STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
+
  select PARENT_ID,
+
          :O$DOC_ID,
+
          PART_ID,
+
          PART_PARENT_ID,
+
          0,
+
          PRICE,
+
          NAC,
+
          QUANT,
+
          DISCOUNT,
+
          SUMMA,
+
          SUMMA_O,
+
          DCARD,
+
          WARE_ID,
+
          PRICE_O,
+
          PRICE_Z,
+
          PRICE_R,
+
          DD.BARCODE,
+
          BARCODE1,
+
          GODENDO,
+
          SERIA,
+
          NDS,
+
          SUM_NDSO,
+
          SERT,
+
          DATESERT,
+
          KEMVSERT,
+
          SDSERT,
+
          REGN,
+
          NGTD,
+
          EDIZM,
+
          DD.NAME_ID,
+
          DD.IZG_ID,
+
          DD.COUNTRY_ID,
+
          DD.ORIG_CODE,
+
          ORIG_NAME_ID,
+
          ORIG_IZG_ID,
+
          ORIG_COUNTRY_ID,
+
          Z_ID,
+
          DD.SNAME,
+
          SIZG,
+
          SCOUNTRY,
+
          SORIG_NAME,
+
          SORIG_IZG,
+
          SORIG_COUNTRY,
+
          DD.INSERTDT,
+
          0,
+
          0,
+
          DEP,
+
          BCODE_IZG,
+
          HUMAN_QUANT,
+
          SUM_DSC,
+
          null,
+
          0,
+
          PART_TYPE,
+
          BASE_AGENT_ID,
+
          DD.PACKET,
+
          0
+
  from VW_DOC_DETAIL DD
+
  left join WARES W on DD.WARE_ID = W.ID
+
  where DOC_ID = :DOC_ID;
+
  else
+
  insert into DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT,
+
                                  DISCOUNT, SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE,
+
                                  BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT, KEMVSERT, SDSERT, REGN, NGTD,
+
                                  EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID,
+
                                  ORIG_COUNTRY_ID, Z_ID, SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY,
+
                                  INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT, SUM_DSC, CUSTOMDRAW,
+
                                  STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
+
  select DD.PARENT_ID,
+
          :O$DOC_ID,
+
          PART_ID,
+
          PART_PARENT_ID,
+
          0,
+
          DD.PRICE,
+
          DD.NAC,
+
          DD.QUANT,
+
          DISCOUNT,
+
          SUMMA,
+
          SUMMA_O,
+
          DCARD,
+
          DD.WARE_ID,
+
          DD.PRICE_O,
+
          DD.PRICE_Z,
+
          DD.PRICE_R,
+
          DD.BARCODE,
+
          DD.BARCODE1,
+
          DD.GODENDO,
+
          DD.SERIA,
+
          DD.NDS,
+
          DD.SUM_NDSO,
+
          DD.SERT,
+
          DD.DATESERT,
+
          DD.KEMVSERT,
+
          DD.SDSERT,
+
          DD.REGN,
+
          DD.NGTD,
+
          DD.EDIZM,
+
          DD.NAME_ID,
+
          DD.IZG_ID,
+
          DD.COUNTRY_ID,
+
          DD.ORIG_CODE,
+
          DD.ORIG_NAME_ID,
+
          W.ORIG_IZG_ID,
+
          W.ORIG_COUNTRY_ID,
+
          DD.Z_ID,
+
          DD.SNAME,
+
          SIZG,
+
          SCOUNTRY,
+
          SORIG_NAME,
+
          SORIG_IZG,
+
          SORIG_COUNTRY,
+
          DD.INSERTDT,
+
          0,
+
          0,
+
          DD.DEP,
+
          W.BARCODE,
+
          DD.QUANT,
+
          SUM_DSC,
+
          null,
+
          0,
+
          P.PART_TYPE,
+
          DD.BASE_AGENT_ID,
+
          P.PACKET,
+
          0
+
  from VW_DOC_DETAIL_DELETED DD
+
  left join WARES W on DD.WARE_ID = W.ID
+
  left join PARTS P on DD.PART_ID = P.ID
+
  where DD.DOC_ID = :DOC_ID;
+
 
+
  /* Проводим */
+
  execute procedure PR_DOC_COMMIT(:O$DOC_ID, :SESSION_ID);
+
 
+
  update DOCS
+
  set COMMENTS = :COMMENTS || '(Дубль чека ID=' || cast(:DOC_ID as DM_TEXT) || ')',
+
      SUMM1 = :SUMM1,
+
      SUMM2 = :SUMM2,
+
      SUMM3 = :SUMM3,
+
      SUMM4 = :SUMM3,
+
      VSHIFT = :VSHIFT,
+
      DEVICE_NUM = :DEVICE_NUM,
+
      VNUM = :VNUM,
+
      BONUS = :BONUS,
+
      CAPTION = :CAPTION,
+
      SUMMA = :SUMMA,
+
      SUMMA_O = :SUMMA_O,
+
      COMMITDATE = :COMMITDATE
+
  where ID = :O$DOC_ID;
+
 
+
  if (abs((select abs(sum(SUMMA))
+
          from DOC_DETAIL
+
          where DOC_ID = :O$DOC_ID) - abs(:SUMMA)) > 0.01) then
+
  update DOC_DETAIL
+
  set SUMMA = SUMMA + SUM_DSC
+
  where DOC_ID = :O$DOC_ID;
+
 
+
  suspend;
+
end
+
 
+
/* Возвращаем режим как было */
+
update PARAMS
+
set PARAM_VALUE = :PARAM_VALUE
+
where PARAM_ID = 'RASHOD_MINUS';
+
  
 +
  while (:DOC_QUANT > i) do
 +
    begin
 +
      i = i + 1;
 +
      select DOC_ID from PR_NEWDOC(:DOC_TYPE, :AGENT_ID, :PARENT_ID, :DOCNUM, :DOCDATE, :SESSION_ID) into :O$DOC_ID; --Новый документ
 +
      if (:STATUS = 1) then --Детализация
 +
        INSERT INTO DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT, DISCOUNT,
 +
          SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE, BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT,
 +
          KEMVSERT, SDSERT, REGN, NGTD, EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID, ORIG_COUNTRY_ID, Z_ID,
 +
          SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT,
 +
          SUM_DSC, CUSTOMDRAW, STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
 +
        select dd.PARENT_ID, :O$DOC_ID, dd.PART_ID, dd.PART_PARENT_ID, 0, dd.PRICE, dd.NAC, dd.QUANT, dd.DISCOUNT, dd.SUMMA, dd.SUMMA_O,
 +
          dd.DCARD, dd.WARE_ID, dd.PRICE_O, dd.PRICE_Z, dd.PRICE_R, dd.BARCODE, dd.BARCODE1, dd.GODENDO, dd.SERIA, dd.NDS, dd.SUM_NDSO,
 +
          dd.SERT, dd.DATESERT, dd.KEMVSERT, dd.SDSERT, dd.REGN, dd.NGTD, dd.EDIZM, dd.NAME_ID, dd.IZG_ID, dd.COUNTRY_ID, dd.ORIG_CODE,
 +
          w.ORIG_NAME_ID, w.ORIG_IZG_ID, w.ORIG_COUNTRY_ID, w.Z_ID, dd.SNAME, dd.SIZG, dd.SCOUNTRY, dd.SORIG_NAME, dd.SORIG_IZG,
 +
          dd.SORIG_COUNTRY, dd.INSERTDT, 0, 0, dd.DEP, dd.BCODE_IZG, dd.HUMAN_QUANT, dd.SUM_DSC, Null, 0, dd.PART_TYPE, dd.BASE_AGENT_ID, dd.PACKET, 0
 +
        from vw_doc_detail dd
 +
          --join doc_detail dd2 on dd.part_id = dd2.part_id
 +
          left join wares w on dd.ware_id = w.id
 +
          where dd.doc_id = :DOC_ID;
 +
      else
 +
        insert into DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT, DISCOUNT,
 +
          SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE, BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT,
 +
          KEMVSERT, SDSERT, REGN, NGTD, EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID, ORIG_COUNTRY_ID, Z_ID,
 +
          SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT,
 +
          SUM_DSC, CUSTOMDRAW, STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
 +
        select dd.PARENT_ID, :O$DOC_ID, PART_ID, PART_PARENT_ID, 0, dd.PRICE, dd.NAC, dd.QUANT, DISCOUNT,
 +
          SUMMA, SUMMA_O, DCARD, dd.WARE_ID, dd.PRICE_O, dd.PRICE_Z, dd.PRICE_R, dd.BARCODE, dd.BARCODE1, dd.GODENDO, dd.SERIA, dd.NDS, dd.SUM_NDSO, dd.SERT, dd.DATESERT,
 +
          dd.KEMVSERT, dd.SDSERT, dd.REGN, dd.NGTD, dd.EDIZM, dd.NAME_ID, dd.IZG_ID, dd.COUNTRY_ID, dd.ORIG_CODE, dd.ORIG_NAME_ID, w.ORIG_IZG_ID, w.ORIG_COUNTRY_ID, dd.Z_ID,
 +
          dd.SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, dd.INSERTDT, 0, 0, dd.DEP, w.barcode, dd.QUANT,
 +
          SUM_DSC, Null, 0, p.PART_TYPE, dd.BASE_AGENT_ID, p.PACKET, 0
 +
        from vw_doc_detail_deleted dd
 +
        left join wares w on dd.ware_id = w.id
 +
        left join parts p on dd.part_id = p.id
 +
        where dd.doc_id = :DOC_ID;
 +
 
 +
      execute procedure pr_doc_commit(:O$DOC_ID,:SESSION_ID); --Проводим
 +
      update docs set comments = :COMMENTS||'(Дубль чека ID='||cast(:DOC_ID as DM_TEXT)||')', SUMM1 = :SUMM1, SUMM2 = :SUMM2, SUMM3 = :SUMM3,
 +
        SUMM4 = :SUMM3, VSHIFT = :VSHIFT, DEVICE_NUM = :DEVICE_NUM, VNUM = :VNUM, BONUS = :BONUS, CAPTION = :CAPTION, summa = :summa, summa_o = :summa_o, INSERTDT = :INSERTDT,  POSTDT = :POSTDT
 +
      where id = :O$DOC_ID;
 +
 
 +
      if (abs((select abs(sum(summa)) from doc_detail where doc_id = :O$DOC_ID)-abs(:summa)) > 0.01) then
 +
        update doc_detail set summa = summa+sum_dsc, INSERTDT = :INSERTDT where doc_id = :O$DOC_ID;
 +
 
 +
    suspend;
 +
    end
 +
  update params set param_value = :PARAM_VALUE where param_id = 'RASHOD_MINUS'; --Возвращаем режим как было
 
end^
 
end^
  
Строка 777: Строка 601:
 
/* Existing privileges on this procedure */
 
/* Existing privileges on this procedure */
  
 +
GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO PROCEDURE PR_DOCSCARE;
 
GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO SYSDBA;
 
GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO SYSDBA;
 +
 
</pre>
 
</pre>
  
Строка 785: Строка 611:
 
=Исправление расхождений из-за неправильного округления=
 
=Исправление расхождений из-за неправильного округления=
  
==Процедура для испраления расхождения путем исправления суммы скидки чека==
+
==Процедура для исправления расхождения путем исправления суммы скидки чека==
  
 
  <nowiki>
 
  <nowiki>
Строка 862: Строка 688:
 
  Теги: дублирование чека, дубль, задублировать чек
 
  Теги: дублирование чека, дубль, задублировать чек
  
 +
=Процедура создание пропущенных Z отчетов =
 +
<pre>
 +
SET TERM ^ ;
 +
 +
create or alter procedure PR_CREATE_Z (
 +
    VSHIFT DM_ID,
 +
    DEVICE_NUM DM_TEXT)
 +
returns (
 +
    VERB DM_TEXT1024)
 +
as
 +
declare variable SUMM1_B DM_DOUBLE;
 +
declare variable SUMM1_S DM_DOUBLE;
 +
declare variable SUMM1 DM_DOUBLE;
 +
declare variable SUMM2_B DM_DOUBLE;
 +
declare variable SUMM2 DM_DOUBLE;
 +
declare variable SUMM2_S DM_DOUBLE;
 +
declare variable SUMM3 DM_DOUBLE;
 +
declare variable SUMM4 DM_DOUBLE;
 +
declare variable VSHIFT_OLD DM_ID_NULL;
 +
declare variable AGENT_ID DM_ID_NULL;
 +
declare variable AUDIT_ID DM_ID_NULL;
 +
declare variable ZDATE DM_DATETIME;
 +
declare variable DOC_ID DM_ID;
 +
begin
 +
 +
  if ((select count(id) from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT and doc_type=13)>0) then
 +
  begin
 +
    verb='Уже существует Z отчет с номером смены ' ||:VSHIFT || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end
 +
 +
  if ((select count(id) from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT and doc_type=3)=0) then
 +
  begin
 +
    verb='Не найдены продажи для смены № ' ||:VSHIFT || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end
 +
 +
  vshift_old = VSHIFT-1;
 +
 +
  select summ4 from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:vshift_old and doc_type=13 into :summ4;
 +
 +
  if ((:summ4=0) and ((:vshift_old)>0)) then
 +
  begin
 +
    verb='Не найден предыдущий Z отчет с номером смены ' || :vshift_old || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end
 +
 +
  --Собрали продажи по смене
 +
  select COALESCE(sum(abs(summ1)),0),COALESCE(sum(abs(summ2)),0),max(AUDIT_ID),max(COMMITDATE),max(AGENT_ID)
 +
        from docs where doc_type =3 and DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT
 +
        into :summ1_s,:summ2_s,:AUDIT_ID,:ZDATE,:AGENT_ID;
 +
 +
/*  if (:summ1_s=0) then
 +
  begin
 +
    verb='Не найдены продажи за наличку в смене № ' || :vshift || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end*/
 +
 +
  --Собрали возвраты по смене
 +
  select COALESCE(sum(summ1),0),COALESCE(sum(summ2),0)
 +
        from docs where doc_type =9 and DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT
 +
        into :summ1_b,:summ2_b;
 +
 +
  --Собрали итоговые суммы
 +
  summ1 = :summ1_s-summ1_b;
 +
  summ2 = :summ1_s+:summ2_s;
 +
  summ3 = :summ2-(:summ1_b+:summ2_b);
 +
  summ4 = :summ4 + :summ2;
 +
 +
  --Пишем в базу строки
 +
  doc_id=gen_id(gen_docs_id,1);
 +
 +
  INSERT INTO docs (ID,PARENT_ID,DOC_TYPE,STATUS,AGENT_ID,RGUID,AUDIT_ID,DOCNUM,DOCDATE,vshift,vnum,DEVICE_NUM,SUMM1,SUMM2,SUMM3,SUMM4,SUMM5,SUMM6,SUMM7,SUMM8) values
 +
                  (:doc_ID,0,13,1,:AGENT_ID,replace(UUID_TO_CHAR( GEN_UUID()),'-',''),:AUDIT_ID,0,:ZDATE,:vshift,0,:DEVICE_NUM,:summ1,:summ2,:summ3,:summ4,null,null,null,null);
 +
  verb='Успешно создано запись№'|| :doc_id || ' в docs summ1=' || :summ1 || ' summ2='|| :summ2 || ' summ3='|| :summ3 || ' summ4='|| :summ4;
 +
  suspend;
 +
 +
  if (coalesce(summ1,0) <> 0) then
 +
  begin
 +
      INSERT INTO CASH_DOCS (PARENT_ID, DOC_TYPE, STATUS, AGENT_ID,CREATESESSION_ID, RGUID, OWNER, COMMITDATE, SUMMA, VSHIFT, DEVICE_NUM, DOC_ID)
 +
              VALUES (0, 1, 1, :AGENT_ID,:AUDIT_ID, replace(UUID_TO_CHAR( GEN_UUID()),'-',''), :AGENT_ID, :ZDATE, :summ1, :VSHIFT, :DEVICE_NUM, :doc_id);
 +
 +
      verb='Успешно создано запись в CASH_DOCS в сумме=' || :summ1;
 +
      suspend;
 +
  end
 +
end^
 +
 +
SET TERM ; ^
 +
 +
/* Следующие операторы GRANT сгенерированы автоматически */
 +
 +
GRANT SELECT,INSERT ON DOCS TO PROCEDURE PR_CREATE_Z;
 +
GRANT INSERT ON CASH_DOCS TO PROCEDURE PR_CREATE_Z;
 +
 +
/* Существующие привилегии на эту процедуру */
 +
 +
GRANT EXECUTE ON PROCEDURE PR_CREATE_Z TO SYSDBA;
 +
</pre>
 +
 +
==Как использовать==
 +
Нужно указать '''vshift''' и '''DEVICE_NUM''' продаж по котрым не создана зетка, процедура проверит есть ли продажи, есть ли существующая уже зетка и если все хорошо создаст запись в таблице docs и в таблице cash_docs.
 +
 +
Теги: создание зетки, Z, z-отчет, создать
  
 
=Автоматическое исправление отмененных чеков=
 
=Автоматическое исправление отмененных чеков=
Строка 1004: Строка 937:
 
GRANT EXECUTE ON PROCEDURE PR_CHECK_ZDOCS TO SYSDBA;
 
GRANT EXECUTE ON PROCEDURE PR_CHECK_ZDOCS TO SYSDBA;
 
</pre>
 
</pre>
 +
 +
* Устанавливаем триггер на закрытие смены '''DOCS_BIU0_CHECK_DOCS'''
 +
<pre>
 +
 +
/******************************************************************************/
 +
/***      Following SET SQL DIALECT is just for the Database Comparer      ***/
 +
/******************************************************************************/
 +
SET SQL DIALECT 3;
 +
 +
 +
SET TERM ^ ;
 +
 +
 +
 +
CREATE OR ALTER TRIGGER DOCS_BIU0_CHECK_DOCS FOR DOCS
 +
ACTIVE BEFORE INSERT OR UPDATE POSITION 999
 +
as
 +
 +
declare variable DEVICE_NUM DM_TEXT;
 +
declare variable VSHIFT DM_ID;
 +
declare variable COMMITDATE DM_DATETIME;
 +
declare variable ZSUMM1 DM_DOUBLE;
 +
declare variable ZSUMM2 DM_DOUBLE;
 +
declare variable ZSUMM3 DM_DOUBLE;
 +
declare variable ZSUMM4 DM_DOUBLE;
 +
declare variable CSUMM1 DM_DOUBLE;
 +
declare variable CSUMM2 DM_DOUBLE;
 +
declare variable CSUMM3 DM_DOUBLE;
 +
declare variable CSUMM4 DM_DOUBLE;
 +
declare variable VSUMM1 DM_DOUBLE;
 +
declare variable VSUMM2 DM_DOUBLE;
 +
declare variable VSUMM3 DM_DOUBLE;
 +
declare variable VSUMM4 DM_DOUBLE;
 +
declare variable HSUMM DM_DOUBLE;
 +
declare variable RASH_NAL DM_DOUBLE;
 +
declare variable RASH_BEZNAL DM_DOUBLE;
 +
declare variable DOC_ID DM_ID;
 +
declare variable OUT_DOC_ID DM_ID;
 +
 +
begin
 +
if ( (new.DOC_TYPE = 13) and
 +
      ((select cast(param_value||' 23:59:59' as dm_datetime) from params p where param_id = 'AUTO_BANCORRECTDATE') < new.commitdate) ) then
 +
  select DEVICE_NUM,
 +
        VSHIFT,
 +
        COMMITDATE,
 +
        ZSUMM1,
 +
        ZSUMM2,
 +
        ZSUMM3,
 +
        ZSUMM4,
 +
        CSUMM1,
 +
        CSUMM2,
 +
        CSUMM3,
 +
        CSUMM4,
 +
        VSUMM1,
 +
        VSUMM2,
 +
        VSUMM3,
 +
        VSUMM4,
 +
        HSUMM,
 +
        RASH_NAL,
 +
        RASH_BEZNAL,
 +
        DOC_ID,
 +
        OUT_DOC_ID
 +
  from PR_CHECK_ZDOCS(new.ID)
 +
  into :DEVICE_NUM,
 +
      :VSHIFT,
 +
      :COMMITDATE,
 +
      :ZSUMM1,
 +
      :ZSUMM2,
 +
      :ZSUMM3,
 +
      :ZSUMM4,
 +
      :CSUMM1,
 +
      :CSUMM2,
 +
      :CSUMM3,
 +
      :CSUMM4,
 +
      :VSUMM1,
 +
      :VSUMM2,
 +
      :VSUMM3,
 +
      :VSUMM4,
 +
      :HSUMM,
 +
      :RASH_NAL,
 +
      :RASH_BEZNAL,
 +
      :DOC_ID,
 +
      :OUT_DOC_ID;
 +
end
 +
^
 +
 +
 +
SET TERM ; ^
 +
 +
</pre>
 +
 +
=Копирование данных с одного чека на другой=
 +
==Создание процедуры в базе==
 +
<pre>
 +
SET TERM ^ ;
 +
 +
create or alter procedure PR_COPY_DATA_CHECK (
 +
    ID_MASTER DM_ID,
 +
    ID_RECIPIENT DM_ID)
 +
returns (
 +
    VERB DM_TEXT1024)
 +
as
 +
declare variable DOCDATE DM_DATETIME;
 +
declare variable INSERTDT DM_DATETIME;
 +
declare variable POSTDT DM_DATETIME;
 +
declare variable VSHIFT DM_ID;
 +
declare variable CREATER DM_ID;
 +
declare variable OWNER DM_ID;
 +
declare variable COMMITDATE DM_DATETIME;
 +
declare variable DEVICE_NUM DM_TEXT;
 +
declare variable DATEZ DM_DATE;
 +
declare variable DD_INSERTDT DM_DATETIME;
 +
declare variable DD_DOC_COMMITDATE DM_DATE;
 +
begin
 +
  if ((select count(id) from docs where id =:id_master)=0) then
 +
  begin
 +
    verb='Не найден чек c которого планируется скопировать данные ID=' ||:id_master|| ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end
 +
  if ((select count(id) from docs where id =:ID_RECIPIENT)=0) then
 +
  begin
 +
    verb='Не найден чек получателя данных от источеника ID=' ||:ID_RECIPIENT|| ', выполнить невозможно';
 +
    suspend;
 +
    exit;
 +
  end
 +
  select docdate, insertdt, postdt, vshift, creater, owner, commitdate,device_num, datez from docs where id =:id_master
 +
  into :docdate, :insertdt, :postdt, :vshift, :creater, :owner, :commitdate, :device_num, :datez;
 +
  update docs set
 +
    docdate=:docdate,
 +
    insertdt=:insertdt,
 +
    postdt=:postdt,
 +
    vshift=:vshift,
 +
    creater=:creater,
 +
    owner=:owner,
 +
    commitdate=:commitdate,
 +
    device_num=:device_num,
 +
    datez=:datez,
 +
    COMMENTS='Документ был изменен процедурой PR_COPY_DATA_CHECK '||CURRENT_TIMESTAMP||', данные взяты с чека='||:id_master
 +
  where id =:ID_RECIPIENT;
 +
  verb='Успешно обновили DOCS ID=' || :ID_RECIPIENT;
 +
  suspend;
 +
 +
  select first 1 insertdt, doc_commitdate from doc_detail where doc_id= :id_master into :DD_INSERTDT, :DD_DOC_COMMITDATE;
 +
  update doc_detail set
 +
    insertdt = :DD_INSERTDT,
 +
    doc_commitdate = :DD_DOC_COMMITDATE
 +
  where doc_id =:ID_RECIPIENT;
 +
  verb='Успешно обновили doc_detail doc_ID=' || :ID_RECIPIENT;
 +
  suspend;
 +
end^
 +
 +
SET TERM ; ^
 +
 +
COMMENT ON PARAMETER PR_COPY_DATA_CHECK.ID_MASTER IS
 +
'ИД чека источника';
 +
 +
COMMENT ON PARAMETER PR_COPY_DATA_CHECK.ID_RECIPIENT IS
 +
'ИД чека получателя';
 +
</pre>
 +
==Как использовать==
 +
В поле ID_MASTER вводим чек с которого будут скопированы данные, в поле ID_RECIPIENT вводим чек нна который будут скопированы данные. Если чеки не существуют процедура выдаст ошибку.
 +
Теги: создание зетки, Z, z-отчет, создать

Текущая версия на 11:31, 5 декабря 2024

Ситуации которые бывают с чеками

#1. ККМ при отбитии выдал ошибку и АРМ Кассир решил, что чек не прошел и отменил его, а на самом деле чек в ккм прошел и суммы обновились. Возможно, была незавершенка, в которой нажали отменить. В z-отчете сумма больше, чем по базе. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:

база - 0, банк - 1, ккм - 1

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

база - 1, банк - 1, ккм - 1


#2. В ккм чек прошел дважды, а по базе - 1. Скорей всего возникла ситуация, как в первом случае, вышла незавершенка, но в ней на этот раз нажали завершить. Если отбивали по безналу, то по терминалу этот чек тоже должен быть проведенный. В итоге:

база - 1, банк - 1, ккм - 2

Решение: сначала нужно продублировать чек. Получится:

база - 2, банк - 1, ккм - 2

Затем нужно сделать возврат с включенной ккм, но с несвязным терминалом. Получится:

база - 1, банк - 1, ккм - 1


#3. При оплате по безналу чек по банку не прошел, но в базе и ккм он записался как проведенный. Скорей всего была незавершенка на банковской операции, при которой нажали пропустить. В итоге:

база - 1, банк - 0, ккм - 1

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

база - 0, банк - 0, ккм - 0

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


#4. При оплает по безналу чек по банку прошел, а при проведении по ккм возникла незавершенка, в которой нажали пропустить. В результате чек по банку и по базе прошел, с остатков списался, а по ккм не прошел. Сумма по чекам будет больше, чем по z-отчету на сумму проблемного чека. Т.е.:

база - 1, банк - 1, ккм - 0

Решение: сначала нужно сделать возврат по безналу в режиме без ккм и несвязного терминала. Получится:

база - 0, банк - 1, ккм - 0

Затем нужно пробить чек по безналу с включенной ккм, но с несвязным терминалом. Ситуация разрешится:

база - 1, банк - 1, ккм - 1


#5. В ккм не настроено обнуление денежного ящика. Из-за этого в z-отчете сумма будет больше, чем по чекам на суммы предыдущих смен.
Решение: предыдущие z-отчеты в базе исправлять не нужно. Нужно изменить настройки ккм, чтобы таких ситуаций больше не было.


#6. В ккм неверное настроено округление. Ситуация характерна для Казахстана, т.к. именно там нужно делать данную настройку, о которой иногда забывают. В итоге z-отчеты расходятся с базой на копейки или несколько тенге.
Решение: предыдущие смены исправляются спомощью процедуры PR_REPAIR_DIFFERENCE_BY_DOC, которая расхождения в скидку. Чтобы в дальнейшем не было расхождений, нужно изменить настройки ккм.


#7. В ккм не фискализирована. В результате у смен не будет меняться номер и в программе будет неправильно определяться принадлежность чеков к смене. Из-за этого будут выходить расхождения.
Решение: предыдущие смены исправлять в программе не нужно. Нужно фискализировать ккм, чтобы таких ситуаций больше не было. При выгрузке в бухгалтерию номера смен редактируются вручную.


Поиск расхождений по чекам в базе

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


Процедура для клиентской базы

SET TERM ^ ;

create or alter procedure PR_GET_DIFFERENCE_BY_DOCS
returns (
    ZDATE DM_DATE,
    ZID DM_ID,
    RASH_NAL DM_DOUBLE,
    RASH_BEZNAL DM_DOUBLE,
    VNUM DM_TEXT,
    VSHIFT DM_TEXT,
    DEVICE_NUM DM_TEXT,
    DOC_ID DM_ID,
    NAL DM_DOUBLE,
    BEZNAL DM_DOUBLE,
    STATUS DM_TEXT,
    comment DM_TEXT,
    CMD DM_TEXT)
as
begin

for

-- для сортировки
select * from (

-- расхождения м/д чеками и z-отчетами
select
r.zdate as zdate,
r.zid as zid,
abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) as rash_nal,
abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) as rash_beznal,
r.vnum as vnum,
r.vshift as vshift,
r.device_num as device_num,
doc.id as doc_id,
doc.summ1 as nal,
doc.summ2 as beznal,
iif(doc.status is not null, iif(doc.status = 1, 'Не удален', 'Удален'), null) as status,
iif((doc.id is not null) or (abs(r.zsumm1 - (r.csumm1 + r.summ_cash))> 10) or (abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10) ,
  'execute procedure PR_CREATE_DUPLICATE_CHECK('||(cast(doc.id as VARCHAR(255)))||');',
  'execute procedure PR_REPAIR_DIFFERENCE_BY_DOC('||(cast(r.zid as VARCHAR(255)))||', '||(cast(coalesce(doc.summ1,0) as VARCHAR(255)))||');'
) as cmd,
iif((doc.id is not null) or (abs(r.zsumm1 - (r.csumm1 + r.summ_cash))> 10) or (abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10) ,
  'Проблема с чеком',
  'Неверное округление'
) as cmt
from (
  select
  cast(d.commitdate as dm_date) as zdate,
  d.id as zid,
  d.vnum as vnum,
  d.vshift as vshift,
  d.device_num as device_num,
  d.summ1 as zsumm1,
  d.summ2 as zsumm2,
  coalesce((select sum(-c1.summ1) from docs c1 where 1=1
    and c1.doc_type in (3,9)
    and c1.device_num=d.device_num
    and c1.vshift=d.vshift
    and c1.status=1
    and cast(c1.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as csumm1,
  coalesce((select sum(-(c2.summ1+c2.summ2)) from docs c2 where 1=1
    and c2.doc_type in (3)
    and c2.device_num=d.device_num
    and c2.vshift=d.vshift
    and c2.status=1
    and cast(c2.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as csumm2,
  coalesce((select sum(-h.summa) from cash_docs h where 1=1
    and h.doc_type in (1,2)
    and h.summa < d.summ1
    and h.device_num=d.device_num
    and h.vshift=d.vshift
    and h.status=1
    and cast(h.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as summ_cash
  from docs d
  where 1=1
  and d.doc_type=13
  and d.status=1
  and cast(d.commitdate as dm_date) between current_date - 365 and current_date + 1
  --order by d.commitdate desc
) r
left join docs doc on 1=1
  and doc.doc_type in (3)
  and doc.vshift=r.vshift
  and doc.device_num=r.device_num
  and cast(doc.commitdate as dm_date) between r.zdate -7 and r.zdate +7
  and (((abs(abs(doc.summ1) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash))) < 0.1 ) and (abs(doc.summ1)>0.01)) or ((abs(abs(doc.summ2) - abs(r.zsumm2 - (r.csumm2))) < 0.1 ) and abs(doc.summ2)>0.01))
where
(
  abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 0.01
    or
  abs(r.zsumm2 - r.csumm2) > 0.01
)

union all

-- Расходжение сумм м/д документами и детализацией
select
  cast(z.commitdate as dm_date) as zdate,
  z.id as zid,
  0.01 as rash_nal,
  0.01 as rash_beznal,
  z.vnum as zvnum,
  z.vshift as vshift,
  z.device_num as device_num,
  d.id as doc_id,
  d.summ1 as nal,
  d.summ2 as beznal,
  iif(d.status is not null, iif(d.status = 1, 'Не удален', 'Удален'), null) as status,
  'update docs d set d.summa = (select sum(dd.price*dd.quant + dd.sum_dsc) from doc_detail dd where dd.doc_id = d.id) where d.id = '||cast(d.id as dm_text)||'' as cmd,
  'Расходжение сумм м/д документами и детализацией' as cmt
  from docs d
  left join docs z on 1=1
  and z.doc_type=13
  and z.vshift=d.vshift
  and z.device_num=d.device_num
  and cast(z.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  where 1=1
  and d.doc_type in (1,2,20,3,9,6,4,11)
  and d.status = 1
  and abs(d.summa - (select sum(dd.price*dd.quant + dd.SUM_DSC) from doc_detail dd where dd.doc_id = d.id)) > 0.01
  and cast(d.commitdate as dm_date) between current_date - 365 and current_date + 1

) q order by q.zdate desc

into
  :zdate, :zid, :rash_nal, :rash_beznal, :vnum, :vshift, :device_num, :doc_id, :nal, :beznal, :status, :cmd, :comment
do
  suspend;

end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT ON DOCS TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON CASH_DOCS TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON DOC_DETAIL TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_GET_DIFFERENCE_BY_DOCS TO SYSDBA;

Процедура для сводной базы

 
SET SQL DIALECT 3;

DROP TABLE DIFFERENCE_BY_DOCS;

CREATE TABLE DIFFERENCE_BY_DOCS (
    CMT          DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    PROFILE_ID   DM_ID /* DM_ID = BIGINT NOT NULL */,
    SPROFILE     DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    ZDATE        DM_DATE /* DM_DATE = DATE */,
    ZID          DM_ID_NULL /* DM_ID_NULL = BIGINT */,
    RASH_NAL     DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
    RASH_BEZNAL  DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
    VNUM         DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    VSHIFT       DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    DEVICE_NUM   DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    DOC_ID       DM_ID_NULL /* DM_ID_NULL = BIGINT */,
    NAL          DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
    BEZNAL       DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
    STATUS       DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    CMD          DM_TEXT /* DM_TEXT = VARCHAR(250) */,
    DT           DM_DATETIME /* DM_DATETIME = TIMESTAMP */
);

SET TERM ^ ;

create or alter procedure PR_GET_DIFFERENCE_BY_DOCS (
    DAYS_AGO DM_ID = 31)
returns (
    CMT DM_TEXT,
    PROFILE_ID DM_ID,
    SPROFILE DM_TEXT,
    ZDATE DM_DATE,
    ZID DM_ID_NULL,
    RASH_NAL DM_DOUBLE,
    RASH_BEZNAL DM_DOUBLE,
    VNUM DM_TEXT,
    VSHIFT DM_TEXT,
    DEVICE_NUM DM_TEXT,
    DOC_ID DM_ID_NULL,
    NAL DM_DOUBLE,
    BEZNAL DM_DOUBLE,
    STATUS DM_TEXT,
    CMD DM_TEXT)
as
begin

delete from difference_by_docs;

for

select * from (

/* несхождение чеков и z-отчетов */
select
r.profile_id,
r.sprofile,
r.zdate,
r.zid,
round(abs(r.zsumm1 - (r.csumm1 + r.summ_cash)), 2) as rash_nal,
round(abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)), 2) as rash_beznal,
r.zvnum as vnum,
r.vshift as vshift,
r.device_num as device_num,
doc.id as doc_id,
round(doc.summ1, 2) as nal,
round(doc.summ2, 2) as beznal,
iif(doc.status is not null, iif(doc.status = 1, 'Не удален', 'Удален'), null) as status,
iif((doc.id is not null) or (abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10) or (abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10),
  'insert into g$tasks (PROFILE_ID,TASK_TYPE,CAPTION,data) values ('||r.profile_id||',0,''Дублирование чека '||(cast(doc.id as VARCHAR(255)))||''',''execute procedure PR_CREATE_DUPLICATE_CHECK('''''||(cast(doc.id as VARCHAR(255)))||''''');'');',
  'insert into g$tasks (PROFILE_ID,TASK_TYPE,CAPTION,data) values ('||r.profile_id||',0,''Исправление скидки чека'',''execute procedure PR_REPAIR_DIFFERENCE_BY_DOC ('''''||(cast(r.zid as VARCHAR(255)))||''''', '''''||(cast(coalesce(doc.summ1,0) as VARCHAR(255)))||''''');'');'
  ) as cmd,
iif((doc.id is not null) or (abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10) or (abs(r.zsumm2 - r.csumm2) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 10),
  'Проблема с чеком',
  'Неверное округление'
  )
as cmt
from (
  select
  d.g$profile_id as profile_id,
  (select g.caption from g$profiles g where g.id=d.g$profile_id) as sprofile,
  cast(d.commitdate as dm_date) as zdate,
  d.id as zid,
  d.vnum as zvnum,
  d.vshift as vshift,
  d.device_num as device_num,
  d.summ1 as zsumm1,
  d.summ2 as zsumm2,
  coalesce((select sum(-c1.summ1) from docs c1 where 1=1
    and c1.doc_type in (3,9)
    and c1.device_num=d.device_num
    and c1.vshift=d.vshift
    and c1.status=1
    and c1.g$profile_id=d.g$profile_id
    and cast(c1.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as csumm1,
  coalesce((select sum(-(c2.summ1+c2.summ2)) from docs c2 where 1=1
    and c2.doc_type in (3)
    and c2.device_num=d.device_num
    and c2.vshift=d.vshift
    and c2.status=1
    and c2.g$profile_id=d.g$profile_id
    and cast(c2.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as csumm2,
  coalesce((select sum(-h.summa) from cash_docs h where 1=1
    and h.doc_type in (1,2)
    and h.summa < d.summ1
    and h.device_num=d.device_num
    and h.vshift=d.vshift
    and h.status=1
    and h.g$profile_id=d.g$profile_id
    and cast(h.commitdate as dm_date) between cast(d.commitdate as dm_date) -7 and cast(d.commitdate as dm_date) +7
  ), 0) as summ_cash
  from docs d
  where 1=1
  and d.doc_type=13
  and d.status=1
  and cast(d.commitdate as dm_date) between current_date - :days_ago and current_date + 1
) r
left join docs doc on 1=1
  and doc.doc_type in (3)
  and doc.vshift=r.vshift
  and doc.device_num=r.device_num
  and doc.g$profile_id=r.profile_id
  and cast(doc.commitdate as dm_date) between r.zdate -7 and r.zdate +7
  and (((abs(abs(doc.summ1) - abs(r.zsumm1 - (r.csumm1 + r.summ_cash))) < 0.1 ) and (abs(doc.summ1)>0.01)) or ((abs(abs(doc.summ2) - abs(r.zsumm2 - (r.csumm2))) < 0.1 ) and abs(doc.summ2)>0.01))
where
(
  abs(r.zsumm1 - (r.csumm1 + r.summ_cash)) > 0.01
    or
  abs(r.zsumm2 - r.csumm2) > 0.01
)

union all

/* z-отчеты которые почему то со статусом -1 */
select
z.g$profile_id as profile_id,
(select g.caption from g$profiles g where g.id=z.g$profile_id) as sprofile,
cast(z.commitdate as dm_date) as zdate,
z.id as zid,
z.summ1 as rash_nal,
z.summ2 as rash_beznal,
z.vnum as vnum,
z.vshift as vshift,
z.device_num as device_num,
null as doc_id,
null as nal,
null as beznal,
null as status,
'insert into g$tasks (PROFILE_ID,TASK_TYPE,CAPTION,data) values ('||z.g$profile_id||',0,''Исправление z-отчета '||(cast(z.id as VARCHAR(255)))||''',''update docs set status=1 where id='||(cast(z.id as VARCHAR(255)))||';'');' as cmd,
'Неверный статус z-отчета' as cmt
from docs z
where 1=1
and z.doc_type=13
and z.status=-1
and (select count(*)
     from docs d
     where 1=1
     and d.doc_type=3
     and d.status=1
     and d.vshift=z.vshift
     and d.device_num=z.device_num
     and d.g$profile_id=z.g$profile_id
     and d.commitdate between cast(z.commitdate as dm_date) - 7 and cast(z.commitdate as dm_date) + 7
    )>0
and (select count(*)
     from docs d where 1=1
     and d.doc_type=13
     and d.status=1
     and d.vshift=z.vshift
     and d.device_num=z.device_num
     and d.g$profile_id=z.g$profile_id
     and d.commitdate between cast(z.commitdate as dm_date) - 7 and cast(z.commitdate as dm_date) + 7
    )=0
and z.commitdate between current_date - :days_ago and current_date + 2

union all

/* чеки без z-отчета */
select
d.g$profile_id as profile_id,
(select g.caption from g$profiles g where g.id=d.g$profile_id) as sprofile,
cast(d.commitdate as dm_date) as zdate,
null as zid,
null as rash_nal,
null as rash_beznal,
null as vnum,
d.vshift as vshift,
d.device_num as device_num,
null as doc_id,
null as nal,
null as beznal,
null as status,
'' as cmd,
cast(sum(c) as VARCHAR(255))||' чеков без z-отчета' as cmt
from (
  select
  count(r.id) as c,
  r.doc_type as doc_type,
  r.status as status,
  r.g$profile_id as g$profile_id,
  r.vshift as vshift,  
  r.device_num as device_num,
  cast(r.commitdate as dm_date) as commitdate
  from docs r
  where 1=1
  and r.doc_type=3
  and r.status=1
  and r.summa<>0
  and r.vnum is not null
  and r.device_num is not null
  and r.commitdate between current_date - :days_ago and current_date-1
  group by r.status, r.vshift, r.device_num, r.g$profile_id, r.doc_type, cast(r.commitdate as dm_date)
) d
where 1=1
and (select count(*)
     from docs z
     where 1=1
     and z.doc_type=13
     and z.status=1
     and z.vshift=d.vshift
     and z.device_num=d.device_num
     and z.g$profile_id=d.g$profile_id
     and z.commitdate between cast(d.commitdate as dm_date) - 7 and cast(d.commitdate as dm_date) + 7
    )=0
group by cast(d.commitdate as dm_date), d.device_num, d.vshift, d.g$profile_id

union all

/* Расходжение сумм м/д документами и детализацией */
select
  d.g$profile_id as profile_id,
  (select g.caption from g$profiles g where g.id=d.g$profile_id) as sprofile,
  cast(d.commitdate as dm_date) as zdate,
  d.id as zid,
  round(abs(d.summa - (select sum(dd.price*dd.quant + dd.SUM_DSC) from doc_detail dd where dd.doc_id = d.id)), 2) as rash_nal,
  null as rash_beznal,
  null as zvnum,
  null as vshift,
  null as device_num,
  d.id as doc_id,
  d.summ1 as nal,
  d.summ2 as beznal,
  iif(d.status is not null, iif(d.status = 1, 'Не удален', 'Удален'), null) as status,
  'insert into g$tasks (PROFILE_ID,TASK_TYPE,CAPTION,data) values ('||d.g$profile_id||',0,''Расходжение документа '||(cast(d.id as VARCHAR(255)))||''',''update docs d set d.summa = (select sum(dd.price*dd.quant + dd.sum_dsc) from doc_detail dd where dd.doc_id = d.id) where d.id='||(cast(d.id as VARCHAR(255)))||';'');' as cmd,
  'Расходжение сумм м/д документами и детализацией' as cmt
  from docs d
  where 1=1
  and d.doc_type in (1,2,20,3,9,6,4,11)
  and d.status = 1
  and abs(d.summa - (select sum(dd.price*dd.quant + dd.SUM_DSC) from doc_detail dd where dd.doc_id = d.id and dd.g$profile_id=d.g$profile_id)) > 0.01
  and cast(d.commitdate as dm_date) between current_date - :days_ago and current_date + 1
  and d.g$profile_id not in (57) /* аптеки удмуртии склад */

) q
where 1=1
and q.profile_id not in (100) /* сводная база */
and q.profile_id not in (2,3) /* фармаком тестовые профили */
and (select pr.dbsecurekey from g$profiles pr where pr.id=q.profile_id) is not null /* закрытые аптеки */
order by q.zdate desc

into
  :profile_id, :sprofile, :zdate, :zid, :rash_nal, :rash_beznal, :vnum, :vshift, :device_num, :doc_id, :nal, :beznal, :status, :cmd, :cmt
do
  begin
    insert into difference_by_docs (profile_id, sprofile, zdate, zid, rash_nal, rash_beznal, vnum, vshift, device_num, doc_id, nal, beznal, status, cmd, cmt, dt)
      values (:profile_id, :sprofile, :zdate, :zid, :rash_nal, :rash_beznal, :vnum, :vshift, :device_num, :doc_id, :nal, :beznal, :status, :cmd, :cmt, current_timestamp);
    /* suspend; */
  end
end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT,INSERT,DELETE ON DIFFERENCE_BY_DOCS TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON G$PROFILES TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON DOCS TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON CASH_DOCS TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;
GRANT SELECT ON DOC_DETAIL TO PROCEDURE PR_GET_DIFFERENCE_BY_DOCS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_GET_DIFFERENCE_BY_DOCS TO SYSDBA;

Исправление расхождений из-за отмененных чеков

Дублирование чека

Иногда возникает необходимость полностью задублировать чек в базе, при этом не проводя его ни по ККМ ни по банковскому терминалу. Для этого выполните скрипт ниже

Создание процедуры

 
SET TERM ^ ;

create or alter procedure PR_CREATE_DUPLICATE_CHECK (
    DOC_ID DM_ID,
    DOC_QUANT DM_ID = 1)
returns (
    O$DOC_ID DM_ID)
as
declare variable I integer;
declare variable DOC_TYPE DM_STATUS;
declare variable AGENT_ID DM_ID;
declare variable PARENT_ID DM_ID;
declare variable DOCNUM DM_TEXT;
declare variable DOCDATE DM_DATETIME;
declare variable SESSION_ID DM_ID;
declare variable PARAM_VALUE DM_TEXT1024;
declare variable COMMENTS DM_BLOBTEXT;
declare variable SUMM1 DM_DOUBLE;
declare variable SUMM2 DM_DOUBLE;
declare variable SUMM3 DM_DOUBLE;
declare variable SUMM4 DM_DOUBLE;
declare variable VSHIFT DM_ID;
declare variable DEVICE_NUM DM_TEXT;
declare variable VNUM DM_ID;
declare variable BONUS DM_DOUBLE;
declare variable CAPTION DM_TEXT;
declare variable STATUS DM_STATUS;
declare variable SUMMA DM_DOUBLE;
declare variable SUMMA_O DM_DOUBLE;
declare variable INSERTDT DM_DATETIME;
declare variable POSTDT DM_DATETIME;
begin
-------------------------------------------------------------
---- от 2017 04 11 ------------------------------------------
-------------------------------------------------------------

  i=0;
  --Включаем режим расход в минус, предварительно запоминая значение режима 1-Разрешен, 0-Запрещен
  select PARAM_VALUE from params where param_id = 'RASHOD_MINUS' into :PARAM_VALUE;
  update params set param_value = '1' where param_id = 'RASHOD_MINUS';

  select STATUS, DOC_TYPE, AGENT_ID, PARENT_ID, DOCNUM, DOCDATE, AUDIT_ID, coalesce(COMMENTS,''), SUMM1,SUMM2,SUMM3,SUMM4,VSHIFT,DEVICE_NUM,VNUM,BONUS,CAPTION, SUMMA, SUMMA_O, INSERTDT, POSTDT from docs where id = :DOC_ID into :STATUS, :DOC_TYPE, :AGENT_ID, :PARENT_ID, :DOCNUM, :DOCDATE, :SESSION_ID, :COMMENTS, :SUMM1,SUMM2,SUMM3,SUMM4,VSHIFT,DEVICE_NUM,VNUM,BONUS,CAPTION, :SUMMA, :SUMMA_O, :INSERTDT, :POSTDT;

  while (:DOC_QUANT > i) do
    begin
      i = i + 1;
      select DOC_ID from PR_NEWDOC(:DOC_TYPE, :AGENT_ID, :PARENT_ID, :DOCNUM, :DOCDATE, :SESSION_ID) into :O$DOC_ID; --Новый документ
      if (:STATUS = 1) then --Детализация
        INSERT INTO DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT, DISCOUNT,
          SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE, BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT,
          KEMVSERT, SDSERT, REGN, NGTD, EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID, ORIG_COUNTRY_ID, Z_ID,
          SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT,
          SUM_DSC, CUSTOMDRAW, STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
        select dd.PARENT_ID, :O$DOC_ID, dd.PART_ID, dd.PART_PARENT_ID, 0, dd.PRICE, dd.NAC, dd.QUANT, dd.DISCOUNT, dd.SUMMA, dd.SUMMA_O,
          dd.DCARD, dd.WARE_ID, dd.PRICE_O, dd.PRICE_Z, dd.PRICE_R, dd.BARCODE, dd.BARCODE1, dd.GODENDO, dd.SERIA, dd.NDS, dd.SUM_NDSO,
          dd.SERT, dd.DATESERT, dd.KEMVSERT, dd.SDSERT, dd.REGN, dd.NGTD, dd.EDIZM, dd.NAME_ID, dd.IZG_ID, dd.COUNTRY_ID, dd.ORIG_CODE,
          w.ORIG_NAME_ID, w.ORIG_IZG_ID, w.ORIG_COUNTRY_ID, w.Z_ID, dd.SNAME, dd.SIZG, dd.SCOUNTRY, dd.SORIG_NAME, dd.SORIG_IZG,
          dd.SORIG_COUNTRY, dd.INSERTDT, 0, 0, dd.DEP, dd.BCODE_IZG, dd.HUMAN_QUANT, dd.SUM_DSC, Null, 0, dd.PART_TYPE, dd.BASE_AGENT_ID, dd.PACKET, 0
        from vw_doc_detail dd
          --join doc_detail dd2 on dd.part_id = dd2.part_id
          left join wares w on dd.ware_id = w.id
          where dd.doc_id = :DOC_ID;
       else
         insert into DOC_DETAIL_ACTIVE (PARENT_ID, DOC_ID, PART_ID, PART_PARENT_ID, DOC_DETAIL_ID, PRICE, NAC, QUANT, DISCOUNT,
           SUMMA, SUMMA_O, DCARD, WARE_ID, PRICE_O, PRICE_Z, PRICE_R, BARCODE, BARCODE1, GODENDO, SERIA, NDS, SUM_NDSO, SERT, DATESERT,
           KEMVSERT, SDSERT, REGN, NGTD, EDIZM, NAME_ID, IZG_ID, COUNTRY_ID, ORIG_CODE, ORIG_NAME_ID, ORIG_IZG_ID, ORIG_COUNTRY_ID, Z_ID,
           SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, INSERTDT, KOEF, MOTHERPART_ID, DEP, BCODE_IZG, HUMAN_QUANT,
           SUM_DSC, CUSTOMDRAW, STATUS, PART_TYPE, BASE_AGENT_ID, PACKET, VPART_ID)
         select dd.PARENT_ID, :O$DOC_ID, PART_ID, PART_PARENT_ID, 0, dd.PRICE, dd.NAC, dd.QUANT, DISCOUNT,
           SUMMA, SUMMA_O, DCARD, dd.WARE_ID, dd.PRICE_O, dd.PRICE_Z, dd.PRICE_R, dd.BARCODE, dd.BARCODE1, dd.GODENDO, dd.SERIA, dd.NDS, dd.SUM_NDSO, dd.SERT, dd.DATESERT,
           dd.KEMVSERT, dd.SDSERT, dd.REGN, dd.NGTD, dd.EDIZM, dd.NAME_ID, dd.IZG_ID, dd.COUNTRY_ID, dd.ORIG_CODE, dd.ORIG_NAME_ID, w.ORIG_IZG_ID, w.ORIG_COUNTRY_ID, dd.Z_ID,
           dd.SNAME, SIZG, SCOUNTRY, SORIG_NAME, SORIG_IZG, SORIG_COUNTRY, dd.INSERTDT, 0, 0, dd.DEP, w.barcode, dd.QUANT,
           SUM_DSC, Null, 0, p.PART_TYPE, dd.BASE_AGENT_ID, p.PACKET, 0
         from vw_doc_detail_deleted dd
         left join wares w on dd.ware_id = w.id
         left join parts p on dd.part_id = p.id
         where dd.doc_id = :DOC_ID;
  
      execute procedure pr_doc_commit(:O$DOC_ID,:SESSION_ID); --Проводим
      update docs set comments = :COMMENTS||'(Дубль чека ID='||cast(:DOC_ID as DM_TEXT)||')', SUMM1 = :SUMM1, SUMM2 = :SUMM2, SUMM3 = :SUMM3,
        SUMM4 = :SUMM3, VSHIFT = :VSHIFT, DEVICE_NUM = :DEVICE_NUM, VNUM = :VNUM, BONUS = :BONUS, CAPTION = :CAPTION, summa = :summa, summa_o = :summa_o, INSERTDT = :INSERTDT,  POSTDT = :POSTDT
      where id = :O$DOC_ID;
  
      if (abs((select abs(sum(summa)) from doc_detail where doc_id = :O$DOC_ID)-abs(:summa)) > 0.01) then
        update doc_detail set summa = summa+sum_dsc, INSERTDT = :INSERTDT where doc_id = :O$DOC_ID;
  
     suspend;
    end
  update params set param_value = :PARAM_VALUE where param_id = 'RASHOD_MINUS'; --Возвращаем режим как было
end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT,UPDATE ON PARAMS TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT,UPDATE ON DOCS TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT EXECUTE ON PROCEDURE PR_NEWDOC TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT INSERT ON DOC_DETAIL_ACTIVE TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT ON VW_DOC_DETAIL TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT ON WARES TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT ON VW_DOC_DETAIL_DELETED TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT ON PARTS TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT EXECUTE ON PROCEDURE PR_DOC_COMMIT TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;
GRANT SELECT,UPDATE ON DOC_DETAIL TO PROCEDURE PR_CREATE_DUPLICATE_CHECK;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO PROCEDURE PR_DOCSCARE;
GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO SYSDBA;

Как использовать

Запустите процедуру, укажите ID чека продажи или возврата и кол-во дублей. Выполните процедуру, подтвердите транзакцию

Исправление расхождений из-за неправильного округления

Процедура для исправления расхождения путем исправления суммы скидки чека

SET TERM ^ ;

create or alter procedure PR_REPAIR_DIFFERENCE_BY_DOC (
    ZDOC_ID DM_ID,
    DIFFERENCE DM_DOUBLE)
returns (
    DOC_DETAIL_ID DM_ID,
    DOC_ID DM_ID,
    SUMMA DM_DOUBLE,
    TEST DM_DOUBLE,
    SUM_DSC DM_DOUBLE)
as
declare variable COMMITDATE DM_DATETIME;
declare variable VSHIFT DM_ID;
declare variable DEVICE_NUM DM_TEXT;
begin

  select z.commitdate, z.device_num, z.vshift from docs z where z.id=:zdoc_id into
    :commitdate, :device_num, :vshift;

  select first 1 d.id, d.summa, d.sum_dsc
  from docs d where 1=1
    and d.doc_type in (3)
    and d.device_num=:device_num
    and d.vshift=:vshift
    and d.status=1
    and cast(d.commitdate as dm_date) between cast(:commitdate as dm_date) -7 and cast(:commitdate as dm_date) +7
    and (abs(d.summa) - abs(d.sum_dsc) - abs(coalesce(:difference,0))) > 0.01
    order by abs(d.sum_dsc) desc
    into
      :doc_id, :summa, :sum_dsc;

  select first 1 dd.id from doc_detail dd where 1=1
    and dd.doc_id = :doc_id
    and (abs(dd.summa) - abs(dd.sum_dsc) - abs(coalesce(:difference,0))) > 0.01
    order by abs(dd.sum_dsc) desc
    into
      :doc_detail_id;

  if ((:doc_id is not null) and (:doc_detail_id is not null)) then
    begin
      update docs ud set
        ud.summa=ud.summa+coalesce(:difference,0),
        ud.summ1=ud.summ1+coalesce(:difference,0),
        ud.sum_dsc=ud.sum_dsc+coalesce(:difference,0)
      where ud.id=:doc_id;

      update doc_detail udd set
        udd.summa=udd.summa+coalesce(:difference,0),
        udd.sum_dsc=udd.sum_dsc+coalesce(:difference,0)
      where udd.id=:doc_detail_id;

    end
  suspend;
end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT,UPDATE ON DOCS TO PROCEDURE PR_REPAIR_DIFFERENCE_BY_DOC;
GRANT SELECT,UPDATE ON DOC_DETAIL TO PROCEDURE PR_REPAIR_DIFFERENCE_BY_DOC;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_REPAIR_DIFFERENCE_BY_DOC TO SYSDBA;
 

Как использовать

Нужно указать doc_id z-отчета по которому есть расхождение и сумму, на которую нужно это расхождение исправить.

Теги: дублирование чека, дубль, задублировать чек

Процедура создание пропущенных Z отчетов

SET TERM ^ ;

create or alter procedure PR_CREATE_Z (
    VSHIFT DM_ID,
    DEVICE_NUM DM_TEXT)
returns (
    VERB DM_TEXT1024)
as
declare variable SUMM1_B DM_DOUBLE;
declare variable SUMM1_S DM_DOUBLE;
declare variable SUMM1 DM_DOUBLE;
declare variable SUMM2_B DM_DOUBLE;
declare variable SUMM2 DM_DOUBLE;
declare variable SUMM2_S DM_DOUBLE;
declare variable SUMM3 DM_DOUBLE;
declare variable SUMM4 DM_DOUBLE;
declare variable VSHIFT_OLD DM_ID_NULL;
declare variable AGENT_ID DM_ID_NULL;
declare variable AUDIT_ID DM_ID_NULL;
declare variable ZDATE DM_DATETIME;
declare variable DOC_ID DM_ID;
begin

  if ((select count(id) from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT and doc_type=13)>0) then
   begin
    verb='Уже существует Z отчет с номером смены ' ||:VSHIFT || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
    suspend;
    exit;
   end

  if ((select count(id) from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT and doc_type=3)=0) then
   begin
    verb='Не найдены продажи для смены № ' ||:VSHIFT || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
    suspend;
    exit;
   end

  vshift_old = VSHIFT-1;

  select summ4 from docs where DEVICE_NUM=:DEVICE_NUM and VSHIFT=:vshift_old and doc_type=13 into :summ4;

  if ((:summ4=0) and ((:vshift_old)>0)) then
   begin
    verb='Не найден предыдущий Z отчет с номером смены ' || :vshift_old || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
    suspend;
    exit;
   end

  --Собрали продажи по смене
  select COALESCE(sum(abs(summ1)),0),COALESCE(sum(abs(summ2)),0),max(AUDIT_ID),max(COMMITDATE),max(AGENT_ID)
         from docs where doc_type =3 and DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT
         into :summ1_s,:summ2_s,:AUDIT_ID,:ZDATE,:AGENT_ID;

/*  if (:summ1_s=0) then
   begin
    verb='Не найдены продажи за наличку в смене № ' || :vshift || ' для ККМ № '|| :DEVICE_NUM || ', выполнить невозможно';
    suspend;
    exit;
   end*/

  --Собрали возвраты по смене
  select COALESCE(sum(summ1),0),COALESCE(sum(summ2),0)
         from docs where doc_type =9 and DEVICE_NUM=:DEVICE_NUM and VSHIFT=:VSHIFT
         into :summ1_b,:summ2_b;

  --Собрали итоговые суммы
  summ1 = :summ1_s-summ1_b;
  summ2 = :summ1_s+:summ2_s;
  summ3 = :summ2-(:summ1_b+:summ2_b);
  summ4 = :summ4 + :summ2;

  --Пишем в базу строки
  doc_id=gen_id(gen_docs_id,1);

  INSERT INTO docs (ID,PARENT_ID,DOC_TYPE,STATUS,AGENT_ID,RGUID,AUDIT_ID,DOCNUM,DOCDATE,vshift,vnum,DEVICE_NUM,SUMM1,SUMM2,SUMM3,SUMM4,SUMM5,SUMM6,SUMM7,SUMM8) values
                   (:doc_ID,0,13,1,:AGENT_ID,replace(UUID_TO_CHAR( GEN_UUID()),'-',''),:AUDIT_ID,0,:ZDATE,:vshift,0,:DEVICE_NUM,:summ1,:summ2,:summ3,:summ4,null,null,null,null);
  verb='Успешно создано запись№'|| :doc_id || ' в docs summ1=' || :summ1 || ' summ2='|| :summ2 || ' summ3='|| :summ3 || ' summ4='|| :summ4;
  suspend;

  if (coalesce(summ1,0) <> 0) then
  begin
      INSERT INTO CASH_DOCS (PARENT_ID, DOC_TYPE, STATUS, AGENT_ID,CREATESESSION_ID, RGUID, OWNER, COMMITDATE, SUMMA, VSHIFT, DEVICE_NUM, DOC_ID)
               VALUES (0, 1, 1, :AGENT_ID,:AUDIT_ID, replace(UUID_TO_CHAR( GEN_UUID()),'-',''), :AGENT_ID, :ZDATE, :summ1, :VSHIFT, :DEVICE_NUM, :doc_id);

      verb='Успешно создано запись в CASH_DOCS в сумме=' || :summ1;
      suspend;
  end
end^

SET TERM ; ^

/* Следующие операторы GRANT сгенерированы автоматически */

GRANT SELECT,INSERT ON DOCS TO PROCEDURE PR_CREATE_Z;
GRANT INSERT ON CASH_DOCS TO PROCEDURE PR_CREATE_Z;

/* Существующие привилегии на эту процедуру */

GRANT EXECUTE ON PROCEDURE PR_CREATE_Z TO SYSDBA;

Как использовать

Нужно указать vshift и DEVICE_NUM продаж по котрым не создана зетка, процедура проверит есть ли продажи, есть ли существующая уже зетка и если все хорошо создаст запись в таблице docs и в таблице cash_docs.

Теги: создание зетки, Z, z-отчет, создать

Автоматическое исправление отмененных чеков

  • Устанавливаем в клиентской базе процедуру PR_CREATE_DUPLICATE_CHECK, описанную выше.
  • Устанавливаем процедуру PR_CHECK_ZDOCS
SET TERM ^ ;

create or alter procedure PR_CHECK_ZDOCS (
    ZDOC_ID DM_ID,
    STATUS integer = -1)
returns (
    DEVICE_NUM DM_TEXT,
    VSHIFT DM_ID,
    COMMITDATE DM_DATETIME,
    ZSUMM1 DM_DOUBLE,
    ZSUMM2 DM_DOUBLE,
    ZSUMM3 DM_DOUBLE,
    ZSUMM4 DM_DOUBLE,
    CSUMM1 DM_DOUBLE,
    CSUMM2 DM_DOUBLE,
    CSUMM3 DM_DOUBLE,
    CSUMM4 DM_DOUBLE,
    VSUMM1 DM_DOUBLE,
    VSUMM2 DM_DOUBLE,
    VSUMM3 DM_DOUBLE,
    VSUMM4 DM_DOUBLE,
    HSUMM DM_DOUBLE,
    RASH_NAL DM_DOUBLE,
    RASH_BEZNAL DM_DOUBLE,
    DOC_ID DM_ID,
    OUT_DOC_ID DM_ID)
as
begin
 /* данные z-отчету */
 select DZ.DEVICE_NUM,
        DZ.VSHIFT,
        DZ.COMMITDATE,
        coalesce(DZ.SUMM1, 0),
        coalesce(DZ.SUMM2, 0),
        coalesce(DZ.SUMM3, 0),
        coalesce(DZ.SUMM4, 0)
 from DOCS DZ
 where 1 = 1
       and DZ.ID = :ZDOC_ID
       and DZ.DOC_TYPE in (13)
 into :DEVICE_NUM,
      :VSHIFT,
      :COMMITDATE,
      :ZSUMM1,
      :ZSUMM2,
      :ZSUMM3,
      :ZSUMM4;

 /* суммы по чекам */
 select coalesce(-sum(DC.SUMM1), 0),
        coalesce(-sum(DC.SUMM2), 0),
        coalesce(-sum(DC.SUMM3), 0),
        coalesce(-sum(DC.SUMM4), 0)
 from DOCS DC
 where 1 = 1
       and DC.VSHIFT = :VSHIFT
       and DC.DEVICE_NUM = :DEVICE_NUM
       and DC.DOC_TYPE in (3)
       and DC.STATUS = 1
       and cast(DC.COMMITDATE as DM_DATE) between cast(:COMMITDATE as DM_DATE) - 7 and cast(:COMMITDATE as DM_DATE) + 7
 into :CSUMM1,
      :CSUMM2,
      :CSUMM3,
      :CSUMM4;

 /* суммы по возвратам */
 select coalesce(sum(DV.SUMM1), 0),
        coalesce(sum(DV.SUMM2), 0),
        coalesce(sum(DV.SUMM3), 0),
        coalesce(sum(DV.SUMM4), 0)
 from DOCS DV
 where 1 = 1
       and DV.VSHIFT = :VSHIFT
       and DV.DEVICE_NUM = :DEVICE_NUM
       and DV.DOC_TYPE in (9)
       and DV.STATUS = 1
       and cast(DV.COMMITDATE as DM_DATE) between cast(:COMMITDATE as DM_DATE) - 7 and cast(:COMMITDATE as DM_DATE) + 7
 into :VSUMM1,
      :VSUMM2,
      :VSUMM3,
      :VSUMM4;

 /* суммы по документам кассы*/
 select coalesce(-sum(H.SUMMA), 0)
 from CASH_DOCS H
 where 1 = 1
       and H.VSHIFT = :VSHIFT
       and H.DEVICE_NUM = :DEVICE_NUM
       and H.DOC_TYPE in (1, 2)
       and H.STATUS = 1
       and H.SUMMA < :ZSUMM1 /* чтобы z-отчеты не попали */
       and cast(H.COMMITDATE as DM_DATE) between cast(:COMMITDATE as DM_DATE) - 7 and cast(:COMMITDATE as DM_DATE) + 7
 into :HSUMM;

 RASH_NAL = :ZSUMM1 - (:CSUMM1 - :VSUMM1 + :HSUMM);
 RASH_BEZNAL = :ZSUMM3 - (:CSUMM1 + :CSUMM2 - :VSUMM1 - :VSUMM2) - :RASH_NAL;

 /*
 summ1 - наличность (ПРОДАЖИ_НАЛ - ВОЗВРАТЫ_НАЛ + ВНЕСЕНИЯ - ИЗЪЯТИЯ)
 summ2 - сменный итог (ПРОДАЖИ_ВСЕ_ВИДЫ_ОПЛАТ)
 summ3 - выручка (ПРОДАЖИ_ВСЕ_ВИДЫ_ОПЛАТ - ВОЗВРАТЫ_ВСЕ_ВИДЫ_ОПЛАТ)
 */

 if ((:RASH_NAL > 0.1) or (:RASH_BEZNAL > 0.1)) then
  select first 1 DS.ID
  from DOCS DS
  where 1 = 1
        and DS.VSHIFT = :VSHIFT
        and DS.DEVICE_NUM = :DEVICE_NUM
        and DS.DOC_TYPE in (3)
        and DS.STATUS = :STATUS
        and cast(DS.COMMITDATE as DM_DATE) between cast(:COMMITDATE as DM_DATE) - 7 and cast(:COMMITDATE as DM_DATE) + 7
        and ((abs(DS.SUMM1 + :RASH_NAL) < 1
        and abs(DS.SUMM1) > 0.1) or (abs(DS.SUMM2 + :RASH_BEZNAL) < 1
        and abs(DS.SUMM2) > 0.1))
  into :DOC_ID;

 if (:DOC_ID is not null) then
  select O$DOC_ID
  from PR_CREATE_DUPLICATE_CHECK(:DOC_ID, 1)
  into :OUT_DOC_ID;

 suspend;
end^

SET TERM ; ^

/* Following GRANT statetements are generated automatically */

GRANT SELECT ON DOCS TO PROCEDURE PR_CHECK_ZDOCS;
GRANT SELECT ON CASH_DOCS TO PROCEDURE PR_CHECK_ZDOCS;
GRANT EXECUTE ON PROCEDURE PR_CREATE_DUPLICATE_CHECK TO PROCEDURE PR_CHECK_ZDOCS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_CHECK_ZDOCS TO SYSDBA;
  • Устанавливаем триггер на закрытие смены DOCS_BIU0_CHECK_DOCS

/******************************************************************************/
/***      Following SET SQL DIALECT is just for the Database Comparer       ***/
/******************************************************************************/
SET SQL DIALECT 3;


SET TERM ^ ;



CREATE OR ALTER TRIGGER DOCS_BIU0_CHECK_DOCS FOR DOCS
ACTIVE BEFORE INSERT OR UPDATE POSITION 999
as

declare variable DEVICE_NUM DM_TEXT;
declare variable VSHIFT DM_ID;
declare variable COMMITDATE DM_DATETIME;
declare variable ZSUMM1 DM_DOUBLE;
declare variable ZSUMM2 DM_DOUBLE;
declare variable ZSUMM3 DM_DOUBLE;
declare variable ZSUMM4 DM_DOUBLE;
declare variable CSUMM1 DM_DOUBLE;
declare variable CSUMM2 DM_DOUBLE;
declare variable CSUMM3 DM_DOUBLE;
declare variable CSUMM4 DM_DOUBLE;
declare variable VSUMM1 DM_DOUBLE;
declare variable VSUMM2 DM_DOUBLE;
declare variable VSUMM3 DM_DOUBLE;
declare variable VSUMM4 DM_DOUBLE;
declare variable HSUMM DM_DOUBLE;
declare variable RASH_NAL DM_DOUBLE;
declare variable RASH_BEZNAL DM_DOUBLE;
declare variable DOC_ID DM_ID;
declare variable OUT_DOC_ID DM_ID;

begin
 if ( (new.DOC_TYPE = 13) and
      ((select cast(param_value||' 23:59:59' as dm_datetime) from params p where param_id = 'AUTO_BANCORRECTDATE') < new.commitdate) ) then
  select DEVICE_NUM,
         VSHIFT,
         COMMITDATE,
         ZSUMM1,
         ZSUMM2,
         ZSUMM3,
         ZSUMM4,
         CSUMM1,
         CSUMM2,
         CSUMM3,
         CSUMM4,
         VSUMM1,
         VSUMM2,
         VSUMM3,
         VSUMM4,
         HSUMM,
         RASH_NAL,
         RASH_BEZNAL,
         DOC_ID,
         OUT_DOC_ID
  from PR_CHECK_ZDOCS(new.ID)
  into :DEVICE_NUM,
       :VSHIFT,
       :COMMITDATE,
       :ZSUMM1,
       :ZSUMM2,
       :ZSUMM3,
       :ZSUMM4,
       :CSUMM1,
       :CSUMM2,
       :CSUMM3,
       :CSUMM4,
       :VSUMM1,
       :VSUMM2,
       :VSUMM3,
       :VSUMM4,
       :HSUMM,
       :RASH_NAL,
       :RASH_BEZNAL,
       :DOC_ID,
       :OUT_DOC_ID;
end
^


SET TERM ; ^

Копирование данных с одного чека на другой

Создание процедуры в базе

SET TERM ^ ;

create or alter procedure PR_COPY_DATA_CHECK (
    ID_MASTER DM_ID,
    ID_RECIPIENT DM_ID)
returns (
    VERB DM_TEXT1024)
as
declare variable DOCDATE DM_DATETIME;
declare variable INSERTDT DM_DATETIME;
declare variable POSTDT DM_DATETIME;
declare variable VSHIFT DM_ID;
declare variable CREATER DM_ID;
declare variable OWNER DM_ID;
declare variable COMMITDATE DM_DATETIME;
declare variable DEVICE_NUM DM_TEXT;
declare variable DATEZ DM_DATE;
declare variable DD_INSERTDT DM_DATETIME;
declare variable DD_DOC_COMMITDATE DM_DATE;
begin
  if ((select count(id) from docs where id =:id_master)=0) then
   begin
    verb='Не найден чек c которого планируется скопировать данные ID=' ||:id_master|| ', выполнить невозможно';
    suspend;
    exit;
   end
  if ((select count(id) from docs where id =:ID_RECIPIENT)=0) then
   begin
    verb='Не найден чек получателя данных от источеника ID=' ||:ID_RECIPIENT|| ', выполнить невозможно';
    suspend;
    exit;
   end
  select docdate, insertdt, postdt, vshift, creater, owner, commitdate,device_num, datez from docs where id =:id_master
  into :docdate, :insertdt, :postdt, :vshift, :creater, :owner, :commitdate, :device_num, :datez;
  update docs set
    docdate=:docdate,
    insertdt=:insertdt,
    postdt=:postdt,
    vshift=:vshift,
    creater=:creater,
    owner=:owner,
    commitdate=:commitdate,
    device_num=:device_num,
    datez=:datez,
    COMMENTS='Документ был изменен процедурой PR_COPY_DATA_CHECK '||CURRENT_TIMESTAMP||', данные взяты с чека='||:id_master
  where id =:ID_RECIPIENT;
  verb='Успешно обновили DOCS ID=' || :ID_RECIPIENT;
  suspend;

  select first 1 insertdt, doc_commitdate from doc_detail where doc_id= :id_master into :DD_INSERTDT, :DD_DOC_COMMITDATE;
  update doc_detail set
    insertdt = :DD_INSERTDT,
    doc_commitdate = :DD_DOC_COMMITDATE
  where doc_id =:ID_RECIPIENT;
  verb='Успешно обновили doc_detail doc_ID=' || :ID_RECIPIENT;
  suspend;
end^

SET TERM ; ^

COMMENT ON PARAMETER PR_COPY_DATA_CHECK.ID_MASTER IS
'ИД чека источника';

COMMENT ON PARAMETER PR_COPY_DATA_CHECK.ID_RECIPIENT IS
'ИД чека получателя';

Как использовать

В поле ID_MASTER вводим чек с которого будут скопированы данные, в поле ID_RECIPIENT вводим чек нна который будут скопированы данные. Если чеки не существуют процедура выдаст ошибку. Теги: создание зетки, Z, z-отчет, создать