| | | 1 | | using Microsoft.EntityFrameworkCore; |
| | | 2 | | using OzonDomains.Models; |
| | | 3 | | using OzonRepositories.Context; |
| | | 4 | | |
| | | 5 | | namespace Services.LabelServices; |
| | | 6 | | |
| | 2 | 7 | | public sealed record LabelPrintLogEntry( |
| | 4 | 8 | | string FileName, |
| | 2 | 9 | | int? OrderId, |
| | 2 | 10 | | LabelPrintSource Source, |
| | 2 | 11 | | LabelPrintActorKind ActorKind, |
| | 2 | 12 | | string? ActorId, |
| | 4 | 13 | | string ActorName); |
| | | 14 | | |
| | | 15 | | public interface ILabelPrintLogService |
| | | 16 | | { |
| | | 17 | | Task RecordAsync(IEnumerable<LabelPrintLogEntry> entries, CancellationToken cancellationToken = default); |
| | | 18 | | Task<IReadOnlyList<LabelPrintLog>> GetLatestByPdfAsync(CancellationToken cancellationToken = default); |
| | | 19 | | } |
| | | 20 | | |
| | | 21 | | /// <summary>Журналирует только успешно доступные из хранилища PDF и инвалидирует каталог этикеток.</summary> |
| | | 22 | | public sealed class LabelPrintLogService( |
| | | 23 | | ApplicationDbContext context, |
| | | 24 | | ILabelCatalogCache catalogCache) : ILabelPrintLogService |
| | | 25 | | { |
| | | 26 | | public async Task RecordAsync(IEnumerable<LabelPrintLogEntry> entries, CancellationToken cancellationToken = default |
| | | 27 | | { |
| | | 28 | | var rows = entries |
| | | 29 | | .Where(x => !string.IsNullOrWhiteSpace(x.FileName)) |
| | | 30 | | .Select(x => new LabelPrintLog |
| | | 31 | | { |
| | | 32 | | FileName = x.FileName.Trim(), |
| | | 33 | | OrderId = x.OrderId, |
| | | 34 | | Source = x.Source, |
| | | 35 | | ActorKind = x.ActorKind, |
| | | 36 | | ActorId = Truncate(x.ActorId, 450), |
| | | 37 | | ActorName = Truncate(x.ActorName, 300) ?? "Неизвестный пользователь", |
| | | 38 | | OccurredAtUtc = DateTime.UtcNow |
| | | 39 | | }) |
| | | 40 | | .ToList(); |
| | | 41 | | if (rows.Count == 0) return; |
| | | 42 | | |
| | | 43 | | context.LabelPrintLogs.AddRange(rows); |
| | | 44 | | await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); |
| | | 45 | | catalogCache.Invalidate(); |
| | | 46 | | } |
| | | 47 | | |
| | | 48 | | public async Task<IReadOnlyList<LabelPrintLog>> GetLatestByPdfAsync(CancellationToken cancellationToken = default) |
| | | 49 | | { |
| | | 50 | | var latestIds = context.LabelPrintLogs.AsNoTracking() |
| | | 51 | | .GroupBy(x => x.FileName) |
| | | 52 | | .Select(x => x.OrderByDescending(log => log.OccurredAtUtc).ThenByDescending(log => log.Id) |
| | | 53 | | .Select(log => log.Id).First()); |
| | | 54 | | |
| | | 55 | | return await context.LabelPrintLogs.AsNoTracking() |
| | | 56 | | .Where(x => latestIds.Contains(x.Id)) |
| | | 57 | | .ToListAsync(cancellationToken) |
| | | 58 | | .ConfigureAwait(false); |
| | | 59 | | } |
| | | 60 | | |
| | | 61 | | private static string? Truncate(string? value, int max) => |
| | | 62 | | string.IsNullOrWhiteSpace(value) ? null : value.Length <= max ? value : value[..max]; |
| | | 63 | | } |