| | | 1 | | namespace Services.AiAssistant; |
| | | 2 | | |
| | | 3 | | /// <summary>Критерии гибкого поиска заказов (tool orders_filter).</summary> |
| | | 4 | | public sealed class AiOrderFilterCriteria |
| | | 5 | | { |
| | | 6 | | // ── Базовые ────────────────────────────────────────────────────────────── |
| | 149 | 7 | | public bool ActionableOnly { get; init; } |
| | 119 | 8 | | public bool OverdueOnly { get; init; } |
| | 119 | 9 | | public bool EmptyPrice { get; init; } |
| | 163 | 10 | | public bool IncludeArchived { get; init; } |
| | | 11 | | |
| | | 12 | | // ── Участники ───────────────────────────────────────────────────────────── |
| | 172 | 13 | | public string? OzonClientName { get; init; } |
| | 161 | 14 | | public string? SupplierName { get; init; } |
| | 113 | 15 | | public string? TransactionConductedBy { get; init; } |
| | 113 | 16 | | public string? ChangedByUser { get; init; } // orders_history.ChangedBy |
| | | 17 | | |
| | | 18 | | // ── Статусы ─────────────────────────────────────────────────────────────── |
| | 148 | 19 | | public string? AppStatusName { get; init; } |
| | 113 | 20 | | public string? ClientStatusName { get; init; } // ClientStatus (Ozon) |
| | 136 | 21 | | public bool? OnlyWithReturns { get; init; } // IsReturned = true |
| | | 22 | | |
| | | 23 | | // ── Товар ──────────────────────────────────────────────────────────────── |
| | 147 | 24 | | public string? Article { get; init; } |
| | 133 | 25 | | public string? ProductName { get; init; } |
| | 132 | 26 | | public string? ManufacturerName { get; init; } |
| | 132 | 27 | | public string? NewCategory { get; init; } |
| | 119 | 28 | | public int? MinQuantity { get; init; } |
| | 115 | 29 | | public int? MaxQuantity { get; init; } |
| | | 30 | | |
| | | 31 | | // ── Финансы ─────────────────────────────────────────────────────────────── |
| | 116 | 32 | | public decimal? PriceMin { get; init; } |
| | 114 | 33 | | public decimal? PriceMax { get; init; } |
| | 135 | 34 | | public decimal? ProfitMin { get; init; } |
| | 134 | 35 | | public decimal? ProfitMax { get; init; } |
| | 145 | 36 | | public bool? OnlyNegativeProfit { get; init; } // MinProfit < 0 |
| | 114 | 37 | | public decimal? PurchasePriceMax { get; init; } |
| | | 38 | | |
| | | 39 | | // ── Логистика ──────────────────────────────────────────────────────────── |
| | 168 | 40 | | public string? ShipmentWarehouseName { get; init; } |
| | 131 | 41 | | public string? DeliveryProviderName { get; init; } |
| | 131 | 42 | | public string? DeliveryName { get; init; } |
| | 132 | 43 | | public string? DeliveryCity { get; init; } |
| | 136 | 44 | | public bool? OnlyWithTrackingNumber { get; init; } |
| | | 45 | | |
| | | 46 | | // ── Даты ───────────────────────────────────────────────────────────────── |
| | 133 | 47 | | public DateTime? ShippingDateFrom { get; init; } |
| | 133 | 48 | | public DateTime? ShippingDateTo { get; init; } |
| | 114 | 49 | | public DateTime? ProcessingDateFrom { get; init; } |
| | 114 | 50 | | public DateTime? ProcessingDateTo { get; init; } |
| | 146 | 51 | | public int? LastMonths { get; init; } // ProcessingDate >= now - N months |
| | | 52 | | |
| | | 53 | | // ── История изменений ──────────────────────────────────────────────────── |
| | 113 | 54 | | public DateTime? ChangedFrom { get; init; } // orders_history.ChangedAt >= |
| | 113 | 55 | | public DateTime? ChangedTo { get; init; } // orders_history.ChangedAt <= |
| | 112 | 56 | | public string? FieldChangedName { get; init; } // ColumnName или ColumnDisplayName (contains) |
| | 112 | 57 | | public string? FieldChangedToValue { get; init; } // NewValue (contains) |
| | | 58 | | |
| | | 59 | | // ── Вычисляемые ────────────────────────────────────────────────────────── |
| | | 60 | | public bool HasCriteria => |
| | 15 | 61 | | ActionableOnly |
| | 15 | 62 | | || OverdueOnly |
| | 15 | 63 | | || EmptyPrice |
| | 15 | 64 | | || IncludeArchived |
| | 15 | 65 | | || MinQuantity.HasValue |
| | 15 | 66 | | || MaxQuantity.HasValue |
| | 15 | 67 | | || OnlyNegativeProfit == true |
| | 15 | 68 | | || OnlyWithReturns == true |
| | 15 | 69 | | || OnlyWithTrackingNumber == true |
| | 15 | 70 | | || PriceMin.HasValue || PriceMax.HasValue |
| | 15 | 71 | | || ProfitMin.HasValue || ProfitMax.HasValue |
| | 15 | 72 | | || PurchasePriceMax.HasValue |
| | 15 | 73 | | || ShippingDateFrom.HasValue || ShippingDateTo.HasValue |
| | 15 | 74 | | || ProcessingDateFrom.HasValue || ProcessingDateTo.HasValue |
| | 15 | 75 | | || LastMonths.HasValue |
| | 15 | 76 | | || ChangedFrom.HasValue || ChangedTo.HasValue |
| | 15 | 77 | | || !string.IsNullOrWhiteSpace(OzonClientName) |
| | 15 | 78 | | || !string.IsNullOrWhiteSpace(SupplierName) |
| | 15 | 79 | | || !string.IsNullOrWhiteSpace(TransactionConductedBy) |
| | 15 | 80 | | || !string.IsNullOrWhiteSpace(ChangedByUser) |
| | 15 | 81 | | || !string.IsNullOrWhiteSpace(AppStatusName) |
| | 15 | 82 | | || !string.IsNullOrWhiteSpace(ClientStatusName) |
| | 15 | 83 | | || !string.IsNullOrWhiteSpace(Article) |
| | 15 | 84 | | || !string.IsNullOrWhiteSpace(ProductName) |
| | 15 | 85 | | || !string.IsNullOrWhiteSpace(ManufacturerName) |
| | 15 | 86 | | || !string.IsNullOrWhiteSpace(NewCategory) |
| | 15 | 87 | | || !string.IsNullOrWhiteSpace(ShipmentWarehouseName) |
| | 15 | 88 | | || !string.IsNullOrWhiteSpace(DeliveryProviderName) |
| | 15 | 89 | | || !string.IsNullOrWhiteSpace(DeliveryName) |
| | 15 | 90 | | || !string.IsNullOrWhiteSpace(DeliveryCity) |
| | 15 | 91 | | || !string.IsNullOrWhiteSpace(FieldChangedName) |
| | 15 | 92 | | || !string.IsNullOrWhiteSpace(FieldChangedToValue); |
| | | 93 | | |
| | | 94 | | public string DescribeRu() |
| | | 95 | | { |
| | 0 | 96 | | var parts = new List<string>(); |
| | 0 | 97 | | if (ActionableOnly) parts.Add("актуальные (нефинальный AppStatus, не в архиве)"); |
| | 0 | 98 | | if (OverdueOnly) parts.Add("просроченные (дедлайн отгрузки прошёл)"); |
| | 0 | 99 | | if (IncludeArchived) parts.Add("включая архивные"); |
| | 0 | 100 | | if (EmptyPrice) parts.Add("пустая цена продажи"); |
| | 0 | 101 | | if (OnlyNegativeProfit == true) parts.Add("прибыль < 0"); |
| | 0 | 102 | | if (OnlyWithReturns == true) parts.Add("есть возврат"); |
| | 0 | 103 | | if (OnlyWithTrackingNumber == true) parts.Add("есть трек-номер"); |
| | | 104 | | |
| | 0 | 105 | | if (MinQuantity is > 0) parts.Add($"кол-во > {MinQuantity}"); |
| | 0 | 106 | | if (MaxQuantity is > 0) parts.Add($"кол-во ≤ {MaxQuantity}"); |
| | 0 | 107 | | if (PriceMin.HasValue) parts.Add($"цена ≥ {PriceMin:F0} ₽"); |
| | 0 | 108 | | if (PriceMax.HasValue) parts.Add($"цена ≤ {PriceMax:F0} ₽"); |
| | 0 | 109 | | if (ProfitMin.HasValue) parts.Add($"прибыль ≥ {ProfitMin:F0} ₽"); |
| | 0 | 110 | | if (ProfitMax.HasValue) parts.Add($"прибыль ≤ {ProfitMax:F0} ₽"); |
| | 0 | 111 | | if (PurchasePriceMax.HasValue) parts.Add($"закупка ≤ {PurchasePriceMax:F0} ₽"); |
| | | 112 | | |
| | 0 | 113 | | if (!string.IsNullOrWhiteSpace(SupplierName)) parts.Add($"поставщик «{SupplierName.Trim()}»"); |
| | 0 | 114 | | if (!string.IsNullOrWhiteSpace(OzonClientName)) parts.Add($"Ozon-клиент «{OzonClientName.Trim()}»"); |
| | 0 | 115 | | if (!string.IsNullOrWhiteSpace(AppStatusName)) parts.Add($"статус в отчёте «{AppStatusName.Trim()}»"); |
| | 0 | 116 | | if (!string.IsNullOrWhiteSpace(ClientStatusName)) parts.Add($"статус Ozon «{ClientStatusName.Trim()}»"); |
| | 0 | 117 | | if (!string.IsNullOrWhiteSpace(Article)) parts.Add($"артикул «{Article.Trim()}»"); |
| | 0 | 118 | | if (!string.IsNullOrWhiteSpace(ProductName)) parts.Add($"товар «{ProductName.Trim()}»"); |
| | 0 | 119 | | if (!string.IsNullOrWhiteSpace(ManufacturerName)) parts.Add($"производитель «{ManufacturerName.Trim()}»"); |
| | 0 | 120 | | if (!string.IsNullOrWhiteSpace(NewCategory)) parts.Add($"категория «{NewCategory.Trim()}»"); |
| | 0 | 121 | | if (!string.IsNullOrWhiteSpace(ShipmentWarehouseName)) parts.Add($"склад «{ShipmentWarehouseName.Trim()}»"); |
| | 0 | 122 | | if (!string.IsNullOrWhiteSpace(DeliveryProviderName)) parts.Add($"провайдер «{DeliveryProviderName.Trim()}»"); |
| | 0 | 123 | | if (!string.IsNullOrWhiteSpace(DeliveryName)) parts.Add($"тип доставки «{DeliveryName.Trim()}»"); |
| | 0 | 124 | | if (!string.IsNullOrWhiteSpace(DeliveryCity)) parts.Add($"город «{DeliveryCity.Trim()}»"); |
| | 0 | 125 | | if (!string.IsNullOrWhiteSpace(TransactionConductedBy)) parts.Add($"транзакцию провёл «{TransactionConductedBy.T |
| | | 126 | | |
| | 0 | 127 | | if (!string.IsNullOrWhiteSpace(ChangedByUser)) parts.Add($"изменял «{ChangedByUser.Trim()}»"); |
| | 0 | 128 | | if (!string.IsNullOrWhiteSpace(FieldChangedName)) parts.Add($"поле «{FieldChangedName.Trim()}» менялось"); |
| | 0 | 129 | | if (!string.IsNullOrWhiteSpace(FieldChangedToValue)) parts.Add($"новое значение «{FieldChangedToValue.Trim()}»") |
| | | 130 | | |
| | 0 | 131 | | if (LastMonths.HasValue) parts.Add($"за последние {LastMonths} мес."); |
| | 0 | 132 | | if (ShippingDateFrom.HasValue) parts.Add($"отгрузка с {ShippingDateFrom:dd.MM.yyyy}"); |
| | 0 | 133 | | if (ShippingDateTo.HasValue) parts.Add($"отгрузка по {ShippingDateTo:dd.MM.yyyy}"); |
| | 0 | 134 | | if (ProcessingDateFrom.HasValue) parts.Add($"принят с {ProcessingDateFrom:dd.MM.yyyy}"); |
| | 0 | 135 | | if (ProcessingDateTo.HasValue) parts.Add($"принят по {ProcessingDateTo:dd.MM.yyyy}"); |
| | 0 | 136 | | if (ChangedFrom.HasValue) parts.Add($"изменён с {ChangedFrom:dd.MM.yyyy}"); |
| | 0 | 137 | | if (ChangedTo.HasValue) parts.Add($"изменён по {ChangedTo:dd.MM.yyyy}"); |
| | | 138 | | |
| | 0 | 139 | | return parts.Count == 0 ? "активные заказы" : string.Join("; ", parts); |
| | | 140 | | } |
| | | 141 | | } |