MAD Lab
/
Tutor > Módulos visuais > Conciliação

Conciliação

Módulos visuais

mad-reconcile
Básico (zero PHP)

mad-reconcile só por valor — context próprio isola esta conciliação da de baixo, mesmo usando os mesmos models.

× — Difference:
Extrato bancário 4
TED Fornecedor Beta 980,00
PIX recebido cliente 250,75
Depósito consolidado 700,00
Tarifa bancária 24,90
Lançamentos 5
Pagto fornecedor Beta 980,00
Recebimento cliente 250,75
Venda balcão manhã 300,00
Venda balcão tarde 400,00
Aluguel sala 9 1.500,00
resources/views/tutor/examples/modulos-reconcile/basico.blade.php
{{-- Zero PHP: mesma fixture do demo grande, mas com `context` PRÓPRIO e
     match-on mais simples (só valor) — contexts diferentes = conciliações
     independentes sobre os MESMOS models (não interferem uma na outra). --}}
<mad-reconcile left-model="TutorDemoReconcileExtrato" right-model="TutorDemoReconcileLancamento"
    database="business" match-on="amount"
    left-amount="valor" right-amount="valor"
    left-label="descricao" right-label="historico"
    left-title="Extrato bancário" right-title="Lançamentos"
    context="tutor_modulos_reconcile_basico" />
Auto-match completo (valor + data + documento)

match-on com os 3 passes do MatchEngine: par exato, tolerância de data e N:1 por soma.

× — Difference:
Extrato bancário 4
2026-08-30 PIX recebido cliente 250,75
2026-09-02 NF-2001 TED Fornecedor Beta 980,00
2026-09-03 Depósito consolidado 700,00
2026-09-04 TAR-12 Tarifa bancária 24,90
Lançamentos 5
2026-08-31 AL-9 Aluguel sala 9 1.500,00
2026-09-01 Recebimento cliente 250,75
2026-09-02 NF-2001 Pagto fornecedor Beta 980,00
2026-09-03 Venda balcão manhã 300,00
2026-09-03 Venda balcão tarde 400,00
resources/views/tutor/examples/modulos-reconcile/completo.blade.php
@php
    // Partial de <x-tutor-demo> = escopo Blade ISOLADO — `$that` não
    // atravessa esse aninhamento sozinho. Reabre aqui só por coerência com o
    // padrão dos outros módulos grandes: mad-reconcile NÃO exige host (todas
    // as props vêm de attrs), mas usar o HOST deixa a página consistente com
    // o `context` "completo" declarado na classe (matchOn com os 3 passes).
    $that = \Mad\Component\MadRenderContext::getComponent();
@endphp
{{-- Tag inline sem atributos reusa a config declarada nas props protected da
     classe (leftModel/rightModel/matchOn="amount,date:3,document"/context). --}}
<mad-reconcile />
Código-fonte completo da página
app/control/Tutor/TutorModulosReconcile.php
<?php

namespace App\Control\Tutor;

use App\Models\TutorDemo\TutorDemoReconcileExtrato;
use App\Models\TutorDemo\TutorDemoReconcileLancamento;
use Illuminate\Support\Facades\Schema;
use Mad\Reconcile\MadReconcile;

/**
 * TutorModulosReconcile — página "Conciliação" do MAD Lab (catálogo
 * modulos_reconcile). Cobre: mad-reconcile (self-closing, sem filhos).
 *
 * Os dois demos leem a MESMA fixture (tutor_reconcile_extrato/lancamentos)
 * mas usam `context` diferente — é exatamente o propósito documentado do
 * prop (§2 de docs/mad-reconcile.md): separar conciliações independentes
 * sobre os MESMOS models. O demo pequeno (basico.blade.php) não reabre
 * `$that` — cai num MadReconcileStandalone novo por request (zero PHP); o
 * grande (completo.blade.php) reabre `$that` pra usar o HOST (esta classe,
 * subclasse de MadReconcile) e demonstrar o `match-on` com os 3 passes do
 * MatchEngine (exato, tolerância de data, N:1 por soma).
 */
class TutorModulosReconcile extends MadReconcile
{
    protected static string $wrapper = self::INTERNAL;

    protected string $leftModel   = TutorDemoReconcileExtrato::class;
    protected string $rightModel  = TutorDemoReconcileLancamento::class;
    protected string $database    = 'business';
    protected string $leftAmount  = 'valor';
    protected string $rightAmount = 'valor';
    protected string $leftDate    = 'data';
    protected string $rightDate   = 'data';
    protected string $leftDoc     = 'documento';
    protected string $rightDoc    = 'documento';
    protected string $leftLabel   = 'descricao';
    protected string $rightLabel  = 'historico';
    protected string $leftTitle   = 'Extrato bancário';
    protected string $rightTitle  = 'Lançamentos';
    protected string $matchOn     = 'amount,date:3,document';
    protected string $context     = 'tutor_modulos_reconcile_completo';

    public function mount(array $params = []): void
    {
        $this->ensureFixture();
        parent::mount($params);
    }

    // ── Fixture ──────────────────────────────────────────────────────────

    private function ensureFixture(): void
    {
        $schema = Schema::connection('business');

        foreach (['tutor_reconcile_extrato' => 'descricao', 'tutor_reconcile_lancamentos' => 'historico'] as $table => $labelCol) {
            if (!$schema->hasTable($table)) {
                $schema->create($table, function ($t) use ($labelCol) {
                    $t->increments('id');
                    $t->string('data', 10);
                    $t->string('documento', 40)->nullable();
                    $t->string($labelCol);
                    $t->decimal('valor', 12, 2);
                });
            }
        }

        if (TutorDemoReconcileExtrato::query()->count() > 0) {
            return;
        }

        $d = fn (int $offset) => date('Y-m-d', strtotime("-{$offset} days"));

        TutorDemoReconcileExtrato::query()->insert([
            // pass 1: valor exato + mesmo documento
            ['data' => $d(2), 'documento' => 'NF-2001', 'descricao' => 'TED Fornecedor Beta',  'valor' => 980.00],
            // pass 2: valor exato, data dentro da tolerância (±3d), sem doc
            ['data' => $d(5), 'documento' => null,      'descricao' => 'PIX recebido cliente',  'valor' => 250.75],
            // pass 3: 1 linha do extrato = soma de 2 lançamentos
            ['data' => $d(1), 'documento' => null,      'descricao' => 'Depósito consolidado',  'valor' => 700.00],
            // sem par (sobra no painel)
            ['data' => $d(0), 'documento' => 'TAR-12',  'descricao' => 'Tarifa bancária',       'valor' => 24.90],
        ]);

        TutorDemoReconcileLancamento::query()->insert([
            ['data' => $d(2), 'documento' => 'NF-2001', 'historico' => 'Pagto fornecedor Beta', 'valor' => 980.00],
            ['data' => $d(3), 'documento' => null,      'historico' => 'Recebimento cliente',   'valor' => 250.75],
            ['data' => $d(1), 'documento' => null,      'historico' => 'Venda balcão manhã',    'valor' => 300.00],
            ['data' => $d(1), 'documento' => null,      'historico' => 'Venda balcão tarde',    'valor' => 400.00],
            ['data' => $d(4), 'documento' => 'AL-9',    'historico' => 'Aluguel sala 9',        'valor' => 1500.00],
        ]);
    }

    protected function view(): string|array
    {
        return ['tutor.modulos.reconcile', []];
    }
}
resources/views/tutor/modulos/reconcile.blade.php
<x-tutor-page page="modulos_reconcile">
    <x-tutor-demo demo="tutor.examples.modulos-reconcile.basico"
        title="Básico (zero PHP)" desc="mad-reconcile só por valor — context próprio isola esta conciliação da de baixo, mesmo usando os mesmos models." />

    <x-tutor-demo demo="tutor.examples.modulos-reconcile.completo"
        title="Auto-match completo (valor + data + documento)" desc="match-on com os 3 passes do MatchEngine: par exato, tolerância de data e N:1 por soma." />
</x-tutor-page>