using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_IBasicService; using WIDESEA_Model.Models; using WIDESEA_Model.Models.Basic; namespace WIDESEA_BasicService { public class MaterialUnitService : ServiceBase>, IMaterialUnitService { private readonly ILogger _logger; public IRepository Repository => BaseDal; public IRepository _materielInfoRepository; public MaterialUnitService(IRepository BaseDal, ILogger logger, IRepository materielInfoRepository) : base(BaseDal) { _logger = logger; _materielInfoRepository = materielInfoRepository; } /// /// 单位转换 /// public async Task ConvertAsync(string materialCode, decimal quantity, string fromUnit, string toUnit) { if (string.IsNullOrEmpty(materialCode)) throw new ArgumentException("物料编号不能为空"); if (string.IsNullOrEmpty(fromUnit) || string.IsNullOrEmpty(toUnit)) throw new ArgumentException("单位不能为空"); // 如果单位相同,直接返回 if (fromUnit.Equals(toUnit, StringComparison.OrdinalIgnoreCase)) return quantity; var ratio = await GetConversionRatioAsync(materialCode, fromUnit, toUnit); if (ratio == null) { _logger.LogWarning($"未找到物料 {materialCode} 从 {fromUnit} 到 {toUnit} 的单位转换关系"); throw new InvalidOperationException($"未找到物料 {materialCode} 从 {fromUnit} 到 {toUnit} 的单位转换关系"); } return quantity * ratio.Value; } /// /// 采购单位转库存单位 /// public async Task ConvertPurchaseToStockAsync(string materialCode, decimal quantity) { // 获取物料信息 var material = await _materielInfoRepository.Db.Queryable() .Where(x => x.MaterielCode == materialCode) .FirstAsync(); if (material == null) { throw new ArgumentException($"未找到物料编号: {materialCode}"); } return await ConvertAsync(materialCode, quantity, material.purchaseUOM, material.inventoryUOM); } /// /// 领料单位转库存单位 /// public async Task ConvertIssueToStockAsync(string materialCode, decimal quantity) { // 获取物料信息 var material = await _materielInfoRepository.Db.Queryable() .Where(x => x.MaterielCode == materialCode) .FirstAsync(); if (material == null) { throw new ArgumentException($"未找到物料编号: {materialCode}"); } return await ConvertAsync(materialCode, quantity, material.usageUOM, material.inventoryUOM); } /// /// 获取单位转换比率 /// public async Task GetConversionRatioAsync(string materialCode, string fromUnit, string toUnit) { // 尝试直接查找转换关系 var conversion = await Repository.Db.Queryable() .Where(x => x.ItemNo == materialCode && x.FromUom == fromUnit && x.ToUom == toUnit) .FirstAsync(); if (conversion != null) { return conversion.Ratio; } // 尝试查找反向转换关系(取倒数) var reverseConversion = await Repository.Db.Queryable() .Where(x => x.ItemNo == materialCode && x.FromUom == toUnit && x.ToUom == fromUnit) .FirstAsync(); if (reverseConversion != null) { return 1 / reverseConversion.Ratio; } // 尝试通过中间单位(库存单位)进行转换 var material = await _materielInfoRepository.Db.Queryable() .Where(x => x.MaterielCode == materialCode) .FirstAsync(); if (material != null) { var stockUnit = material.inventoryUOM; // 如果目标单位已经是库存单位,直接查找源单位到库存单位的转换 if (toUnit.Equals(stockUnit, StringComparison.OrdinalIgnoreCase)) { var toStockRatio = await GetDirectRatioAsync(materialCode, fromUnit, stockUnit); if (toStockRatio != null) return toStockRatio; } // 如果源单位是库存单位,直接查找库存单位到目标单位的转换 if (fromUnit.Equals(stockUnit, StringComparison.OrdinalIgnoreCase)) { var fromStockRatio = await GetDirectRatioAsync(materialCode, stockUnit, toUnit); if (fromStockRatio != null) return fromStockRatio; } // 通过库存单位进行间接转换:fromUnit -> stockUnit -> toUnit var ratio1 = await GetDirectRatioAsync(materialCode, fromUnit, stockUnit); var ratio2 = await GetDirectRatioAsync(materialCode, stockUnit, toUnit); if (ratio1 != null && ratio2 != null) { return ratio1 * ratio2; } } return null; } /// /// 获取直接转换比率(包含正向和反向查找) /// private async Task GetDirectRatioAsync(string materialCode, string fromUnit, string toUnit) { // 正向查找 var conversion = await Repository.Db.Queryable() .Where(x => x.ItemNo == materialCode && x.FromUom == fromUnit && x.ToUom == toUnit) .FirstAsync(); if (conversion != null) { return conversion.Ratio; } // 反向查找 var reverseConversion = await Repository.Db.Queryable() .Where(x => x.ItemNo == materialCode && x.FromUom == toUnit && x.ToUom == fromUnit) .FirstAsync(); if (reverseConversion != null) { return 1 / reverseConversion.Ratio; } return null; } } }