feat(application): CRUD handlers + validators + DI de ProductType (PRD-001)
Create/Update/Deactivate handlers con TransactionScope + audit; validators FluentValidation; DI wiring NullProductQueryRepository + 5 handlers; SqlTestFixture V017 + permiso count 25→26.
This commit is contained in:
@@ -60,6 +60,9 @@ public sealed class SqlTestFixture : IAsyncLifetime
|
||||
// V016 (CAT-001): ensure dbo.Rubro + temporal + permiso 'catalogo:rubros:gestionar'.
|
||||
await EnsureV016SchemaAsync();
|
||||
|
||||
// V017 (PRD-001): ensure dbo.ProductType + temporal + permiso 'catalogo:tipos:gestionar'.
|
||||
await EnsureV017SchemaAsync();
|
||||
|
||||
_respawner = await Respawner.CreateAsync(_connection, new RespawnerOptions
|
||||
{
|
||||
DbAdapter = DbAdapter.SqlServer,
|
||||
@@ -86,6 +89,8 @@ public sealed class SqlTestFixture : IAsyncLifetime
|
||||
new Respawn.Graph.Table("dbo", "IngresosBrutos"),
|
||||
// CAT-001 (V016): Rubro es temporal — history no puede deletearse directo.
|
||||
new Respawn.Graph.Table("dbo", "Rubro_History"),
|
||||
// PRD-001 (V017): ProductType es temporal — history no puede deletearse directo.
|
||||
new Respawn.Graph.Table("dbo", "ProductType_History"),
|
||||
]
|
||||
});
|
||||
|
||||
@@ -933,4 +938,77 @@ public sealed class SqlTestFixture : IAsyncLifetime
|
||||
await _connection.ExecuteAsync(createUqIndex);
|
||||
await _connection.ExecuteAsync(createCoveringIndex);
|
||||
}
|
||||
|
||||
private async Task EnsureV017SchemaAsync()
|
||||
{
|
||||
const string createProductType = """
|
||||
IF OBJECT_ID(N'dbo.ProductType', N'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE dbo.ProductType (
|
||||
Id INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_ProductType PRIMARY KEY,
|
||||
Nombre NVARCHAR(200) COLLATE SQL_Latin1_General_CP1_CI_AI NOT NULL,
|
||||
HasDuration BIT NOT NULL CONSTRAINT DF_ProductType_HasDuration DEFAULT(0),
|
||||
RequiresText BIT NOT NULL CONSTRAINT DF_ProductType_RequiresText DEFAULT(0),
|
||||
RequiresCategory BIT NOT NULL CONSTRAINT DF_ProductType_RequiresCategory DEFAULT(0),
|
||||
IsBundle BIT NOT NULL CONSTRAINT DF_ProductType_IsBundle DEFAULT(0),
|
||||
AllowImages BIT NOT NULL CONSTRAINT DF_ProductType_AllowImages DEFAULT(0),
|
||||
MaxImages INT NULL,
|
||||
MaxImageSizeMB DECIMAL(10,2) NULL,
|
||||
MaxImageWidth INT NULL,
|
||||
MaxImageHeight INT NULL,
|
||||
IsActive BIT NOT NULL CONSTRAINT DF_ProductType_IsActive DEFAULT(1),
|
||||
FechaCreacion DATETIME2(3) NOT NULL CONSTRAINT DF_ProductType_FechaCreacion DEFAULT(SYSUTCDATETIME()),
|
||||
FechaModificacion DATETIME2(3) NULL
|
||||
);
|
||||
END
|
||||
""";
|
||||
|
||||
const string addProductTypePeriod = """
|
||||
IF COL_LENGTH('dbo.ProductType', 'ValidFrom') IS NULL
|
||||
BEGIN
|
||||
ALTER TABLE dbo.ProductType
|
||||
ADD
|
||||
ValidFrom DATETIME2(3) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
|
||||
CONSTRAINT DF_ProductType_ValidFrom DEFAULT(SYSUTCDATETIME()),
|
||||
ValidTo DATETIME2(3) GENERATED ALWAYS AS ROW END HIDDEN NOT NULL
|
||||
CONSTRAINT DF_ProductType_ValidTo DEFAULT(CONVERT(DATETIME2(3), '9999-12-31 23:59:59.999')),
|
||||
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
|
||||
END
|
||||
""";
|
||||
|
||||
const string setProductTypeVersioning = """
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('dbo.ProductType') AND temporal_type = 2)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.ProductType
|
||||
SET (SYSTEM_VERSIONING = ON (
|
||||
HISTORY_TABLE = dbo.ProductType_History,
|
||||
HISTORY_RETENTION_PERIOD = 10 YEARS
|
||||
));
|
||||
END
|
||||
""";
|
||||
|
||||
const string createUqIndex = """
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_ProductType_Nombre_Activo' AND object_id = OBJECT_ID('dbo.ProductType'))
|
||||
BEGIN
|
||||
CREATE UNIQUE INDEX UQ_ProductType_Nombre_Activo
|
||||
ON dbo.ProductType(Nombre)
|
||||
WHERE IsActive = 1;
|
||||
END
|
||||
""";
|
||||
|
||||
const string createCoveringIndex = """
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_ProductType_IsActive_Cover' AND object_id = OBJECT_ID('dbo.ProductType'))
|
||||
BEGIN
|
||||
CREATE INDEX IX_ProductType_IsActive_Cover
|
||||
ON dbo.ProductType(IsActive)
|
||||
INCLUDE (Nombre, HasDuration, RequiresText, RequiresCategory, IsBundle, AllowImages);
|
||||
END
|
||||
""";
|
||||
|
||||
await _connection.ExecuteAsync(createProductType);
|
||||
await _connection.ExecuteAsync(addProductTypePeriod);
|
||||
await _connection.ExecuteAsync(setProductTypeVersioning);
|
||||
await _connection.ExecuteAsync(createUqIndex);
|
||||
await _connection.ExecuteAsync(createCoveringIndex);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user