| | | 1 | | namespace Services.ApiServices._1CApi.Stock; |
| | | 2 | | |
| | | 3 | | /// <summary>Режим фильтра по сроку поступления на склад.</summary> |
| | | 4 | | public enum StockAgeFilterMode |
| | | 5 | | { |
| | | 6 | | /// <summary>Без ограничения по дате прихода.</summary> |
| | | 7 | | None, |
| | | 8 | | |
| | | 9 | | /// <summary>Позиции, по которым не было прихода за последние N дней.</summary> |
| | | 10 | | OlderThanDays, |
| | | 11 | | |
| | | 12 | | /// <summary>Позиции, приходившие на склад в заданном диапазоне дат.</summary> |
| | | 13 | | ReceiptBetween |
| | | 14 | | } |
| | | 15 | | |
| | | 16 | | /// <summary> |
| | | 17 | | /// Корзина давности — самое свежее окно оборотов, в котором был приход на склад. |
| | | 18 | | /// Точной даты регистр не отдаёт (параметр Periodicity в 1С Fresh не поддерживается), |
| | | 19 | | /// поэтому для сортировки всего склада используется именно она. |
| | | 20 | | /// </summary> |
| | | 21 | | public enum StockAgeBucket |
| | | 22 | | { |
| | | 23 | | Upto30 = 0, |
| | | 24 | | Upto90 = 1, |
| | | 25 | | Upto180 = 2, |
| | | 26 | | Upto365 = 3, |
| | | 27 | | Upto730 = 4, |
| | | 28 | | Over730 = 5 |
| | | 29 | | } |
| | | 30 | | |
| | | 31 | | /// <summary>Источник прихода, по которому ограничивается набор позиций склада.</summary> |
| | | 32 | | public enum ReceiptDocumentFilter |
| | | 33 | | { |
| | | 34 | | All, |
| | | 35 | | ReceiptInvoice, |
| | | 36 | | StockTransfer |
| | | 37 | | } |
| | | 38 | | |
| | | 39 | | /// <summary>Параметры выборки остатков склада.</summary> |
| | | 40 | | public sealed record OneCWarehouseStockQuery( |
| | | 41 | | Guid WarehouseKey, |
| | | 42 | | StockAgeFilterMode Mode = StockAgeFilterMode.None, |
| | | 43 | | int? OlderThanDays = null, |
| | | 44 | | DateTime? ReceiptFrom = null, |
| | | 45 | | DateTime? ReceiptTo = null, |
| | | 46 | | string? ArticleSearch = null, |
| | | 47 | | string? ProducerSearch = null, |
| | | 48 | | decimal MinQuantity = 0m, |
| | | 49 | | string Sort = "article", |
| | | 50 | | bool Desc = false, |
| | | 51 | | int Page = 1, |
| | | 52 | | int PageSize = 25, |
| | | 53 | | bool ForceRefresh = false, |
| | | 54 | | ReceiptDocumentFilter DocumentFilter = ReceiptDocumentFilter.All, |
| | | 55 | | Guid? SupplierKey = null); |
| | | 56 | | |
| | | 57 | | /// <summary> |
| | | 58 | | /// Позиция склада до обогащения — то, что кэшируется целиком по складу. |
| | | 59 | | /// Производитель и нормализованный артикул берутся из локальной карты соответствий, без обращения |
| | | 60 | | /// к 1С: их достаточно для поиска и сортировки по всем позициям склада. Артикул в исходном |
| | | 61 | | /// написании и наименование в карте не хранятся — они догружаются из 1С только для видимой страницы. |
| | | 62 | | /// </summary> |
| | | 63 | | public sealed record WarehouseStockPosition( |
| | | 64 | | Guid NomenclatureKey, |
| | | 65 | | decimal Quantity, |
| | | 66 | | string? ArticleNorm, |
| | | 67 | | string? Producer); |
| | | 68 | | |
| | | 69 | | /// <summary>Снимок остатков склада на момент загрузки.</summary> |
| | | 70 | | public sealed record WarehouseStockSnapshot( |
| | | 71 | | Guid WarehouseKey, |
| | | 72 | | IReadOnlyList<WarehouseStockPosition> Positions, |
| | | 73 | | DateTime LoadedAtUtc); |
| | | 74 | | |
| | | 75 | | /// <summary>Последний приход позиции на конкретный склад.</summary> |
| | | 76 | | public sealed record LastReceiptInfo( |
| | | 77 | | DateTime Date, |
| | | 78 | | string? Number, |
| | | 79 | | Guid RefKey, |
| | | 80 | | string Kind, |
| | | 81 | | Guid? SupplierKey = null); |
| | | 82 | | |
| | | 83 | | /// <summary>Строка таблицы раздела.</summary> |
| | 165 | 84 | | public sealed record OneCWarehouseStockRow( |
| | 21 | 85 | | Guid NomenclatureKey, |
| | 102 | 86 | | string? Article, |
| | 101 | 87 | | string? Name, |
| | 105 | 88 | | string? Producer, |
| | 305 | 89 | | decimal Quantity, |
| | 106 | 90 | | DateTime? LastReceiptDate, |
| | 102 | 91 | | int? DaysOnStock, |
| | 107 | 92 | | string? LastReceiptDocNumber, |
| | 105 | 93 | | string? LastReceiptDocKind, |
| | 204 | 94 | | StockAgeBucket? AgeBucket, |
| | 267 | 95 | | string? LastReceiptSupplier = null); |
| | | 96 | | |
| | | 97 | | /// <summary>Результат выборки: страница строк плюс сводка по всему отфильтрованному набору.</summary> |
| | | 98 | | public sealed record OneCWarehouseStockResult( |
| | | 99 | | Guid WarehouseKey, |
| | | 100 | | string WarehouseName, |
| | | 101 | | IReadOnlyList<OneCWarehouseStockRow> Rows, |
| | | 102 | | int TotalCount, |
| | | 103 | | int TotalPositions, |
| | | 104 | | decimal TotalQuantityFiltered, |
| | | 105 | | int Page, |
| | | 106 | | int PageSize, |
| | | 107 | | DateTime SnapshotAtUtc, |
| | | 108 | | bool Failed, |
| | | 109 | | string? Warning) |
| | | 110 | | { |
| | | 111 | | /// <summary>1С недоступна или запрос не удался — таблица пустая, причина в Warning.</summary> |
| | | 112 | | public static OneCWarehouseStockResult Failure(Guid warehouseKey, string warehouseName, string error) |
| | | 113 | | => new(warehouseKey, warehouseName, [], 0, 0, 0m, 1, 0, DateTime.UtcNow, true, error); |
| | | 114 | | } |