From 37acb8358f5602a9013ee29c04a45e33483c2329 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期四, 09 四月 2026 15:21:40 +0800
Subject: [PATCH] fix: 修复PLC字符串解析和任务处理逻辑

---
 Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs |  547 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 464 insertions(+), 83 deletions(-)

diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
index 16c743a..53ef4b5 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();
             }
@@ -153,5 +130,409 @@
                 return WebResponseContent.Instance.Error(ex.Message);
             }
         }
+
+        /// <summary>
+        /// 鏍规嵁宸烽亾鑾峰彇绌洪棽璐т綅淇℃伅
+        /// </summary>
+        /// <param name="roadwayNo">宸烽亾缂栧彿</param>
+        /// <returns>绌洪棽璐т綅淇℃伅锛屽鏋滄湭鎵惧埌鍒欒繑鍥瀗ull</returns>
+        public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo)
+        {
+            var locations = await BaseDal.QueryDataAsync(x =>
+                x.EnableStatus == EnableStatusEnum.Normal.GetHashCode() &&
+                x.RoadwayNo == roadwayNo &&
+                x.LocationStatus == LocationStatusEnum.Free.GetHashCode());
+
+            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>
+        /// <param name="locationCode">璐т綅缂栫爜</param>
+        /// <returns>璐т綅淇℃伅锛屽鏋滄湭鎵惧埌鍒欒繑鍥瀗ull</returns>
+        public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo, string locationCode)
+        {
+            return await BaseDal.QueryFirstAsync(x => x.RoadwayNo == roadwayNo && x.LocationCode == locationCode);
+        }
+
+        /// <summary>
+        /// 鏍规嵁璐т綅缂栫爜鑾峰彇璐т綅淇℃伅
+        /// </summary>
+        /// <param name="locationCode">璐т綅缂栫爜</param>
+        /// <returns>璐т綅淇℃伅</returns>
+        public async Task<Dt_LocationInfo> GetLocationInfoAsync(string locationCode)
+        {
+            return await BaseDal.QueryFirstAsync(x => x.LocationCode == locationCode);
+        }
+
+        /// <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>
+        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
+            {
+                // 鏍规嵁浠诲姟鍙疯幏鍙栦换鍔�
+                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 ex)
+            {
+                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}",
+                LocationCode = $"{row:D3}-{col:D3}-{layer:D3}",
+                LocationName = $"{roadwayNo}宸烽亾{row:D3}琛寋col:D3}鍒梴layer:D3}灞倇depth:D2}娣�"
+            };
+        }
+
+        #endregion 绉佹湁鏂规硶
     }
 }

--
Gitblit v1.9.3