Pular para o conteúdo principal

Postagem em destaque

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️ Olá pessoal, Espero que este post encontre todos vocês bem! É com grande entusiasmo que compartilho que estou expandindo meus serviços como Desenvolvedor AdvPL para novos desafios e colaborações. Com mais de duas décadas de experiência sólida, minha jornada profissional tem sido enriquecedora, com a oportunidade de participar de projetos empolgantes ao longo dos anos. Agora, estou ansioso para trazer minha experiência e habilidades para novas equipes e projetos, trabalhando de forma remota. Minha expertise abrange não apenas AdvPL, mas também outras tecnologias-chave, incluindo JS, SQL, Infraestrutura e Otimização de Processos. Acredito que essa combinação de conhecimentos me permite oferecer soluções abrangentes e eficazes para uma variedade de necessidades de desenvolvimento. Acredito que a tecnologia tem o poder de transformar negócios e impulsionar o sucesso, e estou comprometido em ajudar meus clientes a alcançar seu

Protheus :: Rompendo Limites e Barreiras (open your mind)

Rodrigo entrou em uma roubada. Perguntou-me: "..иαldσ estou com problemas para gerar um client de um WebService no Protheus, não sei se é minha instalação. Será que você poderia me ajudar?" (foi + ou - assim ... rs)

manda-o-link-aew (respondi eu). e;

taí: http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL

Testei.... hummmmm.... Olha a mensagem emitida pelo IDE:

Estabelecendo conexão com o server...
Por favor aguarde. Obtendo descrição do WebService...
Erro na obtenção da descrição do WebService: 
Invalid function return for WSDLSource Call.
Finalizando conexão com o server...
Ok
Bem... não me ajudou muito.... Opa.... "Invalid function return for WSDLSource Call".... hummmmmm.... WSDLSource... acho que é esse carinha aqui quem tenta gerar o client.... Vamos executá-lo diretamente.... Sintaxe: WSDLSource( cUrl ) : [lSucess][cSource/cError].

WSDLSource( "http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL" )
NIL
Retorno NIL, estava eperando um Array.... Vamos ver o Console do server...

[FATAL][SERVER] [Thread 1356] [THROW] String size overflow! at file c:\advtec9_101202a\lib_base\stringz.hpp line 355

String size overflow! (Oops: Erro, erro no servidor, Bad, bad server ).....

Rodrigo, seguinte, o protheus "p...". A restrição no tamanho da string imposta pelo pessoal de Tecnologia do Protheus não vai deixar que gere o seu Client.

Tem alguma solução? (perguntou ele).... e a resposta foi: 3 Possíveis soluções.

1 ) Abrir um chamado da Totvs/Microsiga e solicitar que ampliem o limite da string;
2 ) Entrar em contato com o Desenvolvedor do WebService e pedir para que ele divida o WS em Vários outros WS ; e
3 ) Usar uma aplicação externa para resolver o WS e retornar a informação ao Protheus. Testei no Windows® PowerShell® e funciona que é uma beleza.

O que acha?

"O pessoal aqui não acredita que essa ultima solução funcione. Tem como mandar um exemplo simples? Tem o Método CountUsers que retorna o número de usuários."....

heheheheh.... demorô.....

Segue o Código:

#INCLUDE "APWEBSRV.CH"
#INCLUDE "PROTHEUS.CH"
#INCLUDE "TRYEXCEPTION.CH"
/*/
 WSSERVICE: u_FuturePMS
 Autor:  Marinaldo de Jesus
 Data:  05/05/2011
 Descricao: Usar PowerShell para Resolver WS nao suportado pelo Protheus em Funcao de Limitacao da Linguagem 
/*/
WSSERVICE u_FuturePMS DESCRIPTION "Integracao Protheus x PowerShell x FuturePMS" NAMESPACE "http://localhost/u_futurepms.apw" 
 
 WSDATA CountUser AS INTEGER
 WSDATA PSException AS BOOLEAN

 WSMETHOD CountUsers DESCRIPTION "Retornar o Numero de Usuarios do ServiceFuturePMS"

ENDWSSERVICE

/*/
 WSMETHOD: CountUsers
 Autor:  Marinaldo de Jesus
 Data:  05/05/2011
 Descricao: Encapsular a Chamada ao Metodo CountUsers do WS ServiceFuturePMS executando-o atraves do PS e retornando o Resultado
/*/
WSMETHOD CountUsers WSRECEIVE PSException WSSEND CountUser WSSERVICE u_FuturePMS

 Local aFileErase := {}
 
 Local cCRLF   := CRLF
 Local cPsHome  := ""
 Local cPsScript  := ""
 Local cRootPath  := ""
 Local cPSFileSript := ""
 Local cPathFileXml := ""
 Local cFullPathXml := ""
 Local cFullPathPS1 := ""
 Local cWsResultPath := "\PPSIntWs\"
 Local cWSFileResult := ""

 Local cXmlError  := ""
 Local cXmlWarning := ""

 Local lWsMethodRet := .T.

 Local oXml
 Local oException

 TRYEXCEPTION

  cRootPath := GetSrvProfString( "RootPath" , "" )
  IF ( SubStr( cRootPath , -1 ) == "\" )
   cRootPath := SubStr( cRootPath , 1 , Len( cRootPath ) - 1 )
  EndIF 

  IF !lIsDir( cWsResultPath )
   MakeDir( cWsResultPath )
   IF !lIsDir( cWsResultPath )
    ExUserException( "Impossível Criar o Diretório: " + cWsResultPath ) 
   EndIF
  EndIF
  
  cWSFileResult  := CriaTrab( NIL , .F. )
  cPathFileXml  := ( cWsResultPath + cWSFileResult ) 
  While ( File( cPathFileXml + ".xml" ) .or. File( cPathFileXml + ".ps1" ) )
   cWSFileResult := CriaTrab( NIL , .F. )
   cPathFileXml := ( cWsResultPath + cWSFileResult ) 
  End While

  cPSFileSript  := ( cWSFileResult + ".ps1" )

  cPathFileXml  += ".xml"
  aAdd( aFileErase , cPathFileXml )

  cFullPathXml  := ( cRootPath + cPathFileXml )
  cPSFileSript  := ( cWsResultPath + cPSFileSript )
  cFullPathPS1  := ( cRootPath + cPSFileSript )

  aAdd( aFileErase , cPSFileSript )

  DEFAULT Self:PSException := .F.
  DEFAULT PSException   := Self:PSException

  /*/
   Para que o "script" possa ser executado faz-se necessario autoriza-lo atraves do Windows PowerShell,   sendo
   assim, execute o Windows PowerShell e digite o seguinte comando: 
   
   get-help about_signing. 
   
   Esse comando ira listar as opcoes de "Diretivas de Assinatura e de Execucao" de "Script". Leia-as atentamente. 
   
   Mas se quiser pular esse passo (eu nao recomendo) digite o seguinte comando abaixo no Windows PowerShell: 
   
   Set-ExecutionPolicy Unrestricted. 
   
   Esse comando fara que qualquer "Script" seja executado em sua máquina (mas atente para os itens de   seguranca 
   listados aa partir do comando get-help about_signing).

  /*/

  cPsScript    :=  " [int]$CountUserResult = 0"
  cPsScript    += cCRLF
  cPsScript    += " [boolean]$CountUserResultSpecified = $True"
  cPsScript    += cCRLF
  cPsScript    += " $ws = New-WebServiceProxy -URI http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL"
  cPsScript    += cCRLF
  cPsScript    += " $ws.CountUsers( [ref]$CountUserResult , [ref]$CountUserResultSpecified )"
  cPsScript    += cCRLF
  cPsScript    += " [string]$PSOutFile = '" + cFullPathXml + "'"
  cPsScript    += cCRLF
  cPsScript    += " $xml = " + '"' + "$CountUserResult" + '"'
  cPsScript    += cCRLF
  cPsScript    += " $xml | Out-File $PSOutFile"
  cPsScript    += cCRLF

  IF ( PSException )
   cPsScript   := AddPsException( @cPsScript , @cCRLF )
  EndIF

  MemoWrite( cPSFileSript , cPsScript )
        
  cPsHome := AllTrim( GetSrvProfString( "PSHome" , "C:\WINDOWS\system32\WindowsPowerShell\v1.0\" ) )
  IF !( SubStr( cPsHome , -1 ) == "\" )
   cPsHome += "\"
  EndIF

  IF !( WaitRunSrv( cPsHome + "powershell.exe " + cFullPathPS1 , .T. , cPsHome ) )
      ExUserException( "Impossivel Executar o PowerShell" )
  EndIF

  IF !File( cPathFileXml )
   ExUserException( "XML não carregado: " + cPathFileXml ) 
  EndIF

  oXml    := XmlParserFile( @cPathFileXml , "_" , @cXmlError , @cXmlWarning )

  IF !( ValType( oXml ) == "O" )
   IF !Empty( cXmlError )
    ExUserException( cXmlError ) 
   EndIF 
   ExUserException( "Impossovel Carregar o XML: " + cPathFileXml ) 
  EndIF

  Self:CountUser  := Val( oXml:_Result:_CountUser:Text )
  CountUser   := Self:CountUser

 CATCHEXCEPTION USING oException
 
  lWsMethodRet  := .F.

  SetSoapFault( ProcName() , CaptureError() )

 ENDEXCEPTION

 aEval( aFileErase , { |cFile| IF( File( cFile ) , fErase( cFile ) , NIL ) } )

Return( lWsMethodRet )

/*/
 WSMETHOD: AddPsException
 Autor:  Marinaldo de Jesus
 Data:  05/05/2011
 Descricao: Adicionar Tratamento de Excecao no Script em PowerShell
/*/
Static Function AddPsException( cPsScript , cCRLF )

 Local cPSException := ""
 Local cMsgException := " 'Não foi possível conectar-se a http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL'"

 cPSException  := "try"
 cPSException  += cCRLF
 cPSException  += "{"
 cPSException  += cCRLF
 cPSException  += cPsScript
 cPSException  += cCRLF
 cPSException  += "}"
 cPSException  += cCRLF
 cPSException  += "catch"
 cPSException  += cCRLF
 cPSException  += "{"  
 cPSException  += cCRLF
 cPSException  += cMsgException
 cPSException  += cCRLF
 cPSException  += "}"
 cPSException  += cCRLF

Return( cPSException )


e o Client gerado a partir dele:

#INCLUDE "PROTHEUS.CH"
#INCLUDE "APWEBSRV.CH"

/* ===============================================================================
WSDL Location    http://200.143.193.75:8081/ws/U_FUTUREPMS.apw?WSDL
Gerado em        05/05/11 09:58:21
Observações      Código-Fonte gerado por ADVPL WSDL Client 1.101007
                 Alterações neste arquivo podem causar funcionamento incorreto
                 e serão perdidas caso o código-fonte seja gerado novamente.
=============================================================================== */

User Function _WHYOFUC ; Return  // "dummy" function - Internal Use 

/* -------------------------------------------------------------------------------
WSDL Service WSU_FUTUREPMS
------------------------------------------------------------------------------- */

WSCLIENT WSU_FUTUREPMS

 WSMETHOD NEW
 WSMETHOD INIT
 WSMETHOD RESET
 WSMETHOD CLONE
 WSMETHOD COUNTUSERS

 WSDATA   _URL                      AS String
 WSDATA   _HEADOUT                  AS Array of String
 WSDATA   lPSEXCEPTION              AS boolean
 WSDATA   nCOUNTUSERSRESULT         AS integer

ENDWSCLIENT

WSMETHOD NEW WSCLIENT WSU_FUTUREPMS
::Init()
If !FindFunction("XMLCHILDEX")
 UserException("O Código-Fonte Client atual requer os executáveis do Protheus Build [7.00.101202A-20110330] ou superior. Atualize o Protheus ou gere o Código-Fonte novamente utilizando o Build atual.")
EndIf
Return Self

WSMETHOD INIT WSCLIENT WSU_FUTUREPMS
Return

WSMETHOD RESET WSCLIENT WSU_FUTUREPMS
 ::lPSEXCEPTION       := NIL 
 ::nCOUNTUSERSRESULT  := NIL 
 ::Init()
Return

WSMETHOD CLONE WSCLIENT WSU_FUTUREPMS
Local oClone := WSU_FUTUREPMS():New()
 oClone:_URL          := ::_URL 
 oClone:lPSEXCEPTION  := ::lPSEXCEPTION
 oClone:nCOUNTUSERSRESULT := ::nCOUNTUSERSRESULT
Return oClone

// WSDL Method COUNTUSERS of Service WSU_FUTUREPMS

WSMETHOD COUNTUSERS WSSEND lPSEXCEPTION WSRECEIVE nCOUNTUSERSRESULT WSCLIENT WSU_FUTUREPMS
Local cSoap := "" , oXmlRet

BEGIN WSMETHOD

cSoap += ''
cSoap += WSSoapValue("PSEXCEPTION", ::lPSEXCEPTION, lPSEXCEPTION , "boolean", .T. , .F., 0 , NIL, .T.) 
cSoap += ""

oXmlRet := SvcSoapCall( Self,cSoap,; 
 "http://localhost/u_futurepms.apw/COUNTUSERS",; 
 "DOCUMENT","http://localhost/u_futurepms.apw",,"1.031217",; 
 "http://200.143.193.75:8081/ws/U_FUTUREPMS.apw")

::Init()
::nCOUNTUSERSRESULT  :=  WSAdvValue( oXmlRet,"_COUNTUSERSRESPONSE:_COUNTUSERSRESULT:TEXT","integer",NIL,NIL,NIL,NIL,NIL,NIL) 

END WSMETHOD

oXmlRet := NIL
Return .T.


Compile o WSServer, gere o Client baseado na sua URL, teste e me diga se funciona ou não.... Foi um exemplo bem simples. Poderia ter retornado o xml diretamente, mas nesse caso não faria sentido.

Eu testei aqui, e olha o resultado.

NameSpace  http://localhost/u_futurepms.apw  
  URL Location  http://200.143.193.75:8081/ws/  
  Nome do Serviço  U_FUTUREPMS  
  Método do Serviço  COUNTUSERS  
 
Resposta da Requisição SOAP 
  

   
      
         1
      
   



Bendita WaitRunSrv() e salve o Windows® PowerShell® (a Totvs bem podia contratar o Engenheiro que planejou o novo Shell do Windows® para reescrever a tecnologia Protheus/by you... o que acham ... rs)

Considerações:

1 ) O Pessoal da Tecnologia Protheus deveria rever essa limitação do tamanho da string no protheus;
2 ) AppServer64 já.

Para baixar os códigos utilizados neste "post", cliquem aqui.


[]s
иαldσ dj

(simples assim)

Comentários

  1. Grande Naldo! Mestre no que faz... Para quem pensou que esse nosso desafio nao daria em nada hein!? hehehehe... é como eu ja disse ate para o Bindo... Marinaldo de Jesus é o cara... o resto...bem... o resto é programador... hehehe
    É isso ae Naldo... vc domina e creio q todos que acompanham devia te-lo como exemplo... analizar... modelar.... desenvolver... Se isso fosse de fato feito, talvez o Protheus nao seria uma colcha de retalho! Grande abraço e obrigado pelo desafio!

    ResponderExcluir
  2. Naldo, blz?

    Cara... aproveitando seu tópico... to com um problema aqui... será que você poderia me ajudar?

    Seguinte... gerei uma função client de webservice no Protheus que foi compilada certinho... desenvolvi uma função para chamar esse client e blz... tudo funcionava ok.

    Porém agora mudaram a URL do webservice e tive que alterar minha função client... pra apontar pra essa nova URL... só que agora, na execução do Protheus, retorna a seguinte mensagem:

    "The Web application at http://testehh80.empresaX.com.br/formularios could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application."

    Só que o endereço do webservice que configurei na função não é esse... segue o código que escrevi abaixo...

    oXmlRet := SvcSoapCall( Self,cSoap,;
    "http://tempuri.org/GetCadastrosPendentes",;
    "DOCUMENT","http://tempuri.org/",,,;
    "http://arasrvvirshp002:85/EmpresaXWsSpMicInt/WsSPMicData.asmx")

    O mais engraçado é que essa URL ta funcionando legal no browser do IE e o IDE do Protheus também tá gerando a função desse client certinho.

    Enfim... não consegui descobrir o motivo pelo qual o Protheus não chama o webservice do endereço que to passando... e devolve essa mensagem de erro apontando pra esse testehh80.empresaX.

    Você pode me ajudar nesse problema?

    Obrigado e abraços!

    ResponderExcluir
    Respostas
    1. Perguntas-Respostas:

      1) Quando regerou o Client utilizou o mesmo arquivo fonte ou gerou um novo? Já que está apenas atualizado deveria manter o mesmo arquivo fonte limpando-o antes de gerar o novo client.

      2) Por via das dúvidas (não que isso seja necessário) você excluiu do Projeto e, consequentemente, do RPO o código do Client antigo antes da geração do novo?

      Com as informações passadas, as perguntas-respostas acima talvez resolvam o seu "problema". Caso contrário necessitarei de mais informações.

      Uma forma de descobrir se, de fato o seu RPO está compilado com a última versão é verificando via "Object Inspector" ou utilizando-se das funções existentes no post:

      Protheus :: Advpl :: Usando GetFuncArray, GetApoInfo e VarInfo ( http://goo.gl/k9Fea ).

      Se os itens acima elencados não solucionarem o seu problema envie-me o código do client (o novo) e o seu RPO para mail@blacktdn.com.br. Dessa forma poderei comparar ambos os códigos.

      Excluir
  3. TryExeption.ch? Onde consigo essa CH? rsrs

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

BlackTDN :: RLeg ~ Desvendando a Função ParamBox

Para quem precisar desenvolver uma interface de entrada de dados, coisa rápida, e não quer ter aquele trabalhão danado que todos já sabemos, o Protheus tem uma função que ajuda muito, é uma interface semelhante a função Pergunte, porém com muito mais opção de objeto de entrada de dados, alias até colocar o scrollbox desta interface com todos os objetos em outra MsDialog ou Wizard é simples. Vejam o exemplo abaixo, boa sorte! Rleg. //---------------------------------------------------------- // Função exemplo utilizando a função ParamBox() //---------------------------------------------------------- User Function xParamBox() Local aRet := {} Local aParamBox := {} Local aCombo := {"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"} Local i := 0 Private cCadastro := "xParambox" // ---------------

Protheus :: Chamando Funções do Menu Diretamente e sem a Necessidade de Login

Ferne$ perguntou: "...é possível abrir alguma rotina do sistema sem solicitar login ao usuário, como por exemplo a rotina MATA010..." Sim Ferne$, é possível sim. Abaixo um Exemplo para a Chamada à função MATA010 sem a necessidade de Login no sistema. #INCLUDE "PROTHEUS.CH" #INCLUDE "TBICONN.CH" /*/ Funcao: MATA010Ex Data: 30/04/2011 Autor: Marinaldo de Jesus Descricao: Executar a Funcao MATA010 diretamente sem a necessidade de LOGIN no Protheus Sintaxe: 1 ) U_MATA010Ex ( Chamada diretamente na Tela de Entrada do Sistema ) ; ou 2 ) totvsclient.exe -q -p=u_MATA010Ex -a=01;01 -c=rnp_local -e=rnp -m -l ( Chamada Via Linha de Comando ) /*/ User Function MATA010Ex( cEmpFil ) Local aEmpFil Local bWindowInit := { || __Execute( "MATA010()" , "xxxxxxxxxxxxxxxxxxxx" , "MATA010" , "SIGAFAT" , "SIGAFAT", 1 , .T. ) } Local cEmp Local cFil Local cMod Local cModName := "SIGAFAT" DEFA

BlackTDN :: Customizando a interface de Login no Protheus e by You

A publicação “ BlackTDN :: By You e sua nova tela de login ”  de nosso amigo OBona deu o que falar e, em função disso, esse que a muito não vos escreve resolveu criar uma versão onde será possível personalizar, “por completo”, a tela de login no Protheus/by You. Considerando que OBona já havia “mapeado, identificado e customizado” as imagens peguei-as emprestadas para o exemplo que se segue: O primeiro passo para a customização “total” da interface de login do Protheus/by You será implementar o “Ponto de Entrada” ChgPrDir (Diretório de impressão) . Usaremos esse PE juntamente como programa U_FindMsObject.prg (apresentado pela primeira vez em: Protheus :: ADVPL : The Container : Presents Pandora's box ). Diferente do exemplo proposto por OBona, que substitui, durante o processo de compilação, as imagens padrões do sistema (excluindo-as) por imagens customizadas (com o mesmo nome) este novo exemplo mantém, no RPO, as imagens padrões adicionando novas imagens customizadas que serã