|
@@ -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
|
|
|
}
|