Pesquisa personalizada

2008/11/19

E-mails com Pedidos do Mercado Livre + GMail * Greasemonkey = Produtividade

Já faz algum tempinho que acumulei centenas de vendas no Mercado Livre. Em tempos de gloria, chegava a fazer mais de uma dezena de vendas ao dia e isso trouxe a problemática de atender aos clientes de forma ágil e adequada. E a verdade, é que o simples processo (sem falar nos outros) de enviar o e-mail com os dados do pedido ao cliente, me aborrecia pelo tempo perdido.

O Paulinho, um amigo, me disse que o bom programador, era antes de tudo, um grande preguiçoso. Eis-me: A preguiça personificada! Raramente repito duas tarefas da mesma forma, sempre dou um jeitinho de melhorar (nos meus critérios) o processo, seja o que for... Obviamente, as vezes, decaio na inprodutividade, no perfeccionismo imperfeito e na tolice aguda! Mas mesmo assim, invento e reinvento! Até, no ápice do sucesso, faço funcionar!

A questão é que, contrariando qualquer instinto (por mais forte que fosse), resisti a tentação de fazer um script, ou até mesmo, simplesmente criar uma regra/filtro que me ajudasse na simples tarefa de responder com os dados da compra de meus clientes. Visto que me despersuadia:
- "Não seja tolo, Marcio. Vai perder ainda mais tempo com isso."
Sinceramente, nem me reconheço com essa atitude, mas é verdade: resisti!

A questão, é que depois de fazer a mesma coisa por mais de 800 vezes (real!! foi mais que isso mesmo!), você pára (logo agora que tentava escrever direito, me tiram o tal do acento... <0) e, após xingar toda seus antepassados - se excomungar -, diz:
Devia ter automatizado isso antes...

EMail com Pedido do Mercado Livre

Eis, logo eu que atualmente me vejo trabalhando nuns trocentos projetos ao mesmo tempo e tentando ser dono de meu próprio narzi, mas ao contrário, cada vez mais preso... me vejo tomado por uma completa indignação por fazer a mesma tarefa por quase 1000 vezes e digo a mim mesmo:
- basta! Vou automatizar isto!

Chega o momento de ver o que seria melhor. Com certeza o melhor é criar um sistema, baseado em uma base de dados, que concentre todas as informações de compra, inclusive passadas e que fosse integrada com a "maravilha" do ML... até fiz vários progressos nesse sentido, mas parei no ponto onde precisava alimentar a base com os dados que retirava de 5 (sim, cinco!) diferentes páginas do ML e mantê-los de uma forma racional e principalmente utilizável!

Optei, então, por me concentrar somente no simples problema de responder ao cliente com os dados de sua compra, como: onde pagar, o quanto pagar, onde fazer etc. Isso poderia simplesmente ser feito com um filtro no GMail, por exemplo e até soluções mais elaboradas via VBA, por exemplo, com o Outlook. Mas queria uma coisa que NÃO funcionasse totalmente por si só, que ainda precisasse de minha leitura prévia (e rápida). Por isso, já que atualmente ando trabalhando tanto com AJAX e naturalmente Javascript (como se nunca o tivesse feito antes [8 anos atrás já usava DHTML e AJAX, sem nem saber que o nome desse tipo de coisa era isso]) que fosse simples e perfeitamente integrado à minha rotina.

Após estudar as opções, resolvi botar o meu velho entusiamo no Greasemonkey para render algo e fui atrás de alguma alguma API do GMAIL que funcionasse bem com ele. Nessas horas, é ótimo descobrir que você é um tolo nada original, vi que já haviam criado tal API - algo simples, mas que resolve o mínimo. Daí então, foi só botar a mão em XPath, RegEx, DTHML/DOM e, claro, não poderia faltar, o Firebug.

Firebug

E é esse, meu pequeno legado, e sei que não evitará que ainda assim me chamem de pária ou até mesmo lammer, mas eventualmente, inspirará (nem que seja o desprezo) alguém. Não sei quantos programadores vendem no ML, mas deve ter mais alguém; creio.

À Programação

O Greasemonkey tem uma variável com um objeto mágico chamado de nome window que encapsula a window "real". Se quiser acessar o objeto window real, na verdade, terá que usar unsafeWindow. Isso vale para qualquer variável global, pois ela só estará acessível em unsafeWindow. Isso é causa de muita dor de cabeça para os iniciantes no Greasemonkey. Por exemplo, a instância do console do Firebug só existe em unsafeWindow.

EMail já preenchido com os dados do pedido

O GMail te disponibiliza o objeto unsafeWindow.gmonkey e é por meio dele que você interage com o DOM do GMail e particularmente, alguns de seus membros. Antes de avançar no uso de unsafeWindow.gmonkey, você vai precisar informar ao GMail que deseja (sim o suporte ao Greasemonkey, graças a um funcionário da Google, é da própria Google) carregar o módulo do GMonkey. Para mais informações, leia a:
API reference for version 1.0 of the experimental Gmail Greasemonkey API.

Após se obter acesso à DOM (DHTML) do GMail, o resto é trivial e atualmente, totalmente dependente da estrutura atual do GMail, ou seja, em futuras modificações do GMail, corre-se o risco do código que funcionava antes parar de funcionar.

Para flexibilizar e facilitar o acesso à DHTML do GMail, preferi o uso conjunto de XPath e RegEx pelo poder inerente dessas linguagens de consultas.

O funcionamento é basicamente clicar em "Reply" no e-mail que foi recebido do Mercado Livre (com os dados da compra do cliente) e ir até o Greasemonkey e acionar o comando "Preencher Dados de Compra". Com isso, de forma automática e quase mágica, todos os dados, de todos os campos, serão preenchidos, e, inclui, seguintes recursos:

  • Preenchimento do Nome/Email do destinatário (o cliente);
  • Suporte a uma template de resposta HTML onde todos os campos são preenchidos de forma automática. Os dados são obtidos do email original que foi enviado pelo ML;
  • Cálculo automático do total da compra e incluindo o frete (padrão) e quantidade adquirida.
   1:// ==UserScript==
   2:// @name           GMail - Pedidos do ML
   3:// @namespace      net.marciowb.gmail.ml.pedidos
   4:// @description    Me ajuda a preencher os pedidos do ML - by Marcio Wesley Borges<marciowb@gmail.com>
   5:// @include        http://mail.google.com/mail/*
   6:// ==/UserScript==
   7:
   8:const GMONKEYVER = "1.0";
   9:var gmail = null;
  10:var console = null;
  11:
  12:function evaluateXPath(xPath, aNode) {
  13:        if (!aNode) {
  14:                aNode=document;
  15:        }
  16:        var res = aNode.ownerDocument.evaluate(xPath, aNode, null, XPathResult.ANY_TYPE, null);
  17:        switch (res.resultType) {
  18:                case XPathResult.STRING_TYPE:
  19:                        return res.stringValue;
  20:                case XPathResult.NUMBER_TYPE:
  21:                        return res.numberValue;
  22:                case XPathResult.BOOLEAN_TYPE:
  23:                        return res.booleanValue;
  24:                default:;
  25:        }
  26:        var foundNodes = new Array();
  27:        var item = res.iterateNext(); 
  28:        while (item) {
  29:                foundNodes.push(item);
  30:                item = res.iterateNext();
  31:        }
  32:        return foundNodes;
  33:}
  34:
  35:/**
  36:* Obtém o elemento BODY do e-mail que está sendo composto (criado).
  37:*/
  38:function getComposingMailBody() {
  39:        if (!gmail)
  40:                return null;
  41:        var el = gmail.getActiveViewElement();  
  42:        if (!el)
  43:                return null;
  44:        var aa=evaluateXPath("//iframe[@id!='remote_iframe_0']", el);
  45:        if (!aa || aa.length==0)
  46:                return null;
  47:        var doc = aa[0].contentDocument;
  48:        if (!doc)
  49:                return null;
  50:        var body = doc.body;
  51:        return body;
  52:}
  53:
  54:/** 
  55:* Esta função é para ser chamada por dadosCompra().<br>
  56:* @param _gmail É fornecido automaticamente pela função gmonkey.load que chama esta.
  57:*/
  58:function _dadosCompra(_gmail) {
  59:        console = unsafeWindow.console;
  60:        gmail = _gmail;
  61:        
  62:        var bodyElem = getComposingMailBody();
  63:        if (bodyElem==null) {
  64:                window.alert("Antes, é necessário que  um reply no e-mail com os dados da compra do Mercado Livre");
  65:                return;
  66:        }
  67:        
  68:        
  69:        //Tenta obter o "quoted" mail que está sendo respondido
  70:        var aQuoted=evaluateXPath("//div[@class='gmail_quote']", bodyElem);
  71:        if (!aQuoted || aQuoted.length==0) {
  72:                window.alert("Não se deve apagar o quoted mail ainda.");
  73:                return;
  74:        }
  75:        var quotedMailBody = aQuoted[0].innerHTML;
  76:                
  77:        //Obtém o código do anúncio e nome do produto
  78:        var rgx = /;id=(\d*)[^>]*>([^<]*)/
  79:        var m = rgx.exec(quotedMailBody);
  80:        if (!m || m.length<3) {
  81:                window.alert("Isto  funciona para os e-mails de compra do Mercado Livre.");
  82:                return;
  83:        }
  84:        var codAnuncio = m[1];
  85:        var nomeAnuncio = m[2];
  86:        
  87:        //Obtém o nome do comprador
  88:        rgx = /Nome:\s*<b\b[^>]*>(.*)<\/b>/
  89:        m = rgx.exec(quotedMailBody);
  90:        var nomeComprador = m[1];
  91:        
  92:        //Obtém o código, apelido e pontuação do comprador
  93:        rgx = /Apelido:.*id=(\d*)".*[^>]>(.*) \((\d*)\)/
  94:        m = rgx.exec(quotedMailBody);
  95:        var codComprador = m[1];
  96:        var apelidoComprador = m[2];
  97:        var pontuacaoComprador = m[3];
  98:        
  99:        //Obtém a quantidade de produtos comprados
 100:        rgx = /Quantidade:\s*(\d*)/
 101:        m = rgx.exec(quotedMailBody);
 102:        var quantidade = m[1];
 103:        
 104:        //Obtém o preço pelo qual o cliente comprou o produto
 105:        rgx = /Preço:\s*([^<]*)/
 106:        m = rgx.exec(quotedMailBody);
 107:        var descPreco = m[1].replace("R$","").replace("unit.","");
 108:        
 109:        //Obtém o e-mail do comprador
 110:        rgx = /E-mail:[^>]*>([^<]*)/i
 111:        m = rgx.exec(quotedMailBody);
 112:        var emailComprador = m[1];
 113:        
 114:        //Obtém o telefone do comprador
 115:        rgx = /Telefone:\s*([^<]*)/
 116:        m = rgx.exec(quotedMailBody);
 117:        var telefoneComprador = m[1];
 118:        
 119:        //Obtém a cidade do comprador
 120:        rgx = /Cidade:\s*([^<]*)/
 121:        m = rgx.exec(quotedMailBody);
 122:        var cidadeComprador = m[1];
 123:        
 124:        //Obtém o estado do comprador
 125:        rgx = /Estado:\s*([^<]*)/
 126:        m = rgx.exec(quotedMailBody);
 127:        var estadoComprador = m[1];
 128:        
 129:        //Obtém o país do comprador
 130:        rgx = /País:\s*([^<]*)/
 131:        m = rgx.exec(quotedMailBody);
 132:        var paisComprador = m[1];
 133:
 134:        //////////////////////////////////////  
 135:        var VLR_MIN = 4; //Valor mínimo da compra. Isto é realizado por segurança nossa e o objetivo é evitar que um erro qualquer nos cause prejuízo.
 136:        var TIP_FRETE = "Frete por SEDEX";
 137:        var VLR_FRETE = "23.00";
 138:        
 139:        var vlrTotal = (Number(descPreco) * Number(quantidade)) + Number(VLR_FRETE);
 140:        if (vlrTotal<VLR_MIN) {
 141:                window.alert("Erro: o valor total da compra está sendo computado como: " + vlrTotal);
 142:                return;
 143:        }
 144:        
 145:        var TEMPLATE = '<div>Oi,<br> <br> &nbsp;&nbsp; Td blz?<br><br></div><span style="color: rgb(0, 102, 0);">&nbsp;&nbsp; É o seguinte, informa aí:<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Nome: @NOME_COMPRADOR</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">Endereço:</span></span><br style="font-family: courier new,monospace;"><span style="color: rgb(0, 102, 0);"><span style="font-family: courier new,monospace;">Bairro: </span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">Cidade/Estado: @CIDADE_COMPRADOR-@ESTADO_COMPRADOR </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">CEP: </span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">APELIDO: @APELIDO_COMPRADOR </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">CPF: </span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">TEL: @TELEFONE_COMPRADOR </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">E-MAIL: @EMAIL_COMPRADOR </span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">FORMA DE PAGAMENTO: </span><br><br>E se tu tivé uma companhia, diz, também:<br><span style="font-family: courier new,monospace;">Nome da Empresa: </span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">CNPJ: </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Inscrição Estadual: </span><br></span><br><b style="color: rgb(0, 102, 0);">Importante: </b><span style="color: rgb(0, 102, 0);"><br> Nessa, você  levando:<pre> <br><table border="1" cellspacing="0" cols="3" style="font-family: courier new,monospace;font-size:9pt" rules="groups" width="100%" frame="void"><tbody> <tr> <td width="35" align="right"><b>Qnt.</b></td> <td  align="right" width="94"><b>Valor</b></td> <td align="left"><b>Descrição</b></td> </tr> <tr> <td width="35" align="right">@QNT_PRODUTO</td> <td align="right" >@VALOR_PRODUTO</td> <td>@NOME_PRODUTO</td> </tr> <tr> <td width="35" align="right">@QNT_FRETE</td> <td align="right" >@VALOR_FRETE</td> <td>@TIPO_FRETE</td> </tr> <tr> <td bgcolor="#e6e6e6" align="right" height="16"><b>@QNT_TOTAL</b></td> <td bgcolor="#e6e6e6" align="right" ><b>@VALOR_TOTAL</b></td> <td bgcolor="#e6e6e6"><font size="2"><b>Total</b></font></td> </tr> </tbody> </table><font face="monospace"><br></font></pre> &nbsp;&nbsp; É isso, aí.<br>Valeu brother,<br> Ful. de Talz';
 146:        var emailBody = TEMPLATE
 147:                .replace("@NOME_PRODUTO", (nomeAnuncio+" #"+codAnuncio))
 148:                .replace("@VALOR_PRODUTO", descPreco)
 149:                .replace("@QNT_PRODUTO", quantidade)
 150:                .replace("@QNT_FRETE", "1")
 151:                .replace("@VALOR_FRETE", VLR_FRETE)
 152:                .replace("@TIPO_FRETE", TIP_FRETE)
 153:                .replace("@QNT_TOTAL", (Number(quantidade)+1))
 154:                .replace("@VALOR_TOTAL", vlrTotal)
 155:                .replace("@EMAIL_COMPRADOR", emailComprador)
 156:                .replace("@TELEFONE_COMPRADOR", telefoneComprador)
 157:                .replace("@APELIDO_COMPRADOR", apelidoComprador)
 158:                .replace("@CIDADE_COMPRADOR", cidadeComprador)
 159:                .replace("@ESTADO_COMPRADOR", estadoComprador)
 160:                .replace("@NOME_COMPRADOR", nomeComprador);
 161:                
 162:        bodyElem.innerHTML = emailBody;
 163:        
 164:        //Tenta obter o campo de listagens dos e-mails dos destinatários
 165:        var el = gmail.getActiveViewElement();
 166:        var aTos=evaluateXPath('//textarea[@name="to"]', el);
 167:        if (!aTos || aTos.length<1) {
 168:                window.alert("Erro: não foi possível determinar onde está o campo relativo aos emails do destinatário. Isso pode ocorrer no caso do GMail mudar sua estrutura DHTML.");
 169:                return;
 170:        }
 171:        var to = aTos[0];
 172:        to.value = nomeComprador + "<" + emailComprador + ">";
 173:        
 174:        console.log("Viva Java! Viva a Liberdade! Reviva a SUN!");
 175:}
 176:
 177:function dadosCompra() {
 178:        unsafeWindow.gmonkey.load(GMONKEYVER, _dadosCompra);
 179:}
 180:
 181:GM_registerMenuCommand('Preencher Dados de Compra', dadosCompra); 
 182:

Caso alguém queira o script acima para o Greasemonkey, pode pegá-lo aqui:
Preenchimento automático de e-mail com os dados da compra do cliente do Mercado Livre.

Referências

Labels: ,

2008/11/13

Gotan Project - La Viguela

aquí me pongo a cantar
al compás de la vigüela
que al hombre que lo desvela
una pena extraordinaria
como el ave solitaria
con el cantar se consuela

vengan santos milagrosos
vengan todos en mi ayuda
que la lengua se me añuda
y se me turba la vista
pido a mi dios que me asista
y en esta ocasión me ayuda

aquí me pongo a cantar
al compás de la vigüela
que al hombre que lo desvela
una pena extraordinaria
como el ave solitaria
con el cantar se consuela
Gracias Daniel por la letra!

Labels: