Files
sms-task-one/src/Console/Program.cs

206 lines
6.0 KiB
C#
Raw 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.Globalization;
using ApiClient;
using ApiClient.Grpc;
using ApiClient.Http;
using ConsoleApp.Data;
using ConsoleApp.Logging;
using Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
.AddEnvironmentVariables()
.Build();
var connectionString = configuration.GetConnectionString("Default")
?? throw new InvalidOperationException("Connection string 'Default' не задана.");
var httpOptions = configuration.GetSection("Http").Get<HttpSmsClientOptions>() ?? new();
var grpcOptions = configuration.GetSection("Grpc").Get<GrpcSmsClientOptions>() ?? new();
using var log = ConsoleLog.Open();
var smsClient = AskSmsClient(log, httpOptions, grpcOptions);
try
{
log.WriteLine("Инициализация базы данных...");
await using var db = CreateDbContext(connectionString);
await db.Database.MigrateAsync();
log.WriteLine("База данных готова.");
log.WriteLine("Запрос меню с сервера...");
var menuResponse = await smsClient.GetMenuAsync(withPrice: true);
if (!menuResponse.Success)
{
log.WriteLine(menuResponse.ToString());
return;
}
var dishes = menuResponse.Data?.MenuItems ?? [];
await SaveDishesAsync(db, dishes);
log.WriteLine("Меню:");
foreach (var dish in dishes)
{
log.WriteLine(dish.ToString());
}
var order = ReadOrder(log, dishes);
log.WriteLine(order.ToString());
log.WriteLine("Отправка заказа на сервер...");
var sendResponse = await smsClient.SendOrderAsync(order);
if (sendResponse.Success)
{
log.WriteLine("УСПЕХ");
return;
}
log.WriteLine(sendResponse.ToString());
}
finally
{
(smsClient as IDisposable)?.Dispose();
log.WriteLine($"Файл лога (запуск {log.StartedAt:yyyy-MM-dd HH:mm:ss}): {log.FilePath}");
}
static ISmsClient AskSmsClient(ConsoleLog log, HttpSmsClientOptions http, GrpcSmsClientOptions grpc)
{
log.WriteLine("Выберите протокол: 1 — HTTP, 2 — gRPC");
while (true)
{
var input = log.ReadLine("> ")?.Trim();
if (input is "1" or "http" or "Http" or "HTTP")
{
return SmsClientFactory.CreateHttp(http);
}
if (input is "2" or "grpc" or "Grpc" or "gRPC")
{
return SmsClientFactory.CreateGrpc(grpc);
}
log.WriteLine("Введите 1 (HTTP) или 2 (gRPC).");
}
}
static AppDbContext CreateDbContext(string connectionString)
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseNpgsql(connectionString)
.UseSnakeCaseNamingConvention()
.Options;
return new AppDbContext(options);
}
static async Task SaveDishesAsync(AppDbContext db, IReadOnlyList<Dish> dishes)
{
await db.Dishes.ExecuteDeleteAsync();
db.Dishes.AddRange(dishes.Select(d => new MenuDish
{
Id = d.Id,
Article = d.Article,
Name = d.Name,
Price = d.Price,
IsWeighted = d.IsWeighted,
FullPath = d.FullPath,
Barcodes = d.Barcodes.ToList(),
}));
await db.SaveChangesAsync();
}
static Order ReadOrder(ConsoleLog log, IReadOnlyList<Dish> dishes)
{
var dishesByArticle = dishes.ToDictionary(d => d.Article, StringComparer.OrdinalIgnoreCase);
log.WriteLine();
log.WriteLine("Введите позиции заказа в формате Код:Количество;Код:Количество;...");
while (true)
{
var input = log.ReadLine("> ");
if (!TryParseOrderInput(input, out var lines, out var parseError))
{
log.WriteLine(parseError);
continue;
}
var unknownArticles = lines
.Select(line => line.Article)
.Where(article => !dishesByArticle.ContainsKey(article))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (unknownArticles.Count > 0)
{
log.WriteLine($"Неизвестные коды: {string.Join(", ", unknownArticles)}");
continue;
}
Order order = new();
foreach (var (article, quantity) in lines)
{
order = order.AddItem(dishesByArticle[article].Id, quantity);
}
return order;
}
}
static bool TryParseOrderInput(
string? input,
out List<(string Article, decimal Quantity)> items,
out string errorMessage)
{
items = [];
if (string.IsNullOrWhiteSpace(input))
{
errorMessage = "Строка заказа не может быть пустой.";
return false;
}
var parts = input.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var part in parts)
{
var pair = part.Split(':', 2);
if (pair.Length != 2)
{
errorMessage = $"Некорректный формат позиции: '{part}'. Ожидается Код:Количество.";
return false;
}
var article = pair[0].Trim();
if (string.IsNullOrWhiteSpace(article))
{
errorMessage = "Артикул не может быть пустым.";
return false;
}
if (!decimal.TryParse(pair[1].Trim(), NumberStyles.Number, CultureInfo.InvariantCulture, out var quantity)
&& !decimal.TryParse(pair[1].Trim(), NumberStyles.Number, CultureInfo.CurrentCulture, out quantity))
{
errorMessage = $"Некорректное количество для артикула '{article}'.";
return false;
}
if (quantity <= 0)
{
errorMessage = $"Количество для артикула '{article}' должно быть больше нуля.";
return false;
}
items.Add((article, quantity));
}
errorMessage = "";
return true;
}