Browse Source

Merge branch 'develop' of http://132.232.92.186:3000/XinXiBu/OA2023 into develop

yuanrf 5 days ago
parent
commit
4f3bd3ed69

+ 86 - 36
OASystem/OASystem.Api/Controllers/GroupsController.cs

@@ -3366,6 +3366,8 @@ FROM
                                          checkOut = Convert.ToDateTime(hotelReservations.CheckOutDate);
                                 int hotel_days = (int)(checkOut - checkIn).TotalDays;
 
+
+
                                 string roomFeeStr = "", roomFeestr1 = "";
 
                                 //是否比较房型价格
@@ -3377,33 +3379,33 @@ FROM
                                 if (hotelReservations.SingleRoomPrice > 0)
                                 {
                                     var fee = hotelReservations.SingleRoomPrice * hotelReservations.SingleRoomCount * (int)hotel_days;
-                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>单间:{hotelReservations.SingleRoomPrice.ToString("#0.00")} * {hotelReservations.SingleRoomCount}间 * {(int)hotel_days}晚 = {fee.ToString("#0.00")}<br/>";
+                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>单间:{hotelReservations.SingleRoomPrice:#0.00} * {hotelReservations.SingleRoomCount}间 * {(int)hotel_days}晚 = {fee:#0.00}<br/>";
                                     //__isSingle = true;
                                     roomTotal += fee;
                                 }
                                 if (hotelReservations.DoubleRoomPrice > 0)
                                 {
                                     var fee = hotelReservations.DoubleRoomPrice * hotelReservations.DoubleRoomCount * (int)hotel_days;
-                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>双人间:{hotelReservations.DoubleRoomPrice.ToString("#0.00")} * {hotelReservations.DoubleRoomCount}间 * {(int)hotel_days}晚 = {fee.ToString("#0.00")}<br/>";
+                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>双人间:{hotelReservations.DoubleRoomPrice:#0.00} * {hotelReservations.DoubleRoomCount}间 * {(int)hotel_days}晚 = {fee:#0.00}<br/>";
                                     // __isDouble = true;
                                     roomTotal += fee;
                                 }
                                 if (hotelReservations.SuiteRoomPrice > 0)
                                 {
                                     var fee = hotelReservations.SuiteRoomPrice * hotelReservations.SuiteRoomCount * (int)hotel_days;
-                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>套房:{hotelReservations.SuiteRoomPrice.ToString("#0.00")} * {hotelReservations.SuiteRoomCount}间 * {(int)hotel_days}晚 = {fee.ToString("#0.00")}<br/>";
+                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>套房:{hotelReservations.SuiteRoomPrice:#0.00} * {hotelReservations.SuiteRoomCount}间 * {(int)hotel_days}晚 = {fee:#0.00}<br/>";
                                     //__isSuite = true;
                                     roomTotal += fee;
                                 }
                                 if (hotelReservations.OtherRoomPrice > 0)
                                 {
                                     var fee = hotelReservations.OtherRoomPrice * hotelReservations.OtherRoomCount * (int)hotel_days;
-                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>其他:{hotelReservations.OtherRoomPrice.ToString("#0.00")} * {hotelReservations.OtherRoomCount}间 * {(int)hotel_days}晚 = {fee.ToString("#0.00")}<br/>";
+                                    roomFeestr1 += $"<span style='width:70px;display: inline-block;'></span>其他:{hotelReservations.OtherRoomPrice:#0.00} * {hotelReservations.OtherRoomCount}间 * {(int)hotel_days}晚 = {fee:#0.00}<br/>";
                                     //__isOther = true;
                                     roomTotal += fee;
                                 }
 
-                                if (roomFeestr1.Length > 0) roomFeeStr += roomFeestr1 + $"<span style='width:70px;display: inline-block;'></span>房费总金额:{roomTotal.ToString("#0.00")}";
+                                if (roomFeestr1.Length > 0) roomFeeStr += roomFeestr1 + $"<span style='width:70px;display: inline-block;'></span>房费总金额:{roomTotal:#0.00}";
                                 else roomFeeStr += "  0.00 * 0";
 
 
@@ -3488,7 +3490,7 @@ FROM
                                 {
                                     if (int.TryParse(groupCost.Currency, out int currencyId)) groupCost.Currency = currencyItems.Find(s => s.Id == currencyId)?.Name ?? "-";
 
-                                    hotelCostStr += $"{groupCost.Currency}(汇率:{groupCost.Rate.ToString("#0.0000")})<br/>";
+                                    hotelCostStr += $"{groupCost.Currency}(汇率:{groupCost.Rate:#0.0000})<br/>";
                                 }
 
 
@@ -3502,21 +3504,21 @@ FROM
                                 {
                                     hotelCsotTotal += item.Sum(x => x.HotelSingleRoomFee) + item.Sum(x => x.HotelDoubleRoomFee) + item.Sum(x => x.HotelSuiteRoomFee) + item.Sum(x => x.HotelSuiteFee);
                                     hotelCost_day += @$"{item.First()?.Date ?? "-"}";
-                                    if (item.Sum(x => x.HotelSingleRoomFee) != 0) hotelCost_day += @$"   单间:{item.Sum(x => x.HotelSingleRoomFee).ToString("#0.00")}";
+                                    if (item.Sum(x => x.HotelSingleRoomFee) != 0) hotelCost_day += @$"   单间:{item.Sum(x => x.HotelSingleRoomFee):#0.00}";
                                     //else { if (__isSingle) hotelCost_day += @$"   单间:0.00"; }
-                                    if (item.Sum(x => x.HotelDoubleRoomFee) != 0) hotelCost_day += @$"   双人间:{item.Sum(x => x.HotelDoubleRoomFee).ToString("#0.00")}";
+                                    if (item.Sum(x => x.HotelDoubleRoomFee) != 0) hotelCost_day += @$"   双人间:{item.Sum(x => x.HotelDoubleRoomFee):#0.00}";
                                     //else { if (__isDouble) hotelCost_day += @$"   双人间:0.00"; }
-                                    if (item.Sum(x => x.HotelSuiteRoomFee) != 0) hotelCost_day += @$"   小套房/豪华套房:{item.Sum(x => x.HotelSuiteRoomFee).ToString("#0.00")}";
+                                    if (item.Sum(x => x.HotelSuiteRoomFee) != 0) hotelCost_day += @$"   小套房/豪华套房:{item.Sum(x => x.HotelSuiteRoomFee):#0.00}";
                                     //else { if (__isSuite) hotelCost_day += @$"   小套房/豪华套房:0.00"; }
-                                    if (item.Sum(x => x.HotelSuiteFee) != 0) hotelCost_day += @$"   套房:{item.Sum(x => x.HotelSuiteFee).ToString("#0.00")}";
+                                    if (item.Sum(x => x.HotelSuiteFee) != 0) hotelCost_day += @$"   套房:{item.Sum(x => x.HotelSuiteFee):#0.00}";
                                     //else { if (__isOther) hotelCost_day += @$"   套房:0.00"; }
                                     hotelCost_day += @$"<br/>";
                                 }
 
                                 string hotelBreakfastStr = "", hotelGovernmentRentStr = "", hotelCityTaxStr = "";
-                                if (breakfastFee > 0) hotelBreakfastStr = $"酒店早餐: {breakfastFee.ToString("#0.00")} {breakfastCode} {breakfastName} 当时汇率 {breakfastData?.Rate.ToString("#0.0000")} <br/>是否由地接或其他人代付:{breakfastBool}<br/><br/>";
-                                if (governmentRentFee > 0) hotelGovernmentRentStr = $"地税: {governmentRentFee.ToString("#0.00")} {governmentRentCode} {governmentRentName} 当时汇率 {governmentRentData?.Rate.ToString("#0.0000")} <br/>是否由地接或其他人代付:{governmentRentBool}<br/><br/>";
-                                if (cityTaxFee > 0) hotelCityTaxStr = $"城市税: {cityTaxFee.ToString("#0.00")} {cityTaxCode} {cityTaxName} 当时汇率 {cityTaxData?.Rate.ToString("#0.0000")} <br/>是否由地接或其他人代付:{cityTaxBool}<br/>";
+                                if (breakfastFee > 0) hotelBreakfastStr = $"酒店早餐: {breakfastFee:#0.00} {breakfastCode} {breakfastName} 当时汇率 {breakfastData?.Rate:#0.0000} <br/>是否由地接或其他人代付:{breakfastBool}<br/><br/>";
+                                if (governmentRentFee > 0) hotelGovernmentRentStr = $"地税: {governmentRentFee:#0.00} {governmentRentCode} {governmentRentName} 当时汇率 {governmentRentData?.Rate:#0.0000} <br/>是否由地接或其他人代付:{governmentRentBool}<br/><br/>";
+                                if (cityTaxFee > 0) hotelCityTaxStr = $"城市税: {cityTaxFee:#0.00} {cityTaxCode} {cityTaxName} 当时汇率 {cityTaxData?.Rate:#0.0000)} <br/>是否由地接或其他人代付:{cityTaxBool}<br/>";
 
                                 string hotelCostTotalStr = "";// $"&nbsp;&nbsp;成本合计:{hotelCsotTotal.ToString("#0.00")}<br/>";
                                 _detail.PriceMsgContent = $"{hotelCostTitalStr}{hotelCostStr}{hotelCostTotalStr}{hotelCost_day}<br/>" +
@@ -3568,7 +3570,9 @@ FROM
                                 var touristGuideGroundReservationsContents =
                                     _CarTouristGuideGroundReservationsContent.Where(s => s.CTGGRId == touristGuideGroundReservations.Id && s.IsDel == 0 && s.Price != 0).ToList();
 
-                                string priceMsg = $"<span style='font-weight:800;'>{touristGuideGroundReservations.PriceName}({touristGuideGroundReservations.ServiceStartTime} - {touristGuideGroundReservations.ServiceEndTime})</span><br/>";
+                                var opContent_sb = new StringBuilder();
+                                string contetTitle = $"<span style='font-weight:800;'>{touristGuideGroundReservations.PriceName}({touristGuideGroundReservations.ServiceStartTime} - {touristGuideGroundReservations.ServiceEndTime})</span><br/>";
+                                opContent_sb.AppendLine(contetTitle);
 
                                 foreach (var item in touristGuideGroundReservationsContents)
                                 {
@@ -3586,19 +3590,21 @@ FROM
                                         carCurrencyName = currencyData.Remark;
                                     }
 
-                                    //op、成本 币种是否一致
+                                    //op、成本 币种是否一致 (币种一致只比较金额:2025-04-18)
                                     bool IsCurrencyAgreement = false;
                                     if (carCurrencyCode.Equals(_groupCurrencyCode)) IsCurrencyAgreement = true;
 
                                     string opCostStr = string.Empty;
                                     decimal opCostTypePrice = 0.00M;
                                     #region 处理成本各项费用
-
                                     var opDate = item.DatePrice?.ToString("yyyy-MM-dd");
 
-
                                     var opCost = groupCostDetails.Where(x => x.Date.Equals(opDate)).ToList();
 
+                                    decimal aduitOPFeeCNY = 0.00M,   //费用审核 op费用
+                                            costOPFeeCNY = 0.00M,    //团组成本 op费用
+                                            opPayPercentage = entity.PayPercentage == 0.00M ? 1.00M : entity.PayPercentage / 100M; //费用审核 op付款百分比
+
                                     if (opCost.Count > 0)
                                     {
                                         switch (item.SId)
@@ -3631,23 +3637,66 @@ FROM
                                                                                                                      //case 91: opCostTypePrice = opCost.Sum(x => x.CarFee); break; //1075    午餐超支费用
                                                                                                                      //case 91: opCostTypePrice = opCost.Sum(x => x.CarFee); break; //1076    晚餐超支费用
                                         }
-                                        opCostStr = $"&nbsp;&nbsp;/&nbsp;&nbsp;成本:{opCostTypePrice.ToString("#0.00")} {_groupCurrencyCode}(汇率:{_groupRate.ToString("#0.0000")})";
-                                        if (!IsCurrencyAgreement) opCostStr += $" ≈ {(opCostTypePrice * _groupRate).ToString("#0.00")} CNY";
+                                        opCostStr = $"&nbsp;&nbsp;/&nbsp;&nbsp;成本:{opCostTypePrice:#0.00} {_groupCurrencyCode}(汇率:{_groupRate:#0.0000})";
+
+                                        costOPFeeCNY = opCostTypePrice * _groupRate;
+                                        if (!IsCurrencyAgreement) opCostStr += $" ≈ {costOPFeeCNY:#0.00} CNY";
                                     }
 
                                     #endregion
 
-                                    string opTypeStr = $"{typeName}:{item.Price.ToString("#0.00")} {carCurrencyCode}(汇率:{entity.DayRate.ToString("#0.0000")})";
-                                    if (!IsCurrencyAgreement) opTypeStr += $" ≈ {(item.Price * entity.DayRate).ToString("#0.00")} CNY";
+                                    string opTypeStr = $"{typeName}:{item.Price:#0.00} {carCurrencyCode}(汇率:{entity.DayRate:#0.0000})";
 
-                                    priceMsg += $"日期:{item.DatePrice?.ToString("yyyy-MM-dd") ?? "-"}<br/>" +
-                                                $"{opTypeStr}   {opCostStr}<br/>" +
-                                                $"明细:{item.PriceContent ?? "-"}<br/>" +
-                                                $"备注:{item.Remark ?? "-"}<br/><br/>";
-                                }
+                                    aduitOPFeeCNY = item.Price * entity.DayRate;
+                                    if (!IsCurrencyAgreement) opTypeStr += $" ≈ {aduitOPFeeCNY:#0.0000} CNY";
 
+                                    var opContent = $"日期:{item.DatePrice?.ToString("yyyy-MM-dd") ?? "-"}<br/>" +
+                                                    $"{opTypeStr}   {opCostStr}<br/>" +
+                                                    $"明细:{item.PriceContent ?? "-"}<br/>" +
+                                                    $"备注:{item.Remark ?? "-"}<br/><br/>";
+
+                                    if (entity.IsAuditGM != 3) //状态 != 自动审核
+                                    {
+                                        if (IsCurrencyAgreement)
+                                        {
+                                            if (item.Price > opCostTypePrice)
+                                            {
+                                                opContent_sb.Append("<span style='color:red;'>");
+                                                opContent_sb.Append(opContent);
+                                                opContent_sb.Append("</span>");
+                                                opContent_sb.AppendLine();
+                                            }
+                                            else
+                                            {
+                                                opContent_sb.Append(opContent);
+                                                opContent_sb.AppendLine();
+                                            }
+                                        }
+                                        else
+                                        {
+                                            //验证是否超成本 按付款比例计算
+                                            if (aduitOPFeeCNY * opPayPercentage > costOPFeeCNY * opPayPercentage)
+                                            {
+                                                opContent_sb.Append("<span style='color:red;'>");
+                                                opContent_sb.Append(opContent);
+                                                opContent_sb.Append("</span>");
+                                                opContent_sb.AppendLine();
+                                            }
+                                            else
+                                            {
+                                                opContent_sb.Append(opContent);
+                                                opContent_sb.AppendLine();
+                                            }
+                                        }
+                                    }
+                                    else
+                                    {
+                                        opContent_sb.Append(opContent);
+                                        opContent_sb.AppendLine();
+                                    }
+                                }
 
-                                _detail.PriceMsgContent = priceMsg;
+                                _detail.PriceMsgContent = opContent_sb.ToString();
                             }
 
                             break;
@@ -19877,9 +19926,9 @@ AirHotelPrice
             #endregion
 
             var hrDtas = await _sqlSugar.Queryable<Grp_HotelReservations>()
-                                        .Where(it => it.IsDel == 0 && it.DiId == _dto.DiId)
-                                        .OrderBy(x => x.CheckInDate)
-                                        .ToListAsync();
+                .Where(it => it.IsDel == 0 && it.DiId == _dto.DiId)
+                .OrderBy(x => x.CheckInDate)
+                .ToListAsync();
 
             //判断数据是否完整
             if (hrDtas.Count < 1) return Ok(JsonView(StatusCodes.Status400BadRequest, "请先录入酒店预订信息!", ""));
@@ -19983,7 +20032,7 @@ AirHotelPrice
                     builder.Writeln(@$"VOUCHER No:{item.CheckNumber}   DATE: {item.CreateTime.ToString("yyyy-MM-dd")}");
 
 
-                    builder.StartTable();
+                     builder.StartTable();
 
                     // 设置边框颜色
                     builder.CellFormat.Borders.Top.Color = System.Drawing.Color.Black;
@@ -20068,18 +20117,19 @@ AirHotelPrice
                     builder.ParagraphFormat.LineSpacing = 11;   //设置固定的行距为11磅
                     builder.Write("CONFIRMATION NO:");
 
+
                     builder.InsertCell();
-                    builder.CellFormat.PreferredWidth = PreferredWidth.FromPercent(30);//列宽 - 百分比
+                    builder.CellFormat.PreferredWidth = PreferredWidth.FromPercent(20);//列宽 - 百分比
                     builder.ParagraphFormat.Style.Font.Name = "微软雅黑";
-                    builder.ParagraphFormat.Style.Font.Size = 7.5;
+                    builder.ParagraphFormat.Style.Font.Size = 8;
                     builder.ParagraphFormat.Style.Font.Bold = false;
+                    builder.CellFormat.HorizontalMerge = CellMerge.None;
                     builder.CellFormat.FitText = true;//单元格内文字设为多行(默认为单行,会影响单元格宽)
-                    builder.ParagraphFormat.Alignment = ParagraphAlignment.Left;//对齐
+                    builder.ParagraphFormat.Alignment = ParagraphAlignment.Left;//对齐 
                     builder.ParagraphFormat.SpaceBefore = 0;    //设置段前间距 0
                     builder.ParagraphFormat.SpaceAfter = 0;     //设置段后间距 0
                     builder.ParagraphFormat.LineSpacingRule = LineSpacingRule.Exactly;  //设置行距 固定值
                     builder.ParagraphFormat.LineSpacing = 11;   //设置固定的行距为11磅
-                    builder.CellFormat.VerticalMerge = CellMerge.None;
                     builder.CellFormat.HorizontalMerge = CellMerge.First;
                     builder.Write($"{item.DetermineNo}");
 
@@ -20328,7 +20378,7 @@ AirHotelPrice
                     builder.ParagraphFormat.LineSpacingRule = LineSpacingRule.Exactly;  //设置行距 固定值
                     builder.ParagraphFormat.LineSpacing = 11;   //设置固定的行距为11磅
                     builder.CellFormat.HorizontalMerge = CellMerge.First;
-                    builder.Write($"{item.GuestName}");
+                    builder.Write($"{item.GuestName.Trim()}");
 
 
                     builder.InsertCell();

+ 223 - 1
OASystem/OASystem.Api/Controllers/PersonnelModuleController.cs

@@ -2052,6 +2052,7 @@ WHERE
                 pageId = 191;
 
             PageFunAuthViewBase pageFunAuthView = new PageFunAuthViewBase();
+
             #region 页面操作权限验证
             pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(userId, pageId);
 
@@ -2061,7 +2062,6 @@ WHERE
             return Ok(await _goodsRep.GoodsStorageExcelDownload());
         }
 
-
         /// <summary>
         /// 物资进销存
         /// 领用 List
@@ -2098,6 +2098,26 @@ WHERE
             return Ok(await _goodsRep.GoodsReceiveList(dto));
         }
 
+        /// <summary>
+        /// 物资进销存
+        /// 领用 审核 List
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> GoodsReceiveAuditList(GoodsReceiveAuditListDTO dto)
+        {
+            //token验证
+            var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
+            if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
+
+            if (dto.PortType < 1 || dto.PortType > 3) return Ok(JsonView(false, MsgTips.Port));
+            if (dto.PageIndex < 1 || dto.PageSize < 1) return Ok(JsonView(false, MsgTips.PageIndex));
+
+            dto.CurrUserId = currUserInfo.UserId;
+            return Ok(await _goodsRep.GoodsReceiveAuditList(dto));
+        }
+
         /// <summary>
         /// 物资进销存
         /// 领用详情
@@ -2135,6 +2155,30 @@ WHERE
             }
 
             return Ok(await _goodsRep.GoodsReceiveOp(dto, currUserInfo.UserId));
+
+            //TODO:调试完成后 单个领用使用批量领用方法
+            //var receiveDetails = new GoodsReceiveDetailsView[] {
+            //    new () {
+            //        Id = 0,
+            //        GoodsReceiveId = dto.Id,
+            //        GoodsId = dto.GoodsId,
+            //        Quantity = dto.Quantity,
+            //        Remark = dto.Remark
+            //    }
+            //};
+
+            //var newDto = new GoodsReceiveBatchOpDto()
+            //{
+            //    Id = dto.Id,
+            //    GroupId = dto.GroupId,
+            //    ReceiveDetails = receiveDetails,
+            //    Reason = dto.Reason,
+            //    Remark = dto.Remark,
+            //    CurrUserId = currUserInfo.UserId,
+            //};
+
+            //return Ok(await _goodsRep.GoodsReceiveBatchOp(newDto));
+
         }
 
         /// <summary>
@@ -2272,6 +2316,184 @@ WHERE
             return Ok(view);
         }
 
+        /// <summary>
+        /// 物资进销存
+        /// 领用 OP 批量领用
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> GoodsReceiveBatchOp(GoodsReceiveBatchOpDto dto)
+        {
+            var currUserId = dto.CurrUserId;
+            var userInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.IsDel == 0 && x.Id == currUserId);
+            if (userInfo == null)
+            {
+                var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
+                if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
+                dto.CurrUserId = currUserInfo.UserId;
+            }
+
+            //参数验证
+            if (!dto.ReceiveDetails.Any()) Ok(JsonView(false,"请传入领用明细!"));
+
+            int index = 1;
+            foreach (var item in dto.ReceiveDetails)
+            {
+                //物品验证
+                if (item.GoodsId < 1) return Ok(JsonView(false, $"第{index}项物品无效!"));
+
+                //数量验证
+                if (item.Quantity <= 0.00M ) return Ok(JsonView(false, $"第{index}项物品的数量无效!"));
+                index++;
+            }
+
+            return Ok(await _goodsRep.GoodsReceiveBatchOp(dto));
+        }
+
+        /// <summary>
+        /// 物资进销存
+        /// 领用 审核 含批量领用
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> GoodsReceiveAuditNew(GoodsReceiveAuditDTO dto)
+        {
+            var currUserInfo = JwtHelper.SerializeJwt(HttpContext.Request.Headers.Authorization);
+            if (currUserInfo == null) return Ok(JsonView(false, "请传入token!"));
+
+            var validator = new GoodsReceiveAuditDTOValidator();
+            var validatorRes = await validator.ValidateAsync(dto);
+            if (!validatorRes.IsValid)
+            {
+                var sb = new StringBuilder();
+                foreach (var error in validatorRes.Errors) sb.AppendLine(error.ErrorMessage);
+                return Ok(JsonView(false, sb.ToString()));
+            }
+            int[] idArray = dto.Label
+                .Split(',')
+                .Select(x =>
+                {
+                    if (int.TryParse(x, out var id)) return id;
+                    return id;
+                })
+                .ToArray();
+
+            if (idArray.Length < 1) return Ok(JsonView(false, "请传入有效的领用ID"));
+            int receiveId = idArray[0];
+            var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveId);
+            if (receiveInfo == null) return Ok(JsonView(false,"请传入有效的领用ID"));
+
+            var view = new JsonView();
+
+            if (dto.AuditEnum == GoodsAuditEnum.Approved) //审核通过
+            {
+                view = await _goodsRep.GoodsReceiveApproveAsync(receiveId, currUserInfo.UserId);
+            }
+            else if (dto.AuditEnum == GoodsAuditEnum.UnApproved) //审核拒绝
+            {
+                view = await _goodsRep.GoodsReceiveRejectAsync(receiveId, currUserInfo.UserId);
+            }
+
+            if (view.Code != StatusCodes.Status200OK) return Ok(view);
+
+             
+            //TODO:出库成功 并且是团组相关物资 向团组其他款项添加信息
+            #region 出库成功并且是团组相关物资 向团组其他款项添加信息
+
+            var auditEnums = new List<GoodsAuditEnum>() { GoodsAuditEnum.OutConfirmed, GoodsAuditEnum.OutRejected };
+            if (!auditEnums.Contains(receiveInfo.AuditStatus)) return Ok(view);
+
+            var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveInfo.GroupId);
+            if (groupInfo == null) return Ok(view);
+
+            var basicData = await _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && x.STid == 91).ToListAsync();
+            var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == receiveInfo.GoodsId);
+            if (goodsInfo == null) return Ok(view);
+
+            var basicInfo = basicData.FirstOrDefault(x => x.Name.Equals(goodsInfo.Name));
+            if (basicInfo == null) return Ok(view);
+
+            string priceName = basicInfo.Name;
+
+            _ = decimal.TryParse(basicInfo.Remark, out decimal price);
+            decimal total = price * receiveInfo.Quantity;
+
+            var requestData = new DecreasePaymentsOpDto()
+            {
+                Status = 1,
+                DiId = groupInfo.Id,
+                PriceName = priceName,
+                Price = price,
+                Quantity = receiveInfo.Quantity,
+                FeeTotal = total,
+                Currency = 836,
+                FilePath = "",
+                OrbitalPrivateTransfer = 0,
+                OTAOrderNo = "-",
+                OtherBankName = "-",
+                OtherSideName = "-",
+                OtherSideNo = "-",
+                PayDId = 105,
+                SupplierAddress = "-",
+                SupplierArea = 1,
+                SupplierContact = "-",
+                SupplierContactNumber = "-",
+                SupplierEmail = "-",
+                SupplierName = "-",
+                SupplierSocialAccount = "-",
+                SupplierTypeId = 0,
+                CreateUserId = currUserInfo.UserId,
+                Remark = $"物资领用模块添加"
+            };
+
+            //其他费用
+
+            #region 调用方法
+            //JsonView groupData = await _otherPaymentRep.OpDecreasePayments(requestData);
+            //if (groupData.Code != 200)
+            //{
+            //    view.Msg += groupData.Msg;
+            //    return Ok(view);
+            //}
+
+            #region 应用推送
+
+            //int diId = requestData.DiId, status = requestData.Status;
+
+            //int otherId = Convert.ToInt32(groupData.Data.GetType().GetProperty("dataId").GetValue(groupData.Data, null) ?? 0);
+            //int ccpId = Convert.ToInt32(groupData.Data.GetType().GetProperty("ccpId").GetValue(groupData.Data, null) ?? 0);
+            //int sign = Convert.ToInt32(groupData.Data.GetType().GetProperty("sign").GetValue(groupData.Data, null) ?? 0);
+
+            ////自动审核
+            //var autoAdit = await _feeAuditRep.FeeAutomaticAudit(3, diId, otherId);
+
+            //await AppNoticeLibrary.SendChatMsg_GroupStatus_ApplyFee(ccpId, sign, QiyeWeChatEnum.GuoJiaoLeaderChat);
+
+            ////2024-10-21 新增LZ UID
+            //var userIds = new List<int>() { 208 };
+            ////var userIds = new List<int>() { 21 };
+            //string title = $"系统通知";
+            //string content = "";
+
+            //var ccpInfo = await _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.Id == ccpId).FirstAsync();
+            //if (status == 1) content = $"[新增-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{(ccpInfo.PayMoney * ccpInfo.DayRate).ToString("#0.00")} CNY;";
+            //else if (status == 2) content = $"[更新-其他款项({groupInfo?.TeamName ?? "-"})]一项费用:{(ccpInfo.PayMoney * ccpInfo.DayRate).ToString("#0.00")} CNY;";
+
+            //await GeneralMethod.MessageIssueAndNotification(MessageTypeEnum.GroupBusinessOperations, title, content, userIds, diId);
+
+            ////await APNsTools.iOS_PushNotifications1("051", $"其他款项费用审核", "", content);
+
+            #endregion
+            #endregion
+
+            #endregion
+
+            return Ok(view);
+        }
+
         /// <summary>
         /// 物资进销存
         /// 领用 Del

+ 2 - 2
OASystem/OASystem.Api/appsettings.json

@@ -450,8 +450,8 @@
   "KiMiSetting": {
     "Model": "moonshot-v1-8k",
     "BaseUrl": "https://api.moonshot.cn/v1",
-    //"Key": "sk-AY1Sv4rLnSUgGGHcC8SGSWYYKzGID7leZJcFfxAYozLC8dIc
-    "Key": "sk-b6jgRbgU4ZtIFLkgMSjtHeU67q8OHzPTqIVuKuNLG50zd5IY" //leiyi kimi key
+    "Key": "sk-AY1Sv4rLnSUgGGHcC8SGSWYYKzGID7leZJcFfxAYozLC8dIc"
+    //"Key": "sk-b6jgRbgU4ZtIFLkgMSjtHeU67q8OHzPTqIVuKuNLG50zd5IY" //leiyi kimi key
   },
   "OverspendAuditUser": [
     {

+ 27 - 6
OASystem/OASystem.Domain/Dtos/PersonnelModule/GoodsDTO.cs

@@ -235,6 +235,24 @@ namespace OASystem.Domain.Dtos.PersonnelModule
     #endregion
 
     #region 物品领用
+    /// <summary>
+    /// 物品领用List DTO
+    /// </summary>
+    public class GoodsReceiveAuditListDTO : DtoBase
+    {
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public int AuditStatus { get; set; }
+        /// <summary>
+        /// 物品Name
+        /// </summary>
+        public string GoodsName { get; set; }
+
+
+        public int CurrUserId { get; set; }
+    }
+
     /// <summary>
     /// 物品领用List DTO
     /// </summary>
@@ -397,18 +415,19 @@ namespace OASystem.Domain.Dtos.PersonnelModule
         /// Pm_GoodsInfo Id
         /// </summary>
         public int GoodsId { get; set; }
-        /// <summary>
-        /// 物资入库批次信息
-        /// {storageId:1,quantity:10}
-        /// </summary>
-        public string? GoodsStorageInfo { get; set; }
+        ///// <summary>
+        ///// 物资入库批次信息
+        ///// {storageId:1,quantity:10}
+        ///// </summary>
+        //public string? GoodsStorageInfo { get; set; }
         /// <summary>
         /// 领用数量
         /// </summary>
         public decimal Quantity { get; set; }
 
-    }
+        public string Remark { get; set; }
 
+    }
 
     /// <summary>
     /// 物品领用 Audit DTO
@@ -444,3 +463,5 @@ namespace OASystem.Domain.Dtos.PersonnelModule
     #endregion
 
 }
+
+

+ 6 - 0
OASystem/OASystem.Domain/Entities/PersonnelModule/Pm_GoodsReceive.cs

@@ -20,6 +20,12 @@ namespace OASystem.Domain.Entities.PersonnelModule
         [SugarColumn(ColumnDescription = "团组Id", IsNullable = true, ColumnDataType = "int")]
         public int GroupId { get; set; }
 
+        /// <summary>
+        /// 领用物品名称
+        /// </summary>
+        [SugarColumn(ColumnDescription = "领用物品名称", IsNullable = true, ColumnDataType = "varchar(300)")]
+        public string? GoodsName { get; set; }
+
         /// <summary>
         /// 物资入库批次信息
         /// {storageId:1,quantity:10}

+ 5 - 0
OASystem/OASystem.Domain/Entities/System/Sys_AuditRecord.cs

@@ -43,6 +43,11 @@ namespace OASystem.Domain.Entities.System
         [SugarColumn(ColumnDescription = "审核结果(0-待审核,1-通过,2-拒绝,3-无需处理)", IsNullable = true, ColumnDataType = "int")]
         public int AuditResult { get; set; }
         /// <summary>
+        /// 审核时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "审核时间", IsNullable = true, ColumnDataType = "datetime")]
+        public DateTime AuditTime { get; set; }
+        /// <summary>
         /// 审核意见
         /// </summary>
         [SugarColumn(ColumnDescription = "审核意见", IsNullable = true, ColumnDataType = "varchar(200)")]

+ 2 - 0
OASystem/OASystem.Domain/ViewModels/PersonnelModule/GoodsInfoView.cs

@@ -206,6 +206,8 @@ namespace OASystem.Domain.ViewModels.PersonnelModule
     {
 
         public int GoodsTypeId { get; set; }
+
+        public bool IsValuable { get; set; } = false;
     }
 
     /// <summary>

+ 40 - 23
OASystem/OASystem.Infrastructure/Repositories/Groups/FeeAuditRepository.cs

@@ -220,6 +220,7 @@ namespace OASystem.Infrastructure.Repositories.Groups
                 }
                 //获取C表汇率
                 decimal _opRate = 1.0000M;
+                decimal _opPayPercentage = 1.0000M;
                 var payInfo = _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.IsDel == 0 && x.DIId == diId && x.CTable == 79 && x.CId == dataId).First();
                 if (payInfo == null)
                 {
@@ -227,10 +228,11 @@ namespace OASystem.Infrastructure.Repositories.Groups
                     return _view;
                 }
                 _opRate = payInfo.DayRate;
+                _opPayPercentage = payInfo.PayPercentage / 100.00M;
 
                 string opCurrencyName = setData.Find(x => x.Id == opContents[0].Currency)?.Name ?? "";
 
-                //团组、OP币种 验证是否一致
+                //团组、OP币种 验证是否一致(一致:只比较金额,不计算汇率(2024-04-18))
                 if (opCurrencyName.Equals(_teamCurrency))
                 {
                     _opRate = payInfo.DayRate;
@@ -276,7 +278,6 @@ namespace OASystem.Infrastructure.Repositories.Groups
                     return _view;
                 }
 
-
                 //2.按天按项 检查费用是否超过预算 
                 var opDayContent = opContents.GroupBy(x => x.DatePrice);
 
@@ -288,56 +289,72 @@ namespace OASystem.Infrastructure.Repositories.Groups
 
                     //车费 91
                     var opCarCost = item.FirstOrDefault(x => x.SId == 91);
-                    if (opCarCost != null) if (opCarCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.CarFee)) isAutoAudit = false;
+                    if (opCarCost != null) 
+                        if (opCarCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.CarFee) * _opPayPercentage) isAutoAudit = false;
                     //982 车超时费 -- 暂无
                     //92  导游费
                     var opGuideCost = item.FirstOrDefault(x => x.SId == 92);
-                    if (opGuideCost != null) if (opGuideCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideFee)) isAutoAudit = false;
+                    if (opGuideCost != null) 
+                        if (opGuideCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideFee) * _opPayPercentage) isAutoAudit = false;
                     //94  导游景点费
                     var opGuideScenicCost = item.FirstOrDefault(x => x.SId == 94);
-                    if (opGuideScenicCost != null) if (opGuideScenicCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideScenicFee)) isAutoAudit = false;
+                    if (opGuideScenicCost != null) 
+                        if (opGuideScenicCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideScenicFee) * _opPayPercentage) isAutoAudit = false;
                     //95  导游小费
                     var opGuideTipCost = item.FirstOrDefault(x => x.SId == 95);
-                    if (opGuideTipCost != null) if (opGuideTipCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideTipFee)) isAutoAudit = false;
+                    if (opGuideTipCost != null) 
+                        if (opGuideTipCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideTipFee) * _opPayPercentage) isAutoAudit = false;
                     //983 导游餐补
                     var opGuideMealCost = item.FirstOrDefault(x => x.SId == 983);
-                    if (opGuideMealCost != null) if (opGuideMealCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideMealFee)) isAutoAudit = false;
+                    if (opGuideMealCost != null) 
+                        if (opGuideMealCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideMealFee) * _opPayPercentage) isAutoAudit = false;
                     //984 导游房补
                     var opGuideRoomCost = item.FirstOrDefault(x => x.SId == 984);
-                    if (opGuideRoomCost != null) if (opGuideRoomCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideRoomFee)) isAutoAudit = false;
+                    if (opGuideRoomCost != null) 
+                        if (opGuideRoomCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideRoomFee) * _opPayPercentage) isAutoAudit = false;
                     //985 导游交通
                     var opGuideTrafficCost = item.FirstOrDefault(x => x.SId == 985);
-                    if (opGuideTrafficCost != null) if (opGuideTrafficCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideTrafficFee)) isAutoAudit = false;
+                    if (opGuideTrafficCost != null) 
+                        if (opGuideTrafficCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.GuideTrafficFee) * _opPayPercentage) isAutoAudit = false;
                     //96  接送机费 -- 暂无
                     //97  其他费用 -- 暂无
                     //979 司机工资
                     var opDriverCost = item.FirstOrDefault(x => x.SId == 979);
-                    if (opDriverCost != null) if (opDriverCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverFee)) isAutoAudit = false;
+                    if (opDriverCost != null) 
+                        if (opDriverCost.Price * _opRate > _teamRate * _opPayPercentage * opCostInfo.Sum(x => x.DriverFee) * _opPayPercentage) isAutoAudit = false;
                     //980 司机小费
                     var opDriverTipCost = item.FirstOrDefault(x => x.SId == 980);
-                    if (opDriverTipCost != null) if (opDriverTipCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverTipFee)) isAutoAudit = false;
+                    if (opDriverTipCost != null) 
+                        if (opDriverTipCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.DriverTipFee) * _opPayPercentage) isAutoAudit = false;
                     //981 司机餐补
                     var opDriverMealCost = item.FirstOrDefault(x => x.SId == 981);
-                    if (opDriverMealCost != null) if (opDriverMealCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverMealFee)) isAutoAudit = false;
+                    if (opDriverMealCost != null) 
+                        if (opDriverMealCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.DriverMealFee) * _opPayPercentage) isAutoAudit = false;
                     //988 客户早餐费用
                     var opClientBreakfastCost = item.FirstOrDefault(x => x.SId == 988);
-                    if (opClientBreakfastCost != null) if (opClientBreakfastCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientBreakfastFee)) isAutoAudit = false;
+                    if (opClientBreakfastCost != null) 
+                        if (opClientBreakfastCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.ClientBreakfastFee) * _opPayPercentage) isAutoAudit = false;
                     //93  客户午餐费用
                     var opClientLunchCost = item.FirstOrDefault(x => x.SId == 93);
-                    if (opClientLunchCost != null) if (opClientLunchCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientLunchFee)) isAutoAudit = false;
+                    if (opClientLunchCost != null) 
+                        if (opClientLunchCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.ClientLunchFee) * _opPayPercentage) isAutoAudit = false;
                     //989 客户晚餐费用
                     var opClientDinnerCost = item.FirstOrDefault(x => x.SId == 989);
-                    if (opClientDinnerCost != null) if (opClientDinnerCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientDinnerFee)) isAutoAudit = false;
+                    if (opClientDinnerCost != null) 
+                        if (opClientDinnerCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.ClientDinnerFee) * _opPayPercentage) isAutoAudit = false;
                     //990 景点门票费
                     var opScenicTicketCost = item.FirstOrDefault(x => x.SId == 990);
-                    if (opScenicTicketCost != null) if (opScenicTicketCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ScenicTicketFee)) isAutoAudit = false;
+                    if (opScenicTicketCost != null) 
+                        if (opScenicTicketCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.ScenicTicketFee) * _opPayPercentage) isAutoAudit = false;
                     //991 饮料/零食/水果
                     var opDrinkSnackFruitCost = item.FirstOrDefault(x => x.SId == 991);
-                    if (opDrinkSnackFruitCost != null) if (opDrinkSnackFruitCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DrinkSnackFruitFee)) isAutoAudit = false;
+                    if (opDrinkSnackFruitCost != null) 
+                        if (opDrinkSnackFruitCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.DrinkSnackFruitFee) * _opPayPercentage) isAutoAudit = false;
                     //992 住补费用 -- 暂无
                     //994 翻译费
                     var opTranslatorCost = item.FirstOrDefault(x => x.SId == 994);
-                    if (opTranslatorCost != null) if (opTranslatorCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.TranslatorFee)) isAutoAudit = false;
+                    if (opTranslatorCost != null) 
+                        if (opTranslatorCost.Price * _opRate * _opPayPercentage > _teamRate * opCostInfo.Sum(x => x.TranslatorFee) * _opPayPercentage) isAutoAudit = false;
                     //1059    导游超时费用 -- 暂无
                     //1070    尾款金额 -- 暂无
                     //1071    其他额外费用 -- 暂无
@@ -351,11 +368,11 @@ namespace OASystem.Infrastructure.Repositories.Groups
                 if (isAutoAudit)
                 {
                     var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
-                                       .SetColumns(it => it.IsAuditGM == 3)
-                                       .SetColumns(it => it.AuditGMOperate == 4)
-                                       .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
-                                       .Where(s => s.DIId == diId && s.CTable == 79 && s.CId == dataId)
-                                       .ExecuteCommand();
+                        .SetColumns(it => it.IsAuditGM == 3)
+                        .SetColumns(it => it.AuditGMOperate == 4)
+                        .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
+                        .Where(s => s.DIId == diId && s.CTable == 79 && s.CId == dataId)
+                        .ExecuteCommand();
                     if (ccpUpdate > 0)
                     {
                         _view.Code = 200;

+ 673 - 15
OASystem/OASystem.Infrastructure/Repositories/PersonnelModule/GoodsRepository.cs

@@ -11,6 +11,7 @@ using OASystem.Domain.Entities.PersonnelModule;
 using OASystem.Domain.ViewModels.PersonnelModule;
 using OASystem.Infrastructure.Repositories.System;
 using OASystem.Infrastructure.Tools;
+using System.Linq;
 using System.Text.RegularExpressions;
 
 namespace OASystem.Infrastructure.Repositories.PersonnelModule
@@ -103,9 +104,9 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
             var receiveStatus = new List<dynamic>() {
                 new { Value = -1, Text = "全部" },
                 new { Value = GoodsAuditEnum.Pending, Text = GoodsAuditEnum.Pending.GetEnumDescription() },
-                new { Value = GoodsAuditEnum.Approved, Text = GoodsAuditEnum.Approved.GetEnumDescription() },
-                new { Value = GoodsAuditEnum.UnApproved, Text = GoodsAuditEnum.UnApproved.GetEnumDescription() },
-                new { Value = GoodsAuditEnum.OutPending, Text = GoodsAuditEnum.OutPending.GetEnumDescription() },
+                //new { Value = GoodsAuditEnum.Approved, Text = GoodsAuditEnum.Approved.GetEnumDescription() },
+                //new { Value = GoodsAuditEnum.UnApproved, Text = GoodsAuditEnum.UnApproved.GetEnumDescription() },
+                //new { Value = GoodsAuditEnum.OutPending, Text = GoodsAuditEnum.OutPending.GetEnumDescription() },
                 new { Value = GoodsAuditEnum.OutConfirming, Text = GoodsAuditEnum.OutConfirming.GetEnumDescription() },
                 new { Value = GoodsAuditEnum.OutConfirmed, Text = GoodsAuditEnum.OutConfirmed.GetEnumDescription() },
                 new { Value = GoodsAuditEnum.OutRejected, Text = GoodsAuditEnum.OutRejected.GetEnumDescription() },
@@ -1266,6 +1267,29 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 designer.Workbook = new Workbook(excelTempPath);
 
                 var tableData = await data.ToListAsync();
+                foreach (var item in tableData)
+                {
+                    if (string.IsNullOrEmpty(item.GoodsName))
+                    {
+                        var goodIds = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
+                            .Where(x => x.GoodsReceiveId == item.Id && x.IsDel == 0)
+                            .Select(x => x.GoodsId)
+                            .ToListAsync();
+
+                        if (goodIds.Any())
+                        {
+                            var goodsNames = await _sqlSugar.Queryable<Pm_GoodsInfo>()
+                                .Where(x => goodIds.Contains(x.Id) && x.IsDel == 0)
+                                .Select(x => x.Name)
+                                .ToListAsync();
+                            if (goodsNames.Any())
+                            {
+                                item.GoodsName = string.Join("、", goodsNames);
+                            }
+                        }
+                    }
+                }
+
                 designer.SetDataSource("Export", tableData);
 
                 designer.Process();
@@ -1294,6 +1318,28 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 if (isAudit) auditPers.Add(new() { AuditPer = hrAuditPer, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = $"出库确认" });
 
                 item.AuditPers = auditPers.ToArray();
+
+                //批量审核物品处理
+                if (string.IsNullOrEmpty(item.GoodsName))
+                {
+                    var goodIds = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
+                        .Where(x => x.GoodsReceiveId == item.Id && x.IsDel == 0)
+                        .Select(x => x.GoodsId)
+                        .ToListAsync();
+
+                    if (goodIds.Any())
+                    {
+                        var goodsNames = await _sqlSugar.Queryable<Pm_GoodsInfo>()
+                            .Where(x => goodIds.Contains(x.Id) && x.IsDel == 0)
+                            .Select(x => x.Name)
+                            .ToListAsync();
+                        if (goodsNames.Any())
+                        {
+                            item.GoodsName = string.Join("、", goodsNames);
+                        }
+                    }
+                }
+
             }
 
             if (dto.PortType == 2 || dto.PortType == 3)
@@ -2810,6 +2856,105 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
 
         #region New 物品领用、审核
 
+
+        /// <summary>
+        /// 物品领用审核列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public async Task<JsonView> GoodsReceiveAuditList(GoodsReceiveAuditListDTO dto)
+        {
+            var currUserId = dto.CurrUserId;
+            var auditStatus = dto.AuditStatus;
+
+            //财务人事审核权限处理
+            var auditList = GoodsStorageConfirmAuditDep(2);
+            bool hrAuditPer = false;
+            var hrAuditInfo = auditList.FirstOrDefault(x => x.AuditDep == GoodsAuditDepEnum.Hr);
+
+            if (hrAuditInfo.AuditorIds.Any(x => x == currUserId))
+            {
+                hrAuditPer = true;
+            }
+
+            var isValueable = false;
+            if (currUserId == 343) //陈湘OAId登录 只显示贵重物品审核信息
+            {
+                isValueable = true;
+            }
+
+
+            RefAsync<int> total = 0;
+            var data = _sqlSugar.Queryable<Pm_GoodsReceive>()
+                .LeftJoin<Pm_GoodsInfo>((gr, gi) => gr.GoodsId == gi.Id)
+                .LeftJoin<Sys_SetData>((gr, gi, sd) => gi.Type == sd.Id)
+                .LeftJoin<Sys_Users>((gr, gi, sd, u1) => gr.AuditUserId == u1.Id)
+                .LeftJoin<Sys_Users>((gr, gi, sd, u1, u2) => gr.CreateUserId == u2.Id)
+                .LeftJoin<Grp_DelegationInfo>((gr, gi, sd, u1, u2, di) => gr.GroupId == di.Id)
+                .Where((gr, gi, sd, u1, u2, di) => gr.IsDel == 0)
+                .WhereIF(!string.IsNullOrEmpty(dto.GoodsName), (gr, gi, sd, u1, u2, di) => gi.Name.Contains(dto.GoodsName))
+                .WhereIF(auditStatus > 0, (gr, gi, sd, u1, u2, di) => auditStatus == (int)gr.AuditStatus)
+                .Select((gr, gi, sd, u1, u2, di) => new GoodsReceiveListMobileView
+                {
+                    Id = gr.Id,
+                    GroupId = gr.GroupId,
+                    GroupName = di.TeamName,
+                    GoodsId = gr.GoodsId,
+                    GoodsName = gr.GoodsId == 0 ? gr.GoodsName : gi.Name,
+                    GoodsTypeId = gi.Type,
+                    GoodsType = sd.Name,
+                    IsValuable = gi.Type == 0 
+                    ? SqlFunc.Subqueryable<Sys_AuditFlow>().Where(x => x.BusinessId == gr.Id && x.BusinessType == 1).Select(x => x.TemplateId) == 3 
+                    : _goodsTypeIds.Contains(gi.Type),
+                    Quantity = gr.Quantity,
+                    Unit = gi.Unit,
+                    Reason = gr.Reason,
+                    Remark = gr.Remark,
+                    AuditStatus = gr.AuditStatus,
+                    StatusDesc = gr.StatusDesc,
+                    AuditUserId = gr.AuditUserId,
+                    AuditUserName = u1.CnName,
+                    AuditTime = gr.AuditTime,
+                    CreateUserName = u2.CnName,
+                    CreateTime = gr.CreateTime
+                })
+                //.WhereIF(isValueable, )
+                .OrderByDescending(gr => gr.CreateTime);
+
+            //返回分页数据
+            //领用审核List只显示多条审核数据 陈湘
+            var view = await data.ToPageListAsync(dto.PageIndex, dto.PageSize, total);
+
+            foreach (var item in view)
+            {
+                //默认审核验证 多条 or 单挑
+                var isAudit = GoodsAuditType(item.GoodsTypeId);
+                var auditPers = new List<GoodsStorageAuditPerView>()
+                {
+                    new (){ AuditPer  = true, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = $"领用确认"},
+                };
+                if (isAudit) auditPers.Add(new() { AuditPer = hrAuditPer, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = $"出库确认" });
+
+                item.AuditPers = auditPers.ToArray();
+
+            }
+
+            if (dto.PortType == 2 || dto.PortType == 3)
+            {
+                _jv.Data = view;
+            }
+            else if (dto.PortType == 1)
+            {
+                var view1 = _mapper.Map<List<GoodsReceiveListView>>(view);
+                _jv.Data = view1;
+            }
+
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Count = total;
+            _jv.Msg = $"操作成功";
+            return _jv;
+        }
+
         /// <summary>
         /// 物品领用 可批量 OP(Add Or Edit)
         /// </summary>
@@ -2826,6 +2971,7 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 Id = goodsReceiveId,
                 GroupId = dto.GroupId,
                 Reason = dto.Reason,
+                Remark = dto.Remark,
                 AuditStatus = GoodsAuditEnum.Pending,
                 CreateUserId = currUserId,
             };
@@ -2840,6 +2986,7 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
 
             //物品库存验证
             int goodsIndex = 1;
+            var goodsNames = new List<string>();
             foreach (var item in receiveDetails)
             {
                 item.CreateUserId = currUserId;
@@ -2852,14 +2999,15 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                     _sqlSugar.RollbackTran();
                     return _jv;
                 }
+                goodsNames.Add(goodsInfo.Name);
 
                 //物品库存验证
                 var stockQuantity = goodsInfo.StockQuantity;
-                var awaitAuditQuantity = await GoodsAwaitQuantity(goodsId);
+                var awaitAuditQuantity = await GoodsAwaitQuantityAsync(goodsId);
                 stockQuantity -= awaitAuditQuantity;
                 if (item.Quantity > stockQuantity)
                 {
-                    _jv.Msg = $"“{goodsInfo.Name}”物品库存不足!剩余库存:{stockQuantity} {goodsInfo.Unit}(待审数量:{awaitAuditQuantity});";
+                    _jv.Msg = $"“{goodsInfo.Name}”物品库存不足!剩余库存:{stockQuantity} {goodsInfo.Unit}(待审数量:{awaitAuditQuantity});";
                     _sqlSugar.RollbackTran();
                     return _jv;
                 }
@@ -2870,6 +3018,11 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 goodsIndex++;
             }
 
+            if (goodsNames.Any())
+            {
+                receiveInfo.GoodsName = string.Join("、", goodsNames);
+            }
+            
             //验证领用 添加OR编辑
             var goodsReceiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && x.Id == goodsReceiveId);
             if (goodsReceiveInfo == null) //添加
@@ -2942,6 +3095,8 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 }
             }
 
+
+            #region 审批流程验证、创建
             //审核验证 物品含有贵重物品 使用贵重物品审批流程
             var auditTempInfo = new ApprovalProcessView();
             if (isBatchVail)  //贵重物品审核模板
@@ -2970,7 +3125,7 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
             //创建审核流程
             var firstNode = auditTempInfo.TempNodes.OrderBy(x => x.NodeOrder).First();
 
-            var flow = await _approvalProcessRep.GetFlowByBusinessAsync(goodsReceiveId,1);
+            var flow = await _approvalProcessRep.GetFlowByBusinessAsync(goodsReceiveId, 1);
 
             int flowId;
             if (flow == null)
@@ -2994,9 +3149,16 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
             }
             else flowId = flow.Id;
 
+            #endregion
+
             //获取第一个节点的审核人员
             var nodeUsers = firstNode.NodeUsers;
 
+            //删除旧的审核记录
+            var delRecords = await _sqlSugar.Deleteable<Sys_AuditRecord>()
+                .Where(x => x.FlowId == flowId && x.NodeId == firstNode.Id && x.NodeName == firstNode.NodeName)
+                .ExecuteCommandHasChangeAsync();
+
             //创建审核记录
             var records = nodeUsers.Select(user => new Sys_AuditRecord
             {
@@ -3006,6 +3168,7 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 AuditorId = user.UserId,
                 AuditorName = user.UserName,
                 AuditResult = 0, // 审核中
+                AuditTime = DateTime.Now
             }).ToList();
 
             var recordStatus = await _sqlSugar.Insertable(records).ExecuteCommandAsync();
@@ -3015,41 +3178,327 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 _sqlSugar.RollbackTran();
                 return _jv;
             }
+
             _sqlSugar.CommitTran();
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Msg = $"操作成功!";
             return _jv;
         }
 
         /// <summary>
-        /// 物品领用 审核
+        /// 物品领用 审核 通过
         /// </summary>
-        /// <param name="dto"></param>
+        /// <param name="id"></param>
         /// <param name="currUserId"></param>
         /// <returns></returns>
-        public async Task<JsonView> GoodsReceiveAudit(GoodsReceiveAuditDto dto)
+        public async Task<JsonView> GoodsReceiveApproveAsync(int id,int currUserId)
         {
-            var appId = dto.Id;
-            var currUserId = dto.CurrUserId;
+            var appId = id;
 
             //验证审核流程
-            var flowInfo = await _approvalProcessRep.GetFlowByBusinessAsync(appId,1);
-            if (flowInfo == null)
+            var flow = await _approvalProcessRep.GetFlowByBusinessAsync(appId,1);
+            if (flow == null)
             {
                 _jv.Msg = $"审核流程不存在";
                 return _jv;
             }
+            if (flow.Status != 1)
+            {
+                _jv.Msg = $"当前流程不在审核中";
+                return _jv;
+            }
 
+            //获取当前节点
+            var currNode = (await _approvalProcessRep.GetTemplateNodesAsync(flow.TemplateId)).FirstOrDefault(x => x.Id == flow.CurrentNodeId);
+            if (currNode == null)
+            {
+                _jv.Msg = $"当前审核节点不存在";
+                return _jv;
+            }
 
+            //检查用户是否有权审核
+            var canAudit = (await _approvalProcessRep.GetTemplateNodeUsersAsync(currNode.Id))
+                .Any(x => x.UserId == currUserId);
+            if (!canAudit)
+            {
+                _jv.Msg = $"您无权审核此领用";
+                return _jv;
+            }
+
+            //检查是否已审核过
+            var existingRecord = await _sqlSugar.Queryable<Sys_AuditRecord>()
+                .Where(x => x.FlowId == flow.Id && x.NodeId == currNode.Id && x.AuditorId == currUserId)
+                .FirstAsync();
+            if (existingRecord != null && existingRecord.AuditResult == 1)
+            {
+                _jv.Msg = $"您已审核过此领用";
+                return _jv;
+            }
+
+            // 创建或更新审核记录
+            var currUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == currUserId)?.CnName ?? "-";
+
+            var record = existingRecord ?? new Sys_AuditRecord
+            {
+                FlowId = flow.Id,
+                NodeId = currNode.Id,
+                NodeName = currNode.NodeName,
+                AuditorId = currUserId,
+                AuditorName = currUserName,
+                AuditResult = 1, // 通过
+                AuditTime = DateTime.Now,
+                AuditOpinion = "",
+            };
+
+            _sqlSugar.BeginTran();
+
+            if (existingRecord == null) await _sqlSugar.Insertable(record).ExecuteCommandAsync();
+            else
+            {
+                record.AuditResult = 1; // 通过
+                record.AuditTime = DateTime.Now;
+                await _sqlSugar.Updateable(record).ExecuteCommandAsync();
+            }
+
+            //检查节点是否完成
+            var nodeRecords = await _sqlSugar.Queryable<Sys_AuditRecord>()
+                .Where(x => x.FlowId == flow.Id && x.NodeId == currNode.Id)
+                .ToListAsync();
+
+            bool isNodeComplete = false;
+
+            if (currNode.ApproveType == 2) // 或签模式
+            {
+                //或签逻辑:任意一人通过即通过
+                if (nodeRecords.Any(x => x.AuditResult == 1))
+                {
+                    isNodeComplete = true;
 
+                    // 标记其他未审核的记录为"无需处理"
+                    var unprocessed = nodeRecords
+                        .Where(x => x.AuditResult == 0 && x.AuditorId != currUserId)
+                        .ToList();
+
+                    foreach (var r in unprocessed)
+                    {
+                        r.AuditResult = 3; // 无需处理
+                        r.AuditTime = DateTime.Now;
+                        r.AuditOpinion = "其他审核人已处理";
+                    }
+
+                    if (unprocessed.Any())
+                    {
+                        await _sqlSugar.Updateable(unprocessed).ExecuteCommandAsync();
+                    }
+                }
+            }
+            else // 会签模式
+            {
+                // 会签逻辑:全部通过才通过
+                isNodeComplete = nodeRecords.All(x => x.AuditResult == 1);
+            }
+
+            if (isNodeComplete) 
+            {
+                // 查找下一个节点
+                var nextNode = (await _approvalProcessRep.GetTemplateNodesAsync(flow.TemplateId))
+                    .Where(x => x.NodeOrder > currNode.NodeOrder)
+                    .OrderBy(x => x.NodeOrder)
+                    .FirstOrDefault();
+
+                if (nextNode == null)
+                {
+                    // 所有节点完成,审核通过
+                    flow.Status = 2; // 已完成
+                    flow.CurrentNodeId = 0;
+
+                    // 更新业务状态为审核通过
+                    var auditStatus = await UpdateStatusAsync(appId, GoodsAuditEnum.OutConfirmed);
+                    if (!auditStatus)
+                    {
+                        _jv.Msg = $"审核失败!";
+                        _sqlSugar.RollbackTran();
+                        return _jv;
+                    }
+
+                    var deductStatus = await DeductStockAsync(appId);
+
+                    if (!deductStatus)
+                    {
+                        _jv.Msg = $"库存扣除失败失败!";
+                        _sqlSugar.RollbackTran();
+                        return _jv;
+                    }
+                }
+                else
+                {
+                    // 进入下一个节点
+                    flow.CurrentNodeId = nextNode.Id;
+
+                    // 为下一个节点创建审核记录
+                    var nextNodeUsers = await _approvalProcessRep.GetTemplateNodeUsersAsync(nextNode.Id);
+                    var records = nextNodeUsers.Select(user => new Sys_AuditRecord
+                    {
+                        FlowId = flow.Id,
+                        NodeId = nextNode.Id,
+                        NodeName = nextNode.NodeName,
+                        AuditorId = user.UserId,
+                        AuditorName = user.UserName,
+                        AuditResult = 0,
+                        AuditTime = DateTime.Now
+                    }).ToList();
+
+                    var recordStatus = await _sqlSugar.Insertable(records).ExecuteCommandAsync();
+                    if (recordStatus < 1)
+                    {
+                        _jv.Msg = $"下一节点审批记录创建失败!";
+                        _sqlSugar.RollbackTran();
+                        return _jv;
+                    }
+                }
+
+                var flowStatus = await _sqlSugar.Updateable(flow).ExecuteCommandAsync();
+                if (flowStatus < 1)
+                {
+                    _jv.Msg = $"审批流程更新失败!";
+                    _sqlSugar.RollbackTran();
+                    return _jv;
+                }
+
+            }
+            _sqlSugar.CommitTran();
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Msg = $"操作成功!";
             return _jv;
         }
 
+        /// <summary>
+        /// 物品领用 审核 拒绝
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="currUserId"></param>
+        /// <returns></returns>
+        public async Task<JsonView> GoodsReceiveRejectAsync(int id, int currUserId)
+        {
+            var appId = id;
+
+            //验证领用单
+            var receviveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.Id == appId);
+            if (receviveInfo == null)
+            {
+                _jv.Msg = $"当前领用信息不存在";
+                return _jv;
+            }
+
+            //验证审核流程
+            var flow = await _approvalProcessRep.GetFlowByBusinessAsync(appId, 1);
+            if (flow == null)
+            {
+                _jv.Msg = $"审核流程不存在";
+                return _jv;
+            }
+            //if (flow.Status != 1)
+            //{
+            //    _jv.Msg = $"当前流程不在审核中";
+            //    return _jv;
+            //}
+
+            //获取当前节点
+            var currNode = (await _approvalProcessRep.GetTemplateNodesAsync(flow.TemplateId)).FirstOrDefault(x => x.Id == flow.CurrentNodeId);
+            if (currNode == null)
+            {
+                _jv.Msg = $"当前审核节点不存在";
+                return _jv;
+            }
+
+            //检查用户是否有权审核
+            var canAudit = (await _approvalProcessRep.GetTemplateNodeUsersAsync(currNode.Id))
+                .Any(x => x.UserId == currUserId);
+            if (!canAudit)
+            {
+                _jv.Msg = $"您无权审核此申请";
+                return _jv;
+            }
+
+            //检查是否已审核过
+            var existingRecord = await _sqlSugar.Queryable<Sys_AuditRecord>()
+                .Where(x => x.FlowId == flow.Id && x.NodeId == currNode.Id && x.AuditorId == currUserId)
+                .FirstAsync();
+            if (existingRecord != null && existingRecord.AuditResult == 2)
+            {
+                _jv.Msg = $"您已审核过此申请";
+                return _jv;
+            }
+
+            //验证是否已经审核通过
+            bool isApproved = receviveInfo.AuditStatus == GoodsAuditEnum.OutConfirmed;
+            _sqlSugar.BeginTran();
+            if (isApproved) //审核通过拒绝
+            {
+                //回滚库存
+                var rollbackStatus = await RollbackStockAsync(appId);
+                if (!rollbackStatus)
+                {
+                    _jv.Msg = $"物品库存回滚失败!";
+                    _sqlSugar.RollbackTran();
+                    return _jv;
+                }
+            }
+
+            //更新流程状态为已拒绝
+            flow.Status = 3; // 已拒绝
+            flow.CurrentNodeId = currNode.Id;
+            var flowStatus = await _sqlSugar.Updateable(flow).ExecuteCommandAsync();
+            if (flowStatus < 1)
+            {
+                _jv.Msg = $"流程状态更新失败!";
+                _sqlSugar.RollbackTran();
+                return _jv;
+            }
+
+            // 更新领用状态为已拒绝
+            var receviveStatus = await UpdateStatusAsync(appId, GoodsAuditEnum.OutRejected); // 已拒绝
+            if (!receviveStatus)
+            {
+                _jv.Msg = $"领用物品状态更新失败!";
+                _sqlSugar.RollbackTran();
+                return _jv;
+            }
+
+            // 创建拒绝记录
+            var currUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == currUserId)?.CnName ?? "-";
+            var record = new Sys_AuditRecord
+            {
+                FlowId = flow.Id,
+                NodeId = flow.CurrentNodeId,
+                NodeName = $"{currNode.NodeName}-撤销",
+                AuditorId = currUserId,
+                AuditorName = currUserName,
+                AuditResult = 2, // 拒绝
+                AuditTime = DateTime.Now,
+                AuditOpinion = $"用户操作撤销",
+            };
+
+            var recordStatus = await _sqlSugar.Insertable(record).ExecuteCommandAsync();
+            if (recordStatus < 1)
+            {
+                _jv.Msg = $"领用物品拒绝记录创建失败!";
+                _sqlSugar.RollbackTran();
+                return _jv;
+            }
+
+            _sqlSugar.CommitTran();
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Msg = $"操作成功!";
+            return _jv;
+        }
 
         /// <summary>
         /// 物品待审核数量
         /// </summary>
         /// <param name="goodsId"></param>
         /// <returns></returns>
-        public async Task<decimal> GoodsAwaitQuantity(int goodsId)
+        public async Task<decimal> GoodsAwaitQuantityAsync(int goodsId)
         {
             decimal quantity = 0.00M;
             //单条领用 待审核、确认中 物品数量
@@ -3071,7 +3520,7 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                     gr.AuditStatus,
                     grd.Quantity
                 })
-                .SumAsync(x => x.Quantity);
+                .SumAsync(gr => gr.Quantity);
 
             quantity = waitAuditQuantity + waitAuditBatchQuantity;
 
@@ -3092,6 +3541,215 @@ namespace OASystem.Infrastructure.Repositories.PersonnelModule
                 .ExecuteCommandHasChangeAsync();
         }
 
+        /// <summary>
+        /// 领用状态完成扣除库存
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="status"></param>
+        /// <returns></returns>
+        public async Task<bool> DeductStockAsync(int id)
+        {
+            var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.Id == id);
+            if (receiveInfo == null) return false;
+
+            var receiveDetails = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
+                .Where(x => x.IsDel == 0 && x.GoodsReceiveId == id)
+                .ToListAsync();
+            if (!receiveDetails.Any()) return false;
+
+            var goodsInfos = new List<Pm_GoodsInfo>();
+            foreach (var item in receiveDetails)
+            {
+                var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == item.GoodsId);
+                if (goodsInfo == null) return false;
+
+                //1、物品库存扣除
+                var receiveQuantity = item.Quantity;
+                goodsInfo.StockQuantity -= receiveQuantity;
+                goodsInfo.OQ_Total += receiveQuantity;
+
+                //2、入库批次关联领用人 更改批次库存
+                var goodsStorages = await _sqlSugar
+                    .Queryable<Pm_GoodsStorage>()
+                    .Where(x => x.IsDel == 0 &&
+                                x.GoodsId == receiveInfo.GoodsId &&
+                                (x.Quantity - x.ReceiveQuantity) > 0
+                        )
+                    .OrderBy(x => x.CreateTime)
+                    .ToListAsync();
+
+                var goodsReceiveInfos = new List<GoodsReceiveLinkStorageView>();
+                var batchStorageInfos = new List<Pm_GoodsStorage>();
+                foreach (var storage in goodsStorages)
+                {
+                    if (receiveInfo.Quantity == receiveQuantity) break;
+
+                    var thisBatchSurplusQuantity = storage.Quantity - storage.ReceiveQuantity;
+                    if (thisBatchSurplusQuantity <= 0.00M) continue;
+
+                    var thisBatchReceiveQuantity = 0.00M; //此批次领用数量
+                    const decimal unit = 0.50M;
+                    while (receiveQuantity < receiveInfo.Quantity)
+                    {
+                        if (thisBatchSurplusQuantity == thisBatchReceiveQuantity) break;
+
+                        thisBatchReceiveQuantity += unit;
+                        receiveQuantity += unit;
+                    }
+                    goodsReceiveInfos.Add(new GoodsReceiveLinkStorageView
+                    {
+                        StorageId = storage.Id,
+                        Quantity = thisBatchReceiveQuantity
+                    });
+                    storage.ReceiveQuantity += thisBatchReceiveQuantity;
+
+                    batchStorageInfos.Add(storage);
+                }
+
+                //3 更改批次库存
+                if (goodsReceiveInfos.Count > 0)
+                {
+                    var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
+                        .UpdateColumns(x => x.ReceiveQuantity)
+                        .WhereColumns(x => x.Id)
+                        .ExecuteCommandAsync();
+                    if (edit1 < 1) return false;
+                }
+
+                //4 添加入库批次关联领用人
+                if (goodsReceiveInfos.Count > 0)
+                {
+                    item.GoodsStorageInfo = JsonConvert.SerializeObject(goodsReceiveInfos);
+                }
+
+                goodsInfos.Add(goodsInfo);
+            }
+
+            //库存更改
+            var editGoods = await _sqlSugar.Updateable(goodsInfos)
+                .UpdateColumns(x => new
+                {
+                    x.StockQuantity,
+                    x.OQ_Total,
+                })
+                .Where(x => x.Id == x.Id)
+                .ExecuteCommandAsync();
+            if (editGoods < 1) return false;
+
+            //领用明细更改
+            var editDetails = await _sqlSugar.Updateable(receiveDetails)
+                .UpdateColumns(x => new
+                {
+                    x.GoodsStorageInfo,
+                })
+                .Where(x => x.GoodsReceiveId == x.GoodsReceiveId)
+                .ExecuteCommandAsync();
+            if (editDetails < 1) return false;
+
+            return true;
+        }
+
+        /// <summary>
+        /// 领用状态拒绝回滚所有物资的库存
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="status"></param>
+        /// <returns></returns>
+        public async Task<bool> RollbackStockAsync(int id)
+        {
+            var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.Id == id);
+            if (receiveInfo == null) return false;
+
+            var receiveDetails = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
+                .Where(x => x.IsDel == 0 && x.GoodsReceiveId == id)
+                .ToListAsync();
+            if (!receiveDetails.Any()) return false;
+
+            var goodsInfos = new List<Pm_GoodsInfo>();
+            foreach (var item in receiveDetails)
+            {
+                var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == item.GoodsId);
+                if (goodsInfo == null) return false;
+
+                //1、物品表库存回滚
+                var receiveQuantity = item.Quantity;
+                goodsInfo.StockQuantity += receiveQuantity;
+                goodsInfo.OQ_Total -= receiveQuantity;
+
+                //2、入库批次关联领用人 更改批次库存 回滚
+                var goodsStorages = await _sqlSugar
+                    .Queryable<Pm_GoodsStorage>()
+                    .Where(x => x.IsDel == 0 &&
+                                x.GoodsId == receiveInfo.GoodsId &&
+                                (x.Quantity - x.ReceiveQuantity) > 0
+                        )
+                    .OrderBy(x => x.CreateTime)
+                    .ToListAsync();
+
+                var goodsReceiveInfos = new List<GoodsReceiveLinkStorageView>();
+                var batchStorageInfos = new List<Pm_GoodsStorage>();
+                foreach (var storage in goodsStorages)
+                {
+                    if (receiveInfo.Quantity == receiveQuantity) break;
+
+                    var thisBatchSurplusQuantity = storage.Quantity - storage.ReceiveQuantity;
+                    if (thisBatchSurplusQuantity <= 0.00M) continue;
+
+                    var thisBatchReceiveQuantity = 0.00M; //此批次领用数量
+                    const decimal unit = 0.50M;
+                    while (receiveQuantity < receiveInfo.Quantity)
+                    {
+                        if (thisBatchSurplusQuantity == thisBatchReceiveQuantity) break;
+
+                        thisBatchReceiveQuantity -= unit;
+                        receiveQuantity -= unit;
+                    }
+                    goodsReceiveInfos.Add(new GoodsReceiveLinkStorageView
+                    {
+                        StorageId = storage.Id,
+                        Quantity = thisBatchReceiveQuantity
+                    });
+                    storage.ReceiveQuantity -= thisBatchReceiveQuantity;
+
+                    batchStorageInfos.Add(storage);
+                }
+
+                //3 批次库存 回滚
+                if (goodsReceiveInfos.Count > 0)
+                {
+                    var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
+                        .UpdateColumns(x => x.ReceiveQuantity)
+                        .WhereColumns(x => x.Id)
+                        .ExecuteCommandAsync();
+                    if (edit1 < 1) return false;
+                }
+                item.GoodsStorageInfo = null;
+                goodsInfos.Add(goodsInfo);
+            }
+
+            //库存 回滚
+            var editGoods = await _sqlSugar.Updateable(goodsInfos)
+                .UpdateColumns(x => new
+                {
+                    x.StockQuantity,
+                    x.OQ_Total,
+                })
+                .Where(x => x.Id == x.Id)
+                .ExecuteCommandAsync();
+            if (editGoods < 1) return false;
+
+            //领用明细 回滚
+            var editDetails = await _sqlSugar.Updateable(receiveDetails)
+                .UpdateColumns(x => new
+                {
+                    x.GoodsStorageInfo,
+                })
+                .Where(x => x.GoodsReceiveId == x.GoodsReceiveId)
+                .ExecuteCommandAsync();
+            if (editDetails < 1) return false;
+
+            return true;
+        }
 
         #endregion
     }

+ 24 - 0
OASystem/OASystem.Infrastructure/Repositories/System/ApprovalProcessRepository.cs

@@ -131,6 +131,30 @@ namespace OASystem.Infrastructure.Repositories.System
             return await _sqlSugar.Queryable<Sys_AuditFlow>()
                 .FirstAsync(x => x.IsDel == 0 && x.BusinessId == businessId && x.BusinessType == businessType);
         }
+        
+        /// <summary>
+        /// 获取审核模板节点
+        /// </summary>
+        /// <param name="auditTempId"></param>
+        /// <returns></returns>
+        public async Task<List<Sys_AuditTemplateNode>> GetTemplateNodesAsync(int templateId)
+        {
+            return await _sqlSugar.Queryable<Sys_AuditTemplateNode>()
+                .Where(x => x.TemplateId == templateId)
+                .OrderBy(x => x.NodeOrder)
+                .ToListAsync();
+        }
 
+        /// <summary>
+        /// 获取审核模板节点用户
+        /// </summary>
+        /// <param name="nodeId"></param>
+        /// <returns></returns>
+        public async Task<List<Sys_AuditTemplateNodeUser>> GetTemplateNodeUsersAsync(int nodeId)
+        {
+            return await _sqlSugar.Queryable<Sys_AuditTemplateNodeUser>()
+                .Where(x => x.NodeId == nodeId)
+                .ToListAsync();
+        }
     }
 }