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 partial class SendOrderViewModel : ViewModelBase { private readonly ApiClient _api = new(); /// Неотправленные накладные (черновики). public ObservableCollection Drafts { get; } = new(); [ObservableProperty] private DraftOrder? _selected; [ObservableProperty] private bool _busy; [ObservableProperty] private string? _status; [ObservableProperty] private decimal _totalSum; [ObservableProperty] private bool _isEmpty = true; [ObservableProperty] private int _count; public SendOrderViewModel() { _api.SetToken(Session.Current.Token); Load(); } [RelayCommand] private void Refresh() => Load(); private void Load() { Drafts.Clear(); foreach (var d in DraftStore.All.OrderByDescending(x => x.CreatedAt)) Drafts.Add(d); TotalSum = Drafts.Sum(d => d.Total); Count = Drafts.Count; IsEmpty = Drafts.Count == 0; if (Selected is null || !Drafts.Contains(Selected)) Selected = Drafts.FirstOrDefault(); } /// Отправить одну накладную. [RelayCommand] private async Task SendAsync(DraftOrder? draft) { var d = draft ?? Selected; if (d is null) { Status = "Выберите накладную для отправки."; return; } Status = null; try { Busy = true; var resp = await CreateFromDraft(d); DraftStore.Remove(d.Id); Status = $"✓ Накладная {resp.GlobalSign ?? resp.OrderId} отправлена ({resp.ItemsCount} поз., {resp.TotalAmount:N2})."; } catch (Exception ex) { Status = "Ошибка отправки: " + ex.Message; } finally { Busy = false; Load(); } } /// Отправить все неотправленные накладные. [RelayCommand] private async Task SendAllAsync() { if (Drafts.Count == 0) { Status = "Нет неотправленных накладных."; return; } Status = null; int ok = 0; string? lastErr = null; try { Busy = true; foreach (var d in DraftStore.All.ToList()) { try { await CreateFromDraft(d); DraftStore.Remove(d.Id); ok++; } catch (Exception ex) { lastErr = ex.Message; } } } finally { Busy = false; Load(); } Status = lastErr is null ? $"✓ Отправлено накладных: {ok}." : $"Отправлено: {ok}. Не удалось часть — {lastErr}"; } /// Удалить неотправленную накладную (не отправляя). [RelayCommand] private void Delete(DraftOrder? draft) { var d = draft ?? Selected; if (d is null) return; DraftStore.Remove(d.Id); Load(); Status = "Накладная удалена."; } private async Task CreateFromDraft(DraftOrder d) { var req = new BuyerOrderCreateRequest { // Номер EX резервировался при сохранении черновика — используем его. 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() }; return await _api.CreateOrderAsync(req); } }