Pesquisa — Análise de Código: CRMBonus na API Checkout
Data: 2026-05-15
Contexto: Task #193232 — Análise do fluxo de integração CRMBonus
Fonte: coezzion-service-checkout/src/
Interface do Serviço
Arquivo: src/Checkout.Infraestructure/Integrations/CrmBonus/ICrmBonusService.cs
public interface ICrmBonusService
{
Task<HttpResponseMessage> DebitCrmBonusAsync(CrmBonutDTO crmBonus, int storeId);
Task<HttpResponseMessage> FinishCrmBonusAsync(CrmBonutDTO crmBonus, int storeId, int paymentId);
Task<HttpResponseMessage> CancelCrmBonusAsync(CancelBonusDTO cancelCrmBonus, int storeId, int paymentId);
}
DTOs
Arquivo: src/Checkout.Domain/DTO/CrmBonus/CrmBonutDTO.cs
// Usado em DebitCrmBonusAsync e FinishCrmBonusAsync
public class CrmBonutDTO
{
public int user_Id { get; set; }
public decimal valor_bruto { get; set; }
public decimal bonus_resgatado { get; set; }
public string ids_bonus { get; set; }
public string ticket { get; set; } // = paymentIdComplex (código composto do pedido)
public string? campanha { get; set; } // "-1" se campanha == 0, senão "0"
}
// Usado em CancelCrmBonusAsync
public class CancelBonusDTO
{
public string num_pedido { get; set; } // = paymentIdComplex
public bool used_bonus { get; set; } // true = pós-finalização; false = pré-finalização
}
Arquivo: src/Checkout.Domain/DTO/CrmBonus/CrmBonusConfig.cs
public class CrmBonusConfig
{
public string BaseURL { get; set; }
public string Authorization { get; set; }
}
// Configurado via appsettings na seção: Apis:CrmBonus
Implementação do Serviço
Arquivo: src/Checkout.Infraestructure/Integrations/CrmBonus/CrmBonusService.cs
Mecanismo de Autenticação
Dois headers são enviados em cada requisição:
| Header | Valor |
|---|---|
Authorization | Valor fixo da configuração CrmBonusConfig.Authorization |
Codempresa | Base64(tokenCrm) — tokenCrm obtido em runtime via IStorePaymentsRepository.GetTokenCrmByIdAsync(storeId) |
Validação de Resposta — IsCrmBonusValidResponse
Extension method que define o critério de sucesso:
// Resposta válida = HTTP 2xx E body JSON com { "status": true }
public static bool IsCrmBonusValidResponse(this HttpResponseMessage response)
Ambas as condições são obrigatórias. Uma resposta HTTP 200 com "status": false no body é considerada inválida.
Comportamento de Erros por Operação
| Operação | Comportamento em erro |
|---|---|
DebitCrmBonusAsync | Valida bonus_resgatado > 0 antes de enviar; loga resposta |
FinishCrmBonusAsync | Captura HttpRequestException com log detalhado; não lança exceção para cima |
CancelCrmBonusAsync | Loga a ação após a resposta |
Mapa Completo de Callers
DebitCrmBonusAsync — Reserva de bônus
| Caller | Arquivo | Condição de guarda |
|---|---|---|
CreatePaymentCommandHandler | Application/Messages/Commands/CreateCommands/CreatePaymentCommandHandler.cs | cart.CrmBonus != null |
Contexto: Chamado ao criar o pedido (Handle(CreatePaymentByAppCommand)). O debit ocorre antes de qualquer processamento de pagamento. Uma falha não bloqueia a criação do pedido — é logada via ILogQueueService.
FinishCrmBonusAsync — Efetivação do consumo
| Caller | Arquivo | Condição de guarda |
|---|---|---|
PosCaptureService | Application/Services/PosCaptureService.cs | cart.CrmBonus != null && !string.IsNullOrEmpty(cart.CrmBonus.IdsBonus) |
Contexto: Passo 4 de ExecutePosCapture. Chamado após captura bem-sucedida do pagamento.
PosCaptureService é invocado por:
AntiFraudWebhookService(aprovação pelo antifraude)PagarMeCaptureService(captura PagarMe)OrderCommandHandler(captura Braspag)WebhookBraspagService,PagarMeCreditCardService,PagarMePixService,FinishPaymentService
Montagem do DTO em PosCaptureService:
var crmBonus = CrmBonutDTO.CreateFromCrmBonus(
cart.CrmBonus.UserId,
cart.CrmBonus.Total,
cart.CrmBonus.RescuedBonus,
cart.CrmBonus.IdsBonus,
paymentIdComplex,
Convert.ToInt32(cart.GenerateCrmBonus));
CancelCrmBonusAsync — Cancelamento/liberação
| Caller | Arquivo | used_bonus | Cenário |
|---|---|---|---|
OrderCommandHandler | Application/Messages/Commands/OrderCommands/OrderCommandHandler.cs | true | Cancelamento manual do pedido |
OrderCommandHandler | idem | true | Falha na captura Braspag |
AntiFraudWebhookService | Integrations/Clearsale/AntiFraudWebhookService.cs | true | Falha na captura Braspag pós-aprovação antifraude |
Semântica do Parâmetro used_bonus
O parâmetro used_bonus no CancelBonusDTO informa ao CRM&Bonus se o bônus chegou a ser efetivado antes do cancelamento.
| Valor | Significado | Quando ocorre no código |
|---|---|---|
true | Bônus foi efetivado (finaliza_compra já foi chamado) | Cancelamento manual pós-aprovação; falha de captura Braspag pós-aprovação antifraude |
false | Bônus foi apenas reservado (baixa_bonus chamado, finaliza_compra ainda não) | Antifraude recusou; captura PagarMe falhou |
Atenção: O código atual em
AntiFraudWebhookServiceenviaused_bonus = truepara o cenário de falha de captura Braspag — não para rejeição pelo antifraude. Para PagarMe com antifraude reprovado, o cancelamento não é chamado diretamente peloAntiFraudWebhookService; delega aoPagarMeRefundService.
Inconsistência com Documentação Anterior (crm_analise.md)
O arquivo docs/crm/crm_analise.md contém uma imprecisão:
Afirma:
AntiFraudWebhookService→used_bonus = falsequando "o antifraude recusa a transação"
Código real:
AntiFraudWebhookServicechamaCancelCrmBonusAsynccomused_bonus = trueapenas no fluxo Braspag quando a captura falha (não quando o antifraude recusa). Para PagarMe, a responsabilidade é doPagarMeRefundService.
Condições de Guarda Relevantes
DebitCrmBonusAsync: Só é chamado secart.CrmBonus != null. Internamente, só faz a requisição HTTP sebonus_resgatado > 0.FinishCrmBonusAsync: Só é chamado secart.CrmBonus != null && !string.IsNullOrEmpty(cart.CrmBonus.IdsBonus).CancelCrmBonusAsync: Só é chamado secart.CrmBonus != null(verificado emCancelBonusAsyncprivado doOrderCommandHandler).
Campo paymentIdComplex
O identificador ticket/num_pedido enviado ao CRM&Bonus é um código composto, não o ID numérico direto do pedido. É gerado pelo serviço ICreateCodePaymentsForIntegrations.CreateCodePayment(orderId).