O problema
Persiana é produto sob medida: o preço sai de uma fórmula com largura, altura, tecido, bandô e acionamento. Plataforma de e-commerce trabalha com variante fixa cadastrada, não com fórmula. Na prática o cliente pedia orçamento por WhatsApp e alguém calculava na mão.
O frete tinha o mesmo problema por outro caminho. Uma persiana de 1,50 m vira um tubo de 155 cm, e a transportadora expressa configurada na loja cotava R$ 8.911 por peça. Não era bug: as dimensões estavam certas e o pacote é que estourava o limite daquela modalidade.
O que construí
- Configurador na página do produto, dentro do template Twig da loja, com o preço se atualizando a cada escolha de medida, tecido, cor, bandô e acionamento.
- Worker de precificação e variantes, que recebe a configuração, aplica a regra de negócio e cria a variante correspondente via API REST, para o item configurado existir de verdade no carrinho.
- Cotação de frete ao vivo: o Worker está registrado na loja como transportadora, então o checkout chama ele, que cota na Braspress e devolve valor e prazo reais.
- Preço dos cards da home calculado no template a partir do valor cadastrado no painel, para o dono da loja reajustar em um lugar só e os 17 produtos acompanharem.
Decisões técnicas
Não fugir do checkout da plataforma. A tentação era montar um carrinho paralelo. Isso teria quebrado cupom, frete, relatório e integração fiscal, tudo que a loja já fazia. Criar a variante sob demanda foi mais trabalho no começo e menos problema para sempre.
Credencial de transportadora não passa pelo tema, e cotação que falha não derruba a venda. Quem fala com a Braspress é o Worker, então usuário e senha nunca chegam ao navegador. E quando a cotação falha, a resposta volta com a lista de fretes vazia em vez de erro: o comprador perde uma opção de entrega, não a compra.
Dimensão de envio declarada, não calculada. A primeira versão derivava peso e volume da área da peça. Só que a operação embala tudo no mesmo tubo, então passei a declarar a embalagem real, com o comprimento saindo da largura da persiana. O frete cobrado não mudou, porque em toda a faixa de tamanho a transportadora cobra pela cubagem, e o número passou a descrever o que sai do galpão.
A regra de negócio virou documento antes de virar código. Toda mudança na fórmula de preço entrava primeiro na documentação e só depois no Worker. Sem isso não há como saber se um preço estranho é bug ou é a regra, e com produto sob medida essa dúvida aparece toda semana.
Rastreamento inteiro dentro de try/catch. O configurador envia o pedido por requisição própria e, com isso, pulava a camada de métricas da plataforma: os 17 produtos registravam visita e compra, sem nada no meio. Acrescentei o disparo do evento à mão, isolado, porque uma falha de analytics não pode impedir alguém de comprar.
Como verifiquei
A cor que sumia do pedido. O dono da loja notou um pedido chegando sem a cor escolhida. Chamei a função de cálculo do próprio configurador ao vivo em três páginas de produto e as três devolveram o nome da variante sem a cor. Não era caso isolado: desde uma mudança feita seis semanas antes, quando cada cor virou um produto separado, todo pedido saía assim. O seletor de cor era limpo pelo próprio redirecionamento que levava o comprador até a página da cor.
A correção passou a derivar a cor da URL da página. Foi escolha deliberada não usar o nome do produto: o manual de operação entregue ao cliente já pede para não alterar URLs, enquanto o nome ele mexe por SEO, e casar pelo nome faria a cor sumir de novo em silêncio na primeira renomeação. Antes do deploy, validei nas páginas reais, incluindo de propósito duas cores de nome parecido para confirmar que não se confundiam.
O acréscimo que parecia crescer. Um adicional aparecia como ”+ R$ 98,00/m” numa persiana de 1,40 m, o que dava a impressão de uma taxa que subia com o tamanho. Comparei o preço final com e sem o acessório em três larguras diferentes: a diferença dividida pela largura deu exatamente a mesma taxa nas três. A cobrança estava certa desde o começo e só o rótulo estava errado, então a correção foi no texto e não no cálculo.