Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bin/
obj/
.idea/
9 changes: 9 additions & 0 deletions Croc.Domain/Croc.Domain.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
11 changes: 11 additions & 0 deletions Croc.Domain/Order.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;

namespace Croc.Domain;

public sealed class Order
{
public required string UserId { get; set; }
public DateTime OrderedAt { get; set; }
public Status Status { get; set; }
public decimal Total { get; set; }
}
11 changes: 11 additions & 0 deletions Croc.Domain/Status.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;

namespace Croc.Domain;

public enum Status
{
Completed,
Canceled,
Created,
Delivery
}
27 changes: 27 additions & 0 deletions Croc.Infrastructure/Contracts/JsonOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Text.Json.Serialization;

namespace Croc.Infrastructure.Contracts;

public sealed class JsonOrder
{
[JsonPropertyName("user_id")]
public required string UserId { get; set; }

[JsonPropertyName("ordered_at")]
public DateTime OrderedAt { get; set; }

[JsonPropertyName("status")]
public Statuses Status { get; set; }

[JsonPropertyName("total")]
public required string Total { get; set; }

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Statuses
{
Completed,
Canceled,
Created,
Delivery
}
}
17 changes: 17 additions & 0 deletions Croc.Infrastructure/Croc.Infrastructure.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Croc.Domain\Croc.Domain.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions Croc.Infrastructure/Extensions/Mapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Croc.Domain;
using Croc.Infrastructure.Contracts;

namespace Croc.Infrastructure.Extensions;

public static class Mapping
{
public static Order ToDomainOrder(this JsonOrder src)
{
return new Order()
{
UserId = src.UserId,
OrderedAt = src.OrderedAt,
Status = (Status)(int)src.Status,
Total = Convert.ToDecimal(src.Total.Replace('.', ','))
};
}
}
12 changes: 12 additions & 0 deletions Croc.Infrastructure/Extensions/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Croc.Infrastructure.Extensions;

public class Options
{
//Укажите путь до своего json-файла
private const string FilePath = @"Path to your file";

public static string GetPath()
{
return FilePath;
}
}
49 changes: 49 additions & 0 deletions Croc.Infrastructure/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Text;
using Croc.Domain;
using Croc.Infrastructure.Contracts;
using Croc.Infrastructure.Extensions;
using Croc.Infrastructure.Services;
using Croc.Infrastructure.Services.Interfaces;
using JsonSerializer = System.Text.Json.JsonSerializer;

namespace Croc.Infrastructure;

public class Program
{
public static void Main()
{
IReportService reportService = new ReportService();

string filePath = Options.GetPath();
StringBuilder text = new StringBuilder();

if (File.Exists(filePath))
{
StreamReader textFile = new StreamReader(filePath);

while (textFile.ReadLine() is { } line)
{
text.Append(line);
}

textFile.Close();

var jsonOrders = JsonSerializer.Deserialize<List<JsonOrder>>(text.ToString());

List<Order> orders = new List<Order>();
foreach (var order in jsonOrders)
{
orders.Add(order.ToDomainOrder());
}
reportService.AddOrders(orders.ToArray());
var months = reportService.CreateReport();

string jsonString = JsonSerializer.Serialize(new {months});
Console.WriteLine(jsonString);
}
else
{
Console.WriteLine("File does not exist");
}
}
}
9 changes: 9 additions & 0 deletions Croc.Infrastructure/Services/Interfaces/IReportService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Croc.Domain;

namespace Croc.Infrastructure.Services.Interfaces;

public interface IReportService
{
void AddOrders(Order[] orders);
string[] CreateReport();
}
54 changes: 54 additions & 0 deletions Croc.Infrastructure/Services/ReportService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Globalization;
using Croc.Domain;
using Croc.Infrastructure.Services.Interfaces;

namespace Croc.Infrastructure.Services;

public class ReportService : IReportService
{
private readonly Dictionary<string, decimal> _report;

public ReportService()
{
_report = new Dictionary<string, decimal>();

for (int i = 1; i <= 12; i++)
{
var monthName = DateTimeFormatInfo.InvariantInfo.GetMonthName(i);
_report.Add(monthName, 0);
}
}

public void AddOrders(Order[] orders)
{
foreach (var order in orders)
{
var monthName = order.OrderedAt.ToString("MMMM", CultureInfo.InvariantCulture);

//Предположено, что заказ в статусе Delivery можно отменить,
//соответсвенно при подсчете полученных от пользователей сумм
//стоит учитывать только заказы в статусе Completed
if (order.Status == Status.Completed)
_report[monthName] += order.Total;
}
}

public string[] CreateReport()
{
var maxTotal = GetMaxSpending();

var result = new List<string>();
foreach (var data in _report)
{
if (data.Value == maxTotal)
result.Add(data.Key.ToLower());
}

return result.ToArray();
}

private decimal GetMaxSpending()
{
return _report.Values.Prepend(0).Max();
}
}
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,24 @@
4. Найденный в соответствии с условием задачи месяц должен выводиться на английском языке в нижнем регистре. Если месяцев несколько, то на вывод они все подаются на английском языке в нижнем регистре в порядке их следования в течение года.

## Автор решения

Тулузакова Евгения Олеговна
## Описание реализации
Решение разбито на два проекта: Croc.Domain, который содержит доменные сущности - класс Order, и Croc.Infrastructure.
#### Croc.Infrastructure
Проект состоит из трех папок (Contracts, Extensions, Services) и класса Program.
###### Contracts
В данной папке находится класс JsonOrder, используемый при десериализации json.
###### Extensions
Данная директория содержит два класса. При помощи метода класса Mapping происходит преобразования из JsonOrder в Order (доменную сущность). В классе Options содержится путь к файлу для чтения.
###### Services
В данной папке находится интрефейс IReportService и класс ReportService, где происходит формирование отчета. Класс состоит из:
- поля Dictionary, где ключ - название месяца, а значение - сумма пользовательских трат за этот месяц;
- методов добавления информации в словарь, нахождения максимальной сумму трат и формирования отчета.

###### Program
В данном классе в методе Main происходит чтение из файла и вызов всех необходимых функций для формирования отчета.

## Инструкция по сборке и запуску решения
1. В классе Options (Croc.Infrastructure.Extensions.Options) в константе FilePath укажите путь к json-файлу (input.json).
2. Собирите билд решения.
3. Запустите Croc.Infrastructure.Program.Main.
50 changes: 50 additions & 0 deletions input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"user_id": "3acfb0b7-04bd-4978-be4c-3929372277c1",
"ordered_at": "2023-01-16T13:56:39.492",
"status": "COMPLETED",
"total": "1917.00"
},
{
"user_id": "25b003b9-ab22-4a24-a616-dd0303f983d8",
"ordered_at": "2023-03-05T08:34:21.123",
"status": "COMPLETED",
"total": "13990.00"
},
{
"user_id": "e1470ada-fcbb-4424-8c46-065b6409ca4b",
"ordered_at": "2016-03-16T13:56:39.492",
"status": "COMPLETED",
"total": "215.50"
},
{
"user_id": "081a47a5-b7bf-462c-a11a-68002a179152",
"ordered_at": "2023-12-08T21:36:59.281",
"status": "COMPLETED",
"total": "49499.00"
},
{
"user_id": "0999c6aa-1bac-4ded-9a54-92fff4f34d69",
"ordered_at": "2023-12-14T11:10:29.408",
"status": "CANCELED",
"total": "13650.00"
},
{
"user_id": "0999c6aa-1bac-4ded-9a54-92fff4f34d69",
"ordered_at": "2023-12-14T11:15:31.108",
"status": "COMPLETED",
"total": "14760.00"
},
{
"user_id": "0999c6aa-1bac-4ded-9a54-92fff4f34d69",
"ordered_at": "2023-03-14T11:15:31.108",
"status": "COMPLETED",
"total": "14760.00"
},
{
"user_id": "0999c6aa-1bac-4ded-9a54-92fff4f34d69",
"ordered_at": "2023-08-14T11:15:31.108",
"status": "COMPLETED",
"total": "64259.00"
}
]