HSM / Singularity
Duas marcas de educação numa vitrine headless que construí sozinho, com um app próprio que retém tributos federais no checkout quando quem compra é uma empresa.
- Cliente
- HSM · Singularity
- Papel
- Sozinho: vitrine, componentes, app de imposto e formulários
- Ano
- 2026
- Stack
- Shopify HydrogenReact Router 7OxygenShopify FunctionsCheckout UI extensionsMetaobjectsSalesforce APITypeScript
O que foi meu
- 01A vitrine inteira, sozinho: duas marcas de educação num build Hydrogen headless.
- 02O app de retenção de tributos: Functions de desconto e de validação, extensão de checkout e configuração no admin.
- 03Formulários feitos de metaobjects que entregam leads no Salesforce sem perder nenhum.
Problema ·Quando uma empresa compra um curso no Brasil, parte dos tributos federais precisa ser retida do preço. O checkout do Shopify não tem como fazer isso.
FIG. 3O CNPJ de uma empresa vira uma linha de retenção no checkout.
Compre como empresa
Quando uma empresa compra, os tributos federais são retidos na fonte: ela paga o pedido menos a retenção. As configurações de imposto do Shopify só sabem somar. Digite um CPF, um CNPJ válido ou um quebrado, e mova o valor do pedido entre as faixas.
Simulação. Dados ilustrativos, mecanismo real.
Faixas ilustrativas: abaixo de R$ 250 → 0 · até R$ 5.000 → 5% · acima → 6,5%
- Subtotal
- R$ 1.890,00
- Retenção na fonte · 5%
- − R$ 94,50
- Total
- R$ 1.795,50
Empresa acima da primeira faixa: a Function de desconto devolve a retenção como valor fixo.
Contexto
HSM e Singularity são duas marcas de educação executiva, com cursos e eventos, vendidas a partir de um admin Shopify. Construí a vitrine headless sozinho, em Hydrogen sobre React Router 7: um código só, publicado como duas vitrines no Oxygen, com as seções, os formulários e um app próprio para impostos.
O problema técnico central
Quando uma empresa compra no Brasil, parte dos tributos federais é retida na fonte: ela paga o pedido menos a retenção e recolhe o resto direto com a Receita. O Shopify não tem esse conceito. As configurações de imposto dele só somam imposto, não subtraem, e não mudam conforme quem está comprando. E o valor que o checkout mostra precisa bater com a nota no centavo.
O que eu construí
- Retenção como desconto, numa Shopify FunctionA regra roda numa Function de desconto e devolve um valor fixo no pedido, com o nome “Retenção na fonte”. Ela considera faixas de valor, a isenção parcial de quem é optante do Simples Nacional e três formas de reconhecer uma compra de empresa: o CNPJ, uma tag de cliente ou uma empresa B2B.
- CNPJ validado no campo nativoUma Function de validação confere os dígitos verificadores e trava o checkout antes do pagamento quando o número está malformado.
- Uma extensão de checkout que mantém a Function em diaA Function não enxerga o campo nativo de documento ao vivo. A extensão copia o CNPJ para um metafield do carrinho, cada escrita roda a regra de novo, e a própria extensão mostra o detalhamento por tributo.
- Alíquotas como dadoFaixas e alíquotas ficam num JSON em metafield que a Function, a extensão e um formulário no admin leem. Mudar uma alíquota é editar o admin, sem deploy.
- Formulários feitos de metaobjects, entregues no SalesforceCampos e etapas são metaobjects, e cada produto escolhe o seu formulário. O servidor refaz a validação a partir da definição do admin e cria o lead no Salesforce por OAuth. Se o CRM recusa um valor, ele vai para a descrição e o envio é repetido, então um erro de digitação no admin não perde lead.
- Duas marcas, um buildA marca é resolvida em tempo de execução pelo ambiente, o tema é isolado por atributo no HTML, e os e-mails transacionais das duas marcas saem do mesmo conjunto de templates.
Por que foi feito assim
- Desconto, porque imposto no Shopify só sobeModelar a retenção como desconto de pedido com valor fixo é o jeito de o total do checkout mostrar o que a empresa realmente paga.
- Centavos inteiros nas duas pontasA Function e a extensão calculam separadas. Com ponto flutuante, em alguns totais elas discordariam em um centavo na frente do cliente. As duas usam a mesma conta em inteiros, com arredondamento half-up.
- A definição do formulário vale no servidorA validação é refeita a partir do admin, então o cliente não pula campo obrigatório, e quem edita o formulário não depende de deploy.
- Falhar com calma no CRMCRM recusa valor de lista o tempo todo. Um lead perdido custa mais que uma descrição bagunçada.
Status
Em desenvolvimento, antes do lançamento nos domínios finais. As vitrines rodam em deploys de preview e o app de imposto já está instalado na loja.