Fórum Automação Comercial - TEF Discado - Fontes abertos #256685
29/10/2004
0
Há algum tempo iniciei a integração de meus aplicativos comerciais com TEF, mas sempre surge um projeto mais interessante ou mais emergente e até hoje não consegui finalizar.
Acredito que muito dos colegas também podem estar passando por algo semelhante. Porém, agora se tornou vital que eu consiga terminar isto no menor prazo possível.
Visando tirar proveito de nossa capacidade produtiva aqui no fórum, gostaria de disponibilizar o que eu já tenho pronto (in natura), pois não posso garantir que esteja totalmente correto, pois como já disse, ainda não homologuei meu AC e gostaria que os colegas que já possuem rotinas prontas e que possam estar colaborando comigo e com os demais à postarem aqui nesta mensagem e criarmos um banco de conhecimento detalhado sobre TEF com Delphi.
Sem qualquer garantia de exatidão, segue:
unit TEF_Discado; interface Uses Classes, SysUtils, IniFiles, Windows, Graphics, Forms, StdCtrls; procedure AbreTransacaoTEF; procedure FechaTransacaoTEF; procedure AtualizarINI(Mensagem: String; var Transacao: Integer; Incrementar: Boolean); procedure LerINI(var Mensagem: String; var Transacao: Integer); procedure MostraMensagem(const ACaption, APrompt: string; DuracaoEmSegundos: Integer); function TransacaoTEF: Boolean; function GetAveCharSize(Canvas: TCanvas): TPoint; function GP_LeStatus: Boolean; function GP_LeRetorno: Boolean; function GP_VendaCartao(Valor: Currency): Boolean; function GP_Ativar(CarregarTEF_DIAL: Boolean; cTefDial: String): Boolean; function GP_ConfirmaTEF: Boolean; function GP_NaoConfirmaTEF: Boolean; function GP_CancelarTEF: Boolean; implementation function GP_CancelarTEF: Boolean; var Arquivo: TStringList; ArquivoINI: TIniFile; Numero: Integer; begin Arquivo:= TStringList.Create; ArquivoINI := TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); // Atualiza INI e obtem o numero da última transacao AtualizarINI(´CNC´, Numero, False); try Arquivo.Clear; Arquivo.Add(´000-000 = CNC´); Arquivo.Add(´001-000 = ´+ArquivoINI.ReadString(´RETORNO´,´001´,´´)); Arquivo.Add(´010-000 = ´+ArquivoINI.ReadString(´RETORNO´,´010´,´´)); Arquivo.Add(´012-000 = ´+ArquivoINI.ReadString(´RETORNO´,´012´,´´)); Arquivo.Add(´022-000 = ´+ArquivoINI.ReadString(´RETORNO´,´022´,´´)); Arquivo.Add(´023-000 = ´+ArquivoINI.ReadString(´RETORNO´,´023´,´´)); Arquivo.Add(´027-000 = ´+ArquivoINI.ReadString(´RETORNO´,´027´,´´)); Arquivo.Add(´999-999 = 0´); DeleteFile(´c:\tef_dial\resp\IntPos.sts´); Arquivo.SaveToFile(´c:\tef_dial\req\IntPos.tmp´); RenameFile(´c:\tef_dial\req\IntPos.tmp´, ´c:\tef_dial\req\IntPos.001´); finally Arquivo.Free; ArquivoINI.Free; end; Result := GP_LeStatus; end; function GP_VendaCartao(Valor: Currency): Boolean; var Arquivo: TStringList; Numero: Integer; begin Arquivo:= TStringList.Create; if FileExists(´c:\tef_dial\resp\IntPos.001´) then DeleteFile(´c:\tef_dial\resp\IntPos.001´); // Inicia a transacao de cartão e obtem o numero da mesma. AtualizarINI(´CRT´, Numero, True); try Arquivo.Clear; Arquivo.Add(´000-000 = CRT´); Arquivo.Add(´001-000 = ´+IntToStr(Numero)); Arquivo.Add(´003-000 = ´+IntToStr(Trunc(Valor*100))); Arquivo.Add(´999-999 = 0´); DeleteFile(´c:\tef_dial\resp\IntPos.sts´); Arquivo.SaveToFile(´c:\tef_dial\req\IntPos.tmp´); Arquivo.SaveToFile(´c:\EasyPDV\IntPos.tmp´); RenameFile(´c:\tef_dial\req\IntPos.tmp´, ´c:\tef_dial\req\IntPos.001´); finally Arquivo.Free; end; Result := GP_LeStatus; if Result then while not FileExists(´c:\tef_dial\resp\IntPos.001´) do begin Application.ProcessMessages; Sleep(1000); end; end; function GP_ConfirmaTEF: Boolean; var Arquivo: TStringList; ArquivoINI: TIniFile; Numero: Integer; begin Arquivo:= TStringList.Create; ArquivoINI := TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); // Atualiza INI e obtem o numero da última transacao AtualizarINI(´CNF´, Numero, False); try Arquivo.Clear; Arquivo.Add(´000-000 = CNF´); Arquivo.Add(´001-000 = ´+ArquivoINI.ReadString(´RETORNO´,´001´,´´)); Arquivo.Add(´010-000 = ´+ArquivoINI.ReadString(´RETORNO´,´010´,´´)); Arquivo.Add(´012-000 = ´+ArquivoINI.ReadString(´RETORNO´,´012´,´´)); Arquivo.Add(´027-000 = ´+ArquivoINI.ReadString(´RETORNO´,´027´,´´)); Arquivo.Add(´999-999 = 0´); DeleteFile(´c:\tef_dial\resp\IntPos.sts´); Arquivo.SaveToFile(´c:\tef_dial\req\IntPos.tmp´); RenameFile(´c:\tef_dial\req\IntPos.tmp´, ´c:\tef_dial\req\IntPos.001´); finally Arquivo.Free; ArquivoINI.Free; end; Result := GP_LeStatus; end; function GP_NaoConfirmaTEF: Boolean; var Arquivo: TStringList; ArquivoINI: TIniFile; Numero: Integer; begin Arquivo:= TStringList.Create; ArquivoINI := TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); // Atualiza INI e obtem o numero da última transacao AtualizarINI(´NCN´, Numero, False); try Arquivo.Clear; Arquivo.Add(´000-000 = NCN´); Arquivo.Add(´001-000 = ´+ArquivoINI.ReadString(´RETORNO´,´001´,´´)); Arquivo.Add(´010-000 = ´+ArquivoINI.ReadString(´RETORNO´,´010´,´´)); Arquivo.Add(´012-000 = ´+ArquivoINI.ReadString(´RETORNO´,´012´,´´)); Arquivo.Add(´027-000 = ´+ArquivoINI.ReadString(´RETORNO´,´027´,´´)); Arquivo.Add(´999-999 = 0´); DeleteFile(´c:\tef_dial\resp\IntPos.sts´); Arquivo.SaveToFile(´c:\tef_dial\req\IntPos.tmp´); RenameFile(´c:\tef_dial\req\IntPos.tmp´, ´c:\tef_dial\req\IntPos.001´); finally Arquivo.Free; ArquivoINI.Free; end; Result := GP_LeStatus; end; procedure AtualizarINI(Mensagem: String; var Transacao: Integer; Incrementar: Boolean); varArquivoINI: TIniFile; begin try ArquivoINI:= TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); Transacao:= StrToInt(ArquivoINI.ReadString( ´TEF´,´NumeroTransacao´,´0´)); if Incrementar then Inc(Transacao); ArquivoINI.WriteString(´TEF´,´NumeroTransacao´,IntToStr(Transacao)); ArquivoINI.WriteString(´TEF´,´Mensagem´, Mensagem); finally ArquivoINI.Free; end; end; function GP_LeRetorno: Boolean; var Resposta: TStringList; Cupom: TStringList; Aguardar: Integer;// Tempo de espera pelo arquivo retorno. Erros: Integer; ArquivoINI: TIniFile; nX, nL: Integer; LinhaLimpa, LinhaSuja: String; begin Resposta:= TStringList.Create; Cupom:= TStringList.Create; ArquivoINI := TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); Aguardar:= 1; Erros:= 0; while not FileExists(´c:\tef_dial\resp\IntPos.001´) do begin if Aguardar > 7 then break; Sleep(1000); Inc(Aguardar); end; try Resposta.LoadFromFile(´c:\tef_dial\resp\IntPos.001´); // Carrega o cupom anterior no caso de mais de uma forma de paramento. Cupom.LoadFromFile(´C:\EasyPDV\CUPOM.TMP´); For nX := 0 to Resposta.Count-1 do begin LinhaSuja:= ´´; LinhaLimpa:= ´´; if Copy(Resposta.Strings[nX],1,3)=´001´ then begin ArquivoINI.WriteString( ´RETORNO´, ´001´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´003´ then begin ArquivoINI.WriteString( ´RETORNO´, ´003´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´009´ then begin ArquivoINI.WriteString( ´RETORNO´, ´009´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´010´ then begin ArquivoINI.WriteString( ´RETORNO´, ´010´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´011´ then begin ArquivoINI.WriteString( ´RETORNO´, ´011´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´012´ then begin ArquivoINI.WriteString( ´RETORNO´, ´012´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´022´ then begin ArquivoINI.WriteString( ´RETORNO´, ´022´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´023´ then begin ArquivoINI.WriteString( ´RETORNO´, ´023´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´027´ then begin ArquivoINI.WriteString( ´RETORNO´, ´027´, Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-10)); end else if Copy(Resposta.Strings[nX],1,3)=´029´ then begin LinhaSuja:= Copy(Resposta.Strings[nX],11,length(Resposta.Strings[nX])-11); For nL := 1 to Length(LinhaSuja) do if LinhaSuja[nL]<>34 then LinhaLimpa := LinhaLimpa + LinhaSuja[nL]; // Retirar aspas. Cupom.Add(LinhaLimpa); // Armazena o novo cupom para imprimir end; end; // Salvar em arquivo Cupom.SaveToFile(´C:\EasyPDV\CUPOM.TMP´); finally Resposta.Free; ArquivoINI.Free; Cupom.Free; end; Result := Erros=0; end; function GP_LeStatus(): Boolean; var Resposta: TStringList; Erros: Integer; Numero: Integer; Mensagem: String; Aguardar: Integer; begin LerINI(Mensagem, Numero); Erros:= 3; Resposta:= TStringList.Create; Aguardar:= 1;// Aguardar até 7 segundos while not FileExists(´c:\tef_dial\resp\IntPos.sts´) do begin if Aguardar > 7 then break; Sleep(1000); Inc(Aguardar); end; try Resposta.LoadFromFile(´c:\tef_dial\resp\IntPos.sts´); // Verificar se a transacao está consistente - Requisicao e Resposta. Erros := Erros - Integer(Resposta.Strings[0] = ´000-000 = ´+Mensagem); Erros := Erros - Integer(Resposta.Strings[1] = ´001-000 = ´+IntToSTr(Numero)); Erros := Erros - Integer(Resposta.Strings[2] = ´999-999 = 0´); finally Resposta.Free; end; Result := Erros=0; end; procedure LerINI(var Mensagem: String; var Transacao: Integer); varArquivoINI: TIniFile; begin try ArquivoINI:= TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); Transacao:= StrToInt(ArquivoINI.ReadString(´TEF´,´NumeroTransacao´,´0´)); Mensagem:= ArquivoINI.ReadString(´TEF´,´Mensagem´, ´ERR´); finally ArquivoINI.Free; end; end; procedure MostraMensagem(const ACaption, APrompt: string; DuracaoEmSegundos: Integer); var Form: TForm; Prompt: TLabel; DialogUnits: TPoint; ButtonTop, ButtonWidth, ButtonHeight: Integer; nX, Lines: Integer; begin Form := TForm.Create(Application); Lines := 0; For nX := 1 to Length(APrompt) do if APrompt[nX]=13 then Inc(Lines); with Form do try Canvas.Font := Font; DialogUnits := GetAveCharSize(Canvas); BorderStyle := bsDialog; FormStyle:= fsStayOnTop; BorderIcons:= []; Caption := ACaption; ClientWidth := MulDiv(Screen.Width div 4, DialogUnits.X, 4); ClientHeight := MulDiv(23 + (Lines*10), DialogUnits.Y, 8); Position := poScreenCenter; Prompt := TLabel.Create(Form); with Prompt do begin Parent := Form; AutoSize := True; Left := MulDiv(8, DialogUnits.X, 4); Top := MulDiv(8, DialogUnits.Y, 8); Caption := APrompt; end; Show; Application.ProcessMessages; finally Sleep(DuracaoEmSegundos*1000); Form.Free; end; end; function GetAveCharSize(Canvas: TCanvas): TPoint; var I: Integer; Buffer: array[0..51] of Char; begin for I := 0 to 25 do Buffer[I] := Chr(I + Ord(´A´)); for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord(´a´)); GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result)); Result.X := Result.X div 52; end; function TransacaoTEF: Boolean; var ArquivoINI: TIniFile; Status: String; begin try ArquivoINI:= TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); Status:= ArquivoINI.ReadString( ´STATUS´, ´Transacao´, ´Aberta´); finally ArquivoINI.Free; end; Result := Status = ´Aberta´; end; procedure AbreTransacaoTEF; var ArquivoINI: TIniFile; begin try ArquivoINI:= TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); ArquivoINI.WriteString(´STATUS´, ´Transacao´, ´Aberta´); finally ArquivoINI.Free; end; end; procedure FechaTransacaoTEF; var ArquivoINI: TIniFile; begin try ArquivoINI:= TIniFile.Create(´C:\EasyPDV\EasyPDV.INI´); ArquivoINI.WriteString(´STATUS´, ´Transacao´, ´Fechada´); finally ArquivoINI.Free; end; end; function GP_Ativar(CarregarTEF_DIAL: Boolean; cTefDial: String): Boolean; Const NomeArquivo = ´C:\tef_dial\resp\ativo.001´;// Caminho e nome do arquivo criado pelo GP ao ser carregado. var Arquivo: TextFile;// Armazenar o arquivo INTPOS.001. Numero: Integer;// Número da transação - Obtido do arquivo INI. Esperar: Integer;// Esperar até 7 segundos. Erros: Integer;// Quantidade de erros deve ser zero antes de result. Iniciando c/ 2. begin Esperar:= 1; Erros:= 2; MostraMensagem(´Aviso´,´Testando a comunicação com o Gerenciador Padrão.´,1); if CarregarTEF_DIAL then begin WinExec(PChar(cTefDial), SW_HIDE);// Carregar o GP. // Aguardar até 7 segundos pela criação do arquivo de resposta do GP. while not FileExists(NomeArquivo) do begin if Esperar > 7 then begin Inc(Erros);// Incrementa a qtde de erros. Não carregou em tempo hábil. break; end; Sleep(1000);// Espera de 1 segundo. Inc(Esperar);// Incrementar o contador do tempo de espera. end; // Decrementar o contador de erros se o arquivo ATIVO.001 tiver sido criado // Normalmente. Erros := Erros - Integer(FileExists(NomeArquivo)); // Remover o arquivo para. try DeleteFile(NomeArquivo); except // Exceção silenciosa. end; end else Dec(Erros);// Caso não seja para carregar o GP. // Elimina arquivo anterior try DeleteFile(´c:\tef_dial\resp\IntPos.sts´);// Evita erro de armazenamento indevido. // DeleteFile(´c:\tef_dial\req\intpos.001´);// Caso não tenha sido removido pelo GP. except // Exceção silenciosa. end; AtualizarINI(´ATV´, Numero, True); AssignFile(Arquivo,´c:\tef_dial\req\IntPos.tmp´); try ReWrite(Arquivo); WriteLn(Arquivo,´000-000 = ´+´ATV´); WriteLn(Arquivo,´001-000 = ´+IntToSTr(Numero)); WriteLn(Arquivo,´999-999 = 0´); finally CloseFile(Arquivo); RenameFile(´c:\tef_dial\req\IntPos.tmp´, ´c:\tef_dial\req\IntPos.001´); end; Erros := Erros - Integer(GP_LeStatus()); // Número passado e igual ao retornado. Result:= Erros = 0; end; end.
Aroldo Zanela
Curtir tópico
+ 0Post mais votado
12/01/2009
Realmente muito útil esse post, eu peguei os códigos e estou tentando implantar no meu ECF, mas alguém poderia me dizer, dentro do fluxo da Redecard, a qual item representa cada função?
Obrigado
Aroldo diga lá... o componente de skin que eu te passei com fontes funcionou?
abraço.
Nigro
Gostei + 1
Mais Posts
29/10/2004
Aroldo Zanela
Esta é a rotina de inicialização/verificação do GP. Estou deixando até as rotinas comentadas/descartadas:
procedure TFormMain.FormCreate(Sender: TObject); var cTef: String; hTef: HWnd; begin cTef:= ´c:\tef_dial\Tef_dial.exe´; hTef := FindWindow(nil, PChar(´Tef_dial´)); GP_Ativo:= false; if not IsWindow(hTef) then begin MessageDlg(´Gerenciador Padrão não está ativo e será ativado automaticamente.´,mtInformation,[mbOk],0); // PostMessage(hTef, WM_CLOSE, 0, 0); // Derruba tef se já estiver carregado if FileExists(cTef) then begin GP_Ativo := GP_Ativar( True, cTef ); if not GP_Ativo then begin MessageDlg(´Não foi possível ativar gerenciador padrão.´+13+ ´Este terminal não efetuará vendas com cartão.´,mtWarning,[mbCancel],0); end; end else begin MessageDlg(´Não é possível ativar gerenciador padrão.´+#13+ ´Este terminal não efetuará vendas com cartão.´,mtWarning,[mbCancel],0); end; end else begin GP_Ativo := GP_Ativar( false, cTef ); if not GP_Ativo then begin MessageDlg(´Não foi possível ativar gerenciador padrão.´+13+ ´Este terminal não efetuará vendas com cartão.´,mtWarning,[mbCancel],0); end; end; if TransacaoTEF then begin MostraMensagem(´Atenção´,´Uma trasação TEF está pendente e será cancelada.´, 2); // Efetuar o cancelamento FechaTransacaoTEF; end; end;
Gostei + 0
29/10/2004
Aroldo Zanela
function BlockInput(ABlockInput: boolean): Boolean; stdcall; external ´USER32.DLL´;
Mais detalhes:
http://www.swissdelphicenter.ch/en/printcode.php?id=312
Link postado em outra thread pelo colega TatuWeb
Gostei + 0
30/10/2004
Dopi
Parabens pela iniciativa...
Vc conhece CLIPPER ? Se sim, e houver interesse, posso lhe enviar o PRG da rotina TEF Discado que uso em CLIPPER... está bem modular... o mais proximo de uma ´Classe´ que o Clipper permite... ;-)
Estou planejando criar um componente ACBrTEF mas acredito que somente por Dezembro.. estou com outros projetos para concluir...
Analizando o seu código posso dar as sugintes sugestões:
A Função GP_LeRetorno deveria emitir uma msg ao operador quando houver o campo 030-XXX no arquivo de resposta... Ex. quando a transação é aprovada, sempre virá uma msg ´TRANSAÇAO APROVADA´, que deve ser exibida enquando o cupom e fechado e o CV impresso...
A funçao VendaCartao ou na sua sequencia, deve tentar imprimir a forma de pagamento no ECF. Casa ela nao consiga a transação deve ser cancelada... Isso é importante pq nem todas as Formas de pagamento permitem Cupom Vinculo. Seria interessante verificar isso na A.C. antes de chamar a VendaCartao...
No meu caso, deixei a propria função VendaCartao se comunicar com o ECF e tentar imprimir a Forma de Pagamento... se ela nao conseguiu, ela já cancela a transação.
Deixe os diretórios em Variaveis... para permitir a integração com outros TEF´s:
Existem vários tipos de TEF Discado:
- Tef Dial ( Redecard / Visa / Amex ) = C:\TEF_DIAL
- Tef Disc ( TecBan - Cheque Eletronico ) = C:\TEF_DISC
- Tef Sorocred (Cartao Cred. Regiao de Sorocrocaba) = C:\FWTEF
- Tef GOODCard ( Cartao de Gestao de Convenios) = C:\GOOD
Existem algumas diferenças entre os Tefs acima, alguns campos especificos, etc... Mas a lógica de todos é bem semelhante... Sem dúvida os mais importantes são o TEF Dial e Disc... No Norte do pais tb há o Hypercard... (esse ainda nao estou homologado)
Gostei + 0
30/10/2004
Aroldo Zanela
Realmente eu esperava sua particpação nesta thread, assim como de outros colegas que trabalham com automação comercial. Obrigado por suas considerações.
Sobre o desenvolvimento do componete para TEF eu pretendo fazer isto ainda neste mês de novembro (após entender melhor o que deve ser feito em nível de negócio) e posso estar lhe enviando para integrar sua base de recursos do ACBR.
Sobre entender de Clipper, eu acredito que ainda saiba algumas coisas, pois trabalhei alguns anos com a mesma, já desenvolvi até gerador de sistemas em Clipper para Clipper, documentei toda Samples em formato NG, além de criar e documentar (ng) minha própria library.
Gostei + 0
01/11/2004
Aroldo Zanela
Recebi a referenciado hoje e encontrei o seguinte na contra-capa:
Facilidades para o TEF (Exemplos na sua linguagem - Exemplos com código fonte aberto para você utilizar).
Ainda não verifiquei, mas acredito que deve ser material produzido pelo Claudemir C. Andrade, uma das maiores autoridades hoje no assunto.
www.daruma.com.br
Gostei + 0
23/02/2005
Spider
Vi este tópico, copiei a Unit, mas num tô entendendo muito bem como usar as funções da Unit postada pelo Aroldo...
alguem poderia descrever um exemplo de uso ???
me enrolei na hora de verificar se o gerenciador foi finalizado pelo operador, se a transação foi negada ou aceita pela adminstradora, e outros...
Desde Já,
Muito Obrigado!
Gostei + 0
23/02/2005
Aroldo Zanela
Recentemente criamos uma seção de automação comercial no www.forumweb.com.br/forum. Lá, além dos colaboradores do fórum, temos a presença constante dos principais players do mercado de ECF, bem como, estamos contatando mais e mais pessoas ligadas ao fornecimento de equipamentos e/ou provedores de informação.
Gostaria de convidar você e demais leitores desta thread para participar lá também, visando concentrar as dúvidas e conhecimentos neste novo local. Aproveitanto, você poderia abrir um tópico lá (não tem problema se você referenciar outros fóruns ou sites na mesma) e detalhar mais a sua dúvida, pois não consegui compreender exatamente o problema.
Gostei + 0
23/02/2005
Ant.carlos/sp
Legal sua iniciativa, mas na WEB, tem um Site o Projeto Sultan, que está desenvolvendo vários aplicativos e componente para a àrea de Automação Comercial.
O pessoal de lá está precisando de uma ajuda, principalmente no TEF que se iniciou e como vc já tem algo quase q pronto, pode ajudar vc e a toda comunidade em si.
Faça uma visita e seja um membro colaborador.
www.welter.pro.br/sultan
T+
ANT.CARLOS/SP
Gostei + 0
29/02/2008
Daviddalindo
Em relação ao TEF vc já terminou a rotina para o mesmo ou alguem ja acrescentou algo ao que vc postou, ou ainda está conforme descrito no codigo colocado aqui na pagina? Você tentou utilizar o ACBrTef? Você sabe quem já implementou alguma coisa sobre o mesmo?
Fico no aguardo.
Um abraço
David Araujo
Gostei + 0
29/02/2008
Onjahyr
[url]http://www.forumweb.com.br/foruns/index.php?s=4f32b4e654d93226ba178d873f570f2f&showforum=416[/url]
...e o engraçado é que o Massuda também administra este fórum de lá também, :lol:
Gostei + 0
29/02/2008
Aroldo Zanela
Colega,
Não sai do lugar mais com isso, pois não tive mais tempo de me dedicar aos projetos de automação que envolvem TEF. O pessoal do ACBr (Daniel Simões) deve estar com isso finalizado.
Gostei + 0
03/03/2008
Virus69
Qualquer dúvida entre em contato comigo por MP que serei grato em atender
unit Unit_Modulo_TEF;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TModuloTEFFm = class(TForm)
Panel2: TPanel;
Msg: TMemo;
BtnSim: TButton;
BtnNao: TButton;
BtnOk: TButton;
TxtArq: TMemo;
TxtCmd: TMemo;
TxtTmp: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure BtnOkClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
SeqComando: Integer;
function ExecGP(): Boolean;
function ExecComando(Comando: String; IdComando: Integer): Boolean;
public
{ Public declarations }
ValorAutorizado: Real;
CamposAuxilio: String;
function AtivaGP(): Boolean;
function LerMsgRetorno(): String;
function LerCupomTef(Var Cupom: String): Integer;
function AutorizaCRT(Valor: Real): Boolean;
function AutorizaCHQ(Valor: Real): Boolean;
function FuncoesADM(): Boolean;
function EnviaCNF(): Boolean;
function EnviaNCN(): Boolean;
function CarregaArquivo(Arquivo: String): Boolean;
function LerCampo(Campo: String): String;
end;
var
ModuloTEFFm: TModuloTEFFm;
implementation
{$R *.dfm}
procedure TModuloTEFFm.FormShow(Sender: TObject);
begin
// Define altura do memo baseado na quantidade de linhas a exibir
Msg.Height := ( Msg.Lines.Count * 22 ) + 10;
// Posiciona os botões abaixo do memo
BtnOk.Top := ( Msg.Top + Msg.Height ) + 15;
BtnSim.Top := ( Msg.Top + Msg.Height ) + 15;
BtnNao.Top := ( Msg.Top + Msg.Height ) + 15;
// Define altura do fomulario
if ( BtnOk.Visible ) or ( BtnSim.Visible ) then
Self.Height := BtnOk.Top + 80
else
Self.Height := BtnOk.Top;
if ( not BtnOk.Enabled ) then
BtnOk.Visible := False;
end;
//---------------------------------------------------------------------------//
procedure TModuloTEFFm.BtnOkClick(Sender: TObject);
begin
Close;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.ExecGP(): boolean;
var
ProcInfo: TProcessInformation;
SUInfo: TStartupInfo;
GPExe: String;
begin
GPExe := ´C:\TEF_DIAL\Tef_Dial.exe´;
FillChar( SUInfo, SizeOf( SUInfo ), #0 );
with SUInfo do
begin
cb := SizeOf( SUInfo );
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := SW_SHOW;
end;
Result := CreateProcess( nil, PChar( GPExe ), nil, nil, False,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
PChar( ExtractFilePath( GPExe ) ), SUInfo, ProcInfo );
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.ExecComando(Comando: String;
IdComando: Integer): boolean;
var
Retorno: Boolean;
Segundos: Integer;
begin
Retorno := False;
// Apaga o arquivo de requisição temporario caso ele exista
try
if FileExists( ´C:\TEF_DIAL\REQ\IntPos.tmp´ ) then
DeleteFile( ´C:\TEF_DIAL\REQ\IntPos.tmp´ );
except
end;
// Apaga o arquivo de requisição caso ele exista
try
if FileExists( ´C:\TEF_DIAL\REQ\IntPos.001´ ) then
DeleteFile( ´C:\TEF_DIAL\REQ\IntPos.001´ );
except
end;
// Apaga o arquivo de status de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.sts´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ );
except
end;
// Apaga o arquivo de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
except
end;
// Cria um novo aquivo de requisição temporario
TxtCmd.Lines.SaveToFile( ´C:\TEF_DIAL\REQ\IntPos.tmp´ );
// Renomeia o arquivo de requisição temporario para o nome de
// requisição solicitado pelo GP (conforme legislação)
RenameFile( ´C:\TEF_DIAL\REQ\IntPos.tmp´, ´C:\TEF_DIAL\REQ\IntPos.001´ );
// Tempo de espera pelo arquivo de status de resposta
Segundos := 7; // Sete segundos (conforme legislação)
while ( not Retorno ) and ( Segundos > 0 ) do
begin
// Verifica a existencia do arquivo de status de resposta
// e carrega ele pra memoria
if CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.sts´ ) then
begin
// Verifica se o arquivo de status refere-se ao comando enviado
if ( LerCampo( ´000-000´ ) = Comando ) and
( LerCampo( ´001-000´ ) = IntToStr( IdComando ) ) then
// Esse é nosso arquivo
Retorno := True
else
// Arquivo inválido, apaga e aguarda o arquivo correto
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ );
end;
// Se o arquivo de status nao for encontrado ou nao for o correto,
// aguarda um segundo e decrementa o contador de segundos
if not Retorno then
begin
Sleep( 1000 );
Segundos := Segundos - 1;
end;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.CarregaArquivo(Arquivo: String): Boolean;
var
Retorno: Boolean;
ArqNovo: String;
begin
Retorno := False;
if FileExists( Arquivo ) then
begin
TxtArq.Lines.LoadFromFile( Arquivo );
Retorno := True;
// Remove o Path do nome do arquivo
ArqNovo := Arquivo;
while Pos( ´\´, ArqNovo ) > 0 do
begin
ArqNovo := Copy( ArqNovo, Pos( ´\´, ArqNovo ) + 1,
Length( ArqNovo ) - Pos( ´\´, ArqNovo ) );
end;
// Grava uma copia do arquivo no diretorio da aplicação
TxtArq.Lines.SaveToFile( ´.\´ + ArqNovo );
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.LerCampo(Campo: String): String;
var
Retorno: String;
I: Integer;
begin
Retorno := ´´;
I := 0;
while ( Retorno = ´´ ) and ( I < TxtArq.Lines.Count ) do
begin
if Copy( TxtArq.Lines.Strings[ I ], 1, Length( Campo ) ) = Campo then
begin
Retorno := Copy( TxtArq.Lines.Strings[ I ], 11,
Length( TxtArq.Lines.Strings[ I ] ) - 10 );
end;
I := I + 1;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.AtivaGP(): Boolean;
var
Retorno: Boolean;
Segundos: Integer;
begin
Retorno := False;
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Comando para ativar o Gerenciador Padrão
TxtCmd.Lines.Clear;
TxtCmd.Lines.Add( ´000-000 = ATV´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´999-999 = 0´ );
// Executa o comando contido em txtCmd
Retorno := ExecComando( ´ATV´, SeqComando );
// Verifique se tudo saiu como esperado
if Retorno then
// O GP está ativo, apaga o arquivo de status de retorno pois o mesmo
// não nos interessa mais
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ )
else
begin
// Exibe uma mensagem ao operador e aguardo um ´Ok´ para executar
// o GP automaticamente
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo, e será ´ +
´ativado automaticamente!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
// Tenta executar o Gerenciador Padrão
if ExecGP() then
begin
// Aguarda até o gerenciador terminar de carregar
Sleep( 5000 );
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Comando para ativar o Gerenciador Padrão
TxtCmd.Clear;
TxtCmd.Lines.Add( ´000-000 = ATV´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´999-999 = 0´ );
// Executa o comando contido em txtCmd
Retorno := ExecComando( ´ATV´, SeqComando );
end;
// Verifique se tudo saiu como esperado
if Retorno then
// O GP está ativo, apaga o arquivo de status de retorno pois o
// mesmo não nos interessa mais
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ )
else
begin
// Não foi possível ativar o GP, exibe uma mensagem ao operador
// e aguardo por um ´Ok´ para retornar
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO!´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
end;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.LerMsgRetorno(): String;
var
Retorno: String;
begin
Retorno := ´´;
if CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
Retorno := LerCampo( ´030-000´ );
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.LerCupomTef(Var Cupom: String): Integer;
var
Retorno, I: Integer;
Linha, IdLin: String;
begin
Retorno := 0;
TxtTmp.Lines.Clear;
if CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
begin
try
Retorno := StrToInt( LerCampo( ´028-000´ ) );
except
Retorno := 0;
end;
if Retorno > 0 then
begin
// Faz a leitura de todas a linhas do cupom retornado pelo GP
for I := 1 to Retorno do
begin
// Formata a identificação da linha em tres algarismos
IdLin := IntToStr( I );
while Length( IdLin ) < 3 do
IdLin := ´0´ + IdLin;
// Copia a linha
Linha := LerCampo( ´029-´ + IdLin );
// Remove as aspas da linha
Linha := Copy( Linha, 2, Length( Linha ) - 1 );
Linha := Copy( Linha, 1, Length( Linha ) - 1 );
// Adiciona a linha ao cupom
TxtTmp.Lines.Add( Linha );
end;
end;
end;
Cupom := TxtTmp.Lines.Text;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.AutorizaCRT(Valor: Real): Boolean;
var
Retorno: Boolean;
S, VlrStr: String;
I: Integer;
begin
// Apaga o arquivo de status de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.sts´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ );
except
end;
// Apaga o arquivo de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
except
end;
// Verifica se o GP está ativo e tenta ativa-lo caso não esteja
Retorno := AtivaGP();
if Retorno then
begin
// Formata o valor no padrão do comando CRT
S := Trim( Format( ´¬12.2f´, [ Valor ] ) );
VlrStr := ´´;
for I := 1 to Length( S ) do
begin
if ( S[ I ] <> ´.´ ) and ( S[ I ] <> ´,´ ) then
VlrStr := VlrStr + S[ I ];
end;
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Cria o arquivo de requisição para ativar o Gerenciador Padrão
TxtCmd.Clear;
TxtCmd.Lines.Add( ´000-000 = CRT´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´003-000 = ´ + VlrStr );
if ( Length( CamposAuxilio ) > 7 ) then
TxtCmd.Lines.Add( CamposAuxilio );
TxtCmd.Lines.Add( ´999-999 = 0´ );
Retorno := ExecComando( ´CRT´, SeqComando );
if not Retorno then
begin
// Não foi possível contactar o GP, exibe uma mensagem ao operador
// e aguardo por um ´Ok´ para retornar
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO!´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
end;
// Aguarda a resposta do GP (Nesse momento o operador está concluindo
// a transação atraves do GP. O GP so dará uma resposta após a
// conclusão ou cancelamento da transação)
if Retorno then
begin
Retorno := False;
while not Retorno do
begin
// Verifica se o arquivo de retorno existe e se ele refere-se
// ao comando enviado
//if ( CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) ) and
// ( LerCampo( ´000-000´ ) = ´CRT´ ) and
// ( LerCampo( ´001-000´ ) = IntToStr( SeqComando ) ) then
// // Esse é nosso arquivo
// Retorno := True
//else
// // Arquivo inválido, apaga e aguarda o arquivo correto
// DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
// *** O código acima está apagando o arquivo de retorno algumas
// vezes. Necessario corrigir antes de usar esse codigo ***
// *** Codigo temporario para substituir o codigo acima ***
if ( CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) ) then
// Arquivo encontrado
Retorno := True
else
// Aguarda 1/2 segundo antes de tentar ler o arquivo
// novamente
Sleep( 500 );
end;
end;
// Verifica se a transação foi (009-000 = 0) ou não (009-000 <> 0)
// aprovada.
// OBS: O Criterio usado pelo fluxograma do manual do TEF afirma que
// se o campo 028-000 é maior que 0 (zero) então a transação TEF
// foi aprovada. Não estou usando este criterio pois entendo que
// o campo 009-000 tem a informação mais segura a esse respeito,
// pois esse é o motivo de sua existencia.
if Retorno then
Retorno := LerCampo( ´009-000´ ) = ´0´;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.AutorizaCHQ(Valor: Real): Boolean;
var
Retorno: Boolean;
begin
// Apaga o arquivo de status de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.sts´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ );
except
end;
// Apaga o arquivo de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
except
end;
// ..
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.FuncoesADM(): Boolean;
var
Retorno: Boolean;
begin
// Apaga o arquivo de status de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.sts´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.sts´ );
except
end;
// Apaga o arquivo de resposta caso ele exista
try
if FileExists( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
except
end;
// Verifica se o GP está ativo e tenta ativa-lo caso não esteja
Retorno := AtivaGP();
if Retorno then
begin
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Cria o arquivo de requisição para ativar o Gerenciador Padrão
TxtCmd.Clear;
TxtCmd.Lines.Add( ´000-000 = ADM´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´999-999 = 0´ );
Retorno := ExecComando( ´ADM´, SeqComando );
if not Retorno then
begin
// Não foi possível contactar o GP, exibe uma mensagem ao operador
// e aguardo por um ´Ok´ para retornar
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO!´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
end;
// Aguarda a resposta do GP (Nesse momento o operador está concluindo
// a transação atraves do GP. O GP so dará uma resposta após a
// conclusão ou cancelamento da transação)
if Retorno then
begin
Retorno := False;
while not Retorno do
begin
// Verifica se o arquivo de retorno existe e se ele refere-se
// ao comando enviado
//if ( CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) ) and
// ( LerCampo( ´000-000´ ) = ´ADM´ ) and
// ( LerCampo( ´001-000´ ) = IntToStr( SeqComando ) ) then
// // Esse é nosso arquivo
// Retorno := True
//else
// // Arquivo inválido, apaga e aguarda o arquivo correto
// DeleteFile( ´C:\TEF_DIAL\RESP\IntPos.001´ );
// *** O código acima está apagando o arquivo de retorno algumas
// vezes. Necessario corrigir antes de usar esse codigo ***
// *** Codigo temporario para substituir o codigo acima ***
if ( CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) ) then
// Arquivo encontrado
Retorno := True
else
// Aguarda 1/2 segundo antes de tentar ler o arquivo
// novamente
Sleep( 500 );
end;
end;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.EnviaCNF(): Boolean;
var
Retorno: Boolean;
begin
if CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
begin
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Cria o arquivo de requisição para ativar o Gerenciador Padrão
TxtCmd.Clear;
TxtCmd.Lines.Add( ´000-000 = CNF´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´002-000 = ´ + LerCampo( ´002-000´ ) );
TxtCmd.Lines.Add( ´010-000 = ´ + LerCampo( ´010-000´ ) );
TxtCmd.Lines.Add( ´012-000 = ´ + LerCampo( ´012-000´ ) );
TxtCmd.Lines.Add( ´027-000 = ´ + LerCampo( ´027-000´ ) );
TxtCmd.Lines.Add( ´999-999 = 0´ );
Retorno := ExecComando( ´CNF´, SeqComando );
if not Retorno then
begin
// Não foi possível contactar o GP, exibe uma mensagem ao operador
// e aguardo por um ´Ok´ para retornar
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO!´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
end;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
function TModuloTEFFm.EnviaNCN(): Boolean;
var
Retorno: Boolean;
begin
if CarregaArquivo( ´C:\TEF_DIAL\RESP\IntPos.001´ ) then
begin
// Sequencia de identificação do comando de requisição
SeqComando := SeqComando + 1;
// Cria o arquivo de requisição para ativar o Gerenciador Padrão
TxtCmd.Clear;
TxtCmd.Lines.Add( ´000-000 = NCN´ );
TxtCmd.Lines.Add( ´001-000 = ´ + IntToStr( SeqComando ) );
TxtCmd.Lines.Add( ´002-000 = ´ + LerCampo( ´002-000´ ) );
TxtCmd.Lines.Add( ´010-000 = ´ + LerCampo( ´010-000´ ) );
TxtCmd.Lines.Add( ´012-000 = ´ + LerCampo( ´012-000´ ) );
TxtCmd.Lines.Add( ´027-000 = ´ + LerCampo( ´027-000´ ) );
TxtCmd.Lines.Add( ´999-999 = 0´ );
Retorno := ExecComando( ´NCN´, SeqComando );
if not Retorno then
begin
// Não foi possível contactar o GP, exibe uma mensagem ao operador
// e aguardo por um ´Ok´ para retornar
Msg.Lines.Clear;
Msg.Lines.Add( ´ATENÇÃO!´ );
Msg.Lines.Add( ´´ );
Msg.Lines.Add( ´Gerenciador Padrão não está ativo!´ );
BtnSim.Visible := False;
BtnNao.Visible := False;
BtnOk.Visible := True;
ShowModal;
end;
end;
Result := Retorno;
end;
//---------------------------------------------------------------------------//
procedure TModuloTEFFm.FormCreate(Sender: TObject);
begin
CamposAuxilio := ´´;
end;
procedure TModuloTEFFm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Self.Enabled := True;
Self.hide;
end;
end. :)
Gostei + 0
24/03/2008
Wanderok
Gostei + 0
31/03/2008
Daviddalindo
David Araujo
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)