Docs›Componentes (Admin)›mad-reconcile
Componentes (Admin)

mad-reconcile

Conciliação em dois painéis: auto-match por regras (MatchEngine), match manual N:M e desfazer.

Tela de conciliacao em dois paineis: de um lado as linhas nao conciliadas de um model (extrato bancario), do outro as de outro model (lancamentos contabeis). Auto-match por regras, match manual N:M com tolerancia e desfazer. Uma tag declarativa sem filhos.

Compilador: Mad\Reconcile\MadReconcileCompiler (passo 1.09 do MadBlade). Componente: Mad\Reconcile\MadReconcile. Motor de sugestao: Mad\Reconcile\MatchEngine. Sem host proprio, o compiler instancia um Mad\Reconcile\MadReconcileStandalone.

Tag

<mad-reconcile left-model="BankStatementLine" right-model="LedgerEntry"
               database="business"
               left-amount="valor"  right-amount="valor"
               left-date="data"     right-date="data_lancamento"
               left-doc="documento" right-doc="documento"
               left-title="Extrato" right-title="Razao"
               match-on="amount,date:3,document"
               tolerance="0.01" max-rows="500"
               context="banco-conta1" />

Aceita forma self-closing ou par de tags; nao tem filhos.

Props

Prop Tipo Default Descricao
left-model string — Model do painel esquerdo. Obrigatorio
right-model string — Model do painel direito. Obrigatorio
database string MAIN_DATABASE Conexao
match-on string amount Regras do auto-match: amount, date:N, document (separados por virgula)
left-amount string valor Campo de valor do lado esquerdo
right-amount string valor Campo de valor do lado direito
left-date string '' Campo de data (esquerdo)
right-date string '' Campo de data (direito)
left-doc string '' Campo de documento (esquerdo)
right-doc string '' Campo de documento (direito)
left-label string '' Campo de descricao exibido (esquerdo)
right-label string '' Campo de descricao exibido (direito)
left-title string nome do model Titulo do painel esquerdo
right-title string nome do model Titulo do painel direito
tolerance float 0.0 Tolerancia de diferenca de soma no match manual
max-rows int 500 Cap de linhas carregadas por painel
context string '' Namespace da conciliacao — separa grupos de conciliacoes diferentes

Fluxo

  1. Paineis com as linhas nao conciliadas (data, documento, descricao, valor), filtro client-side e contador por painel.
  2. Auto-match (onAutoMatch) roda o MatchEngine e grava grupos com status suggested. Cada sugestao vira um card com score, somas dos dois lados e botoes Confirmar / Rejeitar (mais "Confirmar tudo" na toolbar).
  3. Match manual — o usuario clica linhas nos dois paineis; a toolbar mostra NxM e a diferenca ao vivo. "Conciliar selecao" so habilita com |somaL - somaR| <= tolerance e grava direto como confirmed (onManualMatch, aceita N:M).
  4. Conciliados — secao com os grupos confirmados e Desfazer (onUnmatch), que apaga o grupo e devolve os registros aos paineis. Rejeitar sugestao e onRejectGroup.

MatchEngine

Tokens de match-on: amount (implicito, sempre ativo), date:N (tolerancia de N dias) e document (exige igualdade de documento no passe exato).

Passe Criterio Score
1 Valor exato + mesmo documento (ou mesma data, sem document) 100
2 Valor exato + data dentro da tolerancia (a mais proxima) 95 - 5 x dias (min 70)
3 N:1 por soma (ate 3 itens de um lado somando 1 do outro, nos dois sentidos) 70

Os passes sao greedy: cada registro entra em no maximo um grupo. O passe 3 e subset-sum e esta capado em 20 mil combinacoes por rodada — ao estourar, o usuario recebe um toast pedindo para rodar de novo depois de confirmar (flag truncated).

Persistencia e escopo

Grupos vivem em mad_reconcile_group (context, status suggested|confirmed, score, matched_by, matched_at) e itens em mad_reconcile_item (group_id, side L|R, record_table, record_id e snapshot do valor).

use Mad\Reconcile\MadReconcile;

class ConciliacaoBancaria extends MadReconcile
{
    protected static string $wrapper = self::INTERNAL;

    protected string $leftModel  = 'BankStatementLine';
    protected string $rightModel = 'LedgerEntry';
    protected string $matchOn    = 'amount,date:3,document';
    protected string $context    = 'banco-conta1';

    protected function leftQuery(\Illuminate\Database\Eloquent\Builder $q): void
    {
        $q->where('unit_id', MadSession::unitId());
    }

    protected function rightQuery(\Illuminate\Database\Eloquent\Builder $q): void
    {
        $q->where('unit_id', MadSession::unitId());
    }

    /** Depois de confirmar: baixar titulos, marcar flags, etc. */
    protected function afterConfirm(array $groupIds): void
    {
    }
}

Gotchas

  • Sem subclasse nao ha escopo. leftQuery/rightQuery sao os hooks anti-IDOR: registro fora do escopo nao aparece no painel e e recusado no onManualMatch (o whereIn roda sobre a query escopada e ja exclui os conciliados). Em multi-tenant/multi-unidade, use subclasse sempre.
  • As operacoes de grupo (onConfirmGroup, onRejectGroup, onUnmatch, onConfirmAll) sao travadas pelo context — grupo de outra conciliacao e ignorado. Duas telas de conciliacao na mesma base precisam de context distintos.
  • A validacao de soma do match manual roda no servidor; o client so pre-habilita o botao.
  • Valores negativos so casam com valores de mesmo sinal.
  • Atributo mad-* nao aceita {{ }} — use o prefixo dois-pontos para expressao PHP (:tolerance="$that->tol()").