using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Interfaces.Repositories;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;
namespace CMSMicroservice.Infrastructure.Persistence.Repositories;
///
/// Repository implementation برای مدیریت انبارها
///
public class WarehouseRepository : IWarehouseRepository
{
private readonly IApplicationDbContext _context;
public WarehouseRepository(IApplicationDbContext context)
{
_context = context;
}
#region Read Operations
public async Task GetByIdAsync(long id, CancellationToken cancellationToken = default)
{
return await _context.Warehouses
.Include(w => w.InventoryItems)
.ThenInclude(i => i.Product)
.Include(w => w.InventoryItems)
.ThenInclude(i => i.DiscountProduct)
.FirstOrDefaultAsync(w => w.Id == id, cancellationToken);
}
public async Task GetByCodeAsync(string code, CancellationToken cancellationToken = default)
{
return await _context.Warehouses
.Include(w => w.InventoryItems)
.ThenInclude(i => i.Product)
.Include(w => w.InventoryItems)
.ThenInclude(i => i.DiscountProduct)
.FirstOrDefaultAsync(w => w.Code == code, cancellationToken);
}
public async Task GetDefaultWarehouseAsync(CancellationToken cancellationToken = default)
{
return await _context.Warehouses
.Include(w => w.InventoryItems)
.ThenInclude(i => i.Product)
.Include(w => w.InventoryItems)
.ThenInclude(i => i.DiscountProduct)
.FirstOrDefaultAsync(w => w.IsDefault, cancellationToken);
}
public async Task> GetActiveWarehousesAsync(CancellationToken cancellationToken = default)
{
return await _context.Warehouses
.Where(w => w.IsActive)
.OrderBy(w => w.Name)
.ToListAsync(cancellationToken);
}
public async Task> GetAllAsync(
bool includeInactive = false,
CancellationToken cancellationToken = default)
{
var query = _context.Warehouses.AsQueryable();
if (!includeInactive)
{
query = query.Where(w => w.IsActive);
}
return await query
.OrderBy(w => w.Name)
.ToListAsync(cancellationToken);
}
public async Task> SearchAsync(
string? searchTerm = null,
bool? isActive = null,
int skip = 0,
int take = 50,
CancellationToken cancellationToken = default)
{
var query = _context.Warehouses.AsQueryable();
if (!string.IsNullOrWhiteSpace(searchTerm))
{
var term = searchTerm.ToLower();
query = query.Where(w =>
w.Name.ToLower().Contains(term) ||
w.Code.ToLower().Contains(term) ||
(w.Address != null && w.Address.ToLower().Contains(term)));
}
if (isActive.HasValue)
{
query = query.Where(w => w.IsActive == isActive.Value);
}
return await query
.OrderBy(w => w.Name)
.Skip(skip)
.Take(take)
.ToListAsync(cancellationToken);
}
public async Task CountAsync(
string? searchTerm = null,
bool? isActive = null,
CancellationToken cancellationToken = default)
{
var query = _context.Warehouses.AsQueryable();
if (!string.IsNullOrWhiteSpace(searchTerm))
{
var term = searchTerm.ToLower();
query = query.Where(w =>
w.Name.ToLower().Contains(term) ||
w.Code.ToLower().Contains(term) ||
(w.Address != null && w.Address.ToLower().Contains(term)));
}
if (isActive.HasValue)
{
query = query.Where(w => w.IsActive == isActive.Value);
}
return await query.CountAsync(cancellationToken);
}
public async Task ExistsByCodeAsync(string code, long? excludeId = null, CancellationToken cancellationToken = default)
{
var query = _context.Warehouses.Where(w => w.Code == code);
if (excludeId.HasValue)
{
query = query.Where(w => w.Id != excludeId.Value);
}
return await query.AnyAsync(cancellationToken);
}
#endregion
#region Write Operations
public async Task AddAsync(Warehouse warehouse, CancellationToken cancellationToken = default)
{
// اگر این انبار پیشفرض است، سایر انبارها را غیرپیشفرض کن
if (warehouse.IsDefault)
{
await RemoveDefaultFromAllWarehousesAsync(cancellationToken);
}
_context.Warehouses.Add(warehouse);
await _context.SaveChangesAsync(cancellationToken);
return warehouse;
}
public async Task UpdateAsync(Warehouse warehouse, CancellationToken cancellationToken = default)
{
// اگر این انبار پیشفرض شده، سایر انبارها را غیرپیشفرض کن
if (warehouse.IsDefault)
{
await RemoveDefaultFromAllWarehousesAsync(warehouse.Id, cancellationToken);
}
_context.Warehouses.Update(warehouse);
await _context.SaveChangesAsync(cancellationToken);
}
public async Task DeleteAsync(long id, CancellationToken cancellationToken = default)
{
var warehouse = await _context.Warehouses.FindAsync(new object[] { id }, cancellationToken);
if (warehouse != null)
{
warehouse.IsActive = false;
await _context.SaveChangesAsync(cancellationToken);
}
}
public async Task SetActiveStatusAsync(long id, bool isActive, CancellationToken cancellationToken = default)
{
var warehouse = await _context.Warehouses.FindAsync(new object[] { id }, cancellationToken);
if (warehouse != null)
{
warehouse.IsActive = isActive;
await _context.SaveChangesAsync(cancellationToken);
}
}
public async Task SetAsDefaultAsync(long id, CancellationToken cancellationToken = default)
{
// ابتدا همه انبارها را غیرپیشفرض کن
await RemoveDefaultFromAllWarehousesAsync(cancellationToken);
// سپس انبار مورد نظر را پیشفرض کن
var warehouse = await _context.Warehouses.FindAsync(new object[] { id }, cancellationToken);
if (warehouse != null)
{
warehouse.IsDefault = true;
await _context.SaveChangesAsync(cancellationToken);
}
}
#endregion
#region Analytics
public async Task<(int TotalProducts, int LowStockProducts, int OutOfStockProducts, decimal TotalValue)> GetWarehouseStatisticsAsync(
long warehouseId,
CancellationToken cancellationToken = default)
{
var inventoryItems = await _context.InventoryItems
.Include(i => i.Product)
.Include(i => i.DiscountProduct)
.Where(i => i.WarehouseId == warehouseId)
.ToListAsync(cancellationToken);
var totalProducts = inventoryItems.Count;
var lowStockProducts = inventoryItems.Count(i => i.Quantity <= i.LowStockThreshold && i.Quantity > 0);
var outOfStockProducts = inventoryItems.Count(i => i.Quantity == 0);
// محاسبه ارزش کل بر اساس قیمت محصولات
decimal totalValue = 0;
foreach (var item in inventoryItems)
{
if (item.Product != null)
{
totalValue += item.Quantity * item.Product.Price;
}
else if (item.DiscountProduct != null)
{
totalValue += item.Quantity * item.DiscountProduct.Price;
}
}
return (totalProducts, lowStockProducts, outOfStockProducts, totalValue);
}
public async Task> GetTopSellingProductsAsync(
long warehouseId,
DateTime fromDate,
DateTime toDate,
int count = 10,
CancellationToken cancellationToken = default)
{
// دریافت حرکات فروش برای این انبار در بازه زمانی مشخص
var salesMovements = await _context.StockMovements
.Include(m => m.InventoryItem)
.ThenInclude(i => i.Product)
.Include(m => m.InventoryItem)
.ThenInclude(i => i.DiscountProduct)
.Where(m => m.InventoryItem.WarehouseId == warehouseId &&
m.MovementType == StockMovementType.Sale &&
m.Created >= fromDate &&
m.Created <= toDate)
.ToListAsync(cancellationToken);
// گروهبندی بر اساس محصول و محاسبه تعداد فروش
var topProducts = salesMovements
.GroupBy(m => m.InventoryItemId)
.Select(g =>
{
var firstItem = g.First().InventoryItem;
var productId = firstItem.ProductId ?? firstItem.DiscountProductId ?? 0;
var productName = firstItem.Product?.Title ?? firstItem.DiscountProduct?.Title ?? "Unknown";
var totalSold = g.Sum(m => m.Quantity);
var currentStock = firstItem.Quantity;
return (ProductId: productId, ProductName: productName, TotalSold: totalSold, CurrentStock: currentStock);
})
.OrderByDescending(x => x.TotalSold)
.Take(count)
.ToList();
return topProducts;
}
#endregion
#region Private Methods
private async Task RemoveDefaultFromAllWarehousesAsync(CancellationToken cancellationToken = default)
{
var defaultWarehouses = await _context.Warehouses
.Where(w => w.IsDefault)
.ToListAsync(cancellationToken);
foreach (var warehouse in defaultWarehouses)
{
warehouse.IsDefault = false;
}
}
private async Task RemoveDefaultFromAllWarehousesAsync(long excludeId, CancellationToken cancellationToken = default)
{
var defaultWarehouses = await _context.Warehouses
.Where(w => w.IsDefault && w.Id != excludeId)
.ToListAsync(cancellationToken);
foreach (var warehouse in defaultWarehouses)
{
warehouse.IsDefault = false;
}
}
#endregion
}