Corrigir atualização de dados na tabela de militantes
This commit is contained in:
@@ -560,4 +560,52 @@ input.btn-secondary:hover,
|
||||
border-color: #0b5ed7 !important;
|
||||
color: white !important;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Estilos para alertas */
|
||||
.alert {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 9999;
|
||||
min-width: 300px;
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
padding: 1rem 2.5rem 1rem 1rem;
|
||||
margin: 0;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.alert .btn-close {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1rem;
|
||||
transform: translateY(-50%);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
color: #0f5132;
|
||||
background-color: #d1e7dd;
|
||||
border-color: #badbcc;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #842029;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c2c7;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
color: #664d03;
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffecb5;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #055160;
|
||||
background-color: #cff4fc;
|
||||
border-color: #b6effb;
|
||||
}
|
||||
53
static/css/styles.css
Normal file
53
static/css/styles.css
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Estilos globais para alertas do sistema */
|
||||
.alert {
|
||||
position: relative;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Estilo base para o botão de fechar */
|
||||
.alert .btn-close {
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Alert Success */
|
||||
.alert-success .btn-close {
|
||||
background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23198754'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
|
||||
}
|
||||
|
||||
/* Alert Danger */
|
||||
.alert-danger .btn-close {
|
||||
background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23842029'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
|
||||
}
|
||||
|
||||
/* Alert Warning */
|
||||
.alert-warning .btn-close {
|
||||
background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23997404'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
|
||||
}
|
||||
|
||||
/* Alert Info */
|
||||
.alert-info .btn-close {
|
||||
background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23055160'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
|
||||
}
|
||||
|
||||
/* Efeito hover para todos os botões de fechar */
|
||||
.alert .btn-close:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
/* Estilo das abas do modal */
|
||||
.nav-tabs .nav-link {
|
||||
/* remover estilos */
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
/* remover estilos */
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link:hover:not(.active) {
|
||||
/* remover estilos */
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link i {
|
||||
/* remover estilos */
|
||||
}
|
||||
1
static/img/favicon.ico
Normal file
1
static/img/favicon.ico
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -106,30 +106,87 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
|
||||
// Validação de datas
|
||||
const dateInputs = document.querySelectorAll('input[type="date"]');
|
||||
const dateInputs = document.querySelectorAll('input[type="date"], input.date-mask');
|
||||
dateInputs.forEach(input => {
|
||||
input.addEventListener('change', function() {
|
||||
const date = new Date(this.value);
|
||||
const today = new Date();
|
||||
console.log('Validando data:', this.value);
|
||||
|
||||
if (this.hasAttribute('min')) {
|
||||
const minDate = new Date(this.getAttribute('min'));
|
||||
if (date < minDate) {
|
||||
this.setCustomValidity(`A data não pode ser anterior a ${minDate.toLocaleDateString()}`);
|
||||
this.classList.add('is-invalid');
|
||||
return;
|
||||
let dataValida = true;
|
||||
let mensagemErro = '';
|
||||
|
||||
// Se for um campo com máscara, validar o formato
|
||||
if (this.classList.contains('date-mask')) {
|
||||
if (!validarData(this.value)) {
|
||||
dataValida = false;
|
||||
mensagemErro = 'Por favor, insira uma data válida no formato DD/MM/AAAA';
|
||||
}
|
||||
} else {
|
||||
// Para campos type="date", converter para Date
|
||||
const date = new Date(this.value);
|
||||
if (isNaN(date.getTime())) {
|
||||
dataValida = false;
|
||||
mensagemErro = 'Data inválida';
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasAttribute('max')) {
|
||||
const maxDate = new Date(this.getAttribute('max'));
|
||||
if (date > maxDate) {
|
||||
this.setCustomValidity(`A data não pode ser posterior a ${maxDate.toLocaleDateString()}`);
|
||||
this.classList.add('is-invalid');
|
||||
return;
|
||||
// Validar limites de data
|
||||
if (dataValida) {
|
||||
const hoje = new Date();
|
||||
hoje.setHours(0, 0, 0, 0);
|
||||
|
||||
let dataComparacao;
|
||||
if (this.classList.contains('date-mask')) {
|
||||
const [dia, mes, ano] = this.value.split('/').map(Number);
|
||||
dataComparacao = new Date(ano, mes - 1, dia);
|
||||
} else {
|
||||
dataComparacao = new Date(this.value);
|
||||
}
|
||||
|
||||
// Verificar data mínima
|
||||
if (this.hasAttribute('min')) {
|
||||
const minDate = new Date(this.getAttribute('min'));
|
||||
if (dataComparacao < minDate) {
|
||||
dataValida = false;
|
||||
mensagemErro = `A data não pode ser anterior a ${minDate.toLocaleDateString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar data máxima
|
||||
if (this.hasAttribute('max')) {
|
||||
const maxDate = new Date(this.getAttribute('max'));
|
||||
if (dataComparacao > maxDate) {
|
||||
dataValida = false;
|
||||
mensagemErro = `A data não pode ser posterior a ${maxDate.toLocaleDateString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar se é data futura (quando não permitido)
|
||||
if (this.hasAttribute('data-no-future') && dataComparacao > hoje) {
|
||||
dataValida = false;
|
||||
mensagemErro = 'A data não pode ser futura';
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar validação do campo
|
||||
if (!dataValida) {
|
||||
console.warn('Data inválida:', this.value, mensagemErro);
|
||||
this.setCustomValidity(mensagemErro);
|
||||
this.classList.add('is-invalid');
|
||||
|
||||
// Atualizar mensagem de feedback
|
||||
const feedback = this.nextElementSibling;
|
||||
if (feedback && feedback.classList.contains('invalid-feedback')) {
|
||||
feedback.textContent = mensagemErro;
|
||||
}
|
||||
} else {
|
||||
console.log('Data válida:', this.value);
|
||||
this.setCustomValidity('');
|
||||
this.classList.remove('is-invalid');
|
||||
}
|
||||
});
|
||||
|
||||
// Limpar validação ao começar a digitar
|
||||
input.addEventListener('input', function() {
|
||||
this.setCustomValidity('');
|
||||
this.classList.remove('is-invalid');
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,10 +6,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
language: {
|
||||
url: '//cdn.datatables.net/plug-ins/1.13.7/i18n/pt-BR.json'
|
||||
},
|
||||
order: [[3, 'desc']], // Ordenar por data de pagamento (decrescente)
|
||||
columnDefs: [
|
||||
{ targets: -1, orderable: false } // Desabilitar ordenação na coluna de ações
|
||||
]
|
||||
{
|
||||
targets: 3, // Coluna de data
|
||||
type: 'date-br',
|
||||
render: function(data, type, row) {
|
||||
if (type === 'sort') {
|
||||
return data.split('/').reverse().join('');
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 2, // Coluna de valor
|
||||
type: 'numeric',
|
||||
render: function(data, type, row) {
|
||||
if (type === 'sort') {
|
||||
return parseFloat(data.replace('R$ ', '').replace(',', '.'));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
{ targets: -1, orderable: false } // Coluna de ações
|
||||
],
|
||||
order: [[3, 'desc']] // Ordenar por data decrescente por padrão
|
||||
});
|
||||
|
||||
// Configuração do modal de edição
|
||||
@@ -253,4 +273,44 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Funções de validação e formatação de datas
|
||||
function validarData(data) {
|
||||
if (!data) return false;
|
||||
|
||||
const dataObj = new Date(data);
|
||||
if (isNaN(dataObj.getTime())) return false;
|
||||
|
||||
const hoje = new Date();
|
||||
hoje.setHours(0, 0, 0, 0);
|
||||
|
||||
return dataObj <= hoje;
|
||||
}
|
||||
|
||||
function formatarData(data) {
|
||||
if (!data) return '';
|
||||
|
||||
const dataObj = new Date(data);
|
||||
if (isNaN(dataObj.getTime())) return '';
|
||||
|
||||
return dataObj.toLocaleDateString('pt-BR');
|
||||
}
|
||||
|
||||
// Configurar campos de data
|
||||
const camposData = document.querySelectorAll('input[type="date"]');
|
||||
camposData.forEach(campo => {
|
||||
// Definir data máxima como hoje
|
||||
const hoje = new Date().toISOString().split('T')[0];
|
||||
campo.setAttribute('max', hoje);
|
||||
|
||||
campo.addEventListener('change', function() {
|
||||
if (!validarData(this.value)) {
|
||||
this.setCustomValidity('Data inválida ou futura');
|
||||
this.classList.add('is-invalid');
|
||||
} else {
|
||||
this.setCustomValidity('');
|
||||
this.classList.remove('is-invalid');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
200
static/js/table_sort.js
Normal file
200
static/js/table_sort.js
Normal file
@@ -0,0 +1,200 @@
|
||||
// Função para converter data DD/MM/YYYY para objeto Date
|
||||
function converterDataParaComparacao(dataStr) {
|
||||
console.log('Convertendo data para comparação:', dataStr);
|
||||
|
||||
if (!dataStr) return null;
|
||||
|
||||
try {
|
||||
// Se já estiver no formato ISO
|
||||
if (/^\d{4}-\d{2}-\d{2}/.test(dataStr)) {
|
||||
const data = new Date(dataStr);
|
||||
console.log('Data ISO convertida:', data);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Se estiver no formato DD/MM/YYYY
|
||||
if (/^\d{2}\/\d{2}\/\d{4}/.test(dataStr)) {
|
||||
const [dia, mes, ano] = dataStr.split('/').map(Number);
|
||||
const data = new Date(ano, mes - 1, dia);
|
||||
console.log('Data DD/MM/YYYY convertida:', data);
|
||||
return data;
|
||||
}
|
||||
|
||||
console.warn('Formato de data não reconhecido:', dataStr);
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Erro ao converter data:', error, 'Data:', dataStr);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Função para ordenar tabelas
|
||||
function configurarOrdenacaoTabela(tabelaId) {
|
||||
console.log('Configurando ordenação para tabela:', tabelaId);
|
||||
|
||||
const table = document.getElementById(tabelaId);
|
||||
if (!table) {
|
||||
console.warn('Tabela não encontrada:', tabelaId);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = table.querySelectorAll('th[data-sort]');
|
||||
headers.forEach(header => {
|
||||
if (header.dataset.sort) {
|
||||
header.addEventListener('click', () => {
|
||||
const column = header.dataset.sort;
|
||||
const tbody = table.getElementsByTagName('tbody')[0];
|
||||
const rows = Array.from(tbody.getElementsByTagName('tr'));
|
||||
|
||||
console.log('Ordenando coluna:', column);
|
||||
|
||||
rows.sort((a, b) => {
|
||||
const aValue = a.querySelector(`td[data-${column}]`).dataset[column];
|
||||
const bValue = b.querySelector(`td[data-${column}]`).dataset[column];
|
||||
|
||||
// Ordenação por data
|
||||
if (column === 'data' ||
|
||||
column === 'data_vencimento' ||
|
||||
column === 'data_alteracao' ||
|
||||
column === 'data_pagamento' ||
|
||||
column === 'data_venda' ||
|
||||
column === 'data_relatorio') {
|
||||
const aDate = converterDataParaComparacao(aValue);
|
||||
const bDate = converterDataParaComparacao(bValue);
|
||||
|
||||
// Se alguma data for inválida
|
||||
if (!aDate && !bDate) return 0;
|
||||
if (!aDate) return 1;
|
||||
if (!bDate) return -1;
|
||||
|
||||
return aDate - bDate;
|
||||
}
|
||||
|
||||
// Ordenação por valor monetário
|
||||
if (column === 'valor' ||
|
||||
column === 'valor_total' ||
|
||||
column === 'valor_antigo' ||
|
||||
column === 'valor_novo') {
|
||||
const aNum = parseFloat(aValue.replace(/[^\d,-]/g, '').replace(',', '.'));
|
||||
const bNum = parseFloat(bValue.replace(/[^\d,-]/g, '').replace(',', '.'));
|
||||
return aNum - bNum;
|
||||
}
|
||||
|
||||
// Ordenação padrão para texto
|
||||
return aValue.localeCompare(bValue);
|
||||
});
|
||||
|
||||
// Alternar direção da ordenação
|
||||
if (header.classList.contains('asc')) {
|
||||
rows.reverse();
|
||||
header.classList.remove('asc');
|
||||
header.classList.add('desc');
|
||||
console.log('Ordenação descendente');
|
||||
} else {
|
||||
header.classList.remove('desc');
|
||||
header.classList.add('asc');
|
||||
console.log('Ordenação ascendente');
|
||||
}
|
||||
|
||||
// Atualizar tabela
|
||||
tbody.innerHTML = '';
|
||||
rows.forEach(row => tbody.appendChild(row));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Configurar ordenação para todas as tabelas que precisam
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Configurando ordenação para todas as tabelas...');
|
||||
|
||||
const tabelas = [
|
||||
'materiaisTable',
|
||||
'vendasTable',
|
||||
'cotasTable',
|
||||
'pagamentosTable'
|
||||
];
|
||||
|
||||
tabelas.forEach(tabelaId => {
|
||||
configurarOrdenacaoTabela(tabelaId);
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Carregando script table_sort.js...');
|
||||
|
||||
// Função para comparar datas no formato DD/MM/YYYY
|
||||
function compararDatas(a, b) {
|
||||
if (!a || !b) return 0;
|
||||
|
||||
const [diaA, mesA, anoA] = a.split('/').map(Number);
|
||||
const [diaB, mesB, anoB] = b.split('/').map(Number);
|
||||
|
||||
const dataA = new Date(anoA, mesA - 1, diaA);
|
||||
const dataB = new Date(anoB, mesB - 1, diaB);
|
||||
|
||||
return dataA - dataB;
|
||||
}
|
||||
|
||||
// Função para comparar valores monetários
|
||||
function compararValores(a, b) {
|
||||
const valorA = parseFloat(a.replace('R$ ', '').replace('.', '').replace(',', '.'));
|
||||
const valorB = parseFloat(b.replace('R$ ', '').replace('.', '').replace(',', '.'));
|
||||
|
||||
if (isNaN(valorA)) return -1;
|
||||
if (isNaN(valorB)) return 1;
|
||||
|
||||
return valorA - valorB;
|
||||
}
|
||||
|
||||
// Configurar ordenação para todas as tabelas com classe 'table-sort'
|
||||
document.querySelectorAll('table.table-sort').forEach(tabela => {
|
||||
const tbody = tabela.querySelector('tbody');
|
||||
const headers = tabela.querySelectorAll('th[data-sort]');
|
||||
|
||||
headers.forEach(header => {
|
||||
const tipoOrdenacao = header.dataset.sort;
|
||||
|
||||
header.addEventListener('click', () => {
|
||||
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||
const colIndex = Array.from(header.parentNode.children).indexOf(header);
|
||||
|
||||
rows.sort((rowA, rowB) => {
|
||||
const cellA = rowA.children[colIndex].dataset[tipoOrdenacao] || rowA.children[colIndex].textContent.trim();
|
||||
const cellB = rowB.children[colIndex].dataset[tipoOrdenacao] || rowB.children[colIndex].textContent.trim();
|
||||
|
||||
switch (tipoOrdenacao) {
|
||||
case 'data':
|
||||
return compararDatas(cellA, cellB);
|
||||
case 'valor':
|
||||
return compararValores(cellA, cellB);
|
||||
case 'numero':
|
||||
return parseFloat(cellA) - parseFloat(cellB);
|
||||
default:
|
||||
return cellA.localeCompare(cellB);
|
||||
}
|
||||
});
|
||||
|
||||
if (header.classList.contains('asc')) {
|
||||
rows.reverse();
|
||||
header.classList.remove('asc');
|
||||
header.classList.add('desc');
|
||||
} else {
|
||||
header.classList.remove('desc');
|
||||
header.classList.add('asc');
|
||||
}
|
||||
|
||||
// Remover classes de ordenação de outros headers
|
||||
headers.forEach(h => {
|
||||
if (h !== header) {
|
||||
h.classList.remove('asc', 'desc');
|
||||
}
|
||||
});
|
||||
|
||||
// Atualizar tabela
|
||||
tbody.innerHTML = '';
|
||||
rows.forEach(row => tbody.appendChild(row));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
284
static/js/testes.js
Normal file
284
static/js/testes.js
Normal file
@@ -0,0 +1,284 @@
|
||||
// Testes para o formulário de edição de militantes
|
||||
console.log('Iniciando testes do formulário de edição...');
|
||||
|
||||
// Lista de campos que devem existir no formulário
|
||||
const camposEsperados = {
|
||||
'edit_militante_id': { tipo: 'hidden', obrigatorio: true },
|
||||
'edit_nome': { tipo: 'text', obrigatorio: true },
|
||||
'edit_cpf': { tipo: 'text', obrigatorio: true },
|
||||
'edit_titulo_eleitoral': { tipo: 'text', obrigatorio: false },
|
||||
'edit_data_nascimento': { tipo: 'text', obrigatorio: false },
|
||||
'edit_data_entrada_oci': { tipo: 'text', obrigatorio: false },
|
||||
'edit_data_efetivacao_oci': { tipo: 'text', obrigatorio: false },
|
||||
'edit_email': { tipo: 'email', obrigatorio: true },
|
||||
'edit_telefone1': { tipo: 'text', obrigatorio: false },
|
||||
'edit_telefone2': { tipo: 'text', obrigatorio: false },
|
||||
'edit_cep': { tipo: 'text', obrigatorio: false },
|
||||
'edit_estado': { tipo: 'select', obrigatorio: false },
|
||||
'edit_cidade': { tipo: 'text', obrigatorio: false },
|
||||
'edit_bairro': { tipo: 'text', obrigatorio: false },
|
||||
'edit_rua': { tipo: 'text', obrigatorio: false },
|
||||
'edit_numero': { tipo: 'text', obrigatorio: false },
|
||||
'edit_complemento': { tipo: 'text', obrigatorio: false },
|
||||
'edit_empresa': { tipo: 'text', obrigatorio: false },
|
||||
'edit_contratante': { tipo: 'text', obrigatorio: false },
|
||||
'edit_instituicao_ensino': { tipo: 'text', obrigatorio: false },
|
||||
'edit_tipo_instituicao': { tipo: 'select', obrigatorio: false },
|
||||
'edit_sindicato': { tipo: 'text', obrigatorio: false },
|
||||
'edit_cargo_sindical': { tipo: 'text', obrigatorio: false },
|
||||
'edit_central_sindical': { tipo: 'text', obrigatorio: false },
|
||||
'edit_celula': { tipo: 'select', obrigatorio: false },
|
||||
'responsabilidades_values': { tipo: 'hidden', obrigatorio: false }
|
||||
};
|
||||
|
||||
// Função para testar a existência e configuração dos campos
|
||||
function testarCamposFormulario() {
|
||||
console.log('Testando campos do formulário...');
|
||||
const form = document.getElementById('formEditarMilitante');
|
||||
const erros = [];
|
||||
|
||||
if (!form) {
|
||||
console.error('Formulário não encontrado!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Testar cada campo esperado
|
||||
for (const [id, config] of Object.entries(camposEsperados)) {
|
||||
const campo = document.getElementById(id);
|
||||
if (!campo) {
|
||||
erros.push(`Campo ${id} não encontrado`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verificar tipo
|
||||
if (campo.type !== config.tipo && config.tipo !== 'select') {
|
||||
erros.push(`Campo ${id} tem tipo ${campo.type}, esperado ${config.tipo}`);
|
||||
}
|
||||
|
||||
// Verificar obrigatoriedade
|
||||
if (config.obrigatorio && !campo.hasAttribute('required')) {
|
||||
erros.push(`Campo ${id} deveria ser obrigatório`);
|
||||
}
|
||||
|
||||
// Verificar se o campo tem name attribute
|
||||
if (!campo.hasAttribute('name')) {
|
||||
erros.push(`Campo ${id} não tem atributo name`);
|
||||
}
|
||||
}
|
||||
|
||||
// Reportar erros encontrados
|
||||
if (erros.length > 0) {
|
||||
console.error('Erros encontrados nos campos:', erros);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Todos os campos estão configurados corretamente');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Função para testar o carregamento de dados
|
||||
async function testarCarregamentoDados(militanteId) {
|
||||
console.log('Testando carregamento de dados...');
|
||||
try {
|
||||
const response = await fetch(`/militantes/dados/${militanteId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erro HTTP: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Dados recebidos:', data);
|
||||
|
||||
// Verificar se os dados foram carregados corretamente
|
||||
const erros = [];
|
||||
|
||||
// Verificar campos básicos
|
||||
if (!data.nome) erros.push('Nome não carregado');
|
||||
if (!data.cpf) erros.push('CPF não carregado');
|
||||
|
||||
// Verificar se os campos foram preenchidos
|
||||
for (const [id, config] of Object.entries(camposEsperados)) {
|
||||
const campo = document.getElementById(id);
|
||||
if (!campo) continue;
|
||||
|
||||
// Mapear campos do servidor para campos do formulário
|
||||
let valorEsperado = '';
|
||||
switch(id) {
|
||||
case 'edit_nome': valorEsperado = data.nome; break;
|
||||
case 'edit_cpf': valorEsperado = data.cpf; break;
|
||||
case 'edit_email': valorEsperado = data.emails?.[0]; break;
|
||||
case 'edit_telefone1': valorEsperado = data.telefone1; break;
|
||||
case 'edit_celula': valorEsperado = data.celula_id?.toString(); break;
|
||||
case 'edit_cargo_sindical': valorEsperado = data.cargo_sindical; break;
|
||||
case 'edit_central_sindical': valorEsperado = data.central_sindical; break;
|
||||
case 'edit_sindicato': valorEsperado = data.sindicato; break;
|
||||
// Adicione mais campos conforme necessário
|
||||
}
|
||||
|
||||
if (config.obrigatorio && !valorEsperado) {
|
||||
erros.push(`Campo obrigatório ${id} não tem valor no servidor`);
|
||||
}
|
||||
|
||||
if (valorEsperado && campo.value !== valorEsperado) {
|
||||
erros.push(`Campo ${id} tem valor diferente do servidor. Esperado: ${valorEsperado}, Atual: ${campo.value}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (erros.length > 0) {
|
||||
console.error('Erros no carregamento:', erros);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Dados carregados corretamente');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Erro ao carregar dados:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Função para testar o salvamento de dados
|
||||
async function testarSalvamentoDados(militanteId) {
|
||||
console.log('Testando salvamento de dados...');
|
||||
try {
|
||||
const form = document.getElementById('formEditarMilitante');
|
||||
const formData = new FormData(form);
|
||||
|
||||
// Guardar valores originais para comparação
|
||||
const valoresOriginais = {
|
||||
nome: formData.get('nome'),
|
||||
cpf: formData.get('cpf'),
|
||||
email: formData.get('email'),
|
||||
celula: formData.get('celula'),
|
||||
cargo_sindical: formData.get('cargo_sindical'),
|
||||
central_sindical: formData.get('central_sindical'),
|
||||
sindicato: formData.get('sindicato'),
|
||||
responsabilidades: formData.get('responsabilidades_values')
|
||||
};
|
||||
|
||||
const response = await fetch(`/militantes/editar/${militanteId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erro HTTP: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Resposta do servidor:', data);
|
||||
|
||||
// Verificar se os dados foram salvos corretamente
|
||||
const row = document.querySelector(`tr[data-militante="${militanteId}"]`);
|
||||
if (!row) {
|
||||
console.error('Linha da tabela não encontrada após salvamento');
|
||||
return false;
|
||||
}
|
||||
|
||||
const erros = [];
|
||||
|
||||
// Verificar dados básicos na tabela
|
||||
const nome = row.querySelector('td[data-nome]')?.textContent;
|
||||
const cpf = row.querySelector('td[data-cpf]')?.textContent;
|
||||
const email = row.querySelector('td[data-email]')?.textContent;
|
||||
|
||||
if (nome !== valoresOriginais.nome) erros.push(`Nome não atualizado na tabela. Esperado: ${valoresOriginais.nome}, Atual: ${nome}`);
|
||||
if (cpf !== valoresOriginais.cpf) erros.push(`CPF não atualizado na tabela. Esperado: ${valoresOriginais.cpf}, Atual: ${cpf}`);
|
||||
if (email !== valoresOriginais.email) erros.push(`Email não atualizado na tabela. Esperado: ${valoresOriginais.email}, Atual: ${email}`);
|
||||
|
||||
// Verificar atributos para filtros
|
||||
const celulaId = row.getAttribute('data-celula-id');
|
||||
const responsabilidades = row.getAttribute('data-responsabilidades');
|
||||
|
||||
if (celulaId !== valoresOriginais.celula) erros.push(`Célula não atualizada na tabela. Esperado: ${valoresOriginais.celula}, Atual: ${celulaId}`);
|
||||
if (responsabilidades !== valoresOriginais.responsabilidades) erros.push(`Responsabilidades não atualizadas na tabela. Esperado: ${valoresOriginais.responsabilidades}, Atual: ${responsabilidades}`);
|
||||
|
||||
// Verificar botão de edição
|
||||
const btnEditar = row.querySelector('button[data-bs-target="#modalEditarMilitante"]');
|
||||
if (btnEditar) {
|
||||
if (btnEditar.getAttribute('data-militante-nome') !== valoresOriginais.nome) {
|
||||
erros.push('Nome não atualizado no botão de edição');
|
||||
}
|
||||
if (btnEditar.getAttribute('data-celula-id') !== valoresOriginais.celula) {
|
||||
erros.push('Célula não atualizada no botão de edição');
|
||||
}
|
||||
}
|
||||
|
||||
if (erros.length > 0) {
|
||||
console.error('Erros no salvamento:', erros);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Dados salvos e atualizados corretamente');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Erro ao salvar dados:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Função principal de teste
|
||||
async function testarFormularioEdicao(militanteId) {
|
||||
console.log('Iniciando teste completo do formulário...');
|
||||
|
||||
// Testar campos do formulário
|
||||
if (!testarCamposFormulario()) {
|
||||
console.error('Teste dos campos falhou');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Testar carregamento de dados
|
||||
if (!await testarCarregamentoDados(militanteId)) {
|
||||
console.error('Teste de carregamento falhou');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Testar salvamento de dados
|
||||
if (!await testarSalvamentoDados(militanteId)) {
|
||||
console.error('Teste de salvamento falhou');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Todos os testes passaram com sucesso!');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Executar testes quando o documento estiver carregado
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Adicionar botão de teste na interface
|
||||
const btnTeste = document.createElement('button');
|
||||
btnTeste.className = 'btn btn-info me-2';
|
||||
btnTeste.innerHTML = '<i class="fas fa-vial me-2"></i>Testar Formulário';
|
||||
btnTeste.onclick = function() {
|
||||
// Pegar ID do primeiro militante da lista
|
||||
const primeiraLinha = document.querySelector('#militantesTable tbody tr');
|
||||
if (!primeiraLinha) {
|
||||
mostrarAlerta('danger', 'Nenhum militante encontrado para teste');
|
||||
return;
|
||||
}
|
||||
|
||||
const militanteId = primeiraLinha.getAttribute('data-militante');
|
||||
if (!militanteId) {
|
||||
mostrarAlerta('danger', 'ID do militante não encontrado');
|
||||
return;
|
||||
}
|
||||
|
||||
// Executar testes
|
||||
testarFormularioEdicao(militanteId).then(sucesso => {
|
||||
if (sucesso) {
|
||||
mostrarAlerta('success', 'Testes concluídos com sucesso!');
|
||||
} else {
|
||||
mostrarAlerta('danger', 'Alguns testes falharam. Verifique o console para mais detalhes.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Adicionar botão ao lado do botão de exportar
|
||||
const btnExportar = document.querySelector('.btn-exportar');
|
||||
if (btnExportar && btnExportar.parentNode) {
|
||||
btnExportar.parentNode.insertBefore(btnTeste, btnExportar);
|
||||
}
|
||||
});
|
||||
119
static/js/vendas.js
Normal file
119
static/js/vendas.js
Normal file
@@ -0,0 +1,119 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Carregando script vendas.js...');
|
||||
|
||||
// Funções de validação e formatação de datas
|
||||
function validarData(data) {
|
||||
if (!data) return false;
|
||||
|
||||
const dataObj = new Date(data);
|
||||
if (isNaN(dataObj.getTime())) return false;
|
||||
|
||||
const hoje = new Date();
|
||||
hoje.setHours(0, 0, 0, 0);
|
||||
|
||||
return dataObj <= hoje;
|
||||
}
|
||||
|
||||
function formatarData(data) {
|
||||
if (!data) return '';
|
||||
|
||||
const dataObj = new Date(data);
|
||||
if (isNaN(dataObj.getTime())) return '';
|
||||
|
||||
return dataObj.toLocaleDateString('pt-BR');
|
||||
}
|
||||
|
||||
// Configurar campos de data
|
||||
const camposData = document.querySelectorAll('input[type="date"]');
|
||||
camposData.forEach(campo => {
|
||||
// Definir data máxima como hoje
|
||||
const hoje = new Date().toISOString().split('T')[0];
|
||||
campo.setAttribute('max', hoje);
|
||||
|
||||
campo.addEventListener('change', function() {
|
||||
if (!validarData(this.value)) {
|
||||
this.setCustomValidity('Data inválida ou futura');
|
||||
this.classList.add('is-invalid');
|
||||
} else {
|
||||
this.setCustomValidity('');
|
||||
this.classList.remove('is-invalid');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Configurar tabela de vendas
|
||||
const tabelaVendas = $('#vendasTable').DataTable({
|
||||
language: {
|
||||
url: '//cdn.datatables.net/plug-ins/1.13.7/i18n/pt-BR.json'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 3, // Coluna de data
|
||||
type: 'date-br',
|
||||
render: function(data, type, row) {
|
||||
if (type === 'sort') {
|
||||
return data.split('/').reverse().join('');
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 2, // Coluna de valor
|
||||
type: 'numeric',
|
||||
render: function(data, type, row) {
|
||||
if (type === 'sort') {
|
||||
return parseFloat(data.replace('R$ ', '').replace(',', '.'));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
{ targets: -1, orderable: false } // Coluna de ações
|
||||
],
|
||||
order: [[3, 'desc']] // Ordenar por data decrescente por padrão
|
||||
});
|
||||
|
||||
// Atualizar valor total ao mudar quantidade ou material
|
||||
const campoQuantidade = document.getElementById('quantidade');
|
||||
const campoMaterial = document.getElementById('material_id');
|
||||
const campoValorTotal = document.getElementById('valor_total');
|
||||
|
||||
function atualizarValorTotal() {
|
||||
if (!campoQuantidade || !campoMaterial || !campoValorTotal) return;
|
||||
|
||||
const quantidade = parseInt(campoQuantidade.value) || 0;
|
||||
const materialSelecionado = campoMaterial.options[campoMaterial.selectedIndex];
|
||||
const preco = materialSelecionado ? parseFloat(materialSelecionado.dataset.preco) || 0 : 0;
|
||||
|
||||
campoValorTotal.value = (quantidade * preco).toFixed(2);
|
||||
}
|
||||
|
||||
if (campoQuantidade) {
|
||||
campoQuantidade.addEventListener('change', atualizarValorTotal);
|
||||
}
|
||||
if (campoMaterial) {
|
||||
campoMaterial.addEventListener('change', atualizarValorTotal);
|
||||
}
|
||||
|
||||
// Configurar modal de edição
|
||||
const modalEditarVenda = document.getElementById('modalEditarVenda');
|
||||
if (modalEditarVenda) {
|
||||
modalEditarVenda.addEventListener('show.bs.modal', function(event) {
|
||||
const button = event.relatedTarget;
|
||||
if (!button) return;
|
||||
|
||||
const vendaId = button.getAttribute('data-venda-id');
|
||||
const militanteId = button.getAttribute('data-militante-id');
|
||||
const materialId = button.getAttribute('data-material-id');
|
||||
const quantidade = button.getAttribute('data-quantidade');
|
||||
const valorTotal = button.getAttribute('data-valor-total');
|
||||
const dataVenda = button.getAttribute('data-data-venda');
|
||||
|
||||
document.getElementById('editVendaId').value = vendaId;
|
||||
document.getElementById('editMilitanteId').value = militanteId;
|
||||
document.getElementById('editMaterialId').value = materialId;
|
||||
document.getElementById('editQuantidade').value = quantidade;
|
||||
document.getElementById('editValorTotal').value = valorTotal;
|
||||
document.getElementById('editDataVenda').value = dataVenda;
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user