R-001 — Desconto de membro exige validação do email no servidor
TLDR: o desconto só é aplicado quando o serviço de validação confirma que o email é de membro; qualquer outra resposta — inclusive falha — resulta em preço cheio.
Given / When / Then
Dado um checkout com discount_amount > 0 e discount_validation_url presente (discount_enabled?),
Quando o comprador submete a compra com um email que o serviço de validação responde 200 + { "valid": true },
Então o discount_amount é abatido da base antes do cálculo dos juros de parcelamento, e o total descontado é o que vai para @payment.total e para o totalValue do gateway.
Dado o mesmo checkout,
Quando a validação responde valid: false, não-200, dá timeout (5s) ou lança erro,
Então o preço cheio é cobrado.
Dado um checkout sem discount_validation_url,
Quando qualquer compra é feita,
Então o serviço de validação não é instanciado e o total é exatamente o de um checkout sem desconto.
Tabela de decisão
discount_enabled? |
Resposta da validação | Resultado |
|---|---|---|
false |
(nenhuma chamada é feita) | Preço cheio |
true |
200 + { "valid": true } |
Desconto abatido da base |
true |
200 + { "valid": false } |
Preço cheio |
true |
Status não-200 | Preço cheio |
true |
Timeout (5s) | Preço cheio |
true |
Corpo não é JSON válido | Preço cheio |
Restrições
- A validação é sempre refeita no servidor no momento da compra. O frontend nunca controla o total.
- O fallback é seguro por construção: toda falha resulta em preço cheio, nunca em desconto indevido.
- O token vai no header fixo
X-DISCOUNT-ACCESS-TOKEN, lido decheckouts.discount_access_token— é por checkout, não global. - A regra vale apenas no fluxo v1 de compra (
CheckoutService). O fluxo v2 (Payments::Creation::CreateFlow) não consulta o desconto. - Cross-sell (
cross_sell_items) não recebe desconto. - A revalidação no submit abre uma janela: se a validação passa na digitação e falha na compra, o cliente vê preço com desconto e é cobrado preço cheio, sem aviso.
Teste vinculado
spec/services/checkout_service_spec.rb — “applies the discount to the payment total when the email is a valid member”
spec/services/checkout_service_spec.rb — “sends the discounted total to the gateway when the email is a valid member”
spec/services/checkout_service_spec.rb — “keeps the full total when the email is not a valid member”
spec/services/checkout_service_spec.rb — “applies the discount to the checkout payment type total when the checkout uses payment types”
spec/services/checkout_service_spec.rb — “does not instantiate the validation service and keeps the full total when the checkout has no discount url”
spec/services/member_discount_validation_service_spec.rb — “returns false without calling the endpoint when the discount is not enabled”
spec/services/member_discount_validation_service_spec.rb — “returns false when the request times out”
Referências
- ../../reference/checkout/member_discount.md — comportamento completo, contrato HTTP e pontos de código
- ../../learnings/checkout_fixed_discount_must_be_applied_on_base.md — por que o desconto abate a base, e não o total final