sexta-feira, 3 de abril de 2020


Hoje irei disponibilizar um código em advpl para verificar a similaridade de duas strings. Ele é uma adaptação que eu fiz baseado no algorítimo de Levenshtein.
Mais detalhes no link :Levenshtein distance
Basicamente ele informa quantos operações serão necessárias para deixar uma string igual a outra. Algo muito utilizado em corretores ortográficos como também em aplicações de IA em que podemos analisar a resposta dada por algum usuário em um questionário ou um Chatbot.


Por exemplo, a distância Levenshtein entre as palavras inglesas "kitten" (gato) e "sitting" (sentando-se) é 3, já que com apenas 3 edições conseguimos transformar uma palavra na outra, e não há maneira de o fazer com menos de três edições:
  • kitten
  • sitten (substituição de 'k' por 's')
  • sittin (substituição de 'e' por 'i')
  • sitting (inserção de 'g' no final)


Segue o fonte:
#INCLUDE "PROTHEUS.CH" 
#INCLUDE "RWMAKE.CH" 
#include 'tbiconn.ch'

//recebe duas strings como parâmetro e realiza a comparação entre elas usando
//o algorítimo de Levenshtein

User Function POSTRING(s,t)
Local i := 1
Local j := 1
Local sa   := {}
Local ta   := {}

//transformar string em array 
for i := 1 To len(s)
    aaDD(sa,SubStr(s,i,1))
next 
for i := 1 To len(t)
    aaDD(ta,SubStr(t,i,1))
next 


n = Len(s) 
m = Len(t) 
d = Array(n+1,m+1)

//colocando zeros nas posições do array pois n pode ter elemento nulo (nil)
for i := 1 To n+1
    for j := 1 To m+1
        d[i,j] := 0
    next j
next i 



if (n == 0)
    return m
EndIf
if (m == 0)
    return n
Endif

for i = 1 To  n + 1 
    d[i, 1] = i-1
next

for j = 1 To m + 1
    d[1, j] = j-1
next

for i := 2 To n + 1
    for j:= 2 To m + 1
        cost = iif(ta[j - 1] == sa[i - 1],0,1)
        d[i, j] = Min(Min(d[i - 1, j] + 1, d[i, j - 1] + 1),d[i - 1, j - 1] + cost)
    next j
next i 


Return  d[n+1, m+1]

terça-feira, 3 de julho de 2018

Novo Blogger da empresa ERP Consult Brasil

http://erpconsultbrasil.blogspot.com/

quarta-feira, 18 de outubro de 2017

Integração Protheus vs Arduino

Neste artigo rápido, gostaria de mostrar uma simples integração entre o ERP Protheus e o Arduino. Não irei aprofundar-me na arquitetura da plataforma arduino, mas resumidamente, ele permite uma ótima integração entre software e hardware.

Imagine poder controlar a rotação de um motor elétrico, nível de luminosidade em determinado ambiente, abrir e fechar circuitos, acionar alarmes, trabalhar com diversos sensores como de temperatura, de presença  usando o ERP Protheus. Com o arduino, isso é possível. E para começar a mostrar as possibilidades, irei iniciar com um projeto bem simples aonde uma tela em advpl terá botões que irão controlar o acendimento de leds.

Para começar, segue abaixo o código usado na IDE do Arduino:

const int LEDa = 13;
const int LEDb = 12;
const int LEDc = 11;
const int LEDd = 10;

void setup() {
  Serial.begin(9600);    //configura comunicação serial com 9600 bps
  pinMode(LEDa,OUTPUT);   //configura pino do led como saída
  pinMode(LEDb,OUTPUT);   //configura pino do led como saída
  pinMode(LEDc,OUTPUT);   //configura pino do led como saída
  pinMode(LEDd,OUTPUT);   //configura pino do led como saída
}
void loop() {
   if (Serial.available()) //se byte pronto para leitura
   {
    apagaTudo();
    switch(Serial.read())      //verifica qual caracter recebido
    {
      case 'A':                  //caso 'A'
        digitalWrite(LEDa,HIGH); //inverte estado do LED
      break;

      case 'B':                  //caso 'B'
        digitalWrite(LEDb,HIGH); //inverte estado do LED
      break;

       case 'C':                  //caso 'C'
        digitalWrite(LEDc,HIGH); //inverte estado do LED
      break;

      case 'D':                  //caso 'D'
        digitalWrite(LEDd,HIGH); //inverte estado do LED
      break;
     
    }
  }
}

void apagaTudo()
{
  digitalWrite(LEDa,LOW);
  digitalWrite(LEDb,LOW);
  digitalWrite(LEDc,LOW);
  digitalWrite(LEDd,LOW);
}



Agora, a tela Protheus que irá controlar os leds:

#INCLUDE "rwmake.ch"                                                 
#INCLUDE 'PROTHEUS.CH'
#include "topconn.ch"   
#INCLUDE 'FONT.CH'
#INCLUDE 'COLORS.CH'


User Function intARDU()  

SetPrvt("oDlg1","oBtn1","oBtn2","oBtn3","oBtn4")

oDlg1      := MSDialog():New( 092,232,225,748,"INTEGRAÇÃO PROTHEUS VS ARDUINO",,,.F.,,,,,,.T.,,,.T. )
oBtn1      := TButton():New( 012,032,"LED A",oDlg1,{|| SendMSG('A')},037,012,,,,.T.,,"",,,,.F. )
oBtn2      := TButton():New( 012,080,"LED B",oDlg1,{|| SendMSG('B')},037,012,,,,.T.,,"",,,,.F. )
oBtn3      := TButton():New( 012,128,"LED C",oDlg1,{|| SendMSG('C')},037,012,,,,.T.,,"",,,,.F. )
oBtn4      := TButton():New( 012,176,"LED E",oDlg1,{|| SendMSG('D')},037,012,,,,.T.,,"",,,,.F. )

oDlg1:Activate(,,,.T.)


Return




Static Function SendMSG(cMSG)


Local cCfg := "COM3:9600,n,8,1"
Local nH := 0


lRet       := msOpenPort(nH,cCfg)     

if(!lRet)
    Alert("Falha ao conectar com a porta serial")
    Return
EndIf 

msWrite(nH,cMSG)

Return



A tela no Protheus deverá ficar assim:



O esquema da placa ficaria assim:



Basicamente o Protheus irá se conectar com a placa Arduino usando a porta USB emulada como porta COM, por isso, o código advpl usa  msOpenPort.

Por último, o resultado:



domingo, 17 de setembro de 2017

Uma grande dor de cabeça para o desenvolvedor Advpl Protheus é a confecção de relatórios gráficos. Por não oferecer um bom ambiente de desenvolvimento, os relatórios à base do objeto TMSPrinter são construídos manualmente via código, gerando em muitos casos retrabalho, além de do fato do próprio componente em questão estar descontinuado pela TOTVS.
Uma opção para cobrir este "vazio" seria usar outras ferramentas disponíveis no mercado como o Crystal Reports ou Ireport. A primeira opção tem um custo um pouco elevado além da possibilidade de surgir problemas na integração e a exigência de cada micro ter uma ODBC criada para atender a conexão. Já o Ireport também pode apresentar problemas de integração e exige que cada micro tenha o Java instalado.

Pesando em uma solução, criei uma arquitetura simples que oferece relatórios gráficos, com ferramenta de desenvolvimento rápido além de fácil integração com o Protheus, sem a necessidade de instalar dll, executáveis ou criação de ODBC. Basta apenas compilar um fonte e pronto, os relatórios já ficam disponíveis.

A arquitetura basicamente é a seguinte:


O ambiente de desenvolvimento é bem parecida com as que temos hoje no mercado, abaixo um projeto aberto nele:


E no Protheus um exemplo de um relatório feito pela ferramenta citada:




O relatório pode conter também gráficos, imagens etc. 

Para mais informações, como valores , treinamento e implantações, basta entrar em contato pelo Skype luis.lacombe ou por e-mail : erpconsult@erpconsultbrasil.com.br







quarta-feira, 17 de junho de 2015


Olá desenvolvedores.... Publiquei um vídeo bem rápido ensinando o básico de como consumir um webservice em .net (C#) usando o Protheus. Espero que seja útil. 




domingo, 13 de julho de 2014

Pacote para desenvolvimento de integração Protheus e balança via porta serial

Estou disponibilizando um pacote para desenvolvedores advpl com o objetivo de desenvolver rdmakes de integração com balanças via comunicação serial. No vídeo http://youtu.be/28NJP7xbMpY tem uma pequena demonstração e no link  http://www.4shared.com/rar/P-ejAam9ba/Pacote_Balanca.html? disponibilizo o pacote que vem com emulador de porta COM, simulador de balança além de um rdmake de exemplo.

domingo, 9 de março de 2014

Obter endereço a partir de um cep com ADVPL

Abaixo abaixo estou disponibilizando um pequeno código que recebe um cep como parâmetro e acessa um web service, obtendo como retorno o endereço correspondente. Espero que seja útil.

#INCLUDE 'PROTHEUS.CH'
#INCLUDE 'RWMAKE.CH'
#INCLUDE 'FONT.CH'
#INCLUDE 'COLORS.CH'


User Function VerCep()

Private cBairro    := Space(100)
Private cCidade    := Space(100)
Private cLog       := Space(100)
Private cTipLog    := Space(20)
Private cUF        := Space(20)      
Private cCep       := Space(12)


SetPrvt("oDlg1","oSay1","oSay2","oSay3","oSay4","oSay5","oSay6","oGet1","oSBtn1")


oDlg1      := MSDialog():New( 088,232,316,624,"oDlg1",,,.F.,,,,,,.T.,,,.T. )
oSay1      := TSay():New( 012,012,{||"Digite o CEP:"},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,036,008)
oSay2      := TSay():New( 044,016,,oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,032,008)
oSay3      := TSay():New( 044,056,,oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,128,012)
oSay4      := TSay():New( 064,016,,oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,168,012)
oSay5      := TSay():New( 084,012,,oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,032,012)
oSay6      := TSay():New( 084,052,,oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,132,012)
oGet1      := TGet():New( 012,052,{|u| If(PCount()>0,cCep:=u,cCep)},oDlg1,060,008,'',,CLR_BLACK,CLR_WHITE,,,,.T.,"",,,.F.,.F.,,.F.,.F.,"","cCep",,)
oSBtn1     := SButton():New( 012,160,1,,oDlg1,,"", )    

oSBtn1:bLClicked := {|| LoadCEP() }

oDlg1:Activate(,,,.T.)

Return 

Static Function LoadCEP()
Local cError   := ""
Local cWarning := ""
Local aRetorno := {} 
Local cRETORNO  //obtem o xml

cRETORNO := HttpGet( 'http://republicavirtual.com.br/web_cep.php?cep='+cCep+'&formato=xml' )

if cRETORNO == nil
   MsgStop( Alert( "Servidor de CEP indisponível." ) )
else
   oScript := XmlParser( cRETORNO, "_", @cError, @cWarning )
   if oScript <> nil
      if XmlChildEx( oSCRIPT, "_WEBSERVICECEP" ) <> nil      
         if Val(oSCRIPT:_WEBSERVICECEP:_RESULTADO:TEXT) > 0
            cUF     := oSCRIPT:_WEBSERVICECEP:_UF:TEXT 
            cCidade := oSCRIPT:_WEBSERVICECEP:_CIDADE:TEXT 
            cBairro := oSCRIPT:_WEBSERVICECEP:_BAIRRO:TEXT 
            cTipLog := oSCRIPT:_WEBSERVICECEP:_TIPO_LOGRADOURO:TEXT 
            cLog    := oSCRIPT:_WEBSERVICECEP:_LOGRADOURO:TEXT 
         endif   
      endif
   endif
endif 

oSay2      := TSay():New( 044,016,{||"UF: " + cUF},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,032,008)
oSay3      := TSay():New( 044,056,{||"Cidade: " + cCidade},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,128,012)
oSay4      := TSay():New( 064,016,{||"Bairro: " + cBairro},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,168,012)
oSay5      := TSay():New( 084,012,{|| cTipLog},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,032,012)
oSay6      := TSay():New( 084,052,{|| cLog},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,132,012)      

Return


----------------------------------------------------------------------------------------------------
A aparência do programa é simples, agora é só incrementar do jeito que você quiser.





quarta-feira, 6 de novembro de 2013

Integração Protheus x Balança rodoviária Lider

Abordando mais uma vez integrações entre protheus e balanças, hoje irei demonstrar uma rotina em advpl que lê o peso da balança rodoviária Lider pela porta serial. Para testar nossa aplicação, podemos baixar o emulador da balança Líder gratuitamente no site  http://www.liderbalancas.com.br/2012/manuais-balancas.html no primeiro link de download.

Para que eu consiga acessar a mesma porta COM com dois programas diferentes (emulador da balança e a rotina advpl), eu não uso a porta física e sim um emulador de porta serial VSPE,o qual pode ser baixado pelo site  http://www.baixaki.com.br/download/free-virtual-serial-ports-emulator.htm. Com o VSPE eu crio uma porta virtual COM1 e é com ela que iremos trabalhar.

A rotina em advpl pode ser baixada no link  http://www.4shared.com/file/EcFWKLrC/BalRodov.html?Compile o fonte e em seguida iremos seguir os passos abaixo:

1) Com o VSPE crie a porta serial virtual COM1
2)Acione o emulador da balança Líder ( arquivo Emulador.exe)
3)Deixe o emulador configurado conforme imagem abaixo:







4) Abra a IDE do protheus e com o fonte BALRODOV.PRW compilado,  execute a rotina.



5) No emulador da balança, clique em modo contínuo



















6)Se tudo estiver ok, teremos a captura do peso pelo protheus conforme print abaixo:























7) Abaixo a rotina em advpl :




#INCLUDE 'RWMAKE.CH'

/*ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
±±ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ¿±±
±±³Programa  ³          ³ Autor ³ LUIS LACOMBE          ³ Data ³          ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄ´±±
±±³Locacao   ³                  ³Contato ³83 8819-6539                    ³±±
±±³   ³                         ³        ³gustavo.lacombe@gmail.com       ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Descricao ³  Le peso da balanca rodoviaria Lider modelo LD 1001        ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Parametros³                                                            ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Retorno   ³                                                            ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Aplicacao ³                                                            ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Uso       ³                                                            ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÁÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³Analista Resp.³  Data  ³                                               ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´±±
±±³              ³  /  /  ³                                               ³±±
±±³              ³  /  /  ³                                               ³±±
±±ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ±±
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß*/

User Function BalRodov

Private cPesoAt      := Space(30)
Private cPesStr    := Space(30)    
Private cCfg     :="COM1:4800,n,8,1"
Private nH       := 0


SetPrvt("oDlg1","oSay1","oSay2","oPesStr","oPeso","oSBtn1")

oDlg1      := MSDialog():New( 091,232,304,578,"Balança rodoviária",,,.F.,,,,,,.T.,,,.T. )
oSay1      := TSay():New( 028,016,{||"STRING DA COM1"},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,060,008)
oSay2      := TSay():New( 045,017,{||"PESO TRATADO"},oDlg1,,,.F.,.F.,.F.,.T.,CLR_BLACK,CLR_WHITE,059,008)
oPesStr    := TGet():New( 028,088,{|u| If(PCount()>0,cPesStr:=u,cPesStr)},oDlg1,060,008,'',,CLR_BLACK,CLR_WHITE,,,,.T.,"",,,.F.,.F.,,.F.,.F.,"","cPesStr",,)
oPeso      := TGet():New( 048,088,{|u| If(PCount()>0,cPesoAt:=u,cPesoAt)},oDlg1,060,008,'',,CLR_BLACK,CLR_WHITE,,,,.T.,"",,,.F.,.F.,,.F.,.F.,"","cPesoAt",,)
oSBtn1     := SButton():New( 072,120,1,{|| LerPeso()},oDlg1,,"", )

oDlg1:Activate(,,,.T.)

Return




/*/
ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
±±ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ¿±±
±±³ Programa ³ LerPeso  ³ Autor ³ LUIS LACOMBE          ³ Data ³ 18/04/13 ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄ´±±
±±³Descri‡…o ³Faz a requisicao de peso para a balanca e le o retorno.     ³±±
±±³          ³Para funcionar, eh importante verificar o protocolo de      ³±±
±±³          ³comunicacao da balanca. No caso da TOLEDO,ela tem que estar ³±±
±±³          ³usando o protocolo que responda ao sinal ENQ, por exemplo   ³±±
±±³          ³o protocolo P05 ou P05A. Importante lembrar que a funcao    ³±±
±±³          ³nao trata a estabilizacao de peso. Se quiser receber o peso ³±±
±±³          ³somente quando ele estabilizar,use o protocolo adequado como³±±
±±³          ³P05 da TOLEDO.                                              ³±±
±±ÀÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ±±
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
/*/
Static Function LerPeso()

Local cPeso := 0
Local cBuffer

cCfg      :="COM1:4800,n,8,1"

lRet       := msOpenPort(nH,cCfg)
if(!lRet)
Alert("Falha ao conectar com a porta serial")
Return
EndIf

//msWrite(nH,Chr(5))
//Sleep(200)
For ncont := 1 To 50
msRead(nH,@cBuffer)
if(!Empty(cBuffer))
  // ALERT(cBuffer)
   cPesStr := cBuffer
cPeso := IsNumber(cBuffer)
Exit
EndIf
Next
msClosePort(nH)

cPesoAt  := cPeso

// PRA TESTAR O PROGRAMA SEM BALANCA
//nPeso := Val(cSimPes)

Return



/*/
ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
±±ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ¿±±
±±³ Programa ³ IsNumber ³ Autor ³ LUIS LACOMBE          ³ Data ³ 18/04/13 ³±±
±±ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄ´±±
±±³Descri‡…o ³Separa os caracteres numericos da string recebida da balanca³±±
±±ÀÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ±±
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
/*/
Static Function IsNumber(cNum)

Local nPosPar  
Local cPesB     := ""
Local cNumeros  := "0123456789."
Local cNewNum   := ""
Local nPes      := 0


//bloco que separa o numero da string enviada pela balanca
For nCont := 1 To Len(cNum)
    if(SubStr(cNum,nCont,1)=="E")    
        Exit
    EndIf
   
    if(SubStr(cNum,nCont,1)=="I") // peso instavel
        Return "-1"      
    EndIf
   
    if(SubStr(cNum,nCont,1)$cNumeros)
       cNewNum += SubStr(cNum,nCont,1)
    EndIf
Next nCont

cPesB  :=  cNewNum

Return cPesB


domingo, 1 de setembro de 2013

Integração Protheus X Balança via comunicação serial sem DLL

 Neste artigo irei mostrar como podemos fazer uma rotina em advpl que irá requisitar o peso a uma balança Filizola via porta serial. Essa requisição funciona também para balanças TOLEDO, porém o layout de retorno é um pouco diferente. A vantagem desse método é não depender de DLL e assim não ficar preso a uma marca específica. Antes de tudo é preciso que a balança esteja com o protocolo adequado para funcionar com requisição serial. Em muitos modelos da TOLEDO, o protocolo é o P05, já algumas balanças FILIZOLA já vem preparadas para responder a esse tipo de requisição. 

O esquema abaixo resume o processo:









Primeiramente iremos fazer a comunicação com a porta serial. Para isso usamos o seguinte código Advpl:

Local cCfg :=”COM1:4800,n,8,1″
lRet := msOpenPort(nH,cCfg)
if(!lRet)

    Alert(“Falha ao conectar com a porta serial”)
     Return 

EndIf 

 O próximo passo será enviar um comando 5 HEXADECIMAL (ENQ) para a porta aonde em que a balança está conectada. Eu tinha até aberto um chamado na TOTVS perguntando como isso poderia ser feito e responderam que não era possível, enfim , eu não acredite e pesquisei alguma forma de fazer isso. Até que consegui usando um comando super simples que é : 
 msWrite(nH,Chr(5))

 Ou seja, eu escrevo na porta COM o Chr(5) e se tudo estiver certo a balança irá devolver o peso. Resumidamente, a rotina básica ficaria assim:
lRet := msOpenPort(nH,cCfg)
if(!lRet)
    Alert(“Falha ao conectar com a porta serial”)
    Return
EndIf 

msWrite(nH,Chr(5))
Sleep(200)

For ncont := 1 To 20
      msRead(nH,@cBuffer)
      if(!Empty(cBuffer))
                 cPeso :=IsNumber(cBuffer) // IsNumber função que criei para tirar os caracteres especiais                            cBuffer := “” 
                 Exit 
      EndIf 
Next 
msClosePort(nH)

Para que essa comunicação dê certo, é preciso atentar para alguns detalhes:
 1) Tentei várias combinações de velocidades para a porta COM1 do micro e a que deu mais certo foi Bits         por segundo : 4800, Bits de dados: 7,Paridade: Even, Bits de parada: 2 e controle de fluxo: nenhum.

 2) Com relação a configuração da velocidade da balança, a melhor que eu achei foi A mesma configuração      da COM1 dita no primeiro item mudando apenas Bits de dados para 8.



 Espero que este artigo tenha sido útil . Até a próxima.

sexta-feira, 23 de dezembro de 2011

Importar produtos de outros sistemas para o Protheus

Pessoal, desenvolvi um programa em C# que faz a importação de produtos de qualquer base de dados para o Protheus. Fica aí mais um exemplo de integração entre Protheus e C#.

Este vídeo fala do passo a passo dos procedimentos iniciais





Este outro vídeo mostra o programa funcionando



Aqui o link para baixar o programa
www.4shared.com/rar/qDP_ytZM/Imp_SB1.html?

quarta-feira, 16 de novembro de 2011

Navegador Web feito em Advpl

Abaixo estou disponibilizando um código que monta um navegador em advpl. Ele guarda as páginas visitadas e permite a navegação entre elas como acontece em um navegador web.

Obs: Para funcionar, é preciso configurar o smartcliente.ini e colocar logo abaixo da marcação [config] a opção:
BrowserEnabled=1




#include "protheus.ch"


User Function Navegador()

Private aPages := {} // array que guarda os endereços visitados
Private nPgVist := -1 // controle a posicao do array aPages

Private aSize := MsAdvSize() // pega o tamanho da tela
Private oDlg1, oTIBrw
Private cNavegado := Space(80) // usado no objeto get para guardar os endereços web
Private lcont := .T.

DEFINE MSDIALOG oDlg1 TITLE "Navegador" From aSize[7],0 to aSize[6],aSize[5] of oMainWnd PIXEL

cNavegado := "http://www.google.com" // pagina inicial
oNav:= TGet():New(10,10,{|u| if(PCount()>0,cNavegado:=u,cNavegado)}, oDlg1,340,5,,,,,,,,.T.,,,,,,,,,,)

@ 010, 350 Button oBtnIr PROMPT "Ir" Size 40,10 Action(Processa({||Navegar()},"Abrindo","Aguarde...")) Of oDlg1 Pixel
@ 010, 390 Button oBtnImp PROMPT "Imprimir" Size 40,10 Action oTIBrw:Print() Of oDlg1 Pixel



@ 010, 430 Button oBtnAnte PROMPT "Anterior" Size 40,10 Action (Retorna()) Of oDlg1 Pixel
@ 010, 470 Button oBtnDep PROMPT "Avançar" Size 40,10 Action(Avanca()) Of oDlg1 Pixel
@ 010, 510 Button oBtnSair PROMPT "Sair" Size 40,10 Action(Sair()) Of oDlg1 Pixel



oTIBrw:= TIBrowser():New( 025,010,aSize[5]-640, 270, "http://www.google.com", oDlg1 )

aaDD(aPages,"http://www.google.com")

oNav:bLostFocus := { || Valido()}


Activate MsDialog oDlg1 Centered

Return


Static Function Navegar()

Ir()

Return


Static Function Ir()

oTIBrw:Navigate(AllTrim(cNavegado),oDlg1)
aaDD(aPages,AllTrim(cNavegado))
nPgVist := Len(aPages)

Return



Static Function Avanca() // proxima proxima pagina que jah foi visitada

if(Len(aPages) > nPgVist .and. Len(aPages) > 1 )
nPgVist++
oTIBrw:Navigate(aPages[nPgVist],oDlg1)
cNavegado := aPages[nPgVist]
oNav:Refresh()
EndIf

Return


Static Function Retorna() // pagina anterior que foi visitada
if(nPgVist>1)
nPgVist--
oTIBrw:Navigate(aPages[nPgVist],oDlg1)
cNavegado := aPages[nPgVist]
oNav:Refresh()
EndIf

Return



Static Function Sair() // fecha a tela
oDlg1:End()
Return



Abaixo um print da tela:


quarta-feira, 5 de outubro de 2011

Relatórios Mensais

Algumas vezes eu preciso gerar relatórios que mostrem dados entre determinados meses. Abaixo, um trecho desse tipo de relatório.


Basicamente, o usuário informa o mês e ano inicial, mês e ano final e a partir daí eu gero um array contendo o intervalo. Ele tem a estrutura conforme figura abaixo:


Posso então usar os elementos deste array como parâmetros em consultas que gerem tabelas temporárias além de imprimi-los no relatório conforme a primeira figura.
Abaixo, as funções que geram o array.


Agora a função auxiliar da função acima que retorna o nome do mês:

quarta-feira, 10 de agosto de 2011

Integração do Protheus com C# e .Net


Hoje irei mostrar um outro exemplo de integração do Protheus com DotNet usando a linguagem C#. Neste exemplo irei solicitar ao protheus o cálculo do valor de parcelas (simulação de parcelas), ou seja,irei fazer a conexão da minha aplicação em DotNet com o servidor de aplicações, passarei alguns parâmetros como valor total, código da condição de pagamento e irei obter um array como retorno informando a data de vencimento e valor da parcela. Pra começar é necessário registrar a ocx apconnxcontrol.ocx e fazer referência da mesma no Visual Studio, para isso crie um novo projeto do tipo Console e siga os passos mostrados da publicação anterior "Integração do Protheus com C# ". Feito isso, minimize o Visual Studio, crie e compile o seguinte código fonte no Protheus.


No fonte eu expliquei que poderia referenciar diretamente a função do Protheus que realiza as simulações, mas tive dificuldade em passar como parâmetro o tipo data, então pra não ficar defendendo teoria, criei a user function que faz o tratamento da data que é passada pelo Visual Studio como string.

Voltando ao Visual Studio, criei uma classe que realiza a conexão com o Protheus e também um método que aciona minha user function e obtém o resultado da simulaçao de parcelas. Observe o código da classe e seus comentários.



E na classe principal irei criar o seguinte código:


Para ver o programa funcionando, veja o vídeo abaixo:
obs: Veja em tela cheia para melhor visualização.











segunda-feira, 8 de agosto de 2011

integração do Protheus com C#


Nessa postagem darei um exemplo bem simples de como integrar o Protheus com Csharp. Primeiramente temos que registrar no windows um arquivo ocx que está dentro do smartclient chamado apconnxcontrol.ocx . Para registrar é simples, eu copiei o arquivo para a pasta System32 do windows, logo depois executei o cmd.exe e fiz o seguinte comando:
regsvr32 apconnxcontrol.ocx . Lembrando que no Windows 7 você tem que executar o cmd.exe como administrador, caso contrário não dará certo.









Concluída essa etapa, é hora de abrir o Visual Studio.
No exemplo a seguir eu usei o VS 2010 e criei um novo projeto do tipo Console. Faça o mesmo e com o Program.cs aberto clique em adicionar uma nova referencia conforme figura abaixo:


Usando a guia Browse vá até a pasta System32 do Windows e selecione o arquivo apconnxcontrol.ocx:


Nessa etapa já temos o "link" com nossa ocx do protheus. Agora é só por a mão na massa e começar a brincar com as funções. No exemplo abaixo criei uma User Function no protheus que retorna um array de string. Após compilado, fui no Visual Studio e feito as devidas referências eu fiz com que o código em C# executasse a minha User Function do protheus e exibisse o retorno dela no Console.

//user function compilada no protheus
#INCLUDE "rwmake.ch"

User Function RetTest()

Local aTeste := {}

aaDD(aTeste,"teste1")
aaDD(aTeste,"teste2")
aaDD(aTeste,"teste3")

Return aTeste

Código no C#, observe as referências :






Se tudo der certo teremos o resultado abaixo:



Tem uma documentação de RPC nos fóruns de advpl, lá tem mais detalhes. Espero ter colaborado com algum conhecimento e lembrando que podemos usar a ocx em outras linguagens que tem suporte a esse tipo de arquivo. Até a próxima.










quarta-feira, 13 de abril de 2011

Conectar o Protheus a outra Base de Dados 2

Hoje irei detalhar melhor e passo a passo como podemos fazer uma integração entre o cadastro de clientes de um outro sistema e o sistema Protheus. A idéia é a seguinte:
Ter um JOB que perceba uma inclusão, alteração ou exclusão de um cliente no outro sistema e reflita isso para o Protheus. Nosso primeiro obstáculo é o banco de dados, pois nessa demonstração o sistema Protheus funciona com SQL Server e o sistema que será integrado usa o PostGress. Apesar disso, podemos conectar o Protheus ao banco do outro sistema e extrair as informações do cliente e tratá-las para inserir no cadastro. Vamos então realizar as configurações para que o Protheus tenha acesso a base de dados PostGre.

1)Baixe e instale o Drive ODBC no site http://www.postgresql.org/ftp/odbc/versions/msi/
2) Após instalar, crie a conexão ODBC no mesmo servidor aonde está configurada a ODBC do Protheus para o BD PostGre e teste a conexão.

3)Com a conexão OK é hora de criar o TOPConnect para a ODBC criada.

4)Valide a conexão.

alt=""id="BLOGGER_PHOTO_ID_5595066254285455986" />
















5) Para testar, podemos criar um pequeno Rdmake que irá na tabela do Postgre e trazer o nome do primeiro cliente cadastrado. Para visualizar melhor,abra a figura em uma nova guia.





Na próxima publicação eu irei mostrar como construir uma arquitetura de comunicação entre o Protheus e PostGre e assim deixar pronta a integração de clientes.

segunda-feira, 11 de abril de 2011

DbTree recursiva 2


Na última postagem falei sobre a DbTree baseada em uma única tabela mas que tem infinitas hierarquias. Hoje irei postar a estrutura da tabela e o código principal para poder gerar a árvore.
Primeiramente temos a estrutura da tabela, a qual chamei de ZRA. Eu a fiz para funcionar no Protheus mas ela pode ser usada para qualquer linguagem:

ZRA_COD -> Caracter tamanho 6. Irá guarda o ID único do registro.(Tem que ser auto-incremento. No caso do Protheus eu uso o GetSXEnum("ZRA","ZRA_COD") )

ZRA_DESCRI -> Caracter tamnho 20. Terá a descrição do registro.

ZRA_PAI -> Caracter tamanho 6. Irá guarda o ID único do nó pai. É extremamente importante que este campo tenha as mesmas características do campo ZRA_COD.

ZRA_ATIVO -> Caracter tamanho 1. Criei esse campo como um tipo de "flag" que terá a letra "S" se o nó estiver ativo e "N" caso não. Possibilita desativar um nó sem ter que exclui-lo.

ZRA_BMP1 -> Caracter de tamanho 10. Guarda o nome do ícone que o nó terá.

ZRA_BMP2 -> Caracter de tamanho 10. Guarda o nome do ícone que o nó terá quando estiver aberto, ou seja, exibindo os nós filhos.


ZRA_NIVEL -> Numérico. No caso do Protheus, esse campo será preenchido com 1 caso seja um nó raiz ou 2 caso seja um nó filho de outro nó.

A figura tenta ilustrar genericamente o algoritmo da função principal e abaixo o código em advpl.

Static Function LoadTree(lAt)
Local cATivo := iif(lAt,"S / N","S")
Local aGetArea := GetArea()



if(Empty(ZRA->ZRA_PAI))
Return
EndIf
oTree1:BeginUpdate()
if(AllTrim(ZRA->ZRA_PAI) == "000000" .and. Alltrim(ZRA->ZRA_ATIVO) $ cAtivo )

if(oTree1:Total()>0 .and. nContNo > 0)
oTree1:EndTree()
EndIf

if(! oTree1:TreeSeek(ZRA->ZRA_COD))
oTree1:AddTree(ZRA->ZRA_DESCRI + iif(Alltrim(ZRA->ZRA_ATIVO)=="N"," [DESATIVADO]","")+Space(24),.T.,"FOLDER5","FOLDER6",,,ZRA->ZRA_COD)
EndIf

Elseif(Alltrim(ZRA->ZRA_ATIVO) $ cAtivo)
if(! oTree1:TreeSeek(ZRA->ZRA_COD))
if oTree1:TreeSeek(ZRA->ZRA_PAI)
oTree1:AddItem(ZRA->ZRA_DESCRI + iif(Alltrim(ZRA->ZRA_ATIVO)=="N"," [DESATIVADO]","")+Space(24),ZRA->ZRA_COD,iif(Alltrim(ZRA->ZRA_ATIVO)=="N","F5_VERM","GEOTRECHO"),,,,2)
EndIf
EndIf

EndIf


nContNo++
ZRA->(DbSkip())
if(ZRA->(EOF()))
nContNo := 0
oTree1:EndTree()
RestArea(aGetArea)
oTree1:EndUpdate()
Return
EndIf
LoadTree(lShowDe)

Return

quinta-feira, 7 de abril de 2011

DbTree recursiva



O objeto Dbtree tem usos bem interessantes. Um dos que eu acho mais legal é a construção de uma estrutura DbTree baseada em uma única tabela e que pode conter infinitas hierarquias. O melhor é que a lógica pode ser usada não só para o componente usando na programação Advpl mas em outras linguagens. Já criei a mesma rotina em Visual Basic 6.0 como também no Access. A cima, um print da tela e em seguida outro print com as funções dos objetos contidos nela. Também coloquei um vídeo mostrando a rotina em funcionamento.
Na próxima publicação irei mostrar a estrutura da tabela e o algorítimo que realiza todas as funções.



segunda-feira, 14 de março de 2011

Erros na Rotina Automática

Alguns erros que ocorrem nas rotinas automáticas podem ser exibidos através do comando MostraErro(). Porém alguns erros não são detectados e a rotina roda como se estivesse tudo certo, ou seja, como se a gravação tivesse ocorrido com sucesso. Mas quando vamos procurar o registro, ele não se encontra. Passei várias vezes por isso, principalmente em cadastro que tem uma série de validações como por exemplo o cadastro de clientes. O primeiro problema foi quando eu estava fazendo a integração do Protheus com outro sistema e o CPF vinha em branco ou errado. O controle de erro da rotina automática não era acionado e eu não sabia o motivo pelo qual o cliente não estava sendo inserido até que resolvi olhar o CPF e pronto... primeiro problema resolvido. Verifiquei se o sistema mandava todos os campos obrigatórios para o Protheus e criei um log que avisava carro algum estivesse em branco. Para isso usei a função X3Obrigat(cCampo).
Só que não parou por aí pois alguns clientes continuavam a chegar e não eram gravados. Investiguei e descobri que o número do IBGE estava vindo '0000' em muitos.. ou seja.... o sistema que mandava as informações deixava muito a desejar em algumas validações. Mais uma vez isso foi corrigido. Funcionou por um bom tempo até que em alguns clientes de pessoa Jurídica o erro de não gravar continuava. De novo, investigando, descobri que o sistema mandava de forma incorreta a inscrição estadual, ou seja, não vazia a validação antes de mandar para o Protheus e em alguns casos a inscrição vinha nula ou com números digitados de forma aleatória. Depois de corrigido, até o momento a integração de clientes funciona muito bem.

sexta-feira, 11 de março de 2011

Conectar o Protheus a outra Base de Dados






Uma integração entre o Protheus e outros sistemas pode ser feita de várias formas, xml, arquivo txt etc. Eu resolvi fazer algo mais direto, ou seja, uma aplicação no Protheus(BD Sql Server) que enxerga o banco de dados do outro sistema, que usa o BD Postgres, e monta uma tabela temporária tratando esses dados e logo depois inserindo-os no Protheus através de rotinas automáticas. Apesar do banco do outro sistema não ter nada haver com o banco de dados do Protheus, podemos conectar a ele da seguinte forma:
1- Crie uma ODBC no servidor do BD do Protheus para o outro banco. No caso do Postgres, eu tive que baixar um drive para conexão ODBC específica para ele. Observe configuração de porta, senha e tal. No final, verifique se a conexão foi bem sucedida. Caso tenha sido, deveremos executar o próximo passo.
2- Valide a conexão ODBC da mesma forma que se faz com uma ODBC criada para o Protheus, ou seja, vá ao TOTVSDBMonitor e na aba configurações, escolha a aba Postgres ou a do BD do outro sistema que você quer se conectar. Crie um ambiente, coloque a senha correta e no assistente é só fazer a validação da conexão.
3- Com a validação ok, é hora de enxergar o outro banco. Vamos então criar uma rotina básica de comunicação com nosso BD da outra aplicação.

-----------------------------------------------------------------------------------------------
User Function JOBATAE1()
Private cBDProd := "MSSQL/Interface" // comunicacao com BD Protheus. Usado na funcao //TCLINK.
Private cBDAtae := "POSTGRES/atae" // comunicacao com BD sistema ATAE. Usado na //funcao.
Private cIPBD := "192.168.1.244" // IP do servidor de aplicacoes

Private _nTcConn // conectar com ATAE
Private _nTcCon2 // conectar com Protheus


TCCONTYPE("TCPIP") // tipo de conexao que sera usada

_nTcConn := TCLink(cBDAtae,cIPBD) // conexao com ATAE(sistema que usa o BD PostGres)
_nTcCon2 := TCLink(cBDProd,cIPBD) // conexao com Protheus

-----------------------------------------------------------------------------------------------

Neste primeiro trecho observe que criei duas variáves :
cBDProd
cBDAtae

Elas guardam a string de conexao com os respectivos BD. Logo depois temos a variável
cIPBD que contém o IP do servidor de aplicações do Protheus. Essas variáveis serão usadas na função TCLink pois ela tem a seguinte sintaxe:

TCLink(cConectString,cServer)

cConectString: String composta conforme a regra:

Para TOPConnect NT : Nome do Banco de Dados / Nome do Ambiente

Para TOPConnect/400: Nome do Ambiente

cServer: Endereço IP do servidor TOPConnect.

As variáveis _nTcConn e _nTcCon2 recebem o resultado da conexão, ou seja, o TCLink retorna um número negativo caso a conexão não tenho tido êxito. Neste caso existe a possibilidade de algum dos servidores de BD estarem offline ou a string de conexão está incorreta.

Continuando nossa aplicação temos:

-----------------------------------------------------------------------------------------------

If ( _nTcConn <>
//mostra alerta de erro com a conexão BD postgres ou BD Protheus

Alert("*** Erro de conexão ***")
Else
Alert("*** Conexão OK ***")
TCSETCONN(_nTcConn) // setando conexao com Postgres
LerTab() // lendo uma tabela Postgres
InsProt() // pegando os dados do Postgres e inserindo no Protheus
EndIf

Return

Static Function LerTab()
Local cQuery := " SELECT * FROM CLIENTE "
dbUseArea(.T., "TOPCONN", TCGenQry(,,cQuery), "TRS", .F., .T.)
TRS->(DbGoTop())
Alert(TRS->NOME)
Return



Static Function InsProt()
TCSETCONN(_nTcCon2) // conectando com o Protheus
RPCSetType(3)
RPCSetEnv("01","01","user","senhaUser") // logando no Protheus
// faca um loop para carregar os dados da tabela TRS para seu array
// e execute sua rotina automática
TRS->(DbCloseArea())
Return
-----------------------------------------------------------------------------------------------
Na segunda parte da rotina podemos ver que após verificar se as conexões estão Ok, usamos o comando TCSETCONN(_nTcConn) para setar a conexão da rotina para o BD postgres. A partir daí é tudo quase igual a qualquer rotina para criar uma tabela temporária baseada em informações do Protheus. Observe apenas a sintaxe usada na variável cQuery que terá que obedecer as regras do banco. Depois de recuperar as informações da tabela CLIENTE do postgres, é só usar o comando TCSETCONN(_nTcCon2) para se comunicar com o Protheus e a parti daí usar os comandos RPCSetType e RPCSetEnv para logar na empresa e filial. Depois disso, execute sua rotina automática e pronto, sua integração foi feita.



sexta-feira, 4 de março de 2011

Rotinas Automáticas

Uma ferramenta importante para a integração são as rotinas automáticas. No projeto em que eu estou, toda a integração é baseada em rotinas automáticas, salvo algumas exceções em que o Protheus não disponibiliza tais rotinas como uma para gerar uma nota fiscal de saída pelo faturamento. Tive algumas dores de cabeça com algumas rotinas automáticas pois elas são bem rígidas e não deixam passar em branco alguns erros. Inclusive, alguns desses erros são bem difíceis de identificar . Irei listar abaixo alguns deles e suas soluções:


eu estava gerando Notas Fiscais de entrada através da rotina MSExecAuto({|x,y,z| mata103(x,y,z)},aCabec,aItens,3)

Conferi os dados, tudo certinho. Só que na hora de gerar a nota, a função MostraERRO() gerava o seguinte aviso:

HELP: REGNOIS
Não existe registro relacionado a este
código.

Tabela SF1 18/02/11 16:48:56
- cTipo :=N
- cFormul :=N
- cNFiscal :=102454
- cSerie :=01
- dDEmissao :=18/02/11
- cA100For :=000005
- cLoja :=01 < -- Invalido - cEspecie :=NFE - cUfOrig :=PB

Só que a loja era realmente do fornecedor e todos os outros dados estavam corretos. A não ser por um detalhe. O código do fornecedor está com tamanho igual a 6, porém o campo correspondente do Protheus estava com tamanho 14. Nada muito haver com o erro apresentado pelo Protheus, mas que causou bastante dor de cabeça. Então na linha:

aadd(aCabec,{"F1_FORNECE","000005"})

Eu fiz assim:
aadd(aCabec,{"F1_FORNECE","000005 "})
E a rotina funcionou normalmente.
Resumo da história, é altamente recomendável usar códigos com o mesmo tamanho do campo.