Feat: Se agregan servicios y controladores para ABM de suscriptores
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using GestionIntegral.Api.Services.Suscripciones;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GestionIntegral.Api.Controllers.Suscripciones
|
||||
{
|
||||
[Route("api/formaspago")]
|
||||
[ApiController]
|
||||
[Authorize] // Solo usuarios logueados pueden ver esto
|
||||
public class FormasDePagoController : ControllerBase
|
||||
{
|
||||
private readonly IFormaPagoService _formaPagoService;
|
||||
|
||||
public FormasDePagoController(IFormaPagoService formaPagoService)
|
||||
{
|
||||
_formaPagoService = formaPagoService;
|
||||
}
|
||||
|
||||
// GET: api/formaspago
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll()
|
||||
{
|
||||
var formasDePago = await _formaPagoService.ObtenerTodos();
|
||||
return Ok(formasDePago);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using GestionIntegral.Api.Dtos.Suscripciones;
|
||||
using GestionIntegral.Api.Services.Suscripciones;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace GestionIntegral.Api.Controllers.Suscripciones
|
||||
{
|
||||
[Route("api/suscriptores")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class SuscriptoresController : ControllerBase
|
||||
{
|
||||
private readonly ISuscriptorService _suscriptorService;
|
||||
private readonly ILogger<SuscriptoresController> _logger;
|
||||
|
||||
// Permisos para Suscriptores
|
||||
private const string PermisoVer = "SU001";
|
||||
private const string PermisoCrear = "SU002";
|
||||
private const string PermisoModificar = "SU003";
|
||||
private const string PermisoActivarDesactivar = "SU004";
|
||||
|
||||
public SuscriptoresController(ISuscriptorService suscriptorService, ILogger<SuscriptoresController> logger)
|
||||
{
|
||||
_suscriptorService = suscriptorService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
|
||||
|
||||
private int? GetCurrentUserId()
|
||||
{
|
||||
if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
|
||||
_logger.LogWarning("No se pudo obtener el UserId del token JWT en SuscriptoresController.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// GET: api/suscriptores
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(IEnumerable<SuscriptorDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetAll([FromQuery] string? nombre, [FromQuery] string? nroDoc, [FromQuery] bool soloActivos = true)
|
||||
{
|
||||
if (!TienePermiso(PermisoVer)) return Forbid();
|
||||
var suscriptores = await _suscriptorService.ObtenerTodos(nombre, nroDoc, soloActivos);
|
||||
return Ok(suscriptores);
|
||||
}
|
||||
|
||||
// GET: api/suscriptores/{id}
|
||||
[HttpGet("{id:int}", Name = "GetSuscriptorById")]
|
||||
[ProducesResponseType(typeof(SuscriptorDto), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
if (!TienePermiso(PermisoVer)) return Forbid();
|
||||
var suscriptor = await _suscriptorService.ObtenerPorId(id);
|
||||
if (suscriptor == null) return NotFound();
|
||||
return Ok(suscriptor);
|
||||
}
|
||||
|
||||
// POST: api/suscriptores
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(SuscriptorDto), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> Create([FromBody] CreateSuscriptorDto createDto)
|
||||
{
|
||||
if (!TienePermiso(PermisoCrear)) return Forbid();
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var (dto, error) = await _suscriptorService.Crear(createDto, userId.Value);
|
||||
|
||||
if (error != null) return BadRequest(new { message = error });
|
||||
if (dto == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al crear el suscriptor.");
|
||||
|
||||
return CreatedAtRoute("GetSuscriptorById", new { id = dto.IdSuscriptor }, dto);
|
||||
}
|
||||
|
||||
// PUT: api/suscriptores/{id}
|
||||
[HttpPut("{id:int}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Update(int id, [FromBody] UpdateSuscriptorDto updateDto)
|
||||
{
|
||||
if (!TienePermiso(PermisoModificar)) return Forbid();
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var (exito, error) = await _suscriptorService.Actualizar(id, updateDto, userId.Value);
|
||||
|
||||
if (!exito)
|
||||
{
|
||||
if (error != null && error.Contains("no encontrado")) return NotFound(new { message = error });
|
||||
return BadRequest(new { message = error });
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
// DELETE: api/suscriptores/{id} (Desactivar)
|
||||
[HttpDelete("{id:int}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Deactivate(int id)
|
||||
{
|
||||
if (!TienePermiso(PermisoActivarDesactivar)) return Forbid();
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var (exito, error) = await _suscriptorService.Desactivar(id, userId.Value);
|
||||
|
||||
if (!exito)
|
||||
{
|
||||
if (error != null && error.Contains("no encontrado")) return NotFound(new { message = error });
|
||||
return BadRequest(new { message = error });
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
// POST: api/suscriptores/{id}/activar
|
||||
[HttpPost("{id:int}/activar")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Activate(int id)
|
||||
{
|
||||
if (!TienePermiso(PermisoActivarDesactivar)) return Forbid();
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var (exito, error) = await _suscriptorService.Activar(id, userId.Value);
|
||||
|
||||
if (!exito)
|
||||
{
|
||||
if (error != null && error.Contains("no encontrado")) return NotFound(new { message = error });
|
||||
return BadRequest(new { message = error });
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
public class CreateSuscripcionDto
|
||||
{
|
||||
[Required]
|
||||
public int IdSuscriptor { get; set; }
|
||||
|
||||
[Required]
|
||||
public int IdPublicacion { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime FechaInicio { get; set; }
|
||||
|
||||
public DateTime? FechaFin { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Estado { get; set; } = "Activa";
|
||||
|
||||
[Required(ErrorMessage = "Debe especificar los días de entrega.")]
|
||||
public List<string> DiasEntrega { get; set; } = new List<string>(); // "L", "M", "X"...
|
||||
|
||||
[StringLength(250)]
|
||||
public string? Observaciones { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
// Nota: Por ahora, el DTO de actualización puede ser similar al de creación.
|
||||
// Si se necesita una lógica diferente, se crearía un UpdateSuscripcionDto.
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
public class CreateSuscriptorDto
|
||||
{
|
||||
[Required(ErrorMessage = "El nombre completo es obligatorio.")]
|
||||
[StringLength(150)]
|
||||
public string NombreCompleto { get; set; } = string.Empty;
|
||||
|
||||
[EmailAddress(ErrorMessage = "El formato del email no es válido.")]
|
||||
[StringLength(100)]
|
||||
public string? Email { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string? Telefono { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "La dirección es obligatoria.")]
|
||||
[StringLength(200)]
|
||||
public string Direccion { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "El tipo de documento es obligatorio.")]
|
||||
[StringLength(4)]
|
||||
public string TipoDocumento { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "El número de documento es obligatorio.")]
|
||||
[StringLength(11)]
|
||||
public string NroDocumento { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(22, MinimumLength = 22, ErrorMessage = "El CBU debe tener 22 dígitos.")]
|
||||
public string? CBU { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "La forma de pago es obligatoria.")]
|
||||
public int IdFormaPagoPreferida { get; set; }
|
||||
|
||||
[StringLength(250)]
|
||||
public string? Observaciones { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
public class FormaPagoDto
|
||||
{
|
||||
public int IdFormaPago { get; set; }
|
||||
public string Nombre { get; set; } = string.Empty;
|
||||
public bool RequiereCBU { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
public class SuscripcionDto
|
||||
{
|
||||
public int IdSuscripcion { get; set; }
|
||||
public int IdSuscriptor { get; set; }
|
||||
public int IdPublicacion { get; set; }
|
||||
public string NombrePublicacion { get; set; } = string.Empty; // Para UI
|
||||
public string FechaInicio { get; set; } = string.Empty; // Formato "yyyy-MM-dd"
|
||||
public string? FechaFin { get; set; }
|
||||
public string Estado { get; set; } = string.Empty;
|
||||
public string DiasEntrega { get; set; } = string.Empty;
|
||||
public string? Observaciones { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
// DTO para mostrar la información de un suscriptor
|
||||
public class SuscriptorDto
|
||||
{
|
||||
public int IdSuscriptor { get; set; }
|
||||
public string NombreCompleto { get; set; } = string.Empty;
|
||||
public string? Email { get; set; }
|
||||
public string? Telefono { get; set; }
|
||||
public string Direccion { get; set; } = string.Empty;
|
||||
public string TipoDocumento { get; set; } = string.Empty;
|
||||
public string NroDocumento { get; set; } = string.Empty;
|
||||
public string? CBU { get; set; }
|
||||
public int IdFormaPagoPreferida { get; set; }
|
||||
public string NombreFormaPagoPreferida { get; set; } = string.Empty; // Para UI
|
||||
public string? Observaciones { get; set; }
|
||||
public bool Activo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GestionIntegral.Api.Dtos.Suscripciones
|
||||
{
|
||||
// Es idéntico al CreateDto, pero se mantiene separado por si las reglas de validación cambian.
|
||||
public class UpdateSuscriptorDto
|
||||
{
|
||||
[Required(ErrorMessage = "El nombre completo es obligatorio.")]
|
||||
[StringLength(150)]
|
||||
public string NombreCompleto { get; set; } = string.Empty;
|
||||
|
||||
[EmailAddress(ErrorMessage = "El formato del email no es válido.")]
|
||||
[StringLength(100)]
|
||||
public string? Email { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string? Telefono { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "La dirección es obligatoria.")]
|
||||
[StringLength(200)]
|
||||
public string Direccion { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "El tipo de documento es obligatorio.")]
|
||||
[StringLength(4)]
|
||||
public string TipoDocumento { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "El número de documento es obligatorio.")]
|
||||
[StringLength(11)]
|
||||
public string NroDocumento { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(22, MinimumLength = 22, ErrorMessage = "El CBU debe tener 22 dígitos.")]
|
||||
public string? CBU { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "La forma de pago es obligatoria.")]
|
||||
public int IdFormaPagoPreferida { get; set; }
|
||||
|
||||
[StringLength(250)]
|
||||
public string? Observaciones { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ using GestionIntegral.Api.Services.Reportes;
|
||||
using GestionIntegral.Api.Services.Pdf;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using GestionIntegral.Api.Services.Anomalia;
|
||||
using GestionIntegral.Api.Data.Repositories.Suscripciones;
|
||||
using GestionIntegral.Api.Services.Suscripciones;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -100,6 +102,19 @@ builder.Services.AddScoped<IQuestPdfGenerator, QuestPdfGenerator>();
|
||||
// Servicio de Alertas
|
||||
builder.Services.AddScoped<IAlertaService, AlertaService>();
|
||||
|
||||
// --- Suscripciones ---
|
||||
// Repositorios
|
||||
builder.Services.AddScoped<IFormaPagoRepository, FormaPagoRepository>();
|
||||
builder.Services.AddScoped<ISuscriptorRepository, SuscriptorRepository>();
|
||||
builder.Services.AddScoped<ISuscripcionRepository, SuscripcionRepository>();
|
||||
builder.Services.AddScoped<IFacturaRepository, FacturaRepository>();
|
||||
builder.Services.AddScoped<ILoteDebitoRepository, LoteDebitoRepository>();
|
||||
builder.Services.AddScoped<IPagoRepository, PagoRepository>();
|
||||
|
||||
// Servicios
|
||||
builder.Services.AddScoped<IFormaPagoService, FormaPagoService>();
|
||||
builder.Services.AddScoped<ISuscriptorService, SuscriptorService>();
|
||||
|
||||
// --- SERVICIO DE HEALTH CHECKS ---
|
||||
// Añadimos una comprobación específica para SQL Server.
|
||||
// El sistema usará la cadena de conexión configurada en appsettings.json o variables de entorno.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using GestionIntegral.Api.Data.Repositories.Suscripciones;
|
||||
using GestionIntegral.Api.Dtos.Suscripciones;
|
||||
|
||||
namespace GestionIntegral.Api.Services.Suscripciones
|
||||
{
|
||||
public class FormaPagoService : IFormaPagoService
|
||||
{
|
||||
private readonly IFormaPagoRepository _formaPagoRepository;
|
||||
|
||||
public FormaPagoService(IFormaPagoRepository formaPagoRepository)
|
||||
{
|
||||
_formaPagoRepository = formaPagoRepository;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<FormaPagoDto>> ObtenerTodos()
|
||||
{
|
||||
var formasDePago = await _formaPagoRepository.GetAllAsync();
|
||||
return formasDePago.Select(fp => new FormaPagoDto
|
||||
{
|
||||
IdFormaPago = fp.IdFormaPago,
|
||||
Nombre = fp.Nombre,
|
||||
RequiereCBU = fp.RequiereCBU
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using GestionIntegral.Api.Dtos.Suscripciones;
|
||||
|
||||
namespace GestionIntegral.Api.Services.Suscripciones
|
||||
{
|
||||
public interface IFormaPagoService
|
||||
{
|
||||
Task<IEnumerable<FormaPagoDto>> ObtenerTodos();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Archivo: GestionIntegral.Api/Services/Suscripciones/ISuscriptorService.cs
|
||||
|
||||
using GestionIntegral.Api.Dtos.Suscripciones;
|
||||
|
||||
namespace GestionIntegral.Api.Services.Suscripciones
|
||||
{
|
||||
public interface ISuscriptorService
|
||||
{
|
||||
Task<IEnumerable<SuscriptorDto>> ObtenerTodos(string? nombreFilter, string? nroDocFilter, bool soloActivos);
|
||||
Task<SuscriptorDto?> ObtenerPorId(int id);
|
||||
Task<(SuscriptorDto? Suscriptor, string? Error)> Crear(CreateSuscriptorDto createDto, int idUsuario);
|
||||
Task<(bool Exito, string? Error)> Actualizar(int id, UpdateSuscriptorDto updateDto, int idUsuario);
|
||||
Task<(bool Exito, string? Error)> Desactivar(int id, int idUsuario);
|
||||
Task<(bool Exito, string? Error)> Activar(int id, int idUsuario);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
// Archivo: GestionIntegral.Api/Services/Suscripciones/SuscriptorService.cs
|
||||
|
||||
using GestionIntegral.Api.Data;
|
||||
using GestionIntegral.Api.Data.Repositories.Suscripciones;
|
||||
using GestionIntegral.Api.Dtos.Suscripciones;
|
||||
using GestionIntegral.Api.Models.Suscripciones;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GestionIntegral.Api.Services.Suscripciones
|
||||
{
|
||||
public class SuscriptorService : ISuscriptorService
|
||||
{
|
||||
private readonly ISuscriptorRepository _suscriptorRepository;
|
||||
private readonly IFormaPagoRepository _formaPagoRepository;
|
||||
private readonly DbConnectionFactory _connectionFactory;
|
||||
private readonly ILogger<SuscriptorService> _logger;
|
||||
|
||||
public SuscriptorService(
|
||||
ISuscriptorRepository suscriptorRepository,
|
||||
IFormaPagoRepository formaPagoRepository,
|
||||
DbConnectionFactory connectionFactory,
|
||||
ILogger<SuscriptorService> logger)
|
||||
{
|
||||
_suscriptorRepository = suscriptorRepository;
|
||||
_formaPagoRepository = formaPagoRepository;
|
||||
_connectionFactory = connectionFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// Helper para mapear Modelo -> DTO, enriqueciendo con el nombre de la forma de pago
|
||||
private async Task<SuscriptorDto?> MapToDto(Suscriptor suscriptor)
|
||||
{
|
||||
if (suscriptor == null) return null;
|
||||
|
||||
var formaPago = await _formaPagoRepository.GetByIdAsync(suscriptor.IdFormaPagoPreferida);
|
||||
|
||||
return new SuscriptorDto
|
||||
{
|
||||
IdSuscriptor = suscriptor.IdSuscriptor,
|
||||
NombreCompleto = suscriptor.NombreCompleto,
|
||||
Email = suscriptor.Email,
|
||||
Telefono = suscriptor.Telefono,
|
||||
Direccion = suscriptor.Direccion,
|
||||
TipoDocumento = suscriptor.TipoDocumento,
|
||||
NroDocumento = suscriptor.NroDocumento,
|
||||
CBU = suscriptor.CBU,
|
||||
IdFormaPagoPreferida = suscriptor.IdFormaPagoPreferida,
|
||||
NombreFormaPagoPreferida = formaPago?.Nombre ?? "Desconocida",
|
||||
Observaciones = suscriptor.Observaciones,
|
||||
Activo = suscriptor.Activo
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SuscriptorDto>> ObtenerTodos(string? nombreFilter, string? nroDocFilter, bool soloActivos)
|
||||
{
|
||||
var suscriptores = await _suscriptorRepository.GetAllAsync(nombreFilter, nroDocFilter, soloActivos);
|
||||
var dtosTasks = suscriptores.Select(s => MapToDto(s));
|
||||
var dtos = await Task.WhenAll(dtosTasks);
|
||||
return dtos.Where(dto => dto != null).Select(dto => dto!);
|
||||
}
|
||||
|
||||
public async Task<SuscriptorDto?> ObtenerPorId(int id)
|
||||
{
|
||||
var suscriptor = await _suscriptorRepository.GetByIdAsync(id);
|
||||
if (suscriptor == null)
|
||||
return null;
|
||||
return await MapToDto(suscriptor);
|
||||
}
|
||||
|
||||
public async Task<(SuscriptorDto? Suscriptor, string? Error)> Crear(CreateSuscriptorDto createDto, int idUsuario)
|
||||
{
|
||||
// Validación de Lógica de Negocio
|
||||
if (await _suscriptorRepository.ExistsByDocumentoAsync(createDto.TipoDocumento, createDto.NroDocumento))
|
||||
{
|
||||
return (null, "Ya existe un suscriptor con el mismo tipo y número de documento.");
|
||||
}
|
||||
|
||||
var formaPago = await _formaPagoRepository.GetByIdAsync(createDto.IdFormaPagoPreferida);
|
||||
if (formaPago == null || !formaPago.Activo)
|
||||
{
|
||||
return (null, "La forma de pago seleccionada no es válida o está inactiva.");
|
||||
}
|
||||
if (formaPago.RequiereCBU && string.IsNullOrWhiteSpace(createDto.CBU))
|
||||
{
|
||||
return (null, "El CBU es obligatorio para la forma de pago seleccionada.");
|
||||
}
|
||||
|
||||
var nuevoSuscriptor = new Suscriptor
|
||||
{
|
||||
NombreCompleto = createDto.NombreCompleto,
|
||||
Email = createDto.Email,
|
||||
Telefono = createDto.Telefono,
|
||||
Direccion = createDto.Direccion,
|
||||
TipoDocumento = createDto.TipoDocumento,
|
||||
NroDocumento = createDto.NroDocumento,
|
||||
CBU = createDto.CBU,
|
||||
IdFormaPagoPreferida = createDto.IdFormaPagoPreferida,
|
||||
Observaciones = createDto.Observaciones,
|
||||
IdUsuarioAlta = idUsuario
|
||||
};
|
||||
|
||||
using var connection = _connectionFactory.CreateConnection();
|
||||
await (connection as System.Data.Common.DbConnection)!.OpenAsync();
|
||||
using var transaction = connection.BeginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
var suscriptorCreado = await _suscriptorRepository.CreateAsync(nuevoSuscriptor, transaction);
|
||||
if (suscriptorCreado == null) throw new DataException("La creación en el repositorio devolvió null.");
|
||||
|
||||
transaction.Commit();
|
||||
_logger.LogInformation("Suscriptor ID {IdSuscriptor} creado por Usuario ID {IdUsuario}.", suscriptorCreado.IdSuscriptor, idUsuario);
|
||||
|
||||
var dtoCreado = await MapToDto(suscriptorCreado);
|
||||
return (dtoCreado, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try { transaction.Rollback(); } catch { }
|
||||
_logger.LogError(ex, "Error al crear suscriptor: {Nombre}", createDto.NombreCompleto);
|
||||
return (null, $"Error interno al crear el suscriptor: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool Exito, string? Error)> Actualizar(int id, UpdateSuscriptorDto updateDto, int idUsuario)
|
||||
{
|
||||
var suscriptorExistente = await _suscriptorRepository.GetByIdAsync(id);
|
||||
if (suscriptorExistente == null) return (false, "Suscriptor no encontrado.");
|
||||
|
||||
if (await _suscriptorRepository.ExistsByDocumentoAsync(updateDto.TipoDocumento, updateDto.NroDocumento, id))
|
||||
{
|
||||
return (false, "El tipo y número de documento ya pertenecen a otro suscriptor.");
|
||||
}
|
||||
|
||||
var formaPago = await _formaPagoRepository.GetByIdAsync(updateDto.IdFormaPagoPreferida);
|
||||
if (formaPago == null || !formaPago.Activo)
|
||||
{
|
||||
return (false, "La forma de pago seleccionada no es válida o está inactiva.");
|
||||
}
|
||||
if (formaPago.RequiereCBU && string.IsNullOrWhiteSpace(updateDto.CBU))
|
||||
{
|
||||
return (false, "El CBU es obligatorio para la forma de pago seleccionada.");
|
||||
}
|
||||
|
||||
// Mapeo DTO -> Modelo
|
||||
suscriptorExistente.NombreCompleto = updateDto.NombreCompleto;
|
||||
suscriptorExistente.Email = updateDto.Email;
|
||||
suscriptorExistente.Telefono = updateDto.Telefono;
|
||||
suscriptorExistente.Direccion = updateDto.Direccion;
|
||||
suscriptorExistente.TipoDocumento = updateDto.TipoDocumento;
|
||||
suscriptorExistente.NroDocumento = updateDto.NroDocumento;
|
||||
suscriptorExistente.CBU = updateDto.CBU;
|
||||
suscriptorExistente.IdFormaPagoPreferida = updateDto.IdFormaPagoPreferida;
|
||||
suscriptorExistente.Observaciones = updateDto.Observaciones;
|
||||
suscriptorExistente.IdUsuarioMod = idUsuario;
|
||||
suscriptorExistente.FechaMod = DateTime.Now;
|
||||
|
||||
using var connection = _connectionFactory.CreateConnection();
|
||||
await (connection as System.Data.Common.DbConnection)!.OpenAsync();
|
||||
using var transaction = connection.BeginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
var actualizado = await _suscriptorRepository.UpdateAsync(suscriptorExistente, transaction);
|
||||
if (!actualizado) throw new DataException("La actualización en el repositorio devolvió false.");
|
||||
|
||||
transaction.Commit();
|
||||
_logger.LogInformation("Suscriptor ID {IdSuscriptor} actualizado por Usuario ID {IdUsuario}.", id, idUsuario);
|
||||
return (true, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try { transaction.Rollback(); } catch { }
|
||||
_logger.LogError(ex, "Error al actualizar suscriptor ID: {IdSuscriptor}", id);
|
||||
return (false, $"Error interno al actualizar: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(bool Exito, string? Error)> CambiarEstadoActivo(int id, bool activar, int idUsuario)
|
||||
{
|
||||
var suscriptor = await _suscriptorRepository.GetByIdAsync(id);
|
||||
if (suscriptor == null) return (false, "Suscriptor no encontrado.");
|
||||
|
||||
if (!activar && await _suscriptorRepository.IsInUseAsync(id))
|
||||
{
|
||||
return (false, "No se puede desactivar un suscriptor con suscripciones activas.");
|
||||
}
|
||||
|
||||
using var connection = _connectionFactory.CreateConnection();
|
||||
await (connection as System.Data.Common.DbConnection)!.OpenAsync();
|
||||
using var transaction = connection.BeginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
var actualizado = await _suscriptorRepository.ToggleActivoAsync(id, activar, idUsuario, transaction);
|
||||
if (!actualizado) throw new DataException("No se pudo cambiar el estado del suscriptor.");
|
||||
|
||||
transaction.Commit();
|
||||
_logger.LogInformation("El estado del Suscriptor ID {IdSuscriptor} se cambió a {Estado} por el Usuario ID {IdUsuario}.", id, activar ? "Activo" : "Inactivo", idUsuario);
|
||||
return (true, null);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
try { transaction.Rollback(); } catch { }
|
||||
_logger.LogError(ex, "Error al cambiar estado del suscriptor ID: {IdSuscriptor}", id);
|
||||
return (false, $"Error interno: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<(bool Exito, string? Error)> Desactivar(int id, int idUsuario)
|
||||
{
|
||||
return CambiarEstadoActivo(id, false, idUsuario);
|
||||
}
|
||||
|
||||
public Task<(bool Exito, string? Error)> Activar(int id, int idUsuario)
|
||||
{
|
||||
return CambiarEstadoActivo(id, true, idUsuario);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user