Páginas filhas
  • Preparando uma rotina de integração no Protheus

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.


           Preparar uma rotina de integração no Protheus é bem simples. Existem três formas de realizar este tratamento. Vamos explicar então como desenvolver este adapter e como criar um XSD a partir de um modelo de dados MVC Protheus.

Âncora
_Ref402946865
_Ref402946865
Âncora
_Toc403759544
_Toc403759544
Gerando um Schema XML a partir de um adapter no Protheus

          Um XML Schema Definition, ou XSD, é um arquivo que descreve a estrutura de um documento XML. Para enviar um XML para o outro sistema é necessário conhecer a estrutura do XML esperado por ele.


           Para mensagens da estrutura do TOTVSIntegrator com adapters criados na arquitetura de MVC Protheus é possível, pelo Cadastro de Adapters no Protheus gerar este arquivo e descobrir qual a estrutura esperada por esta rotina. Para isto, no Cadastro de Adapters (CFGA020), em Ações Relacionadas/Schema XML é possível gerar este arquivo:



Figura 13 - Geração de XSD pela rotina de Cadastro de Adapter. É necessário escolher o local de criação do arquivo e também se é necessário criar o cabeçalho dos mesmos (schema TOTVSIntegrator).


           Será criado no diretório especificado todos os arquivos XSD dos adapters cadastrados, e também o Schema do TOTVSIntegrator (desde que a opção 'Todos com cabeçalho?' esteja selecionada), este com o nome MpSchemas.xsd.
As integrações da arquitetura Mensagem Única TOTVS possuem XSDs específicos para cada mensagem trafegada, e não é possível realizar a geração dos mesmos por esta interface. Estes arquivos são criados e disponibilizados pelas áreas responsáveis por cada adapter.


           Dúvidas sobre o que é um XSD? Consulte a página do W3C na internet, clicando aqui.

Âncora
_Ref402949171
_Ref402949171
Âncora
_Toc403759545
_Toc403759545
Integrações do tipo TOTVSIntegrator em rotinas MVC Protheus com cadastro de Adapter


           Vamos agora explicar o funcionamento das integrações do envelope TOTVSIntegrator e como ela se comporta no EAI Protheus. Para este tipo de integração é necessário que o adapter esteja escrito em MVC Protheus. Detalhes do funcionamento do MVC Protheus podem ser encontrados clicando aqui.
Para que o EAI identifique que a mensagem recebida é uma mensagem de processamento do EAI Protheus o valor enviado na tag GlobalFunctionCode no path /TOTVSIntegrator/ deverá ser EAI.
Um fonte construído em MVC Protheus já possui a capacidade de enviar e receber dados automaticamente através do envelope TOTVSIntegrator, desde que a definição de XSD do mesmo seja respeitada. Para detalhes de como gerar um XSD a partir de um adapter no Protheus verifique o tópico Gerando um Schema XML a partir de um adapter no Protheus.
O exemplo abaixo demonstra um cadastro simples realizado em MVC Protheus. Os exemplos completos destes fontes estão disponíveis na Comunidade do Desenhador MVC, no Fluig e os arquivos disponíveis neste artigo. Este exemplo foi modificado para e a User Function foi trocada para uma function. Clique aqui para visualizar a comunidade no Fluig.


#INCLUDE 'PROTHEUS.CH'
#INCLUDE 'FWMVCDEF.CH'
Function COMP011_MVC()
Local oBrowse
oBrowse := FWMBrowse():New()
oBrowse:SetAlias('ZA0')
oBrowse:SetDescription('Cadastro de Autor/Interprete')
oBrowse:AddLegend( "ZA0_TIPO=='1'", "YELLOW", "Autor" )
oBrowse:AddLegend( "ZA0_TIPO=='2'", "BLUE" , "Interprete" )
oBrowse:Activate()
Return NIL
//-------------------------------------------------------------------
Static Function MenuDef()
Local aRotina := {}
ADD OPTION aRotina TITLE 'Visualizar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 2 ACCESS 0
ADD OPTION aRotina TITLE 'Incluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 3 ACCESS 0
ADD OPTION aRotina TITLE 'Alterar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 4 ACCESS 0
ADD OPTION aRotina TITLE 'Excluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 5 ACCESS 0
Return aRotina
//-------------------------------------------------------------------
Static Function ModelDef()
Local oStruZA0 := FWFormStruct( 1, 'ZA0', /bAvalCampo/,/lViewUsado/ )
Local oModel
oModel := MPFormModel():New('COMP011_MVC', /bPreValidacao/, /bPosValidacao/, /bCommit/, /bCancel/ )
oModel:AddFields( 'ZA0MASTER', /cOwner/, oStruZA0, /bPreValidacao/, /bPosValidacao/, /bCarga/ )
oModel:SetDescription( 'Modelo de Dados de Autor/Interprete' )
oModel:GetModel( 'ZA0MASTER' ):SetDescription( 'Dados de Autor/Interprete' )
Return oModel
//-------------------------------------------------------------------
Static Function ViewDef()
Local oModel := FWLoadModel( 'COMP011_MVC' )
Local oStruZA0 := FWFormStruct( 2, 'ZA0' )
Local oView
Local cCampos := {}
oView := FWFormView():New()
oView:SetModel( oModel )
oView:AddField( 'VIEW_ZA0', oStruZA0, 'ZA0MASTER' )
oView:CreateHorizontalBox( 'TELA' , 100 )
oView:SetOwnerView( 'VIEW_ZA0', 'TELA' )
Return oView


           Para que o exemplo acima funcione, é necessário executar o fonte UPDMVC, disponível na comunidade do FLUIG, para que a estrutura da tabela ZA0 seja criada.
           No exemplo acima, o fonte já está totalmente preparado para o envio das mensagens pelo EAI Protheus. Vamos cadastrar o adapter desta rotina no configurador:



Figura 14 - Cadastro do adapter Comp011_MVC


           Feito isto, vamos entrar nesta rotina e incluir um registro.



Figura 15 - Inclusão do cadastro do fonte Teste


           Perceba que não foi parametrizado os endereços de envio do EAI Protheus, desta maneira a integração não será bem sucedida. Importante: Rotinas na arquitetura MVC Protheus fazem a consistência da integração quando configurada. Isto quer dizer que, caso a integração não seja bem sucedida os dados não serão gravados no Protheus.
Como este fonte está escrito em MVC Protheus a mensagem surge em tela, indicando o problema:



Figura 16 - Mensagem de erro em adapter construído em MVC Protheus, indicando que a integração não foi bem sucedida


           Vamos verificar a fila do EAI Protheus e verificar o XML gerado e o status da mensagem:


Figura 17 - Visualização do erro de integração na fila de mensagens do EAI Protheus


           No nosso caso, não foi possível enviar a mensagem para o endereço especificado. Como configuramos nossa mensagem como síncrona não será realizada outra tentativa de envio da mesma. Vamos observar o XML gerado:


<?xml version="1.0" encoding="UTF-8"?>
<TOTVSIntegrator>
<GlobalProduct>PROTHEUS</GlobalProduct>
<GlobalFunctionCode>EAI</GlobalFunctionCode>
<GlobalDocumentFunctionCode>COMP011_MVC</GlobalDocumentFunctionCode>
<GlobalDocumentFunctionDescription>Modelo de Dados de Autor/Interprete</GlobalDocumentFunctionDescription>
<DocVersion>1.000</DocVersion>
<DocDateTime>2014-11-10T14:29:02Z</DocDateTime>
<DocIdentifier>9d4cb8f9-0556-261c-2daf-c9fc4cde8a4c</DocIdentifier>
<DocCompany>18</DocCompany>
<DocBranch>D MG 01</DocBranch>
<DocName/>
<DocFederalID/>
<DocType>1</DocType>
<Message>
<Layouts>
<Identifier>COMP011_MVC</Identifier>
<Version>1.0</Version>
<FunctionCode>FWFORMEAI.COMP011_MVC </FunctionCode>
<Content>
<COMP011_MVC Operation="3" version="1.01">
<ZA0MASTER modeltype="FIELDS" >
<ZA0_CODIGO order="2">
<value>000003</value>
</ZA0_CODIGO>
<ZA0_NOME order="3">
<value>TESTE003</value>
</ZA0_NOME>
<ZA0_TIPO order="6">
<value>1</value>
</ZA0_TIPO>
</ZA0MASTER>
</COMP011_MVC>
</Content>
</Layouts>
</Message>
</TOTVSIntegrator>


           O XML gerado já contém os dados necessários para a gravação das informações. Podemos enviar este mesmo XML, através de qualquer ferramenta de envio de XMLs para o serviço do EAI Protheus, e os dados serão gravados na tabela indicada. Vamos enviar este XML para o Protheus, através de uma ferramenta de envio de dados à Webservices. Entraremos agora na rotina e veremos que o cadastro agora foi incluído:



Figura 18 - Cadastro incluído via integração no Protheus


           Note que todo o processamento realizado no Protheus foi realizado pelo adapter COMP011_MVC. Uma dica para testes é tentar integrar duas bases Protheus diferentes.

Âncora
_Toc403759546
_Toc403759546
Integrações da estrutura TOTVSIntegrator em fontes não estão cadastrados no Cadastro de Adapters


           Existe a possibilidade de realizar a integração de dados do Protheus com outros sistemas, utilizando a estrutura do TOTVSIntegrator. Nestes casos a rotina não deverá estar no Cadastro de Adapters do Protheus. A rotina de processamento somente poderá ser uma rotina que esteja no menu do Protheus ou uma função de usuário (user function). Qualquer tentativa de execução de uma função que não obedeça estes critérios resultará em um retorno de SoapFault para o sistema que enviou a mensagem.

Âncora
_Ref403394257
_Ref403394257
Âncora
_Toc403759547
_Toc403759547
Recebendo uma mensagem pela estrutura TOTVSIntegrator em adapters que não estão no cadastro

          Para que o EAI identifique que a mensagem recebida é uma mensagem de processamento do EAI Protheus o valor enviado na tag GlobalFunctionCode no path /TOTVSIntegrator/ deverá ser EAI.


           Vamos gerar o seguinte xml para envio ao Protheus. Lembrando que o XML enviado deve respeitar o XSD do TOTVSIntegrator. Para gerar o XSD do TOTVSIntegrator, consulte o tópico Gerando um Schema XML a partir de um adapter no Protheus.








<?xml version="1.0" encoding="UTF-8"?>
<TOTVSIntegrator>
<GlobalProduct>PRODUTO XPTO</GlobalProduct>
<GlobalFunctionCode>EAI</GlobalFunctionCode>
<GlobalDocumentFunctionCode>ROTINA DE INTEGRACAO X</GlobalDocumentFunctionCode>
<GlobalDocumentFunctionDescription>ROTINA DE INTEGRAÇÃO</GlobalDocumentFunctionDescription>
<DocVersion>1.000</DocVersion>
<DocDateTime>2014-11-05T15:38:56Z</DocDateTime>
<DocIdentifier>196f6cae-b288-5e36-0046-f5a518121110</DocIdentifier>
<DocCompany>18</DocCompany>
<DocBranch>D MG 01</DocBranch>
<DocName/>
<DocFederalID/>
<DocType>1</DocType>
<Message>
<Layouts>
<Identifier>TESTEEAI</Identifier>
<Version>1.0</Version>
<FunctionCode>U_TSTEAI.01.02.03</FunctionCode>
<Content>
<MyXml>
<MyOperation>UPSERT</MyOperation>
<MyCode>000002</MyCode>
<MyName>TesteSemAdapter</MyName>
<MyType>1</MyType>
</MyXml>
</Content>
</Layouts>
</Message>
</TOTVSIntegrator>

          No XML acima vamos incluir no Protheus um registro na mesma tabela do exemplo Integrações do tipo TOTVSIntegrator em fontes em MVC Protheus com cadastro de Adapter no Protheus. Porém, neste caso a nossa rotina de processamento (adapter) não é um fonte em MVC e nem se encontra disponível no Cadastro de Adapters. Desta maneira, todo o processamento da mensagem deverá ser realizado manualmente. Isto significa que a rotina deverá ser capaz de ler o XML recebido, executar as validações de regra de negócio necessárias e realizar o processamento a mensagem recebida.
No exemplo abaixo, a User Function TSTEAI irá receber o XML recebido pelo EAI Protheus, e irá realizar a chamada do Modelo de dados da rotina COMP011_MVC e irá realizar a gravação do dado recebido (realizar a chamada do Modelo de dados de uma rotina é o equivalente, no MVC Protheus, de se realizar a chamada de uma MsExecAuto. Como a rotina COMP011_MVC está na arquitetura MVC Protheus ela já possui, nativamente, uma maneira de se gravar os seus dados sem a necessidade de interface, de maneira semelhante as MsExecAuto. Para detalhes de como isto funciona, consulte no TDN a documentação do MVC Protheus clicando aqui).


           Abaixo o exemplo da rotina para processamento do XML recebido

#Include 'Protheus.ch'
#include 'FWMVCDEF.CH'
#include 'FWADAPTEREAI.CH'
User Function TSTEAI(cXML,cError,cWarning,cParams,oFWEAI)
Local oTxmlManager :=NIL
Local oModel :=NIL
Local aErro :=NIL
Local aArea :=NIL
Local aAreaZA0 :=NIL
Local cCode :=NIL
Local cNome :=NIL
Local cType :=NIL
Local cOperation :=NIL
Local cModelOper :=NIL
Local lRet :=.T.
oTXmlManager:=tXmlManager():New()
If oTXmlManager:Parse(cXml)
oModel:=FwLoadModel('COMP011_MVC')
cCode:=oTxmlManager:xPathGetNodeValue('/MyXml/MyCode')
cOperation:=oTxmlManager:xPathGetNodeValue('/MyXml/MyOperation')
cNome:=oTxmlManager:xPathGetNodeValue('/MyXml/MyName')
cType:=oTxmlManager:xPathGetNodeValue('/MyXml/MyType')
If cOperation =='DELETE'
cModelOper:=MODEL_OPERATION_DELETE
ElseIF cOperation =='UPSERT'
aArea:=GetArea()
DbSelectArea('ZA0')
aAreaZA0:=ZA0->(GetArea())
If ZA0->(DbSeek(xFilial('ZA0')+cCode))//Encontrei o valor
cModelOper:=MODEL_OPERATION_UPDATE
Else
cModelOper:=MODEL_OPERATION_INSERT
Endif
RestArea(aAreaZA0)
RestArea(aArea)
Else
lRet:=.F.
cError:='Não foi enviada uma operação válida. '
cErro+='Operações permitidas - UPSERT ou DELETE'
Endif
If lRet
oModel:SetOperation(cModelOper)
If oModel:Activate()
oModel:SetValue('ZA0MASTER','ZA0_CODIGO',cCode)
oModel:SetValue('ZA0MASTER','ZA0_NOME',cNome)
oModel:SetValue('ZA0MASTER','ZA0_TIPO',cType)
If oModel:VldData()
If !oModel:CommitData()
lRet:=.F.
Endif
Else
lRet:=.F.
Endif
Else
lRet:=.F.
Endif
If !lRet
aErro:=oModel:GetErrorMessage()
If !Empty(aErro)
cError:='A integração não foi bem sucedida.'
cError+='Foi retornado o seguinte erro: ' +Alltrim(aErro[5])+'-'+AllTrim(aErro[6])
If !Empty(Alltrim(aErro[7]))
cError+='Solução - '+AllTrim(aErro[7])
Endif
Else
cErro:='A integração não foi bem sucedida. '
cErro+='Verifique os dados enviados'
Endif
aSize(aErro,0)
aErro:=nil
Endif
Endif
oModel:Deactivate()
oModel:Destroy()
oModel:=nil
Else//ouve erro no Parse, existe problemas no XML
cError:=oTXmlManager:Error()
lRet:=.F.
Endif
oTXmlManager:=nil
DelClassIntF()
Return lRet

           Veja que no exemplo acima foi necessário um conhecimento maior da estrutura da tabela a ser integrada. O retorno desta rotina (no caso um lógico) é enviado como resposta para o sistema que enviou a mensagem. Retornos lógicos são devolvidos como T (true) ou F (falso). Todos os outros retornos são enviados como Strings para o sistema que enviou a mensagem. Desta maneira, é possível enviar uma mensagem para o outro sistema, indicando o que ocorreu.


           A rotina que irá processar o XML recebido irá receber os seguintes parâmetros:

  • cXml – O conteúdo da tag Content do XML recebido pelo EAI Protheus;

  • cError – Variável passada por referência, serve para alimentar a mensagem de erro, nos casos em que a transação não foi bem sucedida;

  • cWarning – Variável passada por referência, serve para alimentar uma mensagem de warning para o EAI. A alteração deste valor por rotinas tratadas neste tópico não causam nenhum efeito para o EAI;

  • cParams – Parâmetros passados na mensagem do EAI. Para o envio destes parâmetros é utilizada a seguinte regra:
    • Estes parâmetros são passados após o nome da função, na tag FunctionCode, no path /TOTVSIntegrator/Message/Layouts/

    • Após o nome da função a ser executada deve ser colocado um '.' e após cada um dos parâmetros mais um. Exemplo: <FunctionCode>U_TSTEAI.01.02.03</FunctionCode>.

    • OS parâmetros são enviados na forma de uma string, separados por ','. No exemplo acima, a variável cParams irá receber a string 01,02,03

  • oFwEAI – O objeto de EAI criado na camada do EAI Protheus. A manipulação deste objeto deve ser realizada com o máximo de cautela, e deve ser evitada ao máximo.

Âncora
_Toc403759548
_Toc403759548
Enviando uma mensagem pela estrutura TOTVSIntegrator em adapters que não estão no cadastro


Ao contrário do exemplo anterior, onde a rotina em MVC Protheus já estava preparada para o recebimento e envio da mensagem, neste caso, além de realizar o tratamento de recebimento da mensagem é necessário criar também realizar a chamada da integração em algum ponto do sistema (normalmente, após a validação e gravação dos dados no sistema).
Para o nosso exemplo, a integração será chamada após a gravação dos dados no Protheus. Para detalhes do funcionamento da classe FWEAI consulte o TDN clicando aqui.
#INCLUDE 'PROTHEUS.CH'
#INCLUDE 'FWMVCDEF.CH'
#INCLUDE 'FWADAPTEREAI.CH'
Function COMP011_MVC()
Local oBrowse
oBrowse := FWMBrowse():New()
oBrowse:SetAlias('ZA0')
oBrowse:SetDescription('Cadastro de Autor/Interprete')
oBrowse:AddLegend( "ZA0_TIPO=='1'", "YELLOW", "Autor" )
oBrowse:AddLegend( "ZA0_TIPO=='2'", "BLUE" , "Interprete" )
oBrowse:Activate()
Return NIL
//-------------------------------------------------------------------
Static Function MenuDef()
Local aRotina := {}
ADD OPTION aRotina TITLE 'Visualizar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 2 ACCESS 0
ADD OPTION aRotina TITLE 'Incluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 3 ACCESS 0
ADD OPTION aRotina TITLE 'Alterar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 4 ACCESS 0
ADD OPTION aRotina TITLE 'Excluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 5 ACCESS 0
Return aRotina
//-------------------------------------------------------------------
Static Function ModelDef()
Local oStruZA0 := FWFormStruct( 1, 'ZA0', /bAvalCampo/,/lViewUsado/ )
Local oModel
oModel := MPFormModel():New('COMP011_MVC', /bPreValidacao/, /bPosValidacao/, {|oModel|Comp011Commit(oModel)}/bCommit/, /bCancel/ )
oModel:AddFields( 'ZA0MASTER', /cOwner/, oStruZA0, /bPreValidacao/, /bPosValidacao/, /bCarga/ )
oModel:SetDescription( 'Modelo de Dados de Autor/Interprete' )
oModel:GetModel( 'ZA0MASTER' ):SetDescription( 'Dados de Autor/Interprete' )
Return oModel
//-------------------------------------------------------------------
Static Function ViewDef()
Local oModel := FWLoadModel( 'COMP011_MVC' )
Local oStruZA0 := FWFormStruct( 2, 'ZA0' )
Local oView
Local cCampos := {}
oView := FWFormView():New()
oView:SetModel( oModel )
oView:AddField( 'VIEW_ZA0', oStruZA0, 'ZA0MASTER' )
oView:CreateHorizontalBox( 'TELA' , 100 )
oView:SetOwnerView( 'VIEW_ZA0', 'TELA' )
Return oView
Static Function Comp011Commit(oModel)
Local lRet :=.T.
Local oFwEAI :=NIL
Local cXml :=NIL
BEGIN TRANSACTION
If FWFormCommit(oModel)//realizado a gravação do modelo de dados
cXml:='<MyXml>'
cXml+='<MyOperation>'
If oModel:GetOperation() != MODEL_OPERATION_DELETE
cXml+='UPSERT'
Else
cXml+='DELETE'
Endif
cXml+='</MyOperation>'
cXml+='<MyCode>'+oModel:GetValue('ZA0MASTER','ZA0_CODIGO')+'</MyCode>'
cXml+='<MyName>'+_NoTags(oModel:GetValue('ZA0MASTER','ZA0_NOME') )+'</MyName>'
cXml+='<MyType>'+oModel:GetValue('ZA0MASTER','ZA0_TIPO')+'</MyType>'
cXml+='</MyXml>'
oFWEAI:= FWEAI():New()
oFWEAI:SetFuncCode( "ROTINA DE INTEGRACAO X" )
oFWEAI:SetFuncDescription( "ROTINA DE INTEGRAÇÃO" )
oFWEAI:SetDocType( PROC_SYNC )
oFWEAI:AddLayout( "TESTEEAI", '1.0', "U_TSTEAI.01.02.03", cXml )
oFWEAI:SetTypeMessage( EAI_MESSAGE_MVC )
oFWEAI:SetSendChannel( EAI_CHANNEL_ESB )
oFWEAI:Activate()
If !oFWEAI:Save() //verifico se é possível realizar a integração.
lRet:=.F.
DisarmTransaction()
oFWEAI:Update()
oModel:SetErrorMessage('',,oModel:GetId(),'', 'MYEAI', 'Não foi possível realizar a integração.' )
Endif
oFWEAI:Deactivate()
oFWEAI:=NIL
Else
lRet:=.F.
Endif
END TRANSACTION
Return lRet
No fonte acima, foi incluído no bloco de commit do MVC Protheus a chamada da integração. Foi realizado também um tratamento para caso a integração não seja bem sucedida, o valor não seja gravado no Protheus. Esta rotina gera um XML idêntico ao XML recebido no exemplo Recebendo uma mensagem pela estrutura TOTVSIntegrator em adapters que não estão no cadastro.

Âncora
_Toc403759549
_Toc403759549
Integrações via Mensagem Única TOTVS


As integrações via Mensagem Única TOTVS são integrações que usam a arquitetura de mensagem TOTVSMessage. Ao contrário do exemplo da TOTVSIntegrator um adapter de Mensagem Única sempre deverá estar cadastrado para que a integração aconteça.
A arquitetura da mensagem única prevê um adapter com uma função estática, de nome IntegDef, para o processamento e cadastro do adapter sejam realizados. Para utilizar os defines é necessário o include FWADAPTEREAI.CH
A função IntegDef recebe como parâmetros:

  • cXml – O XML recebido pelo EAI Protheus. Diferente do TOTVSIntegrator é passado neste caso todo o XML recebido pelo EAI;
  • cType – Tipo de transação :
    • '0'- para mensagem sendo recebida (DEFINE TRANS_RECEIVE);
    • '1'- para mensagem sendo enviada (DEFINE TRANS_SEND);
  • cTypeMessage – Tipo da mensagem do EAI:
    • '20' – Business Message (DEFINE EAI_MESSAGE_BUSINESS)
    • '21' – Response Message (DEFINE EAI_MESSAGE_RESPONSE)
    • '22' – Receipt Message (DEFINE EAI_MESSAGE_RECEIPT)
    • '23' WhoIs Message (EAI_MESSAGE_WHOIS)
  • cVersion – Versão da Mensagem Única TOTVS.

O retorno desta rotina será sempre um array, de duas posições, sendo estas:

  • aArray[1] – Deve retornar uma variável lógica, indicando se o processamento foi executado com sucesso (.T.) ou não (.F.);
  • aArray[2] – Uma string contendo informações sobre o processamento.

Para os próximos exemplos vamos utilizar a rotina COMP011_MVC mostrada nos exemplos anteriores. A IntegDef deve ser capaz de ler o xml recebido e enviar um XML.

Âncora
_Ref403484488
_Ref403484488
Âncora
_Toc403759550
_Toc403759550
IntegDef em rotinas MVC Protheus

Seguindo o exemplo da rotina COMP011_MVC, vamos incluir a função IntegDef neste fonte.
#INCLUDE 'PROTHEUS.CH'
#INCLUDE 'FWMVCDEF.CH'
#INCLUDE 'FWADAPTEREAI.CH'
Function COMP011_MVC()
Local oBrowse
oBrowse := FWMBrowse():New()
oBrowse:SetAlias('ZA0')
oBrowse:SetDescription('Cadastro de Autor/Interprete')
oBrowse:AddLegend( "ZA0_TIPO=='1'", "YELLOW", "Autor" )
oBrowse:AddLegend( "ZA0_TIPO=='2'", "BLUE" , "Interprete" )
oBrowse:Activate()
Return NIL
//-------------------------------------------------------------------
Static Function MenuDef()
Local aRotina := {}
ADD OPTION aRotina TITLE 'Visualizar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 2 ACCESS 0
ADD OPTION aRotina TITLE 'Incluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 3 ACCESS 0
ADD OPTION aRotina TITLE 'Alterar' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 4 ACCESS 0
ADD OPTION aRotina TITLE 'Excluir' ACTION 'VIEWDEF.COMP011_MVC' OPERATION 5 ACCESS 0
Return aRotina
//-------------------------------------------------------------------
Static Function ModelDef()
Local oStruZA0 := FWFormStruct( 1, 'ZA0', /bAvalCampo/,/lViewUsado/ )
Local oModel
oModel := MPFormModel():New('COMP011_MVC', /bPreValidacao/, /bPosValidacao/, /bCommit/, /bCancel/ )
oModel:AddFields( 'ZA0MASTER', /cOwner/, oStruZA0, /bPreValidacao/, /bPosValidacao/, /bCarga/ )
oModel:SetDescription( 'Modelo de Dados de Autor/Interprete' )
oModel:GetModel( 'ZA0MASTER' ):SetDescription( 'Dados de Autor/Interprete' )
Return oModel
//-------------------------------------------------------------------
Static Function ViewDef()
Local oModel := FWLoadModel( 'COMP011_MVC' )
Local oStruZA0 := FWFormStruct( 2, 'ZA0' )
Local oView
oView := FWFormView():New()
oView:SetModel( oModel )
oView:AddField( 'VIEW_ZA0', oStruZA0, 'ZA0MASTER' )
oView:CreateHorizontalBox( 'TELA' , 100 )
oView:SetOwnerView( 'VIEW_ZA0', 'TELA' )
Return oView
Static Function IntegDef(cXml, cTypeTran, cTypeMsg, cVersion)
Local oXml :=NIL
Local oModel :=NIL
Local aErro :=NIL
Local cXmlRet :=''
Local cCode :=NIL
Local cLocalCode :=NIL
Local cDescri :=NIL
Local cType :=NIL
Local cErro :=NIL
Local cProduct :=NIL
Local cEvent :=NIL
Local cInternalId :=NIL
Local cValExt :=NIL
Local nX :=NIL
Local lRet:=.T.
Do Case
Case (cTypeTran ==TRANS_SEND )
oModel:=FwModelActive()
cCode:=oModel:GetValue('ZA0MASTER','ZA0_CODIGO')
cDescri:=oModel:GetValue('ZA0MASTER','ZA0_NOME')
cType:=oModel:GetValue('ZA0MASTER','ZA0_TIPO')
cInternalId:=CP11MakeId(cCode)
cXMLRet := '<BusinessEvent>'
cXMLRet += '<Entity>EXEMPLO</Entity>'
cXMLRet += '<Event>'
If oModel:GetOperation() <>MODEL_OPERATION_DELETE
cXmlRet+='UPSERT'
Else
cXmlRet+='DELETE'
CP11PutId(,,cInternalId,.T.)
Endif
cXmlRet+= '</Event>'
cXMLRet += '<Identification>'
cXMLRet += '<Key name="InternalId">'+cInternalId+'</Key>'
cXMLRet += '</Identification>'
cXMLRet += '</BusinessEvent>'
cXMLRet += '<BusinessContent>'
cXMLRet += '<Code>'+cCode + '</Code>'
cXMLRet += '<Name>'+ _NoTags(cDescri) + '</Name>'
cXMLRet += '<Type>' + cType + '</Type>'
cXMLRet += '</BusinessContent>'
Case ( cTypeTran == TRANS_RECEIVE )
Do Case
Case (cTypeMsg == EAI_MESSAGE_WHOIS )//whois
cXmlRet := '1.000'
Case (cTypeMsg == EAI_MESSAGE_RESPONSE )//resposta da mensagem única TOTVS
oXml:=tXmlManager():New()
oXml:Parse(cXml)
If Empty(oXml:Error())
cProduct:=oXml:xPathGetAtt('/TOTVSMessage/MessageInformation/Product','name')
For nX:=1 to oXml:xPathChildCount("/TOTVSMessage/ResponseMessage/ReturnContent/ListOfInternalId")
cInternalId:=oXml:xPathGetNodeValue("/TOTVSMessage/ResponseMessage/ReturnContent/ListOfInternalId/InternalId["+cValToCharn(nX)+"]/Origin")
cValExt:=oXml:xPathGetNodeValue("/TOTVSMessage/ResponseMessage/ReturnContent/ListOfInternalId/InternalId["+cValToCharn(nX)+"]/Destination")
If !Empty(cValExt) .and. !Empty(cInternalId)
CP11PutId( cProduct, cValExt, cInternalId)
Endif
Next
Endif
oXml:=Nil
Case (cTypeMsg == EAI_MESSAGE_RECEIPT )//Receipt. Não realizo nenhuma ação
Case ( cTypeMsg == EAI_MESSAGE_BUSINESS )//chegada de mensagem de negócios
oXml:=tXmlManager():New()
oXml:Parse(cXml)
If Empty(cErro:=oXml:Error())
cValExt:=oXml:xPathGetNodeValue('/TOTVSMessage/BusinessMessage/BusinessEvent/Identification/Key')
cEvent:=AllTrim(Upper(oXml:xPathGetNodeValue('/TOTVSMessage/BusinessMessage/BusinessEvent/Event')))
cCode:=oXml:xPathGetNodeValue('/TOTVSMessage/BusinessMessage/BusinessContent/Code')
cDescri:=oXml:xPathGetNodeValue('/TOTVSMessage/BusinessMessage/BusinessContent/Name')
cType:=oXml:xPathGetNodeValue('/TOTVSMessage/BusinessMessage/BusinessContent/Type')
cProduct:=oXml:xPathGetAtt('/TOTVSMessage/MessageInformation/Product','name')
cLocalCode:=CP11RetId(cProduct,cValExt,@cInternalId)
If cEvent=='UPSERT'
If !Empty(cLocalCode) .and. ZA0->(DbSeek(xFilial('ZA0')+cLocalCode))//se encontrou, é atualização
cEvent:=MODEL_OPERATION_UPDATE
Else
cEvent:=MODEL_OPERATION_INSERT
While ZA0->(DbSeek(xFilial('ZA0')+cCode))//não posso gravar com o mesmo, gravo com outro.
cCode:=GetSXENum('ZA0','ZA0_CODIGO')
If !ZA0->(DbSeek(xFilial('ZA0')+cCode))
Exit
Else
ConfirmSX8()
Endif
EndDo
Endif
ElseIf cEvent=='DELETE'
If !Empty(cLocalCode) .and. ZA0->(DbSeek(xFilial('ZA0')+cLocalCode))
cEvent:=MODEL_OPERATION_DELETE
Else
lRet:=.F.
cXmlRet:='Registro não encontrado no Protheus.'
Endif
Else
lRet:=.F.
cXmlRet:='Operação inválida. Somente são permitidas as operações UPSERT e DELETE.'
Endif
If lRet
oModel:=FwLoadModel('COMP011_MVC')
oModel:SetOperation(cEvent)
If oModel:Activate()
If cEvent<> MODEL_OPERATION_DELETE
If cEvent== MODEL_OPERATION_INSERT
oModel:SetValue('ZA0MASTER','ZA0_CODIGO',cCode)
Endif
oModel:SetValue('ZA0MASTER','ZA0_NOME',cDescri)
oModel:SetValue('ZA0MASTER','ZA0_TIPO',cType)
Endif
IF oModel:VldData()
lRet:=oModel:CommitData()
Else
lRet:=.F.
Endif
Else
lRet:=.F.
Endif
If !lRet
aErro:=oModel:GetErrorMessage()
If !Empty(aErro)
cErro:='A integração não foi bem sucedida.'
cErro+='Foi retornado o seguinte erro: ' +Alltrim(aErro[5])+'-'+AllTrim(aErro[6])
If !Empty(Alltrim(aErro[7]))
cErro+='Solução - '+AllTrim(aErro[7])
Endif
Else
cErro:='A integração não foi bem sucedida. '
cErro+='Verifique os dados enviados'
Endif
aSize(aErro,0)
aErro:=nil
cXmlRet:=cErro
Else
If Empty(cInternalId)
cInternalId:=CP11MakeId(cCode)
Endif
If cEvent != MODEL_OPERATION_DELETE//Devolvo o internalID para que seja possível o outro lado gravar o relacionamento
cXmlRet:='<ListOfInternalId>'
cXmlRet+='<InternalId>'
cXmlRet+='<Name>EXEMPLO</Name>'
cXmlRet+='<Origin>'+cValExt+'</Origin>'
cXmlRet+='<Destination>'+cInternalId+'</Destination>'
cXmlRet+='</InternalId>'
cXmlRet+='</ListOfInternalId>'
Endif
CP11PutId(cProduct,cValExt,cInternalId,cEvent == MODEL_OPERATION_DELETE)//realizo a manutenção do internalId
Endif
oModel:Deactivate()
oModel:Destroy()
Endif
Else
lRet:=.F.
cXmlRet:=cErro
Endif
oXml:=nil
EndCase
EndCase
oModel:=nil
DelClassIntF()
Return {lRet,cXmlRet}
Function CP11MakeId(cId,cEmp,cFil)
Local cREt
Default cEmp:=cEmpAnt
Default cFil:=xFilial('ZA0')
cREt:=rTrim(cEmp)+'|'+rTrim(cFil)+'|'+cId
Return cREt

Function CP11RetId(cProduct,cValExt,cValInt)
Local cRet:=''
cValInt:=CFGA070INT(cProduct,'ZA0','ZA0_CODIGO',cValExt)
If !Empty(cValInt)
cRet:=Separa(cValInt,'|')[3]
Endif
Return cRet
Function CP11PutId( cRefer, cValExt, cValInt, lDelete)
Default lDelete:=.F.
Return CFGA070MNT( cRefer, 'ZA0', 'ZA0_CODIGO', cValExt, cValInt, lDelete)
A rotina IntegDef é a responsável por realizar o processamento da mensagem a ser enviada e da mensagem recebida. Perceba que os tratamentos de InternalId (o de/para de registros) é realizado, quando necessário, por esta rotina, e nunca pela camada de EAI Protheus.
A integração é disparada no momento do commit dos dados do modelo. Caso a rotina possua um bloco de commit próprio, a integração somente é disparada automaticamente se a função FWFormCommit for utilizada para a gravação do modelo.
O adapter EAI deve sempre tratar os dois sentidos da mensagem: Envio e Recebimento.
O Adapter EAI deve obrigatoriamente sempre tratar o recebimento da Mensagem Única Whois, que retorna informações sobre a mensagem e a sua versão. Para isto, as versões disponíveis da mensagem devem sempre ser enviadas com a seguinte máscara: V.RRR, onde V é a versão da mensagem e R o release da mesma. Para diferentes versões disponíveis dentro do mesmo adapter, estas devem ser devolvidas com o separador '|' entre elas. Exemplo para uma rotina que possua as versões 1.000, 1.001 e 2.000 disponíveis: '1.000|1.001|2.000'. O Cadastro de Adapters do Protheus somente permite que sejam cadastradas versões de mensagens disponíveis no adapter. As alterações de versões de mensagens são acordadas entre as equipes que fazem as manutenções das mesmas, e são sempre direcionadas ao Comitê de Integrações TOTVS, para a definição de qual será a versão/release de alteração da mesma.
Vamos agora cadastrar o adapter para a Mensagem Única MyMessage (lembrando que o nome da mensagem é acordado no Comitê de Integrações TOTVS. Este nome é usado apenas como exemplo).

Figura 19 - Cadastro da Mensagem Única em fonte MVC no Protheus.
Vamos agora mostrar o XML de envio, e o XML recebido no Protheus:
XML enviado:
<?xml version="1.0" encoding="utf-8"?>
<TOTVSMessage>
<MessageInformation version="1.000">
<UUID>0f4b7f7e-e87d-785f-9f41-0fa5c9894844</UUID>
<Type>BusinessMessage</Type>
<Transaction>MYMESSAGE</Transaction>
<StandardVersion>1.000</StandardVersion>
<SourceApplication>RETAGUARDA</SourceApplication>
<CompanyId>18</CompanyId>
<BranchId>D MG 01 </BranchId>
<Product name="PROTHEUS" version="11"/>
<GeneratedOn>2014-11-11T15:14:26</GeneratedOn>
<DeliveryType>Sync</DeliveryType>
</MessageInformation>
<BusinessMessage>
<BusinessEvent>
<Entity>EXEMPLO</Entity>
<Event>DELETE</Event>
<Identification>
<Key name="InternalId">18|D MG|000005</Key>
</Identification>
</BusinessEvent>
<BusinessContent>
<Code>000005</Code>
<Name>6666666 </Name>
<Type>2</Type>
</BusinessContent>
</BusinessMessage>
</TOTVSMessage>
A mensagem devolveu um XML para esta rotina:
<?xml version="1.0" encoding="utf-8"?>
<TOTVSMessage>
<MessageInformation version="1.000">
<UUID>f9371536-5b6b-612d-3350-7227c4a9a17d</UUID>
<Type>Response</Type>
<Transaction>MYMESSAGE</Transaction>
<StandardVersion>1.000</StandardVersion>
<SourceApplication>PR11_BRA</SourceApplication>
<CompanyId>18</CompanyId>
<BranchId>D MG 01 </BranchId>
<Product name="PROTHEUS" version="11"/>
<GeneratedOn>2014-11-11T15:14:27</GeneratedOn>
<DeliveryType>Sync</DeliveryType>
</MessageInformation>
<ResponseMessage>
<ReceivedMessage>
<SentBy>PROTHEUS</SentBy>
<UUID>0f4b7f7e-e87d-785f-9f41-0fa5c9894844</UUID>
<MessageContent>
<![CDATA[<?xml version="1.0" encoding="utf-8"?><TOTVSMessage>
<MessageInformation version="1.000">
<UUID>0f4b7f7e-e87d-785f-9f41-0fa5c9894844</UUID>
<Type>BusinessMessage</Type>
<Transaction>MYMESSAGE</Transaction>
<StandardVersion>1.000</StandardVersion>
<SourceApplication>RETAGUARDA</SourceApplication>
<CompanyId>18</CompanyId>
<BranchId>D MG 01 </BranchId>
<Product name="PROTHEUS" version="11">
</Product><GeneratedOn>2014-11-11T15:14:26</GeneratedOn>
<DeliveryType>Sync</DeliveryType></MessageInformation>
<BusinessMessage><BusinessEvent><Entity>EXEMPLO</Entity>
<Event>DELETE</Event>
<Identification><Key name="InternalId">18|D MG|000005</Key>
</Identification></BusinessEvent>
<BusinessContent><Code>000005</Code>
<Name>6666666 </Name>
<Type>2</Type></BusinessContent>
</BusinessMessage></TOTVSMessage>]]>
</MessageContent>
</ReceivedMessage>
<ProcessingInformation>
<ProcessedOn>2014-11-11T15:14:27</ProcessedOn>
<Status>ok</Status>
</ProcessingInformation>
<ReturnContent/>
</ResponseMessage>
</TOTVSMessage>

Âncora
_Ref403484500
_Ref403484500
Âncora
_Toc403759551
_Toc403759551
IntegDef em rotinas Não-MVC Protheus


Nas rotinas escritas em MVC Protheus o disparo das integrações via Mensagem Única é realizado internamente, no commit do modelo de dados. Rotinas que não são MVC Protheus devem realizar a chamada da integração manualmente. Este fato se deve ao fato de que, em rotinas que não são MVC Protheus não é possível saber o momento da gravação dos dados pela camada do EAI Protheus. Nestes casos, o desenvolvedor da rotina é o mais indicado a saber o momento correto de iniciar a integração. Para estas rotinas é necessário realizar a chamada da função FWIntegDef nos fontes. Veja o tópico Funções utilizáveis no EAI Protheus para detalhes do funcionamento desta rotina.
Supondo que a rotina COMP011_MVC não estivesse escrita em MVC Protheus, e que em algum ponto do sistema a gravação fosse realizada por esta rotina. Segue abaixo um exemplo de chamada da FWIntegDef:
//.......................
BEGIN TRANSACTION
RecLock('ZA0',.T.)
ZA0->ZA0_CODIGO:=cCode
ZA0->ZA0_NOME:=cDescri
ZA0->ZA0_TIPO:='1'
MsUnlock()
FwIntegDef('COMP011_MVC')
END TRANSACTION
//..........................

Status do documentoConcluídoCriação
Data18/11/2014
Versão1.0
Versão anterior1.0
Autores

Jandir Deodato De Souza Silva

Índice resumido
Índice
maxLevel1
indent10px
Índice
Índice
outlinetrue
indent10px