2eb88b058e
- Implement Sale and SaleItem models for tracking sales transactions. - Create StockReturn model to manage stock adjustments for various reasons. - Introduce Supplier model to represent suppliers of products. - Develop InventoryRepository for CRUD operations on products, suppliers, sales, and stock returns. - Implement InventoryService to handle business logic for inventory management. - Update TenantDbContext to include new models and relationships. - Enhance ProfitLossRepository to account for sales, purchases, and stock returns in profit and loss calculations. - Modify Program.cs to register new inventory-related services.
189 lines
6.7 KiB
C#
189 lines
6.7 KiB
C#
using Fitness_core_BE.Interfaces;
|
|
using Fitness_core_BE.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Fitness_core_BE.Repos
|
|
{
|
|
public class InventoryRepository : IInventoryRepository
|
|
{
|
|
private readonly TenantDbContext _context;
|
|
|
|
public InventoryRepository(TenantDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
// --- Products ---
|
|
|
|
public async Task<List<Product>> GetProducts(Guid clientId, bool includeInactive = false)
|
|
{
|
|
var query = _context.Products.Where(p => p.FKClientId == clientId);
|
|
if (!includeInactive)
|
|
query = query.Where(p => p.IsActive);
|
|
|
|
return await query.OrderBy(p => p.Name).ToListAsync();
|
|
}
|
|
|
|
public Task<Product?> GetProductById(Guid productId)
|
|
=> _context.Products.FirstOrDefaultAsync(p => p.ProductId == productId);
|
|
|
|
public async Task<Product> CreateProduct(Product product)
|
|
{
|
|
product.ProductId = Guid.NewGuid();
|
|
product.CreatedAt = DateTime.UtcNow;
|
|
product.IsActive = true;
|
|
product.CostPrice = 0m;
|
|
product.QuantityOnHand = 0m;
|
|
|
|
_context.Products.Add(product);
|
|
return product;
|
|
}
|
|
|
|
public async Task<Product> UpdateProduct(Product product)
|
|
{
|
|
var existing = await _context.Products.FindAsync(product.ProductId)
|
|
?? throw new KeyNotFoundException("Product not found");
|
|
|
|
// Sku is system-generated at creation and never edited -- not copied here.
|
|
existing.Name = product.Name;
|
|
existing.UnitOfMeasure = product.UnitOfMeasure;
|
|
existing.SellingPrice = product.SellingPrice;
|
|
existing.IsActive = product.IsActive;
|
|
|
|
return existing;
|
|
}
|
|
|
|
public async Task<int> GetNextProductSequence(Guid clientId)
|
|
=> await _context.Products.CountAsync(p => p.FKClientId == clientId) + 1;
|
|
|
|
public Task<List<GoodsReceivedNoteItem>> GetGrnItemsForProduct(Guid productId)
|
|
=> _context.GoodsReceivedNoteItems
|
|
.Include(i => i.Grn)
|
|
.Where(i => i.FKProductId == productId)
|
|
.OrderByDescending(i => i.Grn!.ReceivedAt)
|
|
.ToListAsync();
|
|
|
|
public Task<List<SaleItem>> GetSaleItemsForProduct(Guid productId)
|
|
=> _context.SaleItems
|
|
.Include(i => i.Sale)
|
|
.Where(i => i.FKProductId == productId)
|
|
.OrderByDescending(i => i.Sale!.SoldAt)
|
|
.ToListAsync();
|
|
|
|
public Task<List<StockReturn>> GetStockReturnsForProduct(Guid productId)
|
|
=> _context.StockReturns
|
|
.Where(r => r.FKProductId == productId)
|
|
.OrderByDescending(r => r.ReturnedAt)
|
|
.ToListAsync();
|
|
|
|
// --- Suppliers ---
|
|
|
|
public async Task<List<Supplier>> GetSuppliers(Guid clientId, bool includeInactive = false)
|
|
{
|
|
var query = _context.Suppliers.Where(s => s.FKClientId == clientId);
|
|
if (!includeInactive)
|
|
query = query.Where(s => s.IsActive);
|
|
|
|
return await query.OrderBy(s => s.Name).ToListAsync();
|
|
}
|
|
|
|
public Task<Supplier?> GetSupplierById(Guid supplierId)
|
|
=> _context.Suppliers.FirstOrDefaultAsync(s => s.SupplierId == supplierId);
|
|
|
|
public async Task<Supplier> CreateSupplier(Supplier supplier)
|
|
{
|
|
supplier.SupplierId = Guid.NewGuid();
|
|
supplier.CreatedAt = DateTime.UtcNow;
|
|
supplier.IsActive = true;
|
|
|
|
_context.Suppliers.Add(supplier);
|
|
return supplier;
|
|
}
|
|
|
|
// --- GRN ---
|
|
|
|
public async Task<GoodsReceivedNote> CreateGrn(GoodsReceivedNote grn)
|
|
{
|
|
grn.GrnId = Guid.NewGuid();
|
|
grn.CreatedAt = DateTime.UtcNow;
|
|
foreach (var item in grn.Items)
|
|
item.GrnItemId = Guid.NewGuid();
|
|
|
|
_context.GoodsReceivedNotes.Add(grn);
|
|
return grn;
|
|
}
|
|
|
|
public Task<List<GoodsReceivedNote>> GetGrns(Guid clientId)
|
|
=> _context.GoodsReceivedNotes
|
|
.Include(g => g.Supplier)
|
|
.Include(g => g.Items).ThenInclude(i => i.Product)
|
|
.Where(g => g.FKClientId == clientId)
|
|
.OrderByDescending(g => g.ReceivedAt)
|
|
.ToListAsync();
|
|
|
|
public Task<GoodsReceivedNote?> GetGrnById(Guid grnId)
|
|
=> _context.GoodsReceivedNotes
|
|
.Include(g => g.Supplier)
|
|
.Include(g => g.Items).ThenInclude(i => i.Product)
|
|
.FirstOrDefaultAsync(g => g.GrnId == grnId);
|
|
|
|
public async Task<int> GetNextGrnSequence(Guid clientId)
|
|
=> await _context.GoodsReceivedNotes.CountAsync(g => g.FKClientId == clientId) + 1;
|
|
|
|
// --- Sales ---
|
|
|
|
public async Task<Sale> CreateSale(Sale sale)
|
|
{
|
|
sale.SaleId = Guid.NewGuid();
|
|
sale.CreatedAt = DateTime.UtcNow;
|
|
foreach (var item in sale.Items)
|
|
item.SaleItemId = Guid.NewGuid();
|
|
|
|
_context.Sales.Add(sale);
|
|
return sale;
|
|
}
|
|
|
|
public Task<List<Sale>> GetSales(Guid clientId)
|
|
=> _context.Sales
|
|
.Include(s => s.Items).ThenInclude(i => i.Product)
|
|
.Where(s => s.FKClientId == clientId)
|
|
.OrderByDescending(s => s.SoldAt)
|
|
.ToListAsync();
|
|
|
|
public Task<Sale?> GetSaleById(Guid saleId)
|
|
=> _context.Sales
|
|
.Include(s => s.Items).ThenInclude(i => i.Product)
|
|
.FirstOrDefaultAsync(s => s.SaleId == saleId);
|
|
|
|
public async Task<int> GetNextSaleSequence(Guid clientId)
|
|
=> await _context.Sales.CountAsync(s => s.FKClientId == clientId) + 1;
|
|
|
|
// --- Returns ---
|
|
|
|
public async Task<StockReturn> CreateStockReturn(StockReturn stockReturn)
|
|
{
|
|
stockReturn.StockReturnId = Guid.NewGuid();
|
|
stockReturn.CreatedAt = DateTime.UtcNow;
|
|
|
|
_context.StockReturns.Add(stockReturn);
|
|
return stockReturn;
|
|
}
|
|
|
|
public Task<List<StockReturn>> GetStockReturns(Guid clientId)
|
|
=> _context.StockReturns
|
|
.Include(r => r.Product)
|
|
.Include(r => r.Sale)
|
|
.Include(r => r.Grn)
|
|
.Where(r => r.FKClientId == clientId)
|
|
.OrderByDescending(r => r.ReturnedAt)
|
|
.ToListAsync();
|
|
|
|
public Task<StockReturn?> GetStockReturnById(Guid stockReturnId)
|
|
=> _context.StockReturns
|
|
.Include(r => r.Product)
|
|
.Include(r => r.Sale)
|
|
.Include(r => r.Grn)
|
|
.FirstOrDefaultAsync(r => r.StockReturnId == stockReturnId);
|
|
}
|
|
}
|