GetDataProductsByManufacturer
This commit is contained in:
@@ -1,7 +1,21 @@
|
||||
using CatHasPawsContratcs.BusinessLogicsContracts;
|
||||
using CatHasPawsContratcs.DataModels;
|
||||
using CatHasPawsContratcs.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CatHasPawsBusinessLogic.Implementations;
|
||||
|
||||
internal class ReportContract : IReportContract
|
||||
internal class ReportContract(IProductStorageContract productStorageContract, ILogger logger) : IReportContract
|
||||
{
|
||||
private readonly IProductStorageContract _productStorageContract = productStorageContract;
|
||||
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public Task<List<ManufacturerProductDataModel>> GetDataProductsByManufacturerAsync(CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data ProductsByManufacturer");
|
||||
return GetDataByProductsAsync(ct);
|
||||
}
|
||||
|
||||
private async Task<List<ManufacturerProductDataModel>> GetDataByProductsAsync(CancellationToken ct) => [.. (await _productStorageContract.GetListAsync(ct)).GroupBy(x => x.ManufacturerName).Select(x => new ManufacturerProductDataModel { ManufacturerName = x.Key, Products = [.. x.Select(y => y.ProductName)] })];
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
namespace CatHasPawsContratcs.AdapterContracts;
|
||||
using CatHasPawsContratcs.AdapterContracts.OperationResponses;
|
||||
using CatHasPawsContratcs.DataModels;
|
||||
|
||||
namespace CatHasPawsContratcs.AdapterContracts;
|
||||
|
||||
public interface IReportAdapter
|
||||
{
|
||||
Task<ReportOperationResponse> GetDataProductsByManufacturerAsync(CancellationToken ct);
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using CatHasPawsContratcs.Infrastructure;
|
||||
using CatHasPawsContratcs.ViewModels;
|
||||
|
||||
namespace CatHasPawsContratcs.AdapterContracts.OperationResponses;
|
||||
|
||||
public class ReportOperationResponse : OperationResponse
|
||||
{
|
||||
public static ReportOperationResponse OK(List<ManufacturerProductViewModel> data) => OK<ReportOperationResponse, List<ManufacturerProductViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse BadRequest(string message) => BadRequest<ReportOperationResponse>(message);
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace CatHasPawsContratcs.BusinessLogicsContracts;
|
||||
using CatHasPawsContratcs.DataModels;
|
||||
|
||||
namespace CatHasPawsContratcs.BusinessLogicsContracts;
|
||||
|
||||
public interface IReportContract
|
||||
{
|
||||
Task<List<ManufacturerProductDataModel>> GetDataProductsByManufacturerAsync(CancellationToken ct);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CatHasPawsContratcs.DataModels;
|
||||
|
||||
public class ManufacturerProductDataModel
|
||||
{
|
||||
public required string ManufacturerName { get; set; }
|
||||
|
||||
public required List<string> Products { get; set; }
|
||||
}
|
||||
@@ -6,6 +6,8 @@ public interface IProductStorageContract
|
||||
{
|
||||
List<ProductDataModel> GetList(bool onlyActive = true, string? manufacturerId = null);
|
||||
|
||||
Task<List<ProductDataModel>> GetListAsync(CancellationToken ct);
|
||||
|
||||
List<ProductHistoryDataModel> GetHistoryByProductId(string productId);
|
||||
|
||||
ProductDataModel? GetElementById(string id);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CatHasPawsContratcs.ViewModels;
|
||||
|
||||
public class ManufacturerProductViewModel
|
||||
{
|
||||
public required string ManufacturerName { get; set; }
|
||||
|
||||
public required List<string> Products { get; set; }
|
||||
}
|
||||
@@ -49,6 +49,19 @@ internal class ProductStorageContract : IProductStorageContract
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<ProductDataModel>> GetListAsync(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return [.. await _dbContext.Products.Include(x => x.Manufacturer).Select(x => _mapper.Map<ProductDataModel>(x)).ToListAsync(ct)];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw new StorageException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProductHistoryDataModel> GetHistoryByProductId(string productId)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using CatHasPawsBusinessLogic.Implementations;
|
||||
using CatHasPawsContratcs.DataModels;
|
||||
using CatHasPawsContratcs.Enums;
|
||||
using CatHasPawsContratcs.Exceptions;
|
||||
using CatHasPawsContratcs.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
|
||||
namespace CatHasPawsTests.BusinessLogicsContractsTests;
|
||||
|
||||
[TestFixture]
|
||||
internal class ReportContractTests
|
||||
{
|
||||
private ReportContract _reportContract;
|
||||
private Mock<IProductStorageContract> _productStorageContract;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
_productStorageContract = new Mock<IProductStorageContract>();
|
||||
_reportContract = new ReportContract(_productStorageContract.Object, new Mock<ILogger>().Object);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_productStorageContract.Reset();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataProductsByManufacturer_ShouldSuccess_Test()
|
||||
{
|
||||
//Arrange
|
||||
var manufacturer1 = new ManufacturerDataModel(Guid.NewGuid().ToString(), "name1");
|
||||
var manufacturer2 = new ManufacturerDataModel(Guid.NewGuid().ToString(), "name2");
|
||||
_productStorageContract.Setup(x => x.GetListAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<ProductDataModel>()
|
||||
{
|
||||
new(Guid.NewGuid().ToString(), "name 1.1", ProductType.Accessory, manufacturer1.Id, 10, false, manufacturer1),
|
||||
new(Guid.NewGuid().ToString(), "name 2.1", ProductType.Accessory, manufacturer2.Id, 10, false, manufacturer2),
|
||||
new(Guid.NewGuid().ToString(), "name 1.2", ProductType.Accessory, manufacturer1.Id, 10, false, manufacturer1),
|
||||
new(Guid.NewGuid().ToString(), "name 1.3", ProductType.Accessory, manufacturer1.Id, 10, false, manufacturer1),
|
||||
new(Guid.NewGuid().ToString(), "name 2.2", ProductType.Accessory, manufacturer2.Id, 10, false, manufacturer2)
|
||||
}));
|
||||
//Act
|
||||
var data = await _reportContract.GetDataProductsByManufacturerAsync(CancellationToken.None);
|
||||
//Assert
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data, Has.Count.EqualTo(2));
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(data.First(x => x.ManufacturerName == manufacturer1.ManufacturerName).Products, Has.Count.EqualTo(3));
|
||||
Assert.That(data.First(x => x.ManufacturerName == manufacturer2.ManufacturerName).Products, Has.Count.EqualTo(2));
|
||||
});
|
||||
_productStorageContract.Verify(x => x.GetListAsync(It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataProductsByManufacturer_WhenNoRecords_ShouldSuccess_Test()
|
||||
{
|
||||
//Arrange
|
||||
_productStorageContract.Setup(x => x.GetListAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<ProductDataModel>()));
|
||||
//Act
|
||||
var data = await _reportContract.GetDataProductsByManufacturerAsync(CancellationToken.None);
|
||||
//Assert
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data, Has.Count.EqualTo(0));
|
||||
_productStorageContract.Verify(x => x.GetListAsync(It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDataProductsByManufacturer_WhenStorageThrowError_ShouldFail_Test()
|
||||
{
|
||||
//Arrange
|
||||
_productStorageContract.Setup(x => x.GetListAsync(It.IsAny<CancellationToken>())).Throws(new StorageException(new InvalidOperationException()));
|
||||
//Act&Assert
|
||||
Assert.That(async () => await _reportContract.GetDataProductsByManufacturerAsync(CancellationToken.None), Throws.TypeOf<StorageException>());
|
||||
_productStorageContract.Verify(x => x.GetListAsync(It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,26 @@ internal class ProductStorageContractTests : BaseStorageContractTest
|
||||
Assert.That(list, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Try_GetListAsync_WhenHaveRecords_Test()
|
||||
{
|
||||
var product = CatHasPawsDbContext.InsertProductToDatabaseAndReturn(_manufacturer.Id, productName: "name 1");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(_manufacturer.Id, productName: "name 2");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(_manufacturer.Id, productName: "name 3");
|
||||
var list = await _productStorageContract.GetListAsync(CancellationToken.None);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Has.Count.EqualTo(3));
|
||||
AssertElement(list.First(x => x.Id == product.Id), product);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Try_GetListAsync_WhenNoRecords_Test()
|
||||
{
|
||||
var list = await _productStorageContract.GetListAsync(CancellationToken.None);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_OnlyActual_Test()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using CatHasPawsContratcs.ViewModels;
|
||||
using CatHasPawsTests.Infrastructure;
|
||||
using System.Net;
|
||||
|
||||
namespace CatHasPawsTests.WebApiControllersTests;
|
||||
|
||||
[TestFixture]
|
||||
internal class ReportControllerTests : BaseWebApiControllerTest
|
||||
{
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
CatHasPawsDbContext.RemoveProductsFromDatabase();
|
||||
CatHasPawsDbContext.RemoveManufacturersFromDatabase();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetProducts_WhenHaveRecords_ShouldSuccess_Test()
|
||||
{
|
||||
//Arrange
|
||||
var manufacturer1 = CatHasPawsDbContext.InsertManufacturerToDatabaseAndReturn(manufacturerName: "name 1");
|
||||
var manufacturer2 = CatHasPawsDbContext.InsertManufacturerToDatabaseAndReturn(manufacturerName: "name 2");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(manufacturer1.Id, productName: "name 1.1");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(manufacturer1.Id, productName: "name 1.2");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(manufacturer1.Id, productName: "name 1.3");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(manufacturer2.Id, productName: "name 2.1");
|
||||
CatHasPawsDbContext.InsertProductToDatabaseAndReturn(manufacturer2.Id, productName: "name 2.2");
|
||||
//Act
|
||||
var response = await HttpClient.GetAsync("/api/report/getproducts");
|
||||
//Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
var data = await GetModelFromResponseAsync<List<ManufacturerProductViewModel>>(response);
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(data, Has.Count.EqualTo(2));
|
||||
Assert.That(data.First(x => x.ManufacturerName == manufacturer1.ManufacturerName).Products, Has.Count.EqualTo(3));
|
||||
Assert.That(data.First(x => x.ManufacturerName == manufacturer2.ManufacturerName).Products, Has.Count.EqualTo(2));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,52 @@
|
||||
using CatHasPawsContratcs.AdapterContracts;
|
||||
using AutoMapper;
|
||||
using CatHasPawsContratcs.AdapterContracts;
|
||||
using CatHasPawsContratcs.AdapterContracts.OperationResponses;
|
||||
using CatHasPawsContratcs.BusinessLogicsContracts;
|
||||
using CatHasPawsContratcs.DataModels;
|
||||
using CatHasPawsContratcs.Exceptions;
|
||||
using CatHasPawsContratcs.ViewModels;
|
||||
|
||||
namespace CatHasPawsWebApi.Adapters;
|
||||
|
||||
public class ReportAdapter : IReportAdapter
|
||||
{
|
||||
private IReportContract _reportContract;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly Mapper _mapper;
|
||||
|
||||
public ReportAdapter(IReportContract reportContract, ILogger<ProductAdapter> logger)
|
||||
{
|
||||
_reportContract = reportContract;
|
||||
_logger = logger;
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.CreateMap<ManufacturerProductDataModel, ManufacturerProductViewModel>();
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> GetDataProductsByManufacturerAsync(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReportOperationResponse.OK([.. (await _reportContract.GetDataProductsByManufacturerAsync(ct)).Select(x => _mapper.Map<ManufacturerProductViewModel>(x))]);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "InvalidOperationException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (StorageException ex)
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,20 @@
|
||||
using CatHasPawsContratcs.AdapterContracts;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CatHasPawsWebApi.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class ReportController(IReportAdapter reportAdapter) : ControllerBase
|
||||
public class ReportController(IReportAdapter adapter) : ControllerBase
|
||||
{
|
||||
private IReportAdapter _reportAdapter = reportAdapter;
|
||||
private readonly IReportAdapter _adapter = adapter;
|
||||
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetProducts(CancellationToken ct)
|
||||
{
|
||||
return (await _adapter.GetDataProductsByManufacturerAsync(ct)).GetResponse(Request, Response);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user