Refactoring & Add Quotes
Some checks failed
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Failing after 2m13s

This commit is contained in:
Leandro Hernan Rojas 2025-05-13 12:08:38 -03:00
parent bc07220cf7
commit 272f8330d7
57 changed files with 1226 additions and 6387 deletions

View File

@ -10,6 +10,7 @@
<ProjectReference Include="..\Domain\Domain.csproj" /> <ProjectReference Include="..\Domain\Domain.csproj" />
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
<ProjectReference Include="..\Transversal\Transversal.csproj" /> <ProjectReference Include="..\Transversal\Transversal.csproj" />
<!--<ProjectReference Include="..\Transversal\Transversal.csproj" />-->
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,9 +1,4 @@
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -0,0 +1,10 @@
using Domain.Entities;
namespace Core.Interfaces
{
public interface IArcataxTypeDom
{
Task<IEnumerable<ETaxType>> GetAllActiveAsync();
}
}

View File

@ -1,9 +1,4 @@
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -0,0 +1,11 @@
using Domain.Entities;
namespace Core.Interfaces
{
public interface IExchangeRateHistoryDom
{
Task<EExchangeRateHistory> AddAsync(EExchangeRateHistory entity);
Task<EExchangeRateHistory?> GetByDateAsync(DateOnly date);
}
}

View File

@ -1,10 +1,5 @@
using Domain.Entities; using Domain.Entities;
using Domain.Generics; using Domain.Generics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -1,9 +1,4 @@
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -1,14 +1,14 @@
using Domain.Entities; using Domain.Entities;
using Domain.Generics; using Domain.Generics;
namespace Models.Interfaces namespace Core.Interfaces
{ {
public interface IPeopleDom public interface IPeopleDom
{ {
Task<PagedResult<EPerson>> GetAllAsync(int page = 1, int pageSize = 50); Task<PagedResult<EPerson>> GetAllAsync(int page = 1, int pageSize = 50);
Task<PagedResult<EPerson>> SearchAsync(string? name, string? email, int page = 1, int pageSize = 50); Task<PagedResult<EPerson>> SearchAsync(string? name, string? email, int page = 1, int pageSize = 50);
Task<EPerson?> GetByIdAsync(int id); Task<EPerson?> GetByIdAsync(int id);
Task<EPerson> CreateAsync(EPerson person); Task<EPerson> AddAsync(EPerson person);
Task<bool> UpdateAsync(EPerson person); Task<bool> UpdateAsync(EPerson person);
Task<bool> DeleteAsync(int id); Task<bool> DeleteAsync(int id);
Task<byte[]> ExportFilteredCustomersToExcelAsync(PeopleSearchParams searchParams); Task<byte[]> ExportFilteredCustomersToExcelAsync(PeopleSearchParams searchParams);

View File

@ -0,0 +1,11 @@
using Domain.Entities;
namespace Models.Interfaces
{
public interface IPhOHExchangeRateHistoryDom
{
Task<EExchangeRateHistory> AddAsync(EExchangeRateHistory entity);
Task<EExchangeRateHistory?> GetByDateAsync(DateOnly date);
}
}

View File

@ -4,7 +4,7 @@ namespace Core.Interfaces
{ {
public interface IProductCategoryDom public interface IProductCategoryDom
{ {
Task<EProductCategory> CreateAsync(EProductCategory unit); Task<EProductCategory> AddAsync(EProductCategory unit);
Task<IEnumerable<EProductCategory>> GetAllAsync(); Task<IEnumerable<EProductCategory>> GetAllAsync();
Task<EProductCategory?> GetByIdAsync(int id); Task<EProductCategory?> GetByIdAsync(int id);
Task<IEnumerable<EProductCategory>> SearchAsync(string term); Task<IEnumerable<EProductCategory>> SearchAsync(string term);

View File

@ -1,4 +1,5 @@
using Domain.Entities; using Core.Dtos;
using Domain.Entities;
using Domain.Generics; using Domain.Generics;
namespace Models.Interfaces namespace Models.Interfaces
@ -6,25 +7,15 @@ namespace Models.Interfaces
public interface IQuoteDom public interface IQuoteDom
{ {
#region Presupuestos #region Presupuestos
Task<PagedResult<EQuoteHeader>> GetAllQuotesAsync(int page = 1, int pageSize = 50); //Task<PagedResult<EQuoteHeader>> GetAllQuotesAsync(int page = 1, int pageSize = 50);
Task<EQuoteHeader?> GetQuoteByIdAsync(int id); //Task<EQuoteHeader?> GetQuoteByIdAsync(int id);
Task<IEnumerable<EQuoteHeader>> GetQuotesByCustomerAsync(int customerId); //Task<IEnumerable<EQuoteHeader>> GetQuotesByCustomerAsync(int customerId);
Task<PagedResult<EQuoteHeader>> SearchQuotesAsync( Task<PagedResult<QuoteDto>> SearchAsync(int? customerId, string? customerText, string? quoteNumber, int? professionalId, string? professionalText, int? institutionId, string? institutionText, int? patientId, string? patientText, DateTime? issueDateFrom, DateTime? issueDateTo, string? status, int page = 1, int pageSize = 50);
int? customerId, //Task UpdateQuoteAsync(EQuoteHeader quote);
string? quoteNumber, //Task DeleteQuoteAsync(int id);
int? professionalId,
int? institutionId,
int? patientId,
DateTime? issueDateFrom,
DateTime? issueDateTo,
string? status,
int page = 1,
int pageSize = 50);
Task UpdateQuoteAsync(EQuoteHeader quote);
Task DeleteQuoteAsync(int id);
#endregion #endregion
#region Exportación #region Exportación
Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams); //Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams);
#endregion #endregion
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos) #region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId); Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);

View File

@ -1,9 +1,4 @@
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -1,9 +1,4 @@
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -1,10 +1,5 @@
 
using Domain.Entities; using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Interfaces namespace Core.Interfaces
{ {

View File

@ -4,12 +4,12 @@ using Models.Interfaces;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
public class ExchangeRateDom : IExchangeRateDom public class ExchangeRateRepository : IExchangeRateDom
{ {
private readonly IPhOHExchangeRateHistory _repository; private readonly IPhOHExchangeRateHistory _repository;
private readonly HttpClient _http; private readonly HttpClient _http;
public ExchangeRateDom(IPhOHExchangeRateHistory repository, HttpClient http) public ExchangeRateRepository(IPhOHExchangeRateHistory repository, HttpClient http)
{ {
_repository = repository; _repository = repository;
_http = http; _http = http;

View File

@ -1,4 +1,5 @@
using Domain.Entities; using Core.Interfaces;
using Domain.Entities;
using Domain.Generics; using Domain.Generics;
using Models.Interfaces; using Models.Interfaces;
using System.Reflection; using System.Reflection;
@ -30,7 +31,7 @@ namespace Core.Services
return await _peopleRepository.GetByIdAsync(id); return await _peopleRepository.GetByIdAsync(id);
} }
public async Task<EPerson> CreateAsync(EPerson person) public async Task<EPerson> AddAsync(EPerson person)
{ {
return await _peopleRepository.AddAsync(person); return await _peopleRepository.AddAsync(person);
} }

View File

@ -49,7 +49,7 @@ namespace Core.Services
throw new Exception($"{method} Message: {ex.Message}", ex); throw new Exception($"{method} Message: {ex.Message}", ex);
} }
} }
public async Task<EProductCategory> CreateAsync(EProductCategory entity) public async Task<EProductCategory> AddAsync(EProductCategory entity)
{ {
if (entity == null) if (entity == null)
throw new ArgumentNullException(nameof(entity), "La categoría no puede ser nula."); throw new ArgumentNullException(nameof(entity), "La categoría no puede ser nula.");

View File

@ -1,113 +1,37 @@
using Domain.Entities; using Core.Dtos;
using Domain.Constants;
using Domain.Entities;
using Domain.Generics; using Domain.Generics;
using Models.Helpers;
using Models.Interfaces; using Models.Interfaces;
using System.Reflection;
using Transversal.Services;
namespace Core.Services namespace Core.Services
{ {
public class QuoteService( public class QuoteService(IQuoteRepository quoteRepository):IQuoteDom
IPhSQuoteHeaderRepository quoteHeaderRepository,
IPhSQuoteRepository quoteRepository
) : IQuoteDom
{ {
#region Declaraciones #region Declaraciones
private readonly IPhSQuoteHeaderRepository _quoteHeaderRepository = quoteHeaderRepository; private readonly IQuoteRepository _quoteRepository = quoteRepository;
private readonly IPhSQuoteRepository _quoteRepository = quoteRepository; //private readonly IPhSQuoteRepository _quoteRepository = quoteRepository;
#endregion #endregion
#region Presupuestos public async Task<PagedResult<QuoteDto>> SearchAsync(int? customerId, string? customerText, string? quoteNumber, int? professionalId, string? professionalText, int? institutionId, string? institutionText, int? patientId, string? patientText, DateTime? issueDateFrom, DateTime? issueDateTo, string? status, int page, int pageSize)
public async Task<PagedResult<EQuoteHeader>> GetAllQuotesAsync(int page = 1, int pageSize = 50)
{ {
return await _quoteHeaderRepository.GetAllAsync(page, pageSize); return await _quoteRepository.SearchAsync(
}
public async Task<EQuoteHeader?> GetQuoteByIdAsync(int id)
{
return await _quoteHeaderRepository.GetByIdAsync(id);
}
public async Task<IEnumerable<EQuoteHeader>> GetQuotesByCustomerAsync(int customerId)
{
return await _quoteHeaderRepository.GetByCustomerIdAsync(customerId);
}
public async Task<PagedResult<EQuoteHeader>> SearchQuotesAsync(
int? customerId,
string? quoteNumber,
int? professionalId,
int? institutionId,
int? patientId,
DateTime? issueDateFrom,
DateTime? issueDateTo,
string? status,
int page = 1,
int pageSize = 50)
{
return await _quoteHeaderRepository.SearchAsync(
customerId, customerId,
customerText,
quoteNumber, quoteNumber,
professionalId, professionalId,
professionalText,
institutionId, institutionId,
institutionText,
patientId, patientId,
patientText,
issueDateFrom, issueDateFrom,
issueDateTo, issueDateTo,
status, status,
page, page,
pageSize); pageSize);
} }
public async Task UpdateQuoteAsync(EQuoteHeader quote) #region Presupuestos
{
await _quoteHeaderRepository.UpdateAsync(quote);
}
public async Task DeleteQuoteAsync(int id)
{
await _quoteHeaderRepository.DeleteAsync(id);
}
#endregion
#region Exportación
public async Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams)
{
try
{
var searchResult = await SearchQuotesAsync(
searchParams.CustomerId,
searchParams.QuoteNumber,
searchParams.ProfessionalId,
searchParams.InstitutionId,
searchParams.PatientId,
searchParams.IssueDateFrom,
searchParams.IssueDateTo,
searchParams.Status,
searchParams.Page,
searchParams.PageSize);
if (searchResult?.Items == null || !searchResult.Items.Any())
{
throw new Exception("No se encontraron presupuestos para exportar.");
}
var stream = new XLSXExportBase();
var quotesData = searchResult.Items.Select(q => new
{
NúmeroPresupuesto = q.Quotenumber,
Estado = q.Status,
FechaEmisión = q.Issuedate.ToString("yyyy-MM-dd"),
FechaTentativa = q.Estimateddate?.ToString("yyyy-MM-dd"),
ImporteAprobado = q.Approvedamount,
Profesional = q.PhSQuoteRoles.FirstOrDefault(r => r.Entitytype == PhSEntityTypes.Professional)?.Entitytype,
Institución = q.PhSQuoteRoles.FirstOrDefault(r => r.Entitytype == PhSEntityTypes.Institution)?.Entitytype,
Paciente = q.PhSQuoteRoles.FirstOrDefault(r => r.Entitytype == PhSEntityTypes.Patient)?.Entitytype
}).ToList();
return stream.ExportExcel(quotesData);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
throw new Exception($"{methodName} Message: {ex.Message}", ex);
}
}
#endregion #endregion
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos) #region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
@ -148,17 +72,15 @@ namespace Core.Services
if (quote.PhSQuoteRoles == null || !quote.PhSQuoteRoles.Any()) if (quote.PhSQuoteRoles == null || !quote.PhSQuoteRoles.Any())
throw new InvalidOperationException("Debe asignar al menos un rol (profesional, paciente o institución)."); throw new InvalidOperationException("Debe asignar al menos un rol (profesional, paciente o institución).");
var hasProfessional = quote.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Professional); var hasProfessional = quote.PhSQuoteRoles.Any(r => r.Entitytype == EntityTypes.Professional);
var hasPatient = quote.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Patient); var hasPatient = quote.PhSQuoteRoles.Any(r => r.Entitytype == EntityTypes.Patient);
var hasInstitution = quote.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Institution); var hasInstitution = quote.PhSQuoteRoles.Any(r => r.Entitytype == EntityTypes.Institution);
if (!hasProfessional) if (!hasProfessional)
throw new InvalidOperationException("Debe asignar un profesional."); throw new InvalidOperationException("Debe asignar un profesional.");
if (!hasInstitution) if (!hasInstitution)
throw new InvalidOperationException("Debe asignar un paciente."); throw new InvalidOperationException("Debe asignar un paciente.");
if (!hasPatient) if (!hasPatient)
throw new InvalidOperationException("Debe asignar un paciente."); throw new InvalidOperationException("Debe asignar un paciente.");
if (quote.PhSQuoteTaxes != null) if (quote.PhSQuoteTaxes != null)
{ {
foreach (var tax in quote.PhSQuoteTaxes) foreach (var tax in quote.PhSQuoteTaxes)
@ -167,7 +89,6 @@ namespace Core.Services
throw new ArgumentException($"La alícuota del impuesto '{tax.Taxname}' no es válida."); throw new ArgumentException($"La alícuota del impuesto '{tax.Taxname}' no es válida.");
} }
} }
if (quote.Total < 0) if (quote.Total < 0)
throw new ArgumentException("El total del presupuesto no puede ser negativo."); throw new ArgumentException("El total del presupuesto no puede ser negativo.");
} }

View File

@ -0,0 +1,9 @@
namespace Domain.Constants
{
public static class EntityTypes
{
public const string Professional = "PhS_Professionals";
public const string Institution = "PhS_Institutions";
public const string Patient = "PhS_Patients";
}
}

View File

@ -0,0 +1,15 @@
namespace Core.Dtos
{
public class QuoteAdjustmentDto
{
/// <summary>
/// Motivo del ajuste (ej. "Descuento promocional")
/// </summary>
public string Reason { get; set; } = "";
/// <summary>
/// Importe del ajuste (positivo para recargo, negativo para descuento)
/// </summary>
public decimal Amount { get; set; }
}
}

85
Domain/Dtos/QuoteDto.cs Normal file
View File

@ -0,0 +1,85 @@
namespace Core.Dtos
{
public class QuoteDto
{
/// <summary>
/// Identificador único del presupuesto.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Número de presupuesto (ej. "Q-00000001").
/// </summary>
public string Quotenumber { get; set; } = "";
/// <summary>
/// Fecha de emisión del presupuesto.
/// </summary>
public DateTime IssueDate { get; set; }
/// <summary>
/// Fecha estimada de realización o entrega.
/// </summary>
public DateTime? EstimatedDate { get; set; }
/// <summary>
/// Nombre completo del cliente asociado.
/// </summary>
public string CustomerName { get; set; } = "";
/// <summary>
/// Nombre completo del médico responsable.
/// </summary>
public string ProfessionalName { get; set; } = "";
/// <summary>
/// Nombre de la institución u hospital.
/// </summary>
public string InstitutionName { get; set; } = "";
/// <summary>
/// Nombre completo del paciente.
/// </summary>
public string PatientName { get; set; } = "";
/// <summary>
/// Nombre de la unidad de negocio.
/// </summary>
public string BusinessUnitName { get; set; } = "";
/// <summary>
/// Moneda del presupuesto (ej. "ARS", "USD").
/// </summary>
public string Currency { get; set; } = "";
/// <summary>
/// Importe total final (incluye impuestos y ajustes).
/// </summary>
public decimal Total { get; set; }
/// <summary>
/// Estado actual del presupuesto ("Pendiente", "Aprobado", etc.).
/// </summary>
public string Status { get; set; } = "";
/// <summary>
/// Nombre del vendedor o ejecutivo de ventas.
/// </summary>
public string SalespersonName { get; set; } = "";
/// <summary>
/// Detalle de los ítems o productos cotizados.
/// </summary>
public List<QuoteItemDto> Items { get; set; } = new();
/// <summary>
/// Desglose de los impuestos aplicados.
/// </summary>
public List<QuoteTaxDto> Taxes { get; set; } = new();
/// <summary>
/// Ajustes comerciales aplicados (descuentos o recargos).
/// </summary>
public List<QuoteAdjustmentDto> Adjustments { get; set; } = new();
}
}

View File

@ -0,0 +1,35 @@
namespace Core.Dtos
{
public class QuoteItemDto
{
/// <summary>
/// Descripción del producto o servicio cotizado.
/// </summary>
public string Description { get; set; } = "";
/// <summary>
/// Cantidad de unidades cotizadas.
/// </summary>
public int Quantity { get; set; }
/// <summary>
/// Precio unitario sin incluir impuestos.
/// </summary>
public decimal UnitPrice { get; set; }
/// <summary>
/// Subtotal (Quantity × UnitPrice).
/// </summary>
public decimal Subtotal { get; set; }
/// <summary>
/// Importe de impuestos aplicados al ítem.
/// </summary>
public decimal TaxAmount { get; set; }
/// <summary>
/// Total del ítem (Subtotal + TaxAmount).
/// </summary>
public decimal Total { get; set; }
}
}

View File

@ -0,0 +1,35 @@
namespace Core.Dtos
{
public class QuoteTaxDto
{
/// <summary>
/// Nombre del impuesto (ej. "IVA")
/// </summary>
public string TaxName { get; set; } = "";
/// <summary>
/// Código del impuesto (ej. "30")
/// </summary>
public string TaxCode { get; set; } = "";
/// <summary>
/// Base imponible sobre la que se calcula el impuesto
/// </summary>
public decimal TaxableAmount { get; set; }
/// <summary>
/// Tipo o porcentaje del impuesto (ej. 21)
/// </summary>
public decimal TaxRate { get; set; }
/// <summary>
/// Importe total del impuesto
/// </summary>
public decimal TaxAmount { get; set; }
/// <summary>
/// Indica si el impuesto está incluido en el precio
/// </summary>
public bool IsIncludedInPrice { get; set; }
}
}

View File

@ -3,12 +3,28 @@
public class QuoteSearchParams : PagedRequest public class QuoteSearchParams : PagedRequest
{ {
public int? CustomerId { get; set; } public int? CustomerId { get; set; }
public string? CustomerText { get; set; } // <-- nuevo
public string? QuoteNumber { get; set; } public string? QuoteNumber { get; set; }
public int? ProfessionalId { get; set; } public int? ProfessionalId { get; set; }
public string? ProfessionalText { get; set; } // <-- nuevo
public int? InstitutionId { get; set; } public int? InstitutionId { get; set; }
public string? InstitutionText { get; set; } // <-- nuevo
public int? PatientId { get; set; } public int? PatientId { get; set; }
public string? PatientText { get; set; } // <-- nuevo
public DateTime? IssueDateFrom { get; set; } public DateTime? IssueDateFrom { get; set; }
public DateTime? IssueDateTo { get; set; } public DateTime? IssueDateTo { get; set; }
public string? Status { get; set; } public string? Status { get; set; }
} }
//public class QuoteSearchParams : PagedRequest
//{
// public int? CustomerId { get; set; }
// public string? QuoteNumber { get; set; }
// public int? ProfessionalId { get; set; }
// public int? InstitutionId { get; set; }
// public int? PatientId { get; set; }
// public DateTime? IssueDateFrom { get; set; }
// public DateTime? IssueDateTo { get; set; }
// public string? Status { 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.2</NuGetToolVersion> <NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</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

@ -8,12 +8,8 @@ namespace Models.Interfaces
Task<PagedResult<EQuoteHeader>> GetAllAsync(int page = 1, int pageSize = 50); Task<PagedResult<EQuoteHeader>> GetAllAsync(int page = 1, int pageSize = 50);
Task<EQuoteHeader?> GetByIdAsync(int id); Task<EQuoteHeader?> GetByIdAsync(int id);
Task<IEnumerable<EQuoteHeader>> GetByCustomerIdAsync(int customerId); Task<IEnumerable<EQuoteHeader>> GetByCustomerIdAsync(int customerId);
Task<PagedResult<EQuoteHeader>> SearchAsync(int? customerId, string? quoteNumber, int? professionalId,
int? institutionId, int? patientId, DateTime? issueDateFrom, DateTime? issueDateTo, string? status,
int page = 1, int pageSize = 50);
Task UpdateAsync(EQuoteHeader quoteHeader); Task UpdateAsync(EQuoteHeader quoteHeader);
Task DeleteAsync(int id); Task DeleteAsync(int id);
// Ajustes // Ajustes
//Task<IEnumerable<EQuoteAdjustment>> GetAdjustmentsByQuoteIdAsync(int quoteId); //Task<IEnumerable<EQuoteAdjustment>> GetAdjustmentsByQuoteIdAsync(int quoteId);
//Task<EQuoteAdjustment> AddAdjustmentAsync(EQuoteAdjustment adjustment); //Task<EQuoteAdjustment> AddAdjustmentAsync(EQuoteAdjustment adjustment);

View File

@ -0,0 +1,21 @@
using Core.Dtos;
using Domain.Entities;
using Domain.Generics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Models.Interfaces
{
public interface IQuoteRepository
{
#region Presupuestos
Task<PagedResult<QuoteDto>> SearchAsync(int? customerId, string? customerText, string? quoteNumber, int? professionalId, string? professionalText, int? institutionId, string? institutionText, int? patientId, string? patientText, DateTime? issueDateFrom, DateTime? issueDateTo, string? status, int page = 1, int pageSize = 50);
#endregion
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
#endregion
}
}

View File

@ -977,10 +977,9 @@ public partial class PhronCareOperationsHubContext : DbContext
.HasComment("Número visible del presupuesto") .HasComment("Número visible del presupuesto")
.HasColumnName("quotenumber"); .HasColumnName("quotenumber");
entity.Property(e => e.Status) entity.Property(e => e.Status)
.HasMaxLength(2) .HasMaxLength(15)
.IsUnicode(false) .IsUnicode(false)
.HasDefaultValue("E") .HasDefaultValue("Emitido")
.IsFixedLength()
.HasComment("Estado: E (Emitido), A (Aprobado), AC (Aprobado para cirugia), etc.") .HasComment("Estado: E (Emitido), A (Aprobado), AC (Aprobado para cirugia), etc.")
.HasColumnName("status"); .HasColumnName("status");
entity.Property(e => e.TicketId) entity.Property(e => e.TicketId)

View File

@ -2,12 +2,11 @@
using Domain.Generics; using Domain.Generics;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Models.Helpers; using Models.Helpers;
using Models.Interfaces;
using Models.Models; using Models.Models;
namespace Models.Repositories namespace Models.Repositories
{ {
public class PhSQuoteDetailRepository(PhronCareOperationsHubContext context) : IPhSQuoteDetailRepository public class PhSQuoteDetailRepository(PhronCareOperationsHubContext context)
{ {
#region Declaraciones #region Declaraciones
private readonly PhronCareOperationsHubContext _context = context; private readonly PhronCareOperationsHubContext _context = context;

View File

@ -54,53 +54,6 @@ namespace Models.Repositories
return entities.Select(EntityMapper.MapEntity<PhSQuoteHeader, EQuoteHeader>); return entities.Select(EntityMapper.MapEntity<PhSQuoteHeader, EQuoteHeader>);
} }
public async Task<PagedResult<EQuoteHeader>> SearchAsync(int? customerId,
string? quoteNumber, int? professionalId, int? institutionId, int? patientId,
DateTime? issueDateFrom, DateTime? issueDateTo, string? status,
int page = 1, int pageSize = 50)
{
var query = _context.PhSQuoteHeaders
.Include(q => q.PhSQuoteDetails)
.Include(q => q.PhSQuoteRoles)
.Include(q => q.PhSQuoteAdjustments)
.Include(q => q.PhSQuoteTaxes)
.AsQueryable();
if (customerId.HasValue)
query = query.Where(q => q.CustomerId == customerId);
if (!string.IsNullOrEmpty(quoteNumber))
query = query.Where(q => q.Quotenumber.Contains(quoteNumber));
if (professionalId.HasValue)
query = query.Where(q => q.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Professional && r.EntityId == professionalId));
if (institutionId.HasValue)
query = query.Where(q => q.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Institution && r.EntityId == institutionId));
if (patientId.HasValue)
query = query.Where(q => q.PhSQuoteRoles.Any(r => r.Entitytype == PhSEntityTypes.Patient && r.EntityId == patientId));
if (issueDateFrom.HasValue)
query = query.Where(q => q.Issuedate >= issueDateFrom.Value);
if (issueDateTo.HasValue)
query = query.Where(q => q.Issuedate <= issueDateTo.Value);
if (!string.IsNullOrEmpty(status))
query = query.Where(q => q.Status == status);
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
return new PagedResult<EQuoteHeader>
{
Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSQuoteHeader, EQuoteHeader>),
TotalItems = pagedEntities.TotalItems,
Page = pagedEntities.Page,
PageSize = pagedEntities.PageSize
};
}
public async Task UpdateAsync(EQuoteHeader quoteHeader) public async Task UpdateAsync(EQuoteHeader quoteHeader)
{ {
var dbEntity = EntityMapper.MapEntity<EQuoteHeader, PhSQuoteHeader>(quoteHeader); var dbEntity = EntityMapper.MapEntity<EQuoteHeader, PhSQuoteHeader>(quoteHeader);
@ -117,172 +70,5 @@ namespace Models.Repositories
} }
} }
#endregion #endregion
#region <DECRECATED>
// ----------------------------
// Métodos para Ajustes
// ----------------------------
//public async Task<IEnumerable<EQuoteAdjustment>> GetAdjustmentsByQuoteIdAsync(int quoteId)
//{
// var adjustments = await _context.PhSQuoteAdjustments
// .Where(a => a.QuoteheaderId == quoteId)
// .ToListAsync();
// return adjustments.Select(EntityMapper.MapEntity<PhSQuoteAdjustment, EQuoteAdjustment>);
//}
//public async Task<EQuoteAdjustment> AddAdjustmentAsync(EQuoteAdjustment adjustment)
//{
// var dbEntity = EntityMapper.MapEntity<EQuoteAdjustment, PhSQuoteAdjustment>(adjustment);
// _context.PhSQuoteAdjustments.Add(dbEntity);
// await _context.SaveChangesAsync();
// return EntityMapper.MapEntity<PhSQuoteAdjustment, EQuoteAdjustment>(dbEntity);
//}
//public async Task UpdateAdjustmentAsync(EQuoteAdjustment adjustment)
//{
// var dbEntity = EntityMapper.MapEntity<EQuoteAdjustment, PhSQuoteAdjustment>(adjustment);
// _context.PhSQuoteAdjustments.Update(dbEntity);
// await _context.SaveChangesAsync();
//}
//public async Task DeleteAdjustmentAsync(int adjustmentId)
//{
// var entity = await _context.PhSQuoteAdjustments.FindAsync(adjustmentId);
// if (entity != null)
// {
// _context.PhSQuoteAdjustments.Remove(entity);
// await _context.SaveChangesAsync();
// }
//}
//// ----------------------------
//// Métodos para Impuestos
//// ----------------------------
///// <summary>
///// Obtiene todos los impuestos asociados a un presupuesto dado por su ID.
///// </summary>
//public async Task<IEnumerable<EQuoteTax>> GetTaxesByQuoteIdAsync(int quoteId)
//{
// var taxes = await _context.PhSQuoteTaxes
// .Where(t => t.QuoteheaderId == quoteId)
// .ToListAsync();
// return taxes.Select(EntityMapper.MapEntity<PhSQuoteTaxis, EQuoteTax>);
//}
///// <summary>
///// Agrega un nuevo impuesto al presupuesto correspondiente.
///// </summary>
//public async Task<EQuoteTax> AddTaxAsync(EQuoteTax tax)
//{
// var dbEntity = EntityMapper.MapEntity<EQuoteTax, PhSQuoteTaxis>(tax);
// _context.PhSQuoteTaxes.Add(dbEntity);
// await _context.SaveChangesAsync();
// return EntityMapper.MapEntity<PhSQuoteTaxis, EQuoteTax>(dbEntity);
//}
///// <summary>
///// Actualiza los datos de un impuesto existente en un presupuesto.
///// </summary>
//public async Task UpdateTaxAsync(EQuoteTax tax)
//{
// var dbEntity = EntityMapper.MapEntity<EQuoteTax, PhSQuoteTaxis>(tax);
// _context.PhSQuoteTaxes.Update(dbEntity);
// await _context.SaveChangesAsync();
//}
///// <summary>
///// Elimina un impuesto asociado a un presupuesto a partir de su ID.
///// </summary>
//public async Task DeleteTaxAsync(int taxId)
//{
// var entity = await _context.PhSQuoteTaxes.FindAsync(taxId);
// if (entity != null)
// {
// _context.PhSQuoteTaxes.Remove(entity);
// await _context.SaveChangesAsync();
// }
//}
//#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
///// <summary>
///// Crea un nuevo presupuesto, incluyendo encabezado, detalles, roles, ajustes e impuestos asociados.
///// Genera automáticamente el número de presupuesto en base a la serie indicada.
///// </summary>
///// <param name="quote">Presupuesto a registrar, incluyendo entidades relacionadas.</param>
///// <param name="formSeriesId">Identificador de la serie de numeración a utilizar.</param>
///// <returns>Cadena con el número generado del presupuesto.</returns>
//public async Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId)
//{
// using var transaction = await _context.Database.BeginTransactionAsync();
// try
// {
// // Obtener el próximo número de presupuesto desde SP
// var nextNumber = await _formSeriesRepository.GetNextInternalNumberAsync(formSeriesId);
// quote.Quotenumber = nextNumber.ToString();
// // Map y guardado de Header
// var headerEntity = EntityMapper.MapEntity<EQuoteHeader, PhSQuoteHeader>(quote);
// _context.PhSQuoteHeaders.Add(headerEntity);
// await _context.SaveChangesAsync();
// // Guardado de Detalles
// if (quote.PhSQuoteDetails?.Any() == true)
// {
// foreach (var detail in quote.PhSQuoteDetails)
// {
// detail.QuoteheaderId = headerEntity.Id;
// var dbDetail = EntityMapper.MapEntity<EQuoteDetail, PhSQuoteDetail>(detail);
// _context.PhSQuoteDetails.Add(dbDetail);
// }
// }
// // Guardado de Roles
// if (quote.PhSQuoteRoles?.Any() == true)
// {
// foreach (var role in quote.PhSQuoteRoles)
// {
// role.QuoteheaderId = headerEntity.Id;
// var dbRole = EntityMapper.MapEntity<EQuoteRole, PhSQuoteRole>(role);
// _context.PhSQuoteRoles.Add(dbRole);
// }
// }
// // Guardado de Ajustes
// if (quote.PhSQuoteAdjustments?.Any() == true)
// {
// foreach (var adj in quote.PhSQuoteAdjustments)
// {
// adj.QuoteheaderId = headerEntity.Id;
// var dbAdj = EntityMapper.MapEntity<EQuoteAdjustment, PhSQuoteAdjustment>(adj);
// _context.PhSQuoteAdjustments.Add(dbAdj);
// }
// }
// // Guardado de Impuestos
// if (quote.PhSQuoteTaxes?.Any() == true)
// {
// foreach (var tax in quote.PhSQuoteTaxes)
// {
// tax.QuoteheaderId = headerEntity.Id;
// var dbTax = EntityMapper.MapEntity<EQuoteTax, PhSQuoteTaxis>(tax);
// _context.PhSQuoteTaxes.Add(dbTax);
// }
// }
// await _context.SaveChangesAsync();
// await transaction.CommitAsync();
// return headerEntity.Quotenumber;
// }
// catch
// {
// await transaction.RollbackAsync();
// throw;
// }
//}
//public async Task<IDbContextTransaction> BeginTransactionAsync()
//{
// return await _context.Database.BeginTransactionAsync();
//}
#endregion
} }
} }

View File

@ -1,16 +1,219 @@
using Domain.Entities; using Microsoft.EntityFrameworkCore;
using Models.Helpers; using Core.Dtos;
using Domain.Entities;
using Domain.Generics;
using Models.Interfaces; using Models.Interfaces;
using Models.Helpers;
using Models.Models; using Models.Models;
namespace Models.Repositories namespace Models.Repositories
{ {
public class PhSQuoteRepository(PhronCareOperationsHubContext context, public class PhSQuoteRepository(PhronCareOperationsHubContext context,
IPhSFormSeriesRepository formSeriesRepository) : IPhSQuoteRepository IPhSFormSeriesRepository formSeriesRepository) : IQuoteRepository
{ {
private readonly PhronCareOperationsHubContext _context = context; private readonly PhronCareOperationsHubContext _context = context;
private readonly IPhSFormSeriesRepository _formSeriesRepository = formSeriesRepository; private readonly IPhSFormSeriesRepository _formSeriesRepository = formSeriesRepository;
#region Busqueda usando el QuoteDto
public async Task<PagedResult<QuoteDto>> SearchAsync(
int? customerId,
string? customerText,
string? quoteNumber,
int? professionalId,
string? professionalText,
int? institutionId,
string? institutionText,
int? patientId,
string? patientText,
DateTime? issueDateFrom,
DateTime? issueDateTo,
string? status,
int page = 1,
int pageSize = 50)
{
// 1) Base query with includes
var query = _context.PhSQuoteHeaders
.Include(q => q.PhSQuoteDetails)
.Include(q => q.PhSQuoteRoles)
.Include(q => q.PhSQuoteAdjustments)
.Include(q => q.PhSQuoteTaxes)
.AsQueryable();
// 2) Apply filters
if (customerId.HasValue)
query = query.Where(q => q.CustomerId == customerId.Value);
else if (!string.IsNullOrWhiteSpace(customerText))
query = query.Where(q =>
_context.PhSCustomers.Any(c =>
c.Id == q.CustomerId &&
c.Name.Contains(customerText)));
if (!string.IsNullOrWhiteSpace(quoteNumber))
query = query.Where(q => q.Quotenumber.Contains(quoteNumber));
if (professionalId.HasValue)
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Professional &&
r.EntityId == professionalId.Value));
}
else if (!string.IsNullOrWhiteSpace(professionalText))
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Professional &&
_context.PhSProfessionals.Any(p =>
p.Id == r.EntityId &&
p.Fullname.Contains(professionalText))));
}
if (institutionId.HasValue)
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Institution &&
r.EntityId == institutionId.Value));
}
else if (!string.IsNullOrWhiteSpace(institutionText))
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Institution &&
_context.PhSInstitutions.Any(i =>
i.Id == r.EntityId &&
i.Name.Contains(institutionText))));
}
if (patientId.HasValue)
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Patient &&
r.EntityId == patientId.Value));
}
else if (!string.IsNullOrWhiteSpace(patientText))
{
query = query.Where(q =>
q.PhSQuoteRoles.Any(r =>
r.Entitytype == PhSEntityTypes.Patient &&
(_context.PhSPatients.Any(pt =>
pt.Id == r.EntityId &&
pt.Firstname.Contains(patientText)) ||
_context.PhSPatients.Any(pt =>
pt.Id == r.EntityId &&
pt.Lastname.Contains(patientText)))));
}
if (issueDateFrom.HasValue)
query = query.Where(q => q.Issuedate >= issueDateFrom.Value);
if (issueDateTo.HasValue)
query = query.Where(q => q.Issuedate <= issueDateTo.Value);
if (!string.IsNullOrWhiteSpace(status))
query = query.Where(q => q.Status == status);
// 3) Execute paged query
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
// 4) Project to DTOs
var dtos = pagedEntities.Items.Select(header =>
{
// Precompute tax sums
var totalTaxAmount = header.PhSQuoteTaxes.Sum(t => t.Taxamount);
var netBase = header.Netamount.GetValueOrDefault() != 0m
? header.Netamount.Value
: 1m;
return new QuoteDto
{
Id = header.Id,
Quotenumber = header.Quotenumber,
IssueDate = header.Issuedate,
EstimatedDate = header.Estimateddate,
CustomerName = _context.PhSCustomers
.Where(c => c.Id == header.CustomerId)
.Select(c => c.Name)
.FirstOrDefault() ?? "",
ProfessionalName = header.PhSQuoteRoles
.Where(r => r.Entitytype == PhSEntityTypes.Professional)
.Select(r => _context.PhSProfessionals
.Where(p => p.Id == r.EntityId)
.Select(p => p.Fullname)
.FirstOrDefault())
.FirstOrDefault() ?? "",
InstitutionName = header.PhSQuoteRoles
.Where(r => r.Entitytype == PhSEntityTypes.Institution)
.Select(r => _context.PhSInstitutions
.Where(i => i.Id == r.EntityId)
.Select(i => i.Name)
.FirstOrDefault())
.FirstOrDefault() ?? "",
PatientName = header.PhSQuoteRoles
.Where(r => r.Entitytype == PhSEntityTypes.Patient)
.Select(r => _context.PhSPatients
.Where(pt => pt.Id == r.EntityId)
.Select(pt => (pt.Firstname + " " + pt.Lastname).Trim())
.FirstOrDefault())
.FirstOrDefault() ?? "",
BusinessUnitName = _context.PhSBusinessUnits
.Where(b => b.Id == header.BusinessunitId)
.Select(b => b.Code)
.FirstOrDefault() ?? "",
Currency = header.Currency,
Total = header.Total.GetValueOrDefault(0m),
Status = header.Status.Trim(),
SalespersonName = _context.PhSPeople
.Where(u => u.Id == header.PeopleId)
.Select(u => u.Name)
.FirstOrDefault() ?? "",
Items = header.PhSQuoteDetails.Select(d =>
{
var itemBase = d.Quantity * d.Unitprice;
var itemTax = totalTaxAmount * itemBase / netBase;
return new QuoteItemDto
{
Description = d.ProductDescription,
Quantity = d.Quantity,
UnitPrice = d.Unitprice,
Subtotal = itemBase,
TaxAmount = itemTax,
Total = itemBase + itemTax
};
}).ToList(),
Taxes = header.PhSQuoteTaxes.Select(t => new QuoteTaxDto
{
TaxName = t.Taxname,
TaxCode = t.Taxcode,
TaxableAmount = t.TaxableAmount,
TaxRate = t.Taxrate,
TaxAmount = t.Taxamount,
IsIncludedInPrice = t.IsIncludedInPrice
}).ToList(),
Adjustments = header.PhSQuoteAdjustments.Select(a => new QuoteAdjustmentDto
{
Reason = _context.PhSAdjustmentReasons
.Where(r => r.Code == a.ReasonCode)
.Select(r => r.Description)
.FirstOrDefault() ?? "",
Amount = a.Amount.GetValueOrDefault(0m)
}).ToList()
};
}).ToList();
// 5) Return paged DTO result
return new PagedResult<QuoteDto>
{
Items = dtos,
TotalItems = pagedEntities.TotalItems,
Page = pagedEntities.Page,
PageSize = pagedEntities.PageSize
};
}
#endregion
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos) #region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
/// <summary> /// <summary>
/// Crea un nuevo presupuesto, incluyendo encabezado, detalles, roles, ajustes e impuestos asociados. /// Crea un nuevo presupuesto, incluyendo encabezado, detalles, roles, ajustes e impuestos asociados.

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.2</NuGetToolVersion> <NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</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

@ -1,44 +0,0 @@
using Core.Interfaces;
using Core.Services;
using Microsoft.AspNetCore.Mvc;
using Models.Interfaces;
using Models.Repositories;
namespace phronCare.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DbTestController : ControllerBase
{
private readonly ITicketDom ticketService;
public DbTestController(ITicketRepository ticketRepository)
{
ticketService = new TicketService(ticketRepository);
}
[HttpGet("EDMXTestConnection")]
public IActionResult TestEdmxConnection()
{
try
{
// Intenta realizar una consulta simple para verificar la conexión al EDMX
var firstTicket = ticketService.GetAllAsync().Result.First();
if (firstTicket != null)
{
return Ok("El EDMX está conectado y la consulta fue exitosa.");
}
else
{
return BadRequest("El EDMX está conectado, pero la consulta no devolvió resultados.");
}
}
catch (Exception ex)
{
return StatusCode(500, $"Error al intentar utilizar el EDMX: {ex.Message}");
}
}
}
}

View File

@ -1,7 +1,7 @@
using Domain.Entities; using Core.Interfaces;
using Domain.Entities;
using Domain.Generics; using Domain.Generics;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Models.Interfaces;
using System.Reflection; using System.Reflection;
namespace phronCare.API.Controllers.Sales namespace phronCare.API.Controllers.Sales
@ -73,7 +73,7 @@ namespace phronCare.API.Controllers.Sales
if (person == null) if (person == null)
return BadRequest("La persona no puede ser nula."); return BadRequest("La persona no puede ser nula.");
var result = await _peopleService.CreateAsync(person); var result = await _peopleService.AddAsync(person);
return Ok(result); return Ok(result);
} }
catch (Exception ex) catch (Exception ex)

View File

@ -71,7 +71,7 @@ namespace phronCare.API.Controllers.Sales
if (category == null) if (category == null)
return BadRequest("La categoría de producto no puede ser nula."); return BadRequest("La categoría de producto no puede ser nula.");
var result = await _productCategoryService.CreateAsync(category); var result = await _productCategoryService.AddAsync(category);
return Ok(result); return Ok(result);
} }
catch (ArgumentNullException ex) catch (ArgumentNullException ex)

View File

@ -1,4 +1,5 @@
using Domain.Entities; using Core.Dtos;
using Domain.Entities;
using Domain.Generics; using Domain.Generics;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Models.Interfaces; using Models.Interfaces;
@ -17,29 +18,20 @@ namespace phronCare.API.Controllers.Sales
} }
#region Obtener Presupuestos #region Obtener Presupuestos
/// <summary>
[HttpGet("all")] /// Busca presupuestos con filtros de texto libre o por ID, paginados.
public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 50) /// </summary>
{
try
{
var result = await _quoteService.GetAllQuotesAsync(page, pageSize);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
[HttpGet("search")] [HttpGet("search")]
public async Task<IActionResult> Search( public async Task<ActionResult<PagedResult<QuoteDto>>> Search(
[FromQuery] int? customerId, [FromQuery] int? customerId,
[FromQuery] string? customerText,
[FromQuery] string? quoteNumber, [FromQuery] string? quoteNumber,
[FromQuery] int? professionalId, [FromQuery] int? professionalId,
[FromQuery] string? professionalText,
[FromQuery] int? institutionId, [FromQuery] int? institutionId,
[FromQuery] string? institutionText,
[FromQuery] int? patientId, [FromQuery] int? patientId,
[FromQuery] string? patientText,
[FromQuery] DateTime? issueDateFrom, [FromQuery] DateTime? issueDateFrom,
[FromQuery] DateTime? issueDateTo, [FromQuery] DateTime? issueDateTo,
[FromQuery] string? status, [FromQuery] string? status,
@ -48,12 +40,16 @@ namespace phronCare.API.Controllers.Sales
{ {
try try
{ {
var result = await _quoteService.SearchQuotesAsync( var result = await _quoteService.SearchAsync(
customerId, customerId,
customerText,
quoteNumber, quoteNumber,
professionalId, professionalId,
professionalText,
institutionId, institutionId,
institutionText,
patientId, patientId,
patientText,
issueDateFrom, issueDateFrom,
issueDateTo, issueDateTo,
status, status,
@ -65,87 +61,146 @@ namespace phronCare.API.Controllers.Sales
catch (Exception ex) catch (Exception ex)
{ {
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod"; var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
// Log exception as needed...
return StatusCode(500, $"{methodName} Message: {ex.Message}"); return StatusCode(500, $"{methodName} Message: {ex.Message}");
} }
} }
[HttpGet("{id:int}")]
public async Task<ActionResult<EQuoteHeader>> GetById(int id)
{
try
{
var quote = await _quoteService.GetQuoteByIdAsync(id);
if (quote == null)
return NotFound();
return Ok(quote);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
#endregion #endregion
#region Crear / Actualizar / Eliminar //[HttpGet("all")]
//public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 50)
//{
// try
// {
// var result = await _quoteService.GetAllQuotesAsync(page, pageSize);
// return Ok(result);
// }
// catch (Exception ex)
// {
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
// }
//}
[HttpPut("update")] //[HttpGet("search")]
public async Task<IActionResult> Update([FromBody] EQuoteHeader quote) //public async Task<IActionResult> Search(
{ // [FromQuery] int? customerId,
try // [FromQuery] string? customerText,
{ // [FromQuery] string? quoteNumber,
if (quote == null || quote.Id <= 0) // [FromQuery] int? professionalId,
return BadRequest("El presupuesto es inválido o no tiene un ID válido."); // [FromQuery] string? professionalText,
// [FromQuery] int? institutionId,
// [FromQuery] string? institutionText,
// [FromQuery] int? patientId,
// [FromQuery] string? patientText,
// [FromQuery] DateTime? issueDateFrom,
// [FromQuery] DateTime? issueDateTo,
// [FromQuery] string? status,
// [FromQuery] int page = 1,
// [FromQuery] int pageSize = 50)
//{
// try
// {
// var result = await _quoteService.SearchAsync(
// customerId,
// customerText,
// quoteNumber,
// professionalId,
// professionalText,
// institutionId,
// institutionText,
// patientId,
// patientText,
// issueDateFrom,
// issueDateTo,
// status,
// page,
// pageSize);
await _quoteService.UpdateQuoteAsync(quote); // return Ok(result);
return Ok("Presupuesto actualizado correctamente."); // }
} // catch (Exception ex)
catch (Exception ex) // {
{ // var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod"; // return StatusCode(500, $"{methodName} Message: {ex.Message}");
return StatusCode(500, $"{methodName} Message: {ex.Message}"); // }
} //}
}
[HttpDelete("delete/{id:int}")] //[HttpGet("{id:int}")]
public async Task<IActionResult> Delete(int id) //public async Task<ActionResult<EQuoteHeader>> GetById(int id)
{ //{
try // try
{ // {
await _quoteService.DeleteQuoteAsync(id); // var quote = await _quoteService.GetQuoteByIdAsync(id);
return Ok("Presupuesto eliminado correctamente."); // if (quote == null)
} // return NotFound();
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
#endregion // return Ok(quote);
// }
// catch (Exception ex)
// {
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
// }
//}
//#endregion
//#region Crear / Actualizar / Eliminar
//[HttpPut("update")]
//public async Task<IActionResult> Update([FromBody] EQuoteHeader quote)
//{
// try
// {
// if (quote == null || quote.Id <= 0)
// return BadRequest("El presupuesto es inválido o no tiene un ID válido.");
// await _quoteService.UpdateQuoteAsync(quote);
// return Ok("Presupuesto actualizado correctamente.");
// }
// catch (Exception ex)
// {
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
// }
//}
//[HttpDelete("delete/{id:int}")]
//public async Task<IActionResult> Delete(int id)
//{
// try
// {
// await _quoteService.DeleteQuoteAsync(id);
// return Ok("Presupuesto eliminado correctamente.");
// }
// catch (Exception ex)
// {
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
// }
//}
#region Exportación //#region Exportación
[HttpPost("exportfiltered")] //[HttpPost("exportfiltered")]
public async Task<IActionResult> ExportFiltered([FromBody] QuoteSearchParams searchParams) //public async Task<IActionResult> ExportFiltered([FromBody] QuoteSearchParams searchParams)
{ //{
try // try
{ // {
var file = await _quoteService.ExportFilteredQuotesToExcelAsync(searchParams); // var file = await _quoteService.ExportFilteredQuotesToExcelAsync(searchParams);
return File(file, // return File(file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Presupuestos.xlsx"); // "Presupuestos.xlsx");
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
return BadRequest(ex.Message); // return BadRequest(ex.Message);
} // }
} //}
#endregion //#endregion
#region Endpoint de emision de presupuesto (encabezado + detalles + roles + ajustes + impuestos) #region Endpoint de emision de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
[HttpPost("createfull")] [HttpPost("createfull")]

View File

@ -4,9 +4,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Models.Repositories;
using Models.Interfaces; using Models.Interfaces;
using Models.Models;
using Services.Interfaces; using Services.Interfaces;
using Services.Services; using Services.Services;
using Services.Models; using Services.Models;
@ -15,6 +13,8 @@ using phronCare.API.Models;
using Core.Interfaces; using Core.Interfaces;
using Core.Services; using Core.Services;
using phronCare.API.Models.Security; using phronCare.API.Models.Security;
using Models.Repositories;
using Models.Models;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -222,8 +222,8 @@ static void RepositorysAndServices(WebApplicationBuilder builder)
builder.Services.AddScoped<IPhOhArcataxTypeRepository, PhOhArcataxTypeRepository>(); builder.Services.AddScoped<IPhOhArcataxTypeRepository, PhOhArcataxTypeRepository>();
builder.Services.AddScoped<IQuoteDom, QuoteService>(); builder.Services.AddScoped<IQuoteDom, QuoteService>();
builder.Services.AddScoped<IPhSQuoteHeaderRepository, PhSQuoteHeaderRepository>(); //builder.Services.AddScoped<IPhSQuoteHeaderRepository, PhSQuoteHeaderRepository>();
builder.Services.AddScoped<IPhSQuoteRepository, PhSQuoteRepository>(); builder.Services.AddScoped<IQuoteRepository, PhSQuoteRepository>();
builder.Services.AddScoped<IPhSFormSeriesRepository, PhSFormSeriesRepository>(); builder.Services.AddScoped<IPhSFormSeriesRepository, PhSFormSeriesRepository>();
// Registrar el service de lookup // Registrar el service de lookup
@ -234,7 +234,7 @@ static void RepositorysAndServices(WebApplicationBuilder builder)
builder.Services.AddScoped<IPhOHExchangeRateHistory, PhOHExchangeRateHistory>(); builder.Services.AddScoped<IPhOHExchangeRateHistory, PhOHExchangeRateHistory>();
// Dominio/servicio con HttpClient para BCRA // Dominio/servicio con HttpClient para BCRA
builder.Services.AddHttpClient<IExchangeRateDom, ExchangeRateDom>(client => builder.Services.AddHttpClient<IExchangeRateDom, ExchangeRateRepository>(client =>
{ {
client.BaseAddress = new Uri("https://api.bcra.gob.ar/"); client.BaseAddress = new Uri("https://api.bcra.gob.ar/");
}); });

View File

@ -545,16 +545,6 @@
], ],
"ReturnTypes": [] "ReturnTypes": []
}, },
{
"ContainingType": "phronCare.API.Controllers.DbTestController",
"Method": "TestEdmxConnection",
"RelativePath": "api/DbTest/EDMXTestConnection",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [],
"ReturnTypes": []
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.DocumentTypeController", "ContainingType": "phronCare.API.Controllers.Sales.DocumentTypeController",
"Method": "GetAll", "Method": "GetAll",
@ -1576,53 +1566,6 @@
], ],
"ReturnTypes": [] "ReturnTypes": []
}, },
{
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "GetById",
"RelativePath": "api/Quote/{id}",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "Domain.Entities.EQuoteHeader",
"MediaTypes": [
"text/plain",
"application/json",
"text/json"
],
"StatusCode": 200
}
]
},
{
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "GetAll",
"RelativePath": "api/Quote/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.QuoteController", "ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "CreateFullQuote", "Method": "CreateFullQuote",
@ -1639,38 +1582,6 @@
], ],
"ReturnTypes": [] "ReturnTypes": []
}, },
{
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "Delete",
"RelativePath": "api/Quote/delete/{id}",
"HttpMethod": "DELETE",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
}
],
"ReturnTypes": []
},
{
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "ExportFiltered",
"RelativePath": "api/Quote/exportfiltered",
"HttpMethod": "POST",
"IsController": true,
"Order": 0,
"Parameters": [
{
"Name": "searchParams",
"Type": "Domain.Generics.QuoteSearchParams",
"IsRequired": true
}
],
"ReturnTypes": []
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController", "ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
"Method": "Search", "Method": "Search",
@ -1684,6 +1595,11 @@
"Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"IsRequired": false "IsRequired": false
}, },
{
"Name": "customerText",
"Type": "System.String",
"IsRequired": false
},
{ {
"Name": "quoteNumber", "Name": "quoteNumber",
"Type": "System.String", "Type": "System.String",
@ -1694,16 +1610,31 @@
"Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"IsRequired": false "IsRequired": false
}, },
{
"Name": "professionalText",
"Type": "System.String",
"IsRequired": false
},
{ {
"Name": "institutionId", "Name": "institutionId",
"Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"IsRequired": false "IsRequired": false
}, },
{
"Name": "institutionText",
"Type": "System.String",
"IsRequired": false
},
{ {
"Name": "patientId", "Name": "patientId",
"Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Type": "System.Nullable\u00601[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"IsRequired": false "IsRequired": false
}, },
{
"Name": "patientText",
"Type": "System.String",
"IsRequired": false
},
{ {
"Name": "issueDateFrom", "Name": "issueDateFrom",
"Type": "System.Nullable\u00601[[System.DateTime, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Type": "System.Nullable\u00601[[System.DateTime, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
@ -1730,23 +1661,17 @@
"IsRequired": false "IsRequired": false
} }
], ],
"ReturnTypes": [] "ReturnTypes": [
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController", "Type": "Domain.Generics.PagedResult\u00601[[Core.Dtos.QuoteDto, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"Method": "Update", "MediaTypes": [
"RelativePath": "api/Quote/update", "text/plain",
"HttpMethod": "PUT", "application/json",
"IsController": true, "text/json"
"Order": 0,
"Parameters": [
{
"Name": "quote",
"Type": "Domain.Entities.EQuoteHeader",
"IsRequired": true
}
], ],
"ReturnTypes": [] "StatusCode": 200
}
]
}, },
{ {
"ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController", "ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController",

View File

@ -259,6 +259,9 @@
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj" "projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
}, },
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj"
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj" "projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj"
} }

View File

@ -6506,6 +6506,7 @@
"Microsoft.Extensions.Configuration.Json >= 8.0.1", "Microsoft.Extensions.Configuration.Json >= 8.0.1",
"Microsoft.IdentityModel.Tokens >= 8.9.0", "Microsoft.IdentityModel.Tokens >= 8.9.0",
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets >= 1.21.0", "Microsoft.VisualStudio.Azure.Containers.Tools.Targets >= 1.21.0",
"Models >= 1.0.0",
"Serilog.AspNetCore >= 8.0.3", "Serilog.AspNetCore >= 8.0.3",
"Services >= 1.0.0", "Services >= 1.0.0",
"Swashbuckle.AspNetCore >= 6.6.2", "Swashbuckle.AspNetCore >= 6.6.2",
@ -6551,6 +6552,9 @@
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj" "projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
}, },
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj"
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj" "projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Services\\Services.csproj"
} }

View File

@ -41,6 +41,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" /> <ProjectReference Include="..\Core\Core.csproj" />
<ProjectReference Include="..\Domain\Domain.csproj" /> <ProjectReference Include="..\Domain\Domain.csproj" />
<ProjectReference Include="..\Models\Models.csproj" />
<ProjectReference Include="..\Services\Services.csproj" /> <ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,152 +4,6 @@
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.Test\\phronCare.Test.csproj": {} "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.Test\\phronCare.Test.csproj": {}
}, },
"projects": { "projects": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj",
"projectName": "Domain",
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj",
"packagesPath": "C:\\Users\\maski\\.nuget\\packages\\",
"outputPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\maski\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
}
}
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj",
"projectName": "Models",
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj",
"packagesPath": "C:\\Users\\maski\\.nuget\\packages\\",
"outputPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\maski\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"Microsoft.EntityFrameworkCore.Design": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
"target": "Package",
"version": "[8.0.10, )"
},
"Microsoft.EntityFrameworkCore.SqlServer": {
"target": "Package",
"version": "[8.0.10, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
}
}
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.Test\\phronCare.Test.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.Test\\phronCare.Test.csproj": {
"version": "1.0.0", "version": "1.0.0",
"restore": { "restore": {
@ -177,11 +31,7 @@
"frameworks": { "frameworks": {
"net8.0": { "net8.0": {
"targetAlias": "net8.0", "targetAlias": "net8.0",
"projectReferences": { "projectReferences": {}
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj"
}
}
} }
}, },
"warningProperties": { "warningProperties": {

View File

@ -16,7 +16,6 @@
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)nunit3testadapter\4.5.0\build\netcoreapp3.1\NUnit3TestAdapter.props" Condition="Exists('$(NuGetPackageRoot)nunit3testadapter\4.5.0\build\netcoreapp3.1\NUnit3TestAdapter.props')" /> <Import Project="$(NuGetPackageRoot)nunit3testadapter\4.5.0\build\netcoreapp3.1\NUnit3TestAdapter.props" Condition="Exists('$(NuGetPackageRoot)nunit3testadapter\4.5.0\build\netcoreapp3.1\NUnit3TestAdapter.props')" />
<Import Project="$(NuGetPackageRoot)nunit\3.14.0\build\NUnit.props" Condition="Exists('$(NuGetPackageRoot)nunit\3.14.0\build\NUnit.props')" /> <Import Project="$(NuGetPackageRoot)nunit\3.14.0\build\NUnit.props" Condition="Exists('$(NuGetPackageRoot)nunit\3.14.0\build\NUnit.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props')" />

View File

@ -2,8 +2,6 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)netstandard.library\2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('$(NuGetPackageRoot)netstandard.library\2.0.0\build\netstandard2.0\NETStandard.Library.targets')" /> <Import Project="$(NuGetPackageRoot)netstandard.library\2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('$(NuGetPackageRoot)netstandard.library\2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets')" />
<Import Project="$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets')" /> <Import Project="$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets')" />

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Models\Models.csproj" /> <!--<ProjectReference Include="..\Models\Models.csproj" />-->
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -12,14 +12,14 @@
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject ISalesLookupService SalesLookupService @inject ISalesLookupService SalesLookupService
@inject IExchangeRateService ExchangeRateService @inject IExchangeRateService ExchangeRateService
@inject IQuoteService QuoteService @inject QuoteService QuoteService
@inject IToastService toastService @inject IToastService toastService
@inject IModalService Modal @inject IModalService Modal
<EditForm Model="_quoteModel" > <EditForm Model="_quoteModel" >
<div class="container mt-4" style="zoom:0.8;"> <div class="container mt-4" style="zoom:.8;">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header d-flex justify-content-center align-items-center">
<h3 class="mb-0">Emisión de Presupuesto</h3> <h3 class="mb-0">Emisión de Presupuesto</h3>
</div> </div>
<div class="card-body"> <div class="card-body">

View File

@ -0,0 +1,431 @@
@page "/quotes"
@using Core.Dtos
@using Domain.Generics
@using phronCare.UIBlazor.Services.Sales.Quotes
@inject IToastService toastService
@inject NavigationManager Navigation
@inject QuoteService quoteService
<div class="card" style="zoom:80%">
<div class="card-header d-flex justify-content-center align-items-center">
<h3 class="card-title m-0">Consulta de Presupuestos</h3>
</div>
<!-- BODY -->
<div class="card-body px-4">
<!-- FILTROS -->
<div class="mb-3 row g-2 align-items-end">
<div class="col-sm">
<label for="quotenumber">Presupuesto</label>
<input id="quotenumber" @bind="Filters.QuoteNumber" class="form-control form-control-sm" placeholder="Q-00000001" />
</div>
<div class="col-sm">
<label for="customer">Cliente</label>
<input id="customer" @bind="Filters.CustomerText" class="form-control form-control-sm" placeholder="Nombre o código" />
</div>
<div class="col-sm">
<label for="professional">Médico</label>
<input id="professional" @bind="Filters.ProfessionalText" class="form-control form-control-sm" placeholder="Nombre o código" />
</div>
<div class="col-sm">
<label for="institution">Hospital</label>
<input id="institution" @bind="Filters.InstitutionText" class="form-control form-control-sm" placeholder="Nombre o código" />
</div>
<div class="col-sm">
<label for="patient">Paciente</label>
<input id="patient" @bind="Filters.PatientText" class="form-control form-control-sm" placeholder="Nombre o código" />
</div>
<div class="col-sm">
<label for="status">Estado</label>
<select id="status" @bind="Filters.Status" class="form-select form-select-sm">
<option value="">— Todos —</option>
<option value="Emitido">Emitido</option>
<option value="Aprobado">Aprobado</option>
<option value="Despacho">Despacho</option>
<option value="SinConsumo">Sin Consumo</option>
<option value="Transito">Transito</option>
<option value="Cerrado">Cerrado</option>
</select>
</div>
<div class="col-sm">
<label for="datefrom">Desde</label>
<InputDate id="datefrom" @bind-Value="Filters.IssueDateFrom" class="form-control form-control-sm" />
</div>
<div class="col-sm">
<label for="dateto">Hasta</label>
<InputDate id="dateto" @bind-Value="Filters.IssueDateTo" class="form-control form-control-sm" />
</div>
<div class="col-auto">
<button class="btn btn-primary btn-sm rounded-pill" @onclick="Search">
<i class="fas fa-binoculars me-1"></i> Buscar
</button>
<button class="btn btn-secondary btn-sm rounded-pill ms-1" @onclick="OnClear">
<i class="fas fa-eraser me-1"></i> Limpiar
</button>
<button class="btn btn-success btn-sm rounded-pill" @onclick="Create">
<i class="fas fa-plus me-1"></i> Nuevo
</button>
</div>
</div>
<hr />
<!-- TABLA DE RESULTADOS -->
@if (PagedQuotes?.Items?.Any() == true)
{
<table class="table table-sm table-striped table-hover" style="zoom:0.9;">
<thead>
<tr>
<th>Quotenumber</th>
<th>Emisión</th>
<th>Estimada</th>
<th>Cliente</th>
<th>Médico</th>
<th>Hospital</th>
<th>Paciente</th>
<th>Unidad Negocio</th>
<th>Moneda</th>
<th>Total</th>
<th>Estado</th>
<th>Vendedor</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
@foreach (var quote in PagedQuotes.Items)
{
<tr>
<td>@quote.Quotenumber</td>
<td>@quote.IssueDate.ToString("dd/MM/yyyy")</td>
<td>@(quote.EstimatedDate.HasValue ? quote.EstimatedDate.Value.ToString("dd/MM/yyyy") : "—")</td>
<td>@quote.CustomerName</td>
<td>@quote.ProfessionalName</td>
<td>@quote.InstitutionName</td>
<td>@quote.PatientName</td>
<td>@quote.BusinessUnitName</td>
<td>@quote.Currency</td>
<td>@string.Format("{0:N2}", quote.Total)</td>
<td>
<span class="badge @GetStatusBadge(quote.Status)">@quote.Status</span>
</td>
<td>@quote.SalespersonName</td>
<td>
<button class="btn btn-link btn-lg p-0 text-success ms-2" @onclick="() => ToggleDetail(quote)"><i class="fas fa-eye"></i></button>
<button class="btn btn-link btn-lg p-0 text-primary ms-2" @onclick="() => PrintPdf(quote.Id)"><i class="fas fa-print"></i></button>
</td>
</tr>
}
</tbody>
</table>
@if (SelectedQuote != null)
{
<!-- BACKDROP semitransparente -->
<div class="position-fixed top-0 start-0 w-100 h-100" style="background: rgba(0,0,0,0.4);"></div>
<!-- DRAWER LATERAL -->
<div class="position-fixed top-0 end-0 h-100 bg-white shadow" style="width: 45%; z-index:1050;">
<!-- CABECERA -->
<div class="d-flex justify-content-between align-items-center border-bottom px-3 py-2">
<h5 class="m-0">Detalle Presupuesto @SelectedQuote?.Quotenumber</h5>
<button class="btn-close" @onclick="() => SelectedQuote = null"></button>
</div>
@* <!-- TABS -->
<ul class="nav nav-tabs px-3 mt-2" role="tablist">
<li class="nav-item">
<button class="nav-link @((activeTab == "Datos") ? "active" : "")"
@onclick='() => activeTab = "Datos"'>
Datos
</button>
</li>
<li class="nav-item">
<button class="nav-link @(activeTab == "Items" ? "active" : "")"
@onclick='() => activeTab = "Items"'>
Items
</button>
</li>
</ul> *@
<!-- CONTENIDO -->
<div class="p-3">
<ul class="nav nav-tabs mb-3" role="tablist">
<li class="nav-item">
<button class="nav-link @((activeTab == "Datos") ? "active bg-primary text-white" : "")"
@onclick='() => activeTab = "Datos"'
title="Datos generales">
<i class="fas fa-info-circle me-1"></i> Datos
</button>
</li>
<li class="nav-item">
<button class="nav-link @((activeTab == "Items") ? "active bg-success text-white" : "")"
@onclick='() => activeTab = "Items"'
title="Productos e impuestos">
<i class="fas fa-boxes-stacked me-1"></i> Items
</button>
</li>
</ul>
@if (activeTab == "Datos")
{
<dl class="row">
<dt class="col-5">Cliente:</dt>
<dd class="col-7">@SelectedQuote?.CustomerName</dd>
<dt class="col-5">Médico:</dt>
<dd class="col-7">@SelectedQuote?.ProfessionalName</dd>
<dt class="col-5">Hospital:</dt>
<dd class="col-7">@SelectedQuote?.InstitutionName</dd>
<dt class="col-5">Paciente:</dt>
<dd class="col-7">@SelectedQuote?.PatientName</dd>
<dt class="col-5">Emisión:</dt>
<dd class="col-7">@SelectedQuote?.IssueDate.ToString("dd/MM/yyyy")</dd>
<dt class="col-5">Estimada:</dt>
<dd class="col-7">@SelectedQuote?.EstimatedDate?.ToString("dd/MM/yyyy") ?? "—"</dd>
<dt class="col-5">Unidad Negocio:</dt>
<dd class="col-7">@SelectedQuote?.BusinessUnitName</dd>
<dt class="col-5">Moneda:</dt>
<dd class="col-7">@SelectedQuote?.Currency</dd>
<dt class="col-5">Vendedor:</dt>
<dd class="col-7">@SelectedQuote?.SalespersonName</dd>
<dt class="col-5">Estado:</dt>
<dd class="col-7">
<span class="badge @GetStatusBadge(SelectedQuote?.Status ?? "")">@SelectedQuote?.Status</span>
</dd>
<dt class="col-5">Observaciones:</dt>
<dd class="col-7">SN</dd>
</dl>
}
else if (activeTab == "Items")
{
if (SelectedQuote?.Items == null || !SelectedQuote.Items.Any())
{
<p>No hay productos en este presupuesto.</p>
}
else
{
<h6 class="mt-2"><i class="fas fa-box-open me-1"></i> Productos cotizados</h6>
<table class="table table-sm table-bordered">
<thead class="table-light">
<tr>
<th>Descripción</th>
<th>Cant.</th>
<th>Precio U.</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
@foreach (var item in SelectedQuote.Items)
{
<tr>
<td>@item.Description</td>
<td>@item.Quantity</td>
<td>@string.Format("{0:N2}", item.UnitPrice)</td>
<td>@string.Format("{0:N2}", item.Quantity * item.UnitPrice)</td>
</tr>
}
</tbody>
</table>
}
if (SelectedQuote?.Taxes != null && SelectedQuote.Taxes.Any())
{
<hr class="my-3" />
<h6 class="mt-4"><i class="fas fa-receipt me-1"></i> Impuestos aplicados</h6>
<table class="table table-sm table-bordered">
<thead class="table-light">
<tr>
<th>Impuesto</th>
<th>Código</th>
<th>Porcentaje</th>
<th>Importe</th>
</tr>
</thead>
<tbody>
@foreach (var tax in SelectedQuote.Taxes)
{
<tr>
<td>@tax.TaxName</td>
<td>@tax.TaxCode</td>
<td>@string.Format("{0:N2}%", tax.TaxRate)</td>
<td>@string.Format("{0:N2}", tax.TaxAmount)</td>
</tr>
}
</tbody>
</table>
}
}
</div>
</div>
}
}
else if (IsLoading)
{
<p>Cargando...</p>
}
else
{
<p>No hay resultados.</p>
}
</div>
<!-- FOOTER: PAGINACIÓN -->
<div class="card-footer d-flex justify-content-center align-items-center" style="zoom:80%;">
<div class="d-flex align-items-center gap-3">
<button class="btn btn-secondary rounded-pill" @onclick="PrimeraPagina" disabled="@(Filters.Page == 1)">
<i class="fas fa-angle-double-left me-1"></i> Primera
</button>
<button class="btn btn-secondary rounded-pill" @onclick="AnteriorPagina" disabled="@(!PuedeRetroceder)">
<i class="fas fa-chevron-left me-1"></i> Anterior
</button>
<span class="mx-2">
Página <strong>@Filters.Page</strong> de <strong>@TotalPaginas</strong>
</span>
<button class="btn btn-secondary rounded-pill" @onclick="SiguientePagina" disabled="@(!PuedeAvanzar)">
Siguiente <i class="fas fa-chevron-right ms-1"></i>
</button>
<button class="btn btn-secondary rounded-pill" @onclick="UltimaPagina" disabled="@(Filters.Page == TotalPaginas)">
Última <i class="fas fa-angle-double-right ms-1"></i>
</button>
<div class="d-flex align-items-center ms-3">
<input type="number"
class="form-control form-control-sm rounded"
style="width: 80px;"
min="1"
max="@TotalPaginas"
@bind="PaginaDeseada" />
<button class="btn btn-outline-primary btn-sm ms-2 rounded-pill" @onclick="IrAPagina">
<i class="fas fa-arrow-right-to-bracket me-1"></i> Ir
</button>
</div>
</div>
</div>
</div>
@code {
private QuoteSearchParams Filters = new();
private PagedResult<QuoteDto>? PagedQuotes;
private bool IsLoading;
private int PaginaDeseada = 1;
private QuoteDto? SelectedQuote { get; set; }
// private List<QuoteItemDto>? SelectedQuoteItems => SelectedQuote?.Items;
// private List<QuoteTaxDto>? SelectedQuoteTaxes => SelectedQuote?.Taxes;
private string activeTab = "Datos";
// protected override async Task OnInitializedAsync()
// {
// await Search();
// }
private async Task Search()
{
try
{
IsLoading = true;
PagedQuotes = await quoteService.SearchAsync(
Filters.CustomerId, Filters.CustomerText,
Filters.QuoteNumber,
Filters.ProfessionalId, Filters.ProfessionalText,
Filters.InstitutionId, Filters.InstitutionText,
Filters.PatientId, Filters.PatientText, Filters.Status,
Filters.IssueDateFrom, Filters.IssueDateTo,
Filters.Page, Filters.PageSize);
PaginaDeseada = Filters.Page;
}
catch (Exception ex)
{
toastService.ShowError(ex.Message);
}
finally
{
IsLoading = false;
}
}
private void ToggleDetail(QuoteDto quote)
{
if (SelectedQuote?.Id == quote.Id)
SelectedQuote = null;
else
{
SelectedQuote = quote;
activeTab = "Datos";
}
}
private async Task PrimeraPagina() { Filters.Page = 1; await Search(); }
private async Task UltimaPagina() { Filters.Page = TotalPaginas; await Search(); }
private async Task SiguientePagina() => await CambiarPagina(1);
private async Task AnteriorPagina() => await CambiarPagina(-1);
private async Task CambiarPagina(int delta)
{
var nuevaPagina = Filters.Page + delta;
if (nuevaPagina >= 1 && nuevaPagina <= TotalPaginas)
{
Filters.Page = nuevaPagina;
await Search();
}
}
private async Task IrAPagina()
{
if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas)
{
Filters.Page = PaginaDeseada;
await Search();
}
else
{
toastService.ShowWarning("Número de página fuera de rango.");
}
}
private void Create()
{
Navigation.NavigateTo("/quote/create/");
}
private void OnClear()
{
Filters = new QuoteSearchParams();
PagedQuotes = null;
PaginaDeseada = 1;
}
private bool PuedeRetroceder => PagedQuotes != null && Filters.Page > 1;
private bool PuedeAvanzar => PagedQuotes != null && Filters.Page < TotalPaginas;
private int TotalPaginas => PagedQuotes is null ? 1 :
(int)Math.Ceiling((double)(PagedQuotes.TotalItems) / Filters.PageSize);
private string GetStatusBadge(string status) => status switch
{
"Emitido" => "bg-primary text-white",
"Aprobado" => "bg-success",
"Despacho" => "bg-info text-white",
"SinConsumo" => "bg-warning text-dark",
"Transito" => "bg-secondary text-white",
"Cerrado" => "bg-dark text-white",
_ => "bg-light text-dark"
};
private void PrintPdf(int quoteId)
{
// lógica de impresión...
}
public class QuoteSearchParams : PagedRequest
{
public int? CustomerId { get; set; }
public string? CustomerText { get; set; }
public string? QuoteNumber { get; set; }
public int? ProfessionalId { get; set; }
public string? ProfessionalText { get; set; }
public int? InstitutionId { get; set; }
public string? InstitutionText { get; set; }
public int? PatientId { get; set; }
public string? PatientText { get; set; }
public DateTime? IssueDateFrom { get; set; }
public DateTime? IssueDateTo { get; set; }
public string? Status { get; set; }
}
}

View File

@ -48,9 +48,9 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
builder.Services.AddScoped<ISalesLookupService, SalesLookupService>(); builder.Services.AddScoped<ISalesLookupService, SalesLookupService>();
builder.Services.AddScoped<IExchangeRateService, ExchangeRateService>(); builder.Services.AddScoped<IExchangeRateService, ExchangeRateService>();
builder.Services.AddScoped<IQuoteService,QuoteService>();
builder.Services.AddScoped<ExchangeRateService>();
builder.Services.AddScoped<ExchangeRateService>();
builder.Services.AddScoped<QuoteService>();
builder.Services.AddScoped<TicketsService>(); builder.Services.AddScoped<TicketsService>();
builder.Services.AddScoped<CustomerService>(); builder.Services.AddScoped<CustomerService>();
builder.Services.AddScoped<TaxConditionService>(); builder.Services.AddScoped<TaxConditionService>();

View File

@ -1,6 +1,7 @@
using Domain.Entities; using Domain.Entities;
using phronCare.UIBlazor.Services.Sales.Quotes;
namespace phronCare.UIBlazor.Services.Sales.Quotes namespace Services.Sales.Quotes
{ {
public interface IQuoteService public interface IQuoteService
{ {

View File

@ -1,12 +1,13 @@
using Domain.Entities; using Core.Dtos;
using Domain.Entities;
using Domain.Generics;
using System.Net.Http.Json; using System.Net.Http.Json;
namespace phronCare.UIBlazor.Services.Sales.Quotes namespace phronCare.UIBlazor.Services.Sales.Quotes
{ {
public class QuoteService : IQuoteService public class QuoteService
{ {
private readonly HttpClient _http; private readonly HttpClient _http;
public QuoteService(HttpClient http) public QuoteService(HttpClient http)
{ {
_http = http; _http = http;
@ -18,22 +19,16 @@ namespace phronCare.UIBlazor.Services.Sales.Quotes
/// </summary> /// </summary>
public async Task<CreateQuoteResult> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId) public async Task<CreateQuoteResult> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId)
{ {
// 1) Creamos el DTO request tal cual lo espera el controller
var request = new CreateFullQuoteRequest var request = new CreateFullQuoteRequest
{ {
Quote = quote, Quote = quote,
FormSeriesId = formSeriesId FormSeriesId = formSeriesId
}; };
// 2) Enviamos ese DTO al endpoint
var response = await _http.PostAsJsonAsync("/api/quote/createfull", request); var response = await _http.PostAsJsonAsync("/api/quote/createfull", request);
//var url = $"/api/quote/createfull?formSeriesId={formSeriesId}";
//var response = await _http.PostAsJsonAsync(url, quote);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
// Leer mensaje de error del servidor
var serverMessage = await response.Content.ReadAsStringAsync(); var serverMessage = await response.Content.ReadAsStringAsync();
return new CreateQuoteResult return new CreateQuoteResult
{ {
@ -42,21 +37,73 @@ namespace phronCare.UIBlazor.Services.Sales.Quotes
}; };
} }
// Deserializar el resultado esperado
var result = await response.Content.ReadFromJsonAsync<CreateQuoteResult>(); var result = await response.Content.ReadFromJsonAsync<CreateQuoteResult>();
return result!; return result!;
} }
/// <summary>
/// Busca presupuestos con filtros y paginación.
/// </summary>
public async Task<PagedResult<QuoteDto>> SearchAsync(
int? customerId = null,
string? customerText = null,
string? quoteNumber = null,
int? professionalId = null,
string? professionalText = null,
int? institutionId = null,
string? institutionText = null,
int? patientId = null,
string? patientText = null,
string? status = null,
DateTime? issueDateFrom = null,
DateTime? issueDateTo = null,
int page = 1,
int pageSize = 10)
{
// Construir manualmente la query string
var queryParams = new List<string>();
void AddParam(string key, string? value)
{
if (!string.IsNullOrWhiteSpace(value))
queryParams.Add($"{key}={Uri.EscapeDataString(value!)}");
} }
AddParam("customerId", customerId?.ToString());
AddParam("customerText", customerText);
AddParam("quoteNumber", quoteNumber);
AddParam("professionalId", professionalId?.ToString());
AddParam("professionalText", professionalText);
AddParam("institutionId", institutionId?.ToString());
AddParam("institutionText", institutionText);
AddParam("patientId", patientId?.ToString());
AddParam("patientText", patientText);
AddParam("status", status);
AddParam("issueDateFrom", issueDateFrom?.ToString("o"));
AddParam("issueDateTo", issueDateTo?.ToString("o"));
AddParam("page", page.ToString());
AddParam("pageSize", pageSize.ToString());
var url = "/api/quote/search";
if (queryParams.Any())
url += "?" + string.Join("&", queryParams);
// Llamada al endpoint
var result = await _http.GetFromJsonAsync<PagedResult<QuoteDto>>(url);
return result!;
}
}
public class CreateQuoteResult public class CreateQuoteResult
{ {
public bool Success { get; set; } public bool Success { get; set; }
public string QuoteNumber { get; set; } = string.Empty; public string QuoteNumber { get; set; } = string.Empty;
public string ErrorMessage { get; set; } = string.Empty; public string ErrorMessage { get; set; } = string.Empty;
} }
public class CreateFullQuoteRequest public class CreateFullQuoteRequest
{ {
public EQuoteHeader Quote { get; set; } = default!; public EQuoteHeader Quote { get; set; } = default!;
public int FormSeriesId { get; set; } public int FormSeriesId { get; set; }
} }
} }

View File

@ -97,7 +97,7 @@
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-1"> <div class="nav-item px-1">
<NavLink class="nav-link" href="quote/create"> <NavLink class="nav-link" href="quotes">
<li aria-hidden="true"></li> Presupuesto <li aria-hidden="true"></li> Presupuesto
</NavLink> </NavLink>
</div> </div>

View File

@ -4,81 +4,6 @@
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.UIBlazor\\phronCare.UIBlazor.csproj": {} "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.UIBlazor\\phronCare.UIBlazor.csproj": {}
}, },
"projects": { "projects": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\Core.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\Core.csproj",
"projectName": "Core",
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\Core.csproj",
"packagesPath": "C:\\Users\\maski\\.nuget\\packages\\",
"outputPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\maski\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj"
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
}
}
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"version": "1.0.0", "version": "1.0.0",
"restore": { "restore": {
@ -144,87 +69,6 @@
} }
} }
}, },
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj",
"projectName": "Models",
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\Models.csproj",
"packagesPath": "C:\\Users\\maski\\.nuget\\packages\\",
"outputPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Models\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\maski\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"Microsoft.EntityFrameworkCore.Design": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
"target": "Package",
"version": "[8.0.10, )"
},
"Microsoft.EntityFrameworkCore.SqlServer": {
"target": "Package",
"version": "[8.0.10, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
}
}
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.UIBlazor\\phronCare.UIBlazor.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\phronCare.UIBlazor\\phronCare.UIBlazor.csproj": {
"version": "1.0.0", "version": "1.0.0",
"restore": { "restore": {
@ -253,9 +97,6 @@
"net8.0": { "net8.0": {
"targetAlias": "net8.0", "targetAlias": "net8.0",
"projectReferences": { "projectReferences": {
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\Core.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Core\\Core.csproj"
},
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": { "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj": {
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj" "projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Domain\\Domain.csproj"
}, },

View File

@ -14,7 +14,6 @@
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" /> <SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
</ItemGroup> </ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.illink.tasks\8.0.14\build\Microsoft.NET.ILLink.Tasks.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.illink.tasks\8.0.14\build\Microsoft.NET.ILLink.Tasks.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.net.illink.tasks\8.0.14\build\Microsoft.NET.ILLink.Tasks.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.illink.tasks\8.0.14\build\Microsoft.NET.ILLink.Tasks.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly\8.0.6\build\net8.0\Microsoft.AspNetCore.Components.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly\8.0.6\build\net8.0\Microsoft.AspNetCore.Components.WebAssembly.props')" /> <Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly\8.0.6\build\net8.0\Microsoft.AspNetCore.Components.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly\8.0.6\build\net8.0\Microsoft.AspNetCore.Components.WebAssembly.props')" />

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' "> <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets')" /> <Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets')" />

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" /> <!--<ProjectReference Include="..\Core\Core.csproj" />-->
<ProjectReference Include="..\Domain\Domain.csproj" /> <ProjectReference Include="..\Domain\Domain.csproj" />
<ProjectReference Include="..\Transversal\Transversal.csproj" /> <ProjectReference Include="..\Transversal\Transversal.csproj" />
</ItemGroup> </ItemGroup>