Реальный сценарий владельца: весов с печатью этикеток нет, штрихкоды весовых —
обычные коды «27xxxxx» в карточке. Исправлены два бага:
- поиск по ШК матчил весовой PLU по АРТИКУЛУ (вода арт.12345 → 1,5 кг) — убрано,
поиск по штрихкоду больше нигде не матчит по артикулу;
- разбор весовых этикеток был дефолт-ON (WeightedBarcodeSettings.Enabled,
Organization.WeightBarcodeEnabled) и ловил обычные коды — теперь дефолт OFF.
- ByBarcode: сначала точное совпадение штрихкода (вкл. короткие «27xxxxx»),
разбор этикетки — только если включён в орг И точного ШК нет.
- Phase40: WeightBarcodeEnabled DEFAULT false + выключение у существующих орг;
WeightedCodeFormat('short'|'ean13')/WeightedCodePrefix(27)/WeightedCodeDigits(5).
- Генератор ШК нового весового товара: короткий «<prefix>+N цифр» (27xxxxx, next-free)
или EAN-13 по настройке; уникальность.
- Настройки орг отдают/принимают формат кода весовых.
- Sync отдаёт unitShort («шт»/«кг»/«л») рядом с unitCode (ОКЕИ) — shared UnitShort.
- Тесты: MobileApi (exact-only по умолчанию; не матчит артикул; PLU как ШК при вкл) 9/9;
unit WeightedBarcode/UnitShort 16/16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
5.3 KiB
C#
134 lines
5.3 KiB
C#
using FluentAssertions;
|
||
using foodmarket.Domain.Organizations;
|
||
using foodmarket.Shared.Barcodes;
|
||
using Xunit;
|
||
|
||
namespace foodmarket.UnitTests;
|
||
|
||
public class WeightedBarcodeTests
|
||
{
|
||
[Fact]
|
||
public void Normal_barcode_passes_through()
|
||
{
|
||
var r = WeightedBarcode.Parse("4870204010101");
|
||
r.IsWeighted.Should().BeFalse();
|
||
r.Lookup.Should().Be("4870204010101");
|
||
r.WeightKg.Should().BeNull();
|
||
r.Price.Should().BeNull();
|
||
}
|
||
|
||
// По умолчанию (решение владельца 09.10) разбор этикеток ВЫКЛЮЧЕН: без явно
|
||
// включённых настроек весоподобный код трактуется как обычный штрихкод.
|
||
private static readonly WeightedBarcodeSettings On = WeightedBarcodeSettings.Default with { Enabled = true };
|
||
|
||
[Fact]
|
||
public void Default_settings_are_disabled()
|
||
{
|
||
WeightedBarcodeSettings.Default.Enabled.Should().BeFalse();
|
||
var r = WeightedBarcode.Parse("2112345015007");
|
||
r.IsWeighted.Should().BeFalse("по умолчанию разбор этикеток выключен");
|
||
r.Lookup.Should().Be("2112345015007");
|
||
}
|
||
|
||
[Fact]
|
||
public void Weight_prefix_extracts_plu_and_kg()
|
||
{
|
||
// 21 | 12345 | 01500 | K → PLU 12345, вес 1.500 кг (при включённом разборе)
|
||
var r = WeightedBarcode.Parse("2112345015007", On);
|
||
r.IsWeighted.Should().BeTrue();
|
||
r.ValueKind.Should().Be(WeightedValueKind.WeightKg);
|
||
r.Lookup.Should().Be("12345");
|
||
r.WeightKg.Should().Be(1.500m);
|
||
r.Price.Should().BeNull();
|
||
}
|
||
|
||
[Fact]
|
||
public void Price_prefix_extracts_plu_and_price()
|
||
{
|
||
// 25 | 54321 | 12345 | K → PLU 54321, цена 123.45 (при включённом разборе)
|
||
var r = WeightedBarcode.Parse("2554321123456", On);
|
||
r.IsWeighted.Should().BeTrue();
|
||
r.ValueKind.Should().Be(WeightedValueKind.Price);
|
||
r.Lookup.Should().Be("54321");
|
||
r.Price.Should().Be(123.45m);
|
||
r.WeightKg.Should().BeNull();
|
||
}
|
||
|
||
[Fact]
|
||
public void Disabled_settings_treats_weighted_as_plain()
|
||
{
|
||
var settings = WeightedBarcodeSettings.Default with { Enabled = false };
|
||
var r = WeightedBarcode.Parse("2112345015007", settings);
|
||
r.IsWeighted.Should().BeFalse();
|
||
r.Lookup.Should().Be("2112345015007");
|
||
}
|
||
|
||
[Fact]
|
||
public void Custom_prefixes_and_code_digits_honored()
|
||
{
|
||
// Префикс 28 как весовой, код 6 цифр: 28 | 123456 | 999 | K
|
||
var settings = WeightedBarcodeSettings.Create(
|
||
enabled: true, weightCsv: "28", priceCsv: "", codeDigits: 6);
|
||
var r = WeightedBarcode.Parse("2812345699990", settings);
|
||
r.IsWeighted.Should().BeTrue();
|
||
r.ValueKind.Should().Be(WeightedValueKind.WeightKg);
|
||
r.Lookup.Should().Be("123456");
|
||
// value digits = остаток до контрольной: позиции 8..11 = "9999" → 9.999 кг
|
||
r.WeightKg.Should().Be(9.999m);
|
||
}
|
||
|
||
[Fact]
|
||
public void Create_from_csv_defaults_on_blank()
|
||
{
|
||
var s = WeightedBarcodeSettings.Create(true, null, "", 0);
|
||
s.WeightPrefixes.Should().Contain(new[] { 20, 21, 22, 23, 24 });
|
||
s.PricePrefixes.Should().Contain(new[] { 25, 26, 27, 28, 29 });
|
||
s.CodeDigits.Should().Be(5);
|
||
}
|
||
}
|
||
|
||
public class RolePermissionsEffectiveTests
|
||
{
|
||
[Fact]
|
||
public void SuperAdmin_gets_everything_even_in_simple_mode()
|
||
{
|
||
var p = RolePermissions.Effective(null, isSuperAdmin: true, isAdmin: false, advancedMode: false);
|
||
p["ProductsEdit"].Should().BeTrue();
|
||
p["DemandsView"].Should().BeTrue("SuperAdmin обходит простой режим");
|
||
p["MoneyEdit"].Should().BeTrue();
|
||
}
|
||
|
||
[Fact]
|
||
public void Admin_in_simple_mode_loses_advanced_only()
|
||
{
|
||
var p = RolePermissions.Effective(null, isSuperAdmin: false, isAdmin: true, advancedMode: false);
|
||
p["ProductsEdit"].Should().BeTrue("базовые права у Admin есть");
|
||
p["DemandsView"].Should().BeFalse("advanced-only скрыт в простом режиме");
|
||
p["TransferEdit"].Should().BeFalse();
|
||
p["PriceTypesManage"].Should().BeFalse();
|
||
p["StocksView"].Should().BeTrue("не advanced-only");
|
||
}
|
||
|
||
[Fact]
|
||
public void Admin_in_advanced_mode_keeps_advanced()
|
||
{
|
||
var p = RolePermissions.Effective(null, isSuperAdmin: false, isAdmin: true, advancedMode: true);
|
||
p["DemandsView"].Should().BeTrue();
|
||
p["LoyaltyManage"].Should().BeTrue();
|
||
}
|
||
|
||
[Fact]
|
||
public void Plain_role_reflects_its_flags_and_mode()
|
||
{
|
||
var role = new RolePermissions { ProductsView = true, StocksView = true, DemandsView = true };
|
||
var simple = RolePermissions.Effective(role, false, false, advancedMode: false);
|
||
simple["ProductsView"].Should().BeTrue();
|
||
simple["StocksView"].Should().BeTrue();
|
||
simple["DemandsView"].Should().BeFalse("advanced-only в простом режиме");
|
||
simple["ProductsEdit"].Should().BeFalse("флаг не выдан роли");
|
||
|
||
var advanced = RolePermissions.Effective(role, false, false, advancedMode: true);
|
||
advanced["DemandsView"].Should().BeTrue();
|
||
}
|
||
}
|