using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Elfisa.Core; namespace Elfisa.Avalonia.ViewModels; public sealed class OrderItemRow { public string Name { get; init; } = ""; public string Code { get; init; } = ""; public decimal Qty { get; init; } public decimal Price { get; init; } public decimal Sum { get; init; } public string? SupplierPriceId { get; init; } public string? Barcode { get; init; } } public sealed class OrderSummary { public string Date { get; init; } = ""; public string Number { get; init; } = ""; public string Supplier { get; init; } = ""; public string Location { get; init; } = ""; public string Status { get; init; } = ""; public int ItemsCount { get; init; } public decimal Sum { get; init; } public ObservableCollection Items { get; init; } = new(); public bool IsDraft { get; init; } public string? DraftId { get; init; } public string? LocationId { get; init; } public string? Comment { get; init; } } /// /// Заказы: локальные черновики (статус «Не отправлен») + серверные заказы (из /api/buyer/report). /// Черновик можно отправить (создать реальный заказ) или удалить. /// public partial class OrdersViewModel : ViewModelBase { private readonly ApiClient _api = new(); public ObservableCollection Orders { get; } = new(); [ObservableProperty] private OrderSummary? _selectedOrder; [ObservableProperty] private bool _busy; [ObservableProperty] private string? _status; public OrdersViewModel() { _api.SetToken(Session.Current.Token); if (Session.Current.IsAuthenticated) _ = LoadAsync(); } [RelayCommand] private async Task LoadAsync() { Status = null; try { Busy = true; Orders.Clear(); // 1) Локальные черновики — вверху, статус «Не отправлен» foreach (var d in DraftStore.All) { var items = new ObservableCollection( d.Items.Select(i => new OrderItemRow { Name = i.Name, Qty = i.Qty, Price = i.Price, Sum = i.LineSum, SupplierPriceId = i.SupplierPriceId, Barcode = i.Barcode })); Orders.Add(new OrderSummary { Date = d.CreatedAt.ToString("dd.MM.yyyy"), Number = d.Number, Supplier = string.Join(", ", d.Items.Select(i => i.Supplier).Where(s => !string.IsNullOrWhiteSpace(s)).Distinct()), Location = d.LocationAddress ?? "", Status = "Не отправлен", ItemsCount = d.ItemsCount, Sum = d.Total, Items = items, IsDraft = true, DraftId = d.Id, LocationId = d.LocationId, Comment = d.Comment }); } // 2) Серверные заказы var to = DateTime.Today; var from = to.AddMonths(-24); var lines = await _api.GetBuyerReportAsync(from, to); foreach (var g in lines.GroupBy(l => l.OrderId) .OrderByDescending(x => x.First().OrderDate ?? DateTime.MinValue)) { var f = g.First(); var items = new ObservableCollection( g.Select(l => new OrderItemRow { Name = l.ItemName ?? "", Code = l.ItemCode ?? "", Qty = l.Qty, Price = l.UnitPrice, Sum = l.Sum })); Orders.Add(new OrderSummary { Date = f.OrderDate?.ToLocalTime().ToString("dd.MM.yyyy") ?? "", Number = f.GlobalSign ?? "", Supplier = string.Join(", ", g.Select(x => x.Supplier).Where(s => !string.IsNullOrWhiteSpace(s)).Distinct()), Location = f.Location ?? "", Status = f.Status ?? "", ItemsCount = g.Count(), Sum = g.Sum(x => x.Sum), Items = items }); } SelectedOrder = Orders.FirstOrDefault(); } catch (Exception ex) { Status = ex.Message; } finally { Busy = false; } } [RelayCommand] private async Task SendDraftAsync() { if (SelectedOrder is not { IsDraft: true } d) return; Status = null; try { Busy = true; var req = new BuyerOrderCreateRequest { GlobalSign = d.Number.StartsWith("EX-", StringComparison.OrdinalIgnoreCase) ? d.Number : null, LocationId = d.LocationId, Comment = d.Comment, Items = d.Items.Select(i => new BuyerOrderItemReq { SupplierPriceId = i.SupplierPriceId ?? "", Qty = (double)i.Qty, ItemName = i.Name, Barcode = i.Barcode }).ToList() }; var resp = await _api.CreateOrderAsync(req); if (d.DraftId is { } id) DraftStore.Remove(id); Status = $"✓ Заказ {resp.GlobalSign ?? resp.OrderId} отправлен ({resp.ItemsCount} поз., {resp.TotalAmount:N2})."; await LoadAsync(); } catch (Exception ex) { Status = "Ошибка отправки: " + ex.Message; } finally { Busy = false; } } [RelayCommand] private async Task DeleteDraftAsync() { if (SelectedOrder is not { IsDraft: true } d || d.DraftId is not { } id) return; DraftStore.Remove(id); await LoadAsync(); Status = "Черновик удалён."; } }