Carpeta js
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
const table = $('#tablaClientes').DataTable({
|
||||
paging: true,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
pageLength: 7,
|
||||
lengthChange: false,
|
||||
info: true,
|
||||
autoWidth: false,
|
||||
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: - 1 }
|
||||
],
|
||||
|
||||
dom:
|
||||
"<'row mb-3'<'col-md-8'f><'col-md-4 text-end'l>>" +
|
||||
"<'row'<'col-12'tr>>" +
|
||||
"<'row mt-3'<'col-md-5'i><'col-md-7'p>>",
|
||||
|
||||
language: {
|
||||
search: "",
|
||||
searchPlaceholder: "Buscar clientes...",
|
||||
zeroRecords: "No se encontraron clientes",
|
||||
info: "Mostrando _START_ a _END_ de _TOTAL_ clientes",
|
||||
infoEmpty: "No hay clientes para mostrar",
|
||||
infoFiltered: "(filtrado de _MAX_ clientes totales)",
|
||||
paginate: {
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Insertamos el select al lado del buscador
|
||||
|
||||
$('.dataTables_filter')
|
||||
.addClass('d-flex align-items-center gap-2')
|
||||
.appendTo('#filtrosIzquierda');
|
||||
|
||||
$('#filtrosIzquierda').append($('#columnFilter'));
|
||||
|
||||
const searchInput = $('.dataTables_filter input');
|
||||
|
||||
$('#columnFilter').on('change', function () {
|
||||
const colIndex = $(this).val();
|
||||
|
||||
table.search('').columns().search('').draw();
|
||||
|
||||
searchInput.off('keyup').on('keyup', function () {
|
||||
if (colIndex === "") {
|
||||
table.search(this.value).draw();
|
||||
} else {
|
||||
table.column(colIndex).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
const table = $('#tablaDetalleVenta').DataTable({
|
||||
paging: true,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
pageLength: 7,
|
||||
lengthChange: false,
|
||||
info: true,
|
||||
autoWidth: false,
|
||||
|
||||
columnDefs: [
|
||||
{ orderable: false}
|
||||
],
|
||||
|
||||
dom:
|
||||
"<'row mb-3'<'col-md-8'f><'col-md-4 text-end'l>>" +
|
||||
"<'row'<'col-12'tr>>" +
|
||||
"<'row mt-3'<'col-md-5'i><'col-md-7'p>>",
|
||||
|
||||
language: {
|
||||
search: "",
|
||||
searchPlaceholder: "Buscar producto...",
|
||||
zeroRecords: "No se encontraron productos",
|
||||
info: "Mostrando _START_ a _END_ de _TOTAL_ productos",
|
||||
infoEmpty: "No hay productos para mostrar",
|
||||
infoFiltered: "(filtrado de _MAX_ productos totales)",
|
||||
paginate: {
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Insertamos el select al lado del buscador
|
||||
|
||||
$('.dataTables_filter')
|
||||
.addClass('d-flex align-items-center')
|
||||
.append($('#columnFilter'));
|
||||
|
||||
const searchInput = $('.dataTables_filter input');
|
||||
|
||||
$('#columnFilter').on('change', function () {
|
||||
const colIndex = $(this).val();
|
||||
|
||||
table.search('').columns().search('').draw();
|
||||
|
||||
searchInput.off('keyup').on('keyup', function () {
|
||||
if (colIndex === "") {
|
||||
table.search(this.value).draw();
|
||||
} else {
|
||||
table.column(colIndex).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
const table = $('#tablaVentas').DataTable({
|
||||
paging: true,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
pageLength: 7,
|
||||
lengthChange: false,
|
||||
info: true,
|
||||
autoWidth: false,
|
||||
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: - 1 }
|
||||
],
|
||||
|
||||
dom:
|
||||
"<'row mb-3'<'col-md-8'f><'col-md-4 text-end'l>>" +
|
||||
"<'row'<'col-12'tr>>" +
|
||||
"<'row mt-3'<'col-md-5'i><'col-md-7'p>>",
|
||||
|
||||
language: {
|
||||
search: "",
|
||||
searchPlaceholder: "Buscar venta...",
|
||||
zeroRecords: "No se encontraron ventas",
|
||||
info: "Mostrando _START_ a _END_ de _TOTAL_ ventas",
|
||||
infoEmpty: "No hay ventas para mostrar",
|
||||
infoFiltered: "(filtrado de _MAX_ ventas totales)",
|
||||
paginate: {
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Insertamos el select al lado del buscador
|
||||
|
||||
$('.dataTables_filter')
|
||||
.addClass('d-flex align-items-center')
|
||||
.append($('#columnFilter'));
|
||||
|
||||
const searchInput = $('.dataTables_filter input');
|
||||
|
||||
$('#columnFilter').on('change', function () {
|
||||
const colIndex = $(this).val();
|
||||
|
||||
table.search('').columns().search('').draw();
|
||||
|
||||
searchInput.off('keyup').on('keyup', function () {
|
||||
if (colIndex === "") {
|
||||
table.search(this.value).draw();
|
||||
} else {
|
||||
table.column(colIndex).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
const table = $('#tablaProductos').DataTable({
|
||||
paging: true,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
pageLength: 6,
|
||||
lengthChange: false,
|
||||
info: true,
|
||||
autoWidth: false,
|
||||
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [-1, -2] }
|
||||
],
|
||||
|
||||
dom:
|
||||
"<'row mb-3'<'col-md-8'f><'col-md-4 text-end'l>>" +
|
||||
"<'row'<'col-12'tr>>" +
|
||||
"<'row mt-3'<'col-md-5'i><'col-md-7'p>>",
|
||||
|
||||
language: {
|
||||
search: "",
|
||||
searchPlaceholder: "Buscar productos...",
|
||||
zeroRecords: "No se encontraron productos",
|
||||
info: "Mostrando _START_ a _END_ de _TOTAL_ productos",
|
||||
infoEmpty: "No hay productos para mostrar",
|
||||
infoFiltered: "(filtrado de _MAX_ productos totales)",
|
||||
paginate: {
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Mover buscador al bloque izquierdo
|
||||
|
||||
$('.dataTables_filter')
|
||||
.addClass('d-flex align-items-center gap-2')
|
||||
.appendTo('#filtrosIzquierda');
|
||||
|
||||
$('#filtrosIzquierda').append($('#columnFilter'));
|
||||
|
||||
const searchInput = $('.dataTables_filter input');
|
||||
|
||||
$('#columnFilter').on('change', function () {
|
||||
const colIndex = $(this).val();
|
||||
|
||||
table.search('').columns().search('').draw();
|
||||
|
||||
searchInput.off('keyup').on('keyup', function () {
|
||||
if (colIndex === "") {
|
||||
table.search(this.value).draw();
|
||||
} else {
|
||||
table.column(colIndex).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// SUBMIT (problema de checkbox)
|
||||
|
||||
$('form').on('submit', function () {
|
||||
|
||||
const form = this;
|
||||
|
||||
// Obtener TODOS los checkboxes marcados del DataTable (no solo los visibles)
|
||||
|
||||
const checked = table.$('input[name="ids[]"]:checked');
|
||||
|
||||
// Eliminar cualquier ids[] previo agregado dinámicamente
|
||||
|
||||
$(form).find('input[name="ids[]"][type="hidden"]').remove();
|
||||
|
||||
// Agregar hidden inputs reales al form
|
||||
|
||||
checked.each(function () {
|
||||
$('<input>')
|
||||
.attr('type', 'hidden')
|
||||
.attr('name', 'ids[]')
|
||||
.val($(this).val())
|
||||
.appendTo(form);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
if (serverErrors.length > 0) mostrarErrores(serverErrors);
|
||||
if (serverSuccess.length > 0) mostrarSuccess(serverSuccess);
|
||||
|
||||
const form = document.getElementById("form-crear-venta");
|
||||
if (!form) return;
|
||||
|
||||
// Utilidades
|
||||
|
||||
function isEmpty(value) {
|
||||
return !value || value.trim() === '';
|
||||
}
|
||||
|
||||
function toFloat(value) {
|
||||
return parseFloat(value) || 0;
|
||||
}
|
||||
|
||||
// Submit
|
||||
|
||||
form.addEventListener("submit", (e) => {
|
||||
|
||||
let errores = [];
|
||||
|
||||
const condIva = form.querySelector("[name='cond_iva']");
|
||||
const cuit = form.querySelector("[name='cuit']");
|
||||
const formaPago = form.querySelector("[name='forma_pago']");
|
||||
const tipoPago = form.querySelector("[name='tipo_pago']");
|
||||
const descuento = form.querySelector("[name='descuento']");
|
||||
const recargo = form.querySelector("[name='recargo']");
|
||||
|
||||
// limpiar estados previos
|
||||
|
||||
form.querySelectorAll(".is-invalid").forEach(el =>
|
||||
el.classList.remove("is-invalid")
|
||||
);
|
||||
|
||||
// FORMA Y TIPO DE PAGO
|
||||
|
||||
const reglasPago = {
|
||||
'efectivo': ['pago_unico'],
|
||||
'transferencia': ['pago_unico'],
|
||||
'echeq': ['pago_unico'],
|
||||
'debito': ['pago_unico'],
|
||||
'credito': ['pago_unico', '3_cuotas', '6_cuotas', '12_cuotas'],
|
||||
};
|
||||
|
||||
if (formaPago && tipoPago) {
|
||||
|
||||
const tiposValidos = reglasPago[formaPago.value] || [];
|
||||
|
||||
if (!tiposValidos.includes(tipoPago.value)) {
|
||||
errores.push("Combinación de forma y tipo de pago inválida.");
|
||||
formaPago.classList.add("is-invalid");
|
||||
tipoPago.classList.add("is-invalid");
|
||||
}
|
||||
}
|
||||
|
||||
// DESCUENTO / RECARGO
|
||||
|
||||
if (descuento) {
|
||||
const d = toFloat(descuento.value);
|
||||
|
||||
if (d < 0 || d > 100) {
|
||||
errores.push("El descuento debe estar entre 0 y 100%.");
|
||||
descuento.classList.add("is-invalid");
|
||||
}
|
||||
}
|
||||
|
||||
// RECARGO
|
||||
|
||||
if (recargo) {
|
||||
const r = toFloat(recargo.value);
|
||||
|
||||
if (r < 0 || r > 100) {
|
||||
errores.push("El recargo debe estar entre 0 y 100%.");
|
||||
recargo.classList.add("is-invalid");
|
||||
}
|
||||
}
|
||||
|
||||
// Resultado
|
||||
|
||||
if (errores.length > 0) {
|
||||
e.preventDefault();
|
||||
mostrarErrores(errores);
|
||||
}
|
||||
});
|
||||
|
||||
// FUNCIÓN PARA MOSTRAR ERRORES
|
||||
|
||||
function mostrarErrores(errores) {
|
||||
|
||||
// Buscar si hay un toast previo
|
||||
|
||||
const viejo = document.getElementById("toastErrores");
|
||||
|
||||
// Si existe, se elimina (evita duplicados)
|
||||
|
||||
if (viejo) viejo.remove();
|
||||
|
||||
// Crea el contenedor del toast
|
||||
|
||||
const toast = document.createElement("div");
|
||||
|
||||
// Se le asigna ID para identificarlo
|
||||
|
||||
toast.id = "toastErrores";
|
||||
|
||||
// Clases de estilo (Bootstrap + CSS)
|
||||
|
||||
toast.className = "toast-flotante alert alert-danger";
|
||||
|
||||
// Inserta el contenido dinámico (lista de errores)
|
||||
|
||||
toast.innerHTML = `
|
||||
<strong>Se encontraron errores:</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
${errores.map(e => `<li>${e}</li>`).join("")} <!-- convierte array a <li> -->
|
||||
</ul>
|
||||
`;
|
||||
|
||||
// Agrega el toast al body (lo hace visible)
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// Auto-cierre
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
// Agrega clase para animación de salida (CSS)
|
||||
|
||||
toast.classList.add("toast-out");
|
||||
|
||||
// Elimina el elemento después de la animación
|
||||
|
||||
setTimeout(() => {
|
||||
toast.remove(); // Elimina el DOM
|
||||
}, 350);
|
||||
|
||||
}, 5000); // Visible durante 5 segundos
|
||||
}
|
||||
});
|
||||
|
||||
// FUNCIÓN PARA MOSTRAR SUCCESS
|
||||
|
||||
function mostrarSuccess(mensajes) {
|
||||
|
||||
// Elimina toast previo de éxito si existe
|
||||
|
||||
const viejo = document.getElementById("toastSuccess");
|
||||
if (viejo) viejo.remove();
|
||||
|
||||
// Crea el contenedor del toast
|
||||
|
||||
const toast = document.createElement("div");
|
||||
|
||||
// Se le asigna ID único
|
||||
|
||||
toast.id = "toastSuccess";
|
||||
|
||||
// Estilo
|
||||
|
||||
toast.className = "toast-flotante alert alert-success";
|
||||
|
||||
// Inserta mensajes dinámicos
|
||||
|
||||
toast.innerHTML = `
|
||||
<strong>Mensajes de éxito:</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
${mensajes.map(m => `<li>${m}</li>`).join("")}
|
||||
</ul>
|
||||
`;
|
||||
|
||||
// Agrega al DOM
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// Auto-cierre a los 5 segundos
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
// Animación de salida
|
||||
|
||||
toast.classList.add("toast-out");
|
||||
|
||||
// Eliminación final
|
||||
|
||||
setTimeout(() => {
|
||||
toast.remove();
|
||||
}, 350);
|
||||
|
||||
}, 5000);
|
||||
}
|
||||
Reference in New Issue
Block a user