Add BusinessUnits y ProductCatergories in API
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 2m21s

This commit is contained in:
Leandro Hernan Rojas 2025-04-18 02:01:12 -03:00
parent e41dc8747d
commit e14fecc455
25 changed files with 1460 additions and 17 deletions

View File

@ -0,0 +1,14 @@
using Domain.Entities;
namespace Core.Interfaces
{
public interface IBusinessUnitDom
{
Task<IEnumerable<EBusinessUnit>> GetAllAsync();
Task<EBusinessUnit?> GetByIdAsync(int id);
Task<IEnumerable<EBusinessUnit>> SearchAsync(string term);
Task<EBusinessUnit> CreateAsync(EBusinessUnit unit);
Task<bool> UpdateAsync(EBusinessUnit unit);
Task<bool> DeleteAsync(int id);
}
}

View File

@ -0,0 +1,14 @@
using Domain.Entities;
namespace Core.Interfaces
{
public interface IProductCategoryDom
{
Task<EProductCategory> CreateAsync(EProductCategory unit);
Task<IEnumerable<EProductCategory>> GetAllAsync();
Task<EProductCategory?> GetByIdAsync(int id);
Task<IEnumerable<EProductCategory>> SearchAsync(string term);
Task<bool> UpdateAsync(EProductCategory unit);
Task<bool> DeleteAsync(int id);
}
}

View File

@ -0,0 +1,16 @@
using Domain.Entities;
using Domain.Generics;
namespace Core.Interfaces
{
public interface IProductDom
{
Task<EProduct> CreateAsync(EProduct entity);
Task<bool> DeleteAsync(int id);
Task<byte[]> ExportFilteredProductsToExcelAsync(ProductSearchParams searchParams);
Task<PagedResult<EProduct>> GetAllAsync(int page = 1, int pageSize = 50);
Task<EProduct?> GetByIdAsync(int id);
Task<PagedResult<EProduct>> SearchAsync(string? term, int page = 1, int pageSize = 50);
Task<bool> UpdateAsync(EProduct entity);
}
}

View File

@ -0,0 +1,97 @@
using Core.Interfaces;
using Domain.Entities;
using Models.Interfaces;
using System.Reflection;
namespace Core.Services
{
public class BusinessUnitService: IBusinessUnitDom
{
#region Declaraciones y Constructor
private readonly IPhSBusinessUnitRepository _repository;
public BusinessUnitService(IPhSBusinessUnitRepository repository)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
#endregion
#region Metodos de clases
public async Task<IEnumerable<EBusinessUnit>> GetAllAsync()
{
try
{
return await _repository.GetAllAsync();
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EBusinessUnit?> GetByIdAsync(int id)
{
try
{
return await _repository.GetByIdAsync(id);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<IEnumerable<EBusinessUnit>> SearchAsync(string term)
{
try
{
return await _repository.SearchAsync(term);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EBusinessUnit> CreateAsync(EBusinessUnit entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity), "La unidad de negocio no puede ser nula.");
try
{
return await _repository.CreateAsync(entity);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{ex.Message}", ex);
}
}
public async Task<bool> UpdateAsync(EBusinessUnit unit)
{
if (unit == null)
throw new ArgumentNullException(nameof(unit), "La unidad de negocio no puede ser nula.");
try
{
return await _repository.UpdateAsync(unit);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
public async Task<bool> DeleteAsync(int id)
{
try
{
return await _repository.DeleteAsync(id);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
#endregion
}
}

View File

@ -0,0 +1,87 @@
using Models.Repositories;
using System.Reflection;
using Core.Interfaces;
using Domain.Entities;
using Models.Interfaces;
namespace Core.Services
{
public class ProductCategoryService : IProductCategoryDom
{
private readonly IPhSProductCategoryRepository _repository;
public ProductCategoryService(IPhSProductCategoryRepository repository)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public async Task<IEnumerable<EProductCategory>> GetAllAsync()
{
try
{
return await _repository.GetAllAsync();
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EProductCategory?> GetByIdAsync(int id)
{
try
{
return await _repository.GetByIdAsync(id);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<IEnumerable<EProductCategory>> SearchAsync(string term)
{
try
{
return await _repository.SearchAsync(term);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EProductCategory> CreateAsync(EProductCategory entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity), "La categoría no puede ser nula.");
return await _repository.CreateAsync(entity);
}
public async Task<bool> DeleteAsync(int id)
{
try
{
return await _repository.DeleteAsync(id);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
public async Task<bool> UpdateAsync(EProductCategory unit)
{
if (unit == null)
throw new ArgumentNullException(nameof(unit), "La categoría no puede ser nula.");
try
{
return await _repository.UpdateAsync(unit);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
}
}

View File

@ -0,0 +1,126 @@
using Core.Interfaces;
using Domain.Entities;
using Domain.Generics;
using Models.Interfaces;
using System.Reflection;
using Transversal.Services;
namespace Core.Services
{
public class ProductService : IProductDom
{
#region Declaraciones y Constructor
private readonly IPhSProductRepository _repository;
public ProductService(IPhSProductRepository repository)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
#endregion
#region Métodos
public async Task<PagedResult<EProduct>> GetAllAsync(int page = 1, int pageSize = 50)
{
try
{
return await _repository.GetAllAsync(page, pageSize);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "Unknown";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<PagedResult<EProduct>> SearchAsync(string? name, int page = 1, int pageSize = 50)
{
try
{
return await _repository.SearchAsync(name, page, pageSize);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "Unknown";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EProduct?> GetByIdAsync(int id)
{
try
{
return await _repository.GetByIdAsync(id);
}
catch (Exception ex)
{
var method = MethodBase.GetCurrentMethod()?.Name ?? "Unknown";
throw new Exception($"{method} Message: {ex.Message}", ex);
}
}
public async Task<EProduct> CreateAsync(EProduct entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity), "El producto no puede ser nulo.");
if (string.IsNullOrWhiteSpace(entity.Name))
throw new ArgumentException("El producto debe tener un nombre válido.");
if (entity.Baseprice < 0)
throw new ArgumentException("El precio base no puede ser negativo.");
return await _repository.CreateAsync(entity);
}
public async Task<bool> UpdateAsync(EProduct entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity), "El producto no puede ser nulo.");
if (string.IsNullOrWhiteSpace(entity.Name))
throw new ArgumentException("El producto debe tener un nombre válido.");
if (entity.Baseprice < 0)
throw new ArgumentException("El precio base no puede ser negativo.");
return await _repository.UpdateAsync(entity);
}
public async Task<bool> DeleteAsync(int id)
{
return await _repository.DeleteAsync(id);
}
public async Task<byte[]> ExportFilteredProductsToExcelAsync(ProductSearchParams searchParams)
{
try
{
// Realiza la búsqueda de productos con los parámetros proporcionados
var searchResult = await SearchAsync(searchParams.Term, searchParams.Page, searchParams.PageSize);
if (searchResult?.Items is null || !searchResult.Items.Any())
{
throw new Exception("No se encontraron productos para exportar.");
}
// Llamamos a un método que exporta los datos a Excel
var stream = new XLSXExportBase();
// Convertimos los resultados de la búsqueda a un formato adecuado para el exportador
var productData = searchResult.Items.Select(p => new
{
p.Id,
p.Name,
p.Description,
BusinessUnit = p.Businessunits?.Code,
Category = p.Category?.Name,
p.Origin,
p.Baseprice,
p.Currency,
p.Isactive
}).ToList();
// Genera el archivo Excel
var excelFile = stream.ExportExcel(productData);
// Devuelve el archivo Excel como un array de bytes
return excelFile;
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
#endregion
}
}

View File

@ -0,0 +1,7 @@
namespace Domain.Generics
{
public class ProductSearchParams: PagedRequest
{
public string? Term { get; set; }
}
}

View File

@ -7,7 +7,7 @@
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot> <NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders> <NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle> <NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion> <NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\maski\.nuget\packages\" /> <SourceRoot Include="C:\Users\maski\.nuget\packages\" />

View File

@ -0,0 +1,14 @@
using Domain.Entities;
namespace Models.Interfaces
{
public interface IPhSBusinessUnitRepository
{
Task<IEnumerable<EBusinessUnit>> GetAllAsync();
Task<EBusinessUnit?> GetByIdAsync(int id);
Task<IEnumerable<EBusinessUnit>> SearchAsync(string term);
Task<EBusinessUnit> CreateAsync(EBusinessUnit unit);
Task<bool> UpdateAsync(EBusinessUnit unit);
Task<bool> DeleteAsync(int id);
}
}

View File

@ -0,0 +1,14 @@
using Domain.Entities;
namespace Models.Interfaces
{
public interface IPhSProductCategoryRepository
{
Task<IEnumerable<EProductCategory>> GetAllAsync();
Task<EProductCategory?> GetByIdAsync(int id);
Task<IEnumerable<EProductCategory>> SearchAsync(string term);
Task<EProductCategory> CreateAsync(EProductCategory unit);
Task<bool> UpdateAsync(EProductCategory unit);
Task<bool> DeleteAsync(int id);
}
}

View File

@ -0,0 +1,15 @@
using Domain.Entities;
using Domain.Generics;
namespace Models.Interfaces
{
public interface IPhSProductRepository
{
Task<EProduct> CreateAsync(EProduct entity);
Task<bool> DeleteAsync(int id);
Task<PagedResult<EProduct>> GetAllAsync(int page = 1, int pageSize = 50);
Task<EProduct?> GetByIdAsync(int id);
Task<PagedResult<EProduct>> SearchAsync(string? term, int page = 1, int pageSize = 50);
Task<bool> UpdateAsync(EProduct entity);
}
}

View File

@ -1,7 +1,4 @@
using System; namespace Models.Models;
using System.Collections.Generic;
namespace Models.Models;
public partial class PhSBusinessUnit public partial class PhSBusinessUnit
{ {

View File

@ -1,7 +1,4 @@
using System; namespace Models.Models;
using System.Collections.Generic;
namespace Models.Models;
public partial class PhSProductCategory public partial class PhSProductCategory
{ {

View File

@ -1,7 +1,4 @@
using System; namespace Models.Models;
using System.Collections.Generic;
namespace Models.Models;
public partial class PhSQuoteDetail public partial class PhSQuoteDetail
{ {

View File

@ -1,7 +1,7 @@
using Domain.Entities; using Domain.Entities;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Models.Helpers;
using Models.Interfaces; using Models.Interfaces;
using Models.Helpers;
using Models.Models; using Models.Models;
namespace Models.Repositories namespace Models.Repositories

View File

@ -0,0 +1,97 @@
using Microsoft.EntityFrameworkCore;
using Models.Interfaces;
using Domain.Entities;
using Models.Helpers;
using Models.Models;
namespace Models.Repositories
{
public class PhSBusinessUnitRepository(PhronCareOperationsHubContext context) : IPhSBusinessUnitRepository
{
#region Declaraciones y Constructor
private readonly PhronCareOperationsHubContext _context = context;
#endregion
#region Metodos de clase
public async Task<IEnumerable<EBusinessUnit>> GetAllAsync()
{
var businessUnits = await _context.PhSBusinessUnits.ToListAsync();
return businessUnits.Select(EntityMapper.MapEntity<PhSBusinessUnit, EBusinessUnit>);
}
public async Task<EBusinessUnit?> GetByIdAsync(int id)
{
var entity = await _context.PhSBusinessUnits.FindAsync(id);
return entity is null ? null : EntityMapper.MapEntity<PhSBusinessUnit, EBusinessUnit>(entity);
}
public async Task<IEnumerable<EBusinessUnit>> SearchAsync(string term)
{
var query = _context.PhSBusinessUnits.AsQueryable();
if (!string.IsNullOrWhiteSpace(term))
{
term = term.ToLower();
query = query.Where(x =>
x.Description.ToLower().Contains(term) ||
x.Code.ToLower().Contains(term) ||
x.Manager.ToLower().Contains(term));
}
var result = await query.ToListAsync();
return result.Select(EntityMapper.MapEntity<PhSBusinessUnit, EBusinessUnit>);
}
public async Task<EBusinessUnit> CreateAsync(EBusinessUnit unit)
{
if (unit == null) throw new ArgumentNullException(nameof(unit), "La unidad de negocio no puede ser nulo.");
try
{
var businessUnit = EntityMapper.MapEntity<EBusinessUnit, PhSBusinessUnit>(unit);
await _context.PhSBusinessUnits.AddAsync(businessUnit);
await _context.SaveChangesAsync();
return EntityMapper.MapEntity<PhSBusinessUnit, EBusinessUnit>(businessUnit);
}
catch (DbUpdateException dbEx)
{
// Error relacionado con la base de datos (como violación de integridad referencial)
throw new Exception("Error al guardar la unidad de negocio en la base de datos. Es posible que haya un problema con la integridad de los datos.", dbEx);
}
catch (Exception ex)
{
// Captura cualquier otro tipo de excepción
throw new Exception("Error inesperado al crear la unidad de negocio: " + ex.Message, ex);
}
}
public async Task<bool> UpdateAsync(EBusinessUnit unit)
{
if (unit == null) throw new ArgumentNullException(nameof(unit), "La unidad de negocio no puede ser nula.");
try
{
var existingUnit = await _context.PhSBusinessUnits
.FirstOrDefaultAsync(c => c.Id == unit.Id);
if (existingUnit == null)
return false;
// Mapea los cambios del modelo EBusinessUnit a la entidad trackeada por EF
EntityMapper.MapEntityToExisting(unit, existingUnit);
await _context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
return false;
}
}
public async Task<bool> DeleteAsync(int id)
{
var entity = await _context.PhSBusinessUnits.FindAsync(id);
if (entity != null)
{
_context.PhSBusinessUnits.Remove(entity);
await _context.SaveChangesAsync();
}
return true;
}
#endregion
}
}

View File

@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging;
using Models.Helpers; using Models.Helpers;
using Models.Interfaces; using Models.Interfaces;
using Models.Models; using Models.Models;
using System.Xml.Linq;
namespace Models.Repositories namespace Models.Repositories
{ {

View File

@ -0,0 +1,88 @@
using Microsoft.EntityFrameworkCore;
using Models.Interfaces;
using Domain.Entities;
using Models.Helpers;
using Models.Models;
namespace Models.Repositories
{
public class PhSProductCategoryRepository(PhronCareOperationsHubContext context) : IPhSProductCategoryRepository
{
#region Declaraciones y Constructor
private readonly PhronCareOperationsHubContext _context = context;
#endregion
#region Metodos de clase
public async Task<IEnumerable<EProductCategory>> GetAllAsync()
{
var businessUnits = await _context.PhSProductCategories.ToListAsync();
return businessUnits.Select(EntityMapper.MapEntity<PhSProductCategory, EProductCategory>);
}
public async Task<EProductCategory?> GetByIdAsync(int id)
{
var entity = await _context.PhSProductCategories.FindAsync(id);
return entity is null ? null : EntityMapper.MapEntity<PhSProductCategory, EProductCategory>(entity);
}
public async Task<IEnumerable<EProductCategory>> SearchAsync(string term)
{
var query = _context.PhSProductCategories.AsQueryable();
if (!string.IsNullOrWhiteSpace(term))
{
term = term.ToLower();
query = query.Where(x =>
x.Description.ToLower().Contains(term) ||
x.Name.ToLower().Contains(term));
}
var result = await query.ToListAsync();
return result.Select(EntityMapper.MapEntity<PhSProductCategory, EProductCategory>);
}
public async Task<EProductCategory> CreateAsync(EProductCategory unit)
{
if (unit == null) throw new ArgumentNullException(nameof(unit), "La categoria no puede ser nula.");
try
{
var category = EntityMapper.MapEntity<EProductCategory, PhSProductCategory>(unit);
await _context.PhSProductCategories.AddAsync(category);
await _context.SaveChangesAsync();
return EntityMapper.MapEntity<PhSProductCategory, EProductCategory>(category);
}
catch (DbUpdateException dbEx)
{
// Error relacionado con la base de datos (como violación de integridad referencial)
throw new Exception("Error al guardar la categoria en la base de datos. Es posible que haya un problema con la integridad de los datos.", dbEx);
}
catch (Exception ex)
{
// Captura cualquier otro tipo de excepción
throw new Exception("Error inesperado al crear la categoria: " + ex.Message, ex);
}
}
public async Task<bool> UpdateAsync(EProductCategory category)
{
if (category == null || category.Id <= 0)
throw new ArgumentNullException(nameof(category), "La categoría no puede ser nula o tener un ID inválido.");
var existingCategory = await _context.PhSProductCategories
.FirstOrDefaultAsync(c => c.Id == category.Id);
if (existingCategory == null)
return false;
EntityMapper.MapEntityToExisting(category, existingCategory);
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> DeleteAsync(int id)
{
var entity = await _context.PhSProductCategories.FindAsync(id);
if (entity != null)
{
_context.PhSProductCategories.Remove(entity);
await _context.SaveChangesAsync();
}
return true;
}
#endregion
}
}

View File

@ -0,0 +1,125 @@
using Models.Interfaces;
using Domain.Entities;
using Models.Helpers;
using Models.Models;
using Microsoft.EntityFrameworkCore;
using Domain.Generics;
namespace Models.Repositories
{
public class PhSProductRepository(PhronCareOperationsHubContext context) : IPhSProductRepository
{
#region Declaraciones y Constructor
private readonly PhronCareOperationsHubContext _context = context;
#endregion
#region Métodos de clase
public async Task<PagedResult<EProduct>> GetAllAsync(int page = 1, int pageSize = 50)
{
var query = _context.PhSProducts
.Include(p => p.Businessunits)
.Include(p => p.Category)
.AsQueryable();
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
return new PagedResult<EProduct>
{
Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSProduct, EProduct>),
TotalItems = pagedEntities.TotalItems,
Page = pagedEntities.Page,
PageSize = pagedEntities.PageSize
};
}
public async Task<EProduct?> GetByIdAsync(int id)
{
var product = await _context.PhSProducts
.Include(p => p.Businessunits)
.Include(p => p.Category)
.FirstOrDefaultAsync(p => p.Id == id);
return product is null ? null : EntityMapper.MapEntity<PhSProduct, EProduct>(product);
}
public async Task<PagedResult<EProduct>> SearchAsync(string? term, int page = 1, int pageSize = 50)
{
var query = _context.PhSProducts
.Include(p => p.Businessunits)
.Include(p => p.Category)
.AsQueryable();
if (!string.IsNullOrWhiteSpace(term))
{
term = term.ToLower();
query = query.Where(p =>
p.Name.ToLower().Contains(term) ||
p.Description.ToLower().Contains(term));
}
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
return new PagedResult<EProduct>
{
Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSProduct, EProduct>),
TotalItems = pagedEntities.TotalItems,
Page = pagedEntities.Page,
PageSize = pagedEntities.PageSize
};
}
public async Task<EProduct> CreateAsync(EProduct entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity), "El producto no puede ser nulo.");
try
{
var product = EntityMapper.MapEntity<EProduct, PhSProduct>(entity);
await _context.PhSProducts.AddAsync(product);
await _context.SaveChangesAsync();
return EntityMapper.MapEntity<PhSProduct, EProduct>(product);
}
catch (DbUpdateException dbEx)
{
throw new Exception("Error al guardar el producto en la base de datos. Verificá integridad de datos.", dbEx);
}
catch (Exception ex)
{
throw new Exception("Error inesperado al crear el producto: " + ex.Message, ex);
}
}
public async Task<bool> UpdateAsync(EProduct entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
try
{
var existingProduct = await _context.PhSProducts
.Include(p => p.Businessunits)
.Include(p => p.Category)
.FirstOrDefaultAsync(p => p.Id == entity.Id);
if (existingProduct == null)
return false;
EntityMapper.MapEntityToExisting(entity, existingProduct);
await _context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
return false;
}
}
public async Task<bool> DeleteAsync(int id)
{
var product = await _context.PhSProducts.FindAsync(id);
if (product == null) return false;
_context.PhSProducts.Remove(product);
await _context.SaveChangesAsync();
return true;
}
#endregion
}
}

View File

@ -7,7 +7,7 @@
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot> <NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders> <NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle> <NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion> <NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\maski\.nuget\packages\" /> <SourceRoot Include="C:\Users\maski\.nuget\packages\" />

View File

@ -0,0 +1,134 @@
using Core.Interfaces;
using Domain.Entities;
using Domain.Generics;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace phronCare.API.Controllers.Sales
{
[Route("api/[controller]")]
[ApiController]
public class BusinessUnitController : ControllerBase
{
private readonly IBusinessUnitDom _businessUnitService;
public BusinessUnitController(IBusinessUnitDom businessUnitService)
{
_businessUnitService = businessUnitService ?? throw new ArgumentNullException(nameof(businessUnitService));
}
[HttpGet("all")]
public async Task<IActionResult> GetAll()
{
try
{
var result = await _businessUnitService.GetAllAsync();
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("search")]
public async Task<IActionResult> Search([FromQuery] string? term)
{
try
{
var result = await _businessUnitService.SearchAsync(term ?? string.Empty);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("{id:int}")]
public async Task<ActionResult<EBusinessUnit>> GetById(int id)
{
try
{
var result = await _businessUnitService.GetByIdAsync(id);
if (result == null)
return NotFound($"No se encontró una unidad de negocio con ID {id}.");
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error: {ex.Message}");
}
}
[HttpPost("create")]
public async Task<IActionResult> Create([FromBody] EBusinessUnit unit)
{
try
{
if (unit == null)
return BadRequest("La unidad de negocio no puede ser nula.");
var result = await _businessUnitService.CreateAsync(unit);
return Ok(result);
}
catch (ArgumentNullException ex)
{
return BadRequest($"Validación fallida: {ex.Message}");
}
catch (InvalidOperationException ex)
{
return BadRequest($"Error de negocio: {ex.Message}");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpPut("update")]
public async Task<IActionResult> Update([FromBody] EBusinessUnit unit)
{
try
{
if (unit == null || unit.Id <= 0)
return BadRequest("La unidad de negocio es inválida o no tiene un ID válido.");
var success = await _businessUnitService.UpdateAsync(unit);
if (!success)
return NotFound($"No se encontró una unidad de negocio con ID {unit.Id}.");
return Ok("Unidad de negocio actualizada correctamente.");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpDelete("{id:int}")]
public async Task<IActionResult> Delete(int id)
{
try
{
var success = await _businessUnitService.DeleteAsync(id);
if (!success)
return NotFound($"No se encontró una unidad de negocio con ID {id}.");
return Ok("Unidad de negocio eliminada correctamente.");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,133 @@
using Core.Interfaces;
using Domain.Entities;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace phronCare.API.Controllers.Sales
{
[Route("api/[controller]")]
[ApiController]
public class ProductCategoryController : ControllerBase
{
private readonly IProductCategoryDom _productCategoryService;
public ProductCategoryController(IProductCategoryDom productCategoryService)
{
_productCategoryService = productCategoryService ?? throw new ArgumentNullException(nameof(productCategoryService));
}
[HttpGet("all")]
public async Task<IActionResult> GetAll()
{
try
{
var result = await _productCategoryService.GetAllAsync();
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("search")]
public async Task<IActionResult> Search([FromQuery] string? term)
{
try
{
var result = await _productCategoryService.SearchAsync(term ?? string.Empty);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("{id:int}")]
public async Task<ActionResult<EProductCategory>> GetById(int id)
{
try
{
var result = await _productCategoryService.GetByIdAsync(id);
if (result == null)
return NotFound($"No se encontró una categoría de producto con ID {id}.");
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error: {ex.Message}");
}
}
[HttpPost("create")]
public async Task<IActionResult> Create([FromBody] EProductCategory category)
{
try
{
if (category == null)
return BadRequest("La categoría de producto no puede ser nula.");
var result = await _productCategoryService.CreateAsync(category);
return Ok(result);
}
catch (ArgumentNullException ex)
{
return BadRequest($"Validación fallida: {ex.Message}");
}
catch (InvalidOperationException ex)
{
return BadRequest($"Error de negocio: {ex.Message}");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpPut("update")]
public async Task<IActionResult> Update([FromBody] EProductCategory category)
{
try
{
if (category == null || category.Id <= 0)
return BadRequest("La categoría de producto es inválida o no tiene un ID válido.");
var success = await _productCategoryService.UpdateAsync(category);
if (!success)
return NotFound($"No se encontró una categoría de producto con ID {category.Id}.");
return Ok("Categoría de producto actualizada correctamente.");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpDelete("{id:int}")]
public async Task<IActionResult> Delete(int id)
{
try
{
var success = await _productCategoryService.DeleteAsync(id);
if (!success)
return NotFound($"No se encontró una categoría de producto con ID {id}.");
return Ok("Categoría de producto eliminada correctamente.");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,134 @@
using Core.Interfaces;
using Domain.Entities;
using Domain.Generics;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace phronCare.API.Controllers.Sales
{
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
private readonly IProductDom _productService;
public ProductController(IProductDom productService)
{
_productService = productService ?? throw new ArgumentNullException(nameof(productService));
}
[HttpGet("all")]
public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 50)
{
try
{
var result = await _productService.GetAllAsync(page, pageSize);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("search")]
public async Task<IActionResult> Search(
[FromQuery] string? term,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50)
{
try
{
var result = await _productService.SearchAsync(term, page, pageSize);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("{id:int}")]
public async Task<ActionResult<EProduct>> GetById(int id)
{
try
{
var product = await _productService.GetByIdAsync(id);
if (product == null)
return NotFound();
return Ok(product);
}
catch (Exception ex)
{
return StatusCode(500, $"Error: {ex.Message}");
}
}
[HttpPost("create")]
public async Task<IActionResult> Create([FromBody] EProduct product)
{
try
{
if (product == null)
return BadRequest("El producto no puede ser nulo.");
var result = await _productService.CreateAsync(product);
return Ok(result);
}
catch (ArgumentNullException ex)
{
return BadRequest($"Validación fallida: {ex.Message}");
}
catch (InvalidOperationException ex)
{
return BadRequest($"Error de negocio: {ex.Message}");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpPut("update")]
public async Task<IActionResult> Update([FromBody] EProduct product)
{
try
{
if (product == null || product.Id <= 0)
return BadRequest("El producto es inválido o no tiene un ID válido.");
var success = await _productService.UpdateAsync(product);
if (!success)
return NotFound($"No se encontró un producto con ID {product.Id}.");
return Ok("Producto actualizado correctamente.");
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpPost("exportfiltered")]
public async Task<IActionResult> ExportFiltered([FromBody] ProductSearchParams searchParams)
{
try
{
var file = await _productService.ExportFilteredProductsToExcelAsync(searchParams);
return File(file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Productos.xlsx");
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
}

View File

@ -33,14 +33,31 @@ builder.Services.AddDbContext<PhronCareOperationsHubContext>(options =>
#region Repositorios y Servicios #region Repositorios y Servicios
builder.Services.AddScoped<ITicketDom, TicketService>(); builder.Services.AddScoped<ITicketDom, TicketService>();
builder.Services.AddScoped<ITicketRepository, TicketRepository>(); builder.Services.AddScoped<ITicketRepository, TicketRepository>();
builder.Services.AddScoped<IAccountTypeDom, AccountTypeService>(); builder.Services.AddScoped<IAccountTypeDom, AccountTypeService>();
builder.Services.AddScoped<IPhSAccountTypeRepository, PhSAccountTypeRepository>(); builder.Services.AddScoped<IPhSAccountTypeRepository, PhSAccountTypeRepository>();
builder.Services.AddScoped<ITaxConditionDom, TaxConditionService>(); builder.Services.AddScoped<ITaxConditionDom, TaxConditionService>();
builder.Services.AddScoped<IPhSTaxConditionRepository, PhOhTaxConditionRepository>(); builder.Services.AddScoped<IPhSTaxConditionRepository, PhOhTaxConditionRepository>();
builder.Services.AddScoped<IDocumentTypeDom, DocumentTypeService>(); builder.Services.AddScoped<IDocumentTypeDom, DocumentTypeService>();
builder.Services.AddScoped<IPhSDocumentTypeRepository, PhSDocumentTypeRepository>(); builder.Services.AddScoped<IPhSDocumentTypeRepository, PhSDocumentTypeRepository>();
builder.Services.AddScoped<ICustomerDom, CustomerService>(); builder.Services.AddScoped<ICustomerDom, CustomerService>();
builder.Services.AddScoped<IPhSCustomerRepository, PhSCustomerRepository>(); builder.Services.AddScoped<IPhSCustomerRepository, PhSCustomerRepository>();
builder.Services.AddScoped<IProductDom, ProductService>();
builder.Services.AddScoped<IPhSProductRepository, PhSProductRepository>();
builder.Services.AddScoped<ICustomerDom, CustomerService>();
builder.Services.AddScoped<IPhSCustomerRepository, PhSCustomerRepository>();
builder.Services.AddScoped<IProductCategoryDom, ProductCategoryService>();
builder.Services.AddScoped<IPhSProductCategoryRepository, PhSProductCategoryRepository>();
builder.Services.AddScoped<IBusinessUnitDom, BusinessUnitService>();
builder.Services.AddScoped<IPhSBusinessUnitRepository, PhSBusinessUnitRepository>();
#endregion #endregion
#region Require Confirmed Email #region Require Confirmed Email

View File

@ -304,6 +304,106 @@
], ],
"ReturnTypes": [] "ReturnTypes": []
}, },
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "GetById",
"RelativePath": "api/BusinessUnit/{id}",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "Domain.Entities.EBusinessUnit",
"MediaTypes": [
"text/plain",
"application/json",
"text/json"
],
"StatusCode": 200
}
]
},
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "Delete",
"RelativePath": "api/BusinessUnit/{id}",
"HttpMethod": "DELETE",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "GetAll",
"RelativePath": "api/BusinessUnit/all",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "Create",
"RelativePath": "api/BusinessUnit/create",
"HttpMethod": "POST",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "unit",
"Type": "Domain.Entities.EBusinessUnit",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "Search",
"RelativePath": "api/BusinessUnit/search",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "term",
"Type": "System.String",
"IsRequired": false
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.BusinessUnitController",
"Method": "Update",
"RelativePath": "api/BusinessUnit/update",
"HttpMethod": "PUT",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "unit",
"Type": "Domain.Entities.EBusinessUnit",
"IsRequired": true
}
],
"ReturnTypes": []
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.CustomerController", "ContainingType": "phronCare.API.Controllers.Sales.CustomerController",
"Method": "GetById", "Method": "GetById",
@ -471,6 +571,227 @@
], ],
"ReturnTypes": [] "ReturnTypes": []
}, },
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "GetById",
"RelativePath": "api/Product/{id}",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "Domain.Entities.EProduct",
"MediaTypes": [
"text/plain",
"application/json",
"text/json"
],
"StatusCode": 200
}
]
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "GetAll",
"RelativePath": "api/Product/all",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "page",
"Type": "System.Int32",
"IsRequired": false
},
{
"Name": "pageSize",
"Type": "System.Int32",
"IsRequired": false
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "Create",
"RelativePath": "api/Product/create",
"HttpMethod": "POST",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "product",
"Type": "Domain.Entities.EProduct",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "ExportFiltered",
"RelativePath": "api/Product/exportfiltered",
"HttpMethod": "POST",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "searchParams",
"Type": "Domain.Generics.ProductSearchParams",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "Search",
"RelativePath": "api/Product/search",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "term",
"Type": "System.String",
"IsRequired": false
},
{
"Name": "page",
"Type": "System.Int32",
"IsRequired": false
},
{
"Name": "pageSize",
"Type": "System.Int32",
"IsRequired": false
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductController",
"Method": "Update",
"RelativePath": "api/Product/update",
"HttpMethod": "PUT",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "product",
"Type": "Domain.Entities.EProduct",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "GetById",
"RelativePath": "api/ProductCategory/{id}",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "Domain.Entities.EProductCategory",
"MediaTypes": [
"text/plain",
"application/json",
"text/json"
],
"StatusCode": 200
}
]
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "Delete",
"RelativePath": "api/ProductCategory/{id}",
"HttpMethod": "DELETE",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "GetAll",
"RelativePath": "api/ProductCategory/all",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "Create",
"RelativePath": "api/ProductCategory/create",
"HttpMethod": "POST",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "category",
"Type": "Domain.Entities.EProductCategory",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "Search",
"RelativePath": "api/ProductCategory/search",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "term",
"Type": "System.String",
"IsRequired": false
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.ProductCategoryController",
"Method": "Update",
"RelativePath": "api/ProductCategory/update",
"HttpMethod": "PUT",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "category",
"Type": "Domain.Entities.EProductCategory",
"IsRequired": true
}
],
"ReturnTypes": []
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController", "ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController",
"Method": "GetAll", "Method": "GetAll",