CREACION DE API: INGRESOS FORMAS DE PAGO.

This commit is contained in:
Pablinux
2025-06-09 13:07:09 -05:00
parent 8afb1d09cb
commit ca19ab418b
3 changed files with 459 additions and 1 deletions

View File

@@ -205,7 +205,7 @@ controlador.consulta_clientesApps = (req, res) => { // Nombre de la función cam
FROM FROM
clientes clientes
WHERE WHERE
client_nombre LIKE ? OR client_rucCed LIKE ? client_nombre LIKE %?% OR client_rucCed LIKE %?%
LIMIT 10; LIMIT 10;
`; `;

View File

@@ -0,0 +1,440 @@
// controladores/controlador_ContPagosTransacciones.js
const controladorContPagosTransacciones = {
/**
* @function crearTransaccion
* @description Crea un nuevo registro en la tabla `cont_pagos_transacciones`.
* @param {Object} req - Objeto de solicitud de Express (req.body).
* @param {Object} res - Objeto de respuesta de Express.
*/
crearTransaccion: (req, res) => {
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para crear transacción de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const {
monto_total_cobro,
client_id,
// id_miembro ya no se espera aquí
origen_transaccion,
documento_cobro_tipo,
numero_documento,
fecha_documento,
referencia_interna, // Puede ser id_visita, id_venta, id_membresia, id_miembro
cuenta_contable_ingreso_codigo,
tipo_movimiento_contable, // Espera 'Entrada'
estado_transaccion, // Valor inicial, ej. 'Pendiente' o 'Conciliado'
registrado_por,
observaciones
} = req.body;
// Validaciones básicas de campos obligatorios
if (!monto_total_cobro || !client_id || !origen_transaccion || !documento_cobro_tipo ||
!numero_documento || !fecha_documento || !cuenta_contable_ingreso_codigo ||
!tipo_movimiento_contable || !estado_transaccion) {
return res.status(400).json({ mensaje: 'Faltan campos obligatorios para crear la transacción de pago.' });
}
// Validar tipos ENUM (aunque MySQL los valida al insertar)
// Se asume que 'tipo_cobro' se gestiona a través del 'origen_transaccion' y el estado del proceso de pago.
// La tabla no tiene un campo 'tipo_cobro' directo, sino que se infiere de 'estado_transaccion' y el contexto.
// Si necesitas validar tipo_cobro aquí, agrégalo a req.body y a la validación.
// Ejemplo: if (!['Contado', 'Crédito', 'Mixto'].includes(req.body.tipo_cobro)) {...}
if (!['Pendiente', 'Conciliado', 'ParcialmentePagado', 'Anulado', 'Devuelto', 'EnMora', 'Rechazado'].includes(estado_transaccion)) {
return res.status(400).json({ mensaje: 'El estado_transaccion proporcionado no es válido.' });
}
if (tipo_movimiento_contable !== 'Entrada') { // Para cobros, siempre 'Entrada'
return res.status(400).json({ mensaje: 'El tipo_movimiento_contable para un cobro debe ser "Entrada".' });
}
// Construir la fecha de documento (si no viene en formato DATETIME correcto)
const fechaDocumentoFormateada = new Date(fecha_documento).toISOString().slice(0, 19).replace('T', ' ');
const query = `
INSERT INTO cont_pagos_transacciones (
monto_total_cobro, client_id, origen_transaccion,
documento_cobro_tipo, numero_documento, fecha_documento, referencia_interna,
cuenta_contable_ingreso_codigo, tipo_movimiento_contable, estado_transaccion,
registrado_por, observaciones
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
const values = [
monto_total_cobro,
client_id,
origen_transaccion,
documento_cobro_tipo,
numero_documento,
fechaDocumentoFormateada,
referencia_interna || null,
cuenta_contable_ingreso_codigo,
tipo_movimiento_contable,
estado_transaccion,
registrado_por || null,
observaciones || null
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al crear transacción de pago:', err);
if (err.code === 'ER_NO_REFERENCED_ROW_2' || err.code === 'ER_NO_REFERENCED_ROW') {
return res.status(400).json({ mensaje: 'El cliente referenciado no existe.', error: err.message });
}
if (err.code === 'ER_DUP_ENTRY') {
return res.status(409).json({ mensaje: `El documento de cobro ${documento_cobro_tipo} con número ${numero_documento} ya existe.`, error: err.message });
}
return res.status(500).json({ mensaje: 'Error interno del servidor al crear la transacción de pago.', error: err.message });
}
if (result.affectedRows === 1) {
res.status(201).json({
mensaje: 'Transacción de pago creada exitosamente.',
id_transaccion: result.insertId,
datos_creados: { id_transaccion: result.insertId, monto_total_cobro, client_id, origen_transaccion, numero_documento }
});
} else {
res.status(500).json({ mensaje: 'Error al crear la transacción de pago: no se afectó ninguna fila.' });
}
});
});
},
/**
* @function listarTransacciones
* @description Lista todas las transacciones de pagos, con detalles de cliente y cuenta contable.
* Permite filtros opcionales por client_id, estado_transaccion, origen_transaccion, etc.
* @param {Object} req - Objeto de solicitud de Express (req.query para filtros).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarTransacciones: (req, res) => {
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar transacciones de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
let query = `
SELECT
cpt.*,
cli.client_nombre,
cli.client_rucCed,
cc_ingreso.contCuent_Detalle AS cuenta_ingreso_detalle
FROM
cont_pagos_transacciones cpt
JOIN
clientes cli ON cpt.client_id = cli.client_id
JOIN
cont_cuentas cc_ingreso ON cpt.cuenta_contable_ingreso_codigo = cc_ingreso.contCuent_codigo
WHERE 1=1
`;
const queryParams = [];
// Aplicar filtros desde req.query
if (req.query.client_id) {
query += ` AND cpt.client_id = ?`;
queryParams.push(req.query.client_id);
}
// id_miembro ya no es un campo directo para filtrar
if (req.query.estado_transaccion) {
query += ` AND cpt.estado_transaccion = ?`;
queryParams.push(req.query.estado_transaccion);
}
if (req.query.origen_transaccion) {
query += ` AND cpt.origen_transaccion = ?`;
queryParams.push(req.query.origen_transaccion);
}
if (req.query.numero_documento) {
query += ` AND cpt.numero_documento LIKE ?`;
queryParams.push(`%${req.query.numero_documento}%`);
}
// Puedes añadir filtros por rango de fechas (ej. fecha_hora_registro_desde, fecha_hora_registro_hasta)
if (req.query.fecha_desde) {
query += ` AND cpt.fecha_hora_registro >= ?`;
queryParams.push(req.query.fecha_desde + ' 00:00:00');
}
if (req.query.fecha_hasta) {
query += ` AND cpt.fecha_hora_registro <= ?`;
queryParams.push(req.query.fecha_hasta + ' 23:59:59');
}
query += ` ORDER BY cpt.fecha_hora_registro DESC`;
// Implementar paginación si se necesita
connection.query(query, queryParams, (err, rows) => {
if (err) {
console.error('Error al listar transacciones de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar transacciones de pago.', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function obtenerTransaccionPorId
* @description Obtiene una transacción de pago específica por su ID.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_transaccion).
* @param {Object} res - Objeto de respuesta de Express.
*/
obtenerTransaccionPorId: (req, res) => {
const { id_transaccion } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para transacción de pago por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cpt.*,
cli.client_nombre,
cli.client_rucCed,
cc_ingreso.contCuent_Detalle AS cuenta_ingreso_detalle
FROM
cont_pagos_transacciones cpt
JOIN
clientes cli ON cpt.client_id = cli.client_id
JOIN
cont_cuentas cc_ingreso ON cpt.cuenta_contable_ingreso_codigo = cc_ingreso.contCuent_codigo
WHERE cpt.id_transaccion = ?
`;
connection.query(query, [id_transaccion], (err, rows) => {
if (err) {
console.error('Error al obtener transacción de pago por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener transacción de pago.', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'Transacción de pago no encontrada.' });
}
res.json(rows[0]);
});
});
},
/**
* @function actualizarTransaccion
* @description Actualiza un registro de transacción de pago existente por su ID.
* Se permiten actualizar campos específicos como monto_total_cobro, referencia_interna, estado_transaccion,
* fecha_liquidado_conciliado, registrado_por, observaciones.
* Campos como client_id, origen_transaccion, documento_cobro_tipo, numero_documento, fecha_documento,
* cuenta_contable_ingreso_codigo, tipo_movimiento_contable NO deben actualizarse para mantener la auditoría original.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_transaccion, req.body).
* @param {Object} res - Objeto de respuesta de Express.
*/
actualizarTransaccion: (req, res) => {
const { id_transaccion } = req.params;
const {
monto_total_cobro,
referencia_interna,
estado_transaccion,
fecha_liquidado_conciliado,
registrado_por,
observaciones
} = req.body;
if (!monto_total_cobro || !estado_transaccion) {
return res.status(400).json({ mensaje: 'Faltan campos obligatorios para actualizar la transacción (monto_total_cobro, estado_transaccion).' });
}
if (!['Pendiente', 'Conciliado', 'ParcialmentePagado', 'Anulado', 'Devuelto', 'EnMora', 'Rechazado'].includes(estado_transaccion)) {
return res.status(400).json({ mensaje: 'El estado_transaccion proporcionado para la actualización no es válido.' });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para actualizar transacción de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
UPDATE cont_pagos_transacciones SET
monto_total_cobro = ?,
referencia_interna = ?,
estado_transaccion = ?,
fecha_liquidado_conciliado = ?,
registrado_por = ?,
observaciones = ?,
fecha_actualizacion = CURRENT_TIMESTAMP()
WHERE id_transaccion = ?
`;
const values = [
monto_total_cobro,
referencia_interna || null,
estado_transaccion,
fecha_liquidado_conciliado || null,
registrado_por || null,
observaciones || null,
id_transaccion
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al actualizar transacción de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al actualizar transacción de pago.', error: err.message });
}
if (result.affectedRows === 0) {
return res.status(404).json({ mensaje: 'Transacción de pago no encontrada para actualizar.' });
}
res.json({ mensaje: 'Transacción de pago actualizada exitosamente.' });
});
});
},
/**
* @function anularTransaccion
* @description Realiza una "eliminación lógica" de una transacción de pago,
* cambiando su `estado_transaccion` a 'Anulado'.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_transaccion, req.body.registrado_por, req.body.observaciones_anulacion).
* @param {Object} res - Objeto de respuesta de Express.
*/
anularTransaccion: (req, res) => {
const { id_transaccion } = req.params;
const { registrado_por, observaciones_anulacion } = req.body;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para anular transacción de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
connection.query('SELECT estado_transaccion FROM cont_pagos_transacciones WHERE id_transaccion = ?', [id_transaccion], (err, rows) => {
if (err) {
console.error('Error al verificar estado de transacción para anular:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al verificar estado.', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'Transacción de pago no encontrada para anular.' });
}
if (rows[0].estado_transaccion === 'Anulado') {
return res.status(409).json({ mensaje: 'La transacción ya se encuentra anulada.' });
}
// Si la transacción ya está conciliada, podría requerir un proceso de "reversión" contable
// más complejo en lugar de una simple anulación.
// if (rows[0].estado_transaccion === 'Conciliado') {
// return res.status(409).json({ mensaje: 'No se puede anular una transacción ya conciliada. Debe realizar una reversión.' });
// }
const query = `
UPDATE cont_pagos_transacciones SET
estado_transaccion = 'Anulado',
observaciones = CONCAT(IFNULL(observaciones, ''), '\nAnulado por: ', ?, ' - Motivo: ', ?, ' - Fecha: ', CURRENT_TIMESTAMP()),
fecha_actualizacion = CURRENT_TIMESTAMP()
WHERE id_transaccion = ?
`;
const values = [
registrado_por || 'Sistema/API',
observaciones_anulacion || 'Sin motivo especificado',
id_transaccion
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al anular transacción de pago:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al anular transacción de pago.', error: err.message });
}
if (result.affectedRows === 0) {
return res.status(404).json({ mensaje: 'Transacción de pago no encontrada para anular.' });
}
res.json({ mensaje: 'Transacción de pago anulada exitosamente (estado cambiado a "Anulado").' });
});
});
});
},
/**
* @function listarTransaccionesPorCliente
* @description Lista transacciones de pago filtradas por un client_id específico.
* @param {Object} req - Objeto de solicitud de Express (req.params.client_id).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarTransaccionesPorCliente: (req, res) => {
const { client_id } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar transacciones por cliente:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cpt.*,
cli.client_nombre,
cli.client_rucCed,
cc_ingreso.contCuent_Detalle AS cuenta_ingreso_detalle
FROM
cont_pagos_transacciones cpt
JOIN
clientes cli ON cpt.client_id = cli.client_id
JOIN
cont_cuentas cc_ingreso ON cpt.cuenta_contable_ingreso_codigo = cc_ingreso.contCuent_codigo
WHERE cpt.client_id = ?
ORDER BY cpt.fecha_hora_registro DESC
`;
connection.query(query, [client_id], (err, rows) => {
if (err) {
console.error('Error al listar transacciones por cliente:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar transacciones por cliente.', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'No se encontraron transacciones para el cliente proporcionado.' });
}
res.json(rows);
});
});
},
/**
* @function listarTransaccionesPorEstado
* @description Lista transacciones de pago filtradas por un estado_transaccion específico.
* @param {Object} req - Objeto de solicitud de Express (req.params.estado_transaccion).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarTransaccionesPorEstado: (req, res) => {
const { estado_transaccion } = req.params;
const estadosPermitidos = ['Pendiente', 'Conciliado', 'ParcialmentePagado', 'Anulado', 'Devuelto', 'EnMora', 'Rechazado'];
if (!estadosPermitidos.includes(estado_transaccion)) {
return res.status(400).json({ mensaje: `El estado proporcionado '${estado_transaccion}' no es válido. Los estados permitidos son: ${estadosPermitidos.join(', ')}.` });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar transacciones por estado:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cpt.*,
cli.client_nombre,
cli.client_rucCed,
cc_ingreso.contCuent_Detalle AS cuenta_ingreso_detalle
FROM
cont_pagos_transacciones cpt
JOIN
clientes cli ON cpt.client_id = cli.client_id
JOIN
cont_cuentas cc_ingreso ON cpt.cuenta_contable_ingreso_codigo = cc_ingreso.contCuent_codigo
WHERE cpt.estado_transaccion = ?
ORDER BY cpt.fecha_hora_registro DESC
`;
connection.query(query, [estado_transaccion], (err, rows) => {
if (err) {
console.error('Error al listar transacciones por estado:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar transacciones por estado.', error: err.message });
}
res.json(rows);
});
});
}
};
module.exports = controladorContPagosTransacciones;

View File

@@ -2,6 +2,7 @@ const express = require('express');
const rutas = express.Router(); const rutas = express.Router();
const controlador_init = require('../controladores/controlador_General'); const controlador_init = require('../controladores/controlador_General');
const controladorContPagosTransacciones = require('../controladores/controlador_Cont_PagosTransacciones');
//ver listar items /formulario/:varNomCampoDb, controlador clase.funcion //ver listar items /formulario/:varNomCampoDb, controlador clase.funcion
rutas.get('/ventasJson/', controlador_init.verVentasJson);//ver productos en modo json/get rutas.get('/ventasJson/', controlador_init.verVentasJson);//ver productos en modo json/get
//rutas.get('/', controlador_init.app_sigma);//Una app para PEDIDOS //rutas.get('/', controlador_init.app_sigma);//Una app para PEDIDOS
@@ -25,6 +26,23 @@ rutas.post('/login_app', controlador_init.login_appTK);//login APP / dev
rutas.post('/auth-keygen', controlador_init.auth_keygen);//genera TOKENS / dev rutas.post('/auth-keygen', controlador_init.auth_keygen);//genera TOKENS / dev
rutas.post('/auth-token', controlador_init.auth_token);//Valida TOKENS / dev rutas.post('/auth-token', controlador_init.auth_token);//Valida TOKENS / dev
// --- Rutas RESTful para Transacciones de Pagos (cont_pagos_transacciones) ---
// Crear una nueva transacción de pago
rutas.post('/api/pagos/transacciones', controladorContPagosTransacciones.crearTransaccion);
// Obtener todas las transacciones de pagos (con filtros opcionales)
rutas.get('/api/pagos/transacciones', controladorContPagosTransacciones.listarTransacciones);
// Obtener una transacción de pago por su ID
rutas.get('/api/pagos/transacciones/:id_transaccion', controladorContPagosTransacciones.obtenerTransaccionPorId);
// Actualizar una transacción de pago existente
rutas.put('/api/pagos/transacciones/:id_transaccion', controladorContPagosTransacciones.actualizarTransaccion);
// "Eliminar" lógicamente (cambiar estado a 'Anulado') una transacción de pago
rutas.put('/api/pagos/transacciones/:id_transaccion/anular', controladorContPagosTransacciones.anularTransaccion);
// (Opcional) Obtener transacciones por cliente
rutas.get('/api/pagos/transacciones/por-cliente/:client_id', controladorContPagosTransacciones.listarTransaccionesPorCliente);
// (Opcional) Obtener transacciones por estado
rutas.get('/api/pagos/transacciones/estado/:estado_transaccion', controladorContPagosTransacciones.listarTransaccionesPorEstado);
/** /**
* @swagger * @swagger
* /operaciones: * /operaciones: