food-market/src/food-market.application/Catalog/CatalogDtos.cs
nns e13ac655e5 fix(catalog): FK-guard удаления контрагента + валидация полей товара
Найдено в catalog-edge:

- DELETE контрагента, на которого ссылаются supplies/retail-sales/products
  (DefaultSupplier), отдавал 500 (DbUpdateException 23503) вместо понятного
  409. Добавлен явный чек использования → Conflict со списком где занят.
- POST товара с пустым Name проходил до FK-проверки и падал неинформативно;
  теперь явный 400 с указанием поля. На ProductInput навешены
  [Required]/[MinLength]/[StringLength] на Name/Article/ImageUrl — отсекаем
  пустые и сверхдлинные значения на уровне модели.

catalog-edge: 12/12.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:03:37 +05:00

99 lines
4.5 KiB
C#

using System.ComponentModel.DataAnnotations;
using foodmarket.Domain.Catalog;
namespace foodmarket.Application.Catalog;
public record CountryDto(
Guid Id, string Code, string Name,
Guid? DefaultCurrencyId, string? DefaultCurrencyCode, string? DefaultCurrencySymbol,
decimal VatRate);
public record CurrencyDto(Guid Id, string Code, string Name, string Symbol);
public record UnitOfMeasureDto(
Guid Id, string Code, string Name, Guid? OrganizationId,
bool IsActive = true, bool IsEnabledForOrg = true);
public record PriceTypeDto(
Guid Id, string Name, bool IsRequired, bool IsSystem,
bool IsRetail, int SortOrder);
public record StoreDto(
Guid Id, string Name, string? Code, string? Address, string? Phone,
string? ManagerName, bool IsMain, bool IsActive);
public record RetailPointDto(
Guid Id, string Name, string? Code, Guid StoreId, string? StoreName,
string? Address, string? Phone, string? FiscalSerial, string? FiscalRegNumber, bool IsActive);
public record ProductGroupDto(
Guid Id, string Name, Guid? ParentId, string Path, int SortOrder,
decimal? MarkupPercent, Guid? OrganizationId);
public record CounterpartyDto(
Guid Id, string Name, string? LegalName, CounterpartyType Type,
string? Bin, string? Iin, string? TaxNumber, Guid? CountryId, string? CountryName,
string? Address, string? Phone, string? Email,
string? BankName, string? BankAccount, string? Bik, string? ContactPerson, string? Notes);
public record ProductBarcodeDto(Guid Id, string Code, BarcodeType Type, bool IsPrimary);
public record ProductPriceDto(Guid Id, Guid PriceTypeId, string PriceTypeName, decimal Amount, Guid CurrencyId, string CurrencyCode);
public record ProductDto(
Guid Id, string Name, string? Article, string? Description,
Guid UnitOfMeasureId, string UnitName,
decimal Vat, bool VatEnabled,
Guid ProductGroupId, string ProductGroupName,
Guid? DefaultSupplierId, string? DefaultSupplierName,
Guid? CountryOfOriginId, string? CountryOfOriginName,
bool IsService, Packaging Packaging, bool IsMarked,
decimal? MinStock, decimal? MaxStock,
decimal? ReferencePrice, DateTime? ReferencePriceUpdatedAt,
Guid? PurchaseCurrencyId, string? PurchaseCurrencyCode,
decimal Cost, DateTime? LastSupplyAt,
string? ImageUrl,
IReadOnlyList<ProductPriceDto> Prices,
IReadOnlyList<ProductBarcodeDto> Barcodes);
// Upsert payloads (input)
public record CountryInput(
string Code, string Name,
Guid? DefaultCurrencyId = null, decimal VatRate = 0m);
public record CurrencyInput(string Code, string Name, string Symbol);
public record UnitOfMeasureInput(string Code, string Name);
public record PriceTypeInput(
string Name, bool IsRequired = false,
bool IsRetail = false, int SortOrder = 0);
public record StoreInput(
string Name, string? Code,
string? Address = null, string? Phone = null, string? ManagerName = null,
bool IsMain = false, bool IsActive = true);
public record RetailPointInput(
string Name, string? Code, Guid StoreId,
string? Address = null, string? Phone = null,
string? FiscalSerial = null, string? FiscalRegNumber = null, bool IsActive = true);
public record ProductGroupInput(
string Name, Guid? ParentId, int SortOrder = 0,
[Range(0, 1000)] decimal? MarkupPercent = null);
public record CounterpartyInput(
string Name, string? LegalName, CounterpartyType Type,
string? Bin, string? Iin, string? TaxNumber, Guid? CountryId,
string? Address, string? Phone, string? Email,
string? BankName, string? BankAccount, string? Bik, string? ContactPerson, string? Notes);
public record ProductBarcodeInput(string Code, BarcodeType Type = BarcodeType.Ean13, bool IsPrimary = false);
public record ProductPriceInput(Guid PriceTypeId, [Range(0, 1e10)] decimal Amount, Guid CurrencyId);
public record ProductInput(
[Required, MinLength(1), StringLength(500)] string Name,
[StringLength(500)] string? Article,
string? Description,
Guid UnitOfMeasureId, [Range(0, 100)] decimal? Vat, bool VatEnabled,
Guid ProductGroupId, Guid? DefaultSupplierId, Guid? CountryOfOriginId,
bool IsService = false, Packaging Packaging = Packaging.Piece, bool IsMarked = false,
[Range(0, 1e10)] decimal? MinStock = null, [Range(0, 1e10)] decimal? MaxStock = null,
[Range(0, 1e10)] decimal? ReferencePrice = null, Guid? PurchaseCurrencyId = null,
[StringLength(1000)] string? ImageUrl = null,
IReadOnlyList<ProductPriceInput>? Prices = null,
IReadOnlyList<ProductBarcodeInput>? Barcodes = null);