elfisa-pharmacy/src/Elfisa.Avalonia/ViewModels/SendOrderViewModel.cs
Exest 124a891025 Отправить: отправка неотправленных накладных (из Заказы), без поиска/наименований
Раздел переделан: вместо поиска по прайсу и корзины с наименованиями — список
неотправленных накладных (черновиков) и кнопка «Отправить все» (плюс отправка
по одной). Отправка создаёт реальный заказ у поставщика и убирает черновик.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-11 13:41:34 +03:00

128 lines
4.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// Отправить — отправка НЕОТПРАВЛЕННЫХ накладных (черновиков заказов из раздела
/// «Заказы»). Список готовых накладных, кнопка «Отправить» (создаёт реальный заказ
/// у поставщика). Без поиска по прайсу и наименований — только сами накладные.
/// </summary>
public partial class SendOrderViewModel : ViewModelBase
{
private readonly ApiClient _api = new();
/// <summary>Неотправленные накладные (черновики).</summary>
public ObservableCollection<DraftOrder> 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();
}
/// <summary>Отправить одну накладную.</summary>
[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(); }
}
/// <summary>Отправить все неотправленные накладные.</summary>
[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}";
}
/// <summary>Удалить неотправленную накладную (не отправляя).</summary>
[RelayCommand]
private void Delete(DraftOrder? draft)
{
var d = draft ?? Selected;
if (d is null) return;
DraftStore.Remove(d.Id);
Load();
Status = "Накладная удалена.";
}
private async Task<BuyerOrderResponse> 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);
}
}