| | | 1 | | using System.Linq.Expressions; |
| | | 2 | | using OzonDomains.Models; |
| | | 3 | | |
| | | 4 | | namespace OzonOrdersWeb.WebServices.Orders.Grid; |
| | | 5 | | |
| | | 6 | | /// <summary> |
| | | 7 | | /// Сортировка по нескольким столбцам (Shift+клик в гриде) и внутри группы: общий конвейер умеет один |
| | | 8 | | /// <c>OrderSortState</c>, поэтому цепочка OrderBy/ThenBy строится здесь. Ключи повторяют <c>OrderSortManager</c>. |
| | | 9 | | /// </summary> |
| | | 10 | | public static class OrdersGridSorting |
| | | 11 | | { |
| | 15 | 12 | | public sealed record SortItem(string ColId, bool Descending); |
| | | 13 | | |
| | 1 | 14 | | private static readonly Dictionary<string, LambdaExpression> Keys = new(StringComparer.OrdinalIgnoreCase) |
| | 1 | 15 | | { |
| | 1 | 16 | | ["shipmentNumber"] = Key(o => o.ShipmentNumber), |
| | 1 | 17 | | ["scanit"] = Key(o => o.Scanit), |
| | 1 | 18 | | ["deliveryProvider"] = Key(o => o.Delivery != null && o.Delivery.Provider != null ? o.Delivery.Provider.Name : n |
| | 1 | 19 | | ["ozonClient"] = Key(o => o.OzonClient != null ? o.OzonClient.Name : null), |
| | 1 | 20 | | ["deliveryCity"] = Key(o => o.DeliveryCity), |
| | 1 | 21 | | ["processingDate"] = Key(o => o.ProcessingDate), |
| | 1 | 22 | | ["shippingDate"] = Key(o => o.ShippingDate), |
| | 1 | 23 | | ["deliveryPeriod"] = Key(o => o.DeliveryPeriod), |
| | 1 | 24 | | ["timeLeftDays"] = Key(o => o.ShippingDate), |
| | 1 | 25 | | ["article"] = Key(o => o.ProductKey), |
| | 1 | 26 | | ["manufacturer"] = Key(o => o.EtProducer != null ? o.EtProducer.Name : null), |
| | 1 | 27 | | ["productName"] = Key(o => o.ProductName), |
| | 1 | 28 | | ["clientStatus"] = Key(o => o.ClientStatus != null ? o.ClientStatus.Name : null), |
| | 1 | 29 | | ["appStatus"] = Key(o => o.AppStatus != null ? o.AppStatus.Name : null), |
| | 1 | 30 | | ["shipmentWarehouse"] = Key(o => o.ShipmentWarehouse != null ? o.ShipmentWarehouse.Name : null), |
| | 1 | 31 | | ["lastStatusChangeDate"] = Key(o => o.LastStatusChangeDate), |
| | 1 | 32 | | ["supplier"] = Key(o => o.Supplier != null ? o.Supplier.Name : null), |
| | 1 | 33 | | ["orderNumberToSupplier"] = Key(o => o.OrderNumberToSupplier), |
| | 1 | 34 | | ["category"] = Key(o => o.NewCategory), |
| | 1 | 35 | | ["volumetricWeight"] = Key(o => o.ProductInfo != null ? o.ProductInfo.VolumetricWeight : null), |
| | 1 | 36 | | ["sitePrice"] = Key(o => o.ProductInfo != null ? o.ProductInfo.CurrentPriceWithDiscount : null), |
| | 1 | 37 | | ["quantity"] = Key(o => o.Quantity), |
| | 1 | 38 | | ["price"] = Key(o => o.Price), |
| | 1 | 39 | | ["shipmentAmount"] = Key(o => o.ShipmentAmount), |
| | 1 | 40 | | ["purchasePrice"] = Key(o => o.PurchasePrice), |
| | 1 | 41 | | ["costPrice"] = Key(o => o.CostPrice), |
| | 1 | 42 | | ["ozonCommission"] = Key(o => o.MinOzonCommission), |
| | 1 | 43 | | ["ozonCommissionMax"] = Key(o => o.MaxOzonCommission), |
| | 1 | 44 | | ["profit"] = Key(o => o.MinProfit), |
| | 1 | 45 | | ["discount"] = Key(o => o.MinDiscount) |
| | 1 | 46 | | }; |
| | | 47 | | |
| | 30 | 48 | | private static LambdaExpression Key<TKey>(Expression<Func<Order, TKey>> key) => key; |
| | | 49 | | |
| | 3 | 50 | | public static bool Supports(string colId) => Keys.ContainsKey(colId); |
| | | 51 | | |
| | | 52 | | /// <summary> |
| | | 53 | | /// Добавляет сортировки к запросу: если он уже упорядочен (<paramref name="alreadyOrdered"/>) — как ThenBy, |
| | | 54 | | /// иначе первая становится OrderBy. Неизвестные столбцы пропускаются. Проверять тип на |
| | | 55 | | /// <see cref="IOrderedQueryable{T}"/> нельзя: EF Core и EnumerableQuery реализуют его всегда. |
| | | 56 | | /// </summary> |
| | | 57 | | public static IQueryable<Order> Apply(IQueryable<Order> query, IReadOnlyList<SortItem> sorts, bool alreadyOrdered, o |
| | | 58 | | Func<string, LambdaExpression?>? resolveExtra = null) |
| | | 59 | | { |
| | 3 | 60 | | ordered = alreadyOrdered; |
| | 12 | 61 | | foreach (var sort in sorts) |
| | | 62 | | { |
| | 3 | 63 | | if (!Keys.TryGetValue(sort.ColId, out var key)) |
| | | 64 | | { |
| | | 65 | | // Вычисляемые столбцы: ключ — переведённая формула пользователя. |
| | 0 | 66 | | key = resolveExtra?.Invoke(sort.ColId); |
| | 0 | 67 | | if (key is null) continue; |
| | | 68 | | } |
| | 3 | 69 | | query = ApplyOne(query, key, sort.Descending, ordered); |
| | 3 | 70 | | ordered = true; |
| | | 71 | | } |
| | | 72 | | |
| | 3 | 73 | | return query; |
| | | 74 | | } |
| | | 75 | | |
| | | 76 | | private static IOrderedQueryable<Order> ApplyOne(IQueryable<Order> query, LambdaExpression key, bool descending, boo |
| | | 77 | | { |
| | 3 | 78 | | var name = then ? (descending ? nameof(Queryable.ThenByDescending) : nameof(Queryable.ThenBy)) |
| | 3 | 79 | | : (descending ? nameof(Queryable.OrderByDescending) : nameof(Queryable.OrderBy)); |
| | 3 | 80 | | var call = Expression.Call(typeof(Queryable), name, [typeof(Order), key.ReturnType], query.Expression, Expressio |
| | 3 | 81 | | return (IOrderedQueryable<Order>)query.Provider.CreateQuery<Order>(call); |
| | | 82 | | } |
| | | 83 | | } |