From 1866b69e8f67e382a0a75268d63e6418c8ae02e7 Mon Sep 17 00:00:00 2001
From: heshaofeng <heshaofeng@hnkhzn.com>
Date: 星期二, 13 一月 2026 09:55:01 +0800
Subject: [PATCH] 1

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs |  221 +++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 165 insertions(+), 56 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_OutboundService/OutboundService.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_OutboundService/OutboundService.cs"
index b49a2ad..6adef6d 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_OutboundService/OutboundService.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_OutboundService/OutboundService.cs"
@@ -3,6 +3,7 @@
 using Dm.filter;
 using MailKit.Search;
 using Mapster;
+using Microsoft.IdentityModel.Tokens;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Serialization;
 using Org.BouncyCastle.Asn1.Ocsp;
@@ -18,6 +19,7 @@
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.CodeConfigEnum;
 using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Base;
 using WIDESEA_DTO.Basic;
 using WIDESEA_DTO.CalcOut;
 using WIDESEA_DTO.ReturnMES;
@@ -110,6 +112,7 @@
             PickingOutboundResponseDTO response = new PickingOutboundResponseDTO();
             try
             {
+                _unitOfWorkManage.BeginTran();
                 // 1. 璁$畻鍑哄簱鏁伴噺閫昏緫
                 OutboundCalculationDTO calculationResult = CalcOutboundQuantity(request);
 
@@ -170,7 +173,8 @@
 
                     pickedDetails.AddRange(materielPickedDetails.PickedDetails);
 
-                    decimal allallocatedQuantity = materielCalc.UnallocatedQuantity;
+                    decimal allallocatedQuantity = Math.Min(materielCalc.UnallocatedQuantity, materielPickedDetails.PickedDetails.Sum(x => x.OutboundQuantity));
+                    materielCalc.UnallocatedQuantity = allallocatedQuantity;
                     // 鏇存柊鍑哄簱鍗曟槑缁嗭紙澧炲姞閿佸畾鏁伴噺锛屼笉澧炲姞宸插嚭鏁伴噺锛�
                     foreach (var detail in materielCalc.Details)
                     {
@@ -248,14 +252,23 @@
                 }
 
                 result.FactoryArea = outboundOrder.FactoryArea;
+                List<Dt_OutboundOrderDetail> selectedDetails = new List<Dt_OutboundOrderDetail>();
 
-                // 鑾峰彇閫夋嫨鐨勫嚭搴撴槑缁�
-                List<Dt_OutboundOrderDetail> selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
-
-                if (outboundOrder.IsBatch == 1)
+                if (request.DetailIds == null || !request.DetailIds.Any())
                 {
-                    selectedDetails = _detailRepository.QueryData(x => x.OrderId == selectedDetails.First().OrderId && x.WarehouseCode == selectedDetails.First().WarehouseCode && x.MaterielCode == selectedDetails.First().MaterielCode && x.BatchNo == selectedDetails.First().BatchNo && x.SupplyCode == selectedDetails.First().SupplyCode);
+                    selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id);
                 }
+                else
+                {
+                    // 鑾峰彇閫夋嫨鐨勫嚭搴撴槑缁�
+                    selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
+                }
+
+
+                //if (outboundOrder.IsBatch == 1 && request.DetailIds.Count == 1)
+                //{
+                //    selectedDetails = _detailRepository.QueryData(x => x.OrderId == selectedDetails.First().OrderId && x.WarehouseCode == selectedDetails.First().WarehouseCode && x.MaterielCode == selectedDetails.First().MaterielCode && x.BatchNo == selectedDetails.First().BatchNo && x.SupplyCode == selectedDetails.First().SupplyCode);
+                //}
 
 
                 if (!selectedDetails.Any())
@@ -276,7 +289,7 @@
                 result.OutboundOrder = outboundOrder;
                 result.SelectedDetails = selectedDetails;
 
-                if (outboundOrder.IsBatch == 0)
+                if (outboundOrder.IsBatch == 0 || request.DetailIds.Count != 1)
                 {
                     // 澶氭槑缁嗗嚭搴擄細鎸夌墿鏂欏垎缁勫鐞�
                     result.MaterielCalculations = CalcMaterielOutboundQuantities(outboundOrder, selectedDetails.ToList());
@@ -363,7 +376,6 @@
                 .GroupBy(x => new
                 {
                     x.MaterielCode,
-                    x.MaterielName,
                     x.BatchNo,
                     x.SupplyCode,
                     x.WarehouseCode
@@ -371,7 +383,6 @@
                 .Select(g => new MaterielOutboundCalculationDTO
                 {
                     MaterielCode = g.Key.MaterielCode,
-                    MaterielName = g.Key.MaterielName,
                     BatchNo = g.Key.BatchNo,
                     SupplyCode = g.Key.SupplyCode,
                     WarehouseCode = g.Key.WarehouseCode,
@@ -423,13 +434,15 @@
             Dictionary<int, List<Dt_OutStockLockInfo>> lockStockMap = data.LockStockMap;
 
             // 楠岃瘉鎬诲彲鐢ㄥ簱瀛樻槸鍚︽弧瓒冲嚭搴撻渶姹�
-            if (totalAvailableStock < materielCalc.UnallocatedQuantity)
-            {
-                throw new Exception($"鐗╂枡 {materielCalc.MaterielCode} 鍙敤搴撳瓨 {totalAvailableStock} 涓嶈冻鍑哄簱鏁伴噺 {materielCalc.UnallocatedQuantity}");
-            }
+            //if (totalAvailableStock < materielCalc.UnallocatedQuantity)
+            //{
+            //    throw new Exception($"鐗╂枡 {materielCalc.MaterielCode} 鍙敤搴撳瓨 {totalAvailableStock} 涓嶈冻鍑哄簱鏁伴噺 {materielCalc.UnallocatedQuantity}");
+            //}
+            // 闇�鍒嗛厤鏁伴噺
+            decimal remainingQuantity = Math.Min(totalAvailableStock, materielCalc.UnallocatedQuantity);
 
             // 闇�鍒嗛厤鏁伴噺
-            decimal remainingQuantity = materielCalc.UnallocatedQuantity;
+            //decimal remainingQuantity = materielCalc.UnallocatedQuantity;
 
             // 宸插垎閰嶇殑鎵樼洏鍒楄〃
             List<string> allocatedPallets = new List<string>();
@@ -538,7 +551,7 @@
         private List<Dt_StockInfo> BuildStockQueryWithInfo(MaterielOutboundCalculationDTO materielCalc, string factoryArea)
         {
             // 鍩虹鏌ヨ鏉′欢锛氱墿鏂欑紪鍙枫�佹壒娆″彿锛堝鏋滄彁渚涳級銆佸簱瀛樻暟閲�>0
-            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0);
+            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0 && (x.Status == (int)StockStatusEmun.鍏ュ簱瀹屾垚 || x.Status == (int)StockStatusEmun.鎵嬪姩瑙i攣));
 
             // 鏍规嵁鏉′欢娣诲姞渚涘簲鍟嗙紪鍙峰尮閰嶏紙涓嶄负绌烘椂鎵嶉渶瑕佸尮閰嶏級
             if (!string.IsNullOrEmpty(materielCalc.SupplyCode))
@@ -867,22 +880,6 @@
                     return WebResponseContent.Instance.Error(response.Message);
                 }
 
-                bool isMatMixed = stockInfo.Details.GroupBy(x => new
-                {
-                    x.MaterielCode,
-                    x.MaterielName,
-                    x.BatchNo,
-                    x.SupplyCode,
-                    x.WarehouseCode
-                }).Count() > 1;
-
-                if (isMatMixed)
-                {
-                    response.Success = false;
-                    response.Message = $"娣锋枡鎵樼洏 {request.PalletCode} 涓嶈兘鏁寸鍑哄簱";
-                    return WebResponseContent.Instance.Error(response.Message);
-                }
-
                 // 2. 鏌ユ壘鍑哄簱鍗曚俊鎭�
                 Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(o => o.OrderNo == request.OrderNo);
                 if (outboundOrder == null)
@@ -905,6 +902,67 @@
                 {
                     response.Success = false;
                     response.Message = $"璇ュ簱瀛樻病鏈夊垎閰嶅嚭搴撻噺锛屾墭鐩樺彿锛歿request.PalletCode}";
+                    return WebResponseContent.Instance.Error(response.Message);
+                }
+
+                //bool isMatMixed = stockInfo.Details.GroupBy(x => new
+                //{
+                //    x.MaterielCode,
+                //    x.MaterielName,
+                //    x.BatchNo,
+                //    x.SupplyCode,
+                //    x.WarehouseCode
+                //}).Count() > 1;
+                bool isMatMixed = false;
+
+                bool includeBatchNo = !string.IsNullOrEmpty(lockInfo.BatchNo);
+                bool includeSupplyCode = !string.IsNullOrEmpty(lockInfo.SupplyCode);
+
+                if (includeBatchNo && includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.BatchNo,
+                        x.SupplyCode,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else if (includeBatchNo && !includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.BatchNo,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else if (!includeBatchNo && includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.SupplyCode,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+
+                if (isMatMixed)
+                {
+                    response.Success = false;
+                    response.Message = $"娣锋枡鎵樼洏 {request.PalletCode} 涓嶈兘鏁寸鍑哄簱";
                     return WebResponseContent.Instance.Error(response.Message);
                 }
 
@@ -959,7 +1017,6 @@
 
                     if (outboundOrder.OrderType != 0)
                     {
-
                         Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo);
                         if (allocateOrder != null)
                         {
@@ -1005,34 +1062,47 @@
                         //}
                         List<Barcodes> barcodesList = new List<Barcodes>();
                         List<Dt_StockInfoDetail> stockInfoDetails = stockInfo.Details.Where((x => x.StockQuantity > x.OutboundQuantity)).ToList();
+
+                        decimal itemQuantity = item.LockQuantity - item.OverOutQuantity;
+                        decimal unitbarcodeQuantity;
                         foreach (var stockDetail in stockInfoDetails)
                         {
-                            if (item.LockQuantity - item.OverOutQuantity >= stockDetail.StockQuantity - stockInfoDetail.OutboundQuantity)
+                            
+
+                            if (itemQuantity >= stockDetail.StockQuantity - stockDetail.OutboundQuantity)
                             {
+                                unitbarcodeQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
+                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, unitbarcodeQuantity);
+
                                 Barcodes barcodes = new Barcodes
                                 {
                                     Barcode = stockDetail.Barcode,
-                                    Qty = stockDetail.StockQuantity - stockInfoDetail.OutboundQuantity,
+                                    Qty = currentResult.ToQuantity,
                                     SupplyCode = stockDetail?.SupplyCode ?? "",
                                     BatchNo = stockDetail?.BatchNo ?? "",
-                                    Unit = stockDetail?.Unit ?? ""
+                                    Unit = currentResult.ToUnit ?? ""
                                 };
 
-                                stockDetail.StockQuantity = stockInfoDetail.OutboundQuantity;
+                                itemQuantity -= (stockDetail.StockQuantity - stockDetail.OutboundQuantity);
+                                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
                                 barcodesList.Add(barcodes);
+
+                                if (itemQuantity <= 0) break;
                             }
                             else
                             {
+                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, itemQuantity);
                                 Barcodes barcodes = new Barcodes
                                 {
                                     Barcode = stockDetail.Barcode,
-                                    Qty = item.LockQuantity - item.OverOutQuantity,
+                                    Qty = currentResult.ToQuantity,
                                     SupplyCode = stockDetail?.SupplyCode ?? "",
                                     BatchNo = stockDetail?.BatchNo ?? "",
-                                    Unit = stockDetail?.Unit ?? ""
+                                    Unit = currentResult.ToUnit ?? ""
                                 };
-                                stockInfoDetail.OutboundQuantity += item.LockQuantity - item.OverOutQuantity;
+                                stockDetail.OutboundQuantity += itemQuantity;
                                 barcodesList.Add(barcodes);
+                                break;
                             }
                         }
 
@@ -1097,8 +1167,11 @@
                     {
                         UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt());
 
+                        if (outboundOrder.OrderType != OutOrderTypeEnum.InternalAllocat.ObjToInt())
+                        {
+                            _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                        }
 
-                        //todo: 鍥炰紶MES
                     }
                 }
                 catch (Exception ex)
@@ -1382,7 +1455,6 @@
                     {
                         if (allocatedQuantity <= 0) break;
 
-
                         //if (item.OrderQuantity - item.MoveQty - item.OverOutQuantity >= allocatedQuantity)
                         //{
                         //    item.OverOutQuantity += allocatedQuantity;
@@ -1413,13 +1485,15 @@
                         updateDetails.Add(item);
 
                         List<Barcodes> barcodesList = new List<Barcodes>();
+                        UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, barcodeQuantity);
+
                         Barcodes barcodes = new Barcodes
                         {
-                            Barcode = request.Barcode,
-                            Qty = barcodeQuantity,
+                            Barcode = isUnpacked ? newBarcode : stockDetail?.Barcode,
+                            Qty = currentResult.ToQuantity,
                             SupplyCode = stockDetail?.SupplyCode ?? "",
                             BatchNo = stockDetail?.BatchNo ?? "",
-                            Unit = stockDetail?.Unit ?? ""
+                            Unit = currentResult.ToUnit ?? ""
                         };
                         if (!string.IsNullOrEmpty(item.ReturnJsonData))
                         {
@@ -1435,7 +1509,7 @@
 
                     lockInfo.SortedQuantity = lockInfo.SortedQuantity + actualOutboundQuantity;
 
-                    if (lockInfo.SortedQuantity == lockInfo.AssignQuantity)
+                    if (lockInfo.SortedQuantity >= lockInfo.AssignQuantity)
                     {
                         _outboundLockInfoRepository.DeleteAndMoveIntoHty(lockInfo, WIDESEA_Core.Enums.OperateTypeEnum.鑷姩瀹屾垚);
                     }
@@ -1481,14 +1555,33 @@
                         _feedbackMesService.BarcodeFeedback(newBarcode);
                     }
 
+                    // 鍒犻櫎閿佸畾璁板綍锛堝鏋滃嚭搴撴槑缁嗗叏閮ㄥ畬鎴愶級 涓嶤alculateActualOutboundQuantity鏂规硶閲岄潰娉ㄩ噴浠g爜2閫�1浣跨敤
+                    if (CheckOutboundOrderDetailCompletedByMatCode(request.OrderNo, lockInfo.MaterielCode, outboundOrderDetails.First()))
+                    {
+                        Func<Dt_OutStockLockInfo, bool> supWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().SupplyCode) ? true : x.SupplyCode == outboundOrderDetails.First().SupplyCode;
+
+                        Func<Dt_OutStockLockInfo, bool> wareWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().WarehouseCode) ? true : x.WarehouseCode == outboundOrderDetails.First().WarehouseCode;
+
+                        List<Dt_OutStockLockInfo> stockLockInfos = _outboundLockInfoRepository.QueryData(x =>
+                                x.OrderNo == request.OrderNo &&
+                                x.MaterielCode == stockDetail.MaterielCode).Where(supWhere).Where(wareWhere).ToList();
+                        if (stockLockInfos != null && stockLockInfos.Any())
+                        {
+                            _outboundLockInfoRepository.DeleteAndMoveIntoHty(stockLockInfos, WIDESEA_Core.Enums.OperateTypeEnum.鑷姩鍒犻櫎);
+                        }
+                    }
+
                     // 妫�鏌ュ嚭搴撳崟鏄惁瀹屾垚
                     if (CheckOutboundOrderCompleted(request.OrderNo))
                     {
                         UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt());
 
-
-                        //todo: 鍥炰紶MES
+                        if (outboundOrder.OrderType != OutOrderTypeEnum.InternalAllocat.ObjToInt())
+                        {
+                            _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                        }
                     }
+
                 }
                 catch (Exception ex)
                 {
@@ -1536,6 +1629,8 @@
         /// </summary>
         private decimal CalculateActualOutboundQuantity(Dt_StockInfoDetail stockDetail, List<Dt_OutboundOrderDetail> outboundDetails, Dt_OutStockLockInfo lockInfo)
         {
+            // decimal availableOutboundQuantity = lockInfo.AssignQuantity - lockInfo.SortedQuantity;
+
             decimal availableOutboundQuantity = lockInfo.AssignQuantity;
             decimal detailRemainingQuantity = outboundDetails.Sum(x => x.OrderQuantity - x.OverOutQuantity - x.MoveQty);//outboundDetail.OrderQuantity - outboundDetail.OverOutQuantity;
 
@@ -1554,7 +1649,7 @@
         /// <param name="beforeQuantity"></param>
         /// <param name="taskNum"></param>
         /// <returns></returns>
-        private (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
+        public (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
             decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum, int orderId, string orderNo)
         {
             string newBarcode = GenerateNewBarcode();
@@ -1632,7 +1727,7 @@
         /// <summary>
         /// 鎵ц瀹屾暣鍑哄簱鎿嶄綔锛堜笉鎷嗗寘锛�
         /// </summary>
-        private void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
+        public void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
             decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum)
         {
             // 淇濆瓨搴撳瓨鏄庣粏鍒板巻鍙茶褰�
@@ -1812,6 +1907,20 @@
             return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty);
         }
 
+        /// <summary>
+        /// 妫�鏌ュ嚭搴撳崟鏄庣粏鏄惁瀹屾垚
+        /// </summary>
+        public bool CheckOutboundOrderDetailCompletedByMatCode(string orderNo, string materialCode, Dt_OutboundOrderDetail outboundOrderDetail)
+        {
+            Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
+            if (outboundOrder == null) return false;
+
+            List<Dt_OutboundOrderDetail> details = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && x.MaterielCode == materialCode && (string.IsNullOrEmpty(outboundOrderDetail.SupplyCode) || x.SupplyCode == outboundOrderDetail.SupplyCode) && (string.IsNullOrEmpty(outboundOrderDetail.WarehouseCode) || x.WarehouseCode == outboundOrderDetail.WarehouseCode));
+
+            // 妫�鏌ユ墍鏈夋槑缁嗙殑宸插嚭鏁伴噺鏄惁閮界瓑浜庡崟鎹暟閲�
+            return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty);
+        }
+
         #endregion
 
         #region 鍙栫┖绠�
@@ -1898,13 +2007,13 @@
 
                 var newTask = new Dt_Task()
                 {
-                    CurrentAddress = stations[station],
+                    CurrentAddress = stations.GetValueOrDefault(station) ?? "",
                     Grade = 0,
                     PalletCode = palletCode,
                     NextAddress = "",
                     OrderNo = OrderNo,
                     Roadway = newLocation.RoadwayNo,
-                    SourceAddress = stations[station],
+                    SourceAddress = stations.GetValueOrDefault(station) ?? "",
                     TargetAddress = newLocation.LocationCode,
                     TaskStatus = (int)TaskStatusEnum.New,
                     TaskType = stock.Details.Count > 0 ? (int)TaskTypeEnum.InPick : (int)TaskTypeEnum.InEmpty,
@@ -1914,11 +2023,11 @@
                 _stockInfoRepository.UpdateData(stock);
                 _taskRepository.AddData(newTask);
 
-                //var moveResult = await _eSSApiService.MoveContainerAsync(new MoveContainerRequest
-                //{
-                //    slotCode = movestations[station],
-                //    containerCode = palletCode
-                //});
+                var moveResult = await _eSSApiService.MoveContainerAsync(new MoveContainerRequest
+                {
+                    slotCode = movestations[station],
+                    containerCode = palletCode
+                });
                 return content.OK();
 
             }

--
Gitblit v1.9.3