This commit is contained in:
2026-02-01 14:28:17 -06:00
parent 700af7ea60
commit 1784131456
109 changed files with 19894 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace RS_system.Migrations
{
/// <inheritdoc />
public partial class AddMonthlyAccounting : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "reportes_mensuales_contables",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
grupo_trabajo_id = table.Column<long>(type: "bigint", nullable: false),
mes = table.Column<int>(type: "integer", nullable: false),
anio = table.Column<int>(type: "integer", nullable: false),
saldo_inicial = table.Column<decimal>(type: "numeric(18,2)", nullable: false),
fecha_creacion = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
cerrado = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_reportes_mensuales_contables", x => x.id);
table.ForeignKey(
name: "FK_reportes_mensuales_contables_grupos_trabajo_grupo_trabajo_id",
column: x => x.grupo_trabajo_id,
principalTable: "grupos_trabajo",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "contabilidad_registros",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
reporte_mensual_id = table.Column<long>(type: "bigint", nullable: true),
grupo_trabajo_id = table.Column<long>(type: "bigint", nullable: false),
tipo = table.Column<int>(type: "integer", nullable: false),
monto = table.Column<decimal>(type: "numeric(18,2)", nullable: false),
fecha = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
descripcion = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_contabilidad_registros", x => x.id);
table.ForeignKey(
name: "FK_contabilidad_registros_grupos_trabajo_grupo_trabajo_id",
column: x => x.grupo_trabajo_id,
principalTable: "grupos_trabajo",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_contabilidad_registros_reportes_mensuales_contables_reporte_mensual_id",
column: x => x.reporte_mensual_id,
principalTable: "reportes_mensuales_contables",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_contabilidad_registros_grupo_trabajo_id",
table: "contabilidad_registros",
column: "grupo_trabajo_id");
migrationBuilder.CreateIndex(
name: "IX_contabilidad_registros_reporte_mensual_id",
table: "contabilidad_registros",
column: "reporte_mensual_id");
migrationBuilder.CreateIndex(
name: "IX_reportes_mensuales_contables_grupo_trabajo_id",
table: "reportes_mensuales_contables",
column: "grupo_trabajo_id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "contabilidad_registros");
migrationBuilder.DropTable(
name: "reportes_mensuales_contables");
}
}
}

View File

@@ -0,0 +1,143 @@
-- SQL para agregar funcionalidad de préstamos al sistema de inventario
-- PostgreSQL
-- 1. Agregar el nuevo tipo de movimiento PRESTAMO al enum existente
-- Nota: PostgreSQL no tiene ALTER ENUM, así que necesitamos recrear el enum
-- Primero creamos el nuevo enum
CREATE TYPE tipo_movimiento_new AS ENUM (
'ENTRADA',
'SALIDA',
'TRASLADO',
'BAJA',
'REPARACION',
'AJUSTE',
'CAMBIO_ESTADO',
'PRESTAMO'
);
-- Convertimos los datos existentes al nuevo enum
ALTER TABLE movimientos_inventario
ALTER COLUMN tipo_movimiento TYPE tipo_movimiento_new
USING tipo_movimiento::text::tipo_movimiento_new;
-- Eliminamos el enum viejo y renombramos el nuevo
DROP TYPE tipo_movimiento;
ALTER TYPE tipo_movimiento_new RENAME TO tipo_movimiento;
-- 2. Crear tabla de préstamos
CREATE TABLE prestamos (
id BIGSERIAL PRIMARY KEY,
articulo_id INTEGER NOT NULL,
cantidad INTEGER NOT NULL,
persona_nombre VARCHAR(200) NOT NULL,
persona_identificacion VARCHAR(50),
fecha_prestamo TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
fecha_devolucion_estimada TIMESTAMP WITH TIME ZONE,
fecha_devolucion_real TIMESTAMP WITH TIME ZONE,
estado VARCHAR(20) NOT NULL DEFAULT 'ACTIVO',
observacion VARCHAR(500),
usuario_id VARCHAR(100),
CONSTRAINT fk_prestamos_articulos FOREIGN KEY (articulo_id) REFERENCES articulos(id) ON DELETE CASCADE
);
-- 3. Crear tabla de detalles de préstamo (para códigos individuales)
CREATE TABLE prestamo_detalles (
id BIGSERIAL PRIMARY KEY,
prestamo_id BIGINT NOT NULL,
codigo_articulo_individual VARCHAR(100) NOT NULL,
estado VARCHAR(20) NOT NULL DEFAULT 'PRESTADO',
fecha_devolucion TIMESTAMP WITH TIME ZONE,
observacion VARCHAR(300),
CONSTRAINT fk_prestamo_detalles_prestamo FOREIGN KEY (prestamo_id) REFERENCES prestamos(id) ON DELETE CASCADE
);
-- 4. Crear índices para mejor rendimiento
CREATE INDEX idx_prestamos_articulo_id ON prestamos(articulo_id);
CREATE INDEX idx_prestamos_estado ON prestamos(estado);
CREATE INDEX idx_prestamos_fecha_prestamo ON prestamos(fecha_prestamo);
CREATE INDEX idx_prestamo_detalles_prestamo_id ON prestamo_detalles(prestamo_id);
CREATE INDEX idx_prestamo_detalles_codigo ON prestamo_detalles(codigo_articulo_individual);
-- 5. Crear función para generar códigos individuales automáticamente
CREATE OR REPLACE FUNCTION generar_codigo_individual(p_codigo_base VARCHAR, p_secuencia INTEGER)
RETURNS VARCHAR AS $$
BEGIN
RETURN p_codigo_base || '-' || LPAD(p_secuencia::TEXT, 3, '0');
END;
$$ LANGUAGE plpgsql;
-- 6. Crear trigger para actualizar estado de préstamo cuando todos los detalles están devueltos
CREATE OR REPLACE FUNCTION actualizar_estado_prestamo()
RETURNS TRIGGER AS $$
BEGIN
-- Si se actualiza un detalle a DEVUELTO, verificar si todos están devueltos
IF NEW.estado = 'DEVUELTO' THEN
UPDATE prestamos
SET estado = CASE
WHEN NOT EXISTS (
SELECT 1 FROM prestamo_detalles
WHERE prestamo_id = NEW.prestamo_id AND estado != 'DEVUELTO'
) THEN 'DEVUELTO'
ELSE estado
END,
fecha_devolucion_real = CASE
WHEN NOT EXISTS (
SELECT 1 FROM prestamo_detalles
WHERE prestamo_id = NEW.prestamo_id AND estado != 'DEVUELTO'
) THEN CURRENT_TIMESTAMP
ELSE fecha_devolucion_real
END
WHERE id = NEW.prestamo_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 7. Crear el trigger
CREATE TRIGGER trigger_actualizar_estado_prestamo
AFTER UPDATE ON prestamo_detalles
FOR EACH ROW
EXECUTE FUNCTION actualizar_estado_prestamo();
-- 8. Insertar datos de ejemplo (opcional)
-- INSERT INTO prestamos (articulo_id, cantidad, persona_nombre, persona_identificacion, fecha_devolucion_estimada, observacion, usuario_id)
-- VALUES (1, 2, 'Juan Pérez', '12345678', CURRENT_TIMESTAMP + INTERVAL '7 days', 'Préstamo para evento especial', 'admin');
-- Generar códigos individuales para el préstamo de ejemplo
-- INSERT INTO prestamo_detalles (prestamo_id, codigo_articulo_individual, estado)
-- VALUES
-- (1, generar_codigo_individual('sp-b20', 1), 'PRESTADO'),
-- (1, generar_codigo_individual('sp-b20', 2), 'PRESTADO');
-- 9. Crear vista para préstamos activos con detalles
CREATE OR REPLACE VIEW vista_prestamos_activos AS
SELECT
p.id,
p.articulo_id,
a.codigo as articulo_codigo,
a.nombre as articulo_nombre,
p.cantidad,
p.persona_nombre,
p.persona_identificacion,
p.fecha_prestamo,
p.fecha_devolucion_estimada,
p.estado,
p.observacion,
p.usuario_id,
COUNT(pd.id) as detalles_devueltos,
(p.cantidad - COUNT(pd.id)) as detalles_pendientes
FROM prestamos p
LEFT JOIN articulos a ON p.articulo_id = a.id
LEFT JOIN prestamo_detalles pd ON p.id = pd.prestamo_id AND pd.estado = 'DEVUELTO'
WHERE p.estado = 'ACTIVO'
GROUP BY p.id, p.articulo_id, a.codigo, a.nombre, p.cantidad, p.persona_nombre, p.persona_identificacion, p.fecha_prestamo, p.fecha_devolucion_estimada, p.estado, p.observacion, p.usuario_id;
-- 10. Conceder permisos (ajustar según tu usuario de base de datos)
-- GRANT SELECT, INSERT, UPDATE, DELETE ON prestamos TO tu_usuario;
-- GRANT SELECT, INSERT, UPDATE, DELETE ON prestamo_detalles TO tu_usuario;
-- GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO tu_usuario;
-- GRANT EXECUTE ON FUNCTION generar_codigo_individual TO tu_usuario;
-- GRANT EXECUTE ON FUNCTION actualizar_estado_prestamo TO tu_usuario;
-- GRANT SELECT ON vista_prestamos_activos TO tu_usuario;

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,67 @@
-- Table: public.articulos
CREATE TABLE IF NOT EXISTS public.articulos
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
codigo character varying(50) COLLATE pg_catalog."default" NOT NULL,
nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
descripcion character varying(500) COLLATE pg_catalog."default",
marca character varying(100) COLLATE pg_catalog."default",
modelo character varying(100) COLLATE pg_catalog."default",
numero_serie character varying(100) COLLATE pg_catalog."default",
precio numeric(10,2) NOT NULL DEFAULT 0,
fecha_adquisicion date,
imagen_url text COLLATE pg_catalog."default",
categoria_id integer NOT NULL,
estado_id integer NOT NULL,
ubicacion_id integer NOT NULL,
activo boolean NOT NULL DEFAULT true,
eliminado boolean NOT NULL DEFAULT false,
creado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
actualizado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
creado_por character varying(100) COLLATE pg_catalog."default",
CONSTRAINT articulos_pkey PRIMARY KEY (id),
CONSTRAINT fk_articulos_categorias FOREIGN KEY (categoria_id)
REFERENCES public.categorias (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT,
CONSTRAINT fk_articulos_estados FOREIGN KEY (estado_id)
REFERENCES public.estados_articulos (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT,
CONSTRAINT fk_articulos_ubicaciones FOREIGN KEY (ubicacion_id)
REFERENCES public.ubicaciones (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.articulos
OWNER to postgres;
-- Indexes
CREATE UNIQUE INDEX IF NOT EXISTS ix_articulos_codigo
ON public.articulos USING btree
(codigo COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_articulos_nombre
ON public.articulos USING btree
(nombre COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_articulos_categoria_id
ON public.articulos USING btree
(categoria_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_articulos_estado_id
ON public.articulos USING btree
(estado_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_articulos_ubicacion_id
ON public.articulos USING btree
(ubicacion_id ASC NULLS LAST)
TABLESPACE pg_default;

View File

@@ -0,0 +1,27 @@
-- Table: public.categorias
CREATE TABLE IF NOT EXISTS public.categorias
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
descripcion character varying(500) COLLATE pg_catalog."default",
activo boolean NOT NULL DEFAULT true,
eliminado boolean NOT NULL DEFAULT false,
creado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
actualizado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
creado_por character varying(100) COLLATE pg_catalog."default",
CONSTRAINT categorias_pkey PRIMARY KEY (id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.categorias
OWNER to postgres;
-- Index: ix_categorias_nombre
-- DROP INDEX IF EXISTS public.ix_categorias_nombre;
CREATE INDEX IF NOT EXISTS ix_categorias_nombre
ON public.categorias USING btree
(nombre COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;

View File

@@ -0,0 +1,28 @@
-- Table: public.estados_articulos
CREATE TABLE IF NOT EXISTS public.estados_articulos
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
nombre character varying(50) COLLATE pg_catalog."default" NOT NULL,
descripcion character varying(200) COLLATE pg_catalog."default",
color character varying(20) COLLATE pg_catalog."default" DEFAULT 'secondary'::character varying,
activo boolean NOT NULL DEFAULT true,
eliminado boolean NOT NULL DEFAULT false,
creado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
actualizado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
creado_por character varying(100) COLLATE pg_catalog."default",
CONSTRAINT estados_articulos_pkey PRIMARY KEY (id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.estados_articulos
OWNER to postgres;
-- Index: ix_estados_articulos_nombre
-- DROP INDEX IF EXISTS public.ix_estados_articulos_nombre;
CREATE INDEX IF NOT EXISTS ix_estados_articulos_nombre
ON public.estados_articulos USING btree
(nombre COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;

View File

@@ -0,0 +1,52 @@
-- =====================================================
-- Script: Church Members Module Database Schema (Refactored)
-- Description: Creates tables for work groups and members linked to personas
-- =====================================================
-- Table: grupos_trabajo
CREATE TABLE IF NOT EXISTS public.grupos_trabajo
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
nombre character varying(100) NOT NULL,
descripcion text,
activo boolean NOT NULL DEFAULT true,
creado_en timestamp with time zone NOT NULL DEFAULT NOW(),
actualizado_en timestamp with time zone NOT NULL DEFAULT NOW(),
CONSTRAINT grupos_trabajo_pkey PRIMARY KEY (id)
);
-- Table: miembros
-- Drop if exists to handle the schema change during development
DROP TABLE IF EXISTS public.miembros;
CREATE TABLE IF NOT EXISTS public.miembros
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
persona_id bigint NOT NULL,
bautizado_espiritu_santo boolean NOT NULL DEFAULT false,
fecha_ingreso_congregacion date,
telefono_emergencia character varying(20),
grupo_trabajo_id bigint,
activo boolean NOT NULL DEFAULT true,
eliminado boolean NOT NULL DEFAULT false,
creado_en timestamp with time zone NOT NULL DEFAULT NOW(),
actualizado_en timestamp with time zone NOT NULL DEFAULT NOW(),
creado_por character varying(100),
CONSTRAINT miembros_pkey PRIMARY KEY (id),
CONSTRAINT fk_miembros_persona FOREIGN KEY (persona_id)
REFERENCES public.personas (id),
CONSTRAINT fk_miembros_grupo_trabajo FOREIGN KEY (grupo_trabajo_id)
REFERENCES public.grupos_trabajo (id)
);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_miembros_persona ON public.miembros(persona_id);
CREATE INDEX IF NOT EXISTS idx_miembros_grupo_trabajo ON public.miembros(grupo_trabajo_id);
CREATE INDEX IF NOT EXISTS idx_miembros_activo ON public.miembros(activo, eliminado);
-- Initial work groups data
INSERT INTO public.grupos_trabajo (nombre, descripcion) VALUES
('Concilio Misionero Femenil', 'Grupo de trabajo de mujeres misioneras'),
('Fraternidad de Varones', 'Grupo de trabajo de varones de la iglesia'),
('Embajadores de Cristo', 'Grupo de jóvenes embajadores')
ON CONFLICT DO NOTHING;

View File

@@ -0,0 +1,52 @@
-- Table: public.movimientos_inventario
CREATE TABLE IF NOT EXISTS public.movimientos_inventario
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
articulo_id integer NOT NULL,
tipo_movimiento character varying(50) COLLATE pg_catalog."default" NOT NULL,
fecha timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
ubicacion_origen_id integer,
ubicacion_destino_id integer,
estado_anterior_id integer,
estado_nuevo_id integer,
observacion character varying(500) COLLATE pg_catalog."default",
usuario_id character varying(100) COLLATE pg_catalog."default",
CONSTRAINT movimientos_inventario_pkey PRIMARY KEY (id),
CONSTRAINT fk_movimientos_articulos FOREIGN KEY (articulo_id)
REFERENCES public.articulos (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT fk_movimientos_origen FOREIGN KEY (ubicacion_origen_id)
REFERENCES public.ubicaciones (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE SET NULL,
CONSTRAINT fk_movimientos_destino FOREIGN KEY (ubicacion_destino_id)
REFERENCES public.ubicaciones (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE SET NULL,
CONSTRAINT fk_movimientos_estado_ant FOREIGN KEY (estado_anterior_id)
REFERENCES public.estados_articulos (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE SET NULL,
CONSTRAINT fk_movimientos_estado_new FOREIGN KEY (estado_nuevo_id)
REFERENCES public.estados_articulos (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE SET NULL
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.movimientos_inventario
OWNER to postgres;
-- Indexes
CREATE INDEX IF NOT EXISTS ix_movimientos_articulo_id
ON public.movimientos_inventario USING btree
(articulo_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_movimientos_fecha
ON public.movimientos_inventario USING btree
(fecha DESC NULLS LAST)
TABLESPACE pg_default;

View File

@@ -0,0 +1,106 @@
-- =============================================
-- Módulo de Ofrendas - Script SQL
-- =============================================
-- Tabla: registros_culto
-- Almacena los registros de ofrendas por culto
CREATE TABLE IF NOT EXISTS public.registros_culto
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
fecha date NOT NULL,
observaciones character varying(500) COLLATE pg_catalog."default",
creado_por character varying(100) COLLATE pg_catalog."default",
creado_en timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
actualizado_en timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
eliminado boolean NOT NULL DEFAULT false,
CONSTRAINT registros_culto_pkey PRIMARY KEY (id)
);
COMMENT ON TABLE public.registros_culto IS 'Registros de ofrendas por culto';
-- Índice para búsqueda por fecha
CREATE INDEX IF NOT EXISTS idx_registros_culto_fecha ON public.registros_culto(fecha);
CREATE INDEX IF NOT EXISTS idx_registros_culto_eliminado ON public.registros_culto(eliminado);
-- =============================================
-- Tabla: ofrendas
-- Almacena las ofrendas individuales de cada registro
CREATE TABLE IF NOT EXISTS public.ofrendas
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
registro_culto_id bigint NOT NULL,
monto numeric(10,2) NOT NULL CHECK (monto > 0),
concepto character varying(200) COLLATE pg_catalog."default" NOT NULL,
eliminado boolean NOT NULL DEFAULT false,
CONSTRAINT ofrendas_pkey PRIMARY KEY (id),
CONSTRAINT fk_ofrendas_registro_culto FOREIGN KEY (registro_culto_id)
REFERENCES public.registros_culto (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
);
COMMENT ON TABLE public.ofrendas IS 'Ofrendas individuales de cada registro de culto';
-- Índices
CREATE INDEX IF NOT EXISTS idx_ofrendas_registro_culto_id ON public.ofrendas(registro_culto_id);
CREATE INDEX IF NOT EXISTS idx_ofrendas_eliminado ON public.ofrendas(eliminado);
-- =============================================
-- Tabla: descuentos_ofrenda
-- Almacena los descuentos aplicados a cada ofrenda
CREATE TABLE IF NOT EXISTS public.descuentos_ofrenda
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
ofrenda_id bigint NOT NULL,
monto numeric(10,2) NOT NULL CHECK (monto > 0),
concepto character varying(200) COLLATE pg_catalog."default" NOT NULL,
eliminado boolean NOT NULL DEFAULT false,
CONSTRAINT descuentos_ofrenda_pkey PRIMARY KEY (id),
CONSTRAINT fk_descuentos_ofrenda_ofrenda FOREIGN KEY (ofrenda_id)
REFERENCES public.ofrendas (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
);
COMMENT ON TABLE public.descuentos_ofrenda IS 'Descuentos aplicados a las ofrendas (diezmo, asignaciones, etc.)';
-- Índices
CREATE INDEX IF NOT EXISTS idx_descuentos_ofrenda_ofrenda_id ON public.descuentos_ofrenda(ofrenda_id);
CREATE INDEX IF NOT EXISTS idx_descuentos_ofrenda_eliminado ON public.descuentos_ofrenda(eliminado);
-- =============================================
-- Permisos para el módulo
-- =============================================
-- Primero crear el módulo si no existe
INSERT INTO public.modulos (nombre, descripcion, icono, orden, activo)
SELECT 'Secretaría', 'Módulo de secretaría de la iglesia', 'bi bi-journal-bookmark', 40, true
WHERE NOT EXISTS (SELECT 1 FROM public.modulos WHERE nombre = 'Secretaría');
-- Crear permisos para el controlador Ofrenda
INSERT INTO public.permisos (codigo, nombre, descripcion, modulo_id, activo)
SELECT 'Ofrenda.Index', 'Ver Ofrendas', 'Permite ver el listado de registros de ofrendas',
(SELECT id FROM public.modulos WHERE nombre = 'Secretaría'), true
WHERE NOT EXISTS (SELECT 1 FROM public.permisos WHERE codigo = 'Ofrenda.Index');
INSERT INTO public.permisos (codigo, nombre, descripcion, modulo_id, activo)
SELECT 'Ofrenda.Create', 'Crear Ofrenda', 'Permite crear nuevos registros de ofrendas',
(SELECT id FROM public.modulos WHERE nombre = 'Secretaría'), true
WHERE NOT EXISTS (SELECT 1 FROM public.permisos WHERE codigo = 'Ofrenda.Create');
INSERT INTO public.permisos (codigo, nombre, descripcion, modulo_id, activo)
SELECT 'Ofrenda.Edit', 'Editar Ofrenda', 'Permite editar registros de ofrendas',
(SELECT id FROM public.modulos WHERE nombre = 'Secretaría'), true
WHERE NOT EXISTS (SELECT 1 FROM public.permisos WHERE codigo = 'Ofrenda.Edit');
INSERT INTO public.permisos (codigo, nombre, descripcion, modulo_id, activo)
SELECT 'Ofrenda.Delete', 'Eliminar Ofrenda', 'Permite eliminar registros de ofrendas',
(SELECT id FROM public.modulos WHERE nombre = 'Secretaría'), true
WHERE NOT EXISTS (SELECT 1 FROM public.permisos WHERE codigo = 'Ofrenda.Delete');
INSERT INTO public.permisos (codigo, nombre, descripcion, modulo_id, activo)
SELECT 'Ofrenda.Details', 'Ver Detalle Ofrenda', 'Permite ver el detalle de un registro de ofrendas',
(SELECT id FROM public.modulos WHERE nombre = 'Secretaría'), true
WHERE NOT EXISTS (SELECT 1 FROM public.permisos WHERE codigo = 'Ofrenda.Details');

View File

@@ -0,0 +1,28 @@
-- Table: public.ubicaciones
CREATE TABLE IF NOT EXISTS public.ubicaciones
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
descripcion character varying(200) COLLATE pg_catalog."default",
responsable character varying(100) COLLATE pg_catalog."default",
activo boolean NOT NULL DEFAULT true,
eliminado boolean NOT NULL DEFAULT false,
creado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
actualizado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
creado_por character varying(100) COLLATE pg_catalog."default",
CONSTRAINT ubicaciones_pkey PRIMARY KEY (id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.ubicaciones
OWNER to postgres;
-- Index: ix_ubicaciones_nombre
-- DROP INDEX IF EXISTS public.ix_ubicaciones_nombre;
CREATE INDEX IF NOT EXISTS ix_ubicaciones_nombre
ON public.ubicaciones USING btree
(nombre COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;

View File

@@ -0,0 +1,45 @@
-- Add columns to articulos
ALTER TABLE public.articulos
ADD COLUMN IF NOT EXISTS tipo_control character varying(50) NOT NULL DEFAULT 'UNITARIO';
ALTER TABLE public.articulos
ADD COLUMN IF NOT EXISTS cantidad_global integer NOT NULL DEFAULT 1;
-- Add columns to movimientos_inventario
ALTER TABLE public.movimientos_inventario
ADD COLUMN IF NOT EXISTS cantidad integer NOT NULL DEFAULT 1;
-- Create existencias table
CREATE TABLE IF NOT EXISTS public.existencias
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
articulo_id integer NOT NULL,
ubicacion_id integer NOT NULL,
cantidad integer NOT NULL DEFAULT 0,
actualizado_en timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
CONSTRAINT existencias_pkey PRIMARY KEY (id),
CONSTRAINT fk_existencias_articulo FOREIGN KEY (articulo_id)
REFERENCES public.articulos (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT fk_existencias_ubicacion FOREIGN KEY (ubicacion_id)
REFERENCES public.ubicaciones (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT uq_existencias_articulo_ubicacion UNIQUE (articulo_id, ubicacion_id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.existencias
OWNER to postgres;
-- Index for existencias
CREATE INDEX IF NOT EXISTS ix_existencias_articulo_id
ON public.existencias USING btree
(articulo_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_existencias_ubicacion_id
ON public.existencias USING btree
(ubicacion_id ASC NULLS LAST)
TABLESPACE pg_default;