Files
SIG-CM2.0/database/migrations/V013__create_puntos_de_venta.sql

180 lines
8.6 KiB
MySQL
Raw Permalink Normal View History

-- V013__create_puntos_de_venta.sql
-- ADM-008 Puntos de Venta: DDL para dbo.PuntoDeVenta + permiso AFIP.
--
-- NOTA POST-SMOKE (Batch 9): SecuenciaComprobante, SP usp_ReservarNumeroComprobante
-- y TipoComprobante fueron eliminados. SIG-CM2.0 NO genera números AFIP — IMAC
-- (Plataforma Infogestión) los asigna externamente. Un worker futuro (INT-001)
-- polleará la vista de Infogestión para asociar NumeroOrdenInterno ↔ NumeroFacturaAFIP + CAI.
-- PuntoDeVenta.NumeroAFIP es config fija que se manda en el payload a IMAC.
--
-- Cambios:
-- 1. dbo.PuntoDeVenta (FK→Medio, UNIQUE(MedioId,NumeroAFIP), SYSTEM_VERSIONING ON, retention 10Y).
-- 2. Drops idempotentes de artefactos de versión previa (SecuenciaComprobante + SP).
-- 3. Permiso 'administracion:puntos_de_venta:gestionar' + asignación a rol 'admin'.
--
-- Patrón: V011 (Temporal Tables + Permiso MERGE + PAGE compression en history).
-- Idempotente: seguro para re-ejecutar.
-- Reversa: V013_ROLLBACK.sql.
-- Run on: SIGCM2 (dev) y SIGCM2_Test (integration tests).
--
-- NOTA: el código de permiso usa guion_bajo (_) según CK_Permiso_Codigo_Format del proyecto.
-- Código efectivo: 'administracion:puntos_de_venta:gestionar'
-- El spec menciona 'administracion:puntos-de-venta:gestionar' (guion) pero el CHECK constraint
-- solo permite [a-z0-9_:] — se usa guion_bajo para cumplir la constraint existente.
-- El backend y frontend deben usar el código con guion_bajo.
--
-- Covers: REQ-PDV-001, -003, -009
-- Source of truth: Obsidian/02-ARQUITECTURA-y-TECH-STACK/2.10 ADM-008
--
-- NOTA T1.3 — Seeds: NO se seedean PuntoDeVenta.
-- Cada instalación configura sus propios PdVs con el NumeroAFIP real asignado por AFIP/ARCA.
-- Seedear con valores ficticios generaría confusión operativa. El admin los crea manualmente.
SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
SET NOCOUNT ON;
GO
-- ═══════════════════════════════════════════════════════════════════════
-- 0. Drops idempotentes de artefactos de versión previa
-- (SecuenciaComprobante + SP — eliminados en cirugía post-smoke Batch 9)
-- ═══════════════════════════════════════════════════════════════════════
IF OBJECT_ID(N'dbo.usp_ReservarNumeroComprobante', N'P') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.usp_ReservarNumeroComprobante;
PRINT 'SP dbo.usp_ReservarNumeroComprobante dropped (cleanup).';
END
GO
IF EXISTS (SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('dbo.SecuenciaComprobante') AND temporal_type = 2)
BEGIN
ALTER TABLE dbo.SecuenciaComprobante SET (SYSTEM_VERSIONING = OFF);
PRINT 'SecuenciaComprobante: SYSTEM_VERSIONING = OFF (cleanup).';
END
GO
IF OBJECT_ID(N'dbo.SecuenciaComprobante_History', N'U') IS NOT NULL
BEGIN
DROP TABLE dbo.SecuenciaComprobante_History;
PRINT 'SecuenciaComprobante_History dropped (cleanup).';
END
GO
IF OBJECT_ID(N'dbo.SecuenciaComprobante', N'U') IS NOT NULL
BEGIN
DROP TABLE dbo.SecuenciaComprobante;
PRINT 'Table dbo.SecuenciaComprobante dropped (cleanup).';
END
GO
-- ═══════════════════════════════════════════════════════════════════════
-- 1. dbo.PuntoDeVenta
-- ═══════════════════════════════════════════════════════════════════════
IF OBJECT_ID(N'dbo.PuntoDeVenta', N'U') IS NULL
BEGIN
CREATE TABLE dbo.PuntoDeVenta (
Id INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_PuntoDeVenta PRIMARY KEY,
MedioId INT NOT NULL,
NumeroAFIP SMALLINT NOT NULL,
Nombre NVARCHAR(100) NOT NULL,
Descripcion NVARCHAR(255) NULL,
Activo BIT NOT NULL CONSTRAINT DF_PuntoDeVenta_Activo DEFAULT(1),
FechaCreacion DATETIME2(3) NOT NULL CONSTRAINT DF_PuntoDeVenta_FechaCreacion DEFAULT(SYSUTCDATETIME()),
FechaModificacion DATETIME2(3) NULL,
CONSTRAINT FK_PuntoDeVenta_Medio FOREIGN KEY (MedioId) REFERENCES dbo.Medio(Id) ON DELETE NO ACTION,
CONSTRAINT UQ_PuntoDeVenta_Medio_AFIP UNIQUE (MedioId, NumeroAFIP),
CONSTRAINT CK_PuntoDeVenta_NumeroAFIP CHECK (NumeroAFIP >= 1)
);
PRINT 'Table dbo.PuntoDeVenta created.';
END
ELSE
PRINT 'Table dbo.PuntoDeVenta already exists — skip.';
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_PuntoDeVenta_MedioId_Activo' AND object_id = OBJECT_ID('dbo.PuntoDeVenta'))
BEGIN
CREATE INDEX IX_PuntoDeVenta_MedioId_Activo
ON dbo.PuntoDeVenta(MedioId, Activo)
INCLUDE (NumeroAFIP, Nombre);
PRINT 'Index IX_PuntoDeVenta_MedioId_Activo created.';
END
GO
-- ═══════════════════════════════════════════════════════════════════════
-- 2. SYSTEM_VERSIONING — PuntoDeVenta
-- ═══════════════════════════════════════════════════════════════════════
IF COL_LENGTH('dbo.PuntoDeVenta', 'ValidFrom') IS NULL
BEGIN
ALTER TABLE dbo.PuntoDeVenta
ADD
ValidFrom DATETIME2(3) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
CONSTRAINT DF_PuntoDeVenta_ValidFrom DEFAULT(SYSUTCDATETIME()),
ValidTo DATETIME2(3) GENERATED ALWAYS AS ROW END HIDDEN NOT NULL
CONSTRAINT DF_PuntoDeVenta_ValidTo DEFAULT(CONVERT(DATETIME2(3), '9999-12-31 23:59:59.999')),
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
PRINT 'PuntoDeVenta: PERIOD FOR SYSTEM_TIME added.';
END
GO
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('dbo.PuntoDeVenta') AND temporal_type = 2)
BEGIN
ALTER TABLE dbo.PuntoDeVenta
SET (SYSTEM_VERSIONING = ON (
HISTORY_TABLE = dbo.PuntoDeVenta_History,
HISTORY_RETENTION_PERIOD = 10 YEARS
));
PRINT 'PuntoDeVenta: SYSTEM_VERSIONING = ON (history: dbo.PuntoDeVenta_History, retention: 10 years).';
END
ELSE
PRINT 'PuntoDeVenta: SYSTEM_VERSIONING already ON — skip.';
GO
IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'PuntoDeVenta_History' AND schema_id = SCHEMA_ID('dbo'))
AND NOT EXISTS (
SELECT 1 FROM sys.partitions p
JOIN sys.tables t ON t.object_id = p.object_id
WHERE t.name = 'PuntoDeVenta_History' AND p.data_compression = 2
)
BEGIN
ALTER TABLE dbo.PuntoDeVenta_History REBUILD WITH (DATA_COMPRESSION = PAGE);
PRINT 'PuntoDeVenta_History: rebuilt with PAGE compression.';
END
GO
-- ═══════════════════════════════════════════════════════════════════════
-- 3. Permiso: administracion:puntos_de_venta:gestionar
-- ═══════════════════════════════════════════════════════════════════════
MERGE dbo.Permiso AS t
USING (VALUES
('administracion:puntos_de_venta:gestionar', N'Gestionar puntos de venta', N'Crear, editar y desactivar puntos de venta AFIP', 'administracion')
) AS s (Codigo, Nombre, Descripcion, Modulo)
ON t.Codigo = s.Codigo
WHEN NOT MATCHED BY TARGET THEN
INSERT (Codigo, Nombre, Descripcion, Modulo)
VALUES (s.Codigo, s.Nombre, s.Descripcion, s.Modulo);
GO
MERGE dbo.RolPermiso AS t
USING (
SELECT r.Id AS RolId, p.Id AS PermisoId
FROM (VALUES
('admin', 'administracion:puntos_de_venta:gestionar')
) AS x (RolCodigo, PermisoCodigo)
JOIN dbo.Rol r ON r.Codigo = x.RolCodigo
JOIN dbo.Permiso p ON p.Codigo = x.PermisoCodigo
) AS s ON t.RolId = s.RolId AND t.PermisoId = s.PermisoId
WHEN NOT MATCHED BY TARGET THEN
INSERT (RolId, PermisoId) VALUES (s.RolId, s.PermisoId);
GO
PRINT '';
PRINT 'V013 applied successfully.';
PRINT ' - dbo.PuntoDeVenta (temporal, retention 10y, PAGE compression)';
PRINT ' - Permiso administracion:puntos_de_venta:gestionar (asignado a admin)';
PRINT ' - Artefactos de version previa (SecuenciaComprobante + SP) eliminados si existian';
GO