food-market/tests/food-market.UnitTests/BusinessTimeTests.cs
nns f3a177a121 fix(sales): дата чека в UTC + защита от «будущих» времён
«Последние продажи»/Z-отчёт показывали времена вперёд, потому что дата чека
бралась от клиента (input.Date / POS OccurredAt) без нормализации: наивная
локальная дата или спешащие часы кассы давали будущий инстант. Добавил
BusinessTime.ToInstantUtc: Kind→UTC и clamp будущего (>5 мин) к now — чек не
может быть в будущем. Применено в рознице (create) и в приёме чеков с кассы
(движение берёт тот же инстант). Юнит-тесты на нормализацию/clamp.

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

53 lines
2 KiB
C#
Raw Permalink 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 FluentAssertions;
using foodmarket.Application.Common;
using Xunit;
namespace foodmarket.UnitTests;
/// <summary>Нормализация даты документа к UTC и защита от «будущих» времён
/// (корень бага «Последние продажи» показывали время вперёд).</summary>
public class BusinessTimeTests
{
[Fact]
public void Utc_date_in_past_is_unchanged()
{
var past = DateTime.UtcNow.AddHours(-3);
BusinessTime.ToInstantUtc(past).Should().BeCloseTo(past, TimeSpan.FromSeconds(1));
}
[Fact]
public void Future_date_is_clamped_to_now()
{
var future = DateTime.UtcNow.AddHours(3);
var result = BusinessTime.ToInstantUtc(future);
result.Should().BeOnOrBefore(DateTime.UtcNow.AddSeconds(1));
result.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1), "будущее заменяется на now");
}
[Fact]
public void Small_clock_skew_within_tolerance_is_kept()
{
var slightlyAhead = DateTime.UtcNow.AddMinutes(2);
BusinessTime.ToInstantUtc(slightlyAhead).Should().BeCloseTo(slightlyAhead, TimeSpan.FromSeconds(1),
"небольшой разбег часов (до 5 мин) допускаем");
}
[Fact]
public void Local_kind_is_converted_to_utc()
{
var local = DateTime.SpecifyKind(DateTime.Now.AddHours(-1), DateTimeKind.Local);
var result = BusinessTime.ToInstantUtc(local);
result.Kind.Should().Be(DateTimeKind.Utc);
result.Should().BeCloseTo(local.ToUniversalTime(), TimeSpan.FromSeconds(1));
}
[Fact]
public void Unspecified_kind_is_treated_as_utc_no_shift()
{
var naive = DateTime.SpecifyKind(DateTime.UtcNow.AddHours(-2), DateTimeKind.Unspecified);
var result = BusinessTime.ToInstantUtc(naive);
result.Kind.Should().Be(DateTimeKind.Utc);
result.Should().BeCloseTo(DateTime.SpecifyKind(naive, DateTimeKind.Utc), TimeSpan.FromSeconds(1));
}
}