Chamado clássico de segunda-feira: "o frete grátis some quando o cliente usa o cupom". Alguém já mexeu no CEP, no peso, na tabela de frete, e nada. Não tem nada quebrado — é a regra do core, escrita em uma linha só.
Quem decide isso é o Magento\OfflineShipping\Model\Carrier\Freeshipping. Ele compara o seu mínimo com o subtotal depois do desconto, e o cupom entra nessa conta antes do frete ser cotado.
A conta que o core faz
No método isFreeShippingRequired() do carrier, o valor comparado vem de $request->getPackageValueWithDiscount(). E esse número nasce no Magento\Quote\Model\Quote\Address, quando o endereço pede as cotações:
$baseSubtotalWithDiscount = $baseSubtotal + $this->getBaseDiscountAmount();
$request->setPackageValueWithDiscount($packageWithDiscount);O getBaseDiscountAmount() é negativo, então essa soma é uma subtração. Com o mínimo em R$ 250, a coisa fica assim:
| Subtotal | Cupom | Valor comparado | Frete grátis? |
|---|---|---|---|
| R$ 250,00 | nenhum | R$ 250,00 | sim |
| R$ 250,00 | 10% (−R$ 25,00) | R$ 225,00 | não |
| R$ 280,00 | 10% (−R$ 28,00) | R$ 252,00 | sim |
É por isso que o problema aparece só em alguns carrinhos e some em outros. Quem está bem acima do mínimo nem percebe; quem está raspando o limite perde o benefício no exato momento em que aplica o cupom.
Confira a configuração da sua loja
Três caminhos mandam nesse carrier. Veja os valores que estão valendo hoje:
php bin/magento config:show carriers/freeshippingO que interessa:
carriers/freeshipping/active— vem 0 de fábrica.carriers/freeshipping/free_shipping_subtotal— é o campo Minimum Order Amount no admin.carriers/freeshipping/tax_including— Include Tax to Amount.
O tax_including muda a base da comparação: ligado, o carrier passa a usar getBaseSubtotalWithDiscountInclTax(). Continua sendo o valor com desconto, só que agora com imposto embutido. Em loja brasileira, com preço já cheio na vitrine, ligar ou desligar costuma dar no mesmo — mas se a sua loja calcula imposto separado, esse campo muda quem ganha frete grátis.
No admin, tudo isso vive em Stores > Configuration > Sales > Delivery Methods > Free Shipping.
A saída é regra de carrinho
Não existe uma opção de "comparar antes do desconto" no carrier. Se você quer que o cupom não atrapalhe, tire a decisão do campo de mínimo e coloque numa regra de carrinho, que enxerga a condição que você quiser.
Em Marketing > Promotions > Cart Price Rules, crie a regra com:
- Condição: Subtotal igual ou maior que 250 — esse subtotal é o de antes do desconto do seu cupom, porque cada regra avalia a própria condição.
- Em Actions, campo Free Shipping: For shipment with matching items.
- Sem código de cupom, para valer sempre que a condição bater.
Duas coisas que derrubam essa montagem na prática. Primeira: o carrier Free Shipping precisa continuar ativo, senão a regra marca o pedido como frete grátis e não sobra método nenhum para o cliente escolher. Segunda: se a sua regra de desconto está com Discard subsequent rules em Yes, ela mata a regra de frete que vier depois na prioridade. Coloque a regra de frete com prioridade mais alta (número menor) ou desligue o descarte.
Eu prefiro esse desenho mesmo em loja que não usa cupom nenhum: o campo do carrier é rígido demais, e no dia em que o marketing quiser frete grátis só para o Sudeste, ou só acima de 3 itens, a regra de carrinho já está lá.
Perguntas rápidas
Dá para o Magento comparar o mínimo antes do desconto?
Pelo campo do carrier, não. O core lê sempre o subtotal com desconto. Para comparar antes, você precisa de uma regra de carrinho com condição de Subtotal, ou de um plugin no carrier, que eu não recomendo manter.
Ligar o Include Tax to Amount resolve?
Não resolve o problema do cupom. Esse campo só troca a base de subtotal com desconto para subtotal com desconto e imposto. O desconto continua sendo abatido nos dois casos.
A regra de carrinho aparece no checkout mas o frete continua cobrado. O que falta?
Quase sempre o carrier Free Shipping está desativado. A regra só marca o pedido como elegível; quem monta a linha de R$ 0,00 no checkout é o carrier. Ligue em Delivery Methods e limpe o cache.
Pra conferir na fonte
- Free Shipping — Adobe Experience League
- Create a cart price rule — Adobe Experience League
- Magento_OfflineShipping Carrier/Freeshipping.php — GitHub
- Magento_Quote Model/Quote/Address.php — GitHub