Ir para conteúdo
  • Cadastre-se

dev botao

ACBr PicPay - bug


Ver Solução Respondido por EMBarbosa,
  • Este tópico foi criado há 1624 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

  • Membros Pro
Postado

Amigos há um pequeno problema (bug) no componente ACBrPicPay,  acredito que seja a forma que o componente trata uma ação

Ao inciar a primeira transação (cadastrar um pagamento) com o componente tudo funciona perfeitamente.

Se tentar realizar a segunda operação (de cadastrar novamente) o componente não entra mais no evento  ACBrPicPay1WaitingPayment, é como se a thread de aguardar o status não existisse mais 

O componente não tem um metodo "Clean", igual usamos na NFe, para reiniciar o componente, e talvez aqui esteja o problema.

Ainda não tenho conhecimento suficiente para resolver este, se alguém puder ajudar ficarei agradecido

  • Consultores
Postado
3 horas atrás, marcelosantos disse:

Amigos há um pequeno problema (bug) no componente ACBrPicPay,  acredito que seja a forma que o componente trata uma ação

Ao inciar a primeira transação (cadastrar um pagamento) com o componente tudo funciona perfeitamente.

Se tentar realizar a segunda operação (de cadastrar novamente) o componente não entra mais no evento  ACBrPicPay1WaitingPayment, é como se a thread de aguardar o status não existisse mais 

Oi Marcelo.

   Notei que o componente talvez precise de alguns ajustes no funcionamento da thread. Me diz uma coisa, o primeiro pagamento foi efetuado gerando o status 'paid'?

3 horas atrás, marcelosantos disse:

O componente não tem um metodo "Clean", igual usamos na NFe, para reiniciar o componente, e talvez aqui esteja o problema.

Acho que não é bem a questão de um método "Clean"... me parece que seria a thread mesmo que talvez precise de ajustes para ser reutilizada depois de finalizar...

 

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado

EMBarbosa fiz 2 testes, vou descrever abaixo usando o demo disponível no SVN

Iniciei o programa e solicitei o 1º pagamento, após gerar o qr-code, fiz o pagamento usando o celular, o programa estava contado o tempo e assim que confirmou o pagamento no celular o status mudou para "PAGO" na COR verde. Após isto solicitei um novo pagamento (sem fechar o programa e com um novo id de referencia) o QR-code, foi gerado, recebi no celular a solicitação de pagamento, mais o tempo não estava decrementando (no modo debug ele não passa pelo evento OnWaitPayment).

No 2º teste, iniciei o programa solicitei um novo pagamento (com um novo id é claro), gerou o qr-code, mais não finalizei este pagamento, cancelei a "espera" setando ACBrPicpay1.CancelarAguardoRetorno := true;. Após isso gerei uma nova solicitação e novamente o demo não passa pelo evento onwaitPayment, e logo o tempo não é decrementado
 

  • Consultores
Postado
16 horas atrás, marcelosantos disse:

EMBarbosa fiz 2 testes, vou descrever abaixo usando o demo disponível no SVN

Iniciei o programa e solicitei o 1º pagamento, após gerar o qr-code, fiz o pagamento usando o celular, o programa estava contado o tempo e assim que confirmou o pagamento no celular o status mudou para "PAGO" na COR verde. Após isto solicitei um novo pagamento (sem fechar o programa e com um novo id de referencia) o QR-code, foi gerado, recebi no celular a solicitação de pagamento, mais o tempo não estava decrementando (no modo debug ele não passa pelo evento OnWaitPayment).

No 2º teste, iniciei o programa solicitei um novo pagamento (com um novo id é claro), gerou o qr-code, mais não finalizei este pagamento, cancelei a "espera" setando ACBrPicpay1.CancelarAguardoRetorno := true;. Após isso gerei uma nova solicitação e novamente o demo não passa pelo evento onwaitPayment, e logo o tempo não é decrementado
 

Certo, me parece que o funcionamento por threads vai precisar alguns ajustes mesmo. Deixa eu verificar com a equipe aqui e te dou um retorno.

Mas eu sinceramente aconselho o não implementar utilizando threads. Seu sistema vai ficar tentando contato a toda hora com o PicPay, congestionando o tráfico e tal...

O melhor é implementar utilizando um servidor que aguarda a notificação do PicPay.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Moderadores
Postado

Assista o curso do Thulio em poucos minutos você consegue implementar um servidor para esperar a resposta com Horse ou DMVC usando delphi.

e tu vai poder colocar em cada cliente. lembrando que vai precisar de um IP fixo nele para poder usar

Consultor SAC ACBr Juliomar Marchetti
 

Projeto ACBr

skype: juliomar
telegram: juliomar
e-mail: [email protected]
http://www.juliomarmarchetti.com.br
MVP_NewLogo_100x100_Transparent-02.png
 

 

  • Membros Pro
Postado
21 minutos atrás, EMBarbosa disse:

Certo, me parece que o funcionamento por threads vai precisar alguns ajustes mesmo. Deixa eu verificar com a equipe aqui e te dou um retorno.

Mas eu sinceramente aconselho o não implementar utilizando threads. Seu sistema vai ficar tentando contato a toda hora com o PicPay, congestionando o tráfico e tal...

O melhor é implementar utilizando um servidor que aguarda a notificação do PicPay.

Isso EMBarbosa, acredito que se resolver a questão da destruição e criação das threads resolva o problema do componente. 

Quanto ao não uso de threads por conta do congestionamento vou resolver com esta variável, ACBrPicpay1.CancelarAguardoRetorno := true;, ou seja se for uma transação que não preciso do retorno no exato momento, eu deixo manual para o usuario consultar a transação no momento mais oportuno para ele

se a negociação/transação for no checkout do PDV, então bloqueio tudo (igual ao TEF discado) e aguardo a resposta pelo tempo configurado (com a opção de cancelar o aguardo, caso o cliente não consiga realizar o pagamento) 

 

  • Consultores
Postado
10 minutos atrás, marcelosantos disse:

Isso EMBarbosa, acredito que se resolver a questão da destruição e criação das threads resolva o problema do componente. 

Quanto ao não uso de threads por conta do congestionamento vou resolver com esta variável, ACBrPicpay1.CancelarAguardoRetorno := true;, ou seja se for uma transação que não preciso do retorno no exato momento, eu deixo manual para o usuario consultar a transação no momento mais oportuno para ele

se a negociação/transação for no checkout do PDV, então bloqueio tudo (igual ao TEF discado) e aguardo a resposta pelo tempo configurado (com a opção de cancelar o aguardo, caso o cliente não consiga realizar o pagamento) 

 

Certo. Já confirmei aqui com a equipe e devo mexer nisso nos próximos dias.

Assim que estiver pronto pra testes te retorno nesse mesmo tópico.

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado

Olá a todos

Pessoal, enquanto não sai a atualização do componente, consegui usar o "código fonte" sem erros.

Como estou fazendo?

Crio o Componente em tempo de execução
Configuro todas suas propriedades
Atribuo procedures previamente criadas a todos aos eventos (onwait, statuspayment, error) 

Uso o componente (objeto). Aqui tudo funcionando, Enviar, Consultar e Cancelar

no final destro o objeto com Free

e se for usar novamente, executo tudo novamente 

 

  • Curtir 2
  • Consultores
  • Solution
Postado
Em 31/05/2020 at 11:24, marcelosantos disse:

Olá a todos

Pessoal, enquanto não sai a atualização do componente

Bom dia Marcelo,

Acabei de enviar ao SVN na revisão 20043 alterações no ACBrPicPay que devem corrigir o problema relatado aqui.

Veja o log:

-- ACBrPicPay --
[+] Adicionado tipo retorno trNenhum para quando a aplicação for fazer o controle de forma separada;
[-] Thread de retorno não estava funcionando para mais de uma consulta (veja correções mais abaixo);
[*] nomes das constantes alteradas pra ficar mais semelhante a documentação do PicPay;
[*] Remoção de comentários desnecessários;
[*] Propriedade CancelarAguardoRetorno agora é apenas um método. Afinal, você só precisa cancelar;
[-] Remoção de With
[*] melhoria no tratamento de SetDocumento
[+] Adicionado código para leitura do QRCode no FPC/Lazarus
[*] Layout do código melhorado

-- TACBrPicPayThread
[+] Adicionada propriedade Pausado para controlar o funcionamento da thread;
[-] Thread agora usa fUltimoTempoAguardo para contar o tempo, evitando "race conditions" nessa propriedade;
[-] É necessário usar Synchronize sempre que executar um código na Thread principal;
[-] É melhor não haver Exceptions no Create;
[-] A Thread não tinha verificações de estar sendo terminada;

Se você puder testar e reportar qualquer problema ficaria agradecido.

bom trabalho por aí

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado

EMBarbosa

a principio tudo funcionado perfeitamente, ainda vou continuar com os testes aqui

ainda não consegui pegar o TempoRetorno, entendi que ele mudou para fUltimoTempoAguardo e que preciso usar Thread.synchonize (se você me disse como fazer, posso alterar o exemplo e mandar para vocês)
 

  • Curtir 1
  • Obrigado 1
  • Membros Pro
Postado

Bom dia

"resolvi" o contador de tempo restante do demo

adicionando o seguinte na unit ACBRPicPay.pas
 

procedure TACBrPicPayThread.FazWaitingPayment;
begin
  if Assigned(fACBrPicpay.fOnWaitingPayment) then
  begin
    fACBrPicpay.fOnWaitingPayment(fACBrPicpay.Status);
    fACBrPicpay.TempoRetorno :=  fACBrPicpay.TempoRetorno - 1; // adicionei esta linha
  end;
end;


sei que não estou usando as melhoras praticas, mais resolveu aqui pra mim, tudo funcionando agora.

Se houver uma melhor forma de fazer, gostaria de "ouvi-los"

  • Curtir 1
  • Obrigado 1
  • Membros Pro
Postado

Bom dia

Tb observei este problema apos o commit de ontem, vou usar sua sugestão Marcelo. Penso que alguns eventos, tipo um onshowqrcode(var CancelarProcesso: Boolean) neste evento eu exibiria o form com o qrcode e poderia abortar o processo dali.

onTransacaoAceita, identificaria que o processo ocorreu com sucesso, posso continuar

OnTimeout(var Retry: Boolean) serviria para quando a contagem do tempo terminasse, eu pudesse dar uma msg para usuario e ele continuaria ou não...

Posso tentar implementar algo aqui, mas a preocupação é de mudar a lógica da qual foi pensado o componente.

  • Obrigado 1

Ederson Selvati
www.criareti.com.br

Skype: eselvati

  • Consultores
Postado
20 horas atrás, marcelosantos disse:

ainda não consegui pegar o TempoRetorno, entendi que ele mudou para fUltimoTempoAguardo e que preciso usar Thread.synchonize (se você me disse como fazer, posso alterar o exemplo e mandar para vocês)

Isso aconteceu porque o tempo de retorno estava passível de race condition. Se depois de enviar um pedido, por algum motivo a aplicação alterasse o TempoRetorno, isso alteraria o comportamento da Thread. O componente não tinha como se proteger e poderia até mesmo travar a aplicação inteira.

4 horas atrás, marcelosantos disse:

sei que não estou usando as melhoras praticas, mais resolveu aqui pra mim, tudo funcionando agora.

Se houver uma melhor forma de fazer, gostaria de "ouvi-los"

Note que ao usar o seu código, o tempo de retorno vai reduzir até 1 ou zero. Daí ao fazer o próximo envio, o tempo de retorno vai ter alterado. Você teria que ficar regulando o tempo de retorno a cada envio. Além disso, se houver uma alteração nesse tempoRetorno por sua aplicação, a thread vai sobrescrever o valor.

O melhor seria a thread retornar esse valor em outro lugar. O que eu pensei foi usar o evento WaitingPayment mesmo. Mas pra fazer isso, teria que alterar o evento atual do WaitingPayment.

Posso fazer isso, o que acham?

18 minutos atrás, Ederson Selvati disse:

Pessoal

Fiz alguns ajustes, poderiam verificar se esta dentro dos padrões e se a ideia e boa tb.

ACBrPicpay.pas 21 kB · 0 downloads Demo.rarUnavailable

Vou verificar e retorno. Obrigado pelas sugestões...

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado
26 minutos atrás, EMBarbosa disse:

Isso aconteceu porque o tempo de retorno estava passível de race condition. Se depois de enviar um pedido, por algum motivo a aplicação alterasse o TempoRetorno, isso alteraria o comportamento da Thread. O componente não tinha como se proteger e poderia até mesmo travar a aplicação inteira.

Note que ao usar o seu código, o tempo de retorno vai reduzir até 1 ou zero. Daí ao fazer o próximo envio, o tempo de retorno vai ter alterado. Você teria que ficar regulando o tempo de retorno a cada envio. Além disso, se houver uma alteração nesse tempoRetorno por sua aplicação, a thread vai sobrescrever o valor.

O melhor seria a thread retornar esse valor em outro lugar. O que eu pensei foi usar o evento WaitingPayment mesmo. Mas pra fazer isso, teria que alterar o evento atual do WaitingPayment.

Posso fazer isso, o que acham?

Vou verificar e retorno. Obrigado pelas sugestões...

Eu pensei em mais uma propriedade

teríamos tempo de Retorno que seria o tempo total, e teriamos tempoDecorrido (tempo que falta) que seria o valor retornando para a aplicação

  • Consultores
Postado
2 horas atrás, marcelosantos disse:

Eu pensei em mais uma propriedade

Acho que vai complicar o design. Não podemos esquecer que o funcionamento por meio de Thread é apenas um dos modos de receber retorno do pagamento do status do pagamento. Também esse método não é o mais recomendado.

 

2 horas atrás, marcelosantos disse:

teríamos tempo de Retorno que seria o tempo total, e teriamos tempoDecorrido (tempo que falta) que seria o valor retornando para a aplicação

Isso poderia ser feito por meio da aplicação, não seria necessário outra propriedade.

Assim que terminar a verificação das alterações do @Ederson Selvati acima, eu retorno sobre esse assunto.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Consultores
Postado
Em 04/06/2020 at 10:49, Ederson Selvati disse:

Pessoal

Fiz alguns ajustes, poderiam verificar se esta dentro dos padrões e se a ideia e boa tb.

ACBrPicpay.pas 21 kB · 1 download

demo.rar 19 kB · 0 downloads

Muito obrigado pela contribuição.
Fiz a implementação baseada nela. Com as seguintes alterações que explico o motivo:

  • O evento onWaitingPayment não é levantado caso seja levantado o onWaitingTimeOut. Não tem sentido você estar esperando se o tempo já acabou. Assim como não tem porque estar esperando se o pagamento já foi feito. Por isso o componente levanta um ou outro, mas não os dois.
  • Alterei o nome do segundo parâmetro de on WaitingPayment para TempoRestante para não confundir com outro tipo de TimeOut.
  • Os parâmetros de on WaitingPayment foram alterados para const. A thread não faz tratamentos caso a aplicação altere esses valores, então deixar como estavam poderia gerar problemas.
  • Não subi a o novo evento onShowQRCode. Não é necessário esse evento no fluxo do PicPay. Se o envio do pedido foi feito com sucesso, você recebe o QRCode sempre. Por isso logo após o envio, salvo o tratamento para erros de envio, você já pode colocar na sua aplicação para mostrar o QRCode.
  • Incluí uma correção para um warning levantado no Delphi XE7 e superiores.

Ainda vou ajustar os demos conforme as alterações acima, mas subi as alterações para o SVN na revisão  20058. Assim vocês já podem ir testando e me dando um retorno.

Pelo que vi está tudo certo.
Queira por favor atualizar, testar e reportar qualquer problema.

Mais uma vez obrigado.

Em 04/06/2020 at 11:37, marcelosantos disse:

Eu pensei em mais uma propriedade

teríamos tempo de Retorno que seria o tempo total, e teriamos tempoDecorrido (tempo que falta) que seria o valor retornando para a aplicação

Marcelo, depois de reinstalar o componente você vai notar que há uma diferença no evento onWaitingPayment. O Ederson fez justamente o que eu tinha pensado acima. :)

O parâmetro é o novo TempoRestante que você vai poder usar para mostrar na tela.

  • Curtir 2

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado (editado)

Olá a todos os envolvidos

Refiz todos os testes e tudo esta funcionando perfeitamente

muito boa a ideia  deste evento "procedure TDM.ACBrPicPay1WaitingTimeout(var Retry: Boolean);" -> Testei retornando true e false para a variável e funcionou como esperado

neste evento "procedure TDM.ACBrPicPay1WaitingPayment(const Status: string; const TempoRestante: Integer);" o Retorno do TempoRestante esta funcionando perfeitamente, era justamente o que eu queria 


o único problema agora é um Memory Leak que é estourado ao finalizar a aplicação e ter usado o método Enviar 

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:

29 - 36 bytes: TStringStream x 3

The sizes of unexpected leaked medium and large blocks are: 3116, 3116, 3116

---------------------------
OK   
---------------------------

 

eu acredito que seja esta function, (não tenho certeza)

function TACBrPicPay.GetQRCode: TStringStream;

{$IFDEF FPC}
  procedure DecodeQRCodeLazarusFPC;
  var
    vData: Ansistring;
  begin
    vData := DecodeStringBase64(fQRCode);
    Result := TStringStream.Create(vData);
    Result.Position := 0;
  end;
{$ELSE}
  procedure DecodeQRCodeDelphi;
  var
    Input: TStringStream;
  begin
    Input := TStringStream.Create(fQRCode);
    try
      Result := TStringStream.Create(fQRCode);
      DecodeStream(Input, Result);
      Result.Position := 0;
    finally
      Input.Free;
    end;
  end;
{$ENDIF}

begin
  if fQRCode = ''  then
  begin
    Result := nil;
    EACBrPicpayError.Create('QRCode está vazio ou inválido.');
  end;

  fQRCode := StringReplace(fQRCode, 'data:image/png;base64,', '', [rfReplaceAll]);

  {$IFDEF FPC}
    DecodeQRCodeLazarusFPC;
  {$ELSE}
    DecodeQRCodeDelphi;
  {$ENDIF}
end;

 

Ultimo detalhe, fiz os testes também iniciando a aplicação, usando os métodos, consultar e cancelar e não há nenhum memory leak  ao fechar a aplicação 

Editado por marcelosantos
  • Curtir 1
  • Consultores
Postado
3 horas atrás, marcelosantos disse:

o único problema agora é um Memory Leak que é estourado ao finalizar a aplicação e ter usado o método Enviar 

tem como você ativar o FullDebug e anexar o log?

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Membros Pro
Postado

Tem sim, só vou precisar que você me diga como é feito esse FullDebug


mais detalhes do erro

 

29 - 36 bytes: TStringStream x 3 -> Esse 3 no final indica que foram 3 TStringsStream que estouraram erro, no debug aqui na hora que mandou enviar uma solicitação ele passa no método de gerar o qr-code por 3 vezes, então por isso o 3 


fiz um teste de uso normal e solicitei 5 pagamentos, o leak no final era = 15

 

  • Consultores
Postado
6 minutos atrás, marcelosantos disse:

Tem sim, só vou precisar que você me diga como é feito esse FullDebug

Pra usar o FullDebug mode, você precisa da versão completa do FastMM. Mas agora relendo sua mensagem, eu notei que você não usa ele. Então não precisa se preocupar por enquanto.

Vamos tentar outra maneira...

12 minutos atrás, marcelosantos disse:

mais detalhes do erro
 


29 - 36 bytes: TStringStream x 3 -> Esse 3 no final indica que foram 3 TStringsStream que estouraram erro, no debug aqui na hora que mandou enviar uma solicitação ele passa no método de gerar o qr-code por 3 vezes, então por isso o 3 

fiz um teste de uso normal e solicitei 5 pagamentos, o leak no final era = 15

 

Ok. Me parece que o leak está acontecendo ao ler o QRCode.

A questão é que a propriedade QRCode vai retornar um TStringStream que não é destruído automaticamente. Você precisa destruir ele.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Consultores
Postado
Em 08/06/2020 at 17:01, marcelosantos disse:

Isso exato,

eu tentei colocar um "Result.free" no final da função mais não deu certo, o retorno da função ficou invalido e o qr-code não foi carregado

Oi Marcelo,

   Isso não resolveria porque você estaria destruindo o Stream antes mesmo de ser utilizado. Fiz uma possível correção na revisão 20090.

   Por favor, queira atualizar, testar e reportar qualquer problema.

 

  • Obrigado 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Este tópico foi criado há 1624 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.
Visitante
Este tópico está agora fechado para novas respostas
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.