food-market/src/food-market.infrastructure/Integrations/MoySklad/MoySkladDtos.cs
nns 39d0243ba3
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
feat(migration): денежные документы (платежи/ордера/внесения/выплаты) + плуг балансов счетов
- ImportMoneyDocsAsync: paymentout/paymentin/cashin/cashout/retaildrawercashin/out
  → MoneyTransaction (история), agent→контрагент по externalId, суммы ÷100, МСК→UTC
- EnsureMoneyAccountsAsync: касса + расчётный счёт орг (идемпотентно)
- SetMoneyOpeningBalancesAsync: OpeningBalance = report/money/byaccount − Σпроводок,
  текущий баланс счёта точно совпадает с МойСкладом
- GetMoneyByAccountAsync в MoySkladClient; MsMoneyByAccountRow, paymentPurpose в DTO
- контроллер: type=money (все деньги+плуг), type=balances, одиночные денежные типы

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-09 16:32:22 +05:00

188 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 — исходный чек
// денежные документы (платежи/ордера):
[JsonPropertyName("paymentPurpose")] public string? PaymentPurpose { get; set; }
}
// report/money/byaccount: строка без account = наличные (касса) орг, строка с account = банк. счёт.
// balance — в тиынах.
public class MsMoneyByAccountRow
{
[JsonPropertyName("account")] public MsMetaWrapper? Account { get; set; }
[JsonPropertyName("balance")] public decimal Balance { get; set; }
}
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; }
}