< Summary

Information
Class: OzonDomains.Models.Order
Assembly: OzonDomains
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonDomains/Models/Order.cs
Line coverage
70%
Covered lines: 161
Uncovered lines: 66
Coverable lines: 227
Total lines: 858
Line coverage: 70.9%
Branch coverage
67%
Covered branches: 67
Total branches: 100
Branch coverage: 67%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Id()100%11100%
get_Key()100%11100%
get_ShipmentNumber()100%11100%
get_TrackingNumber()100%11100%
get_Scanit()100%11100%
get_ShipmentId()100%11100%
get_ShipmentNumberTrimmed()100%88100%
set_ShipmentNumberTrimmed(...)100%210%
get_ProcessingDate()100%11100%
get_ShippingDate()100%11100%
get_DeliveryPeriod()100%44100%
set_DeliveryPeriod(...)100%210%
get_TimeLeft()100%22100%
set_TimeLeft(...)100%210%
get_TimeLeftDay()100%22100%
set_TimeLeftDay(...)100%210%
get_FormattedTimeLeftDay()50%2266.66%
set_FormattedTimeLeftDay(...)100%210%
get_DeliveryPeriodDay()100%22100%
set_DeliveryPeriodDay(...)100%210%
get_DeliveryPeriodHour()50%2266.66%
set_DeliveryPeriodHour(...)100%210%
get_FormattedDeliveryPeriod()50%3250%
set_FormattedDeliveryPeriod(...)100%210%
get_FormattedDeliveryDay()50%3250%
set_FormattedDeliveryDay(...)100%210%
get_FormattedDeliveryHours()50%3250%
set_FormattedDeliveryHours(...)100%210%
get_FormattedProcessingDate()100%11100%
set_FormattedProcessingDate(...)100%210%
get_FormattedProcessingTime()25%44100%
set_FormattedProcessingTime(...)100%210%
get_FullFormattedProcessingDate()100%22100%
set_FullFormattedProcessingDate(...)100%210%
get_FormattedShippingDate()100%11100%
set_FormattedShippingDate(...)100%210%
get_FormattedShippingTime()25%44100%
set_FormattedShippingTime(...)100%210%
get_FullFormattedShippingDate()50%22100%
set_FullFormattedShippingDate(...)100%210%
get_ClientStatusId()100%11100%
get_ClientStatus()100%11100%
get_Status()100%22100%
set_Status(...)100%210%
get_AppStatusId()100%11100%
get_AppStatus()100%11100%
get_LastStatusChangeDate()100%11100%
get_FormattedLastStatusChangeDate()100%11100%
set_FormattedLastStatusChangeDate(...)100%210%
get_FullFormattedLastStatusChangeDate()25%44100%
set_FullFormattedLastStatusChangeDate(...)100%210%
get_ShipmentAmount()100%11100%
get_TargetShipmentProfit135()100%1010100%
set_TargetShipmentProfit135(...)100%210%
get_ProductName()100%11100%
get_ProductKey()100%11100%
get_Article()100%11100%
get_CleanedArticle()75%44100%
set_CleanedArticle(...)100%11100%
get_ManufacturerId()100%11100%
get_Manufacturer()100%11100%
get_EtProducerId()100%11100%
get_EtProducer()100%11100%
get_Price()100%11100%
get_Quantity()100%11100%
get_TrueQuantity()100%22100%
set_TrueQuantity(...)100%11100%
ApplyProductKeyMultiplier(...)100%44100%
get_ShipmentWarehouseId()100%11100%
get_ShipmentWarehouse()100%11100%
get_СurrencyId()100%11100%
get_Сurrency()100%11100%
get_SupplierId()100%11100%
get_Supplier()100%11100%
get_OrderNumberToSupplier()100%11100%
get_PurchasePrice()100%11100%
get_OriginalPurchasePrice()100%11100%
get_ProductInfoId()100%11100%
get_ProductInfo()100%11100%
get_MinOzonCommission()100%11100%
get_MaxOzonCommission()100%11100%
get_MaxCommissionInfo()100%11100%
get_MinCommissionInfo()100%11100%
get_MinProfit()100%11100%
get_MaxProfit()100%11100%
get_MinDiscount()100%11100%
get_MaxDiscount()100%11100%
get_CostPrice()100%11100%
get_DeliveryCity()100%11100%
get_NewCategory()100%11100%
get_IsVerified()100%11100%
get_IsAccepted()100%11100%
get_Comment()100%11100%
get_UpdatedColumns()100%11100%
get_UpdatedBy()100%11100%
get_UpdatedAt()100%11100%
get_IsReturnable()100%11100%
get_TransactionId()100%11100%
get_OzonClientId()100%11100%
get_OzonClient()100%11100%
get_LatestOzonPostingCancellation()100%11100%
get_FromFiletId()100%11100%
get_FromFile()100%11100%
get_ExcelFileDataId()100%11100%
get_ExcelFileData()100%11100%
get_NumberInExcel()100%11100%
get_CartItemId()100%11100%
get_CartItemStatus()100%11100%
get_CartItemStatusColor()100%11100%
get_DeliveryId()100%11100%
get_Delivery()100%11100%
get_OrderArchive()100%11100%
get_IsReturned()100%11100%
get_ReturnLogisticBarcode()100%11100%
get_ReturnStatusSysName()100%11100%
get_ReturnStatusDisplayName()100%11100%
get_ReturnWarehouseName()100%11100%
get_ReturnStatusChangeDate()100%11100%
get_FormattedReturnStatusChangeDate()100%11100%
set_FormattedReturnStatusChangeDate(...)100%210%
get_FullFormattedReturnStatusChangeDate()50%22100%
set_FullFormattedReturnStatusChangeDate(...)100%210%
get_SupplierStateProviderKey()100%11100%
get_SupplierStateSupplierName()100%11100%
get_SupplierStateStage()100%11100%
get_Problems()100%11100%
get_SupplierStatusName()100%11100%
get_SupplierStatusColor()100%11100%
get_SupplierStateExternalOrderNumber()100%11100%
get_SupplierStateChangedAt()100%11100%
get_SupplierStateDeliveryDaysMin()100%11100%
get_SupplierStateDeliveryDaysMax()100%11100%
get_SupplierStateOrderedAt()100%11100%
get_SupplierStateCartCreatedAt()100%11100%
get_SupplierStateDirection()100%11100%
get_SupplierExpectedDeliveryDate()78.57%141490%
set_SupplierExpectedDeliveryDate(...)100%210%
get_SupplierExpectedDeliveryTimeLeft()100%22100%
set_SupplierExpectedDeliveryTimeLeft(...)100%210%
get_FormattedSupplierExpectedDeliveryDate()100%11100%
set_FormattedSupplierExpectedDeliveryDate(...)100%210%
get_FullFormattedSupplierExpectedDeliveryDate()50%22100%
set_FullFormattedSupplierExpectedDeliveryDate(...)100%210%
get_FormattedSupplierExpectedDeliveryDaysLeft()100%22100%
set_FormattedSupplierExpectedDeliveryDaysLeft(...)100%210%
get_OrderPrice()100%11100%
get_OzonPromotionSnapshot()100%11100%
get_ExtraExpenses()100%11100%
get_OrderExtensions()100%11100%
Clone()0%156120%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonDomains/Models/Order.cs

#LineLine coverage
 1using System.ComponentModel.DataAnnotations;
 2using System.ComponentModel.DataAnnotations.Schema;
 3using System.Reflection;
 4using OzonDomains.Models.OrderCarts;
 5using OzonDomains.Models.SupplierStatuses;
 6
 7namespace OzonDomains.Models
 8{
 9    /// <summary>
 10    /// Модель заказа из маркетплейса Ozon.
 11    /// Содержит полную информацию о заказе: идентификаторы, даты, стоимость,
 12    /// статусы, связанные сущности (поставщик, склад, клиент) и вычисляемые свойства.
 13    /// </summary>
 14    public class Order
 15    {
 16        /// <summary>Уникальный идентификатор заказа в системе.</summary>
 582917        public int Id { get; set; }
 18
 19        /// <summary>Внутренний ключ заказа (до 50 символов).</summary>
 20        [MaxLength(50)]
 21        [Display(Name = "Ключ")]
 8522        public string? Key { get; set; }
 23
 24        /// <summary>Номер отправления Ozon (до 50 символов).</summary>
 25        [MaxLength(50)]
 26        [Display(Name = "Номер отправления")]
 398327        public string? ShipmentNumber { get; set; }
 28
 29        /// <summary>Трек-номер отправления (до 100 символов).</summary>
 30        [MaxLength(100)]
 31        [Display(Name = "Трек номер")]
 3932        public string? TrackingNumber { get; set; }
 33
 34        /// <summary>
 35        /// Штрихкод ScanIt с новой этикетки FBS Ozon (например, «ii50014311608»): по нему этикетка
 36        /// связывается с заказом. Берётся из ответа /v3/posting/fbs/get; общий для всех Studio-частей
 37        /// одного отправления. До 5 октября 2026 (старые этикетки) у отправления его нет.
 38        /// </summary>
 39        [MaxLength(64)]
 40        [Display(Name = "ScanIt")]
 15041        public string? Scanit { get; set; }
 42
 7243        public int? ShipmentId { get; set; }
 44
 45        /// <summary>
 46        /// Номер отправления без суффикса (например, "12345-1" → "12345").
 47        /// Используется для сопоставления заказов.
 48        /// </summary>
 49        [NotMapped]
 50        public string? ShipmentNumberTrimmed
 51        {
 52            get
 53            {
 3354                if (string.IsNullOrEmpty(ShipmentNumber))
 2455                    return ShipmentNumber;
 56
 957                var trimmed = ShipmentNumber.Trim();
 958                if (trimmed.Length >= 2 && trimmed[trimmed.Length - 2] == '-' &&
 959                    char.IsDigit(trimmed[trimmed.Length - 1]))
 60                {
 461                    return trimmed.Substring(0, trimmed.Length - 2);
 62                }
 63
 564                return trimmed;
 65            }
 066            set { }
 67        }
 68
 69        /// <summary>Дата принятия заказа в обработку.</summary>
 70        [Display(Name = "Принят в обработку")]
 191971        public DateTime? ProcessingDate { get; set; }
 72
 73        /// <summary>Дата отгрузки заказа.</summary>
 74        [Display(Name = "Дата отгрузки")]
 42075        public DateTime? ShippingDate { get; set; }
 76
 77        /// <summary>
 78        /// Срок доставки (разница между датой отгрузки и обработки).
 79        /// </summary>
 80        [Display(Name = "Срок доставки")]
 81        [NotMapped]
 82        public TimeSpan? DeliveryPeriod
 83        {
 84            get
 85            {
 15686                if (ProcessingDate.HasValue && ShippingDate.HasValue)
 87                {
 2588                    return ShippingDate.Value - ProcessingDate.Value;
 89                }
 90
 13191                return null;
 92            }
 093            set { }
 94        }
 95
 96        /// <summary>
 97        /// Оставшееся время до отгрузки (от текущей даты до даты отгрузки).
 98        /// </summary>
 99        [Display(Name = "Осталось времени")]
 100        [NotMapped]
 101        public TimeSpan? TimeLeft
 102        {
 103            get
 104            {
 100105                if (ShippingDate.HasValue)
 106                {
 16107                    return ShippingDate.Value - DateTime.Now;
 108                }
 109
 84110                return null;
 111            }
 0112            set { }
 113        }
 114
 115        /// <summary>
 116        /// Количество оставшихся дней до отгрузки.
 117        /// </summary>
 118        [NotMapped]
 119        public int TimeLeftDay
 120        {
 121            get
 122            {
 32123                if (TimeLeft.HasValue)
 124                {
 8125                    return TimeLeft.Value.Days;
 126                }
 127
 24128                return 0;
 129            }
 0130            set { }
 131        }
 132
 133        /// <summary>
 134        /// Форматированное количество оставшихся дней (например, "5 д.").
 135        /// </summary>
 136        [NotMapped]
 137        public string? FormattedTimeLeftDay
 138        {
 139            get
 140            {
 30141                if (TimeLeft.HasValue)
 142                {
 0143                    return $"{TimeLeft.Value.Days} д.";
 144                }
 145
 30146                return null;
 147            }
 0148            set { }
 149        }
 150
 151        /// <summary>
 152        /// Количество дней в сроке доставки.
 153        /// </summary>
 154        [NotMapped]
 155        public int? DeliveryPeriodDay
 156        {
 157            get
 158            {
 32159                if (DeliveryPeriod.HasValue)
 160                {
 8161                    return DeliveryPeriod.Value.Days;
 162                }
 163
 24164                return null;
 165            }
 0166            set { }
 167        }
 168
 169        /// <summary>
 170        /// Количество часов в сроке доставки.
 171        /// </summary>
 172        [NotMapped]
 173        public int? DeliveryPeriodHour
 174        {
 175            get
 176            {
 22177                if (DeliveryPeriod.HasValue)
 178                {
 0179                    return DeliveryPeriod.Value.Hours;
 180                }
 181
 22182                return null;
 183            }
 0184            set { }
 185        }
 186
 187        /// <summary>
 188        /// Форматированный срок доставки (например, "2 д. 12:30 ч.").
 189        /// </summary>
 190        [NotMapped]
 191        public string FormattedDeliveryPeriod
 192        {
 193            get
 194            {
 15195                if (DeliveryPeriod.HasValue)
 196                {
 0197                    TimeSpan diff = DeliveryPeriod.Value;
 0198                    return $"{diff.Days} д. {diff.Hours:D2}:{diff.Minutes:D2} ч.";
 199                }
 200
 15201                return string.Empty;
 202            }
 0203            set { }
 204        }
 205
 206        /// <summary>
 207        /// Форматированные дни срока доставки (например, "2 д.").
 208        /// </summary>
 209        [NotMapped]
 210        public string FormattedDeliveryDay
 211        {
 212            get
 213            {
 22214                if (DeliveryPeriod.HasValue)
 215                {
 0216                    TimeSpan diff = DeliveryPeriod.Value;
 0217                    return $"{diff.Days} д.";
 218                }
 219
 22220                return string.Empty;
 221            }
 0222            set { }
 223        }
 224
 225        /// <summary>
 226        /// Форматированные часы и минуты срока доставки (например, "12:30 ч.").
 227        /// </summary>
 228        [NotMapped]
 229        public string FormattedDeliveryHours
 230        {
 231            get
 232            {
 22233                if (DeliveryPeriod.HasValue)
 234                {
 0235                    TimeSpan diff = DeliveryPeriod.Value;
 0236                    return $"{diff.Hours:D2}:{diff.Minutes:D2} ч.";
 237                }
 238
 22239                return string.Empty;
 240            }
 0241            set { }
 242        }
 243
 244        /// <summary>
 245        /// Дата принятия в обработку в формате "dd.MM.yyyy".
 246        /// </summary>
 247        [NotMapped]
 248        public string FormattedProcessingDate
 249        {
 14250            get { return OrderDateDisplay.FormatTableDate(ProcessingDate); }
 0251            set { }
 252        }
 253
 254        /// <summary>
 255        /// Время принятия в обработку в формате "HH:mm:ss".
 256        /// </summary>
 257        [NotMapped]
 258        public string FormattedProcessingTime
 259        {
 14260            get { return ProcessingDate.HasValue ? $"{ProcessingDate.Value.ToString("HH:mm:ss")}" : ""; }
 0261            set { }
 262        }
 263
 264        /// <summary>
 265        /// Полная дата и время принятия в обработку (например, "01.01.2023 14:30:00").
 266        /// </summary>
 267        [NotMapped]
 268        public string FullFormattedProcessingDate
 269        {
 23270            get { return ProcessingDate.HasValue ? ProcessingDate.Value.ToString("dd.MM.yyyy HH:mm:ss") : ""; }
 0271            set { }
 272        }
 273
 274        /// <summary>
 275        /// Дата отгрузки в формате "dd.MM.yyyy".
 276        /// </summary>
 277        [NotMapped]
 278        public string FormattedShippingDate
 279        {
 14280            get { return OrderDateDisplay.FormatTableDate(ShippingDate); }
 0281            set { }
 282        }
 283
 284        /// <summary>
 285        /// Время отгрузки в формате "HH:mm:ss".
 286        /// </summary>
 287        [NotMapped]
 288        public string FormattedShippingTime
 289        {
 14290            get { return ShippingDate.HasValue ? $"{ShippingDate.Value.ToString("HH:mm:ss")}" : ""; }
 0291            set { }
 292        }
 293
 294        /// <summary>
 295        /// Полная дата и время отгрузки (например, "01.01.2023 14:30:00").
 296        /// </summary>
 297        [NotMapped]
 298        public string FullFormattedShippingDate
 299        {
 23300            get { return ShippingDate.HasValue ? ShippingDate.Value.ToString("dd.MM.yyyy HH:mm:ss") : ""; }
 0301            set { }
 302        }
 303
 304
 305        /// <summary>Идентификатор статуса клиента.</summary>
 306        [Display(Name = "Статус клиента")]
 229307        public int? ClientStatusId { get; set; }
 308
 309        /// <summary>Объект статуса клиента, связанный с заказом.</summary>
 310        [Display(Name = "Статус клиента")]
 312311        public virtual ClientStatus? ClientStatus { get; set; }
 312
 313        /// <summary>
 314        /// Название статуса Ozon (получается из объекта ClientStatus).
 315        /// </summary>
 316        [NotMapped]
 317        [Display(Name = "Статус Ozon")]
 318        public string? Status
 319        {
 34320            get => ClientStatus?.Name;
 321            set
 322            {
 323                // Для обратной совместимости - можно установить через строку
 324                // Но лучше использовать ClientStatus напрямую
 0325            }
 326        }
 327
 328        /// <summary>Идентификатор статуса в отчете приложения.</summary>
 329        [Display(Name = "Статус в отчете")]
 212330        public int? AppStatusId { get; set; }
 331
 332        /// <summary>Объект статуса в отчете приложения.</summary>
 333        [Display(Name = "Статус в отчете")]
 690334        public virtual AppStatus? AppStatus { get; set; }
 335
 336        /// <summary>Дата последнего изменения статуса заказа.</summary>
 337        [Display(Name = "Дата последнего изменения статуса")]
 246338        public DateTime? LastStatusChangeDate { get; set; } = null;
 339
 340        /// <summary>Дата последнего изменения статуса в формате "dd.MM.yyyy".</summary>
 341        [NotMapped]
 342        public string FormattedLastStatusChangeDate
 343        {
 22344            get { return OrderDateDisplay.FormatTableDate(LastStatusChangeDate); }
 0345            set { }
 346        }
 347
 348        /// <summary>Полная дата последнего изменения статуса в формате "dd.MM.yyyy HH:mm".</summary>
 349        [NotMapped]
 350        public string FullFormattedLastStatusChangeDate
 351        {
 352            get
 353            {
 22354                return LastStatusChangeDate.HasValue
 22355                    ? $"{LastStatusChangeDate.Value.ToString("dd.MM.yyyy HH:mm")}"
 22356                    : "";
 357            }
 0358            set { }
 359        }
 360
 361        /// <summary>Сумма отправления (общая стоимость заказа).</summary>
 362        [Display(Name = "Сумма отправления")]
 363        [DisplayFormat(DataFormatString = "{0:F2}", ApplyFormatInEditMode = true)]
 151364        public decimal? ShipmentAmount { get; set; }
 365
 366        /// <summary>
 367        /// 13,5% от цены сайта (CurrentPriceWithDiscount), с fallback на Price.
 368        /// Вычисляемое поле, не мапится в базу и используется для отображения целевой прибыли.
 369        /// </summary>
 370        [NotMapped]
 371        [Display(Name = "Целевая прибыль (13,5% от цены сайта)")]
 372        public decimal? TargetShipmentProfit135
 373        {
 374            get
 375            {
 38376                var profitBasePrice = ProductInfo?.CurrentPriceWithDiscount is > 0
 38377                    ? ProductInfo.CurrentPriceWithDiscount
 38378                    : Price;
 38379                if (!profitBasePrice.HasValue || profitBasePrice.Value <= 0)
 29380                    return null;
 381
 382                // Аналогично фронтенду: используем целую часть (округление вниз)
 9383                return Math.Floor(profitBasePrice.Value * 0.135m);
 384            }
 0385            set { }
 386        }
 387
 388        /// <summary>Наименование товара (до 255 символов).</summary>
 389        [Display(Name = "Наименование")]
 390        [MaxLength(255)]
 732391        public string? ProductName { get; set; }
 392
 393        /// <summary>Ключ товара (до 255 символов).</summary>
 394        [MaxLength(255)]
 395        [Display(Name = "Ключ")]
 808396        public string? ProductKey { get; set; }
 397
 398        /// <summary>Артикул товара (до 255 символов).</summary>
 399        [MaxLength(255)]
 400        [Display(Name = "Арикул")]
 1297401        public string? Article { get; set; }
 402
 403        /// <summary>
 404        /// Очищенный артикул товара (только буквы и цифры).
 405        /// Используется для поиска и сопоставления.
 406        /// </summary>
 407        [NotMapped]
 408        [Display(Name = "Очищенный артикул")]
 409        public string? CleanedArticle
 410        {
 411            get
 412            {
 130413                if (string.IsNullOrEmpty(Article))
 14414                    return Article;
 116415                var cleaned = System.Text.RegularExpressions.Regex.Replace(Article, @"[^a-zA-Zа-яА-Я0-9]", "");
 116416                return string.IsNullOrEmpty(cleaned) ? null : cleaned;
 417            }
 121418            set { }
 419        }
 420
 421        /// <summary>Идентификатор производителя.</summary>
 572422        public int? ManufacturerId { get; set; }
 423
 424        /// <summary>Объект производителя, связанный с товаром.</summary>
 425        [Display(Name = "Производитель")]
 333426        public Manufacturer? Manufacturer { get; set; }
 427
 428        /// <summary>Идентификатор производителя в системе JCEtalon.</summary>
 32429        public int? EtProducerId { get; set; }
 430
 431        /// <summary>Объект производителя из системы JCEtalon.</summary>
 432        [Display(Name = "Производитель JCEtalon")]
 375433        public virtual EtProducer? EtProducer { get; set; }
 434
 435        /// <summary>Цена единицы товара.</summary>
 436        [Display(Name = "Цена")]
 437        [DisplayFormat(DataFormatString = "{0:F2}", ApplyFormatInEditMode = true)]
 921438        public decimal? Price { get; set; }
 439
 440        /// <summary>Количество единиц товара в заказе.</summary>
 441        [Display(Name = "Количество")]
 1720442        public int? Quantity { get; set; }
 443
 444        /// <summary>
 445        /// Истинное количество товара с учетом множителя из ProductKey.
 446        /// Например, если в ключе указано [2], то умножается на 2.
 447        /// </summary>
 448        [NotMapped]
 449        [Display(Name = "Истинное количество")]
 450        public int? TrueQuantity
 451        {
 357452            get => Quantity.HasValue ? ApplyProductKeyMultiplier(Quantity.Value, ProductKey) : Quantity;
 157453            set { }
 454        }
 455
 456        /// <summary>
 457        /// Кратность упаковки из ключа товара: <c>ARTICLE=BRAND[N]</c> означает упаковку по N штук,
 458        /// поэтому заказ на 2 упаковки списывает со склада 20 штук. Публичный статический метод, чтобы
 459        /// тот же расчёт можно было применить к количеству, отличному от <see cref="Quantity"/>
 460        /// (например, к отредактированному в форме), не расходясь с <see cref="TrueQuantity"/>.
 461        /// </summary>
 462        public static int ApplyProductKeyMultiplier(int quantity, string? productKey)
 463        {
 861464            if (quantity <= 0 || string.IsNullOrEmpty(productKey))
 304465                return quantity;
 466
 557467            return quantity * OzonDomains.Nomenclature.ProductKeyParser.BatchMultiplier(productKey);
 468        }
 469
 470        /// <summary>Идентификатор склада отгрузки.</summary>
 471        [Display(Name = "Склад отгрузки")]
 435472        public int? ShipmentWarehouseId { get; set; }
 473
 474        /// <summary>Объект склада отгрузки, связанный с заказом.</summary>
 632475        public virtual Warehouse? ShipmentWarehouse { get; set; }
 476
 477        /// <summary>Идентификатор валюты заказа.</summary>
 478        [Display(Name = "Валюта")]
 16479        public int? СurrencyId { get; set; }
 480
 481        /// <summary>Объект валюты, связанный с заказом.</summary>
 133482        public virtual Currency? Сurrency { get; set; }
 483
 484        /// <summary>Идентификатор поставщика.</summary>
 96485        public int? SupplierId { get; set; }
 486
 487        /// <summary>Объект поставщика, связанный с заказом (до 255 символов).</summary>
 488        [MaxLength(255)]
 489        [Display(Name = "Поставщик")]
 473490        public Supplier? Supplier { get; set; }
 491
 492        /// <summary>Номер заказа, переданный поставщику (до 50 символов).</summary>
 493        [Display(Name = "Номер заказа")]
 494        [MaxLength(50)]
 258495        public string? OrderNumberToSupplier { get; set; } = null;
 496
 497        /// <summary>Закупочная цена единицы товара.</summary>
 498        [Display(Name = "Цена закупки")]
 339499        public decimal? PurchasePrice { get; set; }
 500
 501        /// <summary>Закупочная цена до конвертации валюты.</summary>
 502        [Display(Name = "Цена закупки до перевода")]
 64503        public decimal? OriginalPurchasePrice { get; set; }
 504
 505        /// <summary>Идентификатор информации о продукте.</summary>
 506        [Display(Name = "Данные Продукта")]
 295507        public int? ProductInfoId { get; set; }
 508
 509        /// <summary>Объект информации о продукте, связанный с заказом.</summary>
 322510        public virtual Product? ProductInfo { get; set; }
 511
 512        /// <summary>Минимальная комиссия Ozon за заказ.</summary>
 513        [Display(Name = "Минимальная комиссия ОЗОН")]
 165514        public decimal? MinOzonCommission { get; set; }
 515
 516        /// <summary>Максимальная комиссия Ozon за заказ.</summary>
 517        [Display(Name = "Максимальная комиссия ОЗОН")]
 165518        public decimal? MaxOzonCommission { get; set; }
 519
 520        /// <summary>Информация о максимальной комиссии Ozon.</summary>
 521        [Display(Name = "Информация по комиссии")]
 7522        public string? MaxCommissionInfo { get; set; }
 523
 524        /// <summary>Информация о минимальной комиссии Ozon.</summary>
 525        [Display(Name = "Информация по комиссии")]
 7526        public string? MinCommissionInfo { get; set; }
 527
 528        /// <summary>Минимальная прибыль от заказа.</summary>
 529        [Display(Name = "Минимальная прибыль")]
 322530        public decimal? MinProfit { get; set; }
 531
 532        /// <summary>Максимальная прибыль от заказа.</summary>
 533        [Display(Name = "Максимальная прибыль")]
 113534        public decimal? MaxProfit { get; set; }
 535
 536        /// <summary>Минимальная скидка на товар в процентах.</summary>
 537        [Display(Name = "Минимальная скидка, %")]
 165538        public decimal? MinDiscount { get; set; }
 539
 540        /// <summary>Максимальная скидка на товар в процентах.</summary>
 541        [Display(Name = "Максивальная скидка, %")]
 55542        public decimal? MaxDiscount { get; set; }
 543
 544        /// <summary>Себестоимость товара.</summary>
 545        [Display(Name = "Себестоимость")]
 351546        public decimal? CostPrice { get; set; }
 547
 548        /// <summary>Город доставки (до 100 символов).</summary>
 549        [Display(Name = "Город доставки")]
 550        [MaxLength(100)]
 194551        public string? DeliveryCity { get; set; }
 552
 553        /// <summary>Категория товара (до 255 символов).</summary>
 554        [MaxLength(255)]
 555        [Display(Name = "Категория")]
 134556        public string? NewCategory { get; set; }
 557
 558        /// <summary>Флаг, указывающий, проверен ли заказ.</summary>
 559        [Display(Name = "Статус обработки")]
 79560        public bool IsVerified { get; set; } = false;
 561
 562        /// <summary>Флаг, указывающий, принят ли заказ.</summary>
 563        [Display(Name = "Принят")]
 71564        public bool IsAccepted { get; set; } = false;
 565
 566        /// <summary>Комментарий к заказу (до 500 символов).</summary>
 567        [Display(Name = "Комментарий")]
 568        [MaxLength(500)]
 31569        public string? Comment { get; set; }
 570
 571        /// <summary>Список обновленных столбцов в заказе.</summary>
 572        [Display(Name = "Обновленные столбцы")]
 5539573        public List<string>? UpdatedColumns { get; set; } = [];
 574
 575        /// <summary>Имя пользователя, обновившего запись (по умолчанию "Ozon").</summary>
 576        [Display(Name = "Пользователь обновивший запись")]
 5413577        public string? UpdatedBy { get; set; } = "Ozon";
 578
 579        /// <summary>
 580        /// Момент последней записи строки в БД. Проставляется BEFORE-триггером
 581        /// <c>trg_orders_before_write_updatedat</c> на КАЖДЫЙ INSERT/UPDATE независимо от
 582        /// C#-пути записи (репозиторий, вебхуки, 1С, rollback) — источник для инкрементальной
 583        /// синхронизации поискового индекса Elasticsearch.
 584        /// </summary>
 50585        public DateTime? UpdatedAt { get; set; }
 586
 587        /// <summary>Флаг, указывающий, подлежит ли заказ возврату.</summary>
 588        [Display(Name = "Подлежит возврату")]
 5425589        public bool? IsReturnable { get; set; } = false;
 590
 591        /// <summary>Идентификатор связанной транзакции.</summary>
 154592        public int? TransactionId { get; set; }
 593
 594        /// <summary>Идентификатор клиента Ozon.</summary>
 1286595        public int? OzonClientId { get; set; }
 596
 597        /// <summary>Объект клиента Ozon, связанный с заказом.</summary>
 598        [Display(Name = "Ozon клиент")]
 1247599        public OzonClient? OzonClient { get; set; } = null;
 600
 601        /// <summary>Последняя сохранённая причина отмены Ozon для отображения в списке заказов.</summary>
 602        [NotMapped]
 30603        public OzonPostingCancellation? LatestOzonPostingCancellation { get; set; }
 604
 605        /// <summary>Идентификатор файла, из которого загружен заказ.</summary>
 22606        public int? FromFiletId { get; set; }
 607
 608        /// <summary>Флаг, указывающий, загружен ли заказ из Excel файла.</summary>
 609        [Display(Name = "Подгружен из Excel файла")]
 5482610        public bool? FromFile { get; set; } = false;
 611
 612        /// <summary>Идентификатор данных Excel файла.</summary>
 32613        public int? ExcelFileDataId { get; set; }
 614
 615        /// <summary>Объект метаданных файла, связанный с заказом.</summary>
 616        [Display(Name = "Данные о файле")]
 27617        public OrdersFileMetadata? ExcelFileData { get; set; }
 618
 619        /// <summary>Порядковый номер записи в Excel файле (не сохраняется в базе).</summary>
 620        [NotMapped]
 42621        public int NumberInExcel { get; set; }
 622
 623        /// <summary>Идентификатор элемента корзины.</summary>
 45624        public int? CartItemId { get; set; }
 625
 626        /// <summary>Статус элемента корзины (не сохраняется в базе).</summary>
 627        [NotMapped]
 38628        public ItemStatus? CartItemStatus { get; set; }
 629
 630        /// <summary>Цвет статуса элемента корзины (не сохраняется в базе).</summary>
 631        [NotMapped]
 30632        public StatusColor? CartItemStatusColor { get; set; }
 633
 634        /// <summary>Идентификатор типа доставки.</summary>
 32635        public int? DeliveryId { get; set; }
 636
 637        /// <summary>Объект типа доставки, связанный с заказом.</summary>
 638        [Display(Name = "Тип доставки")]
 228639        public Delivery? Delivery { get; set; }
 640
 641        /// <summary>Объект архивной записи заказа.</summary>
 642        [Display(Name = "Запись в архиве")]
 62643        public virtual OrderArchive? OrderArchive { get; set; }
 644
 645        /// <summary>Флаг: заказ имеет возврат/отмену в Ozon (есть запись в OrderReturns).</summary>
 646        [Display(Name = "Заказ возвращён/отменён")]
 44647        public bool IsReturned { get; set; } = false;
 648
 649        /// <summary>Штрихкод возврата из OrderReturns (LogisticBarcode). Не хранится в БД.</summary>
 650        [NotMapped]
 22651        public string? ReturnLogisticBarcode { get; set; }
 652
 653        /// <summary>Системное имя статуса возврата (OrderReturns.VisualStatusSysName). Не хранится в БД.</summary>
 654        [NotMapped]
 30655        public string? ReturnStatusSysName { get; set; }
 656
 657        /// <summary>Отображаемый статус возврата (OrderReturns.VisualStatusDisplayName). Не хранится в БД.</summary>
 658        [NotMapped]
 30659        public string? ReturnStatusDisplayName { get; set; }
 660
 661        /// <summary>Склад возврата (OrderReturns.PlaceName/TargetPlaceName). Не хранится в БД.</summary>
 662        [NotMapped]
 30663        public string? ReturnWarehouseName { get; set; }
 664
 665        /// <summary>Дата изменения статуса возврата (OrderReturns.VisualStatusChangeMoment). Не хранится в БД.</summary
 666        [NotMapped]
 50667        public DateTime? ReturnStatusChangeDate { get; set; }
 668
 669        [NotMapped]
 670        public string FormattedReturnStatusChangeDate
 671        {
 14672            get { return OrderDateDisplay.FormatTableDate(ReturnStatusChangeDate); }
 0673            set { }
 674        }
 675
 676        [NotMapped]
 677        public string FullFormattedReturnStatusChangeDate
 678        {
 14679            get { return ReturnStatusChangeDate.HasValue ? ReturnStatusChangeDate.Value.ToString("dd.MM.yyyy HH:mm:ss") 
 0680            set { }
 681        }
 682
 683        /// <summary>Ключ API-поставщика, у которого отслеживается заказ (OrderSupplierStates). Не хранится в БД.</summa
 684        [NotMapped]
 36685        public string? SupplierStateProviderKey { get; set; }
 686
 687        /// <summary>Отображаемое название поставщика для подсказки. Не хранится в БД.</summary>
 688        [NotMapped]
 27689        public string? SupplierStateSupplierName { get; set; }
 690
 691        /// <summary>Стадия у поставщика: Cart / Ordered / Closed. Не хранится в БД.</summary>
 692        [NotMapped]
 42693        public string? SupplierStateStage { get; set; }
 694
 695        /// <summary>Проблемы заказа для значка в сетках: алерты, ошибки 1С и транзакций. Не хранится в БД.</summary>
 696        [NotMapped]
 51697        public List<OrderProblem>? Problems { get; set; }
 698
 699        /// <summary>Текущий статус у поставщика (SupplierStatuses.Name). Не хранится в БД.</summary>
 700        [NotMapped]
 42701        public string? SupplierStatusName { get; set; }
 702
 703        /// <summary>Цвет статуса поставщика (StatusColors.ColorCode). Не хранится в БД.</summary>
 704        [NotMapped]
 34705        public string? SupplierStatusColor { get; set; }
 706
 707        /// <summary>Номер заказа у поставщика, если он уже оформлен. Не хранится в БД.</summary>
 708        [NotMapped]
 26709        public string? SupplierStateExternalOrderNumber { get; set; }
 710
 711        /// <summary>Дата последней смены статуса у поставщика. Не хранится в БД.</summary>
 712        [NotMapped]
 26713        public DateTime? SupplierStateChangedAt { get; set; }
 714
 715        /// <summary>Срок поставки у поставщика, дни (мин) — снимок проценки. Не хранится в БД.</summary>
 716        [NotMapped]
 166717        public int? SupplierStateDeliveryDaysMin { get; set; }
 718
 719        /// <summary>Срок поставки у поставщика, дни (макс) — снимок проценки. Не хранится в БД.</summary>
 720        [NotMapped]
 155721        public int? SupplierStateDeliveryDaysMax { get; set; }
 722
 723        /// <summary>Момент оформления заказа у поставщика (переход в Stage = Ordered), локальное время. Не хранится в Б
 724        [NotMapped]
 42725        public DateTime? SupplierStateOrderedAt { get; set; }
 726
 727        /// <summary>Момент попадания в корзину поставщика, локальное время. Не хранится в БД.</summary>
 728        [NotMapped]
 31729        public DateTime? SupplierStateCartCreatedAt { get; set; }
 730
 731        /// <summary>Направление/склад отгрузки поставщика на момент проценки, например «ЦЗ Москва (0000116774)». Не хра
 732        [NotMapped]
 37733        public string? SupplierStateDirection { get; set; }
 734
 735        /// <summary>
 736        /// Прогнозная дата доставки от поставщика: пока заказ в корзине — от момента добавления
 737        /// в неё (оценка ещё не подтверждена, заказ может уйти позже), после оформления —
 738        /// от реального момента заказа. Плюс среднее между DeliveryDaysMin и DeliveryDaysMax.
 739        /// </summary>
 740        [NotMapped]
 741        public DateTime? SupplierExpectedDeliveryDate
 742        {
 743            get
 744            {
 122745                if (!SupplierStateDeliveryDaysMin.HasValue && !SupplierStateDeliveryDaysMax.HasValue)
 746                {
 113747                    return null;
 748                }
 749
 9750                var baseDate = SupplierStateStage == OrderSupplierStage.Cart
 9751                    ? SupplierStateCartCreatedAt
 9752                    : SupplierStateOrderedAt ?? SupplierStateCartCreatedAt;
 9753                if (!baseDate.HasValue)
 754                {
 0755                    return null;
 756                }
 757
 9758                var min = SupplierStateDeliveryDaysMin ?? SupplierStateDeliveryDaysMax!.Value;
 9759                var max = SupplierStateDeliveryDaysMax ?? SupplierStateDeliveryDaysMin!.Value;
 9760                return baseDate.Value.AddDays((min + max) / 2.0);
 761            }
 0762            set { }
 763        }
 764
 765        /// <summary>Оставшееся время до прогнозной даты доставки от поставщика.</summary>
 766        [NotMapped]
 767        public TimeSpan? SupplierExpectedDeliveryTimeLeft
 768        {
 55769            get { return SupplierExpectedDeliveryDate.HasValue ? SupplierExpectedDeliveryDate.Value - DateTime.Now : nul
 0770            set { }
 771        }
 772
 773        /// <summary>Прогнозная дата доставки от поставщика в формате "dd.MM.yyyy".</summary>
 774        [NotMapped]
 775        public string FormattedSupplierExpectedDeliveryDate
 776        {
 16777            get { return OrderDateDisplay.FormatTableDateFull(SupplierExpectedDeliveryDate); }
 0778            set { }
 779        }
 780
 781        /// <summary>Полная прогнозная дата и время доставки от поставщика (например, "10.08.2026 00:00:00").</summary>
 782        [NotMapped]
 783        public string FullFormattedSupplierExpectedDeliveryDate
 784        {
 14785            get { return SupplierExpectedDeliveryDate.HasValue ? SupplierExpectedDeliveryDate.Value.ToString("dd.MM.yyyy
 0786            set { }
 787        }
 788
 789        /// <summary>Оставшиеся дни до прогнозной даты доставки от поставщика (например, "5 д.").</summary>
 790        [NotMapped]
 791        public string? FormattedSupplierExpectedDeliveryDaysLeft
 792        {
 32793            get { return SupplierExpectedDeliveryTimeLeft.HasValue ? $"{SupplierExpectedDeliveryTimeLeft.Value.Days} д."
 0794            set { }
 795        }
 796
 797        /// <summary>Объект информации о цене заказа.</summary>
 36798        public virtual OrderPrice? OrderPrice { get; set; }
 799
 800        /// <summary>Неизменяемые условия акций Ozon на момент первой загрузки заказа.</summary>
 33801        public virtual OrderOzonPromotionSnapshot? OzonPromotionSnapshot { get; set; }
 802
 803        /// <summary>Список дополнительных расходов, связанных с заказом.</summary>
 804        [Display(Name = "Дополнительные расходы")]
 5420805        public virtual List<OrderExtraExpense> ExtraExpenses { get; set; } = [];
 806
 807        /// <summary>Список расширений заказа (дополнительных данных).</summary>
 808        [Display(Name = "Расширения заказа")]
 5578809        public List<OrderExtension> OrderExtensions { get; set; } = [];
 810
 811        /// <summary>
 812        /// Создает копию текущего объекта заказа, копируя только простые свойства.
 813        /// Навигационные свойства и коллекции очищаются для предотвращения нежелательных связей.
 814        /// </summary>
 815        /// <returns>Новый объект Order с скопированными данными.</returns>
 816        public Order Clone()
 817        {
 0818            var clone = new Order();
 0819            var type = typeof(Order);
 820
 0821            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
 0822                .Where(p =>
 0823                    p.CanRead &&
 0824                    p.CanWrite &&
 0825                    p.Name != nameof(Order.Id) &&
 0826
 0827                    // НЕ навигации
 0828                    !typeof(IEnumerable<object>).IsAssignableFrom(p.PropertyType) &&
 0829                    !p.PropertyType.IsClass ||
 0830
 0831                    // но разрешаем string
 0832                    p.PropertyType == typeof(string)
 0833                );
 834
 0835            foreach (var property in properties)
 836            {
 0837                var value = property.GetValue(this);
 0838                property.SetValue(clone, value);
 839            }
 840
 841            // Явно очищаем навигации и коллекции
 0842            clone.AppStatus = null;
 0843            clone.Сurrency = null;
 0844            clone.Supplier = null;
 0845            clone.ProductInfo = null;
 0846            clone.ShipmentWarehouse = null;
 0847            clone.Delivery = null;
 0848            clone.EtProducer = null;
 0849            clone.OzonClient = null;
 850
 0851            clone.OrderExtensions = new List<OrderExtension>();
 0852            clone.OrderArchive = null;
 0853            clone.OrderPrice = null;
 854
 0855            return clone;
 856        }
 857    }
 858}

Methods/Properties

get_Id()
get_Key()
get_ShipmentNumber()
get_TrackingNumber()
get_Scanit()
get_ShipmentId()
get_ShipmentNumberTrimmed()
set_ShipmentNumberTrimmed(System.String)
get_ProcessingDate()
get_ShippingDate()
get_DeliveryPeriod()
set_DeliveryPeriod(System.Nullable`1<System.TimeSpan>)
get_TimeLeft()
set_TimeLeft(System.Nullable`1<System.TimeSpan>)
get_TimeLeftDay()
set_TimeLeftDay(System.Int32)
get_FormattedTimeLeftDay()
set_FormattedTimeLeftDay(System.String)
get_DeliveryPeriodDay()
set_DeliveryPeriodDay(System.Nullable`1<System.Int32>)
get_DeliveryPeriodHour()
set_DeliveryPeriodHour(System.Nullable`1<System.Int32>)
get_FormattedDeliveryPeriod()
set_FormattedDeliveryPeriod(System.String)
get_FormattedDeliveryDay()
set_FormattedDeliveryDay(System.String)
get_FormattedDeliveryHours()
set_FormattedDeliveryHours(System.String)
get_FormattedProcessingDate()
set_FormattedProcessingDate(System.String)
get_FormattedProcessingTime()
set_FormattedProcessingTime(System.String)
get_FullFormattedProcessingDate()
set_FullFormattedProcessingDate(System.String)
get_FormattedShippingDate()
set_FormattedShippingDate(System.String)
get_FormattedShippingTime()
set_FormattedShippingTime(System.String)
get_FullFormattedShippingDate()
set_FullFormattedShippingDate(System.String)
get_ClientStatusId()
get_ClientStatus()
get_Status()
set_Status(System.String)
get_AppStatusId()
get_AppStatus()
get_LastStatusChangeDate()
get_FormattedLastStatusChangeDate()
set_FormattedLastStatusChangeDate(System.String)
get_FullFormattedLastStatusChangeDate()
set_FullFormattedLastStatusChangeDate(System.String)
get_ShipmentAmount()
get_TargetShipmentProfit135()
set_TargetShipmentProfit135(System.Nullable`1<System.Decimal>)
get_ProductName()
get_ProductKey()
get_Article()
get_CleanedArticle()
set_CleanedArticle(System.String)
get_ManufacturerId()
get_Manufacturer()
get_EtProducerId()
get_EtProducer()
get_Price()
get_Quantity()
get_TrueQuantity()
set_TrueQuantity(System.Nullable`1<System.Int32>)
ApplyProductKeyMultiplier(System.Int32,System.String)
get_ShipmentWarehouseId()
get_ShipmentWarehouse()
get_СurrencyId()
get_Сurrency()
get_SupplierId()
get_Supplier()
get_OrderNumberToSupplier()
get_PurchasePrice()
get_OriginalPurchasePrice()
get_ProductInfoId()
get_ProductInfo()
get_MinOzonCommission()
get_MaxOzonCommission()
get_MaxCommissionInfo()
get_MinCommissionInfo()
get_MinProfit()
get_MaxProfit()
get_MinDiscount()
get_MaxDiscount()
get_CostPrice()
get_DeliveryCity()
get_NewCategory()
get_IsVerified()
get_IsAccepted()
get_Comment()
get_UpdatedColumns()
get_UpdatedBy()
get_UpdatedAt()
get_IsReturnable()
get_TransactionId()
get_OzonClientId()
get_OzonClient()
get_LatestOzonPostingCancellation()
get_FromFiletId()
get_FromFile()
get_ExcelFileDataId()
get_ExcelFileData()
get_NumberInExcel()
get_CartItemId()
get_CartItemStatus()
get_CartItemStatusColor()
get_DeliveryId()
get_Delivery()
get_OrderArchive()
get_IsReturned()
get_ReturnLogisticBarcode()
get_ReturnStatusSysName()
get_ReturnStatusDisplayName()
get_ReturnWarehouseName()
get_ReturnStatusChangeDate()
get_FormattedReturnStatusChangeDate()
set_FormattedReturnStatusChangeDate(System.String)
get_FullFormattedReturnStatusChangeDate()
set_FullFormattedReturnStatusChangeDate(System.String)
get_SupplierStateProviderKey()
get_SupplierStateSupplierName()
get_SupplierStateStage()
get_Problems()
get_SupplierStatusName()
get_SupplierStatusColor()
get_SupplierStateExternalOrderNumber()
get_SupplierStateChangedAt()
get_SupplierStateDeliveryDaysMin()
get_SupplierStateDeliveryDaysMax()
get_SupplierStateOrderedAt()
get_SupplierStateCartCreatedAt()
get_SupplierStateDirection()
get_SupplierExpectedDeliveryDate()
set_SupplierExpectedDeliveryDate(System.Nullable`1<System.DateTime>)
get_SupplierExpectedDeliveryTimeLeft()
set_SupplierExpectedDeliveryTimeLeft(System.Nullable`1<System.TimeSpan>)
get_FormattedSupplierExpectedDeliveryDate()
set_FormattedSupplierExpectedDeliveryDate(System.String)
get_FullFormattedSupplierExpectedDeliveryDate()
set_FullFormattedSupplierExpectedDeliveryDate(System.String)
get_FormattedSupplierExpectedDeliveryDaysLeft()
set_FormattedSupplierExpectedDeliveryDaysLeft(System.String)
get_OrderPrice()
get_OzonPromotionSnapshot()
get_ExtraExpenses()
get_OrderExtensions()
Clone()