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
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>
82 lines
3.8 KiB
C#
82 lines
3.8 KiB
C#
using System.Net.Http.Json;
|
||
using System.Text.Json;
|
||
using FluentAssertions;
|
||
using foodmarket.IntegrationTests.Support;
|
||
using Xunit;
|
||
|
||
namespace foodmarket.IntegrationTests;
|
||
|
||
/// <summary>Регистрация сохраняет выбранный тариф и бесплатный период (90 дней),
|
||
/// а для «Бизнес» — конфигурацию конструктора. Settings-эндпоинт отдаёт их
|
||
/// read-only для показа в кабинете владельца. Биллинга/блокировки нет.
|
||
/// Решение владельца 12.10.</summary>
|
||
[Collection(ApiCollection.Name)]
|
||
public class PlanSignupTests
|
||
{
|
||
private readonly ApiFactory _factory;
|
||
public PlanSignupTests(ApiFactory factory) => _factory = factory;
|
||
|
||
private async Task<JsonElement> SignupWithPlanAndGetSettingsAsync(ApiActor api, string slug, object body)
|
||
{
|
||
var resp = await api.Http.PostAsJsonAsync("/api/auth/signup", body);
|
||
resp.IsSuccessStatusCode.Should().BeTrue(await resp.Content.ReadAsStringAsync());
|
||
api.UseToken(await api.TokenAsync($"{slug}@example.kz", "Passw0rd!"));
|
||
return await api.GetJsonAsync("/api/organization/settings");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Business_signup_saves_plan_trial_and_config()
|
||
{
|
||
var api = new ApiActor(_factory.CreateClient());
|
||
var slug = $"plan-biz-{Guid.NewGuid():N}";
|
||
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
|
||
{
|
||
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
|
||
phone = "+77010000000", plan = "business",
|
||
shops = 3, cashes = 4, warehouses = 2, employees = 25,
|
||
});
|
||
|
||
s.GetProperty("plan").GetString().Should().Be("business");
|
||
s.GetProperty("planShops").GetInt32().Should().Be(3);
|
||
s.GetProperty("planCashes").GetInt32().Should().Be(4);
|
||
s.GetProperty("planWarehouses").GetInt32().Should().Be(2);
|
||
s.GetProperty("planEmployees").GetInt32().Should().Be(25);
|
||
|
||
var trial = s.GetProperty("freeTrialEndsAt").GetDateTime();
|
||
var expected = DateTime.UtcNow.AddDays(90);
|
||
trial.Should().BeCloseTo(expected, TimeSpan.FromHours(1), "бесплатный период = регистрация + 90 дней");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Start_signup_saves_plan_without_config()
|
||
{
|
||
var api = new ApiActor(_factory.CreateClient());
|
||
var slug = $"plan-start-{Guid.NewGuid():N}";
|
||
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
|
||
{
|
||
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
|
||
phone = "+77010000000", plan = "start",
|
||
});
|
||
|
||
s.GetProperty("plan").GetString().Should().Be("start");
|
||
s.GetProperty("freeTrialEndsAt").ValueKind.Should().Be(JsonValueKind.String, "дата бесплатного периода проставлена");
|
||
// Конфигурация «Бизнес» не относится к «Старт» — поля null.
|
||
s.GetProperty("planShops").ValueKind.Should().Be(JsonValueKind.Null);
|
||
s.GetProperty("planEmployees").ValueKind.Should().Be(JsonValueKind.Null);
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Unknown_plan_falls_back_to_start()
|
||
{
|
||
var api = new ApiActor(_factory.CreateClient());
|
||
var slug = $"plan-unk-{Guid.NewGuid():N}";
|
||
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
|
||
{
|
||
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
|
||
phone = "+77010000000", plan = "enterprise-xxl",
|
||
});
|
||
|
||
s.GetProperty("plan").GetString().Should().Be("start", "неизвестный тариф нормализуется к «start»");
|
||
}
|
||
}
|