| | | 1 | | namespace OzonOrdersWeb.WebServices.SystemAlerts; |
| | | 2 | | |
| | | 3 | | public sealed class SystemAlertsOptions |
| | | 4 | | { |
| | | 5 | | public const string SectionName = "SystemAlerts"; |
| | 323 | 6 | | public int AnalysisWindowHours { get; set; } = 24; |
| | | 7 | | |
| | | 8 | | /// <summary>Окно актуальности по ключу алерта (например <c>onec-posting</c>), часы; без записи берётся <see cref="A |
| | 245 | 9 | | public Dictionary<string, int> SourceWindowHours { get; set; } = |
| | 106 | 10 | | new(StringComparer.OrdinalIgnoreCase) |
| | 106 | 11 | | { |
| | 106 | 12 | | ["ozon-cancelled-supplier-live"] = 72, |
| | 106 | 13 | | ["orders-null-reset"] = 1, |
| | 106 | 14 | | ["posted-cost-lost"] = 24 |
| | 106 | 15 | | }; |
| | | 16 | | |
| | | 17 | | /// <summary>Записи без верхней границы окна (зависшие Running/Received, просрочки) старше этого срока не считаются. |
| | 120 | 18 | | public int RecordMaxAgeDays { get; set; } = 3; |
| | | 19 | | |
| | | 20 | | /// <summary>Если самая свежая ошибка старше этого срока, критичность журнального алерта снижается до предупреждения |
| | 110 | 21 | | public int DangerFreshnessHours { get; set; } = 6; |
| | | 22 | | |
| | | 23 | | public int WindowHoursFor(string key) => |
| | 244 | 24 | | Math.Max(1, SourceWindowHours.TryGetValue(key, out var hours) && hours > 0 ? hours : AnalysisWindowHours); |
| | 136 | 25 | | public int DangerFailureCount { get; set; } = 2; |
| | 126 | 26 | | public int SuccessMaxAgeMinutes { get; set; } = 120; |
| | 120 | 27 | | public int PendingWebhookMaxAgeMinutes { get; set; } = 15; |
| | 120 | 28 | | public int MaxPendingWebhooks { get; set; } = 1; |
| | 134 | 29 | | public int RunningJobMaxAgeMinutes { get; set; } = 120; |
| | 120 | 30 | | public int MaxStuckJobs { get; set; } = 1; |
| | 120 | 31 | | public int MaxOverdueOrderControlTasks { get; set; } = 1; |
| | 108 | 32 | | public int OzonNewOrdersMaxAgeHours { get; set; } = 24; |
| | 108 | 33 | | public int OzonNewOrdersDangerAgeHours { get; set; } = 48; |
| | | 34 | | |
| | | 35 | | /// <summary>Сколько проверок подряд должна наблюдаться проблема, прежде чем «состоянческий» алерт откроется.</summa |
| | 155 | 36 | | public int ConfirmationChecks { get; set; } = 2; |
| | 109 | 37 | | public int MaxMuteHours { get; set; } = 168; |
| | | 38 | | |
| | | 39 | | /// <summary>Минимальный интервал между проверками, учитываемыми для debounce: ручные обновления не «подтверждают» а |
| | 121 | 40 | | public int ConfirmationMinGapSeconds { get; set; } = 120; |
| | | 41 | | |
| | | 42 | | /// <summary>Не чаще одного ручного пересчёта алертов (кнопка обновления на вкладке) за этот интервал.</summary> |
| | 106 | 43 | | public int ManualRefreshMinIntervalSeconds { get; set; } = 20; |
| | | 44 | | |
| | | 45 | | /// <summary>Кэш счётчиков для чипов в шапке страниц.</summary> |
| | 108 | 46 | | public int CountsCacheSeconds { get; set; } = 15; |
| | | 47 | | |
| | | 48 | | // ---------- Заказы у поставщиков ---------- |
| | | 49 | | |
| | 132 | 50 | | public bool SupplierChecksEnabled { get; set; } = true; |
| | | 51 | | |
| | | 52 | | /// <summary>Заказы старше этого срока не анализируются: у поставщиков они давно закрыты, их «просрочка» — шум.</sum |
| | 126 | 53 | | public int SupplierOrderMaxAgeDays { get; set; } = 14; |
| | | 54 | | |
| | | 55 | | /// <summary> |
| | | 56 | | /// Автоотмена у поставщика заказов из алерта <c>ozon-cancelled-supplier-live</c>. При false заказы только |
| | | 57 | | /// уходят в Telegram (тема General) с подсказкой, что отменить вручную. |
| | | 58 | | /// </summary> |
| | 110 | 59 | | public bool SupplierAutoCancelEnabled { get; set; } = true; |
| | | 60 | | |
| | | 61 | | /// <summary>Провайдеры, у которых API умеет отмену и она подключена; остальным — «отменить вручную».</summary> |
| | 4 | 62 | | public string[] SupplierAutoCancelProviders { get; set; } = |
| | 106 | 63 | | [ |
| | 106 | 64 | | "ZZapMoscow", "ForumAuto", "ForumAutoInterparts", "ForumAutoPiter", "ForumAutoRostov", "ForumAutoIstra", "Armtek |
| | 106 | 65 | | ]; |
| | | 66 | | |
| | | 67 | | /// <summary>Кого упоминать в сообщении об отменённых в Ozon заказах (<c>@username</c>). Bot API не умеет «упомянуть |
| | 111 | 68 | | public string[] SupplierCancelMentions { get; set; } = ["@Burn1ngSnow"]; |
| | | 69 | | |
| | | 70 | | /// <summary>Позиция лежит в корзине поставщика и не оформлена дольше этого срока (часы).</summary> |
| | 127 | 71 | | public int SupplierCartStaleHours { get; set; } = 12; |
| | | 72 | | |
| | | 73 | | /// <summary>Допуск после ожидаемой даты поставки, прежде чем считать заказ просроченным (часы).</summary> |
| | 126 | 74 | | public int SupplierDeliveryGraceHours { get; set; } = 24; |
| | | 75 | | |
| | | 76 | | /// <summary>Статус открытого заказа у поставщика не менялся дольше этого срока (дни).</summary> |
| | 127 | 77 | | public int SupplierStatusStaleDays { get; set; } = 5; |
| | | 78 | | |
| | | 79 | | /// <summary>Сколько отказов одного поставщика за окно считаются критичными.</summary> |
| | 112 | 80 | | public int SupplierRejectedDangerCount { get; set; } = 3; |
| | | 81 | | |
| | | 82 | | /// <summary>Сколько строк без статуса у одного поставщика считаются критичными («слепая зона»).</summary> |
| | 109 | 83 | | public int SupplierBlindDangerCount { get; set; } = 5; |
| | | 84 | | |
| | | 85 | | /// <summary> |
| | | 86 | | /// Основы слов в названии статуса Ozon: заказ уже доставлен. Основы без первой буквы, чтобы совпадать |
| | | 87 | | /// независимо от регистра («Доставлен», «доставлен», «Получен», «Заказ выполнен»). |
| | | 88 | | /// </summary> |
| | 252 | 89 | | public string[] OzonDeliveredStatusKeywords { get; set; } = ["оставлен", "олучен", "ыполнен"]; |
| | | 90 | | |
| | | 91 | | /// <summary>Основы слов в названии статуса Ozon: заказ отменён («Отменён», «Отменен при доставке»...).</summary> |
| | 226 | 92 | | public string[] OzonCancelledStatusKeywords { get; set; } = ["тмен"]; |
| | | 93 | | |
| | | 94 | | /// <summary>Признаки отказа в названии или коде статуса поставщика (без учёта регистра).</summary> |
| | 39 | 95 | | public string[] SupplierRejectedKeywords { get; set; } = |
| | 106 | 96 | | [ |
| | 106 | 97 | | "отказ", "отклон", "нет в наличии", "аннулир", "отмен", "не выполнен", "снят с резерва", "обнулен", |
| | 106 | 98 | | "не зарезервирован", "не соответствует", "заблокирован", "что-то не так" |
| | 106 | 99 | | ]; |
| | | 100 | | |
| | | 101 | | /// <summary>Исключения из <see cref="SupplierRejectedKeywords"/>: отмена с нашей стороны отказом поставщика не явля |
| | 123 | 102 | | public string[] SupplierRejectedExcludeKeywords { get; set; } = ["покупателем"]; |
| | | 103 | | |
| | | 104 | | /// <summary>Признаки выполненного заказа: такие статусы не считаются просроченными и «зависшими».</summary> |
| | 23 | 105 | | public string[] SupplierDeliveredKeywords { get; set; } = |
| | 106 | 106 | | ["закрыт", "выдан", "отгружен", "получен", "выполнен", "выкуплен", "доставлен", "архив"]; |
| | | 107 | | |
| | | 108 | | /// <summary>Коды статусов-отказов по провайдеру там, где у статуса нет понятного названия («Код 6»).</summary> |
| | 42 | 109 | | public Dictionary<string, string[]> SupplierRejectedStatusCodes { get; set; } = |
| | 106 | 110 | | new(StringComparer.OrdinalIgnoreCase) { ["MlAuto"] = ["6"], ["MlAutoRu"] = ["6"] }; |
| | | 111 | | |
| | | 112 | | /// <summary>Коды статусов «отгружен/выдан» по провайдеру.</summary> |
| | 41 | 113 | | public Dictionary<string, string[]> SupplierDeliveredStatusCodes { get; set; } = |
| | 106 | 114 | | new(StringComparer.OrdinalIgnoreCase) { ["MlAuto"] = ["14"], ["MlAutoRu"] = ["14"] }; |
| | | 115 | | |
| | | 116 | | // ---------- Ozon и заказы ---------- |
| | | 117 | | |
| | 116 | 118 | | public bool OrderChecksEnabled { get; set; } = true; |
| | | 119 | | |
| | | 120 | | /// <summary>Окно актуальности ошибок 1С и транзакций по заказу для значка в сетках (часы).</summary> |
| | 111 | 121 | | public int OrderProblemWindowHours { get; set; } = 72; |
| | | 122 | | |
| | | 123 | | /// <summary>Отправление без обработки: предупреждение за столько часов до дедлайна отгрузки.</summary> |
| | 118 | 124 | | public int SlaWarningHours { get; set; } = 12; |
| | | 125 | | |
| | | 126 | | /// <summary>Критично, если до дедлайна отгрузки осталось меньше этого срока или он уже прошёл.</summary> |
| | 110 | 127 | | public int SlaDangerHours { get; set; } = 3; |
| | | 128 | | |
| | | 129 | | /// <summary>Просрочку старше этого срока не показываем: отправление давно решено вручную.</summary> |
| | 116 | 130 | | public int SlaOverdueMaxHours { get; set; } = 48; |
| | | 131 | | |
| | | 132 | | /// <summary>Названия статусов заказа в приложении, означающие «ещё не обработан».</summary> |
| | 116 | 133 | | public string[] SlaUnhandledAppStatusNames { get; set; } = ["Не указан"]; |
| | | 134 | | |
| | 116 | 135 | | public int CancelSpikeMinCount { get; set; } = 10; |
| | 108 | 136 | | public int CancelSpikeFactor { get; set; } = 3; |
| | | 137 | | |
| | | 138 | | /// <summary>Сколько сбросов ключевых полей заказа в NULL за окно считаются критичными.</summary> |
| | 107 | 139 | | public int NullResetDangerCount { get; set; } = 3; |
| | | 140 | | |
| | | 141 | | /// <summary>Сколько проведённых заказов без расчёта себестоимости считаются критичными.</summary> |
| | 108 | 142 | | public int PostedCostLostDangerCount { get; set; } = 3; |
| | | 143 | | |
| | | 144 | | /// <summary>Сколько убыточных проведённых заказов за окно стоит показать.</summary> |
| | 116 | 145 | | public int PostedLossMinCount { get; set; } = 3; |
| | | 146 | | |
| | | 147 | | // ---------- Остатки и 1С ---------- |
| | | 148 | | |
| | 114 | 149 | | public bool StockChecksEnabled { get; set; } = true; |
| | 114 | 150 | | public int BitrixAutoScheduleOverdueMinutes { get; set; } = 30; |
| | 114 | 151 | | public int PushZeroingMinItems { get; set; } = 50; |
| | 108 | 152 | | public int PushZeroingSharePercent { get; set; } = 60; |
| | 108 | 153 | | public int WarehouseStockStaleHours { get; set; } = 3; |
| | 114 | 154 | | public bool OneCProbeEnabled { get; set; } = true; |
| | 108 | 155 | | public int OneCProbeIntervalMinutes { get; set; } = 10; |
| | 108 | 156 | | public int OneCProbeSlowMs { get; set; } = 5000; |
| | 108 | 157 | | public int OneCProbeTimeoutSeconds { get; set; } = 20; |
| | | 158 | | |
| | 106 | 159 | | public bool HangfireChecksEnabled { get; set; } = true; |
| | 106 | 160 | | public int HangfireRecurringOverdueMinutes { get; set; } = 10; |
| | | 161 | | |
| | 106 | 162 | | public bool DiskChecksEnabled { get; set; } = true; |
| | 108 | 163 | | public int DiskFreePercentWarning { get; set; } = 15; |
| | 110 | 164 | | public int DiskFreePercentDanger { get; set; } = 7; |
| | 108 | 165 | | public int DiskFreeGbDanger { get; set; } = 5; |
| | | 166 | | |
| | 106 | 167 | | public bool ElasticsearchChecksEnabled { get; set; } = true; |
| | 106 | 168 | | public int ElasticsearchTimeoutSeconds { get; set; } = 5; |
| | 106 | 169 | | public int ElasticsearchDiskFreePercentWarning { get; set; } = 15; |
| | 106 | 170 | | public int ElasticsearchDiskFreePercentDanger { get; set; } = 10; |
| | 0 | 171 | | public bool ElasticsearchYellowIsWarning { get; set; } |
| | 106 | 172 | | public int OrderSearchDriftDangerMultiplier { get; set; } = 5; |
| | 106 | 173 | | public int OrderSearchDriftCheckStaleHours { get; set; } = 6; |
| | | 174 | | |
| | 106 | 175 | | public bool DatabaseChecksEnabled { get; set; } = true; |
| | 106 | 176 | | public int DatabaseLatencyWarningMs { get; set; } = 500; |
| | 106 | 177 | | public int DatabaseLatencyDangerMs { get; set; } = 2000; |
| | 106 | 178 | | public int DatabaseConnectionsWarningPercent { get; set; } = 80; |
| | 106 | 179 | | public int DatabaseConnectionsDangerPercent { get; set; } = 95; |
| | | 180 | | } |