Установка НДС 20%

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

Как это работает?

  • Клиент до 2019 г. должен прошить ККМ новой версией прошивки;
  • 31.12.2018г. или ранее, кассиры должны закрыть смену в обязательном порядке;
  • В ночь на 01.01.2019 ККМ автоматически переключит ставки 18% на 20%, при этом номера секций/отделов не изменятся, изменится только ставка для них;
  • При открытии смены в 2019 году новые настройки вступят в силу;
  • После обновления ПО Стандарт-Н, инструкцию см. ниже, будут запрещены:
    • любые манипуляции с НДС 20%, до НГ 2019;
    • любые манипуляции с НДС 18%, после НГ 2019, кроме корректировок;
  • При попытке продать товар с НДС 18% после 01.01.2019 будет создан в фоновом режиме, автоматически, документ корректировки с НДС 18% на НДС 20%, при этом, по необходимости, ставки НДС будут добавлены автоматически, если это не запрещено в программе;
  • Аналогично работают все документы расхода;

Пример письма клиенту

Уважаемый ____, прошу довести аптекам, что с нового года ККМ автоматически вместо НДС 18% будут печатать НДС 20%, для перевода, нужно ОБЯЗАТЕЛЬНО закрыть смену в старом году. 
Не должно быть переходящих смен.
С нового года будет заблокировано поступление в программу документов с НДС 18%, поэтому просьба принять накладные заранее.

Добавить отделы через скрипт или вручную (таблица DEPS)

INSERT INTO DEPS (ID, CAPTION, NDS, NDSR, STATUS, D$UUID, D$SRVUPDDT)
          VALUES (9, 'НДС 20%', 20, 20, 0, '80174FDE-A792-4DD0-B6E2-F4680D0CB9C4', '2000-01-01 00:00:00');
INSERT INTO DEPS (ID, CAPTION, NDS, NDSR, STATUS, D$UUID, D$SRVUPDDT)
          VALUES (10, 'опт 0% розн 20%', 0, 20, 0, 'F7EEF1A1-35A6-40C2-841D-E02A72CBDBA4', '2000-01-01 00:00:00');
INSERT INTO DEPS (ID, CAPTION, NDS, NDSR, STATUS, D$UUID, D$SRVUPDDT)
          VALUES (11, 'опт 18% розн 20%', 18, 20, 0, '640BA652-CC81-43C0-B6FB-77DD9A51BDE5', '2000-01-01 00:00:00');
INSERT INTO DEPS (ID, CAPTION, NDS, NDSR, STATUS, D$UUID, D$SRVUPDDT)
          VALUES (12, 'опт 10% розн 20%', 10, 20, 0, '2BB889D7-A7C3-440E-B1D3-37647E0980D1', '2000-01-01 00:00:00');

Выполнить скрипт

CREATE EXCEPTION EX_NODOC 'Не удалось создать документ корректировки';
CREATE EXCEPTION EX_NODEP 'Не найден отдел';
CREATE EXCEPTION EX_NOPART 'Не удалось добавить партию в корректировку';
CREATE EXCEPTION EX_NDS20 'Запрет установки НДС 20% до 2019';
CREATE EXCEPTION EX_NDS18 'Запрет установки NDS 18% после 2019';


SET TERM ^ ;

create or alter procedure PR_HASNDS (
    DOC_ID DM_ID,
    NDSR DM_STATUS)
returns (
    HASNDS DM_STATUS)
as
begin
  hasnds = 0;
  if ( exists(select first 1 dda.id from doc_detail_active dda
    left join parts p on dda.part_id = p.id
    left join deps dep on iif(p.id > 0, p.dep, dda.dep) = dep.id
    where dda.doc_id = :doc_id and dep.ndsr = :ndsr) )
  then hasnds = 1;
  suspend;
end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT SELECT ON DOC_DETAIL_ACTIVE TO PROCEDURE PR_HASNDS;
GRANT SELECT ON PARTS TO PROCEDURE PR_HASNDS;
GRANT SELECT ON DEPS TO PROCEDURE PR_HASNDS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_HASNDS TO SYSDBA;



SET TERM ^ ;

create or alter procedure PR_GET_DEP (
    NDS DM_STATUS,
    NDSR DM_STATUS)
returns (
    ID DM_ID)
as
begin

  select first 1 id from deps where nds = :nds and ndsr = :ndsr into :id;

  if (id is null) then
  begin
    --exception EX_NODEP;
    id = (select max(id)+1 from deps);
    insert into deps (id, nds, ndsr) values (:id, :nds, :ndsr);
  end

  suspend;
end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT SELECT,INSERT ON DEPS TO PROCEDURE PR_GET_DEP;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_GET_DEP TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_GET_DEP TO SYSDBA;



SET TERM ^ ;

create or alter procedure PR_CORRECTPART_NDS (
    DOC_ID type of DM_ID,
    PART_ID type of DM_ID,
    QUANT type of DM_DOUBLE,
    DONTCHECKQUANT DM_STATUS = null)
returns (
    ID type of DM_ID,
    MSG DM_TEXT)
as
declare variable NAC type of DM_DOUBLE;
declare variable PARENT_ID type of DM_ID;
begin
  if (QUANT < 0) then
    QUANT = 0;
  select ID, MSG from PR_RASHODPART(:DOC_ID, :PART_ID, :QUANT, null, null, :dontcheckquant, null, 1)
  into :PARENT_ID, :MSG;
  if (PARENT_ID <= 0) then
  begin
    ID = PARENT_ID;
    suspend;
    exit;
    --exception EX_RASHOD_ERROR;
  end
  select ID from DOC_DETAIL_ACTIVE where DOC_ID = :DOC_ID and
        PARENT_ID = :PARENT_ID and
        PART_ID = 0
  into ID;
  if (ID is null) then
  begin
    ID = gen_id(GEN_DOC_DETAIL_ACTIVE_ID, 1);
    insert into DOC_DETAIL_ACTIVE (ID, PARENT_ID, DOC_ID, PART_ID, QUANT, NAC, KOEF, MOTHERPART_ID)
    values (:ID, :PARENT_ID, :DOC_ID, :PART_ID, :QUANT, :NAC, 0, :PART_ID);
    update DOC_DETAIL_ACTIVE set PART_ID = 0 where ID = :ID;
    insert into GROUP_DETAIL (GROUP_ID, PARENT_ID, GROUPTABLE_ID, GROUPTABLE)
    select GROUP_ID, 0, :ID, 'DOC_DETAIL_ACTIVE' from GROUP_DETAIL where GROUPTABLE_ID = :PART_ID and
          GROUPTABLE = 'PARTS';
  end
  else
  begin
    update DOC_DETAIL_ACTIVE set QUANT = :QUANT,
                                 SUMMA = :QUANT * PRICE,
                                 SUMMA_O = :QUANT * PRICE_O,
                                 SUM_NDSO = round((:QUANT * PRICE_O) * NDS / (100 + NDS), 2),
                                 SUM_NDSR = (:QUANT * PRICE) * (select D.NDSR from DEPS D where D.ID = DEP) / (100 + (select D.NDSR from DEPS D where D.ID = DEP)) 
    where ID = :ID;
  end
  suspend;
end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT EXECUTE ON PROCEDURE PR_RASHODPART TO PROCEDURE PR_CORRECTPART_NDS;
GRANT SELECT,INSERT,UPDATE ON DOC_DETAIL_ACTIVE TO PROCEDURE PR_CORRECTPART_NDS;
GRANT SELECT,INSERT ON GROUP_DETAIL TO PROCEDURE PR_CORRECTPART_NDS;
GRANT SELECT ON DEPS TO PROCEDURE PR_CORRECTPART_NDS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_CORRECTPART_NDS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_CORRECTPART_NDS TO SYSDBA;


SET TERM ^ ;

create or alter procedure PR_AUTO_PART_CORRECT (
    DOC_ID DM_ID,
    SESSION_ID DM_ID)
as
declare variable DDA_ID DM_ID_NULL;
declare variable QUANT DM_DOUBLE;
declare variable PART_ID DM_ID_NULL;
declare variable DOC_ID_CORRECT DM_ID;
declare variable DEP_ID DM_ID_NULL;
declare variable NDS DM_STATUS;
declare variable PART_ID_NEW DM_ID_NULL;
declare variable ERROR_MSG DM_TEXT;
begin

  DOC_ID_CORRECT = 0;
  error_msg = '';

  select doc_id from pr_newdoc(7, -1, 0, null, null, :session_id) into :DOC_ID_CORRECT;
  if (DOC_ID_CORRECT = 0) then
  begin
    exception EX_NODOC;
    --error_msg = 'Не удалось создать документ корректировки.';
    --suspend;
    --exit;
  end

  for
    select dda.part_id, max(w.quant), max(d.nds)
    from doc_detail_active dda
     left join warebase w on dda.part_id = w.part_id
     left join parts p on dda.part_id = p.id
     left join deps d on p.dep = d.id
    where dda.doc_id = :doc_id and d.ndsr = 18
    group by dda.part_id
  into :part_id, :quant, :nds
  do
  begin
    if (:quant is null) then select sum(quant) from doc_detail where part_id = :part_id into :quant;
    if (:quant > 0.001) then
    begin
      dda_id = 0;
      select id from pr_correctpart_nds(:DOC_ID_CORRECT,:part_id,:quant,1) into :DDA_ID;
      if (dda_id > 0) then
          update doc_detail_active set dep = (select id from PR_GET_DEP(:nds, 20)) where id=:dda_id;
      else exception EX_NOPART; --error_msg = error_msg || ' Не удалось добавить партию ' || :part_id || ' в документ корретировки ' || DOC_ID_CORRECT;


    end

  end

  execute procedure pr_doc_commit(:DOC_ID_CORRECT, :session_id);

  for
    select p.id, p.motherpart_id from doc_detail dd left join parts p on dd.part_id = p.id where dd.doc_id = :DOC_ID_CORRECT into :part_id_new, :part_id
  do
    update doc_detail_active set part_id = :part_id_new where part_id = :part_id and doc_id = :doc_id;

  --suspend;
end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT EXECUTE ON PROCEDURE PR_NEWDOC TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT,UPDATE ON DOC_DETAIL_ACTIVE TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON WAREBASE TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON PARTS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON DEPS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON DOC_DETAIL TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_CORRECTPART_NDS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_GET_DEP TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_DOC_COMMIT TO PROCEDURE PR_AUTO_PART_CORRECT;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_AUTO_PART_CORRECT TO SYSDBA;

Исправить PR_DOC_COMMIT

перед строкой

if (base_type = 4) then execute procedure pr_doc_virtual_commit(:doc_id);

добавить блок

  if ( current_date >= '01.01.2019' and base_type = 2 and (select hasnds from PR_HASNDS(:doc_id, 18)) > 0 ) then
    execute procedure PR_AUTO_PART_CORRECT(:doc_id, :session_id);

  if ( base_type <> 3 ) then
  begin
    if (current_date < '01.01.2019' and (select hasnds from PR_HASNDS(:doc_id, 20)) > 0 ) then
      exception EX_NDS20;
    if (current_date >= '01.01.2019' and (select hasnds from PR_HASNDS(:doc_id, 18)) > 0 ) then
      exception EX_NDS18;
  end

ТМС по автоматической настройке отделов (ставим НЕ ВСЕМ, только опционально, ТМС -327)

uses
  Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, Messages, SysUtils,
  ToolWin, ImgList, dxExEdtr, dxCntner, dxTL, dxDBCtrl, dxDBGrid, StdCtrls,
  unMain,DB, IBQuery, IBDatabase, unDM, DBTables, cfdxUtils, Menus, System,
  Buttons, ExtCtrls, StdCtrls, cfSelectEdit, Math, DateUtils,
  gb_table, Grids, ClipBrd, DBGrids, unFrameCustomDict,
  cfWindows, Mask, shellapi, inifiles;

var
  mainForm: TForm1;
  qWork: TIBQuery;

  t_zkassa:string;
  t_bat, ver:string;
  File_manager: TextFile;   
  File_bat: TextFile;


procedure set_nds_deps;
var
  iq: tibquery;
  i: integer;
  Deps: array;
  ini: tmeminifile;
  sl: tstringlist;
begin
  sl := tstringlist.create;
  ini := tmeminifile.Create('tmp.ini');
  iq := tibquery.create(nil);
  try
    iq.Transaction := CreateWT(CurrDB);
    iq.Transaction.StartTransaction;
    Deps := [2, 3, 4, 4, 2, 3, 2, 4, 3, 3, 3];
    for i := 0 to 10 do
    begin
      iq.SQL.Text := 'select dep_data from deps where id = :id';
      iq.Params[0].AsInteger := i + 1;
      iq.Open;
      sl.Text := iq.Fields[0].AsString;
      ini.SetStrings(sl);
      sl.Clear;
      ini.WriteInteger('FR' + FR_SerialNumber, 'TaxType', Deps[i]);
      ini.GetStrings(sl);

      iq.SQL.Text := 'update deps set dep_data = :data where id = :id';
      iq.Params[0].AsString := sl.Text;
      iq.Params[1].AsInteger := i + 1;
      iq.ExecSQL;
    end;
    iq.Transaction.Commit;
  finally
    iq.free;
    ini.Free;
    sl.Free;
  end;
end;



begin
  set_nds_deps;
end;

Проблема: Отрицательные позиции на остатках

выполнить скрипт

SET TERM ^ ;

create or alter procedure PR_REPAIR_MINUS
as
declare variable PART_ID_OUT integer;
begin

  for select part_id from warebase where quant < 0 or realquant < 0 into :part_id_out do
   execute procedure PR_SETPARTREALQUANT(:part_id_out, 0);

end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT SELECT ON WAREBASE TO PROCEDURE PR_REPAIR_MINUS;
GRANT EXECUTE ON PROCEDURE PR_SETPARTREALQUANT TO PROCEDURE PR_REPAIR_MINUS;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_REPAIR_MINUS TO SYSDBA;

EXECUTE PROCEDURE PR_REPAIR_MINUS;

DROP PROCEDURE PR_REPAIR_MINUS;

SET TERM ^ ;

create or alter procedure PR_AUTO_PART_CORRECT (
    DOC_ID DM_ID,
    SESSION_ID DM_ID)
as
declare variable DDA_ID DM_ID_NULL;
declare variable QUANT DM_DOUBLE;
declare variable PART_ID DM_ID_NULL;
declare variable DOC_ID_CORRECT DM_ID;
declare variable DEP_ID DM_ID_NULL;
declare variable NDS DM_STATUS;
declare variable PART_ID_NEW DM_ID_NULL;
declare variable ERROR_MSG DM_TEXT;
begin

  DOC_ID_CORRECT = 0;
  error_msg = '';

  select doc_id from pr_newdoc(7, -1, 0, null, null, :session_id) into :DOC_ID_CORRECT;
  if (DOC_ID_CORRECT = 0) then
  begin
    exception EX_NODOC;
    --error_msg = 'Не удалось создать документ корректировки.';
    --suspend;
    --exit;
  end

  for
    select dda.part_id, max(w.quant), max(d.nds)
    from doc_detail_active dda
     left join warebase w on dda.part_id = w.part_id
     left join parts p on dda.part_id = p.id
     left join deps d on p.dep = d.id
    where dda.doc_id = :doc_id and d.ndsr = 18
    group by dda.part_id
  into :part_id, :quant, :nds
  do
  begin
    if (:quant is null) then select sum(quant) from doc_detail where part_id = :part_id into :quant;
    if (:quant > 0.001) then
    begin
      dda_id = 0;
      select id from pr_correctpart_nds(:DOC_ID_CORRECT,:part_id,:quant,1) into :DDA_ID;
      if (dda_id > 0) then
          update doc_detail_active set dep = (select id from PR_GET_DEP(:nds, 20)) where id=:dda_id;
      else exception EX_NOPART; --error_msg = error_msg || ' Не удалось добавить партию ' || :part_id || ' в документ корретировки ' || DOC_ID_CORRECT;


    end

  end

  execute procedure pr_doc_commit(:DOC_ID_CORRECT, :session_id);

/*  for
    select p.id, p.motherpart_id from doc_detail dd left join parts p on dd.part_id = p.id where dd.doc_id = :DOC_ID_CORRECT into :part_id_new, :part_id
  do
    update doc_detail_active set part_id = :part_id_new where part_id = :part_id and doc_id = :doc_id;
*/

  for
    select p.id, p.motherpart_id from doc_detail dd left join parts p on dd.part_id = p.id where dd.doc_id = :DOC_ID_CORRECT into :part_id_new, :part_id
  do
  begin
    update doc_detail_active set part_id = :part_id_new where part_id = :part_id and doc_id = :doc_id;
    if (:part_id > 0) then execute procedure PR_SETPARTREALQUANT(:part_id, 0);
    if (:part_id_new > 0) then execute procedure PR_SETPARTREALQUANT(:part_id_new, 0);
  end



  --suspend;
end^

SET TERM ; ^

/* Following GRANT statements are generated automatically */

GRANT EXECUTE ON PROCEDURE PR_NEWDOC TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT,UPDATE ON DOC_DETAIL_ACTIVE TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON WAREBASE TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON PARTS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON DEPS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT SELECT ON DOC_DETAIL TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_CORRECTPART_NDS TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_GET_DEP TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_DOC_COMMIT TO PROCEDURE PR_AUTO_PART_CORRECT;
GRANT EXECUTE ON PROCEDURE PR_SETPARTREALQUANT TO PROCEDURE PR_AUTO_PART_CORRECT;

/* Existing privileges on this procedure */

GRANT EXECUTE ON PROCEDURE PR_AUTO_PART_CORRECT TO PROCEDURE PR_DOC_COMMIT;
GRANT EXECUTE ON PROCEDURE PR_AUTO_PART_CORRECT TO SYSDBA;


Как проверить?

  • До 2019 г. любые манипуляции с НДС 20%, например, приход товара, должны быть запрещены;
  • После начала 2019 г. любые манипуляции (кроме корректировки) с отделами 18%, должны быть запрещены;
  • При "отбитии" чека с НДС 18% с 2019 г. должен создаваться документ корректировки и автоматически корректировать позиции с 18% на 20%.

Чек уже проводить с НДС 20%.