First Commit
This commit is contained in:
+172
@@ -0,0 +1,172 @@
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block title %}{{ title }} - {{ platformName }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="mt-4">{{ title }}</h1>
|
||||
<div>
|
||||
<a href="{{ url('/admin/fluxo-caixa') }}" class="btn btn-outline-secondary me-2">
|
||||
<i class="bi bi-arrow-left me-1"></i> Voltar ao Fluxo
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#newCategoryModal">
|
||||
<i class="bi bi-plus-circle me-1"></i> Nova Categoria
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if flash_messages.success %}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
{{ flash_messages.success }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card shadow mb-4 border-0">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th class="ps-4">Nome</th>
|
||||
<th>Tipo Padrão</th>
|
||||
<th>Cor</th>
|
||||
<th>Ícone</th>
|
||||
<th>Status</th>
|
||||
<th class="text-center">Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cat in categories %}
|
||||
<tr>
|
||||
<td class="ps-4 fw-bold">{{ cat.name }}</td>
|
||||
<td>
|
||||
{% if cat.type == 'income' %}
|
||||
<span class="text-success small"><i class="bi bi-plus-circle me-1"></i> Receita</span>
|
||||
{% else %}
|
||||
<span class="text-danger small"><i class="bi bi-dash-circle me-1"></i> Despesa</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div style="width: 20px; height: 20px; border-radius: 50%; background-color: {{ cat.color }}; margin-right: 8px;"></div>
|
||||
<small class="text-muted">{{ cat.color }}</small>
|
||||
</div>
|
||||
</td>
|
||||
<td><i class="{{ cat.icon }} fs-5"></i></td>
|
||||
<td>
|
||||
{% if cat.is_active %}
|
||||
<span class="badge bg-success">Ativa</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Inativa</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary border-0"
|
||||
data-bs-toggle="modal" data-bs-target="#editCategoryModal{{ cat.id }}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<form action="{{ url('/admin/fluxo-caixa/categories/delete/' ~ cat.id) }}" method="POST">
|
||||
<button type="submit" class="btn btn-sm btn-outline-{{ cat.is_active ? 'warning' : 'success' }} border-0">
|
||||
<i class="bi bi-power"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Modal Editar Categoria -->
|
||||
<div class="modal fade" id="editCategoryModal{{ cat.id }}" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Editar Categoria: {{ cat.name }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{{ url('/admin/fluxo-caixa/categories/update/' ~ cat.id) }}" method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nome da Categoria</label>
|
||||
<input type="text" name="name" class="form-control" value="{{ cat.name }}" required>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Tipo Padrão</label>
|
||||
<select name="type" class="form-select">
|
||||
<option value="income" {{ cat.type == 'income' ? 'selected' : '' }}>Receita</option>
|
||||
<option value="expense" {{ cat.type == 'expense' ? 'selected' : '' }}>Despesa</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Cor</label>
|
||||
<input type="color" name="color" class="form-control form-control-color w-100" value="{{ cat.color }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Ícone (Bootstrap Icon)</label>
|
||||
<input type="text" name="icon" class="form-control" value="{{ cat.icon }}" placeholder="bi bi-tag">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">Salvar Alterações</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-4 text-muted">Nenhuma categoria cadastrada.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Nova Categoria -->
|
||||
<div class="modal fade" id="newCategoryModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Nova Categoria</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{{ url('/admin/fluxo-caixa/categories/store') }}" method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nome da Categoria</label>
|
||||
<input type="text" name="name" class="form-control" required placeholder="Ex: Alimentação, Vendas...">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Tipo Padrão</label>
|
||||
<select name="type" class="form-select">
|
||||
<option value="income">Receita</option>
|
||||
<option value="expense" selected>Despesa</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Cor</label>
|
||||
<input type="color" name="color" class="form-control form-control-color w-100" value="#0d6efd">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Ícone (Bootstrap Icon)</label>
|
||||
<input type="text" name="icon" class="form-control" value="bi bi-tag" placeholder="bi bi-tag">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">Criar Categoria</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Executable
+660
@@ -0,0 +1,660 @@
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block title %}{{ title }} - {{ platformName }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
.card-metric { transition: transform 0.2s; cursor: pointer; }
|
||||
.card-metric:hover { transform: translateY(-5px); }
|
||||
.border-income { border-left: 5px solid #198754 !important; }
|
||||
.border-expense { border-left: 5px solid #dc3545 !important; }
|
||||
.border-balance { border-left: 5px solid #0dcaf0 !important; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="mt-4">{{ title }}</h1>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#reconcileModal">
|
||||
<i class="bi bi-bank me-1"></i> Conciliação
|
||||
</button>
|
||||
<a href="{{ url('/admin/fluxo-caixa/export') }}" class="btn btn-outline-success">
|
||||
<i class="bi bi-file-earmark-excel me-1"></i> Exportar
|
||||
</a>
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#newTransactionModal">
|
||||
<i class="bi bi-plus-circle me-1"></i> Nova Transação
|
||||
</button>
|
||||
<form action="{{ url('/admin/fluxo-caixa/analysis') }}" method="POST">
|
||||
<button type="submit" class="btn btn-info text-white">
|
||||
<i class="bi bi-cpu me-1"></i> Análise IA
|
||||
</button>
|
||||
</form>
|
||||
<a href="{{ url('/admin/fluxo-caixa/categories') }}" class="btn btn-secondary">
|
||||
<i class="bi bi-tags me-1"></i> Categorias
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if flash_messages.success %}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
{{ flash_messages.success }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Filtros de Período e Status -->
|
||||
<div class="card mb-4 shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="row g-3 align-items-end">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold">Período:</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="date" name="start_date" class="form-control" value="{{ startDate }}">
|
||||
<span class="input-group-text">até</span>
|
||||
<input type="date" name="end_date" class="form-control" value="{{ endDate }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Status:</label>
|
||||
<select name="status" class="form-select form-select-sm">
|
||||
<option value="">Todos</option>
|
||||
<option value="paid" {{ filters.status == 'paid' ? 'selected' : '' }}>Pago</option>
|
||||
<option value="pending" {{ filters.status == 'pending' ? 'selected' : '' }}>Pendente</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Tipo:</label>
|
||||
<select name="type" class="form-select form-select-sm">
|
||||
<option value="">Todos</option>
|
||||
<option value="income" {{ filters.type == 'income' ? 'selected' : '' }}>Entrada</option>
|
||||
<option value="expense" {{ filters.type == 'expense' ? 'selected' : '' }}>Saída</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Entidade:</label>
|
||||
<select name="entity" class="form-select form-select-sm">
|
||||
<option value="">Todos</option>
|
||||
<option value="business" {{ filters.entity == 'business' ? 'selected' : '' }}>Empresa</option>
|
||||
<option value="personal" {{ filters.entity == 'personal' ? 'selected' : '' }}>Pessoal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary btn-sm flex-grow-1">
|
||||
<i class="bi bi-filter me-1"></i> Filtrar
|
||||
</button>
|
||||
<a href="{{ url('/admin/fluxo-caixa') }}" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-x-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cards de Métricas Principais -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card card-metric shadow-sm border-0 border-income h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Receitas (Operacional)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">R$ {{ summary.operational_income|number_format(2, ',', '.') }}</div>
|
||||
<small class="text-muted">Total: R$ {{ summary.total_income|number_format(2, ',', '.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card card-metric shadow-sm border-0 border-expense h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Despesas (Operacional)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">R$ {{ summary.operational_expense|number_format(2, ',', '.') }}</div>
|
||||
<small class="text-muted">Total: R$ {{ summary.total_expense|number_format(2, ',', '.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card card-metric shadow-sm border-0 border-info h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Saldo Operacional</div>
|
||||
<div class="h5 mb-0 font-weight-bold {{ summary.operational_balance >= 0 ? 'text-info' : 'text-danger' }}">
|
||||
R$ {{ summary.operational_balance|number_format(2, ',', '.') }}
|
||||
</div>
|
||||
<small class="text-muted">Líquido: R$ {{ summary.net_balance|number_format(2, ',', '.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card card-metric shadow-sm border-0 border-warning h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Contas Pendentes</div>
|
||||
<div class="small">A Receber: <span class="text-success fw-bold">R$ {{ summary.pending_income|number_format(2, ',', '.') }}</span></div>
|
||||
<div class="small">A Pagar: <span class="text-danger fw-bold">R$ {{ summary.pending_expense|number_format(2, ',', '.') }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<!-- Gráfico Mensal -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-header bg-white border-0 py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Fluxo Mensal (Histórico)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="monthlyChart" style="min-height: 300px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Projeções -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-header bg-white border-0 py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Projeção de Saldo (12 Meses)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="projectionChart" style="min-height: 300px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<!-- IA Insights -->
|
||||
<div class="col-lg-12">
|
||||
<div class="card shadow-sm border-0 h-100 bg-light">
|
||||
<div class="card-header bg-white border-0 py-3 d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold text-info"><i class="bi bi-robot me-2"></i>Insights da Inteligência Artificial</h6>
|
||||
{% if latestAnalysis %}
|
||||
<small class="text-muted">Última análise: {{ latestAnalysis.created_at|date('d/m/Y H:i') }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
{% if latestAnalysis %}
|
||||
<div class="mb-3">
|
||||
<small class="text-muted d-block mb-1">Previsão de Saldo Próximo Mês:</small>
|
||||
<span class="h4 fw-bold text-primary">R$ {{ latestAnalysis.summary_data.predicted_balance|number_format(2, ',', '.') }}</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<small class="text-muted d-block mb-1">Nível de Risco Financeiro:</small>
|
||||
{% set risk = latestAnalysis.summary_data.risk_level %}
|
||||
<span class="badge fs-6 bg-{{ risk == 'High' ? 'danger' : (risk == 'Medium' ? 'warning' : 'success') }}">
|
||||
{{ risk == 'High' ? 'Alto Risco' : (risk == 'Medium' ? 'Risco Médio' : 'Baixo Risco') }}
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-cpu fs-1 text-muted opacity-25"></i>
|
||||
<p class="text-muted mt-2 small">Sem análise recente.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
{% if latestAnalysis %}
|
||||
<div class="p-3 bg-white rounded border">
|
||||
<h6 class="fw-bold mb-2">Recomendações Estratégicas:</h6>
|
||||
<p class="text-dark mb-0" style="white-space: pre-line;">{{ latestAnalysis.recommendations }}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i> Clique no botão <strong>Análise IA</strong> no topo para que nosso sistema examine seu fluxo de caixa e forneça recomendações personalizadas baseadas em melhores práticas de gestão financeira.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Últimas Transações -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white border-0 py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Últimas Transações</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th class="ps-4">Data</th>
|
||||
<th>Descrição</th>
|
||||
<th>Categoria</th>
|
||||
<th>Tipo</th>
|
||||
<th>Valor</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end pe-4">Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for trans in latestTransactions %}
|
||||
<tr>
|
||||
<td class="ps-4 small">
|
||||
<span class="text-muted d-block">{{ trans.transaction_date|date('d/m/Y') }}</span>
|
||||
{% if trans.due_date %}
|
||||
<small class="text-info">Venc: {{ trans.due_date|date('d/m/Y') }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ trans.description }}
|
||||
{% if trans.is_personal %}
|
||||
<span class="badge bg-secondary ms-1" title="Despesa/Receita Pessoal">Pessoal</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge" style="background-color: {{ trans.category.color }};">
|
||||
<i class="{{ trans.category.icon }} me-1"></i>{{ trans.category.name }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-{{ trans.type == 'income' ? 'success' : 'danger' }} small fw-bold">
|
||||
{{ trans.type == 'income' ? 'Entrada' : 'Saída' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="fw-bold {{ trans.type == 'income' ? 'text-success' : 'text-danger' }}">
|
||||
{{ trans.type == 'income' ? '+' : '-' }} R$ {{ trans.amount|abs|number_format(2, ',', '.') }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-{{ trans.status == 'paid' ? 'success' : 'warning' }}">
|
||||
{{ trans.status == 'paid' ? 'Pago' : 'Pendente' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<div class="btn-group btn-group-sm">
|
||||
{% if trans.status == 'pending' %}
|
||||
<form action="{{ url('/admin/fluxo-caixa/transaction/pay/' ~ trans.id) }}" method="POST" class="d-inline">
|
||||
<button type="submit" class="btn btn-outline-success" title="Marcar como Pago">
|
||||
<i class="bi bi-check2-circle"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-outline-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#editTransactionModal{{ trans.id }}"
|
||||
title="Editar">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#deleteTransactionModal{{ trans.id }}"
|
||||
title="Excluir">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar Transação -->
|
||||
<div class="modal fade" id="editTransactionModal{{ trans.id }}" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog text-start">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Editar Transação</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{{ url('/admin/fluxo-caixa/transaction/update/' ~ trans.id) }}" method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Descrição</label>
|
||||
<input type="text" name="description" class="form-control" value="{{ trans.description }}" required>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Valor (R$)</label>
|
||||
<input type="number" step="0.01" name="amount" class="form-control" value="{{ trans.amount }}" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Lançamento</label>
|
||||
<input type="date" name="transaction_date" class="form-control" value="{{ trans.transaction_date|date('Y-m-d') }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Vencimento</label>
|
||||
<input type="date" name="due_date" class="form-control" value="{{ trans.due_date ? trans.due_date|date('Y-m-d') : '' }}">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Pagamento</label>
|
||||
<input type="date" name="payment_date" class="form-control" value="{{ trans.payment_date ? trans.payment_date|date('Y-m-d') : '' }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Tipo</label>
|
||||
<select name="type" class="form-select">
|
||||
<option value="income" {{ trans.type == 'income' ? 'selected' : '' }}>Receita</option>
|
||||
<option value="expense" {{ trans.type == 'expense' ? 'selected' : '' }}>Despesa</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Categoria</label>
|
||||
<select name="category_id" class="form-select" required>
|
||||
{% for cat in categories_all %}
|
||||
<option value="{{ cat.id }}" {{ cat.id == trans.category_id ? 'selected' : '' }}>{{ cat.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Status</label>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" value="paid" {{ trans.status == 'paid' ? 'checked' : '' }}>
|
||||
<label class="form-check-label">Pago</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" value="pending" {{ trans.status == 'pending' ? 'checked' : '' }}>
|
||||
<label class="form-check-label">Pendente</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 pt-4">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="is_personal" value="1" id="editIsPersonal{{ trans.id }}" {{ trans.is_personal ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="editIsPersonal{{ trans.id }}">Gasto Pessoal?</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Observações</label>
|
||||
<textarea name="notes" class="form-control" rows="2">{{ trans.notes }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">Salvar Alterações</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Excluir Transação -->
|
||||
<div class="modal fade" id="deleteTransactionModal{{ trans.id }}" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog text-start">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Excluir Transação</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Tem certeza que deseja excluir a transação <strong>"{{ trans.description }}"</strong>?</p>
|
||||
<p class="text-danger small"><i class="bi bi-exclamation-triangle me-1"></i> Esta ação não pode ser desfeita.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<form action="{{ url('/admin/fluxo-caixa/transaction/delete/' ~ trans.id) }}" method="POST">
|
||||
<button type="submit" class="btn btn-danger">Excluir</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4 text-muted">Nenhuma transação encontrada.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Nova Transação -->
|
||||
<div class="modal fade" id="newTransactionModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Nova Transação</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{{ url('/admin/fluxo-caixa/transaction') }}" method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Descrição</label>
|
||||
<input type="text" name="description" class="form-control" required placeholder="Ex: Pagamento Fornecedor X">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Valor (R$)</label>
|
||||
<input type="number" step="0.01" name="amount" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Lançamento</label>
|
||||
<input type="date" name="transaction_date" class="form-control" value="{{ "now"|date("Y-m-d") }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Vencimento</label>
|
||||
<input type="date" name="due_date" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Data Pagamento</label>
|
||||
<input type="date" name="payment_date" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Tipo</label>
|
||||
<select name="type" class="form-select" id="trans_type">
|
||||
<option value="income">Receita</option>
|
||||
<option value="expense" selected>Despesa</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Categoria</label>
|
||||
<select name="category_id" class="form-select" required>
|
||||
{% for cat in categories_all %}
|
||||
<option value="{{ cat.id }}" data-type="{{ cat.type }}">{{ cat.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Status</label>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" value="paid" checked>
|
||||
<label class="form-check-label">Pago</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" value="pending">
|
||||
<label class="form-check-label">Pendente</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 pt-4">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="is_personal" value="1" id="isPersonalSwitch">
|
||||
<label class="form-check-label" for="isPersonalSwitch">Gasto Pessoal?</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Observações</label>
|
||||
<textarea name="notes" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">Salvar Transação</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Conciliação Bancária -->
|
||||
<div class="modal fade" id="reconcileModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Conciliação Bancária</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{{ url('/admin/fluxo-caixa/reconcile') }}" method="POST">
|
||||
<div class="modal-body">
|
||||
<p class="small text-muted mb-3">
|
||||
Insira o saldo atual que aparece no extrato do seu banco para comparar com o saldo registrado no sistema.
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Saldo Atual no Banco (R$)</label>
|
||||
<input type="number" step="0.01" name="bank_balance" class="form-control" required placeholder="0,00">
|
||||
</div>
|
||||
<div class="alert alert-info py-2 small mb-0">
|
||||
<i class="bi bi-info-circle me-1"></i> O sistema utilizará o <strong>Saldo Líquido Total</strong> (Empresa + Pessoal) para esta conferência.
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">Conciliar Agora</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
const monthlyData = {{ monthlyBreakdown|raw }};
|
||||
const projectionsData = {{ projections|raw }};
|
||||
|
||||
// Configuração comum para tooltips de moeda
|
||||
const currencyTooltip = {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
let label = context.dataset.label || '';
|
||||
if (label) label += ': ';
|
||||
if (context.parsed.y !== null) {
|
||||
label += 'R$ ' + context.parsed.y.toLocaleString('pt-BR', {minimumFractionDigits: 2});
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Gráfico Histórico
|
||||
const ctxMonthly = document.getElementById('monthlyChart').getContext('2d');
|
||||
new Chart(ctxMonthly, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: monthlyData.map(d => d.month),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Receitas',
|
||||
data: monthlyData.map(d => d.income),
|
||||
backgroundColor: 'rgba(25, 135, 84, 0.7)',
|
||||
borderColor: 'rgb(25, 135, 84)',
|
||||
borderWidth: 1
|
||||
},
|
||||
{
|
||||
label: 'Despesas',
|
||||
data: monthlyData.map(d => d.expense),
|
||||
backgroundColor: 'rgba(220, 53, 69, 0.7)',
|
||||
borderColor: 'rgb(220, 53, 69)',
|
||||
borderWidth: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return 'R$ ' + value.toLocaleString('pt-BR');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
tooltip: currencyTooltip
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Gráfico de Projeções
|
||||
const ctxProjection = document.getElementById('projectionChart').getContext('2d');
|
||||
new Chart(ctxProjection, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: projectionsData.map(d => d.month),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Cenário Otimista',
|
||||
data: projectionsData.map(d => d.optimistic.balance),
|
||||
borderColor: 'rgba(25, 135, 84, 0.8)',
|
||||
backgroundColor: 'rgba(25, 135, 84, 0.1)',
|
||||
borderDash: [5, 5],
|
||||
fill: false,
|
||||
tension: 0.4
|
||||
},
|
||||
{
|
||||
label: 'Cenário Realista',
|
||||
data: projectionsData.map(d => d.realistic.balance),
|
||||
borderColor: 'rgba(13, 202, 240, 1)',
|
||||
backgroundColor: 'rgba(13, 202, 240, 0.1)',
|
||||
fill: true,
|
||||
tension: 0.4,
|
||||
borderWidth: 3
|
||||
},
|
||||
{
|
||||
label: 'Cenário Pessimista',
|
||||
data: projectionsData.map(d => d.pessimistic.balance),
|
||||
borderColor: 'rgba(220, 53, 69, 0.8)',
|
||||
backgroundColor: 'rgba(220, 53, 69, 0.1)',
|
||||
borderDash: [5, 5],
|
||||
fill: false,
|
||||
tension: 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return 'R$ ' + value.toLocaleString('pt-BR');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
tooltip: currencyTooltip
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,77 @@
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block title %}{{ title }} - {{ platformName }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4">
|
||||
<h1 class="mt-4">{{ title }}</h1>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white border-0 py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Resumo da Conciliação</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span>Saldo no Banco:</span>
|
||||
<span class="fw-bold">R$ {{ bankBalance|number_format(2, ',', '.') }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span>Saldo no Sistema:</span>
|
||||
<span class="fw-bold">R$ {{ systemBalance|number_format(2, ',', '.') }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="h5">Diferença:</span>
|
||||
<span class="h5 fw-bold {{ difference == 0 ? 'text-success' : 'text-danger' }}">
|
||||
R$ {{ difference|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if difference != 0 %}
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong>Atenção!</strong> Existe uma diferença de R$ {{ difference|abs|number_format(2, ',', '.') }} entre o banco e o sistema.
|
||||
<br><br>
|
||||
<strong>Sugestões de gestão para resolver:</strong>
|
||||
<ul class="mt-2">
|
||||
<li>Verifique se todas as tarifas bancárias foram lançadas.</li>
|
||||
<li>Confira se algum cheque ou transferência ainda não compensou.</li>
|
||||
<li>Verifique se houve algum erro de digitação nos valores.</li>
|
||||
<li>Certifique-se de que não houve mistura de gastos pessoais (que não foram lançados).</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-success">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong>Tudo certo!</strong> O saldo do banco coincide perfeitamente com o saldo do sistema. Sua gestão está excelente!
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<a href="{{ url('/admin/fluxo-caixa') }}" class="btn btn-primary mt-3">
|
||||
<i class="bi bi-arrow-left me-1"></i> Voltar ao Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow-sm border-0 bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="fw-bold mb-3">O que é Conciliação Bancária?</h6>
|
||||
<p class="small text-muted">
|
||||
A conciliação bancária consiste em conferir se o saldo do controle interno da empresa bate com o saldo do extrato bancário.
|
||||
</p>
|
||||
<p class="small text-muted">
|
||||
Este processo deve ser feito diariamente ou, no máximo, semanalmente para evitar que erros se acumulem e distorçam a realidade financeira da sua empresa.
|
||||
</p>
|
||||
<div class="text-center mt-4">
|
||||
<i class="bi bi-bank fs-1 text-primary opacity-25"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user