elfisa-pharmacy/src/Elfisa.Avalonia/ViewModels/OrdersViewModel.cs
Exest 132ce1531f Avalonia: верхняя навигация (как в WinForms) + раздел «Заказы»
- Навигация перенесена из левого сайдбара в ВЕРХНЮЮ горизонтальную
  панель, как в исходной программе: логотип слева, вкладки
  (иконка+подпись) по центру, пользователь+Выйти справа
- Раздел «Заказы»: мастер-детали (список слева, состав заказа справа
  с позициями и итогом), на данных /api/buyer/report
- Числовые колонки выровнены вправо (стиль DataGridCell.num)
- Отчёты: тулбар на WrapPanel, стабильные ширины колонок

Проверено запуском (скриншоты): верхняя навигация, отчёты, заказы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 10:00:57 +03:00

100 lines
3.4 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;
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 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<OrderItemRow> Items { get; init; } = new();
}
/// <summary>
/// Заказы: список + состав. Пока строится из /api/buyer/report (он работает);
/// после деплоя фикса /api/buyer/orders можно перейти на «родной» эндпоинт
/// (даст ещё PlacedAt, Comment, отмену/размещение).
/// </summary>
public partial class OrdersViewModel : ViewModelBase
{
private readonly ApiClient _api = new();
public ObservableCollection<OrderSummary> 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;
var to = DateTime.Today;
var from = to.AddMonths(-24);
var lines = await _api.GetBuyerReportAsync(from, to);
Orders.Clear();
foreach (var g in lines.GroupBy(l => l.OrderId)
.OrderByDescending(x => x.First().OrderDate ?? DateTime.MinValue))
{
var f = g.First();
var items = new ObservableCollection<OrderItemRow>(
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();
if (Orders.Count == 0) Status = "Заказов за последние 2 года нет.";
}
catch (Exception ex) { Status = ex.Message; }
finally { Busy = false; }
}
}