From cf3050083e157819b94781d0445547ffc73e21f2 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期五, 28 十一月 2025 21:17:28 +0800
Subject: [PATCH] 提交
---
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/MaterialUnitService.cs | 397 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 394 insertions(+), 3 deletions(-)
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_BasicService/MaterialUnitService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_BasicService/MaterialUnitService.cs"
index cd8417b..7c48c96 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_BasicService/MaterialUnitService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_BasicService/MaterialUnitService.cs"
@@ -1,24 +1,415 @@
-锘縰sing System;
+锘縰sing Microsoft.AspNetCore.JsonPatch.Internal;
+using Microsoft.Extensions.Logging;
+using SqlSugar;
+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_DTO.Basic;
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 MaterialUnitService(IRepository<Dt_MaterialUnit> BaseDal) : base(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>
+ /// 鑾峰彇鐗╂枡鍙婂叾鎵�鏈夊崟浣嶈浆鎹㈠叧绯伙紙浣跨敤MaterialUnit宸﹁繛鎺aterial锛�
+ /// </summary>
+ private async Task<MaterialWithUnits> GetMaterialWithUnitsAsync(string materialCode)
+ {
+
+ var unitConversions = await Repository.Db.Queryable<Dt_MaterialUnit>()
+ .LeftJoin<Dt_MaterielInfo>((u, m) => u.ItemNo == m.MaterielCode)
+ .Where((u, m) => u.ItemNo == materialCode)
+ .Select((u, m) => new
+ {
+ MaterialCode = u.ItemNo,
+ FromUom = u.FromUom,
+ ToUom = u.ToUom,
+ Ratio = u.Ratio,
+ IssueUnit = m.usageUOM,
+ PurchaseUnit = m.purchaseUOM,
+ StockUnit = m.inventoryUOM
+ })
+ .ToListAsync();
+
+ if (!unitConversions.Any())
+ {
+ // 濡傛灉娌℃湁鎵惧埌鍗曚綅杞崲璁板綍锛屽皾璇曠洿鎺ヨ幏鍙栫墿鏂欎俊鎭�
+ var material = await _materielInfoRepository.Db.Queryable<Dt_MaterielInfo>()
+ .Where(m => m.MaterielCode == materialCode)
+ .FirstAsync();
+
+ if (material == null)
+ {
+ throw new ArgumentException($"鏈壘鍒扮墿鏂欑紪鍙�: {materialCode}");
+ }
+
+ return new MaterialWithUnits
+ {
+ MaterialCode = materialCode,
+ IssueUnit = material.usageUOM,
+ PurchaseUnit = material.purchaseUOM,
+ StockUnit = material.inventoryUOM
+ };
+ }
+
+ // 浠庣涓�鏉¤褰曚腑鑾峰彇鐗╂枡淇℃伅锛堟墍鏈夎褰曢兘鏈夌浉鍚岀殑鐗╂枡淇℃伅锛�
+ var firstRecord = unitConversions.First();
+
+ return new MaterialWithUnits
+ {
+ MaterialCode = materialCode,
+ IssueUnit = firstRecord.IssueUnit,
+ PurchaseUnit = firstRecord.PurchaseUnit,
+ StockUnit = firstRecord.StockUnit,
+ UnitConversions = unitConversions.Select(u => new UnitConversion
+ {
+ FromUom = u.FromUom,
+ ToUom = u.ToUom,
+ Ratio = u.Ratio
+ }).ToList()
+ };
+ }
+
+ /// <summary>
+ /// 鍗曚綅杞崲
+ /// </summary>
+ public async Task<MaterialWithUnitConversionResult> 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 new MaterialWithUnitConversionResult(quantity, toUnit, false);
+
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+ var ratio = GetConversionRatioFromData(materialData, fromUnit, toUnit);
+
+ if (ratio == null)
+ {
+ _logger.LogWarning($"鏈壘鍒扮墿鏂� {materialCode} 浠� {fromUnit} 鍒� {toUnit} 鐨勫崟浣嶈浆鎹㈠叧绯�");
+ throw new InvalidOperationException($"鏈壘鍒扮墿鏂� {materialCode} 浠� {fromUnit} 鍒� {toUnit} 鐨勫崟浣嶈浆鎹㈠叧绯�");
+ }
+
+ var convertedQuantity = quantity * ratio.Value;
+ return new MaterialWithUnitConversionResult(convertedQuantity, toUnit, true);
+ }
+
+ private MaterialWithUnitConversionResult ConvertAsync(MaterialWithUnits materialData, decimal quantity, string fromUnit, string toUnit)
+ {
+ if(materialData==null)
+ throw new ArgumentException("鐗╂枡涓嶅瓨鍦�");
+
+ if (string.IsNullOrEmpty(fromUnit) || string.IsNullOrEmpty(toUnit))
+ throw new ArgumentException("鍗曚綅涓嶈兘涓虹┖");
+
+ // 濡傛灉鍗曚綅鐩稿悓锛岀洿鎺ヨ繑鍥烇紝涓嶈繘琛岃浆鎹�
+ if (fromUnit.Equals(toUnit, StringComparison.OrdinalIgnoreCase))
+ return new MaterialWithUnitConversionResult(quantity, toUnit, false);
+
+
+ var ratio = GetConversionRatioFromData(materialData, fromUnit, toUnit);
+
+ if (ratio == null)
+ {
+ _logger.LogWarning($"鏈壘鍒扮墿鏂� {materialData.MaterialCode} 浠� {fromUnit} 鍒� {toUnit} 鐨勫崟浣嶈浆鎹㈠叧绯�");
+ throw new InvalidOperationException($"鏈壘鍒扮墿鏂� {materialData.MaterialCode} 浠� {fromUnit} 鍒� {toUnit} 鐨勫崟浣嶈浆鎹㈠叧绯�");
+ }
+
+ var convertedQuantity = quantity * ratio.Value;
+ return new MaterialWithUnitConversionResult(convertedQuantity, toUnit, true);
+ }
+
+ /// <summary>
+ /// 閲囪喘鍗曚綅杞簱瀛樺崟浣�
+ /// </summary>
+ public async Task<MaterialWithUnitConversionResult> ConvertPurchaseToStockAsync(string materialCode, decimal quantity)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+
+ // 濡傛灉閲囪喘鍗曚綅鍜屽簱瀛樺崟浣嶇浉鍚岋紝鐩存帴杩斿洖
+ if (materialData.PurchaseUnit.Equals(materialData.StockUnit, StringComparison.OrdinalIgnoreCase))
+ return new MaterialWithUnitConversionResult(quantity, materialData.StockUnit, false);
+
+ return ConvertAsync(materialData, quantity, materialData.PurchaseUnit, materialData.StockUnit);
+ }
+
+ public async Task<MaterialWithUnitConversionResult> ConvertFromToStockAsync(string materialCode,string fromUom, decimal quantity)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+
+ // 濡傛灉棰嗘枡鍗曚綅鍜屽簱瀛樺崟浣嶇浉鍚岋紝鐩存帴杩斿洖
+ if (fromUom.Equals(materialData.StockUnit, StringComparison.OrdinalIgnoreCase))
+ return new MaterialWithUnitConversionResult(quantity, materialData.StockUnit, false);
+
+ return ConvertAsync(materialData, quantity, fromUom, materialData.StockUnit);
+ }
+
+
+ /// <summary>
+ /// 棰嗘枡鍗曚綅杞簱瀛樺崟浣�
+ /// </summary>
+ public async Task<MaterialWithUnitConversionResult> ConvertIssueToStockAsync(string materialCode, decimal quantity)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+
+ // 濡傛灉棰嗘枡鍗曚綅鍜屽簱瀛樺崟浣嶇浉鍚岋紝鐩存帴杩斿洖
+ if (materialData.IssueUnit.Equals(materialData.StockUnit, StringComparison.OrdinalIgnoreCase))
+ return new MaterialWithUnitConversionResult(quantity, materialData.StockUnit, false);
+
+ return ConvertAsync(materialData, quantity, materialData.IssueUnit, materialData.StockUnit);
+ }
+
+ /// <summary>
+ /// 鑾峰彇鍗曚綅杞崲姣旂巼
+ /// </summary>
+ public async Task<decimal?> GetConversionRatioAsync(string materialCode, string fromUnit, string toUnit)
+ {
+ // 濡傛灉鍗曚綅鐩稿悓锛屾瘮鐜囦负1
+ if (fromUnit.Equals(toUnit, StringComparison.OrdinalIgnoreCase))
+ return 1m;
+
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+ return GetConversionRatioFromData(materialData, fromUnit, toUnit);
+ }
+
+ /// <summary>
+ /// 浠庡唴瀛樻暟鎹腑鑾峰彇杞崲姣旂巼
+ /// </summary>
+ private decimal? GetConversionRatioFromData(MaterialWithUnits materialData, string fromUnit, string toUnit)
+ {
+ // 鐩存帴鏌ユ壘杞崲鍏崇郴
+ var directConversion = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(fromUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(toUnit, StringComparison.OrdinalIgnoreCase));
+
+ if (directConversion != null)
+ {
+ return directConversion.Ratio;
+ }
+
+ // 鏌ユ壘鍙嶅悜杞崲鍏崇郴锛堝彇鍊掓暟锛�
+ var reverseConversion = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(toUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(fromUnit, StringComparison.OrdinalIgnoreCase));
+
+ if (reverseConversion != null)
+ {
+ return 1 / reverseConversion.Ratio;
+ }
+
+ // 閫氳繃搴撳瓨鍗曚綅杩涜闂存帴杞崲
+ var stockUnit = materialData.StockUnit;
+
+ // 鏌ユ壘 fromUnit -> stockUnit 鐨勮浆鎹�
+ var fromToStock = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(fromUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(stockUnit, StringComparison.OrdinalIgnoreCase));
+ var stockToFrom = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(stockUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(fromUnit, StringComparison.OrdinalIgnoreCase));
+
+ // 鏌ユ壘 stockUnit -> toUnit 鐨勮浆鎹�
+ var stockToTo = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(stockUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(toUnit, StringComparison.OrdinalIgnoreCase));
+ var toToStock = materialData.UnitConversions
+ .FirstOrDefault(x => x.FromUom.Equals(toUnit, StringComparison.OrdinalIgnoreCase) &&
+ x.ToUom.Equals(stockUnit, StringComparison.OrdinalIgnoreCase));
+
+ decimal? ratioFromToStock = null;
+ decimal? ratioStockToTo = null;
+
+ // 璁$畻 fromUnit -> stockUnit 鐨勬瘮鐜�
+ if (fromToStock != null)
+ {
+ ratioFromToStock = fromToStock.Ratio;
+ }
+ else if (stockToFrom != null)
+ {
+ ratioFromToStock = 1 / stockToFrom.Ratio;
+ }
+ else if (fromUnit.Equals(stockUnit, StringComparison.OrdinalIgnoreCase))
+ {
+ ratioFromToStock = 1; // 濡傛灉婧愬崟浣嶅氨鏄簱瀛樺崟浣嶏紝姣旂巼涓�1
+ }
+
+ // 璁$畻 stockUnit -> toUnit 鐨勬瘮鐜�
+ if (stockToTo != null)
+ {
+ ratioStockToTo = stockToTo.Ratio;
+ }
+ else if (toToStock != null)
+ {
+ ratioStockToTo = 1 / toToStock.Ratio;
+ }
+ else if (toUnit.Equals(stockUnit, StringComparison.OrdinalIgnoreCase))
+ {
+ ratioStockToTo = 1; // 濡傛灉鐩爣鍗曚綅灏辨槸搴撳瓨鍗曚綅锛屾瘮鐜囦负1
+ }
+
+ // 濡傛灉鎵惧埌浜嗕袱鏉¤矾寰勶紝杩斿洖涔樼Н
+ if (ratioFromToStock != null && ratioStockToTo != null)
+ {
+ return ratioFromToStock * ratioStockToTo;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// 鎵归噺杞崲锛堜紭鍖栨�ц兘锛屼竴娆℃煡璇㈠鐞嗗涓墿鏂欙級
+ /// </summary>
+ public async Task<Dictionary<string, MaterialWithUnitConversionResult>> BatchConvertAsync(List<BatchConversionRequest> requests)
+ {
+ if (requests == null || !requests.Any())
+ return new Dictionary<string, MaterialWithUnitConversionResult>();
+
+ // 鎸夌墿鏂欑紪鍙峰垎缁�
+ var materialGroups = requests.GroupBy(x => x.MaterialCode);
+ var results = new Dictionary<string, MaterialWithUnitConversionResult>();
+
+ foreach (var group in materialGroups)
+ {
+ var materialCode = group.Key;
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+
+ foreach (var request in group)
+ {
+ try
+ {
+ // 濡傛灉鍗曚綅鐩稿悓锛岀洿鎺ヨ繑鍥�
+ if (request.FromUnit.Equals(request.ToUnit, StringComparison.OrdinalIgnoreCase))
+ {
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, request.ToUnit, false);
+ continue;
+ }
+
+ var ratio = GetConversionRatioFromData(materialData, request.FromUnit, request.ToUnit);
+ if (ratio != null)
+ {
+ var convertedQuantity = request.Quantity * ratio.Value;
+ results[request.RequestId] = new MaterialWithUnitConversionResult(convertedQuantity, request.ToUnit, true);
+ }
+ else
+ {
+ _logger.LogWarning($"鏈壘鍒扮墿鏂� {materialCode} 浠� {request.FromUnit} 鍒� {request.ToUnit} 鐨勫崟浣嶈浆鎹㈠叧绯�");
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, request.ToUnit, false);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"鎵归噺杞崲鐗╂枡 {materialCode} 鏃跺彂鐢熼敊璇�");
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, request.ToUnit, false);
+ }
+ }
+ }
+
+ return results;
+ }
+
+ /// <summary>
+ /// 鎵归噺閲囪喘鍗曚綅杞簱瀛樺崟浣�
+ /// </summary>
+ public async Task<Dictionary<string, MaterialWithUnitConversionResult>> BatchConvertPurchaseToStockAsync(List<BatchConversionRequest> requests)
+ {
+ if (requests == null || !requests.Any())
+ return new Dictionary<string, MaterialWithUnitConversionResult>();
+
+ // 鎸夌墿鏂欑紪鍙峰垎缁�
+ var materialGroups = requests.GroupBy(x => x.MaterialCode);
+ var results = new Dictionary<string, MaterialWithUnitConversionResult>();
+
+ foreach (var group in materialGroups)
+ {
+ var materialCode = group.Key;
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+
+ foreach (var request in group)
+ {
+ try
+ {
+ // 濡傛灉閲囪喘鍗曚綅鍜屽簱瀛樺崟浣嶇浉鍚岋紝鐩存帴杩斿洖
+ if (materialData.PurchaseUnit.Equals(materialData.StockUnit, StringComparison.OrdinalIgnoreCase))
+ {
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, materialData.StockUnit, false);
+ continue;
+ }
+
+ var ratio = GetConversionRatioFromData(materialData, materialData.PurchaseUnit, materialData.StockUnit);
+ if (ratio != null)
+ {
+ var convertedQuantity = request.Quantity * ratio.Value;
+ results[request.RequestId] = new MaterialWithUnitConversionResult(convertedQuantity, materialData.StockUnit, true);
+ }
+ else
+ {
+ _logger.LogWarning($"鏈壘鍒扮墿鏂� {materialCode} 浠庨噰璐崟浣嶅埌搴撳瓨鍗曚綅鐨勮浆鎹㈠叧绯�");
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, materialData.StockUnit, false);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"鎵归噺杞崲鐗╂枡 {materialCode} 閲囪喘鍗曚綅鍒板簱瀛樺崟浣嶆椂鍙戠敓閿欒");
+ results[request.RequestId] = new MaterialWithUnitConversionResult(request.Quantity, materialData.StockUnit, false);
+ }
+ }
+ }
+
+ return results;
+ }
+
+ /// <summary>
+ /// 鑾峰彇鐗╂枡鐨勫簱瀛樺崟浣�
+ /// </summary>
+ public async Task<string> GetStockUnitAsync(string materialCode)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+ return materialData.StockUnit;
+ }
+
+ /// <summary>
+ /// 鑾峰彇鐗╂枡鐨勯噰璐崟浣�
+ /// </summary>
+ public async Task<string> GetPurchaseUnitAsync(string materialCode)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+ return materialData.PurchaseUnit;
+ }
+
+ /// <summary>
+ /// 鑾峰彇鐗╂枡鐨勯鏂欏崟浣�
+ /// </summary>
+ public async Task<string> GetIssueUnitAsync(string materialCode)
+ {
+ var materialData = await GetMaterialWithUnitsAsync(materialCode);
+ return materialData.IssueUnit;
+ }
+
+
+
}
}
--
Gitblit v1.9.3