Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
- ImportRetailReturnsAsync (retailsalesreturn): связь с чеком по externalId demand, +остаток - ImportInventoriesAsync (inventory): Completed без движений, BookQty/ActualQty из calculated/quantity - Все 7 импортёров принимают updatedFromMsk → filter=updated>= (МСК) для дельты - Контроллер: ?updatedFrom=<МСК> прокинут во все типы Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
178 lines
8.2 KiB
C#
178 lines
8.2 KiB
C#
using System.Text.Json.Serialization;
|
||
|
||
namespace foodmarket.Infrastructure.Integrations.MoySklad;
|
||
|
||
// Minimal MoySklad JSON-API response shapes we need for read-only product import.
|
||
// See https://dev.moysklad.ru/doc/api/remap/1.2/ — we intentionally ignore fields we don't consume.
|
||
|
||
public class MsListResponse<T>
|
||
{
|
||
[JsonPropertyName("meta")] public MsListMeta? Meta { get; set; }
|
||
[JsonPropertyName("rows")] public List<T> Rows { get; set; } = [];
|
||
}
|
||
|
||
public class MsListMeta
|
||
{
|
||
[JsonPropertyName("size")] public int Size { get; set; }
|
||
[JsonPropertyName("limit")] public int Limit { get; set; }
|
||
[JsonPropertyName("offset")] public int Offset { get; set; }
|
||
[JsonPropertyName("href")] public string? Href { get; set; }
|
||
}
|
||
|
||
public class MsMeta
|
||
{
|
||
[JsonPropertyName("href")] public string? Href { get; set; }
|
||
[JsonPropertyName("type")] public string? Type { get; set; }
|
||
[JsonPropertyName("uuidHref")] public string? UuidHref { get; set; }
|
||
}
|
||
|
||
public class MsMetaWrapper
|
||
{
|
||
[JsonPropertyName("meta")] public MsMeta? Meta { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||
}
|
||
|
||
public class MsOrganization
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("inn")] public string? Inn { get; set; }
|
||
[JsonPropertyName("kpp")] public string? Kpp { get; set; }
|
||
}
|
||
|
||
public class MsProduct
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string Name { get; set; } = "";
|
||
[JsonPropertyName("article")] public string? Article { get; set; }
|
||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||
[JsonPropertyName("weighed")] public bool Weighed { get; set; }
|
||
[JsonPropertyName("vat")] public int? Vat { get; set; }
|
||
[JsonPropertyName("vatEnabled")] public bool? VatEnabled { get; set; }
|
||
[JsonPropertyName("archived")] public bool Archived { get; set; }
|
||
|
||
[JsonPropertyName("barcodes")] public List<Dictionary<string, string>>? Barcodes { get; set; }
|
||
[JsonPropertyName("salePrices")] public List<MsSalePrice>? SalePrices { get; set; }
|
||
[JsonPropertyName("buyPrice")] public MsMoney? BuyPrice { get; set; }
|
||
[JsonPropertyName("minPrice")] public MsMoney? MinPrice { get; set; }
|
||
|
||
[JsonPropertyName("uom")] public MsMetaWrapper? Uom { get; set; }
|
||
[JsonPropertyName("productFolder")] public MsMetaWrapper? ProductFolder { get; set; }
|
||
[JsonPropertyName("country")] public MsMetaWrapper? Country { get; set; }
|
||
|
||
[JsonPropertyName("alcoholic")] public MsAlcoholic? Alcoholic { get; set; }
|
||
[JsonPropertyName("tnved")] public string? Tnved { get; set; }
|
||
[JsonPropertyName("trackingType")] public string? TrackingType { get; set; }
|
||
}
|
||
|
||
public class MsSalePrice
|
||
{
|
||
[JsonPropertyName("value")] public decimal Value { get; set; } // minor units (копейки/тиын) — MoySklad may return fractional
|
||
[JsonPropertyName("currency")] public MsMetaWrapper? Currency { get; set; }
|
||
[JsonPropertyName("priceType")] public MsPriceType? PriceType { get; set; }
|
||
}
|
||
|
||
public class MsPriceType
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("externalCode")] public string? ExternalCode { get; set; }
|
||
}
|
||
|
||
public class MsMoney
|
||
{
|
||
[JsonPropertyName("value")] public decimal Value { get; set; }
|
||
[JsonPropertyName("currency")] public MsMetaWrapper? Currency { get; set; }
|
||
}
|
||
|
||
public class MsAlcoholic
|
||
{
|
||
[JsonPropertyName("type")] public string? Type { get; set; }
|
||
[JsonPropertyName("strength")] public double? Strength { get; set; }
|
||
}
|
||
|
||
public class MsCurrency
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("isoCode")] public string? IsoCode { get; set; }
|
||
[JsonPropertyName("rate")] public double? Rate { get; set; }
|
||
}
|
||
|
||
public class MsUom
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||
}
|
||
|
||
public class MsProductFolder
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string Name { get; set; } = "";
|
||
[JsonPropertyName("pathName")] public string? PathName { get; set; }
|
||
[JsonPropertyName("productFolder")] public MsMetaWrapper? ParentFolder { get; set; }
|
||
[JsonPropertyName("archived")] public bool Archived { get; set; }
|
||
}
|
||
|
||
public class MsCountry
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||
[JsonPropertyName("externalCode")] public string? ExternalCode { get; set; }
|
||
}
|
||
|
||
public class MsCounterparty
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string Name { get; set; } = "";
|
||
[JsonPropertyName("legalTitle")] public string? LegalTitle { get; set; }
|
||
[JsonPropertyName("legalAddress")] public string? LegalAddress { get; set; }
|
||
[JsonPropertyName("actualAddress")] public string? ActualAddress { get; set; }
|
||
[JsonPropertyName("inn")] public string? Inn { get; set; }
|
||
[JsonPropertyName("kpp")] public string? Kpp { get; set; }
|
||
[JsonPropertyName("ogrn")] public string? Ogrn { get; set; }
|
||
[JsonPropertyName("companyType")] public string? CompanyType { get; set; }
|
||
[JsonPropertyName("phone")] public string? Phone { get; set; }
|
||
[JsonPropertyName("email")] public string? Email { get; set; }
|
||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||
[JsonPropertyName("archived")] public bool Archived { get; set; }
|
||
[JsonPropertyName("tags")] public List<string>? Tags { get; set; }
|
||
}
|
||
|
||
// ── Документы (приёмки/продажи/…): общие поля + позиции ──────────────────────
|
||
public class MsDocument
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("name")] public string? Name { get; set; } // номер документа
|
||
[JsonPropertyName("moment")] public string? Moment { get; set; } // "yyyy-MM-dd HH:mm:ss.fff" МСК
|
||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||
[JsonPropertyName("applicable")] public bool Applicable { get; set; }
|
||
[JsonPropertyName("sum")] public decimal Sum { get; set; } // тиыны (может прийти как 900000.0)
|
||
[JsonPropertyName("agent")] public MsMetaWrapper? Agent { get; set; }
|
||
[JsonPropertyName("store")] public MsMetaWrapper? Store { get; set; }
|
||
[JsonPropertyName("owner")] public MsMetaWrapper? Owner { get; set; } // сотрудник
|
||
[JsonPropertyName("organization")] public MsMetaWrapper? Organization { get; set; }
|
||
[JsonPropertyName("positions")] public MsListResponse<MsPosition>? Positions { get; set; }
|
||
// розничные продажи:
|
||
[JsonPropertyName("cashSum")] public decimal CashSum { get; set; }
|
||
[JsonPropertyName("noCashSum")] public decimal NoCashSum { get; set; }
|
||
[JsonPropertyName("retailShift")] public MsMetaWrapper? RetailShift { get; set; }
|
||
[JsonPropertyName("demand")] public MsMetaWrapper? Demand { get; set; } // для retailsalesreturn — исходный чек
|
||
}
|
||
|
||
public class MsPosition
|
||
{
|
||
[JsonPropertyName("id")] public string? Id { get; set; }
|
||
[JsonPropertyName("quantity")] public decimal Quantity { get; set; }
|
||
[JsonPropertyName("calculatedQuantity")] public decimal CalculatedQuantity { get; set; } // инвентаризация: учётное кол-во
|
||
[JsonPropertyName("price")] public decimal Price { get; set; } // тиыны за ед.
|
||
[JsonPropertyName("discount")] public decimal Discount { get; set; } // % скидки
|
||
[JsonPropertyName("vat")] public int Vat { get; set; }
|
||
[JsonPropertyName("assortment")] public MsMetaWrapper? Assortment { get; set; }
|
||
}
|