Add OfferDays, Payment Condition
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 3m27s

This commit is contained in:
Leandro Hernan Rojas 2025-05-23 12:27:56 -03:00
parent dad339408a
commit a0c9fb2a4c
17 changed files with 259 additions and 52 deletions

View File

@ -11,6 +11,6 @@ namespace Core.Interfaces
Task<IEnumerable<ELookUpItem>> PeopleListAsync(string filter, int limit = 10); Task<IEnumerable<ELookUpItem>> PeopleListAsync(string filter, int limit = 10);
Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10); Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10);
Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10); Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10);
Task<IEnumerable<ELookUpItem>> PaymentTermsListAsync(string filter, int limit = 10);
} }
} }

View File

@ -22,6 +22,9 @@ namespace Core.Services
public Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10) => _repository.BussinessUnitsListAsync(filter); public Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10) => _repository.BussinessUnitsListAsync(filter);
public Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10) => public Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10) =>
_repository.ProductsListAsync(filter); _repository.ProductsListAsync(filter);
public Task<IEnumerable<ELookUpItem>> PaymentTermsListAsync(string filter, int limit = 10)
=> _repository.PaymentTermsListAsync(filter, limit);
#endregion #endregion
} }
} }

View File

@ -127,6 +127,9 @@
<p><strong>Nombre:</strong> @Model.Customer.Name</p> <p><strong>Nombre:</strong> @Model.Customer.Name</p>
<p><strong>Domicilio:</strong> @Model.Customer.Address</p> <p><strong>Domicilio:</strong> @Model.Customer.Address</p>
<p><strong>Condición IVA:</strong> @Model.Customer.IvaCondition</p> <p><strong>Condición IVA:</strong> @Model.Customer.IvaCondition</p>
<p><strong>Condición de pago:</strong> @Model.PaymentTermDescription</p>
<p><strong>Validez de la oferta:</strong> @((Model.OfferValidityDays.HasValue ? $"{Model.OfferValidityDays} días" : "—"))</p>
@if (Model.Customer.Documents != null && Model.Customer.Documents.Any()) @if (Model.Customer.Documents != null && Model.Customer.Documents.Any())
{ {
<p><strong>Documentos:</strong></p> <p><strong>Documentos:</strong></p>

View File

@ -10,7 +10,7 @@
/// <summary> /// <summary>
/// Número de presupuesto (ej. "Q-00000001"). /// Número de presupuesto (ej. "Q-00000001").
/// </summary> /// </summary>
public string Quotenumber { get; set; } = ""; public string Quotenumber { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Fecha de emisión del presupuesto. /// Fecha de emisión del presupuesto.
@ -25,32 +25,43 @@
/// <summary> /// <summary>
/// Nombre completo del cliente asociado. /// Nombre completo del cliente asociado.
/// </summary> /// </summary>
public string CustomerName { get; set; } = ""; public string CustomerName { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre completo del médico responsable. /// Nombre completo del médico responsable.
/// </summary> /// </summary>
public string ProfessionalName { get; set; } = ""; public string ProfessionalName { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre de la institución u hospital. /// Nombre de la institución u hospital.
/// </summary> /// </summary>
public string InstitutionName { get; set; } = ""; public string InstitutionName { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre completo del paciente. /// Nombre completo del paciente.
/// </summary> /// </summary>
public string PatientName { get; set; } = ""; public string PatientName { get; set; } = String.Empty;
/// <summary>
/// Días de validez del presupuesto (desde la fecha de emisión).
/// </summary>
public int? OfferValidityDays { get; set; }
/// <summary>
/// Descripción de la condición de pago (ej. "Contado", "30 días").
/// </summary>
public string? PaymentTermDescription { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre de la unidad de negocio. /// Nombre de la unidad de negocio.
/// </summary> /// </summary>
public string BusinessUnitName { get; set; } = ""; public string BusinessUnitName { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Moneda del presupuesto (ej. "ARS", "USD"). /// Moneda del presupuesto (ej. "ARS", "USD").
/// </summary> /// </summary>
public string Currency { get; set; } = ""; public string Currency { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Importe total final (incluye impuestos y ajustes). /// Importe total final (incluye impuestos y ajustes).
@ -60,16 +71,16 @@
/// <summary> /// <summary>
/// Estado actual del presupuesto ("Pendiente", "Aprobado", etc.). /// Estado actual del presupuesto ("Pendiente", "Aprobado", etc.).
/// </summary> /// </summary>
public string Status { get; set; } = ""; public string Status { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre del vendedor o ejecutivo de ventas. /// Nombre del vendedor o ejecutivo de ventas.
/// </summary> /// </summary>
public string SalespersonName { get; set; } = ""; public string SalespersonName { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Nombre del vendedor o ejecutivo de ventas. /// Nombre del vendedor o ejecutivo de ventas.
/// </summary> /// </summary>
public string Observations { get; set; } = ""; public string Observations { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Detalle de los ítems o productos cotizados. /// Detalle de los ítems o productos cotizados.

View File

@ -0,0 +1,26 @@

namespace Domain.Entities
{
public class EPaymentTerm
{
/// <summary>
/// Identificador único de la condición de pago.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Descripción de la condición de pago (ej: Contado, 30 días, etc.).
/// </summary>
public string Description { get; set; } = null!;
/// <summary>
/// Cantidad de días establecidos para el pago. Contado = 0, 30 días = 30, etc.
/// </summary>
public int Days { get; set; }
/// <summary>
/// Indica si el término de pago está activo (1) o no (0).
/// </summary>
public bool Isactive { get; set; }
}
}

View File

@ -1,6 +1,4 @@
using System.Text.Json.Serialization; namespace Domain.Entities
namespace Domain.Entities
{ {
/// <summary> /// <summary>
/// Tabla de cabeceras de presupuestos /// Tabla de cabeceras de presupuestos
@ -21,7 +19,6 @@ namespace Domain.Entities
/// <summary> /// <summary>
/// Número visible del presupuesto /// Número visible del presupuesto
/// </summary> /// </summary>
public string Quotenumber { get; set; } = String.Empty; public string Quotenumber { get; set; } = String.Empty;
/// <summary> /// <summary>
@ -54,6 +51,16 @@ namespace Domain.Entities
/// </summary> /// </summary>
public DateTime? Estimateddate { get; set; } public DateTime? Estimateddate { get; set; }
/// <summary>
/// Días de validez de la oferta. Indica cuántos días estará vigente el presupuesto desde su fecha de emisión.
/// </summary>
public int? Offervaliditydays { get; set; }
/// <summary>
/// Condición de pago seleccionada para el presupuesto.
/// </summary>
public int? PaymenttermId { get; set; }
/// <summary> /// <summary>
/// Código de moneda pactada (ISO 4217). Ej: ARS, USD /// Código de moneda pactada (ISO 4217). Ej: ARS, USD
/// </summary> /// </summary>
@ -62,12 +69,12 @@ namespace Domain.Entities
/// <summary> /// <summary>
/// Tipo de cambio pactado para conversión a pesos argentinos /// Tipo de cambio pactado para conversión a pesos argentinos
/// </summary> /// </summary>
public decimal Exchangerate { get; set; } public decimal? Exchangerate { get; set; }
/// <summary> /// <summary>
/// Importe neto antes de aplicar impuestos, expresado en la moneda pactada del presupuesto /// Importe neto antes de aplicar impuestos, expresado en la moneda pactada del presupuesto
/// </summary> /// </summary>
public decimal Netamount { get; set; } public decimal? Netamount { get; set; }
/// <summary> /// <summary>
/// Importe total del presupuesto expresado en la moneda pactada (extranjera), incluyendo impuestos y ajustes comerciales /// Importe total del presupuesto expresado en la moneda pactada (extranjera), incluyendo impuestos y ajustes comerciales
@ -118,9 +125,13 @@ namespace Domain.Entities
/// Fecha de modificación /// Fecha de modificación
/// </summary> /// </summary>
public DateTime? Modifiedat { get; set; } public DateTime? Modifiedat { get; set; }
public virtual ICollection<EQuoteAdjustment> PhSQuoteAdjustments { get; set; } = new List<EQuoteAdjustment>(); public virtual ICollection<EQuoteAdjustment> PhSQuoteAdjustments { get; set; } = new List<EQuoteAdjustment>();
public virtual ICollection<EQuoteDetail> PhSQuoteDetails { get; set; } = new List<EQuoteDetail>(); public virtual ICollection<EQuoteDetail> PhSQuoteDetails { get; set; } = new List<EQuoteDetail>();
public virtual ICollection<EQuoteRole> PhSQuoteRoles { get; set; } = new List<EQuoteRole>(); public virtual ICollection<EQuoteRole> PhSQuoteRoles { get; set; } = new List<EQuoteRole>();
public virtual ICollection<EQuoteTax> PhSQuoteTaxes { get; set; } = new List<EQuoteTax>(); public virtual ICollection<EQuoteTax> PhSQuoteTaxes { get; set; } = new List<EQuoteTax>();
} }
} }

View File

@ -11,5 +11,6 @@ namespace Models.Interfaces
Task<IEnumerable<ELookUpItem>> PeopleListAsync(string filter, int limit = 10); Task<IEnumerable<ELookUpItem>> PeopleListAsync(string filter, int limit = 10);
Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10); Task<IEnumerable<ELookUpItem>> BussinessUnitsListAsync(string filter, int limit = 10);
Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10); Task<IEnumerable<EProductLookupItem>> ProductsListAsync(string filter, int limit = 10);
Task<IEnumerable<ELookUpItem>> PaymentTermsListAsync(string filter, int limit = 10);
} }
} }

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
namespace Models.Models;
/// <summary>
/// Tabla de condiciones o términos de pago aplicables a los presupuestos.
/// </summary>
public partial class PhSPaymentTerm
{
/// <summary>
/// Identificador único de la condición de pago.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Descripción de la condición de pago (ej: Contado, 30 días, etc.).
/// </summary>
public string Description { get; set; } = null!;
/// <summary>
/// Cantidad de días establecidos para el pago. Contado = 0, 30 días = 30, etc.
/// </summary>
public int Days { get; set; }
/// <summary>
/// Indica si el término de pago está activo (1) o no (0).
/// </summary>
public bool Isactive { get; set; }
public virtual ICollection<PhSQuoteHeader> PhSQuoteHeaders { get; set; } = new List<PhSQuoteHeader>();
}

View File

@ -53,6 +53,16 @@ public partial class PhSQuoteHeader
/// </summary> /// </summary>
public DateTime? Estimateddate { get; set; } public DateTime? Estimateddate { get; set; }
/// <summary>
/// Días de validez de la oferta. Indica cuántos días estará vigente el presupuesto desde su fecha de emisión.
/// </summary>
public int? Offervaliditydays { get; set; }
/// <summary>
/// Condición de pago seleccionada para el presupuesto.
/// </summary>
public int? PaymenttermId { get; set; }
/// <summary> /// <summary>
/// Código de moneda pactada (ISO 4217). Ej: ARS, USD /// Código de moneda pactada (ISO 4217). Ej: ARS, USD
/// </summary> /// </summary>
@ -118,6 +128,8 @@ public partial class PhSQuoteHeader
/// </summary> /// </summary>
public DateTime? Modifiedat { get; set; } public DateTime? Modifiedat { get; set; }
public virtual PhSPaymentTerm? Paymentterm { get; set; }
public virtual ICollection<PhSQuoteAdjustment> PhSQuoteAdjustments { get; set; } = new List<PhSQuoteAdjustment>(); public virtual ICollection<PhSQuoteAdjustment> PhSQuoteAdjustments { get; set; } = new List<PhSQuoteAdjustment>();
public virtual ICollection<PhSQuoteDetail> PhSQuoteDetails { get; set; } = new List<PhSQuoteDetail>(); public virtual ICollection<PhSQuoteDetail> PhSQuoteDetails { get; set; } = new List<PhSQuoteDetail>();

View File

@ -49,6 +49,8 @@ public partial class PhronCareOperationsHubContext : DbContext
public virtual DbSet<PhSPatient> PhSPatients { get; set; } public virtual DbSet<PhSPatient> PhSPatients { get; set; }
public virtual DbSet<PhSPaymentTerm> PhSPaymentTerms { get; set; }
public virtual DbSet<PhSPeopleGroup> PhSPeopleGroups { get; set; } public virtual DbSet<PhSPeopleGroup> PhSPeopleGroups { get; set; }
public virtual DbSet<PhSPerson> PhSPeople { get; set; } public virtual DbSet<PhSPerson> PhSPeople { get; set; }
@ -501,6 +503,8 @@ public partial class PhronCareOperationsHubContext : DbContext
entity.ToTable("PhS_Institutions"); entity.ToTable("PhS_Institutions");
entity.HasIndex(e => e.Name, "IDX_PhS_Institutions_Name");
entity.Property(e => e.Id).HasColumnName("id"); entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.City) entity.Property(e => e.City)
.HasMaxLength(100) .HasMaxLength(100)
@ -587,6 +591,28 @@ public partial class PhronCareOperationsHubContext : DbContext
.HasConstraintName("FK_Patients_DocumentTypes"); .HasConstraintName("FK_Patients_DocumentTypes");
}); });
modelBuilder.Entity<PhSPaymentTerm>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__PhS_Paym__3213E83F53A19842");
entity.ToTable("PhS_PaymentTerms", tb => tb.HasComment("Tabla de condiciones o términos de pago aplicables a los presupuestos."));
entity.Property(e => e.Id)
.HasComment("Identificador único de la condición de pago.")
.HasColumnName("id");
entity.Property(e => e.Days)
.HasComment("Cantidad de días establecidos para el pago. Contado = 0, 30 días = 30, etc.")
.HasColumnName("days");
entity.Property(e => e.Description)
.HasMaxLength(100)
.HasComment("Descripción de la condición de pago (ej: Contado, 30 días, etc.).")
.HasColumnName("description");
entity.Property(e => e.Isactive)
.HasDefaultValue(true)
.HasComment("Indica si el término de pago está activo (1) o no (0).")
.HasColumnName("isactive");
});
modelBuilder.Entity<PhSPeopleGroup>(entity => modelBuilder.Entity<PhSPeopleGroup>(entity =>
{ {
entity.HasKey(e => e.Id).HasName("PK__PhS_Peop__3213E83F8005BEA1"); entity.HasKey(e => e.Id).HasName("PK__PhS_Peop__3213E83F8005BEA1");
@ -906,6 +932,8 @@ public partial class PhronCareOperationsHubContext : DbContext
entity.ToTable("PhS_QuoteHeaders", tb => tb.HasComment("Tabla de cabeceras de presupuestos")); entity.ToTable("PhS_QuoteHeaders", tb => tb.HasComment("Tabla de cabeceras de presupuestos"));
entity.HasIndex(e => e.PaymenttermId, "ix_quoteheaders_paymenttermid");
entity.Property(e => e.Id) entity.Property(e => e.Id)
.HasComment("ID interno") .HasComment("ID interno")
.HasColumnName("id"); .HasColumnName("id");
@ -961,9 +989,15 @@ public partial class PhronCareOperationsHubContext : DbContext
entity.Property(e => e.Observations) entity.Property(e => e.Observations)
.HasComment("Observaciones internas") .HasComment("Observaciones internas")
.HasColumnName("observations"); .HasColumnName("observations");
entity.Property(e => e.Offervaliditydays)
.HasComment("Días de validez de la oferta. Indica cuántos días estará vigente el presupuesto desde su fecha de emisión.")
.HasColumnName("offervaliditydays");
entity.Property(e => e.OutOfTown) entity.Property(e => e.OutOfTown)
.HasComment("Indica si la cirugía se realizará fuera de la ciudad/localidad habitual (“out of town”)") .HasComment("Indica si la cirugía se realizará fuera de la ciudad/localidad habitual (“out of town”)")
.HasColumnName("out_of_town"); .HasColumnName("out_of_town");
entity.Property(e => e.PaymenttermId)
.HasComment("Condición de pago seleccionada para el presupuesto.")
.HasColumnName("paymentterm_id");
entity.Property(e => e.PeopleId) entity.Property(e => e.PeopleId)
.HasDefaultValue(1) .HasDefaultValue(1)
.HasComment("Identificador único del vendedor") .HasComment("Identificador único del vendedor")
@ -993,6 +1027,11 @@ public partial class PhronCareOperationsHubContext : DbContext
.HasComment("Importe total del presupuesto expresado en la moneda pactada (extranjera), incluyendo impuestos y ajustes comerciales") .HasComment("Importe total del presupuesto expresado en la moneda pactada (extranjera), incluyendo impuestos y ajustes comerciales")
.HasColumnType("decimal(18, 2)") .HasColumnType("decimal(18, 2)")
.HasColumnName("total_foreign"); .HasColumnName("total_foreign");
entity.HasOne(d => d.Paymentterm).WithMany(p => p.PhSQuoteHeaders)
.HasForeignKey(d => d.PaymenttermId)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("fk_quoteheaders_paymenttermid");
}); });
modelBuilder.Entity<PhSQuoteRole>(entity => modelBuilder.Entity<PhSQuoteRole>(entity =>

View File

@ -78,6 +78,20 @@ namespace Models.Repositories
.Select(c => new EProductLookupItem { Id = c.Id, Code=c.Businessunits.Code, Description = c.Description , UnitPrice= c.Baseprice }) .Select(c => new EProductLookupItem { Id = c.Id, Code=c.Businessunits.Code, Description = c.Description , UnitPrice= c.Baseprice })
.Take(limit) .Take(limit)
.ToListAsync(); .ToListAsync();
public async Task<IEnumerable<ELookUpItem>> PaymentTermsListAsync(string filter = "", int limit = 10)
{
var query = _context.PhSPaymentTerms
.Where(p => p.Isactive);
if (!string.IsNullOrWhiteSpace(filter))
query = query.Where(p => p.Description.Contains(filter));
return await query
.OrderBy(p => p.Days)
.Select(p => new ELookUpItem { Id = p.Id, Nombre = p.Description })
.Take(limit)
.ToListAsync();
}
} }
} }

View File

@ -228,7 +228,7 @@ namespace Models.Repositories
// Cargar Customer completo con documentos y tipos // Cargar Customer completo con documentos y tipos
var customer = await _context.PhSCustomers var customer = await _context.PhSCustomers
.Include(c => c.PhSCustomerDocuments) .Include(c => c.PhSCustomerDocuments)
.ThenInclude(d => d.Documenttypes) // ✅ CORRECTO .ThenInclude(d => d.Documenttypes)
.Include(c => c.PhSCustomerAddresses) .Include(c => c.PhSCustomerAddresses)
.Include(c => c.TaxCondition) .Include(c => c.TaxCondition)
.FirstOrDefaultAsync(c => c.Id == header.CustomerId); .FirstOrDefaultAsync(c => c.Id == header.CustomerId);
@ -244,16 +244,21 @@ namespace Models.Repositories
Quotenumber = header.Quotenumber, Quotenumber = header.Quotenumber,
IssueDate = header.Issuedate, IssueDate = header.Issuedate,
EstimatedDate = header.Estimateddate, EstimatedDate = header.Estimateddate,
OfferValidityDays = header.Offervaliditydays,
PaymentTermDescription = _context.PhSPaymentTerms
.Where(p => p.Id == header.PaymenttermId)
.Select(p => p.Description)
.FirstOrDefault() ?? "",
BusinessUnitName = _context.PhSBusinessUnits
.Where(b => b.Id == header.BusinessunitId)
.Select(b => b.Code)
.FirstOrDefault() ?? "",
Currency = header.Currency, Currency = header.Currency,
Total = header.Total.GetValueOrDefault(0m), Total = header.Total.GetValueOrDefault(0m),
Status = header.Status.Trim(), Status = header.Status.Trim(),
Observations = header.Observations ?? "", Observations = header.Observations ?? "",
CustomerName = customer?.Name ?? "", CustomerName = customer?.Name ?? "",
BusinessUnitName = _context.PhSBusinessUnits
.Where(b => b.Id == header.BusinessunitId)
.Select(b => b.Code)
.FirstOrDefault() ?? "",
ProfessionalName = header.PhSQuoteRoles ProfessionalName = header.PhSQuoteRoles
.Where(r => r.Entitytype == PhSEntityTypes.Professional) .Where(r => r.Entitytype == PhSEntityTypes.Professional)
@ -329,11 +334,12 @@ namespace Models.Repositories
Documents = customer?.PhSCustomerDocuments Documents = customer?.PhSCustomerDocuments
.Select(d => new QuoteCustomerDocumentDto .Select(d => new QuoteCustomerDocumentDto
{ {
DocumentType = d.Documenttypes.Name, // ✅ correcto DocumentType = d.Documenttypes.Name,
Number = d.DocumentNumber Number = d.DocumentNumber
}).ToList() ?? new() }).ToList() ?? new()
} }
}; };
return dto; return dto;
} }

View File

@ -34,5 +34,8 @@ namespace phronCare.API.Controllers.Sales
public Task<IEnumerable<EProductLookupItem>> Products([FromQuery] string q) public Task<IEnumerable<EProductLookupItem>> Products([FromQuery] string q)
=> _lookup.ProductsListAsync(q); => _lookup.ProductsListAsync(q);
[HttpGet("paymentterms")]
public Task<IEnumerable<ELookUpItem>> PaymentTerms()
=> _lookup.PaymentTermsListAsync(""); // o sin parámetro si lo hacés opcional
} }
} }

View File

@ -862,6 +862,26 @@
} }
] ]
}, },
{
"ContainingType": "phronCare.API.Controllers.Sales.LookUpController",
"Method": "PaymentTerms",
"RelativePath": "api/LookUp/paymentterms",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [],
"ReturnTypes": [
{
"Type": "System.Collections.Generic.IEnumerable\u00601[[Domain.Entities.ELookUpItem, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"MediaTypes": [
"text/plain",
"application/json",
"text/json"
],
"StatusCode": 200
}
]
},
{ {
"ContainingType": "phronCare.API.Controllers.Sales.LookUpController", "ContainingType": "phronCare.API.Controllers.Sales.LookUpController",
"Method": "People", "Method": "People",

View File

@ -114,7 +114,25 @@
</InputSelect> </InputSelect>
</div> </div>
</div> </div>
<!-- FILA 4: Moneda, Cambio, OutOfTown --> <!-- FILA 3.1: Condición de pago y validez -->
<div class="row mb-3">
<div class="col-md-6">
<label for="paymenttermid">Condición de pago</label>
<InputSelect id="paymenttermid" class="form-select" @bind-Value="_quoteModel.PaymenttermId">
<option disabled selected value="">Seleccione...</option>
@foreach (var term in _paymentTerms)
{
<option value="@term.Id">@term.Nombre</option>
}
</InputSelect>
</div>
<div class="col-md-3">
<label for="offerValidityDays">Validez (días)</label>
<InputNumber id="offerValidityDays" class="form-control" @bind-Value="_quoteModel.Offervaliditydays" />
</div>
</div>
<!-- FILA 4: Fecha estimada, Moneda, Cambio, OutOfTown -->
<div class="row mb-3"> <div class="row mb-3">
<div class="col-md-3"> <div class="col-md-3">
<label for="estimateddate">Fecha estimada</label> <label for="estimateddate">Fecha estimada</label>
@ -155,11 +173,9 @@
<hr /> <hr />
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="d-flex justify-content-between align-items-center mb-2">
<h5 class="mb-3">Productos Cotizados</h5> <h5 class="mb-3">Productos Cotizados</h5>
<button type="button" class="btn btn-outline-success mb-2" @onclick="AddNewProduct"> <button type="button" class="btn btn-outline-success mb-2" @onclick="AddNewProduct">
<i class="fas fa-cart-plus me-1"></i> Agregar producto <i class="fas fa-cart-plus me-1"></i> Agregar producto
</button> </button>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover align-middle"> <table class="table table-bordered table-hover align-middle">
@ -313,9 +329,15 @@
</EditForm> </EditForm>
@code { @code {
private EQuoteHeader _quoteModel = new(); private EQuoteHeader _quoteModel = new()
{
Offervaliditydays = 15,
Estimateddate = DateTime.Today,
Currency="ARS"
};
private ELookUpItem? _selectedCustomer, _selectedProfessional, _selectedInstitution, _selectedPatient, _selectedPerson; private ELookUpItem? _selectedCustomer, _selectedProfessional, _selectedInstitution, _selectedPatient, _selectedPerson;
private List<ELookUpItem> _businessUnits = new(); private List<ELookUpItem> _businessUnits = new(), _paymentTerms = new();
private EExchangeRateHistory? YesterdayRate; private EExchangeRateHistory? YesterdayRate;
private string returnUrl = "quotes/"; private string returnUrl = "quotes/";
private decimal _netAmount = 0, _taxAmount = 0, _grandTotal = 0; private decimal _netAmount = 0, _taxAmount = 0, _grandTotal = 0;
@ -336,11 +358,13 @@
} }
// 2. Asignamos al modelo si aún no tiene valor // 2. Asignamos al modelo si aún no tiene valor
if (YesterdayRate != null && _quoteModel.Exchangerate == 0) if (YesterdayRate != null)
{ {
_quoteModel.Exchangerate = YesterdayRate.Salerate; _quoteModel.Exchangerate = YesterdayRate.Salerate;
} }
_businessUnits = (await SalesLookupService.SearchBussinessUnitsAsync(string.Empty)).ToList(); _businessUnits = (await SalesLookupService.SearchBussinessUnitsAsync(string.Empty)).ToList();
_paymentTerms = (await SalesLookupService.GetPaymentTermsAsync()).ToList();
} }
private async Task AddNewProduct() private async Task AddNewProduct()
{ {
@ -365,6 +389,24 @@
_quoteModel.PhSQuoteDetails.Add(newDetail); _quoteModel.PhSQuoteDetails.Add(newDetail);
} }
} }
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;
if (!result.Cancelled && result.Data is EQuoteTax newTax)
{
_quoteModel.PhSQuoteTaxes.Add(newTax);
RecalculateTotals();
}
}
private async Task AddNewPatient() private async Task AddNewPatient()
{ {
var options = new ModalOptions() var options = new ModalOptions()
@ -379,7 +421,6 @@
_selectedPatient = nuevo; _selectedPatient = nuevo;
} }
} }
private async Task AddNewProfessional() private async Task AddNewProfessional()
{ {
var options = new ModalOptions() var options = new ModalOptions()
@ -427,25 +468,6 @@
toastService.ShowToast<PhLinkToast>(_parameters); toastService.ShowToast<PhLinkToast>(_parameters);
Navigation.NavigateTo(returnUrl); Navigation.NavigateTo(returnUrl);
} }
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;
if (!result.Cancelled && result.Data is EQuoteTax newTax)
{
_quoteModel.PhSQuoteTaxes.Add(newTax);
RecalculateTotals();
}
}
private Task OnCustomerSelected(ELookUpItem item) private Task OnCustomerSelected(ELookUpItem item)
=> SetLookupSelection(item, sel => _selectedCustomer = sel, id => _quoteModel.CustomerId = id); => SetLookupSelection(item, sel => _selectedCustomer = sel, id => _quoteModel.CustomerId = id);
private Task OnPersonSelected(ELookUpItem item) private Task OnPersonSelected(ELookUpItem item)

View File

@ -13,5 +13,6 @@ namespace phronCare.UIBlazor.Services.Lookups
Task<IEnumerable<EProductLookupItem>> SearchProductsAsync(string filtro); Task<IEnumerable<EProductLookupItem>> SearchProductsAsync(string filtro);
Task<IEnumerable<EAdjustmentReason>> GetAdjustmentReasonsAsync(); Task<IEnumerable<EAdjustmentReason>> GetAdjustmentReasonsAsync();
Task<IEnumerable<ETaxType>> GetTaxTypesAsync(); Task<IEnumerable<ETaxType>> GetTaxTypesAsync();
Task<IEnumerable<ELookUpItem>> GetPaymentTermsAsync();
} }
} }

View File

@ -54,7 +54,10 @@ namespace phronCare.UIBlazor.Services.Lookups
var items = await _http.GetFromJsonAsync<ETaxType[]>("api/taxtype/getall"); var items = await _http.GetFromJsonAsync<ETaxType[]>("api/taxtype/getall");
return items ?? Array.Empty<ETaxType>(); return items ?? Array.Empty<ETaxType>();
} }
public async Task<IEnumerable<ELookUpItem>> GetPaymentTermsAsync()
{
var items = await _http.GetFromJsonAsync<ELookUpItem[]>("api/lookup/paymentterms?q=");
return items ?? Array.Empty<ELookUpItem>();
}
} }
} }