225 lines
8.4 KiB
C#
225 lines
8.4 KiB
C#
using AutoMapper;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Npgsql;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Runtime.CompilerServices;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Xml.Linq;
|
||
using YAPContracts.DataModels;
|
||
using YAPContracts.Exceptions;
|
||
using YAPContracts.StorageContracts;
|
||
using YAPDatabase.Models;
|
||
|
||
namespace YAPDatabase.Implementations
|
||
{
|
||
internal class PurchaseStorageContract : IPurchaseStorageContract
|
||
{
|
||
private readonly YAPDbContext _dbContext;
|
||
private readonly Mapper _mapper;
|
||
|
||
public PurchaseStorageContract(YAPDbContext dbContext)
|
||
{
|
||
_dbContext = dbContext;
|
||
var config = new MapperConfiguration(cfg =>
|
||
{
|
||
cfg.CreateMap<ProductInPurchase, ProductInPurchaseDataModel>();
|
||
cfg.CreateMap<ProductInPurchaseDataModel, ProductInPurchase>();
|
||
cfg.CreateMap<ProductSetInPurchase, ProductSetInPurchaseDataModel>();
|
||
cfg.CreateMap<ProductSetInPurchaseDataModel, ProductSetInPurchase>();
|
||
|
||
cfg.CreateMap<PurchaseDataModel, Purchase>()
|
||
.ForMember(dest => dest.ProductsInPurchase, opt => opt.MapFrom(src => src.Products))
|
||
.ForMember(dest => dest.ProductSetsInPurchase, opt => opt.MapFrom(src => src.ProductSets));
|
||
cfg.CreateMap<Purchase, PurchaseDataModel>()
|
||
.ForMember(dest => dest.Products, opt => opt.MapFrom(src => src.ProductsInPurchase))
|
||
.ForMember(dest => dest.ProductSets, opt => opt.MapFrom(src => src.ProductSetsInPurchase));;
|
||
|
||
cfg.CreateMap<Component, ComponentDataModel>();
|
||
});
|
||
_mapper = new Mapper(config);
|
||
}
|
||
|
||
public void AddElement(PurchaseDataModel purchase)
|
||
{
|
||
try
|
||
{
|
||
var entity = _mapper.Map<Purchase>(purchase);
|
||
entity.TotalPrice = CalculateTotalPrice(entity);
|
||
if (entity.TotalPrice <= 0) throw new ValidationException("Total price must be greater than zero.");
|
||
_dbContext.Purchases.Add(entity);
|
||
_dbContext.SaveChanges();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
|
||
public void UpdateElement(PurchaseDataModel purchase)
|
||
{
|
||
try
|
||
{
|
||
var oldPurchase = GetPurchaseById(purchase.Id) ?? throw new ElementNotFoundException(purchase.Id);
|
||
var newEntity = _mapper.Map(purchase, oldPurchase);
|
||
newEntity.TotalPrice = CalculateTotalPrice(newEntity);
|
||
if (newEntity.TotalPrice <= 0) throw new ValidationException("Total price must be greater than zero.");
|
||
_dbContext.Purchases.Update(newEntity);
|
||
_dbContext.SaveChanges();
|
||
}
|
||
catch (ElementNotFoundException ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
|
||
public void DeleteElement(string id)
|
||
{
|
||
try
|
||
{
|
||
var client = GetPurchaseById(id) ?? throw new ElementNotFoundException(id);
|
||
_dbContext.Purchases.Remove(client);
|
||
_dbContext.SaveChanges();
|
||
}
|
||
catch (ElementNotFoundException ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
|
||
public PurchaseDataModel? GetElementById(string id)
|
||
{
|
||
try
|
||
{
|
||
return _mapper.Map<PurchaseDataModel>(GetPurchaseById(id));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
|
||
public List<PurchaseDataModel> GetList(DateTime? fromDate = null, DateTime? toDate = null, string? userId = null)
|
||
{
|
||
try
|
||
{
|
||
var query = _dbContext.Purchases.Include(x => x.ProductsInPurchase).Include(x => x.ProductSetsInPurchase).AsQueryable();
|
||
if (fromDate is not null && toDate is not null)
|
||
{
|
||
query = query.Where(x => x.PurchaseDate >= fromDate && x.PurchaseDate < toDate);
|
||
}
|
||
if (userId is not null)
|
||
{
|
||
query = query.Where(x => x.UserId == userId);
|
||
}
|
||
return [.. query.Select(x => _mapper.Map<PurchaseDataModel>(x))];
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
|
||
private Purchase? GetPurchaseById(string id)
|
||
{
|
||
return _dbContext.Purchases.Include(x => x.ProductsInPurchase).Include(x => x.ProductSetsInPurchase).FirstOrDefault(p => p.Id == id);
|
||
}
|
||
|
||
private double CalculateTotalPrice(Purchase entity)
|
||
{
|
||
double total = 0;
|
||
|
||
// Products
|
||
if (entity.ProductsInPurchase != null && entity.ProductsInPurchase.Any())
|
||
{
|
||
var productIds = entity.ProductsInPurchase.Select(p => p.ProductId).ToList();
|
||
var productsFromDb = _dbContext.Products
|
||
.Where(p => productIds.Contains(p.Id))
|
||
.ToDictionary(p => p.Id, p => p.Price);
|
||
|
||
foreach (var product in entity.ProductsInPurchase)
|
||
{
|
||
if (productsFromDb.TryGetValue(product.ProductId, out var price))
|
||
{
|
||
total += price * product.Amount;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ProductSets
|
||
if (entity.ProductSetsInPurchase != null && entity.ProductSetsInPurchase.Any())
|
||
{
|
||
var setIds = entity.ProductSetsInPurchase.Select(ps => ps.ProductSetId).ToList();
|
||
var setsFromDb = _dbContext.ProductSets
|
||
.Where(s => setIds.Contains(s.Id))
|
||
.ToDictionary(s => s.Id, s => s.TotalPrice);
|
||
|
||
foreach (var set in entity.ProductSetsInPurchase)
|
||
{
|
||
if (setsFromDb.TryGetValue(set.ProductSetId, out var price))
|
||
{
|
||
total += price;
|
||
}
|
||
}
|
||
}
|
||
|
||
return total;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Метод для получения отчета по продажам с расшифровкой
|
||
/// по комплектующим и комментариям за период.
|
||
/// </summary>
|
||
/// <param name="start"></param>
|
||
/// <param name="finish"></param>
|
||
/// <returns></returns>
|
||
public List<PurchasesReportModel>? GetDataForReport(DateTime start, DateTime finish)
|
||
{
|
||
try
|
||
{
|
||
var report = _dbContext.Purchases
|
||
.Where(p => p.PurchaseDate >= start && p.PurchaseDate <= finish)
|
||
.Select(p => new PurchasesReportModel
|
||
{
|
||
Purchase = _mapper.Map<PurchaseDataModel>(p),
|
||
Components = p.ProductSetsInPurchase
|
||
.SelectMany(pps => pps.ProductSet.ComponentsInProductSet)
|
||
.Select(cps => cps.Component)
|
||
.Select(comp => _mapper.Map<ComponentDataModel>(comp))
|
||
.ToList(),
|
||
Comments = p.ProductSetsInPurchase
|
||
.SelectMany(pps => pps.ProductSet.Comments)
|
||
.Select(c => new CommentDataModel(c.Id, c.ProductSetId, c.UserId, c.Text, c.CommentDate))
|
||
.ToList()
|
||
})
|
||
.ToList();
|
||
|
||
return report;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_dbContext.ChangeTracker.Clear();
|
||
throw new StorageException(ex);
|
||
}
|
||
}
|
||
}
|
||
}
|