Estructura multi-agencias

This commit is contained in:
2025-06-18 13:10:45 -06:00
parent a75e07c587
commit a830e3a84a
4 changed files with 104 additions and 34 deletions

View File

@@ -1,4 +1,5 @@
-- 1. Tabla de Agencias Aduanales -- 1. Tabla de Agencias Aduanales
CREATE TABLE [dbo].[agencias_aduanales]( CREATE TABLE [dbo].[agencias_aduanales](
[id_agencia] [int] IDENTITY(1,1) NOT NULL, [id_agencia] [int] IDENTITY(1,1) NOT NULL,
[nombre_agencia] [nvarchar](255) NOT NULL, [nombre_agencia] [nvarchar](255) NOT NULL,
@@ -6,22 +7,39 @@ CREATE TABLE [dbo].[agencias_aduanales](
[direccion] [nvarchar](500) NULL, [direccion] [nvarchar](500) NULL,
[telefono] [nvarchar](20) NULL, [telefono] [nvarchar](20) NULL,
[email] [nvarchar](255) NULL, [email] [nvarchar](255) NULL,
[id_administrador] [int] NULL, -- Usuario administrador de la agencia
[activo] [bit] NOT NULL DEFAULT 1, [activo] [bit] NOT NULL DEFAULT 1,
[creado_en] [datetime] NOT NULL DEFAULT GETDATE(), [creado_en] [datetime] NOT NULL DEFAULT GETDATE(),
[actualizado_en] [datetime] NULL, [actualizado_en] [datetime] NULL,
[creado_por] [int] NULL, -- Super admin que creó la agencia
CONSTRAINT [PK_agencias_aduanales] PRIMARY KEY CLUSTERED ([id_agencia] ASC) CONSTRAINT [PK_agencias_aduanales] PRIMARY KEY CLUSTERED ([id_agencia] ASC)
); );
-- 2. Modificar tabla usuarios_sistema para agregar referencia a agencia (solo para agentes)
ALTER TABLE [dbo].[usuarios_sistema]
ADD [id_agencia] [int] NULL;
-- Agregar foreign key constraint -- Agregar foreign key para administrador de agencia
ALTER TABLE [dbo].[agencias_aduanales]
ADD CONSTRAINT [FK_agencias_administrador]
FOREIGN KEY ([id_administrador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]);
-- 2. Actualizar tipos de usuario válidos
-- Los tipos de usuario ahora serán:
-- 'super_admin' - Administrador del sistema completo
-- 'admin_agencia' - Administrador de una agencia específica
-- 'agente_aduanal' - Agente que trabaja para una agencia
-- 'importador' - Cliente que puede trabajar con múltiples agencias
-- Campos de auditoría para usuarios_sistema
ALTER TABLE [dbo].[usuarios_sistema] ALTER TABLE [dbo].[usuarios_sistema]
ADD CONSTRAINT [FK_usuarios_agencia] ADD [actualizado_en] [datetime] NULL,
FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]); [creado_por] [int] NULL;
-- 3. Tabla de relación importador-agencia (many-to-many) -- 3. Tabla de relación importador-agencia (many-to-many)
CREATE TABLE [dbo].[importador_agencia]( CREATE TABLE [dbo].[importador_agencia](
[id_relacion] [int] IDENTITY(1,1) NOT NULL, [id_relacion] [int] IDENTITY(1,1) NOT NULL,
[id_importador] [int] NOT NULL, [id_importador] [int] NOT NULL,
@@ -30,35 +48,101 @@ CREATE TABLE [dbo].[importador_agencia](
[fecha_vinculacion] [datetime] NOT NULL DEFAULT GETDATE(), [fecha_vinculacion] [datetime] NOT NULL DEFAULT GETDATE(),
[fecha_desvinculacion] [datetime] NULL, [fecha_desvinculacion] [datetime] NULL,
[creado_por] [int] NULL, -- ID del usuario que creó la relación [creado_por] [int] NULL, -- ID del usuario que creó la relación
[aprobado_por] [int] NULL, -- Admin de agencia que aprobó la vinculación
[estado] [varchar](20) NOT NULL DEFAULT 'PENDIENTE', -- 'PENDIENTE', 'APROBADO', 'RECHAZADO'
CONSTRAINT [PK_importador_agencia] PRIMARY KEY CLUSTERED ([id_relacion] ASC), CONSTRAINT [PK_importador_agencia] PRIMARY KEY CLUSTERED ([id_relacion] ASC),
CONSTRAINT [FK_importador_agencia_usuario] CONSTRAINT [FK_importador_agencia_usuario]
FOREIGN KEY ([id_importador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]), FOREIGN KEY ([id_importador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
CONSTRAINT [FK_importador_agencia_agencia] CONSTRAINT [FK_importador_agencia_agencia]
FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]), FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]),
CONSTRAINT [FK_importador_agencia_creador] CONSTRAINT [FK_importador_agencia_creador]
FOREIGN KEY ([creado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]) FOREIGN KEY ([creado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
CONSTRAINT [FK_importador_agencia_aprobador]
FOREIGN KEY ([aprobado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario])
); );
-- Índice único para evitar duplicados activos -- Índice único para evitar duplicados activos
CREATE UNIQUE INDEX [IX_importador_agencia_unique] CREATE UNIQUE INDEX [IX_importador_agencia_unique]
ON [dbo].[importador_agencia] ([id_importador], [id_agencia]) ON [dbo].[importador_agencia] ([id_importador], [id_agencia])
WHERE [activo] = 1; WHERE [activo] = 1;
-- 4. Tabla para auditoría de cambios de agencia
CREATE TABLE [dbo].[historial_agencia_cambios]( -- 4. Tabla de relación agente-agencia
[id_historial] [int] IDENTITY(1,1) NOT NULL,
CREATE TABLE [dbo].[agente_agencia](
[id_relacion] INT IDENTITY(1,1) NOT NULL,
[id_agente] INT NOT NULL,
[id_agencia] INT NOT NULL,
[fecha_asignacion] DATETIME NOT NULL DEFAULT GETDATE(),
[activo] BIT NOT NULL DEFAULT 1,
[asignado_por] INT NULL, -- quien lo asignó (admin agencia o super admin)
CONSTRAINT [PK_agente_agencia] PRIMARY KEY CLUSTERED ([id_relacion]),
CONSTRAINT [FK_agente_agencia_usuario]
FOREIGN KEY ([id_agente]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
CONSTRAINT [FK_agente_agencia_agencia]
FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]),
CONSTRAINT [UQ_agente_activo]
UNIQUE ([id_agente]) WHERE [activo] = 1 -- evita duplicados activos
);
-- Índice único para evitar duplicados activos
CREATE UNIQUE INDEX [IX_agente_agencia_unique]
ON [dbo].[agente_agencia] ([id_agente], [id_agencia])
WHERE [activo] = 1;
-- 5. Tabla para solicitudes de vinculación de importadores
CREATE TABLE [dbo].[solicitudes_vinculacion](
[id_solicitud] [int] IDENTITY(1,1) NOT NULL,
[id_importador] [int] NOT NULL, [id_importador] [int] NOT NULL,
[id_agencia] [int] NOT NULL,
[mensaje] [nvarchar](1000) NULL,
[estado] [varchar](20) NOT NULL DEFAULT 'PENDIENTE', -- 'PENDIENTE', 'APROBADA', 'RECHAZADA'
[fecha_solicitud] [datetime] NOT NULL DEFAULT GETDATE(),
[fecha_respuesta] [datetime] NULL,
[respondido_por] [int] NULL, -- Admin de agencia que respondió
[comentarios_respuesta] [nvarchar](1000) NULL,
CONSTRAINT [PK_solicitudes_vinculacion] PRIMARY KEY CLUSTERED ([id_solicitud] ASC),
CONSTRAINT [FK_solicitudes_importador]
FOREIGN KEY ([id_importador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
CONSTRAINT [FK_solicitudes_agencia]
FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]),
CONSTRAINT [FK_solicitudes_respondido]
FOREIGN KEY ([respondido_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario])
);
-- 6. Tabla para auditoría de cambios de agencia
CREATE TABLE [dbo].[historial_agencia](
[id_historial] [int] IDENTITY(1,1) NOT NULL,
[id_importador] [int] NULL,
[id_agente] [int] NULL,
[id_agencia_anterior] [int] NULL, [id_agencia_anterior] [int] NULL,
[id_agencia_nueva] [int] NULL, [id_agencia_nueva] [int] NULL,
[accion] [varchar](50) NOT NULL, -- 'VINCULACION', 'DESVINCULACION', 'CAMBIO' [accion] [varchar](50) NOT NULL, -- 'VINCULACION', 'DESVINCULACION'
[motivo] [nvarchar](500) NULL, [motivo] [nvarchar](500) NULL,
[realizado_por] [int] NOT NULL, [realizado_por] [int] NOT NULL,
[fecha_cambio] [datetime] NOT NULL DEFAULT GETDATE(), [fecha_cambio] [datetime] NOT NULL DEFAULT GETDATE(),
[datos_adicionales] [nvarchar](max) NULL, -- JSON con información adicional
CONSTRAINT [PK_historial_agencia_cambios] PRIMARY KEY CLUSTERED ([id_historial] ASC) CONSTRAINT [PK_historial_agencia_cambios] PRIMARY KEY CLUSTERED ([id_historial] ASC)
); );
-- Índices adicionales para mejorar rendimiento -- Índices adicionales para mejorar rendimiento
CREATE INDEX [IX_usuarios_tipo_agencia] ON [dbo].[usuarios_sistema] ([tipo_usuario], [id_agencia]); CREATE INDEX [IX_usuarios_tipo_agencia] ON [dbo].[usuarios_sistema] ([tipo_usuario], [id_agencia]);
CREATE INDEX [IX_importador_agencia_importador] ON [dbo].[importador_agencia] ([id_importador]); CREATE INDEX [IX_importador_agencia_importador] ON [dbo].[importador_agencia] ([id_importador]);
CREATE INDEX [IX_importador_agencia_agencia] ON [dbo].[importador_agencia] ([id_agencia]); CREATE INDEX [IX_importador_agencia_agencia] ON [dbo].[importador_agencia] ([id_agencia]);
CREATE INDEX [IX_agencias_activo] ON [dbo].[agencias_aduanales] ([activo]);
CREATE INDEX [IX_importador_agencia_estado] ON [dbo].[importador_agencia] ([estado], [activo]);
CREATE INDEX [IX_agencias_activo] ON [dbo].[agencias_aduanales] ([activo]);
CREATE INDEX [IX_agencias_administrador] ON [dbo].[agencias_aduanales] ([id_administrador]);
CREATE INDEX [IX_solicitudes_estado] ON [dbo].[solicitudes_vinculacion] ([estado], [id_agencia]);

View File

@@ -29,7 +29,7 @@ function alta()
include __DIR__ . '/../../views/agencias/.php'; include __DIR__ . '/../../views/agencias/.php';
} }
function alta_agente() function guardarAgente()
{ {
} }

View File

@@ -1,16 +1,13 @@
<?php <?php
require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/env.php'; require_once __DIR__ . '/../helpers/env.php';
require_once __DIR__ . '/../helpers/crypto.php'; require_once __DIR__ . '/../helpers/crypto.php';
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
loadEnv(); loadEnv();
session_start(); session_start();
function index() { function index() {
@@ -37,7 +34,6 @@ function login() {
} }
} }
function alta_usuarios() { function alta_usuarios() {
if (!($_SESSION['usuario_sistemas'] ?? false)) { if (!($_SESSION['usuario_sistemas'] ?? false)) {
die("⚠️ No autorizado."); die("⚠️ No autorizado.");
@@ -55,7 +51,6 @@ function alta_usuarios() {
include __DIR__ . '/../../views/admin/alta_usuarios.php'; include __DIR__ . '/../../views/admin/alta_usuarios.php';
} }
function guardar_usuario() function guardar_usuario()
{ {
if (!($_SESSION['usuario_sistemas'] ?? false)) { if (!($_SESSION['usuario_sistemas'] ?? false)) {
@@ -108,6 +103,10 @@ function guardar_usuario()
exit; exit;
} }
function agencias_activas()
{
}
function logout() { function logout() {
session_start(); session_start();
@@ -155,8 +154,6 @@ function toggle_estado() {
exit; exit;
} }
function reset_password() { function reset_password() {
session_start(); session_start();
@@ -180,9 +177,6 @@ function reset_password() {
$stmtEmail = sqlsrv_query($conn, $sqlEmail, [$id]); $stmtEmail = sqlsrv_query($conn, $sqlEmail, [$id]);
$row = sqlsrv_fetch_array($stmtEmail, SQLSRV_FETCH_ASSOC); $row = sqlsrv_fetch_array($stmtEmail, SQLSRV_FETCH_ASSOC);
$sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?"; $sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?";
$stmt = sqlsrv_query($conn, $sql, [$passwordHash, $id]); $stmt = sqlsrv_query($conn, $sql, [$passwordHash, $id]);
@@ -196,8 +190,6 @@ function reset_password() {
exit; exit;
} }
function enviar_password() { function enviar_password() {
$email = $_GET['email'] ?? ''; $email = $_GET['email'] ?? '';
$pass = $_GET['pass'] ?? ''; $pass = $_GET['pass'] ?? '';
@@ -246,7 +238,7 @@ function enviar_password() {
<p style='font-size: 14px; color: #888;'>Este es un mensaje automático generado por el sistema. Si no solicitaste esta acción, contacta al administrador.</p> <p style='font-size: 14px; color: #888;'>Este es un mensaje automático generado por el sistema. Si no solicitaste esta acción, contacta al administrador.</p>
</div> </div>
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'> <div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
&copy; " . date('Y') . " $siglas · Desarrollado por AduanaSoft &copy; " . date('Y') . " $siglas · Sistema Integral para Importadores de Hidrocarburos
</div> </div>
</div> </div>
</div> </div>
@@ -260,8 +252,6 @@ function enviar_password() {
} }
} }
function bitacora_login() { function bitacora_login() {
if (!($_SESSION['usuario_sistemas'] ?? false)) { if (!($_SESSION['usuario_sistemas'] ?? false)) {
die("⚠️ No autorizado."); die("⚠️ No autorizado.");
@@ -294,4 +284,4 @@ function bitacora_usuarios() {
} }
include __DIR__ . '/../../views/admin/bitacora_usuarios.php'; include __DIR__ . '/../../views/admin/bitacora_usuarios.php';
} }

View File

@@ -660,7 +660,6 @@ function actualizar() {
exit; exit;
} }
/** “Soft-delete” de una factura **/ /** “Soft-delete” de una factura **/
function eliminar() { function eliminar() {
if (!($_SESSION['usuario_id'] ?? false)) { if (!($_SESSION['usuario_id'] ?? false)) {
@@ -674,9 +673,6 @@ function eliminar() {
header('Location: /IMPORTADORES/solicitud_importacion/lista?deleted=ok'); exit; header('Location: /IMPORTADORES/solicitud_importacion/lista?deleted=ok'); exit;
} }
function actualizar_masivo() { function actualizar_masivo() {
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');