Часть 3 + автопоиск (данные sysadmin: касса МойСклад спамит «Порт не выбран»): - Весовой товар при сканировании/плитке → вес с весов (если на связи), иначе модалка ручного ввода веса. Сумма = цена/кг × вес; подпись «1,235 кг × 690 ₸/кг». - ScaleMonitor (pos.core): опрос ТОЛЬКО по требованию (при весовом товаре), мягкая деградация на ручной ввод, запись о потере/восстановлении связи РОВНО ОДИН раз (не сотни «Таймаут»). Юнит-тесты (100 опросов → 1 запись). - ScaleDiscovery (pos): автоскан всех COM-портов (вкл. USB-COM CH340/Prolific) × протоколы Масса-К/CAS × скорости; кнопка «Найти весы» в верхней панели; найденный порт запоминается (kv) и восстанавливается при старте. - UnitShort («шт»/«кг»/«л») протянут через sync→SQLite→PosProduct/CartLine; цена весового показывается «690 ₸/кг» вместо кода ОКЕИ «690 ₸/796». - Разбор этикеток в кассе — по настройкам орг (по умолчанию ВЫКЛ, точный штрихкод). - Юнит-тесты 321/321 (обновлены PosBarcodeTests под дефолт-off). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
2.6 KiB
C#
74 lines
2.6 KiB
C#
using FluentAssertions;
|
||
using foodmarket.Pos.Core.Hardware;
|
||
using foodmarket.Pos.Core.Models;
|
||
using Xunit;
|
||
|
||
namespace foodmarket.UnitTests;
|
||
|
||
public class ScaleMonitorTests
|
||
{
|
||
[Fact]
|
||
public async Task No_reader_returns_null_and_disconnected()
|
||
{
|
||
var m = new ScaleMonitor();
|
||
(await m.TryReadWeightAsync()).Should().BeNull();
|
||
m.IsConnected.Should().BeFalse();
|
||
m.HasReader.Should().BeFalse();
|
||
m.StatusText.Should().Be("Весы не подключены");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Reader_weight_is_returned_and_connected()
|
||
{
|
||
var m = new ScaleMonitor();
|
||
m.SetReader(_ => Task.FromResult(1.234m));
|
||
(await m.TryReadWeightAsync()).Should().Be(1.234m);
|
||
m.IsConnected.Should().BeTrue();
|
||
m.StatusText.Should().Be("Весы на связи");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Loss_of_connection_is_logged_exactly_once()
|
||
{
|
||
var log = new List<string>();
|
||
var m = new ScaleMonitor(log.Add);
|
||
m.SetReader(_ => throw new InvalidOperationException("Порт не выбран"));
|
||
|
||
// Сто опросов подряд при оборванной связи — одна запись о потере (не сотни).
|
||
for (int i = 0; i < 100; i++) (await m.TryReadWeightAsync()).Should().BeNull();
|
||
|
||
log.Count(l => l.Contains("нет связи")).Should().Be(1, "потеря связи логируется один раз");
|
||
m.IsConnected.Should().BeFalse();
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Recovery_after_loss_is_logged_once()
|
||
{
|
||
var log = new List<string>();
|
||
var m = new ScaleMonitor(log.Add);
|
||
var fail = true;
|
||
m.SetReader(_ => fail ? throw new TimeoutException() : Task.FromResult(0.5m));
|
||
|
||
await m.TryReadWeightAsync(); // потеря
|
||
await m.TryReadWeightAsync(); // ещё раз — не логируем повторно
|
||
fail = false;
|
||
(await m.TryReadWeightAsync()).Should().Be(0.5m); // восстановление
|
||
|
||
log.Count(l => l.Contains("нет связи")).Should().Be(1);
|
||
log.Count(l => l.Contains("восстановлена")).Should().Be(1);
|
||
m.IsConnected.Should().BeTrue();
|
||
}
|
||
|
||
[Fact]
|
||
public void Weighed_line_text_shows_kg_times_price_per_kg()
|
||
{
|
||
var line = new CartLine
|
||
{
|
||
ProductId = Guid.NewGuid(), Name = "Яблоки", UnitCode = "166", UnitShort = "кг",
|
||
IsWeighed = true, UnitPrice = 690m, Quantity = 1.235m,
|
||
};
|
||
line.WeighedQtyText.Should().Be("1,235 кг × 690 ₸/кг");
|
||
line.LineTotal.Should().Be(852.15m);
|
||
}
|
||
}
|