line-gestao-api/Controllers/NotificationsController.cs

246 lines
8.6 KiB
C#

using ClosedXML.Excel;
using line_gestao_api.Data;
using line_gestao_api.Dtos;
using line_gestao_api.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace line_gestao_api.Controllers;
[ApiController]
[Route("api/notifications")]
[Authorize]
public class NotificationsController : ControllerBase
{
private readonly AppDbContext _db;
public NotificationsController(AppDbContext db)
{
_db = db;
}
[HttpGet]
[HttpGet("/notifications")]
public async Task<ActionResult<List<NotificationDto>>> GetNotifications()
{
var items = await (
from notification in _db.Notifications.AsNoTracking()
join vigencia in _db.VigenciaLines.AsNoTracking()
on notification.VigenciaLineId equals vigencia.Id into vigencias
from vigencia in vigencias.DefaultIfEmpty()
orderby notification.Data descending
select new NotificationDto
{
Id = notification.Id,
Tipo = notification.Tipo,
Titulo = notification.Titulo,
Mensagem = notification.Mensagem,
Data = notification.Data,
ReferenciaData = notification.ReferenciaData,
DiasParaVencer = notification.DiasParaVencer,
Lida = notification.Lida,
LidaEm = notification.LidaEm,
VigenciaLineId = notification.VigenciaLineId,
Cliente = notification.Cliente ?? vigencia.Cliente,
Linha = notification.Linha ?? vigencia.Linha,
Conta = vigencia.Conta,
Usuario = notification.Usuario ?? vigencia.Usuario,
PlanoContrato = vigencia.PlanoContrato,
DtEfetivacaoServico = vigencia.DtEfetivacaoServico,
DtTerminoFidelizacao = vigencia.DtTerminoFidelizacao
})
.ToListAsync();
return Ok(items);
}
[HttpPatch("{id:guid}/read")]
[HttpPatch("/notifications/{id:guid}/read")]
public async Task<IActionResult> MarkAsRead(Guid id)
{
var notification = await _db.Notifications
.FirstOrDefaultAsync(n => n.Id == id);
if (notification is null)
{
return NotFound();
}
if (!notification.Lida)
{
notification.Lida = true;
notification.LidaEm = DateTime.UtcNow;
await _db.SaveChangesAsync();
}
return NoContent();
}
[HttpPatch("read-all")]
[HttpPatch("/notifications/read-all")]
public async Task<IActionResult> MarkAllAsRead(
[FromQuery] string? filter,
[FromBody] NotificationSelectionRequest? request)
{
var utcNow = DateTime.UtcNow;
var query = ApplySelectionAndFilter(_db.Notifications, filter, request?.NotificationIds)
.Where(n => !n.Lida);
await query.ExecuteUpdateAsync(updates => updates
.SetProperty(n => n.Lida, true)
.SetProperty(n => n.LidaEm, utcNow));
return NoContent();
}
[HttpGet("export")]
[HttpGet("/notifications/export")]
public async Task<IActionResult> ExportNotifications([FromQuery] string? filter)
{
var query = ApplySelectionAndFilter(_db.Notifications.AsNoTracking(), filter, null);
return await ExportNotificationsAsync(query, filter);
}
[HttpPost("export")]
[HttpPost("/notifications/export")]
public async Task<IActionResult> ExportNotifications(
[FromQuery] string? filter,
[FromBody] NotificationSelectionRequest? request)
{
var query = ApplySelectionAndFilter(_db.Notifications.AsNoTracking(), filter, request?.NotificationIds);
return await ExportNotificationsAsync(query, filter);
}
private async Task<IActionResult> ExportNotificationsAsync(IQueryable<Notification> query, string? filter)
{
var rows = await (
from notification in query
join vigencia in _db.VigenciaLines.AsNoTracking()
on notification.VigenciaLineId equals vigencia.Id into vigencias
from vigencia in vigencias.DefaultIfEmpty()
orderby notification.ReferenciaData descending, notification.Data descending
select new NotificationExportRow(
vigencia.Conta,
notification.Linha ?? vigencia.Linha,
notification.Cliente ?? vigencia.Cliente,
notification.Usuario ?? vigencia.Usuario,
vigencia.PlanoContrato,
vigencia.DtEfetivacaoServico,
notification.ReferenciaData ?? vigencia.DtTerminoFidelizacao,
notification.Tipo))
.ToListAsync();
using var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Notificacoes");
var normalizedFilter = NormalizeFilter(filter);
var headers = new[]
{
"CONTA",
"LINHA",
"Cliente",
"Usuário",
"PLANO CONTRATO",
"DATA INICIO",
normalizedFilter is "vencidas" or "vencido" ? "DATA VENCIMENTO" : "DATA A VENCER",
"Status"
};
for (var i = 0; i < headers.Length; i++)
{
worksheet.Cell(1, i + 1).Value = headers[i];
}
var headerRange = worksheet.Range(1, 1, 1, headers.Length);
headerRange.Style.Font.Bold = true;
headerRange.Style.Fill.BackgroundColor = XLColor.LightGray;
headerRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
for (var i = 0; i < rows.Count; i++)
{
var row = rows[i];
var rowIndex = i + 2;
worksheet.Cell(rowIndex, 1).Value = row.Conta ?? string.Empty;
worksheet.Cell(rowIndex, 2).Value = row.Linha ?? string.Empty;
worksheet.Cell(rowIndex, 3).Value = (row.Cliente ?? string.Empty).ToUpperInvariant();
worksheet.Cell(rowIndex, 4).Value = (row.Usuario ?? string.Empty).ToUpperInvariant();
worksheet.Cell(rowIndex, 5).Value = row.PlanoContrato ?? string.Empty;
worksheet.Cell(rowIndex, 6).Value = row.DataInicio;
worksheet.Cell(rowIndex, 7).Value = row.DataReferencia;
worksheet.Cell(rowIndex, 8).Value = row.Tipo.ToUpperInvariant();
}
worksheet.Column(1).Width = 18;
worksheet.Column(2).Width = 18;
worksheet.Column(3).Width = 26;
worksheet.Column(4).Width = 24;
worksheet.Column(5).Width = 22;
worksheet.Column(6).Width = 16;
worksheet.Column(7).Width = 18;
worksheet.Column(8).Width = 14;
worksheet.Column(6).Style.DateFormat.Format = "dd/MM/yyyy";
worksheet.Column(7).Style.DateFormat.Format = "dd/MM/yyyy";
worksheet.Columns().AdjustToContents();
using var stream = new MemoryStream();
workbook.SaveAs(stream);
stream.Position = 0;
var fileName = $"notificacoes-{DateTime.UtcNow:yyyyMMddHHmmss}.xlsx";
return File(
stream.ToArray(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
fileName);
}
private static IQueryable<Notification> ApplySelectionAndFilter(
IQueryable<Notification> query,
string? filter,
IReadOnlyCollection<Guid>? notificationIds)
{
query = ApplyFilter(query, filter);
if (notificationIds is { Count: > 0 })
{
query = query.Where(n => notificationIds.Contains(n.Id));
}
return query;
}
private static IQueryable<Notification> ApplyFilter(IQueryable<Notification> query, string? filter)
{
var normalized = NormalizeFilter(filter);
return normalized switch
{
"a-vencer" or "avencer" => query.Where(n => n.Tipo == "AVencer"),
"vencidas" or "vencido" => query.Where(n => n.Tipo == "Vencido"),
_ => query
};
}
private static string? NormalizeFilter(string? filter)
{
return filter?.Trim().ToLowerInvariant();
}
private sealed record NotificationExportRow(
string? Conta,
string? Linha,
string? Cliente,
string? Usuario,
string? PlanoContrato,
DateTime? DataInicio,
DateTime? DataReferencia,
string Tipo);
public sealed class NotificationSelectionRequest
{
public List<Guid>? NotificationIds { get; set; }
}
}