diff --git a/Core/Interfaces/IDeliveryNoteDom.cs b/Core/Interfaces/IDeliveryNoteDom.cs
index bbeff1e..fb9f44f 100644
--- a/Core/Interfaces/IDeliveryNoteDom.cs
+++ b/Core/Interfaces/IDeliveryNoteDom.cs
@@ -22,6 +22,11 @@ public interface IDeliveryNoteDom
int page = 1,
int pageSize = 50);
+ ///
+ /// Exporta a Excel los Delivery Notes filtrados.
+ ///
+ Task ExportFilteredToExcelAsync(DeliveryNoteSearchParams searchParams);
+
///
/// Obtiene un Delivery Note por su identificador Ășnico.
///
diff --git a/Core/Services/DeliveryNoteService.cs b/Core/Services/DeliveryNoteService.cs
index e5e45b8..2915301 100644
--- a/Core/Services/DeliveryNoteService.cs
+++ b/Core/Services/DeliveryNoteService.cs
@@ -1,8 +1,10 @@
-using Core.Interfaces;
using Domain.Dtos.Sales;
using Domain.Entities;
using Domain.Generics;
using Models.Interfaces;
+using System.Reflection;
+using System.Text.Json;
+using Transversal.Services;
namespace Core.Services
{
@@ -46,6 +48,62 @@ namespace Core.Services
return _deliveryNoteRepository.GetDtoByIdAsync(id);
}
+ public async Task ExportFilteredToExcelAsync(DeliveryNoteSearchParams searchParams)
+ {
+ ArgumentNullException.ThrowIfNull(searchParams);
+
+ try
+ {
+ var searchResult = await _deliveryNoteRepository.SearchAsync(
+ searchParams.CustomerId,
+ string.IsNullOrWhiteSpace(searchParams.CustomerText) ? null : searchParams.CustomerText.Trim(),
+ string.IsNullOrWhiteSpace(searchParams.DeliveryNoteNumber) ? null : searchParams.DeliveryNoteNumber.Trim(),
+ searchParams.QuoteId,
+ string.IsNullOrWhiteSpace(searchParams.QuoteNumber) ? null : searchParams.QuoteNumber.Trim(),
+ searchParams.IssueDateFrom,
+ searchParams.IssueDateTo,
+ string.IsNullOrWhiteSpace(searchParams.Status) ? null : searchParams.Status.Trim(),
+ searchParams.Page <= 0 ? 1 : searchParams.Page,
+ searchParams.PageSize <= 0 ? 50 : searchParams.PageSize);
+
+ if (searchResult?.Items is null || !searchResult.Items.Any())
+ throw new Exception("No se encontraron remitos para exportar.");
+
+ var items = searchResult.Items.ToList();
+ var exportRows = new List(items.Count);
+
+ foreach (var deliveryNote in items)
+ {
+ var dto = await _deliveryNoteRepository.GetDtoByIdAsync(deliveryNote.Id);
+ var snapshot = DeliveryNoteSnapshotInfo.FromJson(dto?.ExtraInfoJson);
+
+ exportRows.Add(new DeliveryNoteExcelRow
+ {
+ DeliveryNoteNumber = deliveryNote.DeliveryNoteNumber,
+ IssueDate = deliveryNote.IssueDate.ToString("dd/MM/yyyy"),
+ QuoteNumber = deliveryNote.QuoteNumber,
+ CustomerName = deliveryNote.CustomerName,
+ Status = deliveryNote.Status,
+ ProfessionalName = snapshot.ProfessionalName,
+ InstitutionName = snapshot.InstitutionName,
+ PatientName = snapshot.PatientName,
+ SurgeryDate = snapshot.SurgeryDate,
+ Observations = deliveryNote.Observations,
+ PrintCount = deliveryNote.PrintCount,
+ CreatedAt = deliveryNote.CreatedAt.ToString("dd/MM/yyyy HH:mm")
+ });
+ }
+
+ var stream = new XLSXExportBase();
+ return stream.ExportExcel(exportRows);
+ }
+ catch (Exception ex)
+ {
+ var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
+ throw new Exception($"{methodName} Message: {ex.Message}", ex);
+ }
+ }
+
public Task GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber)
{
if (string.IsNullOrWhiteSpace(deliveryNoteNumber))
@@ -125,5 +183,113 @@ namespace Core.Services
DeliveryNoteNumber = created.Deliverynotenumber
};
}
+
+ private sealed class DeliveryNoteExcelRow
+ {
+ public string DeliveryNoteNumber { get; set; } = string.Empty;
+ public string IssueDate { get; set; } = string.Empty;
+ public string? QuoteNumber { get; set; }
+ public string? CustomerName { get; set; }
+ public string? Status { get; set; }
+ public string? ProfessionalName { get; set; }
+ public string? InstitutionName { get; set; }
+ public string? PatientName { get; set; }
+ public string? SurgeryDate { get; set; }
+ public string? Observations { get; set; }
+ public int PrintCount { get; set; }
+ public string CreatedAt { get; set; } = string.Empty;
+ }
+
+ private sealed class DeliveryNoteSnapshotInfo
+ {
+ public string? ProfessionalName { get; private set; }
+ public string? InstitutionName { get; private set; }
+ public string? PatientName { get; private set; }
+ public string? SurgeryDate { get; private set; }
+
+ public static DeliveryNoteSnapshotInfo FromJson(string? extraInfoJson)
+ {
+ var snapshot = new DeliveryNoteSnapshotInfo();
+
+ if (string.IsNullOrWhiteSpace(extraInfoJson))
+ return snapshot;
+
+ try
+ {
+ using var document = JsonDocument.Parse(extraInfoJson);
+ var root = document.RootElement;
+
+ snapshot.ProfessionalName = ReadString(root, "professional", "professionalName", "doctor", "doctorName", "medico", "medicoNombre");
+ snapshot.InstitutionName = ReadString(root, "institution", "institutionName", "hospital", "hospitalName", "institucion", "institucionNombre");
+ snapshot.PatientName = ReadString(root, "patient", "patientName", "paciente", "pacienteNombre");
+ snapshot.SurgeryDate = ReadDate(root, "surgeryDate", "estimatedDate", "fechaCirugia", "surgery_date", "estimated_date");
+ }
+ catch
+ {
+ return snapshot;
+ }
+
+ return snapshot;
+ }
+
+ private static string? ReadString(JsonElement root, params string[] propertyNames)
+ {
+ foreach (var propertyName in propertyNames)
+ {
+ if (!TryGetPropertyIgnoreCase(root, propertyName, out var value))
+ continue;
+
+ if (value.ValueKind == JsonValueKind.String)
+ return value.GetString();
+
+ if (value.ValueKind != JsonValueKind.Null && value.ValueKind != JsonValueKind.Undefined)
+ return value.ToString();
+ }
+
+ return null;
+ }
+
+ private static string? ReadDate(JsonElement root, params string[] propertyNames)
+ {
+ foreach (var propertyName in propertyNames)
+ {
+ if (!TryGetPropertyIgnoreCase(root, propertyName, out var value))
+ continue;
+
+ if (value.ValueKind == JsonValueKind.String)
+ {
+ var raw = value.GetString();
+
+ if (string.IsNullOrWhiteSpace(raw))
+ return null;
+
+ if (DateTime.TryParse(raw, out var parsedDate))
+ return parsedDate.ToString("dd/MM/yyyy");
+
+ return raw;
+ }
+
+ if (value.ValueKind != JsonValueKind.Null && value.ValueKind != JsonValueKind.Undefined)
+ return value.ToString();
+ }
+
+ return null;
+ }
+
+ private static bool TryGetPropertyIgnoreCase(JsonElement element, string propertyName, out JsonElement value)
+ {
+ foreach (var property in element.EnumerateObject())
+ {
+ if (string.Equals(property.Name, propertyName, StringComparison.OrdinalIgnoreCase))
+ {
+ value = property.Value;
+ return true;
+ }
+ }
+
+ value = default;
+ return false;
+ }
+ }
}
}
diff --git a/Models/Models/PhSDeliveryNoteDetail.cs b/Models/Models/PhSDeliveryNoteDetail.cs
index 667eef9..eb7c94b 100644
--- a/Models/Models/PhSDeliveryNoteDetail.cs
+++ b/Models/Models/PhSDeliveryNoteDetail.cs
@@ -17,7 +17,7 @@ public partial class PhSDeliveryNoteDetail
public int? QuoteDetailId { get; set; }
- public string Description { get; set; } = null!;
+ public string? Description { get; set; }
public decimal Quantity { get; set; }
diff --git a/Models/Models/PhronCareOperationsHubContext.cs b/Models/Models/PhronCareOperationsHubContext.cs
index b2514c6..9cab453 100644
--- a/Models/Models/PhronCareOperationsHubContext.cs
+++ b/Models/Models/PhronCareOperationsHubContext.cs
@@ -1104,9 +1104,7 @@ public partial class PhronCareOperationsHubContext : DbContext
.HasColumnType("datetime")
.HasColumnName("createdat");
entity.Property(e => e.DeliverynoteId).HasColumnName("deliverynote_id");
- entity.Property(e => e.Description)
- .HasMaxLength(500)
- .HasColumnName("description");
+ entity.Property(e => e.Description).HasColumnName("description");
entity.Property(e => e.LineNumber).HasColumnName("line_number");
entity.Property(e => e.Modifiedat)
.HasColumnType("datetime")
diff --git a/Models/Repositories/PhSDeliveryNoteRepository.cs b/Models/Repositories/PhSDeliveryNoteRepository.cs
index 0686bec..7102e7c 100644
--- a/Models/Repositories/PhSDeliveryNoteRepository.cs
+++ b/Models/Repositories/PhSDeliveryNoteRepository.cs
@@ -176,7 +176,7 @@ namespace Models.Repositories
OriginType = source.OriginType,
OriginId = source.OriginId,
QuoteDetailId = source.QuoteDetailId,
- Description = source.Description,
+ Description = source.Description??string.Empty,
Quantity = source.Quantity,
Notes = source.Notes,
Createdat = source.Createdat,
diff --git a/phronCare.API/Controllers/Sales/DeliveryNoteController.cs b/phronCare.API/Controllers/Sales/DeliveryNoteController.cs
index 86de3ff..639ba6c 100644
--- a/phronCare.API/Controllers/Sales/DeliveryNoteController.cs
+++ b/phronCare.API/Controllers/Sales/DeliveryNoteController.cs
@@ -150,5 +150,31 @@ namespace phronCare.API.Controllers.Sales
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
+
+ [HttpPost("exportfiltered")]
+ public async Task ExportFiltered([FromBody] DeliveryNoteSearchParams searchParams)
+ {
+ try
+ {
+ var file = await _deliveryNoteService.ExportFilteredToExcelAsync(searchParams);
+ return File(
+ file,
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "Remitos.xlsx");
+ }
+ catch (ArgumentException ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ catch (InvalidOperationException ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
+ return BadRequest($"{methodName} Message: {ex.Message}");
+ }
+ }
}
}