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<Dt_MaterialUnit, IRepository<Dt_MaterialUnit>>, IMaterialUnitService
|
{
|
private readonly ILogger<MaterialUnitService> _logger;
|
public IRepository<Dt_MaterialUnit> Repository => BaseDal;
|
|
public IRepository<Dt_MaterielInfo> _materielInfoRepository;
|
public MaterialUnitService(IRepository<Dt_MaterialUnit> BaseDal, ILogger<MaterialUnitService> logger, IRepository<Dt_MaterielInfo> materielInfoRepository) : base(BaseDal)
|
{
|
_logger = logger;
|
_materielInfoRepository = materielInfoRepository;
|
}
|
/// <summary>
|
/// 单位转换
|
/// </summary>
|
public async Task<decimal> 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;
|
}
|
|
/// <summary>
|
/// 采购单位转库存单位
|
/// </summary>
|
public async Task<decimal> ConvertPurchaseToStockAsync(string materialCode, decimal quantity)
|
{
|
// 获取物料信息
|
var material = await _materielInfoRepository.Db.Queryable<Dt_MaterielInfo>()
|
.Where(x => x.MaterielCode == materialCode)
|
.FirstAsync();
|
|
if (material == null)
|
{
|
throw new ArgumentException($"未找到物料编号: {materialCode}");
|
}
|
|
return await ConvertAsync(materialCode, quantity, material.purchaseUOM, material.inventoryUOM);
|
}
|
|
/// <summary>
|
/// 领料单位转库存单位
|
/// </summary>
|
public async Task<decimal> ConvertIssueToStockAsync(string materialCode, decimal quantity)
|
{
|
// 获取物料信息
|
var material = await _materielInfoRepository.Db.Queryable<Dt_MaterielInfo>()
|
.Where(x => x.MaterielCode == materialCode)
|
.FirstAsync();
|
|
if (material == null)
|
{
|
throw new ArgumentException($"未找到物料编号: {materialCode}");
|
}
|
|
return await ConvertAsync(materialCode, quantity, material.usageUOM, material.inventoryUOM);
|
}
|
/// <summary>
|
/// 获取单位转换比率
|
/// </summary>
|
public async Task<decimal?> GetConversionRatioAsync(string materialCode, string fromUnit, string toUnit)
|
{
|
// 尝试直接查找转换关系
|
var conversion = await Repository.Db.Queryable<Dt_MaterialUnit>()
|
.Where(x => x.ItemNo == materialCode &&
|
x.FromUom == fromUnit &&
|
x.ToUom == toUnit)
|
.FirstAsync();
|
|
if (conversion != null)
|
{
|
return conversion.Ratio;
|
}
|
|
// 尝试查找反向转换关系(取倒数)
|
var reverseConversion = await Repository.Db.Queryable<Dt_MaterialUnit>()
|
.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<Dt_MaterielInfo>()
|
.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;
|
}
|
|
/// <summary>
|
/// 获取直接转换比率(包含正向和反向查找)
|
/// </summary>
|
private async Task<decimal?> GetDirectRatioAsync(string materialCode, string fromUnit, string toUnit)
|
{
|
// 正向查找
|
var conversion = await Repository.Db.Queryable<Dt_MaterialUnit>()
|
.Where(x => x.ItemNo == materialCode &&
|
x.FromUom == fromUnit &&
|
x.ToUom == toUnit)
|
.FirstAsync();
|
|
if (conversion != null)
|
{
|
return conversion.Ratio;
|
}
|
|
// 反向查找
|
var reverseConversion = await Repository.Db.Queryable<Dt_MaterialUnit>()
|
.Where(x => x.ItemNo == materialCode &&
|
x.FromUom == toUnit &&
|
x.ToUom == fromUnit)
|
.FirstAsync();
|
|
if (reverseConversion != null)
|
{
|
return 1 / reverseConversion.Ratio;
|
}
|
|
return null;
|
}
|
|
}
|
}
|