food-market/tests/food-market.IntegrationTests/RegistryCopyPrimaryBarcodeTests.cs
nns 0ce0e0df77
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (test + latest) (push) Waiting to run
Docker Public / Deploy :test → test.food-market.kz (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
fix(регистрация): 7 правок этапа «Регистрация» (прогон 12.10)
1. Маска телефона: префикс «+7 », оператор не подставляется заранее.
   Нормализация снимает ведущую «8» и код страны «7» (на 11 цифрах),
   value хранится каноническим «+7»+national и восстанавливается снятием
   литерального «+7» (без 8/11-эвристик) — ввод больше не «скачет».
   Обе копии (public + admin). Проверено на всех вариантах + вставка.
2. Тариф и бесплатный период: Organization.Plan/FreeTrialEndsAt +
   конфигурация «Бизнес» (Phase50, существующие → «start», дата NULL).
   Signup сохраняет план и 90 дней; показ в кабинете владельца и в
   карточке/списке суперадмина. Биллинга/блокировки нет.
3. Ошибки формы: переход к первому полю с ошибкой + фокус; единые
   сообщения «Укажите email/телефон/название магазина», «Придумайте пароль».
4. «Первые шаги»: кнопка «Скрыть» (возврат из настроек организации);
   шаг каталога показывает статус копии реестра («загружается…» /
   «Каталог готов: N товаров — проверьте продажные цены»); ссылка на
   Forgejo заменена на «Базу знаний».
5. «Новые функции»: не считаем изменения до даты регистрации орг
   (новой орг баннер скрыт) + русская плюрализация улучшений/исправлений.
6. Карточка товара: «Закупочная цена» видна и в простом режиме (настройка
   ShowReferencePriceOnProduct), подпись настройки приведена к новой схеме.
7. Копия реестра: первый штрихкод помечается «Основным»; бэкфилл уже
   скопированных товаров без основного (Phase51).

Тесты: PlanSignupTests (3), RegistryCopyPrimaryBarcodeTests (1),
MarkupToggleTests (3, регрессия) — зелёные. Phone-нормализация покрыта
симуляцией ввода/вставки.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-12 21:46:15 +05:00

75 lines
3.9 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 System.Text.Json;
using FluentAssertions;
using foodmarket.Domain.Registry;
using foodmarket.Infrastructure.Persistence;
using foodmarket.Infrastructure.Registry;
using foodmarket.IntegrationTests.Support;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace foodmarket.IntegrationTests;
/// <summary>Копия «Реестра товаров» в каталог магазина должна помечать первый
/// штрихкод «Основным» (IsPrimary). Товар с единственным штрихкодом раньше
/// оставался без «Основного» (баг, fix #7).</summary>
[Collection(ApiCollection.Name)]
public class RegistryCopyPrimaryBarcodeTests
{
private readonly ApiFactory _factory;
public RegistryCopyPrimaryBarcodeTests(ApiFactory factory) => _factory = factory;
private static string RandomBarcode()
=> string.Concat(Enumerable.Range(0, 13).Select(_ => Random.Shared.Next(0, 10)));
[Fact]
public async Task Copy_sets_single_barcode_as_primary()
{
var api = new ApiActor(_factory.CreateClient());
var slug = $"regcopy-{Guid.NewGuid():N}";
await api.SignupAndLoginAsync(slug);
var settings = await api.GetJsonAsync("/api/organization/settings");
var orgId = Guid.Parse(settings.GetProperty("id").GetString()!);
var barcode = RandomBarcode();
var cardName = $"REG-{slug}";
// Готовим карточку реестра с ОДНИМ штрихкодом и запускаем копию напрямую
// (Hangfire в тестах выключен, поэтому зовём сервис сами).
using (var scope = _factory.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var unitId = await db.UnitsOfMeasure.AsNoTracking().Select(u => u.Id).FirstAsync();
db.ProductRegistryCards.Add(new ProductRegistryCard
{
Name = cardName,
UnitOfMeasureId = unitId,
Cost = 100m,
PurchasePrice = 100m,
RetailPrice = 150m,
Source = RegistryCardSource.Shop,
Barcodes = new List<ProductRegistryBarcode> { new() { Code = barcode } },
});
await db.SaveChangesAsync();
// Регистрация выставила RegistryCopyState=1; копия отработает.
var svc = scope.ServiceProvider.GetRequiredService<ProductRegistryService>();
await svc.CopyRegistryToOrgAsync(orgId, default);
}
// Находим скопированный товар по штрихкоду и проверяем «Основной».
var found = await api.GetJsonAsync($"/api/catalog/products?pageSize=50&search={cardName}");
var items = found.TryGetProperty("items", out var it) ? it : found;
var product = items.EnumerateArray()
.FirstOrDefault(p => p.GetProperty("name").GetString() == cardName);
product.ValueKind.Should().Be(JsonValueKind.Object, "товар из реестра скопирован в каталог");
var detail = await api.GetJsonAsync($"/api/catalog/products/{product.GetProperty("id").GetString()}");
var barcodes = detail.GetProperty("barcodes").EnumerateArray().ToList();
barcodes.Should().ContainSingle(b => b.GetProperty("code").GetString() == barcode);
barcodes.Count(b => b.GetProperty("isPrimary").GetBoolean()).Should().Be(1, "ровно один штрихкод — «Основной»");
barcodes.Single(b => b.GetProperty("code").GetString() == barcode)
.GetProperty("isPrimary").GetBoolean().Should().BeTrue("единственный штрихкод должен быть «Основным»");
}
}