General Refactor 1
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m30s

This commit is contained in:
Leandro Hernan Rojas 2025-05-08 15:46:04 -03:00
parent 001ba4146a
commit 605447e18a
16 changed files with 217 additions and 288 deletions

View File

@ -6,8 +6,10 @@ using Models.Interfaces;
using System.Reflection;
using Transversal.Services;
public class PatientService : IPatientDom
namespace Core.Services
{
public class PatientService : IPatientDom
{
#region Declaraciones y Constructor
private readonly IPhSPatientRepository _repository;
public PatientService(IPhSPatientRepository patientRepository)
@ -124,4 +126,5 @@ public class PatientService : IPatientDom
}
}
#endregion
}
}

View File

@ -5,7 +5,7 @@ using Models.Interfaces;
using System.Reflection;
using Transversal.Services;
namespace PhronCare.Core.Services.Sales
namespace Core.Services
{
public class QuoteService(
IPhSQuoteHeaderRepository quoteHeaderRepository,

View File

@ -2,7 +2,7 @@
using Models.Interfaces;
using Models.Models;
namespace PhronCare.Core.Data.Repositories.Sales
namespace Models.Repositories
{
public class PhSFormSeriesRepository(PhronCareOperationsHubContext context) : IPhSFormSeriesRepository
{

View File

@ -6,7 +6,7 @@ using Models.Helpers;
using Models.Interfaces;
using Models.Models;
namespace Infrastructure.Repositories.Patients
namespace Models.Repositories
{
public class PhSPatientRepository(PhronCareOperationsHubContext context, ILogger<PhSPatientRepository> logger) : IPhSPatientRepository
{

View File

@ -6,7 +6,7 @@ using Models.Helpers;
using Models.Interfaces;
using Models.Models;
namespace PhronCare.Core.Data.Repositories.Sales
namespace Models.Repositories
{
public class PhSPeopleRepository(PhronCareOperationsHubContext context) : IPhSPeopleRepository
{

View File

@ -5,7 +5,7 @@ using Models.Helpers;
using Models.Interfaces;
using Models.Models;
namespace PhronCare.Core.Data.Repositories.Sales
namespace Models.Repositories
{
public class PhSQuoteDetailRepository(PhronCareOperationsHubContext context) : IPhSQuoteDetailRepository
{

View File

@ -5,7 +5,7 @@ using Models.Models;
using Domain.Entities;
using Domain.Generics;
namespace PhronCare.Core.Data.Repositories.Sales
namespace Models.Repositories
{
public class PhSQuoteHeaderRepository(PhronCareOperationsHubContext context) : IPhSQuoteHeaderRepository
{

View File

@ -5,7 +5,7 @@ using Models.Helpers;
using Models.Interfaces;
using Models.Models;
namespace PhronCare.Core.Data.Repositories.Sales
namespace Models.Repositories
{
public class PhSQuoteRoleRepository(PhronCareOperationsHubContext context) : IPhSQuoteRoleRepository
{

View File

@ -11,14 +11,10 @@ using Services.Interfaces;
using Services.Services;
using Services.Models;
using System.Text;
using Infrastructure.Repositories.Patients;
using PhronCare.Core.Data.Repositories.Sales;
using PhronCare.Core.Services.Sales;
using phronCare.API.Models.Security;
using phronCare.API.Models;
using Core.Interfaces;
using Core.Services;
using System.Net.Http.Headers;
using phronCare.API.Models.Security;
var builder = WebApplication.CreateBuilder(args);
@ -37,7 +33,6 @@ builder.Services.AddDbContext<PhronCareOperationsHubContext>(options =>
#region Repositorios y Servicios
RepositorysAndServices(builder);
#endregion
#region Require Confirmed Email
@ -55,16 +50,7 @@ builder.Services.Configure<DataProtectionTokenProviderOptions>(opts =>
builder.Services.AddSingleton<TwoFactorAuthenticator>();
#endregion
//#region Security Identity EF Configuration
//builder.Services.AddIdentity<IdentityUser, IdentityRole>()
// .AddEntityFrameworkStores<phronCareDbContext>()
// .AddDefaultTokenProviders();
//builder.Services.Configure<DataProtectionTokenProviderOptions>( opts => opts.TokenLifespan=TimeSpan.FromHours(10));
//builder.Services.AddSingleton<TwoFactorAuthenticator>();
//#endregion
#region Authentication Service
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@ -142,16 +128,8 @@ builder.Services.AddSwaggerGen(option =>
#endregion
#region CORS sin cambios
// builder.Services.AddCors(p => p.AddPolicy("CORS", builder =>
// {
// builder
// .AllowAnyOrigin()
// .AllowAnyMethod()
// .AllowAnyHeader();
// }));
builder.Services.AddCors(options =>
{
options.AddPolicy("CORS", policy =>
{
/*
@ -182,8 +160,8 @@ var app = builder.Build();
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI();
app.UseSwagger();
app.UseSwaggerUI();
//}
app.UseCors("CORS");
@ -246,20 +224,18 @@ static void RepositorysAndServices(WebApplicationBuilder builder)
builder.Services.AddScoped<IPhSQuoteHeaderRepository, PhSQuoteHeaderRepository>();
builder.Services.AddScoped<IPhSQuoteRepository, PhSQuoteRepository>();
//builder.Services.AddScoped<IPhSQuoteRoleRepository, PhSQuoteRoleRepository>();
builder.Services.AddScoped<IPhSFormSeriesRepository, PhSFormSeriesRepository>();
// Registrar el service de lookup
builder.Services.AddScoped<ILookUpDom, LookupService>();
builder.Services.AddScoped<IPhSLookUpRepository, PhSLookUpRepository>();
// 2) Repositorio de histórico de cotizaciones
// Repositorio de histórico de cotizaciones
builder.Services.AddScoped<IPhOHExchangeRateHistory, PhOHExchangeRateHistory>();
// 3) Dominio/servicio con HttpClient para BCRA
// Dominio/servicio con HttpClient para BCRA
builder.Services.AddHttpClient<IExchangeRateDom, ExchangeRateDom>(client =>
{
client.BaseAddress = new Uri("https://api.bcra.gob.ar/");
});

View File

@ -1,5 +1,5 @@
@page "/sales/patients"
@using phronCare.UIBlazor.Services.Sales
@using Services.Sales
@using Domain.Entities
@using Domain.Generics
@using Domain.SearchParams

View File

@ -2,19 +2,19 @@
@using System.Globalization;
@using System.Net.Http.Json
@using Blazored.Typeahead
@using Pages.Sales.Modals
@using Services.Lookups
@using phronCare.UIBlazor.Pages.Sales.Modals
@using phronCare.UIBlazor.Services.Integrations
@using phronCare.UIBlazor.Services.Sales.Quotes
@using Services.Integrations
@using Services.Sales.Quotes
@using Blazored.Toast.Services
@using Blazored.Toast.Configuration
@inject ISalesLookupService SalesLookupService
@inject IQuoteService QuoteService
@inject IToastService toastService
@inject NavigationManager Navigation
@inject IModalService Modal
@inject ISalesLookupService SalesLookupService
@inject IExchangeRateService ExchangeRateService
@inject IQuoteService QuoteService
@inject IToastService toastService
@inject IModalService Modal
<EditForm Model="_quoteModel" >
<div class="container mt-4" style="zoom:0.8;">
@ -147,7 +147,6 @@
<InputText class="form-control" @bind-Value="_quoteModel.Observations" />
</div>
</div>
<!-- Productos Cotizados -->
<hr />
<div class="d-flex justify-content-between align-items-center mb-2">
@ -199,7 +198,6 @@
<td>
<button class="btn btn-sm btn-danger" @onclick="() => RemoveDetail(item)">🗑</button>
</td>
</tr>
}
}
@ -212,9 +210,8 @@
</tbody>
</table>
</div>
<!-- Totales + Ajustes -->
<div class="row justify-content-end mt-3">
<div class="row justify-content-end mt-3" >
<div class="col-md-4">
<label class="form-label d-flex justify-content-between align-items-center">
Ajustes comerciales
@ -240,8 +237,6 @@
{
<p class="text-muted">Sin ajustes.</p>
}
</div>
<!-- Impuestos -->
<div class="col-md-4">
@ -304,7 +299,6 @@
</ul>
</div>
</div>
</div>
<div class="card-footer text-end">
<button type="button" class="btn btn-primary" @onclick="HandleValidSubmit">Guardar</button>
@ -316,22 +310,12 @@
@code {
private EQuoteHeader _quoteModel = new();
private ELookUpItem? _selectedCustomer;
private ELookUpItem? _selectedProfessional;
private ELookUpItem? _selectedInstitution;
private ELookUpItem? _selectedPatient;
private ELookUpItem? _selectedPerson;
private ELookUpItem? _selectedCustomer, _selectedProfessional, _selectedInstitution, _selectedPatient, _selectedPerson;
private List<ELookUpItem> _businessUnits = new();
private decimal _netAmount = 0;
private decimal _taxAmount = 0;
private decimal _grandTotal = 0;
private EExchangeRateHistory? YesterdayRate;
private Task OnValueChanged<T>(EQuoteDetail item, T value, Action<EQuoteDetail, T> setter)
{
setter(item, value);
RecalculateTotals();
return Task.CompletedTask;
}
private decimal _netAmount = 0, _taxAmount = 0, _grandTotal = 0;
public const int QuoteSeriesId = 1; // Serie de comprobante para presupuestos (talonario Q).
protected override async Task OnInitializedAsync()
{
@ -392,35 +376,6 @@
// _quoteModel.ProfessionalId = nuevo.Id;
}
}
private Task OnCustomerSelected(ELookUpItem item)
=> SetLookupSelection(item, sel => _selectedCustomer = sel, id => _quoteModel.CustomerId = id);
private Task OnPersonSelected(ELookUpItem item)
=> SetLookupSelection(item, sel => _selectedPerson = sel, id => _quoteModel.PeopleId = id);
// private Task OnProfessionalSelected(ELookUpItem item)
// => SetLookupSelection(item, sel => _selectedProfessional = sel);
// private Task OnInstitutionSelected(ELookUpItem item)
// => SetLookupSelection(item, sel => _selectedInstitution = sel);
// private Task OnPatientSelected(ELookUpItem item)
// => SetLookupSelection(item, sel => _selectedPatient = sel);
private Task SetLookupSelection(ELookUpItem? item, Action<ELookUpItem?> setSelected, Action<int>? setModelId = null)
{
setSelected(item);
if (item != null && setModelId != null) setModelId(item.Id);
return Task.CompletedTask;
}
private void OnDetailChanged(EQuoteDetail item) { }
private void RemoveDetail(EQuoteDetail item)
=> _quoteModel.PhSQuoteDetails.Remove(item);
private void RecalculateTotals()
{
_netAmount = _quoteModel.PhSQuoteDetails.Sum(d => d.Quantity * d.Unitprice);
_taxAmount = _quoteModel.PhSQuoteTaxes.Sum(t => t.Taxamount);
_grandTotal = _netAmount + _taxAmount;
_quoteModel.Netamount = _netAmount;
_quoteModel.Total = _grandTotal;
}
private async Task OpenAdjustmentModal()
{
var modal = Modal.Show<QuoteAdjustmentQuickAddModal>("Agregar Ajuste", new ModalOptions { HideHeader = true });
@ -435,23 +390,28 @@
});
}
}
private void RemoveAdjustment(EQuoteAdjustment adj)
private async Task HandleValidSubmit()
{
_quoteModel.PhSQuoteAdjustments.Remove(adj);
var result = await QuoteService.CreateFullQuoteAsync(_quoteModel, QuoteSeriesId);
if (!result.Success)
{
toastService.ShowError(result.ErrorMessage);
return;
}
ToastParameters _parameters = new ToastParameters();
_parameters.Add(nameof(PhLinkToast.Comprobante), result.QuoteNumber);
_parameters.Add(nameof(PhLinkToast.Style), "success");
toastService.ShowToast<PhLinkToast>(_parameters);
}
private async Task AddNewTax()
{
var parameters = new ModalParameters();
parameters.Add(nameof(QuoteTaxQuickAddModal.NetAmount), _netAmount);
var options = new ModalOptions
{
HideHeader = true,
Size = ModalSize.Small
};
var modal = Modal.Show<QuoteTaxQuickAddModal>("", parameters, options);
var result = await modal.Result;
@ -461,49 +421,61 @@
RecalculateTotals();
}
}
private Task OnCustomerSelected(ELookUpItem item)
=> SetLookupSelection(item, sel => _selectedCustomer = sel, id => _quoteModel.CustomerId = id);
private Task OnPersonSelected(ELookUpItem item)
=> SetLookupSelection(item, sel => _selectedPerson = sel, id => _quoteModel.PeopleId = id);
private Task OnProfessionalSelected(ELookUpItem item)
{
_selectedProfessional = item;
AddOrUpdateRole("PhS_Professionals", item.Id, "Medico");
return Task.CompletedTask;
}
private Task OnInstitutionSelected(ELookUpItem item)
{
_selectedInstitution = item;
AddOrUpdateRole("PhS_Institutions", item.Id, "Hospital");
return Task.CompletedTask;
}
private Task OnPatientSelected(ELookUpItem item)
{
_selectedPatient = item;
AddOrUpdateRole("PhS_Patients", item.Id, "Paciente");
return Task.CompletedTask;
}
private Task OnValueChanged<T>(EQuoteDetail item, T value, Action<EQuoteDetail, T> setter)
{
setter(item, value);
RecalculateTotals();
return Task.CompletedTask;
}
private Task SetLookupSelection(ELookUpItem? item, Action<ELookUpItem?> setSelected, Action<int>? setModelId = null)
{
setSelected(item);
if (item != null && setModelId != null) setModelId(item.Id);
return Task.CompletedTask;
}
private void OnDetailChanged(EQuoteDetail item) { }
private void RemoveDetail(EQuoteDetail item)
=> _quoteModel.PhSQuoteDetails.Remove(item);
private void RemoveAdjustment(EQuoteAdjustment adj)
{
_quoteModel.PhSQuoteAdjustments.Remove(adj);
}
private void RemoveTax(EQuoteTax tax)
{
_quoteModel.PhSQuoteTaxes.Remove(tax);
RecalculateTotals();
}
private async Task Cancel()
private void RecalculateTotals()
{
// 2) Añades los parámetros que luego el componente tomará
// settings.Parameters.Add(nameof(CustomActionToast.Url), url);
ToastParameters _toastParameters;
_toastParameters = new ToastParameters();
_toastParameters.Add(nameof(PhLinkToast.Comprobante), "FAC A0001-00000009");
_toastParameters.Add(nameof(PhLinkToast.Style), "purple");
toastService.ShowToast<PhLinkToast>(_toastParameters);
_netAmount = _quoteModel.PhSQuoteDetails.Sum(d => d.Quantity * d.Unitprice);
_taxAmount = _quoteModel.PhSQuoteTaxes.Sum(t => t.Taxamount);
_grandTotal = _netAmount + _taxAmount;
_quoteModel.Netamount = _netAmount;
_quoteModel.Total = _grandTotal;
}
private async Task HandleValidSubmit()
{
// Si necesitas validar algo extra antes de llamar al servicio, hazlo aquí
int selectedSeriesId = 1/* obtenlo de donde corresponda, p.ej. de un dropdown */;
var result = await QuoteService.CreateFullQuoteAsync(_quoteModel, selectedSeriesId);
if (!result.Success)
{
toastService.ShowError(result.ErrorMessage);
return;
}
ToastParameters _toastParameters;
_toastParameters = new ToastParameters();
_toastParameters.Add(nameof(PhLinkToast.Comprobante), result.QuoteNumber);
_toastParameters.Add(nameof(PhLinkToast.Style), "success");
toastService.ShowToast<PhLinkToast>(_toastParameters);
}
/// <summary>
/// Agrega o actualiza un rol dentro de _quoteModel.PhSQuoteRoles
/// </summary>
private void AddOrUpdateRole(string entityType, int entityId, string roleName)
{
var existing = _quoteModel.PhSQuoteRoles
@ -517,32 +489,18 @@
{
_quoteModel.PhSQuoteRoles.Add(new EQuoteRole
{
// QuoteheaderId lo llenará EF en el servidor
Entitytype = entityType,
EntityId = entityId,
Role = roleName
});
}
}
private Task OnProfessionalSelected(ELookUpItem item)
private void Cancel()
{
_selectedProfessional = item;
AddOrUpdateRole("PhS_Professionals", item.Id, "Medico");
return Task.CompletedTask;
}
ToastParameters _parameters = new ToastParameters();
_parameters.Add(nameof(PhLinkToast.Comprobante), "Q-00000009");
_parameters.Add(nameof(PhLinkToast.Style), "lime");
private Task OnInstitutionSelected(ELookUpItem item)
{
_selectedInstitution = item;
AddOrUpdateRole("PhS_Institutions", item.Id, "Hospital");
return Task.CompletedTask;
toastService.ShowToast<PhLinkToast>(_parameters);
}
private Task OnPatientSelected(ELookUpItem item)
{
_selectedPatient = item;
AddOrUpdateRole("PhS_Patients", item.Id, "Paciente");
return Task.CompletedTask;
}
}

View File

@ -4,14 +4,14 @@ using phronCare.UIBlazor.Services.Sales;
using phronCare.UIBlazor.Services.Lookups;
using phronCare.UIBlazor.Services.Tickets;
using phronCare.UIBlazor.Services.Authorization;
using phronCare.UIBlazor.Services.Sales.Quotes;
using phronCare.UIBlazor.Services.Integrations;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Blazored.Modal;
using Blazored.Toast;
using phronCare.UIBlazor.Services.Sales.Quotes;
using phronCare.UIBlazor.Services.Integrations;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
@ -26,14 +26,6 @@ builder.Services.AddAuthorizationCore();
#endregion
#region Load Configuration
//var apiBaseUrl = Environment.GetEnvironmentVariable("API_BASE_URL")
// ?? builder.Configuration.GetSection("BaseAd").Value;
//if (!string.IsNullOrEmpty(apiBaseUrl) && Uri.TryCreate(apiBaseUrl, UriKind.Absolute, out var validUri))
//{
// builder.Services.AddScoped(sp => new HttpClient { BaseAddress = validUri });
//}
//Console.WriteLine($" valor apiBaseUrl: {apiBaseUrl}");
var config = builder.Configuration.GetSection("BaseAd").Value;
if (config != null)
{
@ -63,7 +55,6 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
builder.Services.AddScoped<CustomerService>();
builder.Services.AddScoped<TaxConditionService>();
builder.Services.AddScoped<AccountTypeService>();
builder.Services.AddScoped<PatientService>();
builder.Services.AddScoped<DocumentTypeService>();
builder.Services.AddScoped<InstitutionService>();
builder.Services.AddScoped<ProductService>();
@ -72,5 +63,5 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
builder.Services.AddScoped<PeopleService>();
builder.Services.AddScoped<ProfessionalSpecialtyService>();
builder.Services.AddScoped<ProductCategoryService>();
builder.Services.AddScoped<PatientService>();
}

View File

@ -1,11 +1,12 @@
using Domain.Entities;
using Domain.Generics;
using Domain.SearchParams;
using Microsoft.JSInterop;
using System.Net.Http.Json;
using System.Reflection;
using System.Text.Json;
using System.Text;
using Microsoft.JSInterop;
using System.Reflection;
namespace phronCare.UIBlazor.Services.Sales
{

View File

@ -1,7 +1,7 @@
using System.Net.Http.Json;
using Domain.Entities;
namespace phronCare.UIBlazor.Services.People
namespace phronCare.UIBlazor.Services.Sales
{
public class PeopleGroupService
{

View File

@ -1,8 +1,8 @@
@using Microsoft.AspNetCore.Components
@inject NavigationManager Navigation
<div class="toast-body text-white p-3 rounded shadow-lg"
style="background-color:@GetBackgroundColor();">
<div class="toast-body text-white p-3 rounded shadow-sm"
style="background-color:@GetBackgroundColor(); border:2px solid white;">
<div class="d-flex justify-content-between align-items-center">
<i class="fas fa-link fa-sm me-2"></i>
<span class="fw-bold small me-3">Documento</span>