Раздел переделан: вместо поиска по прайсу и корзины с наименованиями — список неотправленных накладных (черновиков) и кнопка «Отправить все» (плюс отправка по одной). Отправка создаёт реальный заказ у поставщика и убирает черновик. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
128 lines
4.6 KiB
C#
128 lines
4.6 KiB
C#
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);
|
||
}
|
||
}
|