diadoc / diadocsdk-csharp

Official Diadoc SDK for C#
MIT License
35 stars 64 forks source link

Подписание формализованного Акта #776

Closed alkrot closed 3 years ago

alkrot commented 3 years ago

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

а методы генерации и парсинга XML требует Content в byte, было написано что можно получить с помощью ссылки XSDUrl необходимое XML вроде как понял, но так саму XSD получить из этой ссылки?

также сообщает что UserDataXsdUrl не поддерживается

Используется эта библиотека, но язык программирования ISBL

NataliaShumikhina commented 3 years ago

Для подписания формализованного акта нужно сформировать xml-файл 2го титула и запостить его с помощью метода PostMessagePatch и структуры RecipientTitles По поводу схемы. Нужно вызвать метод GetDocumentTypes, в ответе найти нужный тип-функцию-версию, взять ссылку из поля XsdUrl. Эта ссылка - это по сути Get-запрос, при выполнении которого в ответе приходит xsd-схема. Работа с любыми формализованными актами аналогична работе с документами 820 формата, о которой можно почитать в статье https://api-docs.diadoc.ru/ru/latest/howto/utd820.html

alkrot commented 3 years ago

Для подписания формализованного акта нужно сформировать xml-файл 2го титула и запостить его с помощью метода PostMessagePatch и структуры RecipientTitles По поводу схемы. Нужно вызвать метод GetDocumentTypes, в ответе найти нужный тип-функцию-версию, взять ссылку из поля XsdUrl. Эта ссылка - это по сути Get-запрос, при выполнении которого в ответе приходит xsd-схема. Работа с любыми формализованными актами аналогична работе с документами 820 формата, о которой можно почитать в статье https://api-docs.diadoc.ru/ru/latest/howto/utd820.html

XSD схему то я скачиваю, но получается по ней заполнять XML?

В SDK есть пример о том как сформировать виде классов, но через COM это недоступно просто

И как понять какая мне действительно нужна версия?

OlgaPetushina commented 3 years ago

Да, вам нужно составить xml по скаченной userdata xsd. Версия 2 титула должна совпадать с версией 1 титула (эти данные у вас должны быть).

alkrot commented 3 years ago

@OlgaPetushina @NataliaShumikhina

Да, вам нужно составить xml по скаченной userdata xsd. Версия 2 титула должна совпадать с версией 1 титула (эти данные у вас должны быть).

По XSDUrl файлу генерируется просто шаблон получается и сам шаблон уже заполняется?

А версия 1 титула тоже где то хранится виде xml?

Есть один момент в документации UserData image

У меня например говорит что нет данного метода, это получается что никакого титула нет?

И не в один Titles не возвращает Index? точнее говорит что данное свойство не поддерживается

GenerateTitleXml передается последним параметром через SDK все таки XML мною заполненная?

alkrot commented 3 years ago
  function Sign() {
    //ID akta
    var DocumentEntityId = "%s";
    //ID soobshenia
    var messageId = "%s";
    //ID nashego yashika
    var boxId = "%s";
    //klyuch razrabotchika
    var DeveloperKey = "%s";
    //adres interfeisa
    var ApiAdress = "%s";
    // nyjno li podpisuvatb izvechenie
    var SignInvoice = "%s";
    //familia podpisanta
    var Surname = "%s";
    //imya pozpisanta
    var FirstName = "%s";
    //otchestvo podpisanta
    var Patronymic = "%s";
    //doljnost podpisanta
    var JobTitle = "%s";
    //data podpisi
    var SignatureDate = "%s";
    //vremennyi fail sertifikata
    var CertFilePath = "%s";
    //vremennyi fail podpisyvaemogo documenta
    var SignedDocFilePath = "%s";
    //vremennyi fail podpisyvaemogo izvecheniya
    var SignedInvoiceFilePath = "%s";
    //vremennyi fail podpisi
    var SignatureFilePath = "%s";
    //otpechatok sertificata
    var SignatureInvoiceFilePath = "%s"; 
    //otpechatok sertificata
    var Thumbprint = "%s";
    // cam fail
    var FileContentPuth = "%s";               
    // naim. ek. cyb.
    var nameEconEntity = "%s";
    // coderjanie operasii
    var ContentOfOperationPuth = "%s";
    // data prin9tiua tovara
    var AcceptanceDate = "%s";

    var INN = "%s"

    var SignerOrgPowersBase = "%s"

    // status trebyetc9 otvetnoe deuctvie
    var InboundWaitingForRecipientSignature_STATUS = 2;
    // priznak ispolzovaniya dl9 lokalhogo hranilicha certifikata
    var UserLocalSystemStorage =  false;
    // IOP podpisano
    var Finished = 4;
    //zahodim v diadoc
    var diadoc = new ActiveXObject("Diadoc.Api.ComDiadocApi2");
    diadoc.Initialize(DeveloperKey, ApiAdress);

    //crypt api
    var crypt = new ActiveXObject("Diadoc.Api.ComCryptApi");
    var token = diadoc.AuthenticateWithCertificate(Thumbprint, UserLocalSystemStorage);

    // proverim status documenta
    var document = diadoc.GetDocument(token, boxId, messageId, DocumentEntityId) 
    metadata = document.RecipientResponseStatusValue 
    if (metadata != null && metadata == InboundWaitingForRecipientSignature_STATUS) {   // trebyetc9 otvetnoe deisctvie              
      //получаем и сохраняем документ
      var Content  = diadoc.GetEntityContent(token,boxId,messageId,DocumentEntityId); //получаем документ                                         

      var FileStream = new ActiveXObject("ADODB.Stream");

      //certificate
      FileStream.Type = 1; // binary
      FileStream.Mode = 3; // read/write
      FileStream.Open();
      FileStream.LoadFromFile(CertFilePath);
      var SignerCertificate = FileStream.Read();
      FileStream.Close();

      /*****************IZVECHENIE*****************/          
      if(SignInvoice && document.ReceiptStatusValue != Finished){  
        //podpisant
        var Signer = new ActiveXObject("Diadoc.Api.Signer");
        Signer.SignerCertificate = SignerCertificate; 

        //poluchim podtverzhdenie operatora
        var invoiceConfirmation = diadoc.GetMessage(token, boxId, messageId);
        //formiruem izveshenie o poluchenii operatora
        var invoiceReceipt = diadoc.GenerateInvoiceDocumentReceiptXml(token, boxId, messageId, DocumentEntityId, Signer);
        invoiceReceipt.SaveContentToFile(SignedInvoiceFilePath);

        crypt.Sign(SignedInvoiceFilePath, Thumbprint, SignatureInvoiceFilePath, UserLocalSystemStorage);
        //cignature
        var stream = new ActiveXObject("ADODB.Stream");
        stream.Type = 1; // binary
        stream.Mode = 3; // read/write
        stream.Open();
        stream.LoadFromFile(SignatureInvoiceFilePath);
        var Signature = stream.Read();
        stream.Close();

        //dannie, podpisannie ECP
        var SignedInvoiceContent = new ActiveXObject("Diadoc.Api.SignedContent");
        SignedInvoiceContent.LoadContentFromFile(SignedInvoiceFilePath);
        SignedInvoiceContent.Signature = Signature;
        SignedInvoiceContent.SignWithTestSignature = 0;//true
        SignedInvoiceContent.SignByAttorney = 0; //false
        //izveshenie o poluchenii SF
        var ReceiptAttachment = new ActiveXObject("Diadoc.Api.ReceiptAttachment");
        ReceiptAttachment.ParentEntityId = DocumentEntityId;
        ReceiptAttachment.SignedContent = SignedInvoiceContent;
        //dopolnenie k soobsheniu
        var MessagePatchToPost = new ActiveXObject("Diadoc.Api.MessagePatchToPost");
        MessagePatchToPost.boxId = boxId;
        MessagePatchToPost.messageId = messageId;
        MessagePatchToPost.AddReceipt(ReceiptAttachment);
        //otpravlyaem podtverzhdenie poluchenia SF
        diadoc.PostMessagePatch(token, MessagePatchToPost);   
      }      
      /*******************************/

      //dostaem coderjanie operasii                      
      FileStream.Type = 2
      FileStream.Charset = "Windows-1251"
      FileStream.Open
      FileStream.LoadFromFile(ContentOfOperationPuth) 
      var contentOfOperation = FileStream.ReadText                                   
      FileStream.close                     

      // dop. informasia pro cotrydnika kotoryu podpicuvaet document

     // var SignerType = new ActiveXObject("Diadoc.Api.Com.SignerType"); 

      //ExtendedSignerDetails
      var ExtendedSignerDetails = new ActiveXObject("Diadoc.Api.ExtendedSignerDetails");
      ExtendedSignerDetails.Surname = Surname;
      ExtendedSignerDetails.FirstName = FirstName;
      ExtendedSignerDetails.Patronymic = Patronymic;
      ExtendedSignerDetails.INN = INN;
      ExtendedSignerDetails.JobTitle = JobTitle;
      ExtendedSignerDetails.SignerTypeValue = 1 //SignerType.LegalEntity;       // выбрать правильный
      ExtendedSignerDetails.SignerStatusValue = 5;     // выбрать правильный
      ExtendedSignerDetails.SignerPowersValue = 3;     // выбрать правильный
      ExtendedSignerDetails.SignerPowersBase = SignerOrgPowersBase;  // основание
      Alert("ExtendedSignerDetails");

      //ExtendedSigner
      var ExtendedSigner = new ActiveXObject("Diadoc.Api.ExtendedSigner")
      ExtendedSigner.SignerCertificate = SignerCertificate;
      ExtendedSigner.SignerCertificateThumbprint = Thumbprint; 
      ExtendedSigner.BoxId = boxId;
      // dop. dannue podpisanta
      ExtendedSigner.SignerDetails = ExtendedSignerDetails;                   

      Alert("ExtendedSigner");

      //yniversalnuy vid titula zakazchika
      var UniversalTransferDocumentBuyerTitleInfo = new ActiveXObject("Diadoc.Api.UniversalTransferDocumentBuyerTitleInfo");
      UniversalTransferDocumentBuyerTitleInfo.DocumentCreator = nameEconEntity;       // Наименование экономического субъекта
      UniversalTransferDocumentBuyerTitleInfo.OperationContent = contentOfOperation;  // Содержание операции
      UniversalTransferDocumentBuyerTitleInfo.AcceptanceDate = AcceptanceDate;        //ДатаПрин - Дата принятия товаров (результатов выполненных работ)
      UniversalTransferDocumentBuyerTitleInfo.AddSigner(ExtendedSigner);

      Alert("UniversalTransferDocumentBuyerTitleInfo");

      //titul zakazchika
      var AcceptanceCertificateXmlForBuyer = diadoc.GenerateUniversalTransferDocumentXmlForBuyer(token, UniversalTransferDocumentBuyerTitleInfo, boxId, messageId, DocumentEntityId);
      AcceptanceCertificateXmlForBuyer.SaveContentToFile(SignedDocFilePath);

      Alert("AcceptanceCertificateXmlForBuyer");                  

      crypt.Sign(SignedDocFilePath, Thumbprint, SignatureFilePath, UserLocalSystemStorage);

      //cignature
      var stream = new ActiveXObject("ADODB.Stream");
      stream.Type = 1; // binary
      stream.Mode = 3; // read/write
      stream.Open();
      stream.LoadFromFile(SignatureFilePath);
      var Signature = stream.Read();
      stream.Close();

      //zagruzim fail po 4act9m
      var NameOnShelf = diadoc.UploadFileToShelf(token, SignedDocFilePath)

      //dannie, podpisannie ECP
      var SignedContent = new ActiveXObject("Diadoc.Api.SignedContent");
      SignedContent.NameOnShelf = NameOnShelf;
      SignedContent.Signature = Signature;
      SignedContent.SignWithTestSignature = 0;// false
      SignedContent.SignByAttorney = 0;// false
      //izveshenie o poluchenii documenta
      var ReceiptAttachment = new ActiveXObject("Diadoc.Api.ReceiptAttachment");
      ReceiptAttachment.ParentEntityId = DocumentEntityId;
      ReceiptAttachment.SignedContent = SignedContent;
      //dopolnenie k soobshenii
      var MessagePatchToPost = new ActiveXObject("Diadoc.Api.MessagePatchToPost");
      MessagePatchToPost.BoxId = boxId;
      MessagePatchToPost.MessageId = messageId;
      MessagePatchToPost.AddXmlAcceptanceCertificateBuyerTitle(ReceiptAttachment);

      Alert("MessagePatchToPost");

      //otpravka podpisania
      diadoc.PostMessagePatch(token, MessagePatchToPost);
      Alert("Send");
    }
  }                

Вот вроде на JScript работает под windows но при попытки

var AcceptanceCertificateXmlForBuyer = diadoc.GenerateUniversalTransferDocumentXmlForBuyer(token, UniversalTransferDocumentBuyerTitleInfo, boxId, messageId, DocumentEntityId);

Выходит ошибка

Ошибка выполнения JS-скрипта при подписании УПД. BaseUrl=https://diadoc-api.kontur.ru, PathAndQuery=/GenerateUniversalTransferDocumentXmlForBuyer?boxId=a41d989fd47d46d981a592b683892137%40diadoc.ru&sellerTitleMessageId=7a306818-7643-4051-b4d5-d259c6050792&sellerTitleAttachmentId=211eb8b5-84bb-4b75-9152-639cf83cdfa8, AdditionalMessage=Invalid data UserContractData: Line: 4, Position: 120, /UniversalTransferDocumentBuyerTitle[1]/Signers[1]/SignerDetails[1]/@SignerStatus: The 'SignerStatus' attribute is invalid - The value 'BuyerEmployee' is invalid according to its datatype 'Integer' - The string 'BuyerEmployee' is not a valid Integer value., StatusCode=BadRequest, DiadocErrorCode: Http.BadRequest.

aeremina88 commented 3 years ago

Добрый день! Метод GenerateUniversalTransferDocumentXmlForBuyer не подходит для документа 820 формата, нужно использовать GenerateTitleXml. Выше вы писали, что он недоступен. Какую версию COM используете?

alkrot commented 3 years ago

@aeremina88

Добрый день! Метод GenerateUniversalTransferDocumentXmlForBuyer не подходит для документа 820 формата, нужно использовать GenerateTitleXml. Выше вы писали, что он недоступен. Какую версию COM используете?

Сам метод доступен, что на той библиотеке который писались интеграции, но не для формализованных актов, что с мастера библиотеки

В доке непонятно как все таки получить мне необходимую Xml которую нужно заполнить или какой класс и какие поля достаточно заполнить?

GenerateTitleXml в исходниках есть параметр который не уточнен в документации userContractData - что в него должно передаваться и как формировать например на стороне JS, если UniversalTransferDocumentWithHyphens если не доступен из под COM

В SDK есть пример генерации BuildUserDataContract типа UniversalTransferDocumentWithHyphens

Нужно ли применять такой подход для формирования второго титула?

Capucinimo commented 3 years ago

Привет, да, можно применять такой же подход. userContractData - это упрощенный XML-файл(байты), соответствующий XSD-схеме контракта для генерации титула. XSD-схема контракта, необходимого для генерации титула, может быть получена с помощью ссылки, доступной в поле UserDataXsdUrl контракта DocumentTitle, который можно получить с помощью метода-справочника GetDocumentTypes. https://api-docs.diadoc.ru/ru/latest/http/GenerateTitleXml.html В COM UniversalTransferDocumentWithHyphens не доступен. В зависимости от использованного вами языка способы кодогенерации по xsd и дальнейшей сериализации объекта в xml отличаются.

alkrot commented 3 years ago

@Dmitriy-Ipatyev UserDataXsdUrl - это не возвращается для акта XsdUrl - есть, но как я понял будет сгенерирована полная xml по этой ссылки?

Подход можно, но UniversalTransferDocumentWithHyphens, тогда как его возможно применять?

alkrot commented 3 years ago

XmlAcceptanceCertificate - для этого типа нет упрощенный схемы XML?

Как все таки получить XML первого титула от отправившего контрагента, и дополнить вторым?

Capucinimo commented 3 years ago

Есть. Ссылка присутствует в ответе GetDocumentTypes. Например, для версии utd820_05_01_01_hyphen "XsdUrl": "/GetContent?typeNamedId=XmlAcceptanceCertificate&function=default&version=utd820_05_01_01_hyphen&titleIndex=1&contentType=TitleXsd", "UserDataXsdUrl": "/GetContent?typeNamedId=XmlAcceptanceCertificate&function=default&version=utd820_05_01_01_hyphen&titleIndex=1&contentType=UserContractXsd" У нас сейчас нет объектов для COM, которые можно просто заполнить. Методы COM принимают и возвращают xml файлы, соответствующие xsd-схемам. Остальное не отличается.