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

This commit is contained in:
Mikhail Chechnev 2019-01-11 21:31:03 +03:00
parent 9b42179bde
commit 3f8966b621
4 changed files with 442 additions and 335 deletions

View File

@ -1,17 +1,36 @@
create or replace package UDO_PKG_EXS_ATOL as
/* Êîíñòàíòû - òåñòîâîå îêðóæåíèå ñåðâåðà ÀÒÎË-Îíëàéí */
STEST_SRV_ROOT_PATTERN constant varchar2(80) := '%testonline.atol.ru%'; -- Øàáëîí àäðåñà òåñòîâîãî ñåðâåðà
STEST_INN constant varchar2(80) := '5544332219'; -- Òåñòîâûé ÈÍÍ
STEST_ADDR constant varchar2(80) := 'https://v4.online.atol.ru'; -- Òåñòîâûé àäðåñ ðàñ÷¸òîâ
/* Константы - типы функций обработки */
SFN_TYPE_REG_BILL constant varchar2(20) := 'REG_BILL'; -- Типовая функция регистрации чека
SFN_TYPE_GET_BILL_INF constant varchar2(20) := 'GET_BILL_INF'; -- Типовая функция получения иформации о регистрации чека
/* Êîíñòàíòû - âåðñèè ÔÔÄ (ñòðîêîâûå ïðåäñòàâëåíèÿ) */
SFFD105 constant varchar2(20) := '1.05'; -- Âåðñèÿ ÔÔÄ 1.05
SFFD110 constant varchar2(20) := '1.10'; -- Âåðñèÿ ÔÔÄ 1.10
/* Êîíñòàíòû - çíà÷åíèÿ òýãà "Íîìåð âåðñèè ÔÔÄ" (1209) äëÿ âåðñèé ôîðìàòà */
NTAG1209_FFD105 constant number(2) := 2; -- Çíà÷åíèå òýãà 1209 äëÿ âåðñèè ÔÔÄ 1.05
NTAG1209_FFD110 constant number(2) := 3; -- Çíà÷åíèå òýãà 1209 äëÿ âåðñèè ÔÔÄ 1.10
/* Ïðîâåðêà ñåðâèñà íà òî, ÷òî îí ÿâëÿåòñÿ òåñòîâûì */
function UTL_EXSSERVICE_IS_TEST
(
NEXSSERVICE in number -- Ðåãèñòðàöèîííûé íîìåð ñåðâèñà îáìåíà
) return boolean; -- Ïðèçíàê òåñòîâîãî ñåðâèñà (true - òåñòîâûé, false - íå òåñòîâûé)
/* Получение рег. номера функции сервиса обмена для регистрации чека по рег. номеру фискального документа */
function UTL_FISCDOC_GET_REG_EXSFN
function UTL_FISCDOC_GET_EXSFN_REG
(
NFISCDOC in number -- Рег. номер фискального документа
) return number; -- Рег. номер функции регистрации чека в сервисе АТОЛ-Онлайн
/* Получение рег. номера функции сервиса обмена для запроса информации о регистрации чека по рег. номеру фискального документа */
function UTL_FISCDOC_GET_INF_EXSFN
function UTL_FISCDOC_GET_EXSFN_INF
(
NFISCDOC in number -- Рег. номер фискального документа
) return number; -- Рег. номер функции запроса информации о регистрации чека в сервисе АТОЛ-Онлайн
@ -72,13 +91,13 @@ create or replace package body UDO_PKG_EXS_ATOL as
/* Считывание записи фискального документа */
function UTL_FISCDOC_GET
(
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return UDO_V_FISCDOCS%rowtype -- Íàéäåííàÿ çàïèñü ôèñêàëüíîãî äîêóìåíòà
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return UDO_FISCDOCS%rowtype -- Íàéäåííàÿ çàïèñü ôèñêàëüíîãî äîêóìåíòà
is
RRES UDO_V_FISCDOCS%rowtype; -- Áóôåð äëÿ ðåçóëüòàòà
RRES UDO_FISCDOCS%rowtype; -- Áóôåð äëÿ ðåçóëüòàòà
begin
/* Считаем запись */
select T.* into RRES from UDO_V_FISCDOCS T where T.NRN = NFISCDOC;
select T.* into RRES from UDO_FISCDOCS T where T.RN = NFISCDOC;
/* Вернём результат */
return RRES;
exception
@ -87,137 +106,115 @@ create or replace package body UDO_PKG_EXS_ATOL as
end UTL_FISCDOC_GET;
/* Получение мнемокода сервиса обмена и мнемокода его функции по типу функции обработки и версии ФФД */
procedure UTL_FISCDOC_GET_EXSFN_BY_FFD
procedure UTL_FISCDOC_GET_EXSFN
(
NFISCDOC in number, -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
SFN_TYPE in varchar2, -- Тип функции обработки (см. константы SFN_TYPE_*)
SFFD_VERSION in varchar2, -- Âåðñèÿ ÔÔÄ
SEXSSERVICE out varchar2, -- Êîä ñåðâèñà-îáðàáîò÷èêà
SEXSSERVICEFN out varchar2 -- Êîä ôóíêöèè-îáðàáîò÷èêà
NEXSSERVICEFN out number -- Ðåã. íîìåð ôóíêöèè-îáðàáîò÷èêà
)
is
begin
/* Ðàáîòàåì îò òèïîâîé ôóíêöèè */
case SFN_TYPE
/* Ðåãèñòðàöèÿ ÷åêà */
when SFN_TYPE_REG_BILL then
begin
/* Âûáèðàåì API îáìåíà â çàâèñèìîñòè îò âåðñèè ôèñêàëüíîãî äîêóìåíòà */
case SFFD_VERSION
/* ÔÔÄ 1.05 */
when '1.05' then
begin
SEXSSERVICE := 'ÀÒÎË_V4_ÈÑÕ';
SEXSSERVICEFN := 'V4_ÔÔÄ1.05_Ðåãèñòðàöèÿ×åêàÐÏÂ';
end;
/* Íåèçâåñòíàÿ âåðñèÿ ÔÔÄ */
else
begin
P_EXCEPTION(0,
'Âåðñèÿ ôèñêàëüíîãî äîêóìåíòà "%s" íå ïîääåðæèâàåòñÿ!',
SFFD_VERSION);
end;
end case;
end;
/* Ïîëó÷åíèå èôîðìàöèè î ðåãèñòðàöèè ÷åêà */
when SFN_TYPE_GET_BILL_INF then
begin
/* Âûáèðàåì API îáìåíà â çàâèñèìîñòè îò âåðñèè ôèñêàëüíîãî äîêóìåíòà */
case SFFD_VERSION
/* ÔÔÄ 1.05 */
when '1.05' then
begin
SEXSSERVICE := 'ÀÒÎË_V4_ÈÑÕ';
SEXSSERVICEFN := 'V4_ÔÔÄ1.05_ÐåçÎáðàá×åêà';
end;
/* Íåèçâåñòíàÿ âåðñèÿ ÔÔÄ */
else
begin
P_EXCEPTION(0,
'Âåðñèÿ ôèñêàëüíîãî äîêóìåíòà "%s" íå ïîääåðæèâàåòñÿ!',
SFFD_VERSION);
end;
end case;
end;
/* Íåèçâåñòíàÿ òèïîâàÿ ôóíêöèÿ */
else
begin
P_EXCEPTION(0, 'Òèïîâàÿ ôóíêöèÿ "%s" íå ïîääåðæèâàåòñÿ!', SFN_TYPE);
end;
end case;
end UTL_FISCDOC_GET_EXSFN_BY_FFD;
begin
select DECODE(SFN_TYPE, SFN_TYPE_REG_BILL, SFNREG.RN, SFN_TYPE_GET_BILL_INF, SFNINF.RN)
into NEXSSERVICEFN
from UDO_FISCDOCS FD,
UDO_FDKNDVERS TV,
EXSSERVICEFN SFNREG,
EXSSERVICEFN SFNINF
where FD.RN = NFISCDOC
and FD.TYPE_VERSION = TV.RN
and TV.FUNCTION_SEND = SFNREG.RN(+)
and TV.FUNCTION_RESP = SFNINF.RN(+);
exception
when others then
NEXSSERVICEFN := null;
end;
/* Ïðîâåðèì, ÷òî õîòü ÷òî-òî íàøëîñü */
if (NEXSSERVICEFN is null) then
P_EXCEPTION(0,
'Äëÿ ôèñêàëüíîãî äîêóìåíòà (RN: %s) íå îïðåäåëåíàÿ òèïîâàÿ ôóíêöèÿ "%s".',
TO_CHAR(NFISCDOC),
SFN_TYPE);
end if;
end UTL_FISCDOC_GET_EXSFN;
/* Получение рег. номера функции сервиса обмена для регистрации чека по рег. номеру фискального документа */
function UTL_FISCDOC_GET_REG_EXSFN
function UTL_FISCDOC_GET_EXSFN_REG
(
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return number -- Ðåã. íîìåð ôóíêöèè ðåãèñòðàöèè ÷åêà â ñåðâèñå ÀÒÎË-Îíëàéí
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return number -- Ðåã. íîìåð ôóíêöèè ðåãèñòðàöèè ÷åêà â ñåðâèñå ÀÒÎË-Îíëàéí
is
NRES PKG_STD.TREF; -- Áóôåð äëÿ ðåçóëüòàòà
RFISCDOC UDO_V_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
NEXSSERVICE EXSSERVICEFN.RN%type; -- Ðåã. íîìåð ñåðâèñà-îáðàáîò÷èêà
SEXSSERVICE EXSSERVICEFN.CODE%type; -- Êîä ñåðâèñà-îáðàáîò÷èêà
SEXSSERVICEFN EXSSERVICEFN.CODE%type; -- Êîä ôóíêöèè-îáðàáîò÷èêà
NRES PKG_STD.TREF; -- Áóôåð äëÿ ðåçóëüòàòà
begin
/* Ñ÷èòàåì çàïèñü ôèñêàëüíîãî äîêóìåíòà */
RFISCDOC := UTL_FISCDOC_GET(NFISCDOC => NFISCDOC);
/* Определим мнемокоды сервиса и функции для обработки */
UTL_FISCDOC_GET_EXSFN_BY_FFD(SFN_TYPE => SFN_TYPE_REG_BILL,
SFFD_VERSION => RFISCDOC.STYPE_VERSION,
SEXSSERVICE => SEXSSERVICE,
SEXSSERVICEFN => SEXSSERVICEFN);
/* Íàõîäèì ðåã. íîìåð ñåðâèñà */
FIND_EXSSERVICE_CODE(NFLAG_SMART => 0, NFLAG_OPTION => 0, SCODE => SEXSSERVICE, NRN => NEXSSERVICE);
/* Íàõîäèì ðåã. íîìåð ôóíêöèè ñåðâèñà */
FIND_EXSSERVICEFN_CODE(NFLAG_SMART => 0,
NFLAG_OPTION => 0,
NEXSSERVICE => NEXSSERVICE,
SCODE => SEXSSERVICEFN,
NRN => NRES);
UTL_FISCDOC_GET_EXSFN(NFISCDOC => NFISCDOC, SFN_TYPE => SFN_TYPE_REG_BILL, NEXSSERVICEFN => NRES);
/* Вернём результат */
return NRES;
end UTL_FISCDOC_GET_REG_EXSFN;
end UTL_FISCDOC_GET_EXSFN_REG;
/* Получение рег. номера функции сервиса обмена для запроса информации о регистрации чека по рег. номеру фискального документа */
function UTL_FISCDOC_GET_INF_EXSFN
function UTL_FISCDOC_GET_EXSFN_INF
(
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return number -- Ðåã. íîìåð ôóíêöèè çàïðîñà èíôîðìàöèè î ðåãèñòðàöèè ÷åêà â ñåðâèñå ÀÒÎË-Îíëàéí
NFISCDOC in number -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
) return number -- Ðåã. íîìåð ôóíêöèè çàïðîñà èíôîðìàöèè î ðåãèñòðàöèè ÷åêà â ñåðâèñå ÀÒÎË-Îíëàéí
is
NRES PKG_STD.TREF; -- Áóôåð äëÿ ðåçóëüòàòà
RFISCDOC UDO_V_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
NEXSSERVICE EXSSERVICEFN.RN%type; -- Ðåã. íîìåð ñåðâèñà-îáðàáîò÷èêà
SEXSSERVICE EXSSERVICEFN.CODE%type; -- Êîä ñåðâèñà-îáðàáîò÷èêà
SEXSSERVICEFN EXSSERVICEFN.CODE%type; -- Êîä ôóíêöèè-îáðàáîò÷èêà
NRES PKG_STD.TREF; -- Áóôåð äëÿ ðåçóëüòàòà
begin
/* Ñ÷èòàåì çàïèñü ôèñêàëüíîãî äîêóìåíòà */
RFISCDOC := UTL_FISCDOC_GET(NFISCDOC => NFISCDOC);
/* Определим мнемокоды сервиса и функции для обработки */
UTL_FISCDOC_GET_EXSFN_BY_FFD(SFN_TYPE => SFN_TYPE_GET_BILL_INF,
SFFD_VERSION => RFISCDOC.STYPE_VERSION,
SEXSSERVICE => SEXSSERVICE,
SEXSSERVICEFN => SEXSSERVICEFN);
/* Íàõîäèì ðåã. íîìåð ñåðâèñà */
FIND_EXSSERVICE_CODE(NFLAG_SMART => 0, NFLAG_OPTION => 0, SCODE => SEXSSERVICE, NRN => NEXSSERVICE);
/* Íàõîäèì ðåã. íîìåð ôóíêöèè ñåðâèñà */
FIND_EXSSERVICEFN_CODE(NFLAG_SMART => 0,
NFLAG_OPTION => 0,
NEXSSERVICE => NEXSSERVICE,
SCODE => SEXSSERVICEFN,
NRN => NRES);
UTL_FISCDOC_GET_EXSFN(NFISCDOC => NFISCDOC, SFN_TYPE => SFN_TYPE_GET_BILL_INF, NEXSSERVICEFN => NRES);
/* Вернём результат */
return NRES;
end UTL_FISCDOC_GET_INF_EXSFN;
end UTL_FISCDOC_GET_EXSFN_INF;
/* Êîíòðîëü âåðñèè ÔÔÄ */
procedure UTL_FISCDOC_CHECK_FFD_VERS
(
NCOMPANY in number, -- Ðåã. íîìåð îðãàíèçàöèè
NFISCDOC in number, -- Ðåã. íîìåð ôèñêàëüíîãî äîêóìåíòà
NEXPECTED_VERS in number, -- Îæèäàåìàÿ âåðñèÿ ÔÔÄ (ïî çíà÷åíèþ òýãà 1209, ñì. êîíñòíàòû NTAG1209_FFD*)
SEXPECTED_VERS in varchar2 -- Îæèäàåìàÿ âåðñèÿ ÔÔÄ (ñòðîêîâîå ïðåäñòàâëåíèå)
)
is
begin
/* Ñ÷èòàåì òýã 1209 (â íåì õðàíèòñÿ íîìåð âåðñèè ÔÔÄ) è ñâåðèì çíà÷åíèÿ, ôàêòè÷åñêîå è îæèäàåìîå ïðîöåäóðîé */
if (UDO_F_FISCDOCS_GET_NUMB(NRN => NFISCDOC, NCOMPANY => NCOMPANY, SATTRIBUTE => '1209') != NEXPECTED_VERS) then
P_EXCEPTION(0,
'Âåðñèÿ ôîðìàòà ôèñêàëüíîãî äîêóìåíòà (çíà÷åíèå òýãà 1209 - %s) íå ïîääåðæèâàåòñÿ. Îæèäàåìàÿ âåðñèÿ - %s (çíà÷åíèå òýãà 1209 - %s).',
NVL(TO_CHAR(UDO_F_FISCDOCS_GET_NUMB(NRN => NFISCDOC, NCOMPANY => NCOMPANY, SATTRIBUTE => '1209')),
'<ÍÅ ÓÊÀÇÀÍÎ>'),
NVL(SEXPECTED_VERS, '<ÍÅ ÓÊÀÇÀÍÀ>'),
NVL(TO_CHAR(NEXPECTED_VERS), '<ÍÅ ÓÊÀÇÀÍÎ>'));
end if;
end UTL_FISCDOC_CHECK_FFD_VERS;
/* Ïðîâåðêà ñåðâèñà íà òî, ÷òî îí ÿâëÿåòñÿ òåñòîâûì */
function UTL_EXSSERVICE_IS_TEST
(
NEXSSERVICE in number -- Ðåãèñòðàöèîííûé íîìåð ñåðâèñà îáìåíà
) return boolean -- Ïðèçíàê òåñòîâîãî ñåðâèñà (true - òåñòîâûé, false - íå òåñòîâûé)
is
REXSSERVICE EXSSERVICE%rowtype; -- Çàïèñü ñåðâèñà îáìåíà
begin
/* Ñ÷èòàåì çàïèñü ñåðâèñà îáìåíà */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Ïðîâåðèì åãî ïî àäðåñó */
if (REXSSERVICE.SRV_ROOT like STEST_SRV_ROOT_PATTERN) then
return true;
else
return false;
end if;
end;
/* Отработка ответов АТОЛ (v4) на регистрацию чека на приход, расход, возврат (ФФД 1.05) */
procedure V4_FFD105_PROCESS_REG_BILL_SIR
(
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
NEXSQUEUE in number -- Ðåãèñòðàöèîííûé íîìåð îáðàáàòûâàåìîé ïîçèöèè î÷åðåäè îáìåíà
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
NEXSQUEUE in number -- Ðåãèñòðàöèîííûé íîìåð îáðàáàòûâàåìîé ïîçèöèè î÷åðåäè îáìåíà
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Çàïèñü ïîçèöèè î÷åðåäè
RFISCDOC UDO_V_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
CTMP clob; -- Áóôåð äëÿ õðàíåíèÿ äàííûõ îòâåòà ñåðâåðà
REXSQUEUE EXSQUEUE%rowtype; -- Çàïèñü ïîçèöèè î÷åðåäè
RFISCDOC UDO_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
CTMP clob; -- Áóôåð äëÿ õðàíåíèÿ äàííûõ îòâåòà ñåðâåðà
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
@ -226,11 +223,10 @@ create or replace package body UDO_PKG_EXS_ATOL as
/* Считаем запись фискального документа */
RFISCDOC := UTL_FISCDOC_GET(NFISCDOC => REXSQUEUE.LNK_DOCUMENT);
/* Проверим, что он верного формата */
if (RFISCDOC.STYPE_VERSION <> '1.05') then
P_EXCEPTION(0,
'Âåðñèÿ ôîðìàòà ôèñêàëüíîãî äîêóìåíòà (%s) íå ïîääåðæèâàåòñÿ. Îæèäàåìàÿ âåðñèÿ - 1.05.',
RFISCDOC.STYPE_VERSION);
end if;
UTL_FISCDOC_CHECK_FFD_VERS(NCOMPANY => RFISCDOC.COMPANY,
NFISCDOC => RFISCDOC.RN,
NEXPECTED_VERS => NTAG1209_FFD105,
SEXPECTED_VERS => SFFD105);
/* Разбираем ответ */
CTMP := BLOB2CLOB(LBDATA => REXSQUEUE.RESP, SCHARSET => 'UTF8');
if (CTMP is null) then
@ -249,23 +245,25 @@ create or replace package body UDO_PKG_EXS_ATOL as
/* Отработка ответов АТОЛ (v4) на запрос сведений о зарегистрированном документе (ФФД 1.05) */
procedure V4_FFD105_PROCESS_GET_BILL_INF
(
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
NEXSQUEUE in number -- Ðåãèñòðàöèîííûé íîìåð îáðàáàòûâàåìîé ïîçèöèè î÷åðåäè îáìåíà
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
NEXSQUEUE in number -- Ðåãèñòðàöèîííûé íîìåð îáðàáàòûâàåìîé ïîçèöèè î÷åðåäè îáìåíà
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Çàïèñü ïîçèöèè î÷åðåäè
RFISCDOC UDO_V_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
RDOC PKG_XPATH.TDOCUMENT; -- Ðàçîáðàííûé XML-äîêóìåíò
RROOT_NODE PKG_XPATH.TNODE; -- Êîðíåâîé òýã XML-äîêóìåíòà
SSTATUS PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ñòàòóñ îáðàáîòêè äîêóìåíòà"
STIMESTAMP PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà âíåøíåé ñèñòåìû" (ñòðîêîâîå ïðåäñòàâëåíèå)
DTIMESTAMP PKG_STD.TLDATE; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà âíåøíåé ñèñòåìû"
STAG1012 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà èç ÔÍ" (òýã 1012)
STAG1040 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ôèñêàëüíûé íîìåð äîêóìåíòà" (òýã 1040)
STAG1041 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Íîìåð ÔÍ" (òýã 1041)
STAG1077 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ôèñêàëüíûé ïðèçíàê äîêóìåíòà" (òýã 1077)
SERR_CODE PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Êîä îøèáêè"
SERR_TEXT PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Òåêñò îøèáêè"
REXSQUEUE EXSQUEUE%rowtype; -- Çàïèñü ïîçèöèè î÷åðåäè
RFISCDOC UDO_FISCDOCS%rowtype; -- Çàïèñü ôèñêàëüíîãî äîêóìåíòà
RDOC PKG_XPATH.TDOCUMENT; -- Ðàçîáðàííûé XML-äîêóìåíò
RROOT_NODE PKG_XPATH.TNODE; -- Êîðíåâîé òýã XML-äîêóìåíòà
SSTATUS PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ñòàòóñ îáðàáîòêè äîêóìåíòà"
STIMESTAMP PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà âíåøíåé ñèñòåìû" (ñòðîêîâîå ïðåäñòàâëåíèå)
DTIMESTAMP PKG_STD.TLDATE; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà âíåøíåé ñèñòåìû"
STAG1012 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Äàòà è âðåìÿ äîêóìåíòà èç ÔÍ" (òýã 1012)
STAG1038 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Íîìåð ñìåíû" (òýã 1038)
STAG1040 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ôèñêàëüíûé íîìåð äîêóìåíòà" (òýã 1040)
STAG1041 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Íîìåð ÔÍ" (òýã 1041)
STAG1042 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Íîìåð ÷åêà â ñìåíå" (òýã 1042)
STAG1077 PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Ôèñêàëüíûé ïðèçíàê äîêóìåíòà" (òýã 1077)
SERR_CODE PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Êîä îøèáêè"
SERR_TEXT PKG_STD.TSTRING; -- Áóôåð äëÿ çíà÷åíèÿ "Òåêñò îøèáêè"
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
@ -274,11 +272,10 @@ create or replace package body UDO_PKG_EXS_ATOL as
/* Считаем запись фискального документа */
RFISCDOC := UTL_FISCDOC_GET(NFISCDOC => REXSQUEUE.LNK_DOCUMENT);
/* Проверим, что он верного формата */
if (RFISCDOC.STYPE_VERSION <> '1.05') then
P_EXCEPTION(0,
'Âåðñèÿ ôîðìàòà ôèñêàëüíîãî äîêóìåíòà (%s) íå ïîääåðæèâàåòñÿ. Îæèäàåìàÿ âåðñèÿ - 1.05.',
RFISCDOC.STYPE_VERSION);
end if;
UTL_FISCDOC_CHECK_FFD_VERS(NCOMPANY => RFISCDOC.COMPANY,
NFISCDOC => RFISCDOC.RN,
NEXPECTED_VERS => NTAG1209_FFD105,
SEXPECTED_VERS => SFFD105);
/* Разбираем ответ */
begin
RDOC := PKG_XPATH.PARSE_FROM_BLOB(LBXML => REXSQUEUE.RESP, SCHARSET => 'UTF8');
@ -290,12 +287,14 @@ create or replace package body UDO_PKG_EXS_ATOL as
RROOT_NODE := PKG_XPATH.ROOT_NODE(RDOCUMENT => RDOC);
/* Забираем значения документа */
SSTATUS := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/STATUS'));
STIMESTAMP := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE,
SPATTERN => '/RESP/TIMESTAMP'));
STAG1012 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1012'));
STAG1038 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1038'));
STAG1040 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1040'));
STAG1041 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1041'));
STAG1042 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1042'));
STAG1077 := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE, SPATTERN => '/RESP/TAG1077'));
STIMESTAMP := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE,
SPATTERN => '/RESP/TIMESTAMP'));
SERR_CODE := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE,
SPATTERN => '/RESP/ERROR/CODE'));
SERR_TEXT := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => RROOT_NODE,
@ -323,6 +322,16 @@ create or replace package body UDO_PKG_EXS_ATOL as
'Документ в статусе "%s", но не указано значение "Дата и время документа внешней системы".',
SSTATUS);
end if;
if (STAG1012 is null) then
P_EXCEPTION(0,
'Äîêóìåíò â ñòàòóñå "%s", íî íå óêàçàíî çíà÷åíèå "Äàòà è âðåìÿ äîêóìåíòà èç ÔÍ" (òýã 1012).',
SSTATUS);
end if;
if (STAG1038 is null) then
P_EXCEPTION(0,
'Äîêóìåíò â ñòàòóñå "%s", íî íå óêàçàíî çíà÷åíèå "Íîìåð ñìåíû" (òýã 1038).',
SSTATUS);
end if;
if (STAG1040 is null) then
P_EXCEPTION(0,
'Документ в статусе "%s", но не указано значение "Фискальный номер документа" (тэг 1040).',
@ -333,6 +342,11 @@ create or replace package body UDO_PKG_EXS_ATOL as
'Документ в статусе "%s", но не указано значение "Номер ФН" (тэг 1041).',
SSTATUS);
end if;
if (STAG1042 is null) then
P_EXCEPTION(0,
'Äîêóìåíò â ñòàòóñå "%s", íî íå óêàçàíî çíà÷åíèå "Íîìåð ÷åêà â ñìåíå" (òýã 1042).',
SSTATUS);
end if;
if (STAG1077 is null) then
P_EXCEPTION(0,
'Документ в статусе "%s", но не указано значение "Фискальный признак документа" (тэг 1077).',
@ -353,19 +367,31 @@ create or replace package body UDO_PKG_EXS_ATOL as
T.DOC_URL = replace(replace(replace(SBILL_OFD_UTL, '<1040>', STAG1040), '<1041>', STAG1041),
'<1077>',
STAG1077)
where T.RN = RFISCDOC.NRN;
where T.RN = RFISCDOC.RN;
/* Устанавливаем значения тэгов */
begin
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.NRN,
NCOMPANY => RFISCDOC.NCOMPANY,
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1012',
DVAL_DATETIME => TO_DATE(STAG1012, 'dd.mm.yyyy hh24:mi:ss'));
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1038',
NVAL_NUMB => TO_NUMBER(STAG1038));
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1040',
NVAL_NUMB => TO_NUMBER(STAG1040));
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.NRN,
NCOMPANY => RFISCDOC.NCOMPANY,
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1041',
SVAL_STR => STAG1041);
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.NRN,
NCOMPANY => RFISCDOC.NCOMPANY,
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1042',
NVAL_NUMB => TO_NUMBER(STAG1042));
UDO_P_FISCDOCSPROP_SET_VAL(NPRN => RFISCDOC.RN,
NCOMPANY => RFISCDOC.COMPANY,
SATTRIBUTE => '1077',
SVAL_STR => STAG1077);
exception
@ -390,7 +416,7 @@ create or replace package body UDO_PKG_EXS_ATOL as
REGEXP_REPLACE(replace(SERR_TEXT, CHR(10), ''), '[[:space:]]+', ' '),
1,
4000)
where T.RN = RFISCDOC.NRN;
where T.RN = RFISCDOC.RN;
end;
/* Неизвестный статус */
else

View File

@ -13,10 +13,10 @@ begin
and Q.LNK_UNITCODE = 'UDO_FiscalDocuments'
and Q.LNK_DOCUMENT = T.RN
and Q.EXEC_STATE = PKG_EXS.NQUEUE_EXEC_STATE_OK
and Q.EXSSERVICEFN = UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_REG_EXSFN(T.RN))
and Q.EXSSERVICEFN = UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_EXSFN_REG(T.RN))
loop
/* Ñòàâèì çàïðîñ íà ïîëó÷åíèå ñòàòóñà äîêóìåíòà â î÷åðåäü */
PKG_EXS.QUEUE_PUT(NEXSSERVICEFN => UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_INF_EXSFN(NFISCDOC => C.RN),
PKG_EXS.QUEUE_PUT(NEXSSERVICEFN => UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_EXSFN_INF(NFISCDOC => C.RN),
BMSG => C.BUUID,
NLNK_COMPANY => C.COMPANY,
NLNK_DOCUMENT => C.RN,

View File

@ -1,18 +1,20 @@
create or replace procedure UDO_P_FISCDOCS_MAKE_MSG_ATOL
(
NCOMPANY in number, -- Îðãàíèçàöèÿ
NFISCDOC in number, -- Ðåãèñòðàöèîííûé íîìåð ôèñêàëüíîãî äîêóìåíòà
NEXSQUEUE out number -- Ðåãèñòðàöèîííûé íîìåð äîáàâëåííîé ïîçèöèè î÷åðåäè îáìåíà
NCOMPANY in number, -- Îðãàíèçàöèÿ
NFISCDOC in number, -- Ðåãèñòðàöèîííûé íîìåð ôèñêàëüíîãî äîêóìåíòà
NEXSQUEUE out number -- Ðåãèñòðàöèîííûé íîìåð äîáàâëåííîé ïîçèöèè î÷åðåäè îáìåíà
)
as
/* Ëîêàëüíûå ïåðåìåííûå */
CDATA clob; -- Áóôåð äëÿ XML-ïîñûëêè
NTMP_RN PKG_STD.TREF; -- Áóôåð äëÿ âû÷èñëåíèé
CDATA clob; -- Áóôåð äëÿ XML-ïîñûëêè
NTMP_RN PKG_STD.TREF; -- Áóôåð äëÿ âû÷èñëåíèé
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Çàïèñü ôóíêöèè ñåðâèñà èíòåãðàöèè
BTEST_SRV boolean := false; -- Ïðèçíàê òåñòîâîãî ñåðâèñà
/* Äîáàâëåíèå ïóñòîé îòêðûòîé âåòêè */
procedure NODE
(
SNAME varchar2 -- Èìÿ âåòêè
SNAME varchar2 -- Èìÿ âåòêè
)
as
begin
@ -25,8 +27,8 @@ as
/* Äîáàâëåíèå âåòêè ñî çíà÷åíèåì (ñòðîêà) */
procedure NODE
(
SNAME varchar2, -- Èìÿ âåòêè
SVALUE varchar2 -- Çíà÷åíèå âåòêè (ñòðîêà)
SNAME varchar2, -- Èìÿ âåòêè
SVALUE varchar2 -- Çíà÷åíèå âåòêè (ñòðîêà)
)
as
begin
@ -43,8 +45,8 @@ as
/* Äîáàâëåíèå âåòêè ñî çíà÷åíèåì (÷èñëî) */
procedure NODE
(
SNAME varchar2, -- Èìÿ âåòêè
NVALUE number -- Çíà÷åíèå âåòêè (÷èñëî)
SNAME varchar2, -- Èìÿ âåòêè
NVALUE number -- Çíà÷åíèå âåòêè (÷èñëî)
)
as
begin
@ -61,8 +63,8 @@ as
/* Äîáàâëåíèå âåòêè ñî çíà÷åíèåì (äàòà) */
procedure NODE
(
SNAME varchar2, -- Èìÿ âåòêè
DVALUE date -- Çíà÷åíèå âåòêè (äàòà)
SNAME varchar2, -- Èìÿ âåòêè
DVALUE date -- Çíà÷åíèå âåòêè (äàòà)
)
as
begin
@ -79,6 +81,11 @@ as
begin
/* Ïðîâåðèì íàëè÷èå äîêóìåíòà */
UDO_P_FISCDOCS_EXISTS(NRN => NFISCDOC, NCOMPANY => NCOMPANY, NCRN => NTMP_RN, NJUR_PERS => NTMP_RN);
/* Îïðåäåëèì ñåðâèñ èíòåãðàöèè è åãî ôóíêöèþ, ÷åðåç êîòîðûå áóäåì îòïðàâëÿòü ñîîáùåíèå */
REXSSERVICEFN := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0,
NRN => UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_EXSFN_REG(NFISCDOC => NFISCDOC));
/* Âûñòàâèì ôëàã òåñòîâîãî ñåðâèñà */
BTEST_SRV := UDO_PKG_EXS_ATOL.UTL_EXSSERVICE_IS_TEST(NEXSSERVICE => REXSSERVICEFN.PRN);
/* Èíèöèàëèçèðóåì ñáîðêó äîêóìåíòà äëÿ îòïðàâêè */
PKG_XMLFAST.PROLOGUE(NENCODING => PKG_XMLFAST.ENCODING_UTF8_,
NSTANDALONE => PKG_XMLFAST.STANDALONE_YES_,
@ -87,77 +94,53 @@ begin
NODE(SNAME => 'FISCDOC');
/* Êóðñîðíûé öèêë äëÿ äîñòóïà ê äàííûì ôèñêàëüíîãî äîêóìåíòà */
for D in (select T.*
from UDO_V_FISCDOCS T
where T.NRN = UDO_P_FISCDOCS_MAKE_MSG_ATOL.NFISCDOC
and T.NCOMPANY = UDO_P_FISCDOCS_MAKE_MSG_ATOL.NCOMPANY)
loop
from UDO_FISCDOCS T
where T.RN = NFISCDOC
and T.COMPANY = NCOMPANY)
loop
/* Äàííûå çàãîëîâêà ôèñêàëüíîãî äîêóìåíòà */
NODE(SNAME => 'NRN', NVALUE => D.NRN);
NODE(SNAME => 'NCOMPANY', NVALUE => D.NCOMPANY);
NODE(SNAME => 'NCRN', NVALUE => D.NCRN);
NODE(SNAME => 'NJUR_PERS', NVALUE => D.NJUR_PERS);
NODE(SNAME => 'SJUR_PERS', SVALUE => D.SJUR_PERS);
NODE(SNAME => 'SDOC_PREF', SVALUE => trim(D.SDOC_PREF));
NODE(SNAME => 'SDOC_NUMB', SVALUE => trim(D.SDOC_NUMB));
NODE(SNAME => 'NDOC_TYPE', NVALUE => D.NDOC_TYPE);
NODE(SNAME => 'NDOC_TYPE_CODE', NVALUE => D.NDOC_TYPE_CODE);
NODE(SNAME => 'NTYPE_VERSION', NVALUE => D.NTYPE_VERSION);
NODE(SNAME => 'STYPE_VERSION', SVALUE => D.STYPE_VERSION);
NODE(SNAME => 'DDOC_DATE', DVALUE => D.DDOC_DATE);
NODE(SNAME => 'SDDOC_DATE', SVALUE => TO_CHAR(D.DDOC_DATE, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'NAGENT', NVALUE => D.NAGENT);
NODE(SNAME => 'SAGENT', SVALUE => D.SAGENT);
NODE(SNAME => 'NCALC_KIND', NVALUE => D.NCALC_KIND);
NODE(SNAME => 'NBASE_SUM', NVALUE => D.NBASE_SUM);
NODE(SNAME => 'SAUTHID', SVALUE => D.SAUTHID);
NODE(SNAME => 'DEDIT_TIME', DVALUE => D.DEDIT_TIME);
NODE(SNAME => 'SDEDIT_TIME', SVALUE => TO_CHAR(D.DEDIT_TIME, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'SNOTE', SVALUE => D.SNOTE);
NODE(SNAME => 'NSTATUS', NVALUE => D.NSTATUS);
NODE(SNAME => 'DSEND_TIME', DVALUE => D.DSEND_TIME);
NODE(SNAME => 'SDSEND_TIME', SVALUE => TO_CHAR(D.DSEND_TIME, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'DCONFIRM_DATE', DVALUE => D.DCONFIRM_DATE);
NODE(SNAME => 'SDCONFIRM_DATE', SVALUE => TO_CHAR(D.DCONFIRM_DATE, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'SNUMB_FD', SVALUE => D.SNUMB_FD);
NODE(SNAME => 'NFACEACC', NVALUE => D.NFACEACC);
NODE(SNAME => 'SFACEACC', SVALUE => D.SFACEACC);
NODE(SNAME => 'SADD_PROP', SVALUE => D.SADD_PROP);
NODE(SNAME => 'SSRC_UNITCODE', SVALUE => D.SSRC_UNITCODE);
NODE(SNAME => 'SSRC_UNITNAME', SVALUE => D.SSRC_UNITNAME);
NODE(SNAME => 'NSRC_TYPE', NVALUE => D.NSRC_TYPE);
NODE(SNAME => 'SSRC_TYPE', SVALUE => D.SSRC_TYPE);
NODE(SNAME => 'SSRC_NUMB', SVALUE => D.SSRC_NUMB);
NODE(SNAME => 'DSRC_DATE', DVALUE => D.DSRC_DATE);
NODE(SNAME => 'SDSRC_DATE', SVALUE => TO_CHAR(D.DSRC_DATE, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'NVALID_TYPE', NVALUE => D.NVALID_TYPE);
NODE(SNAME => 'SVALID_TYPE', SVALUE => D.SVALID_TYPE);
NODE(SNAME => 'SVALID_NUMB', SVALUE => D.SVALID_NUMB);
NODE(SNAME => 'DVALID_DATE', DVALUE => D.DVALID_DATE);
NODE(SNAME => 'SDVALID_DATE', SVALUE => TO_CHAR(D.DVALID_DATE, 'dd.mm.yyyy hh24:mi:ss'));
NODE(SNAME => 'SDOC_URL', SVALUE => D.SDOC_URL);
NODE(SNAME => 'NCORRECT_TYPE', NVALUE => D.NCORRECT_TYPE);
NODE(SNAME => 'NRN', NVALUE => D.RN);
NODE(SNAME => 'DDOC_DATE', DVALUE => D.DOC_DATE);
NODE(SNAME => 'SDDOC_DATE', SVALUE => TO_CHAR(D.DOC_DATE, 'dd.mm.yyyy hh24:mi:ss'));
/* Ñïèñîê ñâîéñòâ ôèñêàëüíîãî äîêóìåíòà */
NODE('FISCDOC_PROPS');
for SP in (select T.*,
A.CODE SCODE,
A.NAME SNAME
for SP in (select A.CODE SCODE,
A.NAME SNAME,
UDO_GET_FISCDOCSPROP_VALUE(T.RN) SVALUE,
T.VAL_STR SVAL_STR,
T.VAL_NUMB NVAL_NUMB,
T.VAL_DATE DVAL_DATE,
T.VAL_DATETIME DVAL_DATETIME
from UDO_FISCDOCSPROP T,
UDO_FDKNDATT P,
UDO_FISCDOCATT A
where T.PRN = D.NRN
where T.PRN = D.RN
and T.PROP = P.RN
and P.ATTRIBUTE = A.RN)
loop
/* Ñâîéñòâî ôèñêàëüíîãî äîêóìåíòà */
NODE(SNAME => 'FISCDOC_PROP');
/* Äëÿ íåêîòîðûõ òýãîâ íåîáõîäèì òåñòîâûé íàáîð äàííûõ, åñëè ýòî òåñòîâûé ñåðâèñ */
if (BTEST_SRV) then
/* Ïîäñòàâèì òåñòîâûé ÈÍÍ */
if (SP.SCODE = '1018') then
SP.SVALUE := UDO_PKG_EXS_ATOL.STEST_INN;
SP.SVAL_STR := UDO_PKG_EXS_ATOL.STEST_INN;
end if;
/* Ïîäñòàâèì òåñòîâûé àäðåñ ðàñ÷¸òîâ */
if (SP.SCODE = '1187') then
SP.SVALUE := UDO_PKG_EXS_ATOL.STEST_ADDR;
SP.SVAL_STR := UDO_PKG_EXS_ATOL.STEST_ADDR;
end if;
end if;
/* Äàííûå ñâîéñòâà ôèñêàëüíîãî äîêóìåíòà */
NODE(SNAME => 'SCODE', SVALUE => SP.SCODE);
NODE(SNAME => 'SNAME', SVALUE => SP.SNAME);
NODE(SNAME => 'VALUE', SVALUE => UDO_GET_FISCDOCSPROP_VALUE(SP.RN));
NODE(SNAME => 'SVALUE', SVALUE => SP.VAL_STR);
NODE(SNAME => 'NVALUE', NVALUE => SP.VAL_NUMB);
NODE(SNAME => 'DVALUE', DVALUE => SP.VAL_DATE);
NODE(SNAME => 'DTVALUE', DVALUE => SP.VAL_DATETIME);
NODE(SNAME => 'VALUE', SVALUE => SP.SVALUE);
NODE(SNAME => 'SVALUE', SVALUE => SP.SVAL_STR);
NODE(SNAME => 'NVALUE', NVALUE => SP.NVAL_NUMB);
NODE(SNAME => 'DVALUE', DVALUE => SP.DVAL_DATE);
NODE(SNAME => 'DTVALUE', DVALUE => SP.DVAL_DATETIME);
/* Çàêðûâàåì ñâîéñòâî ôèñêàëüíîãî äîêóìåíòà */
PKG_XMLFAST.UP;
end loop;
@ -169,11 +152,11 @@ begin
/* Ôèíàëèçèðóåì ñáîðêó XML-äîêóìåíòà */
PKG_XMLFAST.EPILOGUE(LDATA => CDATA);
/* Îòïðàâëÿåì ñôîðìèðîâàííûé äîêóìåíò */
PKG_EXS.QUEUE_PUT(NEXSSERVICEFN => UDO_PKG_EXS_ATOL.UTL_FISCDOC_GET_REG_EXSFN(NFISCDOC => NFISCDOC),
PKG_EXS.QUEUE_PUT(NEXSSERVICEFN => REXSSERVICEFN.RN,
BMSG => CLOB2BLOB(LCDATA => CDATA, SCHARSET => 'UTF8'),
NLNK_COMPANY => NCOMPANY,
NLNK_DOCUMENT => NFISCDOC,
SLNK_UNITCODE => 'UDO_FiscalDocuments',
SLNK_UNITCODE => 'UDO_FiscalDocuments',
NNEW_EXSQUEUE => NEXSQUEUE);
end;
/

View File

@ -2,7 +2,7 @@
Сервис интеграции ПП Парус 8 с WEB API
Дополнительный модуль: Взаимодействие с "АТОЛ-Онлайн" (v4) в формате ФФД 1.05
Полный формат формируемой посылки:
Полный формат формируемой посылки для чека:
reqBody = {
timestamp: "",
external_id: 0,
@ -98,6 +98,39 @@
}
}
};
Полный формат формируемой посылки для чека коррекции:
reqBody = {
timestamp: "",
external_id: 0,
correction: {
company: {
sno: "",
inn: "",
payment_address: ""
},
correction_info: {
type: "",
base_date: "",
base_number: "",
base_name: ""
},
payments: [
{
type: "",
sum: 0
}
],
vats: [
{
type: "",
sum: 0
}
],
cashier: ""
}
};
*/
//----------------------
@ -113,9 +146,13 @@ const { buildURL } = require("@core/utils"); //Вспомогательные ф
// Глобальные константы
//---------------------
//Код круппы ККТ
//Код круппы ККТ (тестовой, для боевой - прописать его в настройках сервиса)
const SGROUP_CODE = "v4-online-atol-ru_4179";
//Типы документов по значению "Наименование документа" (тэг 1000)
const SDOCTYPE_TAG100_CHECK = "3"; //Чек
const SDOCTYPE_TAG100_CHECK_CORR = "31"; //Чек коррекции
//Статусы документов АТОЛ-онлайн
const SSTATUS_DONE = "done"; //Готово
const SSTATUS_FAIL = "fail"; //Ошибка
@ -164,14 +201,16 @@ const paymentObject = {
const paymensOperation = {
sName: "Тип операции",
vals: {
"1": "sell",
"2": "sell_refund",
"3": "buy",
"4": "buy_refund"
"3_1": "sell", //Тэг 1000 = 3 (чек), тэг 1054 = 1 (приход)
"31_2": "sell_refund", //Тэг 1000 = 31 (коррекция), тэг 1054 = 2 (возврат прихода)
"31_1": "sell_correction", //Тэг 1000 = 31 (коррекция), тэг 1054 = 1 (приход)
"3_3": "buy", //Тэг 1000 = 3 (чек), тэг 1054 = 3 (расход)
"31_4": "buy_refund", //Тэг 1000 = 31 (коррекция), тэг 1054 = 4 (возврат расхода)
"31_3": "buy_correction" //Тэг 1000 = 31 (коррекция), тэг 1054 = 3 (расход)
}
};
//Словарь - ставка НДС позиции чека
//Словарь - Ставка НДС позиции чека
const receiptItemVat = {
sName: "Ставка НДС позиции чека",
vals: {
@ -184,6 +223,15 @@ const receiptItemVat = {
}
};
//Словарь - Тип коррекции
const correctionInfoType = {
sName: "Тип коррекции",
vals: {
"0": "self",
"1": "instruction"
}
};
//------------
// Тело модуля
//------------
@ -281,6 +329,92 @@ const strDDMMYYYYHHMISStoDate = sDate => {
return res;
};
//Получение списка оплат по чеку
const getPayments = props => {
//Список платежей
let payments = [];
//Сумма по чеку электронными
if (getPropValueByCode(props, "1081", "NUM") !== null) {
payments.push({
type: 1,
sum: getPropValueByCode(props, "1081", "NUM")
});
}
//Сумма по чеку предоплатой (зачет аванса и (или) предыдущих платежей)
if (getPropValueByCode(props, "1215", "NUM") !== null) {
payments.push({
type: 2,
sum: getPropValueByCode(props, "1215", "NUM")
});
}
//Сумма по чеку постоплатой (кредит)
if (getPropValueByCode(props, "1216", "NUM") !== null) {
payments.push({
type: 3,
sum: getPropValueByCode(props, "1216", "NUM")
});
}
//Сумма по чеку встречным представлением
if (getPropValueByCode(props, "1217", "NUM") !== null) {
payments.push({
type: 4,
sum: getPropValueByCode(props, "1217", "NUM")
});
}
//Возвращаем результат
return payments;
};
//Получение списка налогов по чеку
const getVats = props => {
//Список налогов
let vats = [];
//Сумма расчета по чеку без НДС;
if (getPropValueByCode(props, "1105", "NUM") !== null) {
vats.push({
type: "none",
sum: getPropValueByCode(props, "1105", "NUM")
});
}
//Сумма расчета по чеку с НДС по ставке 0%;
if (getPropValueByCode(props, "1104", "NUM") !== null) {
vats.push({
type: "vat0",
sum: getPropValueByCode(props, "1104", "NUM")
});
}
//Сумма НДС чека по ставке 10%;
if (getPropValueByCode(props, "1103", "NUM") !== null) {
vats.push({
type: "vat10",
sum: getPropValueByCode(props, "1103", "NUM")
});
}
//Сумма НДС чека по ставке 20%;
if (getPropValueByCode(props, "1102", "NUM") !== null) {
vats.push({
type: "vat20",
sum: getPropValueByCode(props, "1102", "NUM")
});
}
//Сумма НДС чека по расч. ставке 10/110;
if (getPropValueByCode(props, "1107", "NUM") !== null) {
vats.push({
type: "vat110",
sum: getPropValueByCode(props, "1107", "NUM")
});
}
//Сумма НДС чека по расч. ставке 20/120
if (getPropValueByCode(props, "1106", "NUM") !== null) {
vats.push({
type: "vat120",
sum: getPropValueByCode(props, "1106", "NUM")
});
}
//Возвращаем результат
return vats;
};
//Обработчик "До" подключения к сервису
const beforeConnect = async prms => {
return {
@ -341,119 +475,79 @@ const beforeRegBillSIR = async prms => {
//Сохраним короткие ссылки на документ и его свойства
const doc = parseRes.FISCDOC;
const docProps = parseRes.FISCDOC.FISCDOC_PROPS.FISCDOC_PROP;
//Определим тип операции
const sOperation = mapDictionary(paymensOperation, getPropValueByCode(docProps, "1054"));
//Определим тип операции по значению "Наименование документа" (тэг 1000) и "Признак расчета" (тэг 1054)
if (!getPropValueByCode(docProps, "1000"))
throw new Error("В фискальном документе не указано значение 'Наименование документа' (тэг 1000)");
if (!getPropValueByCode(docProps, "1054"))
throw new Error("В фискальном документе не указано значение 'Признак расчёта' (тэг 1054)");
const sOperation = mapDictionary(
paymensOperation,
`${getPropValueByCode(docProps, "1000")}_${getPropValueByCode(docProps, "1054")}`
);
//Собираем тело запроса в JSON из XML-данных документа
let reqBody = {
timestamp: doc.SDDOC_DATE,
external_id: doc.NRN,
receipt: {
client: {
email: getPropValueByCode(docProps, "1008"),
phone: ""
},
company: {
email: getPropValueByCode(docProps, "1117"),
sno: getPropValueByCode(docProps, "1055"),
inn: getPropValueByCode(docProps, "1018"),
payment_address: getPropValueByCode(docProps, "1187")
},
items: [
{
name: getPropValueByCode(docProps, "1030"),
price: getPropValueByCode(docProps, "1079", "NUM"),
quantity: getPropValueByCode(docProps, "1023", "NUM"),
sum: getPropValueByCode(docProps, "1043", "NUM"),
measurement_unit: getPropValueByCode(docProps, "1197"),
payment_method: mapDictionary(paymentMethod, getPropValueByCode(docProps, "1214")),
payment_object: mapDictionary(paymentObject, getPropValueByCode(docProps, "1212")),
vat: {
type: mapDictionary(receiptItemVat, getPropValueByCode(docProps, "1199", "NUM")),
sum: getPropValueByCode(docProps, "1200", "NUM")
let reqBody = {};
if (getPropValueByCode(docProps, "1000") === SDOCTYPE_TAG100_CHECK) {
//Собираем чека
reqBody = {
timestamp: doc.SDDOC_DATE,
external_id: doc.NRN,
receipt: {
client: {
email: getPropValueByCode(docProps, "1008"),
phone: ""
},
company: {
email: getPropValueByCode(docProps, "1117"),
sno: getPropValueByCode(docProps, "1055"),
inn: getPropValueByCode(docProps, "1018"),
payment_address: getPropValueByCode(docProps, "1187")
},
items: [
{
name: getPropValueByCode(docProps, "1030"),
price: getPropValueByCode(docProps, "1079", "NUM"),
quantity: getPropValueByCode(docProps, "1023", "NUM"),
sum: getPropValueByCode(docProps, "1043", "NUM"),
measurement_unit: getPropValueByCode(docProps, "1197"),
payment_method: mapDictionary(paymentMethod, getPropValueByCode(docProps, "1214")),
payment_object: mapDictionary(paymentObject, getPropValueByCode(docProps, "1212")),
vat: {
type: mapDictionary(receiptItemVat, getPropValueByCode(docProps, "1199", "NUM")),
sum: getPropValueByCode(docProps, "1200", "NUM")
}
}
}
],
total: getPropValueByCode(docProps, "1020", "NUM")
}
};
//Добавим общие платежи
let payments = [];
//Сумма по чеку электронными
if (getPropValueByCode(docProps, "1081", "NUM") !== null) {
payments.push({
type: 1,
sum: getPropValueByCode(docProps, "1081", "NUM")
});
],
total: getPropValueByCode(docProps, "1020", "NUM")
}
};
//Добавим общие платежи
let payments = getPayments(docProps);
if (payments.length > 0) reqBody.receipt.payments = payments;
//Добавим общие налоги
let vats = getVats(docProps);
if (vats.length > 0) reqBody.receipt.vats = vats;
} else {
//Собираем чек коррекции
reqBody = {
timestamp: doc.SDDOC_DATE,
external_id: doc.NRN,
correction: {
company: {
sno: getPropValueByCode(docProps, "1055"),
inn: getPropValueByCode(docProps, "1018"),
payment_address: getPropValueByCode(docProps, "1187")
},
correction_info: {
type: mapDictionary(correctionInfoType, getPropValueByCode(docProps, "1173")),
base_date: getPropValueByCode(docProps, "1178"),
base_number: getPropValueByCode(docProps, "1179"),
base_name: getPropValueByCode(docProps, "1177")
},
payments: getPayments(docProps),
vats: getVats(docProps)
}
};
}
//Сумма по чеку предоплатой (зачет аванса и (или) предыдущих платежей)
if (getPropValueByCode(docProps, "1215", "NUM") !== null) {
payments.push({
type: 2,
sum: getPropValueByCode(docProps, "1215", "NUM")
});
}
//Сумма по чеку постоплатой (кредит)
if (getPropValueByCode(docProps, "1216", "NUM") !== null) {
payments.push({
type: 3,
sum: getPropValueByCode(docProps, "1216", "NUM")
});
}
//Сумма по чеку встречным представлением
if (getPropValueByCode(docProps, "1217", "NUM") !== null) {
payments.push({
type: 4,
sum: getPropValueByCode(docProps, "1217", "NUM")
});
}
//Если есть хоть один платёж - помещаем массив в запрос
if (payments.length > 0) reqBody.receipt.payments = payments;
//Добавим общие налоги
let vats = [];
//Сумма расчета по чеку без НДС;
if (getPropValueByCode(docProps, "1105", "NUM") !== null) {
vats.push({
type: "none",
sum: getPropValueByCode(docProps, "1105", "NUM")
});
}
//Сумма расчета по чеку с НДС по ставке 0%;
if (getPropValueByCode(docProps, "1104", "NUM") !== null) {
vats.push({
type: "vat0",
sum: getPropValueByCode(docProps, "1104", "NUM")
});
}
//Сумма НДС чека по ставке 10%;
if (getPropValueByCode(docProps, "1103", "NUM") !== null) {
vats.push({
type: "vat10",
sum: getPropValueByCode(docProps, "1103", "NUM")
});
}
//Сумма НДС чека по ставке 20%;
if (getPropValueByCode(docProps, "1102", "NUM") !== null) {
vats.push({
type: "vat20",
sum: getPropValueByCode(docProps, "1102", "NUM")
});
}
//Сумма НДС чека по расч. ставке 10/110;
if (getPropValueByCode(docProps, "1107", "NUM") !== null) {
vats.push({
type: "vat110",
sum: getPropValueByCode(docProps, "1107", "NUM")
});
}
//Сумма НДС чека по расч. ставке 20/120
if (getPropValueByCode(docProps, "1106", "NUM") !== null) {
vats.push({
type: "vat120",
sum: getPropValueByCode(docProps, "1106", "NUM")
});
}
//Если есть хоть один налог - помещаем массив в запрос
if (vats.length > 0) reqBody.receipt.vats = vats;
//Собираем общий результат работы
let res = {
options: {
@ -581,10 +675,14 @@ const afterGetBillInfo = async prms => {
TIMESTAMP: resp.timestamp,
//Дата и время документа из ФН
TAG1012: resp.payload.receipt_datetime,
//Номер смены
TAG1038: resp.payload.shift_number,
//Фискальный номер документа
TAG1040: resp.payload.fiscal_document_number,
//Номер ФН
TAG1041: resp.payload.fn_number,
//Номер чека в смене
TAG1042: resp.payload.fiscal_receipt_number,
//Фискальный признак документа
TAG1077: resp.payload.fiscal_document_attribute
};