Viabilidade — MB-476: Recebimento no Fluxo e Antecipação de Recebíveis

Tarefa: MB-476 — "[AppControl] Recebimento no Fluxo e Antecipação" Repositórios: tickets-apiv2 (backend NestJS), tickets-appprodutor (app Flutter), tickets-dashboard (admin Vue) Status: Viável, com alterações significativas nas três camadas (detalhes abaixo)


1. Objetivo da tarefa

Permitir que o produtor anticipe vendas parceladas (cartão) com juros por período, escolhendo:

Regra central definida pelo time de produto:

Por padrão, todos os eventos seguem o fluxo atual (recebimento automático via split PagarMe + retenção de 24h + saque pelo availableBalance). Somente quando o evento NÃO estiver com a flag de recebimento/antecipação automática habilitada, o app apresenta o "fluxo de recebimento": produtor vê recebíveis (disponíveis + futuros), simula a antecipação e solicita saque com juros.

Recapitulação de produto: se o evento NÃO tiver recebimento automático, a retenção passa a incidir SOMENTE sobre PIX — não faz sentido reter cartão, pois ele será recebido pelo fluxo de antecipação.


2. Como funciona hoje (linha base)

2.1. Ciclo financeiro

  1. Venda → pedido criado no PagarMe com split (PagarMeSplitConfig) entre recebedores:
    • Seller (produtor), Taxes (impostos), além do recebedor da própria plataforma.
    • src/modules/payment/payment-gateway-services/pagar-me/pagar-me.service.ts (getPagarMeRecipientConfig).
  2. Fechamento (closing-calculation.service.ts) monta o ClosingSummaryDto:
    • totalSalesWithoutFees, totalPaymentFees, totalInstallmentFeeAmount, companyOwedAmount, availableBalance.
    • salesByPaymentMethod[]já discrimina por método (paymentType: Pix, Credit, Debit, ...) com total e totalFee. É a base para a retenção seletiva.
  3. Saldo (event-balance.service.ts buildBalance) → ResponseEventBalanceDto:
    • summary (com availableBalance), commercialConditions, financialUserId, retention {active, pct, amount}.
    • Endpoint: GET /event-balance/:eventId.
  4. Retenção (documentada em documentation/producer-withdrawal-rules.md):
    • Ativa até 24h após o evento (base = dateEndEvent ?? dateStartEvent, com ajuste -3h de timezone).
    • retencao = totalSalesWithoutFees × retentionPct / 100; availableBalance -= retencao.
    • Se não há dateStartEvent, retenção fica ativa permanentemente.
  5. Saque (producer-withdrawal.service.ts):
    • Valida pin == passwordWithdraw, permissão financeiro/admin e value <= availableBalance.
    • Cria saque pending → admin conclui (/complete) via MercadoPago, Sicoob ou Manual → webhook atualiza para paid.
    • Tipos: ProducerWithdrawalTypeEnum { normal, advanced }advanced já existe no enum, mas NÃO é usado em lugar nenhum (nem no backend, nem no app, nem no dashboard).

2.2. Exposição atual


3. Mudança proposta

3.1. Nova flag de evento

Reutilizar o mecanismo existente getEventFlag(event, flag, defaultValue) (src/common/utils/event-flags.ts), que lê event.flags (JSON):

// Proposta de nome — a definir com produto
const automaticReceipt = getEventFlag<boolean>(
  event, 'antecipacao_habilitada', /* default: */ true,
);

A flag precisa ser editável em dashboard admin (novo campo na tela de condições comerciais ou flags do evento) e propagada em event.flags via PATCH de evento (campo flags já existe no create-event.dto.ts / response-event.ts).

3.2. Retenção seletiva (PIX apenas)

No event-balance.service.ts (buildBalance), quando o evento não tem recebimento automático:

// Base atual: retenção sobre o total (cartões + PIX + demais)
const base = sumary.totalSalesWithoutFees;

// Proposta (fluxo de recebimento): base = apenas PIX, líquido de taxas
const pixSales = closing.salesByPaymentMethod
  .filter((m) => m.paymentType === PaymentMethodType.Pix)
  .reduce((acc, m) => acc + (m.total - m.totalFee), 0);

const retentionBase = automaticReceipt ? sumary.totalSalesWithoutFees : pixSales;
retentionAmount = (retentionBase * commercialConditions.retentionPct) / 100;
sumary.availableBalance -= retentionAmount;

ClosingService.calculate já retorna o EventClosingCalculationDto com salesByPaymentMethod — basta expor/consumir o array no serviço de saldo (hoje buildBalance só usa closing.summary).

3.3. Fluxo de recebimento (novos dados para o app)

Novo endpoint de leitura (ex.: GET /event-balance/:eventId/receivables ou extensão do DTO de saldo) retornando:

Fonte de dados: PagarMe já está integrado via PagarmeApiClient com:

Lacuna: o cliente atual NÃO possui chamada à API de antecipação do PagarMe (POST /anticipations, POST /recipients/:id/anticipations etc.). Precisa ser adicionada ao PagarmeApiClient + service para: criar antecipação, listar GET /anticipations e receber status via webhook.


4. Impacto por camada

4.1. tickets-apiv2 (backend)

Área Arquivo Mudança
Flag src/common/utils/event-flags.ts + event.entity.ts Criar/ler flag antecipacao_habilitada (campo flags já existe).
Retenção seletiva src/modules/event/event-balance/event-balance.service.ts Quando sem recebimento automático, calcular retenção sobre PIX (salesByPaymentMethod). Precisa que ClosingService.calculate exponha o array (já retorna via EventClosingCalculationDto).
DTO saldo src/modules/event/event-balance/dto/response-event-balance.dto.ts Adicionar bloco de recebíveis/antecipação quando flag ativa.
Recebíveis pagarme-api.client.ts + pagar-me.service.ts Novo: método getAnticipations/createAnticipation (API de antecipação PagarMe) e consolidação de recebíveis por parcela.
Saque c/ juros producer-withdrawal (service, DTOs, webhook) Passar a usar ProducerWithdrawalTypeEnum.advanced (já definido) e calcular juros (advanceTaxPct) no valor; validação contra recebíveis antecipáveis e não só availableBalance.
Webhook producer-withdrawal.controller.ts Tratar status de antecipação do PagarMe (criada/efetivada).

4.2. tickets-appprodutor (Flutter)

Área Arquivo Mudança
Model de saldo extract/data/models/extract_event_balance_entity.dart Ler novo bloco de recebíveis/antecipação.
Extrato extract/ui/extract_page.dart Se flag sem recebimento automático, apresentar "fluxo de recebimento": recebíveis disponíveis + futuros e simulação de antecipação (valor hoje × juros por período).
Saque cash_withdrawal/ (value step / cubit) Novos passos: seleção de recebíveis/parcelas a antecipar e exibição de juros; tipo advanced.
Home/entradas home/ui/... Badge/sinalização quando o evento usa fluxo de recebimento.

4.3. tickets-dashboard (admin)

Área Arquivo Mudança
Condições comerciais EventCommercialConditions.vue, ProducerCommercialConditions.vue Já existem Taxa de Antecipação (%), Adiantamento (R$), Valor Total do Advanced (R$). Faltam a flag de recebimento automático e a gestão de antecipações (visualizar pedidos de antecipação, status).
Financeiro event-balance/EventBalancePage.vue, WithdrawalList.vue Lista de antecipações (tipo advanced já mapeado no enum do dashboard).

5. Riscos e pré-requisitos

  1. Anexo PDF do MB-476 inacessível (You do not have permission to view attachment with id: 18304). As telas de referência do fluxo de recebimento não puderam ser validadas; documentação baseada na descrição do ticket.
  2. Integração de antecipação PagarMe ausente — é o maior esforço de backend (API de antecipações + webhook + regras de taxa/teto).
  3. Definição da flag: nome (antecipacao_habilitada vs recebimento_automatico), default (true), escopo (evento e/ou produtor) e UI de edição.
  4. Fórmula da retenção PIX: confirmar se a base é o total PIX líquido de taxas (recomendado, espelhando totalSalesWithoutFees) e se débito/crédito à vista entram no "fluxo" (cartão) ou no disponível.
  5. Retenção de 24h + recebíveis: alinhar como os dois mecanismos interagem no fluxo sem recebimento automático (PIX retido 24h; cartão segue fluxo de antecipação).
  6. Não há trabalho anterior (sem branches/PRs) — greenfield nas três camadas.

6. Recomendação de implementação (ordem sugerida)

  1. Backend — fundamentos: flag antecipacao_habilitada + retenção seletiva PIX (event-balance.service.ts) + exposição de salesByPaymentMethod via ClosingService.
  2. Backend — recebíveis/antecipação: métodos PagarMe (getPayables p/ futuros, createAnticipation), DTO de recebíveis, uso do tipo advanced no saque e webhook.
  3. App produtor: modelo de recebíveis + fluxo de recebimento no extrato e no saque (simulação de antecipação).
  4. Dashboard: flag nas condições comerciais + gestão de antecipações no financeiro.
  5. Testes: atualizar event-balance.service.spec.ts (retensão PIX vs total), testes de fechamento e novos testes de antecipação.