Some checks failed
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 59s
CI / Web (React + Vite) (push) Successful in 42s
Docker API / Build + push API (push) Successful in 1m26s
Docker Web / Build + push Web (push) Successful in 35s
Docker API / Deploy API on stage (push) Failing after 38s
Docker Web / Deploy Web on stage (push) Successful in 12s
Было: каждая орга держала свои 5 копий («штука», «кг», ...). 95 строк в БД на 19 орг — duplication, любой Admin мог их редактировать. Стало: 5 globals (OrganizationId=NULL), CRUD только у SuperAdmin. Орга включает нужные единицы у себя через junction org_units_of_measure. Backend: - UnitOfMeasure: добавлен IsActive (для soft-delete с filtered unique index) - Новый OrgUnitOfMeasure (junction PK Organization+Unit, FK Restrict) - Migration Phase5c_UnitsOfMeasureGlobal: безопасная для prod — поднимает по одной строке на (Code, Name) до global, remap'ит products.UnitOfMeasureId, наполняет junction по факту существующих привязок, удаляет дубликаты. - /api/catalog/units-of-measure для org Admin: read-only список enabled-globals + POST/DELETE /enable для toggle - /api/super-admin/units-of-measure: full CRUD; DELETE soft (IsActive=false) с 409 если есть products или active org-junction (со списком орг) - DevDataSeeder.SeedTenantReferencesAsync вместо создания per-tenant юнитов — auto-enable всех active globals через junction Frontend: - /catalog/units — checkbox-список (включить/выключить); CTA на платформу для SuperAdmin - /super-admin/units — full CRUD над глобалами, 409 со списком организаций при попытке деактивировать используемую единицу
97 lines
4.4 KiB
C#
97 lines
4.4 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, string? Description, 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, string? Description = null);
|
|
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(
|
|
string Name, 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,
|
|
string? ImageUrl = null,
|
|
IReadOnlyList<ProductPriceInput>? Prices = null,
|
|
IReadOnlyList<ProductBarcodeInput>? Barcodes = null);
|