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 }