ЦИК-ЦБ-КО 4012-У

Автор:tema
Дата:29.06.2016
Просмотров:5380
Скачиваний:661
Оценка:, Оценок - 8
Скачать (zip-файл; Размер - 392315)

Обсудить в форуме

Описание

Разбор запроса и формирование ответа для взаимодействия кредитной организации и центральной избирательной комиссии через центральный банк.
Только счета (MVODB+Retail), без ценных бумаг.
Без работы с криптографией.
Есть заимствования из раздела Библиотека разработчика.

Текст примера

 /* Формирование ответа на запрос ЦИК о счетах кандидатов */
/* Версия 0.6c 20160823 */
/* см Требования к составу, названиям и структуре файлов обмена, используемых при взаимодействии между ФЦИ при ЦИК России, Банком России и участниками финансового рынка */
import rsexts;
import boostre;
//import "nss_by_nightmare2000.mac"; //https://isupport.softlab.ru/portal/Samples/sample.asp?Typ=7&Id=250
import BankInter, ClnInter, CurrInter, CtgInter;
//import formdate;
import globals;
import "regcls.mac";
import assarray;   //для кодов квитанции
import feldsher;


const ВерсПрог="КБ392 ЦИК-ЦБР 0.6c 20160823";
const КАТЕГОРИЯ_EMAIL_ПОЛЬЗОВАТЕЛЯ=...; //Сделать категорию e-mail по образцу 900
const mybank_ini="tandem.ini";

var folderIN = GetIniString ("CIKCBR_ImportFolder", mybank_ini);  //в OBJ должен лежать .ini файл и там строка CIKCBR_ImportFolder=..\Import\CIK_CBR
var folderOUT= GetIniString ("CIKCBR_ExportFolder", mybank_ini);  //в OBJ должен лежать .ini файл и там строка CIKCBR_ExportFolder=..\Export\CIK_CBR
var folderXSD= GetIniString ("CIKCBR_XsdFolder",    mybank_ini);  //в OBJ должен лежать .ini файл и там строка CIKCBR_XsdFolder=..\Import\CIK_CBR

var sOGRN_CIK="1027700466640";       //ОГРН ЦЕНТРАЛЬНАЯ ИЗБИРАТЕЛЬНАЯ КОМИССИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
//var Порог =0.8; //%% совпадения ФИО

var reg=TReg("USER_MAC\\CIK_CBR\\");
var flagValidateQuery:Bool =reg.Get("VALIDATE QUERY", true); //проверять запрос по схеме
var flagValidateAnswer:Bool=reg.Get("VALIDATE ANSWER",true); //проверять ответ по схеме
var flagValidateKvt:Bool=reg.Get("VALIDATE KVT",true); //проверять ответ-квитанцию по схеме
var flagKvtNotFound:Bool=reg.Get("KVT 1000",true); //формировать квитанцию если совпадений не найдено
var flagKvtXsdError:Bool=reg.Get("KVT 1003",true); //формировать квитанцию если ошибка в XSD схеме
var flagUseXsdPathHack:Bool=reg.Get("USE XSD PATH HACK",true); //
var flagIgnoreQueryValidateError:Bool =reg.Get("IGNORE QUERY VALIDATE ERROR", true); //прогонять запрос даже если есть ошибки по схеме валидации
var modeRetailRestDef=1;
if ("3202"=={Reg_Num})
    modeRetailRestDef=2;
end;
var modeRetailRest:Integer=reg.Get("MODE RETAIL REST", modeRetailRestDef); //способ получения остатка по счёту RETAIL  1-pc_drest, 2-sbdepdoc;

var ДистанцияФИО:Integer=reg.Get("ДИСТАНЦИЯ СТРОК ФИО", 5); //вместо порога
var reportClassName:String=reg.Get("REPORT CLASS",""); //Условное имя класса отчёта для списка на повторную идентификацию (XCR, ODT)
var rep; //Отчёт

var sOutFileName;

var DOMDoc;     //запрос, он же ответ
var fPaperKind=TBFile("paprkind.dbt","R",1,null,"bank.def");
var okPaperKind:Bool;
var fRegDoc=TBFile("regdoc.dbt","R",4,null,"bank.def");
var flagFind:Bool;
//flagFindAcc:Bool;
var fAccountMvodb =TBFile("account.dbt", "R",4,null,  "bank.def");
var fAccountRetail=TBFile("depositr.dbt","R",4,null,"sbbank.def");
var fRestRetail   =TBFile("pc_drest.dbt","R",0,null,"sbbank.def");
var fPersn        =TBFile("persn.dbt",   "R",1,null,  "bank.def");
var fClient       =TBFile("client.dbt",  "R",0,null,  "bank.def");
var fSbdepdoc     =tbfile("sbdepdoc", "R", 6, "sbdepdoc.dbt", "sbbank.def");

var aAccMask=TArray();
var aAccType=TArray();

var cntPerson=TArray(); //со счетами
var cntPersonTotal=TArray(); //всего кандидатов в запросе
var cntBadDoc=TArray();  //не найден типдокумента
var cntFoundDoc=TArray(); //найден документ
var cntFoundFIODR=TArray(); //найден 
var queryName=TArray();
var cntPersonDoc=TArray();  // найден документ и совпали ФИО
var queryXsdResult=TArray();
var answerXsdResult=TArray();
var answerName=TArray();
var iQueryNumber:Integer;  //порядковый номер запроса в пределах календарного года (0001, 0002 : 9999) в рамках обмена информацией по которому совершено действие, повлекшее формирование квитанции.
var sMessageId:String;
var sQueryType:String; // T - тип запроса. Имеет значение Z - для пакетного запроса и P - для персонального запроса; 
var cntKvt=0;

var t_start=Time();


var domXsdQuery, domXsdAnswer;
var objQuerySchemaCache;
var objXsdErr;
 

aAccMask[0]="40817*, 40820*";                                 aAccType[0]="Текущий счет";
aAccMask[1]="40802*";                                         aAccType[1]="Расчетный счет";
aAccMask[2]="40803*, 40804*, 40805*, 40806*, 40809*, 40813*"; aAccType[2]="Специальный банковский счет";
aAccMask[3]="423*,426*,42108-42114";                          aAccType[3]="Счет по вкладу (депозиту)";
aAccMask[4]="хз";                                             aAccType[4]="Обезличенный металлический счет";

//текстовое описание кода квитанции по-умолчанию
var aKvtCode=TAssArrayIS(
    1001, "некорректная подпись",
    1002, "невозможно расшифровать файл обмена",
    1003, "формат файла обмена не соответствует схеме",
    1004, "ошибка логической обработки файла обмена",
    2001, "некорректная подпись",
    2002, "невозможно расшифровать файл обмена",
    2003, "формат файла обмена не соответствует схеме",
    2004, "ошибка логической обработки файла обмена",
    1010, "сообщение об успешной отправке запроса",
    2010, "сообщение об успешной доставке ответа",
    1000, "сообщение об отсутствии информации по проверяемым лицам",
    2000, "сообщение об успешной обработке ответа",
    2005, "сообщение об успешной обработке ответа, и наличии в ответе проверяемых лиц с изменившимися идентификационными данными",
    2006, "несвоевременное представление сведений"

    );

if (reportClassName=="XCR")
    if (InstLoadModule("xcr.mac"))
        //rep=XCReport();
        rep=GenObject("XCReport");
        rep.SetArrayHead("Код в АБС", "ФИО в АБС", "ФИО в запросе", "Дистанция ФИО", "Тип док. в АБС","Номер док. в АБС", "Тип док. в запросе","Номер док. в запросе","Дата рождения в АБС","Дата рождения в запросе","Адрес в АБС","Адрес в запросе");
    end;
elif (reportClassName=="ODT") 
    if (InstLoadModule("toffdoc.mac"))
        //rep=XCReport();
        rep=GenObject("TOpenDocForm","На повторную идентификацию.odt");
        rep.Table("Повторная_идетификация");
    end;
end;

// структура списка для повторной идентификации
var aReIdentReport=TArray(); //список клинтов для повторной идентификации

class TReIdentReport(client_)
    var ClientID=client_;
    var ClientCode; //код клиента в АБС
    var fioRS;
    var fioCIK;
    var fioDistance;
    var docTypeRS;
    var docNumRS;
    var docTypeCIK;
    var docNumCIK;
    var adrRS;
    var adrCIK;
    var bdRS;
    var bdCIK;

    macro GetRsDoc(iKind) 
        var aRegDoc=TArray();

        // если в АБС существует такой тип документа как в запросе ЦИК
        if (okPaperKind)
            GetClientDocuments(ClientCode, aRegDoc, fPaperKind.rec.PaperKind, 1);
            if (aRegDoc.size>0)
                // и он есть уклиента, то выводим этот  документ
                aReIdentReport[aReIdentReport.Size-1].docTypeRS=fPaperKind.rec.CodeDocum;
                aReIdentReport[aReIdentReport.Size-1].docNumRS   =Trim(aRegDoc[0].rec.Series+" "+aRegDoc[0].rec.DocNum);
                return;
            end;
        end;

        // иначе выводим паспорт, если есть. глубже не копаем
        GetClientDocuments(ClientCode, aRegDoc, 0, 1);
        if (aRegDoc.size>0)
            aReIdentReport[aReIdentReport.Size-1].docTypeRS ="21";
            aReIdentReport[aReIdentReport.Size-1].docNumRS   =Trim(aRegDoc[0].rec.Series+" "+aRegDoc[0].rec.DocNum);
        end;
    end; //macro

    ClientCode=GetClientCodeByID(ClientID);
    adrRS=GetClientAddress (ClientID, ADRTYPE_JUR);
    bdRS=GetClientBirthday (ClientID);

end;

macro MakeReportReIdent
    if (aReIdentReport.size>0)
        var e;
        for(e,aReIdentReport)
            if(ValType(rep)==V_GENOBJ)
                rep.WriteRow(
                    e.ClientCode,
                    e.fioRS,
                    e.fioCIK,
                    e.fioDistance,
                    e.docTypeRS,
                    e.docNumRS,
                    e.docTypeCIK,
                    e.docNumCIK,
                    e.bdRS,
                    e.bdCIK,
                    e.adrRS,
                    e.adrCIK
                    );
            end;
        end;
    end;
end;
                                               
macro MakeReport
    var iQuery;
    [------------------------------------------------------------------------------------------------------------------------------------];
    [################################ ### ##### ##### ##### ##### ##### ##### #### ######################################################]
    ("Файл","XSD","Всего","Отв.","Док","Д+ФИО","ПлохД","ФИОДР","aXSD","Файл ответа");
    For (iQuery, 0, queryName.Size-1,1)
        if ((queryXsdResult[iQuery]=="OK") or (ValType(queryXsdResult[iQuery])==V_UNDEF) or flagIgnoreQueryValidateError)
            [################################ ### ##### ##### ##### ##### ##### ##### #### ######################################################]
            (queryName[iQuery],queryXsdResult[iQuery],cntPersonTotal[iQuery],cntPerson[iQuery],cntFoundDoc[iQuery],cntPersonDoc[iQuery],cntBadDoc[iQuery],cntFoundFIODR[iQuery],answerXsdResult[iQuery],answerName[iQuery]);
        else
            [################################ ### ](queryName[iQuery],queryXsdResult[iQuery]);
        end;
    end;
    [------------------------------------------------------------------------------------------------------------------------------------];
    [Сформированно квитанций: ###](cntKvt);
end;


    macro GetXPath(strXPath, elem)

        if (DOMDoc.documentElement==NullVal)
            return false;
        end;

        if (ValType(elem)==V_UNDEF)
            elem=DOMDoc.documentElement;
        end;

        var domNodes=elem.selectNodes(strXPath);
        if (domNodes.Length>0)
            return Trim(domNodes.item(0).text);
        end;

        return "";
    end; //macro GetXPath
    
    macro GetXPathItems(strXPath, elem)

        if (DOMDoc.documentElement==NullVal)
            return false;
        end;

        if (ValType(elem)==V_UNDEF)
            elem=DOMDoc.documentElement;
        end;

        var domNodes=elem.selectNodes(strXPath);
        return domNodes;
    end; //macro GetXPath


macro CreateXMLObject(strXMLFilePath)
    var obj:object = NULL;

    private macro CreateXMLObject_Ver(strVer)
        obj=ActiveX ("Msxml"+strVer+".DOMDocument.6.0", null, true);
        obj.async = False;
        return true;
    OnError( er )
        return false;
    end;

    if(not CreateXMLObject_Ver("2"))  
        if(not CreateXMLObject_Ver(""))
            return null;
        end;      
    end; 

    if ((V_UNDEF!=ValType(strXMLFilePath)) and (""!=strXMLFilePath))
        obj.Load(strXMLFilePath);
        if ((obj.documentElement==NullVal) or not obj.documentElement)
            PrintLn("Дом не построен после загрузки "+strXMLFilePath);
            return null;
        end;
    end;

    obj.setProperty("SelectionLanguage", "XPath");

    return obj;  
end;

var aMatch=TArray();
var strErr="";
var iMatch;

var dirIN: TDirList = TDirList();
var domPersons;
var iAccType;

dirIN.List (folderIN+"\\"+"F"+sOGRN_CIK+"*.xml","F");
var iQuery, iPerson;
var Фамилия, Имя, Отчество, ДатаРожд;
var ДокВид, ДокСер, ДокНом;
var ДатаСвед:Date;
var Адрес; //для списка на проверку сведений
var fioRS, fioCIK;

//
macro GetRegionName(iRegion)
    var fRegion=TBFile("ptregion.dbt","R",0,null,"bank.def");
    fRegion.rec.CodeRegion=iRegion;
    if (fRegion.GetEQ)
        return  fRegion.rec.NameRegion;
    end;
    return "";
end; //macro GetRegionName()

//добавляет к строке адресу элемент из структурированного адреса
macro AddAdrPart(sResult:@string, sName, sKind)
    if (ValType(sResult)==V_UNDEF) sResult=""; end;
    sName=Trim(sName);
    if (sName!="")
        if ((ValType(sKind)!=V_UNDEF) and (Trim(sKind)!=""))
            sName=sKind+" "+sName;
        end;
        if (sResult=="")
            sResult=sName;
        else
            sResult=sResult+", "+sName;
        end;
    end;
end;

macro GetCtg(iObjectID, iCtgId:Integer, ObjType, defValue)
   var aVal=TArray();
   var iType;
   var sObjId;

   if (ValType(ObjType)==V_UNDEF) ObjType=OBJTYPE_CLIENT; end;

   if  (OBJTYPE_CLIENT==ObjType)
       sObjId=GetClientId(iObjectID);
   elif(14            ==ObjType)
       if ((Valtype(iObjectID)==V_UNDEF) or (0==iObjectID))
           iObjectID={oper};
       end;
       sObjId=String(iObjectID);
   end;


   if (GetCtgVal(ObjType, iCtgId, sObjId, aVal))
       if (aVal.Size==1)
           return aVal[0];
       elif (aVal.Size==0)
           //return ZeroValue(iType);
           //return null;
       else
           //return aVal;
           return aVal[0];
       end;
   end;
   //return null;
   return defValue;
end; //macro GetCtg

//true если клиент открыт на текущую дату
macro ClientIsOpen(ClientID)
    fClient.rec.Client=ClientID;
    if (fClient.GetEQ)
        return (fClient.rec.bdFinishDate==Date(0,0,0))
    end;
    exit(0,"Нарушение БД. Клиент "+ClientID);
end;

// остаток по счёту retail за дату
macro RetailRestV1(d)
    DebugBreak();
    fRestRetail.rec.Referenc=fAccountRetail.rec.Referenc;
    fRestRetail.rec.Type_Object=2001;
    fRestRetail.rec.Date_Rest=d;
    if (fRestRetail.GetLE
        and (fRestRetail.rec.Referenc==fAccountRetail.rec.Referenc)
        and (fRestRetail.rec.Type_Object==2001)
       )
        return fRestRetail.rec.Rest;
    end;

    return 0;
end;

/*
НОКССБАНК
Свернуть  еще моментик. Таскать остатки из pc_drest.dbt нежелательно. Нужно использовать базу sbdepdoc.dbt ( Eugene Korolev  22.08.2016 13:55:00 )
На вопрос почему - ответ:
Потому что :). Ретейл штука такая, с ней бывают (и не раз были уже) при выходе новых сборок разные интересные проблемы.
*/

const                      /* Виды документов:       */
  DD_AR            =  8,   /* Проводка в архиве      */
  DD_ARC           =  9,   /* Корректировка в архиве */
  DD_AUDIT_STORN   = 14,   /* Сторнирование операции */
  DD_AUDIT_DELETE  = 15,   /* Удаление операции      */
  DD_AUDIT_CORRECT = 16,   /* Корректировка операции */
  DD_DELETE        =  2;

macro IsServDocWithEst(doc_rec);
   var isDoc =(
      ( doc_rec.rec.KindOp    != DD_AR            )  AND  /* проводка в архиве      */
      ( doc_rec.rec.KindOp    != DD_ARC           )  AND  /* корректировка в архиве */
      ( doc_rec.rec.KindOp    != DD_AUDIT_STORN   )  AND  /* Сторнирование операции */
      ( doc_rec.rec.KindOp    != DD_AUDIT_DELETE  )  AND  /* Удаление операции      */
      ( doc_rec.rec.KindOp    != DD_AUDIT_CORRECT )  AND  /* Корректировка операции */
      ( doc_rec.rec.Action    != DD_DELETE        )
    );
    if (isDoc)
//    isDoc = ( GetBitFlag( doc_rec.Flags, 17 ) == 0 );   /* BIT_FLAG_HIDDEN */
    end;

    return IsDoc;
end;

//получение остатка по счёту Retail
macro RetailRestV2(Date_Document);
    fSbdepdoc.rec.Referenc = fAccountRetail.rec.Referenc;
    fSbdepdoc.rec.Date_Document = Date_Document;
    fSbdepdoc.rec.NumDayDoc = 32000;
    var RecFound = GetLE( fSbdepdoc );
    while ((RecFound) and (fSbdepdoc.rec.Referenc==fAccountRetail.rec.Referenc)and 
          (fSbdepdoc.rec.Date_Document<=Date_Document))
       if (not IsServDocWithEst(fSbdepdoc))
           RecFound=Prev(fSbdepdoc);
       else
           return  fSbdepdoc.rec.Rest;
       end;
    end;
    return $0.0;
end;

//получение остатка по счёту Retail с учётом настройки
macro RetailRest(d)
    if  (1==modeRetailRest)
        return RetailRestV2(d);
    elif (1==modeRetailRest)
        return RetailRestV1(d);
    end;
end;


// преобразует путь для вставки в атрибут xml
macro CnvPath(s)
    return flUrlCreateFromPath(s);
end; //macro CnvPath

macro Kvt(Type, ResultCode, ResultText)
    var domKvt=CreateXMLObject();
    
    domKvt.loadXml("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<File xsi:noNamespaceSchemaLocation='VO_CIK_CB_K_6.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'></File>");
    //var node = domKvt.createElement("File");
    var node = domKvt.documentElement;
    var sKvtFName:String;        
    var sFrom="K"+GetClientRegNumber({OurBankId});

    macro AddElement(sName,sValue)
        //node.SetAttribute(sName,sValue);
        var node = domKvt.documentElement.appendChild(domKvt.createElement(sName));
        node.Text=sValue;
    end; //macro AddElement

    if (ValType(ResultCode)==V_INTEGER)
        ResultCode=String(ResultCode:o:4);
    end;

    if (ValType(Type)==V_UNDEF)
        Type="8";
    end;

    if (ValType(ResultText)==V_UNDEF)
        ResultText=aKvtCode.Get(Int(ResultCode));
    end;

    cntKvt=cntKvt+1;

    //YZZZZZZZZZZZZZ_DDMMGG_hhmmss_Т_NNNN_XXXX_YZZZZZZZZZZZZZ.xml
    sKvtFName=sFrom+"_"+flFormDate("%d%m%y_%H%M%S")+"_K_"+ String(cntKvt:o:4)+"_"+ResultCode+"_"+"F"+sOGRN_CIK;

    
    AddElement("AcknowledgementType",Type);
    AddElement("ResultCode",ResultCode);
    AddElement("ResultText",ResultText);
    AddElement("To","F"+sOGRN_CIK);
    AddElement("From",sFrom);
    AddElement("MessageID",sKvtFName);
    AddElement("CorrelationMessageID", sMessageId);
    AddElement("MessageType","2");
    AddElement("Priority","5");
    //AddElement("CreateTime",formnowdate("%Y-%m-%d"));
    AddElement("CreateTime",flFormDate("%d.%m.%Y"));
     
    var validateOk=true;
    if (flagValidateKvt)                           
        var domXsdKvt=CreateXMLObject(folderXSD+"\\"+"VO_CIK_CB_K_6.xsd");
        var objKvtSchemaCache=ActiveX ("MSXML2.XMLSchemaCache.6.0", null, true);
        objKvtSchemaCache.Add("", domXsdKvt);

        if (flagUseXsdPathHack)
            domKvt.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation",CnvPath(folderXSD+"\\"+"VO_CIK_CB_K_6.xsd"));
        end;

        domKvt.Schemas=objKvtSchemaCache;
        var objXsdErr=domKvt.Validate();
        if (objXsdErr.errorCode==0)
            PrintLn("Проверка квитанции "+sKvtFName+" на соответствие XSD схеме прошла успешно");
            answerXsdResult[iQuery]="OK";
        else
            PrintLn("ERROR: Ошибка при проверке квитанции "+sKvtFName+" на соответствие XSD схеме. \n   Код: "+" "+String(objXsdErr.errorCode)+". ("+objXsdErr.reason+") ");
            answerXsdResult[iQuery]="ERR";
            validateOk=false;
        end;

        if (flagUseXsdPathHack)
            domKvt.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation","VO_CIK_CB_K_6.xsd");
        end;

    end;
    
    domKvt.Save(folderOUT+"\\"+sKvtFName+".xml");
    if ((ValType(answerName[iQuery])==V_UNDEF) or (answerName[iQuery]==""))
        answerName[iQuery]=sKvtFName+".xml";
    else
        answerName[iQuery]=answerName[iQuery]+","+sKvtFName+".xml";
    end;


end;

//---
if (flagValidateKvt)
    var domXsdKvt=CreateXMLObject(folderXSD+"\\"+"VO_CIK_CB_K_6.xsd");
    var objKvtSchemaCache=ActiveX ("MSXML2.XMLSchemaCache.6.0", null, true);
    objKvtSchemaCache.Add("", domXsdKvt);
end;

if (flagValidateQuery or flagValidateAnswer)
    domXsdQuery=CreateXMLObject(folderXSD+"\\"+"VO_CIK_CB_7.xsd");
    objQuerySchemaCache=ActiveX ("MSXML2.XMLSchemaCache.6.0", null, true);
    objQuerySchemaCache.Add("", domXsdQuery);
end;

//---- определение параметров КО
var aHouseKind=TArray(2);
aHouseKind[0]="дом";
aHouseKind[1]="строение";

var НаимКредит, КодСубКред, НеконфАдрКред, КонфАдрКред;
GetClientFullName({OurBankID},НаимКредит);

var aBankAddr=TArray();
GetClientAddresses ({OurBankID}, aBankAddr, ADRTYPE_JUR, 1);
if (aBankAddr.Size>0)
    КодСубКред=aBankAddr[0].rec.Region;
    
    AddAdrPart(@НеконфАдрКред,GetRegionName(aBankAddr[0].rec.Region));
    AddAdrPart(@НеконфАдрКред,aBankAddr[0].rec.Area,       aBankAddr[0].rec.AreaKind);
    AddAdrPart(@НеконфАдрКред,aBankAddr[0].rec.City,       aBankAddr[0].rec.CityKind);
    AddAdrPart(@НеконфАдрКред,aBankAddr[0].rec.Settlement, aBankAddr[0].rec.Place   );
                                                                                       
    AddAdrPart(@КонфАдрКред,  aBankAddr[0].rec.Street,     aBankAddr[0].rec.StreetKind); 
    AddAdrPart(@КонфАдрКред,  aBankAddr[0].rec.House,      aHouseKind[aBankAddr[0].rec.HouseKind]);
    AddAdrPart(@КонфАдрКред,  aBankAddr[0].rec.Building,   "корпус");
    AddAdrPart(@КонфАдрКред,  aBankAddr[0].rec.Building2,  "строение");
    AddAdrPart(@КонфАдрКред,  aBankAddr[0].rec.Apartment,  "офис");
else         
    //Tinkoff?
end;

var Телефон=GetCtg(null, 900, 14,{Phone_Numb});
var EMail=GetCtg(null, КАТЕГОРИЯ_EMAIL_ПОЛЬЗОВАТЕЛЯ, 14, GetClientEMail({OurBankId},ADRTYPE_JUR));


For (iQuery, 0, dirIN.Count-1,1)
      PrintLn(dirIN.Name(iQuery));
      queryName[iQuery]=dirIN.Name(iQuery);
      answerXsdResult[iQuery]="";
      answerName[iQuery]="";

      iMatch=boostre_match("^([A-Z])(\\d{13})_(\\d{6})_([ZP])_(\\d{4})\.xml$", dirIN.Name(iQuery), strErr, aMatch);

      if (iMatch>0)
          //1-тип, 2 - id, 3 - дата, 4 - тип запроса, 5 - номер
          iQueryNumber=Int(aMatch[5]); //для квинанции
          sMessageId=SubStr(aMatch[0],1,StrLen(aMatch[0])-4); //для квинанции
          sQueryType=aMatch[4];
            DOMDoc=CreateXMLObject(folderIN+"\\"+dirIN.Name(iQuery));
            if (not DOMDoc)
               PrintLn("Ошибка загрузки "+folderIN+"\\"+dirIN.Name(iQuery));
               queryXsdResult[iQuery]="ELD";

               continue;
            end;

            Log_WriteCheckpoint (1002,"Обработка запроса ЦИК ЦБР "+queryName[iQuery]);

            if (flagValidateQuery)
                //подменяем путь к XSD
                if (flagUseXsdPathHack)
                    domDoc.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation",CnvPath(folderXSD+"\\"+"VO_CIK_CB_7.xsd"));
                end;

                domDoc.Schemas=objQuerySchemaCache;
                objXsdErr=domDoc.Validate();
                if (objXsdErr.errorCode==0)
                    PrintLn("Проверка запроса на соответствие XSD схеме прошла успешно");
                    queryXsdResult[iQuery]="OK";
                else
                    PrintLn("ERROR: Ошибка при проверке запроса на соответствие XSD схеме. \n   Код: "+" "+String(objXsdErr.errorCode)+". ("+objXsdErr.reason+") "+
                        "\n   Строка: "+objXsdErr.Line+", "+objXsdErr.linepos + 
                        " в файле: "+objXsdErr.filepos+
                        "\n   Исходный текст: "+objXsdErr.srcText);
                    queryXsdResult[iQuery]="ERR";
                    if (flagKvtXsdError)
                        Kvt(null, 1003, objXsdErr.reason);
                    end;

                end;

                //восстанавливаем путь к XSD
                if (flagUseXsdPathHack)
                    domDoc.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation","VO_CIK_CB_7.xsd");
                end;

                //если была ошибка в схеме, то дальнейшую обработку не производим
                if ((objXsdErr.errorCode!=0) and (not flagIgnoreQueryValidateError))
                    continue;
                end;

            end;

            domPersons=GetXPathItems("/Файл/Персона");
            if (ValType(domPersons)==V_GENOBJ)
                  cntPerson[iQuery]=0;
                  cntBadDoc[iQuery]=0;
                  cntPersonTotal[iQuery]=domPersons.length;
                  cntFoundDoc[iQuery]=0;
                  cntPersonDoc[iQuery]=0;
                  cntFoundFIODR[iQuery]=0;
                  for(iPerson, 0, domPersons.length-1, 1)
                  
                      if (0==iPerson)
                          var nodeInfOrg=DOMDoc.documentElement.insertBefore(DOMDoc.CreateElement("ИнфОрг"),domPersons.item(iPerson));
                          nodeInfOrg.setAttribute("Название",   НаимКредит);
                          nodeInfOrg.setAttribute("Адрес",   GetClientAddress({OurBankID}, ADRTYPE_JUR));
                          nodeInfOrg.setAttribute("ИНН",     GetClientINN({OurBankID}));
                          nodeInfOrg.setAttribute("ОГРН",    GetClientRegNumber({OurBankID}));
                          nodeInfOrg.setAttribute("ФИО",       GetFioOper({oper}));
                          nodeInfOrg.setAttribute("Телефон",   Телефон	);
                          nodeInfOrg.setAttribute("ЭлПочта",   EMail);

                      end;
                      flagFind=false;
                      //flagFindAcc=false;
                      var aNodeAccount=TArray;

                      Фамилия  =GetXPath("ПерсИнфо/ФИОД/@Фамилия",       domPersons.item(iPerson));
                      Имя      =GetXPath("ПерсИнфо/ФИОД/@Имя",           domPersons.item(iPerson));
                      Отчество =GetXPath("ПерсИнфо/ФИОД/@Отчество",      domPersons.item(iPerson));
                      ДатаРожд =GetXPath("ПерсИнфо/ФИОД/@ДатаРожд",      domPersons.item(iPerson));
                      ДокВид   =GetXPath("ПерсИнфо/Документ/@КодВидДок", domPersons.item(iPerson));
                      ДокСер   =GetXPath("ПерсИнфо/Документ/@Серия",     domPersons.item(iPerson));
                      ДокНом   =GetXPath("ПерсИнфо/Документ/@Номер",     domPersons.item(iPerson));
                      Адрес    =GetXPath("ПерсИнфо/Адрес/@НеконфАдрес",  domPersons.item(iPerson))+", "
                               +GetXPath("ПерсИнфо/Адрес/@КонфАдрес",    domPersons.item(iPerson));

                      if ((ДокВид=="21") and (StrLen(ДокСер)==5) and (SubStr(ДокСер,3,1)==" "))
                          ДокСер=SubStr(ДокСер,1,2)+SubStr(ДокСер,4,2);
                      end;

                      ДатаСвед =Date(GetXPath("СлужИнфо/Наименование/@ДатаСвед",     domPersons.item(iPerson)));

                      PrintLn(Фамилия,"\t",Имя,"\t",Отчество,"\t",ДатаРожд);

                      //ищем в таблицах RS чо за документ такой, наверняка же паспорт
                      fPaperKind.rec.CodeDocum=string(int(ДокВид):o:2);
                      okPaperKind=fPaperKind.GetEQ;
                      if (okPaperKind)

                          //а теперь ищем всех клиентов, у которых такой паспорт :) 
                          fRegDoc.rec.RDKind=fPaperKind.rec.PaperKind;
                          fRegDoc.rec.Series=ДокСер;
                          fRegDoc.rec.DocNum=ДокНом;
                          fRegDoc.rec.Client=0;
                          var getOk=fRegDoc.GetGE;
                          while (getOk and (fRegDoc.rec.RDKind==fPaperKind.rec.PaperKind) and (fRegDoc.rec.Series==ДокСер) and (fRegDoc.rec.DocNum==ДокНом))
                              cntFoundDoc[iQuery]=cntFoundDoc[iQuery]+1;
                              GetClientFullName(fRegDoc.rec.Client,fioRS);
                              fioCIK=Trim(Фамилия+" "+Имя+" "+Отчество);
                              //не паримся с алгоритмом её, парных букв, вариантами имён. считаем, что депутаут как террорист
                              //var l=LevensteinDistance(fioRS,fioCIK);
                              //var l=НечеткоеСравнениеСтрок(4,StrUpr(fioRS),StrUpr(fioCIK));
                              //PrintLn(fioRS + " совпадает с "+ fioCIK+" на "+l);
                              var l=flLevenshteinDistance(StrUpr(fioRS),StrUpr(fioCIK));
                              PrintLn(fioRS + " отличается от "+ fioCIK+" на "+l);

                              //if (l>=Порог)
                              if (l<=ДистанцияФИО)

                                  flagFind=true;

                                  cntPersonDoc[iQuery]=cntPersonDoc[iQuery]+1;

                                  //поиск по счетам МВОДБ
                                  fAccountMvodb.rec.Open_Close="";
                                  fAccountMvodb.rec.Client     = fRegDoc.rec.Client;
                                  fAccountMvodb.rec.Sort       = "";

                                  var getOkAcc=fAccountMvodb.GetGE();
                                  while (getOkAcc and (fAccountMvodb.rec.Open_Close!="X") and (fAccountMvodb.rec.Client==fRegDoc.rec.Client))
                                      for(iAccType,0,aAccMask.Size-1)
                                          if (0==CompareStrWithMasks (aAccMask[iAccType], fAccountMvodb.rec.Account))
                                              PrintLn(fAccountMvodb.rec.Account," ",aAccType[iAccType]);
                                              //if (fAccountMvodb.rec.R0!=$0) 
                                              //08.07.2016 и нулевые тоже
                                                  aNodeAccount[aNodeAccount.Size]=DOMDoc.CreateElement("Счет");
                                                  aNodeAccount[aNodeAccount.Size-1].setAttribute("ВидСчета",   aAccType[iAccType]);
                                                  aNodeAccount[aNodeAccount.Size-1].setAttribute("НомерСчета", fAccountMvodb.rec.Account);
                                                  aNodeAccount[aNodeAccount.Size-1].setAttribute("Остаток",    Abs(RestA(fAccountMvodb.rec.Account,0,ДатаСвед-1))); //ДатаСвед-на, (ДатаСвед-1)-за
                                              //end;
                                              //flagFindAcc=true;
                                              break;
                                          end;
                                      end;
                                      getOkAcc=fAccountMvodb.next;
                                  end;

                                  //поиск по счетам Retail
                                  fAccountRetail.rec.CodClient=fRegDoc.rec.Client;
                                  fAccountRetail.rec.IsCur    =0;
                                  fAccountRetail.rec.Number   =0;

                                  getOkAcc=fAccountRetail.GetGE();
                                  while (getOkAcc and (fAccountRetail.rec.CodClient==fRegDoc.rec.Client))
                                      for(iAccType,0,aAccMask.Size-1)
                                          if (0==CompareStrWithMasks (aAccMask[iAccType], fAccountRetail.rec.Account))
                                              PrintLn(fAccountRetail.rec.Account," ",aAccType[iAccType]);
                                              //if (fAccountRetail.rec.Sum_Rest!=$0)
                                              //08.07.2016 и нулевые тоже
                                              if (((fAccountRetail.rec.Close_Date==Date(0,0,0)) or (fAccountRetail.rec.Close_Date>=ДатаСвед)) and (fAccountRetail.rec.Open_Date<ДатаСвед))
                                                  aNodeAccount[aNodeAccount.Size]=DOMDoc.CreateElement("Счет");
                                                  aNodeAccount[aNodeAccount.Size-1].setAttribute("ВидСчета",   aAccType[iAccType]);
                                                  aNodeAccount[aNodeAccount.Size-1].setAttribute("НомерСчета", fAccountRetail.rec.Account);
                                                  if (0==fAccountRetail.rec.IsCur)
                                                      aNodeAccount[aNodeAccount.Size-1].setAttribute("Остаток",    RetailRest(ДатаСвед-1));
                                                  else
                                                      aNodeAccount[aNodeAccount.Size-1].setAttribute("Остаток",    ConvSum (RetailRest(ДатаСвед-1), Int(SubStr(fAccountRetail.rec.Account,6,3)))); //не паримся с таблицей валют из Retail. дёргаем валюту из счёта
                                                  end;
                                              end;
                                              //flagFindAcc=true;
                                              break;
                                          end;
                                      end; //for acc
                                      getOkAcc=fAccountRetail.next;
                                  end; //while client

                              end;

                              //v0.6список на повторную идентификацию
                              if (l>0)
                                  //только тех, у кого стоит признак "Клиент" и он не закрыт
                                  if (IsClientOwnerKind(fRegDoc.rec.Client,PTK_CLIENT) and ClientIsOpen(fRegDoc.rec.Client))
                                      aReIdentReport[aReIdentReport.Size]=GenObject("TReIdentReport",fRegDoc.rec.Client);
                                      aReIdentReport[aReIdentReport.Size-1].fioRS      =fioRS;
                                      aReIdentReport[aReIdentReport.Size-1].fioCIK     =fioCIK;
                                      aReIdentReport[aReIdentReport.Size-1].fioDistance=l;
                                      aReIdentReport[aReIdentReport.Size-1].docTypeRS  =fPaperKind.rec.CodeDocum;
                                      aReIdentReport[aReIdentReport.Size-1].docNumRS   =Trim(fRegDoc.rec.Series+" "+fRegDoc.rec.DocNum);
                                      aReIdentReport[aReIdentReport.Size-1].docTypeCIK =ДокВид;
                                      aReIdentReport[aReIdentReport.Size-1].docNumCIK  =Trim(ДокСер+" "+ДокНом);
                                      aReIdentReport[aReIdentReport.Size-1].adrCIK     =Адрес;
                                      aReIdentReport[aReIdentReport.Size-1].bdCIK      =ДатаРожд;
                                  end;
                              end;

                              getOk=fRegDoc.Next;
                          end;
                          if (not flagFind)
                              PrintLn("Документ "+ ДокВид +" (" +fPaperKind.rec.Name+") " + ДокСер   +" "+ ДокНом   +" не найден");
                          end;

                      else
                          cntBadDoc[iQuery]=cntBadDoc[iQuery]+1;
                          PrintLn("ERROR: Не найден документ вида "+ДокВид);    
                      end;

                      if (not okPaperKind or not flagFind)
                          //--- а вдруг?
                          fPersn.rec.LastName=Фамилия;
                          var okPersn=fPersn.GetGE();
                          while  (okPersn and (StrUpr(fPersn.rec.LastName)==StrUpr(Фамилия)))
                              if ((StrUpr(fPersn.rec.Name)==StrUpr(Имя)) and  (StrUpr(fPersn.rec.Patronymic)==StrUpr(Отчество)) and (String(fPersn.rec.BirthDate:f)==ДатаРожд))
                                  PrintLn("WARNING: "+GetClientCodeById(fPersn.rec.ClientID)+" "+fPersn.rec.Name+" "+fPersn.rec.Patronymic+" "+"Совпало ФИО+Др.");
                                  cntFoundFIODR[iQuery]=cntFoundFIODR[iQuery]+1;

                                  //v0.6 список на повторную идентификацию
                                  //только тех, у кого стоит признак "Клиент" и он не закрыт
                                  if (IsClientOwnerKind(fPersn.rec.ClientID,PTK_CLIENT) and ClientIsOpen(fPersn.rec.ClientID))
                                      aReIdentReport[aReIdentReport.Size]=GenObject("TReIdentReport",fPersn.rec.ClientID);
                                      aReIdentReport[aReIdentReport.Size-1].fioRS      =fioRS;
                                      aReIdentReport[aReIdentReport.Size-1].fioCIK     =fioCIK;
                                      aReIdentReport[aReIdentReport.Size-1].fioDistance=0;
                                      aReIdentReport[aReIdentReport.Size-1].docTypeCIK =ДокВид;
                                      aReIdentReport[aReIdentReport.Size-1].docNumCIK  =Trim(ДокСер+" "+ДокНом);
                                      aReIdentReport[aReIdentReport.Size-1].GetRSDoc();
                                      aReIdentReport[aReIdentReport.Size-1].adrCIK     =Адрес;
                                      aReIdentReport[aReIdentReport.Size-1].bdCIK      =ДатаРожд;
                                  end;
                                  
                              end;
                              okPersn=fPersn.next;
                          end;

                          //---
                      end;

                      //if (flagFindAcc)
                      if (aNodeAccount.Size>0)
                          var domNodeAcc;
                          var domNodeAccTop;
                          var domNodeInfo=GetXPathItems("СлужИнфо",domPersons.item(iPerson)).item(0);

                          for (domNodeAcc, aNodeAccount)
                              domNodeAccTop=domPersons.item(iPerson).insertBefore(DOMDoc.CreateElement("Счета"),domNodeInfo);
                              domNodeAccTop.setAttribute("ИдСчета",{Reg_Num}+SubStr(domNodeAcc.GetAttribute("НомерСчета"),1,8)+SubStr(domNodeAcc.GetAttribute("НомерСчета"),10,11));
                              domNodeAccTop.insertBefore(domNodeAcc,domNodeAccTop.childNodes(1));


                              var domNodeBank=domNodeAccTop.appendChild(DOMDoc.CreateElement("КредитОрг"));
                              domNodeBank.setAttribute("НаимКредит",   НаимКредит);
                              domNodeBank.setAttribute("КодСубКред",   КодСубКред);
                              domNodeBank.setAttribute("КонфАдрКред",  КонфАдрКред);
                              if (НеконфАдрКред!="")
                                  domNodeBank.setAttribute("НеконфАдрКред",НеконфАдрКред);
                              end;
                          end;
                          cntPerson[iQuery]=cntPerson[iQuery]+1;
                      else
                          domPersons.item(iPerson).ParentNode.RemoveChild(domPersons.item(iPerson));
                      end;
                  end;
              end;
              domPersons=null;

          if ((ValType(cntPerson[iQuery])!=V_UNDEF) and (cntPerson[iQuery]>0))
              
              //YZZZZZZZZZZZZZ_DDMMGG_hhmmss_T_NNNN.xml
              //Y: K - для кредитных организаций, D - для депозитариев, R - для регистраторов, S - для спецдепозитариев
              sOutFileName="K"+GetClientRegNumber({OurBankId})+"_"+flFormDate("%y%m%d_%H%M%S")+"_"+sQueryType+"_"+String((iQueryNumber+1):o:4); 
              domDoc.documentElement.SetAttribute("ИдФайл",sOutFileName);
              sOutFileName=sOutFileName+".xml";
              domDoc.documentElement.SetAttribute("ВерсПрог",ВерсПрог);
              

              //12.07.2016
              if (flagValidateAnswer)

                //подменяем путь к XSD
                if (flagUseXsdPathHack)
                    domDoc.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation",CnvPath(folderXSD+"\\"+"VO_CIK_CB_7.xsd"));
                end;

                  if (not flagValidateQuery)
                      domDoc.Schemas=objQuerySchemaCache;
                  end;
                  objXsdErr=domDoc.Validate();
                  if (objXsdErr.errorCode==0)
                      PrintLn("Проверка ответа "+sOutFileName+" на соответствие XSD схеме прошла успешно");
                      answerXsdResult[iQuery]="OK";
                  else
                      PrintLn("ERROR: Ошибка при проверке ответа "+sOutFileName+" на соответствие XSD схеме. \n   Код: "+" "+String(objXsdErr.errorCode)+". ("+objXsdErr.reason+") "+
                          "\n   Строка: "+objXsdErr.Line+", "+objXsdErr.linepos + 
                          " в файле: "+objXsdErr.filepos+
                          "\n   Исходный текст: "+objXsdErr.srcText);
                      answerXsdResult[iQuery]="ERR";
                      //continue;
                  end;

                //восстанавливаем путь к XSD
                if (flagUseXsdPathHack)
                    domDoc.documentElement.SetAttribute("xsi:noNamespaceSchemaLocation","VO_CIK_CB_7.xsd");
                end;

              end;


              DOMDoc.Save(folderOUT+"\\"+sOutFileName);
              answerName[iQuery]=sOutFileName;
              PrintLn("В ответ на файл "+dirIN.Name(iQuery)+" сформирован файл "+sOutFileName+" количество персон "+cntPerson[iQuery]);
          else
              PrintLn("Ответ на файл "+dirIN.Name(iQuery)+" НЕ сформирован.  Персоны не найдены ");
              if (flagKvtNotFound)
                  Kvt(null, 1000, null);
              end;
          end;
          DOMDoc=null;
          PrintLN();
            Log_WriteCheckpoint (1003,"Обработка запроса ЦИК ЦБР "+queryName[iQuery]);
          
      elif(iMatch==0)
          PrintLN("BADFN: "+dirIN.Name(iQuery));
          queryXsdResult[iQuery]="EFN";
      elif(iMatch<0)
          PrintLN("ERROR: "+strErr);
          queryXsdResult[iQuery]="E";

          //PrintLN("   RE: "+strRE );
      end;
end;

var t_finish=Time();

MakeReport();
MakeReportReIdent();

PrintLn("Время выполнения: "+String(t_finish-t_start)); //допущение, что не переваливает через полночь

/*

    Словарь:         ..\DBFILE\bank.def
    Структура файла: paprkind.dbt (Виды документов                 )
------------------------------------------------------------------------
        Имя поля       |  Тип  |Длина|Смещ.|       Примечание
-----------------------|-------|-----|-----|----------------------------
PaperKind               INT         2     0 Номер вида документа, удост.личность
Name                    STRING     90     2 Название вида
Definition              STRING    165    92 Описание вида
CodeDocum               STRING      5   257 Код документа
FM_CodeDocum            STRING      5   262 Соответствующий код в ФМ
CodeASV                 STRING      5   267 Код документа (1417-У)
Reserved                STRING     60   272 Резерв
------------------------------------------------------------------------
                                        332

    Ключи файла
------------------------------------------------------------------------
Номер|       Имя поля        |  Флаги   |  Тип  |Длина|Смещ.|Примечание
-----|-----------------------|----------|-------|-----|-----|-----------
 0    PaperKind                M      E  INTEGER     2     0
 1    CodeDocum                M N    E  ZSTRING     5     0
 
 
4    RDKind                  DM  S   E  INTEGER     4     0
4    Series                  DM  S   E  ZSTRING    16     0
4    DocNum                  DM  S   E  ZSTRING    36     0
4    Client                  DM      E  INTEGER     4     0
 
 */

/*
/*
%a Abbreviated weekday name
%A Full weekday name
%b Abbreviated month name
%B Full month name
%c Date and time representation appropriate for locale
%d Day of month as decimal number (01 Ц 31)
%H Hour in 24-hour format (00 Ц 23)
%I Hour in 12-hour format (01 Ц 12)
%j Day of year as decimal number (001 Ц 366)
%m Month as decimal number (01 Ц 12)
%M Minute as decimal number (00 Ц 59)
%p Current localeТs A.M./P.M. indicator for 12-hour clock
%S Second as decimal number (00 Ц 59)
%U Week of year as decimal number, with Sunday as first day of week (00 Ц 53)
%w Weekday as decimal number (0 Ц 6; Sunday is 0)
%W Week of year as decimal number, with Monday as first day of week (00 Ц 53)
%x Date representation for current locale
%X Time representation for current locale
%y Year without century, as decimal number (00 Ц 99)
%Y Year with century, as decimal number
%z, %Z Time-zone name or abbreviation; no characters if time zone is unknown
%% Percent sign
As in the printf function, the # flag may prefix any formatting code. In that case, the meaning of the format code is changed as follows.
Format Code Meaning 
%#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z, %#% # flag is ignored. 
%#c Long date and time representation, appropriate for current locale. For example: УTuesday, March 14, 1995, 12:41:29Ф. 
%#x Long date representation, appropriate to current locale. For example: УTuesday, March 14, 1995Ф. 
%#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y Remove leading zeros (if any 

*/


*/