feat: implementa sistema de comprovantes com centralizações e PIX

This commit is contained in:
LS
2025-04-16 13:54:31 -03:00
parent 813c968efd
commit 8ff58cc51e
15 changed files with 581 additions and 480 deletions

View File

@@ -541,8 +541,8 @@
</a>
</li>
<li>
<a class="dropdown-item" href="{{ url_for('listar_pagamentos') }}">
<i class="fas fa-receipt"></i>Pagamentos
<a class="dropdown-item" href="{{ url_for('listar_comprovantes') }}">
<i class="fas fa-receipt"></i>Comprovantes
</a>
</li>
</ul>
@@ -563,8 +563,8 @@
</a>
</li>
<li>
<a class="dropdown-item" href="{{ url_for('listar_assinaturas') }}">
<i class="fas fa-file-signature"></i>Assinaturas
<a class="dropdown-item" href="{{ url_for('listar_vendas_jornal') }}">
<i class="fas fa-file-signature"></i>Assinaturas de Jornal
</a>
</li>
</ul>

View File

@@ -57,7 +57,7 @@
<div class="stats-card yellow">
<div class="title">Assinaturas Ativas</div>
<div class="value">{{ total_assinaturas }}</div>
<a href="{{ url_for('listar_assinaturas') }}" class="link">
<a href="{{ url_for('listar_vendas_jornal') }}" class="link">
Ver detalhes <i class="fas fa-arrow-right"></i>
</a>
<div class="icon">

View File

@@ -7,7 +7,7 @@
<div class="d-flex justify-content-between align-items-center mb-3">
<h2><i class="fas fa-money-bill-wave"></i> Comprovantes</h2>
<div>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalNovoComprovante">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#novoComprovanteModal">
<i class="fas fa-plus"></i> Novo Comprovante
</button>
<button type="button" class="btn btn-outline-primary" id="btnExportar">
@@ -22,40 +22,30 @@
<table class="table table-striped table-hover" id="tabelaComprovantes">
<thead>
<tr>
<th>ID</th>
<th>Militante</th>
<th>Tipo de Comprovante</th>
<th>Valor</th>
<th>Data do Comprovante</th>
<th>Data</th>
<th>Forma de Pagamento</th>
<th>Campanha</th>
<th>Centralizações</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
{% for comprovante in comprovantes %}
<tr>
<td data-militante="{{ comprovante.militante_id }}">{{ comprovante.militante.nome if comprovante.militante else 'N/A' }}</td>
<td data-tipo="{{ comprovante.tipo_comprovante }}">
{% if comprovante.tipo_comprovante == 1 %}
Cota
{% elif comprovante.tipo_comprovante == 2 %}
Contribuição Extra
{% elif comprovante.tipo_comprovante == 3 %}
Doação
{% elif comprovante.tipo_comprovante == 4 %}
Taxa de Evento
{% elif comprovante.tipo_comprovante == 5 %}
Jornal Avulso
{% elif comprovante.tipo_comprovante == 6 %}
Assinatura de Jornal
{% elif comprovante.tipo_comprovante == 7 %}
Campanha Financeira
{% elif comprovante.tipo_comprovante == 8 %}
Outros
{% else %}
Não Definido
{% endif %}
<td>{{ comprovante.id }}</td>
<td>{{ comprovante.militante.nome }}</td>
<td>{{ comprovante.data_comprovante.strftime('%d/%m/%Y') }}</td>
<td>{{ comprovante.forma_pagamento }}</td>
<td>{{ comprovante.campanha.nome if comprovante.campanha else '-' }}</td>
<td>
<ul class="list-unstyled">
{% for centralizacao in comprovante.centralizacoes %}
<li>{{ centralizacao.tipo_comprovante }}: R$ {{ "%.2f"|format(centralizacao.valor) }}</li>
{% endfor %}
</ul>
</td>
<td data-valor="{{ comprovante.valor }}">R$ {{ "%.2f"|format(comprovante.valor) }}</td>
<td data-data="{{ comprovante.data_comprovante }}">{{ comprovante.data_comprovante.strftime('%d/%m/%Y') }}</td>
<td>
<button type="button"
class="btn btn-sm btn-outline-primary"
@@ -63,8 +53,7 @@
data-bs-target="#modalEditarComprovante"
data-comprovante-id="{{ comprovante.id }}"
data-militante-id="{{ comprovante.militante_id }}"
data-tipo-comprovante="{{ comprovante.tipo_comprovante }}"
data-valor="{{ comprovante.valor }}"
data-militante-nome="{{ comprovante.militante.nome }}"
data-data-comprovante="{{ comprovante.data_comprovante.strftime('%Y-%m-%d') }}"
title="Editar">
<i class="fas fa-edit"></i>
@@ -74,7 +63,7 @@
data-bs-toggle="modal"
data-bs-target="#modalExcluirComprovante"
data-comprovante-id="{{ comprovante.id }}"
data-comprovante-info="Comprovante de {{ comprovante.militante.nome if comprovante.militante else 'N/A' }} - R$ {{ "%.2f"|format(comprovante.valor) }}"
data-comprovante-info="Comprovante de {{ comprovante.militante.nome }} - Total: R$ {{ "%.2f"|format(comprovante.centralizacoes|sum(attribute='valor')) }}"
title="Excluir">
<i class="fas fa-trash"></i>
</button>
@@ -89,58 +78,159 @@
</div>
<!-- Modal Novo Comprovante -->
<div class="modal fade" id="modalNovoComprovante" tabindex="-1">
<div class="modal-dialog">
<div class="modal fade" id="novoComprovanteModal" tabindex="-1" aria-labelledby="novoComprovanteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-plus"></i> Novo Comprovante</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
<h5 class="modal-title" id="novoComprovanteModalLabel">Novo Comprovante</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="formNovoComprovante" method="post" action="{{ url_for('adicionar_comprovante') }}">
<div class="mb-3">
<label for="militante" class="form-label">Militante:</label>
<select class="form-select" id="militante" name="militante_id" required>
<option value="">Selecione um militante</option>
{% for militante in militantes %}
<option value="{{ militante.id }}">{{ militante.nome }}</option>
{% endfor %}
</select>
<form id="novoComprovanteForm">
<!-- Dados únicos do comprovante -->
<div class="row mb-3">
<div class="col-md-6">
<label for="militante_id" class="form-label">Militante</label>
<select class="form-select" id="militante_id" name="militante_id" required>
<option value="">Selecione o militante</option>
{% for militante in militantes %}
<option value="{{ militante.id }}">{{ militante.nome }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6">
<label for="data_comprovante" class="form-label">Data do Comprovante</label>
<input type="date" class="form-control" id="data_comprovante" name="data_comprovante" required>
</div>
</div>
<div class="mb-3">
<label for="tipoComprovante" class="form-label">Tipo de Comprovante:</label>
<select class="form-select" id="tipoComprovante" name="tipo_comprovante" required>
<option value="">Selecione o tipo</option>
<option value="1">Cota</option>
{% if current_user.has_permission('gerenciar_tipos_comprovante') %}
<option value="2">Contribuição Extra</option>
<option value="3">Doação</option>
<option value="4">Taxa de Evento</option>
<option value="5">Jornal Avulso</option>
<option value="6">Assinatura de Jornal</option>
<option value="7">Campanha Financeira</option>
<option value="8">Outros</option>
{% endif %}
</select>
<div class="row mb-3">
<div class="col-md-6">
<label for="forma_pagamento" class="form-label">Forma de Pagamento</label>
<select class="form-select" id="forma_pagamento" name="forma_pagamento" required>
<option value="">Selecione a forma de pagamento</option>
<option value="PIX">PIX</option>
<option value="TRANSFERENCIA">Transferência/DOC</option>
<option value="DEPOSITO">Depósito</option>
<option value="MAQUININHA">Maquininha</option>
</select>
</div>
<div class="col-md-6">
<label for="campanha_id" class="form-label">Campanha</label>
<select class="form-select" id="campanha_id" name="campanha_id">
<option value="">Selecione a campanha</option>
{% for campanha in campanhas %}
<option value="{{ campanha.id }}">{{ campanha.nome }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="mb-3">
<label for="valor" class="form-label">Valor:</label>
<input type="number" step="0.01" class="form-control" id="valor" name="valor" required>
</div>
<div class="mb-3">
<label for="dataComprovante" class="form-label">Data do Comprovante:</label>
<input type="date" class="form-control" id="dataComprovante" name="data_comprovante" required>
</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</button>
<!-- Centralizações -->
<div class="centralizacoes-container">
<h6 class="mb-3">Centralizações</h6>
<div class="centralizacao-item mb-3">
<div class="row">
<div class="col-md-6">
<label class="form-label">Tipo de Comprovante</label>
<select class="form-select tipo-comprovante" name="tipo_comprovante[]" required>
<option value="">Selecione o tipo</option>
<option value="COTA">Cota</option>
<option value="JORNAL">Jornal</option>
<option value="ASSINATURA">Assinatura</option>
</select>
</div>
<div class="col-md-5">
<label class="form-label">Valor</label>
<input type="number" class="form-control valor" name="valor[]" step="0.01" required>
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="button" class="btn btn-danger btn-sm remover-centralizacao">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-secondary btn-sm mb-3" id="adicionar-centralizacao">
<i class="bi bi-plus"></i> Adicionar Centralização
</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="button" class="btn btn-primary" id="salvarComprovante">Salvar</button>
</div>
</div>
</div>
</div>
<style>
.centralizacao-item {
background-color: #f8f9fa;
padding: 15px;
border-radius: 5px;
border: 1px solid #dee2e6;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Adicionar nova centralização
document.getElementById('adicionar-centralizacao').addEventListener('click', function() {
const container = document.querySelector('.centralizacoes-container');
const newItem = document.querySelector('.centralizacao-item').cloneNode(true);
newItem.querySelector('.valor').value = '';
newItem.querySelector('.tipo-comprovante').value = '';
container.appendChild(newItem);
});
// Remover centralização
document.addEventListener('click', function(e) {
if (e.target.closest('.remover-centralizacao')) {
const centralizacoes = document.querySelectorAll('.centralizacao-item');
if (centralizacoes.length > 1) {
e.target.closest('.centralizacao-item').remove();
}
}
});
// Salvar comprovante
document.getElementById('salvarComprovante').addEventListener('click', function() {
const form = document.getElementById('novoComprovanteForm');
const formData = new FormData(form);
// Coletar dados das centralizações
const centralizacoes = [];
document.querySelectorAll('.centralizacao-item').forEach(item => {
centralizacoes.push({
tipo_comprovante: item.querySelector('.tipo-comprovante').value,
valor: item.querySelector('.valor').value
});
});
// Adicionar centralizações ao formData
formData.append('centralizacoes', JSON.stringify(centralizacoes));
fetch('/comprovantes/novo', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(data.message || 'Erro ao salvar comprovante');
}
})
.catch(error => {
console.error('Error:', error);
alert('Erro ao salvar comprovante');
});
});
});
</script>
<!-- Modal Editar Comprovante -->
<div class="modal fade" id="modalEditarComprovante" tabindex="-1">
<div class="modal-dialog">

View File

@@ -47,7 +47,7 @@
</div>
<div class="form-floating mb-4">
<input type="text" class="form-control" id="otp" name="otp" placeholder="Código OTP" required>
<input type="text" class="form-control" id="otp" name="otp" placeholder="Código OTP">
<label for="otp">Código OTP</label>
<div class="invalid-feedback">
Por favor, informe o código OTP.

View File

@@ -31,7 +31,7 @@
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Registrar</button>
<a href="{{ url_for('listar_assinaturas') }}" class="btn btn-secondary">Voltar</a>
<a href="{{ url_for('listar_vendas_jornal') }}" class="btn btn-secondary">Voltar</a>
<a href="{{ url_for('home') }}" class="btn btn-outline-primary">Início</a>
</div>
</form>