From 559bb7b4be83575cc5fedee98484647243c96f89 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期三, 08 四月 2026 15:57:44 +0800
Subject: [PATCH] feat: 空托盘出库完整流程 + 输送线调度优化 + S7Simulator 协议同步增强
---
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs | 563 +++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 438 insertions(+), 125 deletions(-)
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
index a2eedf1..935624b 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
@@ -1,56 +1,68 @@
-锘縰sing HslCommunication.WebSocket;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-using SqlSugar;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Mapster;
+using MapsterMapper;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
+using WIDESEA_Common.TaskEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
-using WIDESEA_Core.Const;
-using WIDESEA_Core.DB;
-using WIDESEA_Core.Enums;
-using WIDESEA_Core.Helper;
-using WIDESEA_Core.Seed;
using WIDESEA_Core.Utilities;
using WIDESEA_DTO.Basic;
+using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
+using WIDESEA_IRecordService;
using WIDESEA_Model.Models;
namespace WIDESEA_BasicService
{
+ /// <summary>
+ /// 璐т綅淇℃伅鏈嶅姟瀹炵幇绫�
+ /// </summary>
public partial class LocationInfoService : ServiceBase<Dt_LocationInfo, IRepository<Dt_LocationInfo>>, ILocationInfoService
{
- private readonly IUnitOfWorkManage _unitOfWorkManage;
+ private readonly IMapper _mapper;
+ private readonly IRepository<Dt_Task> _taskRepository;
private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
- public IRepository<Dt_LocationInfo> Repository => BaseDal;
+ private readonly IRecordService _recordService;
+ private readonly IRepository<Dt_Warehouse> _warehouseRepository;
- public LocationInfoService(IRepository<Dt_LocationInfo> BaseDal, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockInfoRepository) : base(BaseDal)
+ /// <summary>
+ /// 鏋勯�犲嚱鏁�
+ /// </summary>
+ /// <param name="baseDal">鍩虹鏁版嵁璁块棶瀵硅薄</param>
+ /// <param name="taskRepository">浠诲姟浠撳偍</param>
+ /// <param name="stockInfoRepository">搴撳瓨淇℃伅浠撳偍</param>
+ public LocationInfoService(
+ IRepository<Dt_LocationInfo> baseDal,
+ IRepository<Dt_Task> taskRepository,
+ IRepository<Dt_StockInfo> stockInfoRepository,
+ IRepository<Dt_Warehouse> warehouseRepository,
+ IMapper mapper,
+ IRecordService recordService) : base(baseDal)
{
- _unitOfWorkManage = unitOfWorkManage;
+ _taskRepository = taskRepository;
_stockInfoRepository = stockInfoRepository;
+ _mapper = mapper;
+ _recordService = recordService;
+ _warehouseRepository = warehouseRepository;
}
+
+ /// <summary>
+ /// 鑾峰彇璐т綅淇℃伅浠撳偍
+ /// </summary>
+ public IRepository<Dt_LocationInfo> Repository => BaseDal;
/// <summary>
/// 鎵归噺鍚敤璐т綅
/// </summary>
/// <param name="keys">璐т綅涓婚敭鏁扮粍</param>
- /// <returns></returns>
+ /// <returns>鎿嶄綔缁撴灉</returns>
public WebResponseContent LocationEnableStatus(int[] keys)
{
- List<Dt_LocationInfo> locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
- locationInfos.ForEach(x =>
- {
- x.EnableStatus = EnableStatusEnum.Normal.ObjToInt();
- });
+ var locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
+ locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Normal.GetHashCode());
Repository.UpdateData(locationInfos);
-
return WebResponseContent.Instance.OK();
}
@@ -58,16 +70,12 @@
/// 鎵归噺绂佺敤璐т綅
/// </summary>
/// <param name="keys">璐т綅涓婚敭鏁扮粍</param>
- /// <returns></returns>
+ /// <returns>鎿嶄綔缁撴灉</returns>
public WebResponseContent LocationDisableStatus(int[] keys)
{
- List<Dt_LocationInfo> locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
- locationInfos.ForEach(x =>
- {
- x.EnableStatus = EnableStatusEnum.Disable.ObjToInt();
- });
+ var locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
+ locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Disable.GetHashCode());
Repository.UpdateData(locationInfos);
-
return WebResponseContent.Instance.OK();
}
@@ -75,76 +83,45 @@
/// 鍗曚釜鍚敤璐т綅
/// </summary>
/// <param name="key">璐т綅涓婚敭</param>
- /// <returns></returns>
- public WebResponseContent LocationEnableStatus(int key)
- {
- return LocationEnableStatus(new int[] { key });
- }
+ /// <returns>鎿嶄綔缁撴灉</returns>
+ public WebResponseContent LocationEnableStatus(int key) => LocationEnableStatus(new[] { key });
/// <summary>
/// 鍗曚釜绂佺敤璐т綅
/// </summary>
/// <param name="key">璐т綅涓婚敭</param>
- /// <returns></returns>
- public WebResponseContent LocationDisableStatus(int key)
- {
- return LocationDisableStatus(new int[] { key });
- }
+ /// <returns>鎿嶄綔缁撴灉</returns>
+ public WebResponseContent LocationDisableStatus(int key) => LocationDisableStatus(new[] { key });
/// <summary>
/// 鍒濆鍖栬揣浣�
/// </summary>
- /// <param name="initializationLocationDTO"></param>
- /// <returns></returns>
- public WebResponseContent InitializationLocation(InitializationLocationDTO initializationLocationDTO)
+ /// <param name="dto">鍒濆鍖栬揣浣嶆暟鎹紶杈撳璞�</param>
+ /// <returns>鎿嶄綔缁撴灉</returns>
+ public WebResponseContent InitializationLocation(InitializationLocationDTO dto)
{
try
{
- (bool, string, object?) result = ModelValidate.ValidateModelData(initializationLocationDTO);
- if (!result.Item1) return WebResponseContent.Instance.Error(result.Item2);
+ var (isValid, errorMsg, _) = ModelValidate.ValidateModelData(dto);
+ if (!isValid) return WebResponseContent.Instance.Error(errorMsg);
- int depth = initializationLocationDTO.Depth;
- List<Dt_LocationInfo> locationInfos = new List<Dt_LocationInfo>();
- for (int i = 0; i < initializationLocationDTO.MaxRow; i++)
+ var locationInfos = new List<Dt_LocationInfo>();
+ int depth = dto.Depth;
+
+ for (int row = 1; row <= dto.MaxRow; row++)
{
- if ((i + 1) % initializationLocationDTO.MaxRow == 1)
+ depth = CalculateDepth(row, dto.MaxRow, dto.Depth, depth);
+
+ for (int col = 1; col <= dto.MaxColumn; col++)
{
- depth = initializationLocationDTO.Depth;
- }
- else if ((i + 1) % initializationLocationDTO.MaxRow == initializationLocationDTO.Depth + 1)
- {
- depth = 1;
- }
- else if ((i + 1) % initializationLocationDTO.MaxRow > 1 && (i + 1) % initializationLocationDTO.MaxRow <= initializationLocationDTO.Depth)
- {
- depth -= 1;
- }
- else
- {
- depth += 1;
- }
- for (int j = 0; j < initializationLocationDTO.MaxColumn; j++)
- {
- for (int k = 0; k < initializationLocationDTO.MaxLayer; k++)
+ for (int layer = 1; layer <= dto.MaxLayer; layer++)
{
- Dt_LocationInfo locationInfo = new Dt_LocationInfo()
- {
- WarehouseId = 0,
- Column = j + 1,
- EnableStatus = EnableStatusEnum.Normal.ObjToInt(),
- Layer = k + 1,
- LocationStatus = LocationStatusEnum.Free.ObjToInt(),
- LocationType = LocationTypeEnum.Undefined.ObjToInt(),
- RoadwayNo = $"{initializationLocationDTO.Roadway.ToString()}",
- Row = i + 1,
- Depth = depth,
- };
- locationInfo.LocationCode = $"{locationInfo.RoadwayNo}-{locationInfo.Row.ToString().PadLeft(3, '0')}-{locationInfo.Column.ToString().PadLeft(3, '0')}-{locationInfo.Layer.ToString().PadLeft(3, '0')}-{locationInfo.Depth.ToString().PadLeft(2, '0')}";
- locationInfo.LocationName = $"{locationInfo.RoadwayNo}宸烽亾{locationInfo.Row.ToString().PadLeft(3, '0')}琛寋locationInfo.Column.ToString().PadLeft(3, '0')}鍒梴locationInfo.Layer.ToString().PadLeft(3, '0')}灞倇locationInfo.Depth.ToString().PadLeft(2, '0')}娣�";
- locationInfos.Add(locationInfo);
+ var location = CreateLocationInfo(dto.Roadway, row, col, layer, depth);
+ locationInfos.Add(location);
}
}
}
+
BaseDal.AddData(locationInfos);
return WebResponseContent.Instance.OK();
}
@@ -154,71 +131,407 @@
}
}
-
-
/// <summary>
- /// 鑾峰彇绌洪棽璐т綅淇℃伅(鏍规嵁宸烽亾鏌ヨ)
+ /// 鏍规嵁宸烽亾鑾峰彇绌洪棽璐т綅淇℃伅
/// </summary>
- /// <param name="RoadwayNo">宸烽亾</param>
- /// <returns></returns>
- public async Task<Dt_LocationInfo?> GetLocationInfo(string RoadwayNo)
+ /// <param name="roadwayNo">宸烽亾缂栧彿</param>
+ /// <returns>绌洪棽璐т綅淇℃伅锛屽鏋滄湭鎵惧埌鍒欒繑鍥瀗ull</returns>
+ public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo)
{
- try
- {
- var locations = await BaseDal.QueryDataAsync(x => x.EnableStatus == EnableStatusEnum.Normal.GetHashCode() && x.RoadwayNo == RoadwayNo && x.LocationStatus == LocationStatusEnum.Free.GetHashCode());
+ var locations = await BaseDal.QueryDataAsync(x =>
+ x.EnableStatus == EnableStatusEnum.Normal.GetHashCode() &&
+ x.RoadwayNo == roadwayNo &&
+ x.LocationStatus == LocationStatusEnum.Free.GetHashCode());
- if (locations == null || locations.Count == 0)
- {
- return null;
- }
-
- return locations.OrderBy(x => x.Layer).ThenBy(x => x.Depth).ThenBy(x => x.Column).ThenBy(x => x.Row).FirstOrDefault();
- }
- catch (Exception)
- {
- return null;
- }
+ return locations?
+ .OrderByDescending(x => x.Depth) // 1. 娣卞害浼樺厛锛堜粠澶у埌灏忥級
+ .ThenBy(x => x.Layer) // 2. 灞傛暟
+ .ThenBy(x => x.Column) // 3. 鍒�
+ .ThenBy(x => x.Row) // 4. 琛�
+ .FirstOrDefault();
}
/// <summary>
- /// 鑾峰彇绌洪棽璐т綅淇℃伅(鏍规嵁宸烽亾鏌ヨ)
+ /// 鏍规嵁宸烽亾鍜岃揣浣嶇紪鐮佽幏鍙栫┖闂茶揣浣嶄俊鎭�
/// </summary>
- /// <param name="RoadwayNo">宸烽亾</param>
- /// <returns></returns>
- public async Task<Dt_LocationInfo?> GetLocationInfo(string RoadwayNo,string locationCode)
+ /// <param name="roadwayNo">宸烽亾缂栧彿</param>
+ /// <param name="locationCode">璐т綅缂栫爜</param>
+ /// <returns>璐т綅淇℃伅锛屽鏋滄湭鎵惧埌鍒欒繑鍥瀗ull</returns>
+ public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo, string locationCode)
{
- try
- {
- var locations = await BaseDal.QueryFirstAsync(x => x.RoadwayNo == RoadwayNo && x.LocationCode == locationCode);
+ return await BaseDal.QueryFirstAsync(x => x.RoadwayNo == roadwayNo && x.LocationCode == locationCode);
+ }
- if (locations == null)
- {
- return null;
- }
+ /// <summary>
+ /// 鏍规嵁璐т綅缂栫爜鑾峰彇璐т綅淇℃伅
+ /// </summary>
+ /// <param name="locationCode">璐т綅缂栫爜</param>
+ /// <returns>璐т綅淇℃伅</returns>
+ public async Task<Dt_LocationInfo> GetLocationInfoAsync(string locationCode)
+ {
+ return await BaseDal.QueryFirstAsync(x => x.LocationCode == locationCode);
+ }
- return locations;
- }
- catch (Exception)
- {
- return null;
- }
+ /// <summary>
+ /// 鏍规嵁璐т綅ID鑾峰彇璐т綅淇℃伅
+ /// </summary>
+ /// <param name="id">璐т綅id</param>
+ /// <returns>璐т綅淇℃伅</returns>
+ public async Task<Dt_LocationInfo> GetLocationInfoAsync(int id)
+ {
+ return await BaseDal.QueryFirstAsync(x => x.Id == id);
}
/// <summary>
/// 鏇存柊璐т綅淇℃伅
/// </summary>
- /// <param name="locationInfo"></param>
- /// <returns></returns>
+ /// <param name="locationInfo">璐т綅淇℃伅瀵硅薄</param>
+ /// <returns>鏇存柊鏄惁鎴愬姛</returns>
public async Task<bool> UpdateLocationInfoAsync(Dt_LocationInfo locationInfo)
{
+ var beforeLocation = await BaseDal.QueryFirstAsync(x => x.Id == locationInfo.Id);
+ var result = await BaseDal.UpdateDataAsync(locationInfo);
+ if (!result)
+ return false;
+
+ return beforeLocation == null
+ || await _recordService.AddLocationChangeRecordAsync(beforeLocation, locationInfo, LocationChangeType.HandUpdate, remark: "璐т綅鏇存柊");
+ }
+
+ public override WebResponseContent UpdateData(Dt_LocationInfo entity)
+ {
+ var beforeLocation = BaseDal.QueryFirst(x => x.Id == entity.Id);
+ var result = base.UpdateData(entity);
+ if (!result.Status || beforeLocation == null)
+ return result;
+
+ var saveRecordResult = _recordService.AddLocationChangeRecordAsync(beforeLocation, entity, LocationChangeType.HandUpdate, remark: "璐т綅鏇存柊").GetAwaiter().GetResult();
+ return saveRecordResult ? result : WebResponseContent.Instance.Error("璐т綅鐘舵�佸彉鏇磋褰曚繚瀛樺け璐�");
+ }
+
+ public override WebResponseContent UpdateData(List<Dt_LocationInfo> entities)
+ {
+ var beforeLocations = entities
+ .Select(entity => BaseDal.QueryFirst(x => x.Id == entity.Id))
+ .Where(location => location != null)
+ .ToDictionary(location => location!.Id, location => location!);
+
+ var result = base.UpdateData(entities);
+ if (!result.Status)
+ return result;
+
+ foreach (var entity in entities)
+ {
+ if (!beforeLocations.TryGetValue(entity.Id, out var beforeLocation))
+ continue;
+
+ var saveRecordResult = _recordService.AddLocationChangeRecordAsync(beforeLocation, entity, LocationChangeType.HandUpdate, remark: "鎵归噺璐т綅鏇存柊").GetAwaiter().GetResult();
+ if (!saveRecordResult)
+ return WebResponseContent.Instance.Error("璐т綅鐘舵�佸彉鏇磋褰曚繚瀛樺け璐�");
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// 妫�鏌ュ苟鐢熸垚绉诲簱浠诲姟鎴栬繑鍥炲嚭搴撲换鍔�
+ /// </summary>
+ /// <param name="taskNum">浠诲姟鍙�</param>
+ /// <returns>浠诲姟淇℃伅</returns>
+ public async Task<WebResponseContent> TransferCheckAsync(int taskNum)
+ {
+ var content = new WebResponseContent();
try
{
- return await BaseDal.UpdateDataAsync(locationInfo);
+ // 鏍规嵁浠诲姟鍙疯幏鍙栦换鍔�
+ var outboundTask = await _taskRepository.QueryFirstAsync(x => x.TaskNum == taskNum);
+ if (outboundTask == null)
+ return content.Error("浠诲姟涓嶅瓨鍦�");
+
+ var location = await BaseDal.QueryFirstAsync(x => x.LocationCode == outboundTask.SourceAddress && x.RoadwayNo == outboundTask.Roadway);
+
+ // 妫�鏌ユ槸鍚﹂渶瑕佽繘琛岀Щ搴�
+ if (CheckForInternalTransfer(location))
+ {
+ // 璁$畻瀵瑰簲浣嶇疆鐨勭浉瀵瑰簱浣嶏紙濂囨暟琛岀殑涓嬩竴琛屾垨鑰呭伓鏁拌鐨勪笂涓�琛岋級
+ var newLocationID = GetRelativeLocationID(location);
+
+ // 鑾峰彇鏂扮殑搴撲綅鐨勪换鍔�
+ var internalTransferTask = await _taskRepository.QueryFirstAsync(x => x.SourceAddress == newLocationID && x.Roadway == outboundTask.Roadway);
+
+ // 濡傛灉鏂扮殑搴撲綅娌℃湁鎵惧埌瀵瑰簲鐨勪换鍔�
+ if (internalTransferTask == null)
+ {
+ return content.OK("鑾峰彇鍒扮Щ搴撲换鍔�", await HandleNoTaskAtLocation(newLocationID, outboundTask));
+ }
+
+ // 鐩存帴杩斿洖涓�娣变綅鍑哄簱浠诲姟
+ return content.OK("鑾峰彇鍒颁竴娣变綅鍑哄簱浠诲姟", internalTransferTask);
+ }
+
+ // 杩斿洖褰撳墠搴撲綅鐨勫嚭搴撲换鍔�
+ return content.OK("褰撳墠鍑哄簱浠诲姟", outboundTask);
}
- catch (Exception)
+ catch (Exception ex)
{
- return false;
+ return content.Error($"鍙戠敓閿欒:{ex.Message}");
}
}
+
+ #region 绉佹湁鏂规硶
+
+ /// <summary>
+ /// 璁$畻鐩稿鐨勫簱浣岻D
+ /// </summary>
+ /// <param name="locationInfo">璐т綅淇℃伅</param>
+ /// <returns>鐩稿鐨勫簱浣岻D</returns>
+ private static string GetRelativeLocationID(Dt_LocationInfo locationInfo)
+ {
+ int line = locationInfo.Row;
+
+ // 璁$畻鐩稿鐨勮揣浣嶈鍊硷紝濂囨暟琛岀殑涓嬩竴琛屾垨鑰呭伓鏁拌鐨勪笂涓�琛�
+ int relativeLine = line % 2 == 1 ? line + 1 : line - 1;
+
+ // 鏋勫缓鏂扮殑搴撲綅ID
+ string[] newLocationParts = new string[] { relativeLine.ToString().PadLeft(3, '0'), locationInfo.Column.ToString().PadLeft(3, '0'), locationInfo.Layer.ToString().PadLeft(3, '0') };
+ return string.Join("-", newLocationParts);
+ }
+
+ /// <summary>
+ /// 澶勭悊娌℃湁浠诲姟鐨勫簱浣嶆儏鍐�
+ /// </summary>
+ /// <param name="newLocationID">鏂扮殑搴撲綅ID</param>
+ /// <param name="outboundTask">鍑哄簱浠诲姟</param>
+ /// <returns>鐢熸垚鐨勭Щ搴撲换鍔℃垨鍘熷鍑哄簱浠诲姟</returns>
+ private async Task<Dt_Task> HandleNoTaskAtLocation(string newLocationID, Dt_Task outboundTask)
+ {
+ // 鍒ゆ柇璇ヤ綅缃槸鍚︽湁搴撳瓨
+ var stockInfo = await _stockInfoRepository.QueryDataNavFirstAsync(x =>
+ x.LocationCode == newLocationID &&
+ x.StockStatus == StockStatusEmun.鍏ュ簱瀹屾垚.GetHashCode() &&
+ x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode());
+ if (stockInfo == null)
+ {
+ // 濡傛灉娌℃湁搴撳瓨锛岀洿鎺ヨ繑鍥炲綋鍓嶅嚭搴撲换鍔�
+ return outboundTask;
+ }
+
+ // 濡傛灉鏈夊簱瀛橈紝鐢熸垚绉诲簱浠诲姟
+ var emptyLocation = await GetTransferLocationEmptyAsync(outboundTask.Roadway);
+ var taskNo = await _taskRepository.GetTaskNo();
+
+ var newTransferTask = new Dt_Task
+ {
+ CreateDate = DateTime.Now,
+ Creater = App.User.UserName ?? "system",
+ CurrentAddress = newLocationID,
+ Grade = 99,
+ NextAddress = emptyLocation.LocationCode,
+ PalletCode = stockInfo.PalletCode,
+ Remark = "绉诲簱",
+ Roadway = stockInfo.LocationDetails.RoadwayNo,
+ SourceAddress = newLocationID,
+ TaskNum = taskNo,
+ TargetAddress = emptyLocation.LocationCode,
+ TaskType = TaskRelocationTypeEnum.Relocation.GetHashCode(),
+ TaskStatus = TaskRelocationStatusEnum.RelocationNew.GetHashCode(),
+ WarehouseId = stockInfo.WarehouseId
+ };
+
+ var createdTask = await _taskRepository.Db.Insertable(newTransferTask).ExecuteReturnEntityAsync();
+ var beforeStock = CloneStockSnapshot(stockInfo);
+ var beforeSourceLocation = stockInfo.LocationDetails == null ? null : CloneLocationSnapshot(stockInfo.LocationDetails);
+ var beforeTargetLocation = CloneLocationSnapshot(emptyLocation);
+
+ // 鍒涘缓绉诲簱浠诲姟鍚庯紝绔嬪嵆閿佸畾搴撳瓨鍜岀浉鍏宠揣浣嶏紝閬垮厤骞跺彂閲嶅鍒嗛厤
+ stockInfo.StockStatus = StockStatusEmun.绉诲簱閿佸畾.GetHashCode();
+ var updateStockResult = await _stockInfoRepository.UpdateDataAsync(stockInfo);
+
+ var locationsToUpdate = new List<Dt_LocationInfo>();
+ if (stockInfo.LocationDetails != null)
+ {
+ stockInfo.LocationDetails.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode();
+ locationsToUpdate.Add(stockInfo.LocationDetails);
+ }
+
+ emptyLocation.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode();
+ locationsToUpdate.Add(emptyLocation);
+
+ var updateLocationResult = await BaseDal.UpdateDataAsync(locationsToUpdate);
+ if (!updateStockResult || !updateLocationResult)
+ {
+ throw new Exception("鍒涘缓绉诲簱浠诲姟鍚庢洿鏂板簱瀛樼姸鎬佹垨璐т綅鐘舵�佸け璐�");
+ }
+
+ var saveStockRecordResult = await _recordService.AddStockChangeRecordAsync(
+ beforeStock,
+ stockInfo,
+ StockChangeTypeEnum.Relocation,
+ createdTask.TaskNum,
+ createdTask.OrderNo,
+ "绉诲簱浠诲姟棰勫崰搴撳瓨");
+ if (!saveStockRecordResult)
+ {
+ throw new Exception("鍒涘缓绉诲簱浠诲姟鍚庤褰曞簱瀛樺彉鏇村け璐�");
+ }
+
+ if (beforeSourceLocation != null && stockInfo.LocationDetails != null)
+ {
+ var saveSourceLocationRecordResult = await _recordService.AddLocationChangeRecordAsync(
+ beforeSourceLocation,
+ stockInfo.LocationDetails,
+ LocationChangeType.RelocationAssignLocation,
+ createdTask.TaskNum,
+ createdTask.OrderNo,
+ null,
+ "绉诲簱浠诲姟閿佸畾婧愯揣浣�");
+ if (!saveSourceLocationRecordResult)
+ {
+ throw new Exception("鍒涘缓绉诲簱浠诲姟鍚庤褰曟簮璐т綅鍙樻洿澶辫触");
+ }
+ }
+
+ var saveTargetLocationRecordResult = await _recordService.AddLocationChangeRecordAsync(
+ beforeTargetLocation,
+ emptyLocation,
+ LocationChangeType.RelocationAssignLocation,
+ createdTask.TaskNum,
+ createdTask.OrderNo,
+ null,
+ "绉诲簱浠诲姟閿佸畾鐩爣璐т綅");
+ if (!saveTargetLocationRecordResult)
+ {
+ throw new Exception("鍒涘缓绉诲簱浠诲姟鍚庤褰曠洰鏍囪揣浣嶅彉鏇村け璐�");
+ }
+
+ return createdTask;
+ }
+
+ private static Dt_LocationInfo CloneLocationSnapshot(Dt_LocationInfo location)
+ {
+ return new Dt_LocationInfo
+ {
+ Id = location.Id,
+ WarehouseId = location.WarehouseId,
+ LocationCode = location.LocationCode,
+ LocationName = location.LocationName,
+ RoadwayNo = location.RoadwayNo,
+ Row = location.Row,
+ Column = location.Column,
+ Layer = location.Layer,
+ Depth = location.Depth,
+ LocationType = location.LocationType,
+ LocationStatus = location.LocationStatus,
+ EnableStatus = location.EnableStatus,
+ Remark = location.Remark
+ };
+ }
+
+ private static Dt_StockInfo CloneStockSnapshot(Dt_StockInfo stockInfo)
+ {
+ return new Dt_StockInfo
+ {
+ Id = stockInfo.Id,
+ PalletCode = stockInfo.PalletCode,
+ PalletType = stockInfo.PalletType,
+ LocationId = stockInfo.LocationId,
+ LocationCode = stockInfo.LocationCode,
+ WarehouseId = stockInfo.WarehouseId,
+ StockStatus = stockInfo.StockStatus,
+ Remark = stockInfo.Remark,
+ OutboundDate = stockInfo.OutboundDate,
+ Details = stockInfo.Details?.Select(detail => new Dt_StockInfoDetail
+ {
+ Id = detail.Id,
+ StockId = detail.StockId,
+ MaterielCode = detail.MaterielCode,
+ MaterielName = detail.MaterielName,
+ OrderNo = detail.OrderNo,
+ BatchNo = detail.BatchNo,
+ ProductionDate = detail.ProductionDate,
+ EffectiveDate = detail.EffectiveDate,
+ SerialNumber = detail.SerialNumber,
+ StockQuantity = detail.StockQuantity,
+ OutboundQuantity = detail.OutboundQuantity,
+ Status = detail.Status,
+ Unit = detail.Unit,
+ InboundOrderRowNo = detail.InboundOrderRowNo,
+ Remark = detail.Remark
+ }).ToList()
+ };
+ }
+
+ /// <summary>
+ /// 妫�鏌ヨ揣浣嶆槸鍚﹂渶瑕佺Щ搴�
+ /// </summary>
+ /// <param name="location">璐т綅淇℃伅</param>
+ /// <returns>鏄惁闇�瑕佺Щ搴�</returns>
+ private static bool CheckForInternalTransfer(Dt_LocationInfo location)
+ {
+ return location.Depth == 2;
+ }
+
+ /// <summary>
+ /// 鏍规嵁宸烽亾鑾峰彇浜屾繁浣嶇殑绌哄簱浣�
+ /// </summary>
+ /// <param name="roadway">宸烽亾缂栧彿</param>
+ /// <returns>璐т綅瀵硅薄</returns>
+ private async Task<Dt_LocationInfo> GetTransferLocationEmptyAsync(string roadway)
+ {
+ return await BaseDal.QueryFirstAsync(x => x.Depth == 2 && x.LocationStatus == LocationStatusEnum.Free.GetHashCode() && x.RoadwayNo == roadway);
+ }
+
+ /// <summary>
+ /// 璁$畻娣卞害
+ /// </summary>
+ /// <param name="row">琛屽彿</param>
+ /// <param name="maxRow">鏈�澶ц鏁�</param>
+ /// <param name="maxDepth">鏈�澶ф繁搴�</param>
+ /// <param name="currentDepth">褰撳墠娣卞害</param>
+ /// <returns>璁$畻鍚庣殑娣卞害</returns>
+ private static int CalculateDepth(int row, int maxRow, int maxDepth, int currentDepth)
+ {
+ int mod = row % maxRow;
+ if (mod == 1) return maxDepth;
+ if (mod == maxDepth + 1) return 1;
+ if (mod > 1 && mod <= maxDepth) return currentDepth - 1;
+ return currentDepth + 1;
+ }
+
+ /// <summary>
+ /// 鍒涘缓璐т綅淇℃伅
+ /// </summary>
+ /// <param name="roadwayNo">宸烽亾缂栧彿</param>
+ /// <param name="row">琛屽彿</param>
+ /// <param name="col">鍒楀彿</param>
+ /// <param name="layer">灞傛暟</param>
+ /// <param name="depth">娣卞害</param>
+ /// <returns>璐т綅淇℃伅瀵硅薄</returns>
+ private Dt_LocationInfo CreateLocationInfo(string roadwayNo, int row, int col, int layer, int depth)
+ {
+ var warehouse = _warehouseRepository.QueryData(x => x.WarehouseCode == roadwayNo).FirstOrDefault();
+
+ if (warehouse == null)
+ {
+ throw new InvalidOperationException($"鏈壘鍒板贩閬撶紪鍙蜂负 {roadwayNo} 鐨勪粨搴撲俊鎭�");
+ }
+
+ return new Dt_LocationInfo
+ {
+ WarehouseId = warehouse.WarehouseId,
+ Row = row,
+ Column = col,
+ Layer = layer,
+ Depth = depth,
+ RoadwayNo = roadwayNo,
+ EnableStatus = EnableStatusEnum.Normal.GetHashCode(),
+ LocationStatus = LocationStatusEnum.Free.GetHashCode(),
+ LocationType = LocationTypeEnum.Undefined.GetHashCode(),
+ LocationCode = $"{roadwayNo}-{row:D3}-{col:D3}-{layer:D3}",
+ LocationName = $"{roadwayNo}宸烽亾{row:D3}琛寋col:D3}鍒梴layer:D3}灞倇depth:D2}娣�"
+ };
+ }
+
+ #endregion 绉佹湁鏂规硶
}
}
--
Gitblit v1.9.3