using Aspose.Cells;
using AutoMapper;
using EyeSoft.Collections.Generic;
using Newtonsoft.Json;
using OASystem.Domain;
using OASystem.Domain.Dtos.PersonnelModule;
using OASystem.Domain.Entities.Groups;
using OASystem.Domain.Entities.PersonnelModule;
using OASystem.Domain.ViewModels.PersonnelModule;
using OASystem.Infrastructure.Repositories.System;
using OASystem.Infrastructure.Tools;

namespace OASystem.Infrastructure.Repositories.PersonnelModule
{
    /// <summary>
    /// 物品进销存 
    /// 仓储
    /// </summary>
    public class GoodsRepository : BaseRepository<Pm_GoodsInfo, GoodsInfoView>
    {
        private readonly IMapper _mapper;
        private JsonView _jv;
        private string _url;
        private string _excelPath;
        private List<int> _goodsTypeIds; //多部门审核物品类型Id     
        private readonly ApprovalProcessRepository _approvalProcessRep;
        public GoodsRepository(SqlSugarClient sqlSugar, IMapper mapper, ApprovalProcessRepository approvalProcessRep) : base(sqlSugar)
        {
            _mapper = mapper;
            _jv = new JsonView() { Code = StatusCodes.Status400BadRequest, Msg = "操作失败!" };
            _url = AppSettingsHelper.Get("ExcelBaseUrl");
            _excelPath = $"{AppSettingsHelper.Get("ExcelBasePath")}";
            if (!Directory.Exists(_excelPath))
            {
                Directory.CreateDirectory(_excelPath);
            }
            _goodsTypeIds = new List<int>() {
                1423, //1423	贵重物品
            };
            _approvalProcessRep = approvalProcessRep;
        }

        /// <summary>
        /// 基础数据
        /// </summary>
        /// <returns></returns>
        public async Task<JsonView> InitDataSource()
        {
            var typeData = await _sqlSugar.Queryable<GoodsTypeView>()
                .Includes(x => x.SubTypeItems.Where(z => z.IsDel == 0)
                //.Select(z => new {
                //     z.Id,
                //     z.STid,
                //     z.Name
                //})
                .ToList())
                .Where(x => x.IsDel == 0 &&
                            x.Remark.Equals("GoodsType"))
                //.Select(x => new { 
                //        x.Id,
                //        x.Name,
                //        x.SubTypeItems
                //})
                .ToListAsync();

            var groupData = await _sqlSugar.Queryable<Grp_DelegationInfo>()
                .Where(x => x.IsDel == 0)
                .Select(x => new
                {
                    id = x.Id,
                    groupName = x.TeamName
                })
                .OrderByDescending(x => x.id)
                .ToListAsync();

            groupData.Insert(0, new { id = 0, groupName = "其他物资(公司内部物资)" });
            groupData.Insert(0, new { id = -1, groupName = "拜访客户所使用的物资" });
            groupData.Insert(0, new { id = -2, groupName = "库存调整" });
            groupData.Insert(0, new { id = -3, groupName = "全部团组" });

            var userData = await _sqlSugar.Queryable<Sys_Users>()
                .Where(x => x.IsDel == 0)
                .Select(x => new
                {
                    x.Id,
                    UserName = x.CnName,
                })
                .ToListAsync();

            //库存状态
            var stockStatus = new List<dynamic>() {
                new { Value = -1, Text = "全部" },
                new { Value = 0, Text = "待确认" },
                new { Value = 1, Text = "部分确认" },
                new { Value = 2, Text = "已确认" },
                new { Value = 3, Text = "已拒绝" },
            };

            //领用出库状态
            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.OutConfirming, Text = GoodsAuditEnum.OutConfirming.GetEnumDescription() },
                new { Value = GoodsAuditEnum.OutConfirmed, Text = GoodsAuditEnum.OutConfirmed.GetEnumDescription() },
                new { Value = GoodsAuditEnum.OutRejected, Text = GoodsAuditEnum.OutRejected.GetEnumDescription() },
            };

            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = new { goodsTypeData = typeData, stockStatus, receiveStatus, groupNameData = groupData, userNameData = userData };
            _jv.Msg = $"操作成功";
            return _jv;
        }

        /// <summary>
        /// 物品列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsList(GoodsListDto dto)
        {
            var ids = new List<int>();
            if (!string.IsNullOrEmpty(dto.TypeIds))
            {
                var strArray = dto.TypeIds.Split(',');
                foreach (var str in strArray)
                {
                    if (int.TryParse(str, out int id))
                    {
                        ids.Add(id);
                    }
                }
            }

            var auditEnums = new List<GoodsAuditEnum>() {
                GoodsAuditEnum.Pending,
                GoodsAuditEnum.OutPending,
                GoodsAuditEnum.OutConfirming
            };

            RefAsync<int> total = 0;

            var data = await _sqlSugar.Queryable<GoodsListView>()
                //.Includes(glv => glv.Receives.Where(z1 => z1.IsDel == 0 && z1.AuditStatus == GoodsAuditEnum.Pending).ToList())
                .Includes(glv => glv.Receives.Where(z1 => z1.IsDel == 0 && auditEnums.Contains(z1.AuditStatus)).ToList())
                .Includes(glv => glv.TypeData)
                .Includes(glv => glv.UserData)
                .LeftJoin<Sys_SetData>((glv, sd) => glv.Type == sd.Id)
                .LeftJoin<Sys_Users>((glv, sd, u) => glv.LastUpdateUserId == u.Id)
                .Where(glv => glv.IsDel == 0)
                .WhereIF(ids.Count > 0, glv => ids.Contains(glv.Type))
                .WhereIF(!string.IsNullOrEmpty(dto.GoodsName), glv => glv.Name.Contains(dto.GoodsName))
                .OrderByDescending(glv => glv.LastUpdateTime)
                .ToPageListAsync(dto.PageIndex, dto.PageSize, total);

            var view = data.Select(x => new
            {
                x.Id,
                x.Name,
                x.Type,
                TypeName = x.TypeData?.Name ?? string.Empty,
                LastUpdateUserName = x.UserData?.CnName ?? string.Empty,
                x.LastUpdateTime,
                StockQuantity = x.StockQuantity - x.WaitAuditQuantity,
                x.Unit,
                x.StockQuantityLabel,
                x.Remark
            }).ToList();

            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = view;
            _jv.Count = total;
            _jv.Msg = $"操作成功";
            return _jv;
        }

        /// <summary>
        /// 物品Info
        /// </summary>
        /// <param name="portType"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsInfo(int portType, int id)
        {
            var data = await _sqlSugar.Queryable<Pm_GoodsInfo>()
                .LeftJoin<Sys_SetData>((gi, sd) => gi.Type == sd.Id)
                .LeftJoin<Sys_Users>((gi, sd, u1) => gi.LastUpdateUserId == u1.Id)
                .LeftJoin<Sys_Users>((gi, sd, u1, u2) => gi.CreateUserId == u2.Id)
                .Where((gi, sd, u1, u2) => gi.IsDel == 0 && gi.Id == id)
                .Select((gi, sd, u1, u2) => new
                {
                    gi.Id,
                    gi.Name,
                    ParentType = sd.STid,
                    gi.Type,
                    TypeName = sd.Name,
                    gi.SQ_Total,
                    gi.OQ_Total,
                    gi.PriceTotal,
                    gi.StockQuantity,
                    gi.Unit,
                    gi.Remark,
                    LastUpdateUserName = u1.CnName,
                    gi.LastUpdateTime,
                    CreateUserName = u2.CnName,
                    gi.CreateTime,
                })
                .FirstAsync();

            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = data;
            _jv.Msg = $"操作成功";
            return _jv;
        }

        /// <summary>
        /// 物品 OP(Create Or Edit)
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsOp(GoodsOpDto dto, int currUserId)
        {
            var info = new Pm_GoodsInfo()
            {
                Id = dto.Id,
                Name = dto.Name,
                Type = dto.Type,
                SQ_Total = 0,
                OQ_Total = 0,
                PriceTotal = 0,
                StockQuantity = 0,
                Unit = dto.Unit,
                Remark = dto.Remark,
                LastUpdateUserId = currUserId,
                LastUpdateTime = DateTime.Now,
                CreateUserId = currUserId
            };

            if (dto.Id > 0) //Edit
            {
                var upd = await _sqlSugar.Updateable(info)
                    .UpdateColumns(x => new
                    {
                        x.Name,
                        x.Type,
                        x.Unit,
                        x.Remark,
                        x.LastUpdateUserId,
                        x.LastUpdateTime,
                    })
                    .ExecuteCommandAsync();
                if (upd > 0)
                {
                    _jv.Msg = $"修改成功!";
                    _jv.Code = StatusCodes.Status200OK;
                    return _jv;
                }
            }
            else if (dto.Id < 1) //添加
            {
                var selectInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Name.Equals(info.Name));
                if (selectInfo != null)
                {
                    _jv.Msg = $"“{info.Name}”该物品已存在,请勿重新添加!";
                    return _jv;
                }

                var add = await _sqlSugar.Insertable(info).ExecuteCommandAsync();
                if (add > 0)
                {
                    _jv.Msg = $"添加成功!";
                    _jv.Code = StatusCodes.Status200OK;
                    return _jv;
                }
            }
            return _jv;
        }

        /// <summary>
        /// 物品 Del
        /// </summary>
        /// <param name="id"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsDel(int id, int currUserId)
        {
            _sqlSugar.BeginTran();

            var goods = await _sqlSugar.Updateable<Pm_GoodsInfo>()
                .SetColumns(x => new Pm_GoodsInfo()
                {
                    IsDel = 1,
                    DeleteUserId = currUserId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                })
                .Where(x => x.Id == id)
                .ExecuteCommandAsync();
            if (goods < 1)
            {
                _sqlSugar.RollbackTran();
                _jv.Msg = $"操作失败";
                return _jv;
            }

            var goodsStorage = await _sqlSugar.Updateable<Pm_GoodsStorage>()
                .SetColumns(x => new Pm_GoodsStorage()
                {
                    IsDel = 1,
                    DeleteUserId = currUserId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                })
                .Where(x => x.Id == id)
                .ExecuteCommandAsync();

            var goodsReceive = await _sqlSugar.Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    IsDel = 1,
                    DeleteUserId = currUserId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                })
                .Where(x => x.Id == id)
                .ExecuteCommandAsync();
            _sqlSugar.CommitTran();
            _jv.Code = StatusCodes.Status200OK;
            _jv.Msg = $"操作成功!";
            return _jv;
        }

        /// <summary>
        /// 入库/出库 审核类型
        /// 根据物品类型 处理审核是否需要多部门审核
        /// </summary>
        /// <param name="goodsTypeId">物品类型Id </param>
        /// <returns></returns>
        public bool GoodsAuditType(int goodsTypeId)
        {
            if (_goodsTypeIds.Contains(goodsTypeId))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 物品入库列表(带审核)
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageList(GoodsStorageListDto dto)
        {
            string reqAuditLabel = dto.AuditLabel;
            var auditLabel = Array.Empty<int>();
            int userId = dto.CurrUserId;

            if (!string.IsNullOrEmpty(reqAuditLabel))
            {
                if (!reqAuditLabel.Contains("-1"))
                {
                    auditLabel = reqAuditLabel
                    .Split(',')
                    .Select(x =>
                    {
                        if (int.TryParse(x, out var id)) return id;
                        return id;
                    })
                    .ToArray();
                }
            }

            var auditList = GoodsStorageConfirmAuditDep(1);
            var hrAuditPer = false;
            var finAuditPer = false;
            var hrAuditInfo = auditList.FirstOrDefault(x => x.AuditDep == GoodsAuditDepEnum.Hr);
            var finAuditInfo = auditList.FirstOrDefault(x => x.AuditDep == GoodsAuditDepEnum.Financial);
            if (hrAuditInfo != null)
            {
                if (hrAuditInfo.AuditorIds.Any(x => x == userId)) hrAuditPer = true;
            }
            if (finAuditInfo != null)
            {
                if (finAuditInfo.AuditorIds.Any(x => x == userId)) finAuditPer = true;
            }


            RefAsync<int> total = 0;
            var data = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                .LeftJoin<Pm_GoodsInfo>((gs, gi) => gs.GoodsId == gi.Id)
                .LeftJoin<Sys_Users>((gs, gi, u) => gs.CreateUserId == u.Id)
                .LeftJoin<Sys_Users>((gs, gi, u, u1) => gs.StorageUserId == u1.Id)
                .Where((gs, gi, u, u1) => gs.IsDel == 0)
                .WhereIF(dto.GoodsId > 0, (gs, gi, u, u1) => gs.GoodsId == dto.GoodsId)
                .WhereIF(auditLabel.Length > 0, (gs, gi, u, u1) => auditLabel.Contains((int)gs.ConfirmStatus))
                .WhereIF(!string.IsNullOrEmpty(dto.GoodsName), (gs, gi, u, u1) => gi.Name.Contains(dto.GoodsName))
                .WhereIF(!string.IsNullOrEmpty(dto.BatchNo), (gs, gi, u, u1) => gs.BatchNo.Contains(dto.BatchNo))
                .WhereIF(finAuditPer, (gs, gi, u, u1) => _goodsTypeIds.Contains(gi.Type))
                .Select((gs, gi, u, u1) => new GoodsStorageListView()
                {
                    Id = gs.Id,
                    GoodsId = gs.GoodsId,
                    GoodsType = gi.Type,
                    BatchNo = gs.BatchNo,
                    GoodsName = gi.Name,
                    Quantity = gs.Quantity,
                    UnitPrice = gs.UnitPrice,
                    TotalPrice = gs.TotalPrice,
                    SupplierName = gs.SupplierName,
                    SupplierTel = gs.SupplierTel,
                    SupplierAddress = gs.SupplierAddress,
                    SupplierSource = gs.SupplierSource,
                    StorageUserName = u1.CnName,
                    StorageTime = gs.StorageTime,
                    CreateUserName = u.CnName,
                    ConfirmStatus = gs.ConfirmStatus,
                    StatusDesc = gs.StatusDesc,
                    CreateTime = gs.CreateTime,
                    Remark = gs.Remark
                })
                .OrderByDescending(gs => gs.CreateTime)
                .ToPageListAsync(dto.PageIndex, dto.PageSize, total);


            foreach (var item in data)
            {
                var auditDeps = new List<GoodsStorageAuditPerView>
                {
                    new() { AuditPer = hrAuditPer, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = GoodsAuditDepEnum.Hr.GetEnumDescription() }
                };
                var auditPer = GoodsAuditType(item.GoodsType);
                if (auditPer)
                {
                    auditDeps.Add(new() { AuditPer = finAuditPer, AuditDep = GoodsAuditDepEnum.Financial, ButtonText = GoodsAuditDepEnum.Financial.GetEnumDescription() });
                }

                item.AuditPers = auditDeps.ToArray();
            }

            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = data;
            _jv.Count = total;
            _jv.Msg = $"操作成功";
            return _jv;
        }

        /// <summary>
        /// 物品入库详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageInfo(int portType, int id)
        {
            var data = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                .LeftJoin<Pm_GoodsInfo>((gs, gi) => gs.GoodsId == gi.Id)
                .LeftJoin<Sys_Users>((gs, gi, u) => gs.CreateUserId == u.Id)
                .LeftJoin<Sys_Users>((gs, gi, u, u1) => gs.StorageUserId == u1.Id)
                .Where((gs, gi, u, u1) => gs.IsDel == 0)
                .WhereIF(id > 0, (gs, gi, u, u1) => gs.Id == id)
                .Select((gs, gi, u, u1) => new
                {
                    gs.Id,
                    gs.GoodsId,
                    GoodsName = gi.Name,
                    gs.Quantity,
                    gs.UnitPrice,
                    gs.TotalPrice,
                    gs.SupplierName,
                    gs.SupplierTel,
                    gs.SupplierAddress,
                    gs.SupplierSource,
                    gs.ReceiveQuantity,
                    gs.StorageUserId,
                    StorageUser = u1.CnName,
                    gs.StorageTime,
                    CreateUserName = u.CnName,
                    gs.CreateUserId,
                    gs.CreateTime,
                    gs.Remark,
                    //gs.IsInConfirm
                })
                .FirstAsync();

            _jv.Msg = $"操作成功!";
            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = data;
            return _jv;
        }

        /// <summary>
        /// 物品入库 操作(Create Or Edit)
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageOp(GoodsStorageOpDto dto, int currUserId)
        {
            var info = _mapper.Map<Pm_GoodsStorage>(dto);
            info.CreateUserId = currUserId;
            info.BatchNo = DateTime.Now.ToString("yyyyMMddHHmmssfff");

            _sqlSugar.BeginTran();
            if (info.Id > 0) //修改
            {
                var selectInfo = await _sqlSugar.Queryable<Pm_GoodsStorage>().FirstAsync(x => x.Id == dto.Id);
                var auditStatus = selectInfo.ConfirmStatus;
                if (auditStatus == GoodsConfirmEnum.Confirmed || auditStatus == GoodsConfirmEnum.PartConfirmed)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"该条入库信息已确认或部分确认审核,不可更改!如若更改请取消已确认或部分确认审核状态!";
                    return _jv;
                }

                var storageEdit = await _sqlSugar.Updateable(info)
                    .UpdateColumns(x => new
                    {
                        x.Quantity,
                        x.UnitPrice,
                        x.TotalPrice,
                        x.SupplierName,
                        x.SupplierTel,
                        x.SupplierAddress,
                        x.SupplierSource,
                        x.StorageUserId,
                        x.StorageTime
                    })
                    .Where(x => x.Id == dto.Id)
                    .ExecuteCommandAsync();
                if (storageEdit < 1)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"修改失败!";
                    return _jv;
                }

                //入库确认默认状态 多条 or 单条
                var auditInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>().Where(x => x.Type == 1 && x.DataId == dto.Id).ToListAsync();

                if (auditInfos.Any())
                {
                    var isAuditPer = false;
                    var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == dto.GoodsId);
                    if (goodsInfo != null)
                    {
                        isAuditPer = GoodsAuditType(goodsInfo.Type);
                    }

                    if (!isAuditPer && auditInfos.Count == 1)
                    {
                        var auditInfo = new Pm_GoodsAudit(1, GoodsAuditDepEnum.Financial, dto.Id, GoodsConfirmEnum.WaitConfirm, currUserId);
                        await _sqlSugar.Insertable(auditInfo).ExecuteCommandAsync();
                    }
                }
            }
            else if (info.Id < 1) //添加
            {
                info.ConfirmStatus = GoodsConfirmEnum.WaitConfirm;

                var storageAddId = await _sqlSugar.Insertable(info).ExecuteReturnIdentityAsync();
                if (storageAddId < 1)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"添加失败!";
                    return _jv;
                }

                //入库确认默认状态
                List<Pm_GoodsAudit> auditInfos = GoodsStorageConfirm(1, storageAddId, info.CreateUserId);
                if (auditInfos.Any())
                {
                    //验证添加多条或者单条审核状态
                    var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.IsDel == 0 && x.Id == dto.GoodsId);
                    if (goodsInfo != null)
                    {
                        var isAuditPer = GoodsAuditType(goodsInfo.Type);
                        if (!isAuditPer) auditInfos = auditInfos.Where(x => x.Dep == GoodsAuditDepEnum.Hr).ToList();
                    }

                    await _sqlSugar.Insertable(auditInfos).ExecuteCommandAsync();
                }
            }

            _sqlSugar.CommitTran();
            _jv.Msg = $"操作成功!";
            _jv.Code = StatusCodes.Status200OK;
            return _jv;
        }

        /// <summary>
        /// 物品入库 确认操作-默认审核部门
        /// </summary>
        /// <param name="auditType">
        /// 审核类型
        /// 1.入库 2.出库 
        /// </param>
        /// <param name="dataId">dataId</param>
        /// <param name="currUserId">审核人</param>
        /// <returns></returns>
        public List<Pm_GoodsAudit> GoodsStorageConfirm(int auditType, int dataId, int currUserId)
        {
            var goodsAuditList = new List<Pm_GoodsAudit>
            {
                new(auditType, GoodsAuditDepEnum.Hr, dataId, GoodsConfirmEnum.WaitConfirm, currUserId),
                new(auditType, GoodsAuditDepEnum.Financial, dataId, GoodsConfirmEnum.WaitConfirm, currUserId)
            };

            return goodsAuditList;
        }

        /// <summary>
        /// 物品入库 确认操作
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageConfirmStatusChange(GoodsStorageConfirmDto dto, int currUserId)
        {
            int gsId = dto.Id;
            var auditDep = dto.AuditDep;
            if (gsId < 1)
            {
                _jv.Msg = string.Format("{0}", MsgTips.Id);
                return _jv;
            }

            if (currUserId < 1)
            {
                _jv.Msg = string.Format("{0}", MsgTips.UserId);
                return _jv;
            }

            //验证审核部门
            (bool auditPer, GoodsAuditDepEnum goodsAuditDep) = GoodsAuditDep(currUserId, auditDep, 1);
            if (!auditPer)
            {
                _jv.Msg = string.Format("未分配入库确认权限!");
                return _jv;
            }

            //入库确认 更改审核状态
            _sqlSugar.BeginTran();

            var info = await _sqlSugar.Queryable<Pm_GoodsStorage>().Where(x => x.IsDel == 0 && x.Id == gsId).FirstAsync();
            if (info == null)
            {
                _jv.Msg = string.Format("入库信息不存在!");
                return _jv;
            }

            var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().Where(x => x.IsDel == 0 && x.Id == info.GoodsId).FirstAsync();
            if (goodsInfo == null)
            {
                _jv.Msg = string.Format("物品信息不存在!");
                return _jv;
            }
            int goodsTypeId = goodsInfo.Type;

            var preChangeStatus = info.ConfirmStatus;

            if (preChangeStatus == dto.ConfirmStatus)
            {
                _jv.Msg = string.Format("“{0}”已操作,请勿重复该操作!", dto.ConfirmStatus.GetEnumDescription());
                return _jv;
            }

            var preInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>().Where(x => x.IsDel == 0 && x.DataId == gsId).ToListAsync();

            //验证是否需要多级确认
            var isAuditPer = GoodsAuditType(goodsTypeId);

            //单部门审核时默认人事部审核
            if (!isAuditPer) goodsAuditDep = GoodsAuditDepEnum.Hr;

            var auditInfo = preInfos.FirstOrDefault(x => x.Dep == goodsAuditDep);
            if (auditInfo != null)
            {
                //移除部门审核状态
                preInfos.Remove(auditInfo);

                auditInfo.AuditStatus = dto.ConfirmStatus;
                auditInfo.AuditUserId = currUserId;
                auditInfo.AuditTime = DateTime.Now;

                var updStatus = await _sqlSugar.Updateable(auditInfo)
                    .UpdateColumns(x => new { x.AuditStatus, x.AuditUserId, x.AuditTime })
                    .ExecuteCommandAsync();

                if (updStatus < 1)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = string.Format("入库确认失败!");
                    return _jv;
                }

            }
            else
            {
                auditInfo = new Pm_GoodsAudit(1, goodsAuditDep, gsId, dto.ConfirmStatus, currUserId, currUserId);
                var addStatus = await _sqlSugar.Insertable(auditInfo).ExecuteCommandAsync();
                if (addStatus < 1)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = string.Format("入库确认失败!");
                    return _jv;
                }
            }

            preInfos.Add(auditInfo);

            //入库确认 更改入库状态及扣或增加除库存数、金额
            var confirmStatus = GoodsConfirmEnum.WaitConfirm;

            if (isAuditPer) //多级审核确认
            {
                if (preInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() >= 2)
                {
                    confirmStatus = GoodsConfirmEnum.Confirmed;
                }
                else if (preInfos.Count(x => x.AuditStatus == GoodsConfirmEnum.Confirmed) >= 1)
                {
                    confirmStatus = GoodsConfirmEnum.PartConfirmed;
                }
                else if (preInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.UnApproved).Count() > 0)
                {
                    confirmStatus = GoodsConfirmEnum.UnApproved;
                }
                else if (preInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.PartConfirmed).Count() > 0)
                {
                    confirmStatus = GoodsConfirmEnum.PartConfirmed;
                }
            }
            else //人事部审核确认
            {
                confirmStatus = GoodsConfirmEnum.Confirmed;
                confirmStatus = dto.ConfirmStatus;
                preInfos = preInfos.Where(x => x.Dep == GoodsAuditDepEnum.Hr).ToList();
            }

            //入库状态描述
            var statusDesc = new StringBuilder();
            foreach (var preInfo in preInfos)
            {
                string depName = preInfo.Dep.GetEnumDescription(),
                       auditStatus = preInfo.AuditStatus.GetEnumDescription(),
                       auditUserName = preInfo.AuditUserId > 0 ? _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == preInfo.AuditUserId)?.CnName ?? "-" : "-",
                       auditTime = preInfo.AuditUserId > 0 ? preInfo.AuditTime.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                statusDesc.Append(string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>", depName, auditStatus, auditUserName, auditTime));
            }

            //更改入库状态及描述
            info.ConfirmStatus = confirmStatus;
            info.StatusDesc = statusDesc.ToString();

            var goodsStorageUpd = await _sqlSugar.Updateable(info)
                .UpdateColumns(x => new
                {
                    x.ConfirmStatus,
                    x.StatusDesc,
                })
                .Where(x => x.Id == info.Id)
                .ExecuteCommandAsync();
            if (goodsStorageUpd < 1)
            {
                _sqlSugar.RollbackTran();
                _jv.Msg = $"入库确认状态更改失败!";
                return _jv;
            }

            //入库审核通过数量、金额
            decimal auditQuantity = info.Quantity,
                    auditTotalPrice = info.TotalPrice;

            goodsInfo.LastUpdateUserId = currUserId;
            goodsInfo.LastUpdateTime = DateTime.Now;
            if (confirmStatus == GoodsConfirmEnum.Confirmed) // 确认状态
            {
                //更改后的状态和更改前的状态不一致时 更改库存数、金额
                if (preChangeStatus != confirmStatus) //
                {
                    goodsInfo.SQ_Total += auditQuantity;
                    goodsInfo.StockQuantity += auditQuantity;
                    goodsInfo.PriceTotal += auditTotalPrice;
                }
            }
            else //其他状态 拒绝、部分确认、等待确认
            {
                //更改前状态为确认状态时,减库存数、金额
                if (preChangeStatus == GoodsConfirmEnum.Confirmed)
                {
                    goodsInfo.SQ_Total -= auditQuantity;
                    goodsInfo.StockQuantity -= auditQuantity;
                    goodsInfo.PriceTotal -= auditTotalPrice;
                }
            }

            var goodsUpd = await _sqlSugar.Updateable(goodsInfo)
                .UpdateColumns(x => new
                {
                    x.SQ_Total,
                    x.StockQuantity,
                    x.PriceTotal,
                    x.LastUpdateUserId,
                    x.LastUpdateTime,
                })
                .Where(x => x.Id == info.GoodsId)
                .ExecuteCommandAsync();
            if (goodsUpd > 0)
            {
                _sqlSugar.CommitTran();
                _jv.Msg = $"操作成功!";
                _jv.Code = StatusCodes.Status200OK;
                return _jv;
            }

            _sqlSugar.RollbackTran();
            _jv.Msg = $"操作失败!";
            return _jv;
        }

        /// <summary>
        /// 获取物品审核部门
        /// </summary>
        /// <param name="userId"> userId </param>
        /// <param name="auditDepEnum"> 审核部门枚举 </param>
        /// <param name="auditType">
        /// 指定审核类型(入库/出库)
        /// 1:入库审核
        /// 2:出库审核
        /// </param>
        /// <returns></returns>
        public static (bool, GoodsAuditDepEnum) GoodsAuditDep(int userId, GoodsAuditDepEnum auditDepEnum, int auditType = 1)
        {
            if (userId < 1) return (false, GoodsAuditDepEnum.Hr);

            var auditList = GoodsStorageConfirmAuditDep(1);

            if (auditType == 1)
            {
                if (auditList.Any(x => x.AuditDep == auditDepEnum && x.AuditorIds.Contains(userId)))
                {
                    return (true, auditDepEnum);
                }
            }

            return (false, GoodsAuditDepEnum.Hr);
        }

        /// <summary>
        /// 物品审核部门列表
        /// </summary>
        /// <param name="auditType">
        /// 指定审核类型(入库/出库)
        /// 1:入库审核
        /// 2:出库审核
        /// </param>
        /// <returns></returns>
        public static List<GoodsAuditDepView> GoodsStorageConfirmAuditDep(int auditType = 1)
        {
            var auditList = new List<GoodsAuditDepView>();

            var hrAuditorIds = new GoodsAuditDepView()
            {
                AuditDep = GoodsAuditDepEnum.Hr,
                AuditorIds = new int[] {
                    309,    // 赖红燕
                    343,    // 陈湘 
                    //374,    // 罗颖
                    208,    // 雷怡
                }
            };
            var finAuditorIds = new GoodsAuditDepView()
            {
                AuditDep = GoodsAuditDepEnum.Financial,
                AuditorIds = new int[] {
                    187,    // 曾艳 
                    281,    // 伏虹瑾
                    208,    // 雷怡
                }
            };

            if (auditType == 1)//入库
            {
                hrAuditorIds.AuditorIds = new int[] {
                    //343,    // 陈湘 
                    374,    // 罗颖
                    208,    // 雷怡
                };
                auditList.Add(hrAuditorIds);
                auditList.Add(finAuditorIds);

            }
            else if (auditType == 2) //出库
            {
                auditList.Add(hrAuditorIds);
                auditList.Add(finAuditorIds);
            }

            return auditList;
        }

        /// <summary>
        /// 物品入库 Del
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageDel(int id, int userId)
        {
            var storageInfo = await _sqlSugar
                .Queryable<Pm_GoodsStorage>()
                .Where(x => x.Id == id)
                .FirstAsync();
            if (storageInfo == null) return _jv;

            var auditStatus = storageInfo.ConfirmStatus;
            if (auditStatus == GoodsConfirmEnum.Confirmed || auditStatus == GoodsConfirmEnum.PartConfirmed)
            {
                _sqlSugar.RollbackTran();
                _jv.Msg = $"该条入库信息已确认或部分确认审核,不可删除!如若删除请取消已确认或部分确认审核状态!";
                return _jv;
            }

            decimal delAgoQuantity = storageInfo.Quantity,
                    delAgoTotalPrice = storageInfo.TotalPrice;
            var goodsId = storageInfo.GoodsId;

            _sqlSugar.BeginTran();

            var storageDel = await _sqlSugar.Updateable<Pm_GoodsStorage>()
                .SetColumns(x => new Pm_GoodsStorage
                {
                    DeleteUserId = userId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    IsDel = 1
                })
                .Where(x => x.Id == id)
                .ExecuteCommandAsync();
            if (storageDel < 1)
            {
                _sqlSugar.RollbackTran();
                _jv.Msg = $"操作失败!";
                return _jv;
            }

            var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == goodsId);
            goodsInfo.SQ_Total -= delAgoQuantity;
            goodsInfo.StockQuantity -= delAgoQuantity;
            goodsInfo.PriceTotal -= delAgoTotalPrice;
            goodsInfo.LastUpdateUserId = userId;
            goodsInfo.LastUpdateTime = DateTime.Now;

            var goodsEdit = await _sqlSugar.Updateable(goodsInfo)
                .UpdateColumns(x => new
                {
                    x.SQ_Total,
                    x.StockQuantity,
                    x.PriceTotal,
                    x.LastUpdateUserId,
                    x.LastUpdateTime,
                })
                .Where(x => x.Id == goodsId)
                .ExecuteCommandAsync();
            if (goodsEdit > 0)
            {
                _sqlSugar.CommitTran();
                _jv.Msg = $"操作成功!";
                _jv.Code = StatusCodes.Status200OK;
                return _jv;
            }

            _sqlSugar.RollbackTran();
            _jv.Msg = $"操作失败!";
            return _jv;
        }

        /// <summary>
        /// 物品入库
        /// excelDownload
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsStorageExcelDownload()
        {
            var fileName = $"物资入库{Guid.NewGuid()}.xlsx";

            var excelTempPath = $"{_excelPath}Template/物资入库Temp.xlsx";
            if (!File.Exists(excelTempPath))
            {
                _jv.Code = StatusCodes.Status204NoContent;
                _jv.Msg = $"该模板文件不存在!";
                return _jv;
            }

            _url = $"{_url}Office/Excel/GoodsFiles/";
            _excelPath = $"{_excelPath}GoodsFiles";
            if (!Directory.Exists(_excelPath))
            {
                Directory.CreateDirectory(_excelPath);
            }

            //入库记录
            var storageData = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                .LeftJoin<Sys_Users>((gs, su) => gs.StorageUserId == su.Id)
                .Where((gs, su) => gs.IsDel == 0)
                .Select((gs, su) => new
                {
                    gs.GoodsId,
                    gs.Quantity,
                    su.CnName,
                    gs.StorageTime
                })
                .ToListAsync();

            //出库记录
            var receiveData = await _sqlSugar.Queryable<Pm_GoodsReceive>()
                .LeftJoin<Sys_Users>((gr, su) => gr.CreateUserId == su.Id)
                .Where((gr, su) => gr.IsDel == 0)
                .Select((gr, su) => new
                {
                    gr.GoodsId,
                    gr.Quantity,
                    su.CnName,
                    gr.CreateTime,
                    gr.Reason
                })
                .ToListAsync();

            var data = await _sqlSugar.Queryable<Pm_GoodsInfo>()
                .Where(gi => gi.IsDel == 0)
                .Select(gi => new GoodsStorageExcelDownloadView
                {
                    Id = gi.Id,
                    Name = gi.Name,
                    SQ_Total = gi.SQ_Total,
                    OQ_Total = gi.OQ_Total,
                    StockQuantity = gi.StockQuantity,
                    Unit = gi.Unit
                })
                .ToListAsync();

            foreach (var item in data)
            {
                var storageData1 = storageData.Where(x => x.GoodsId == item.Id).ToList();
                if (storageData1.Any())
                {
                    item.SQ_Total1 = storageData1.Sum(x => x.Quantity);
                    item.SQ_Total -= item.SQ_Total1;
                    item.StorageLabel = string.Join("\r\n", storageData1.Select(x => "数量:【" + x.Quantity.ToString("#0.00") + "】  入库人:【" + x.CnName + "】  入库时间:【" + x.StorageTime + "】").ToList());
                }

                var receiveData1 = receiveData.Where(x => x.GoodsId == item.Id).ToList();
                if (receiveData1.Any())
                {
                    item.ReceiveLabel = string.Join("\r\n", receiveData1.Select(x => "数量:【" + x.Quantity.ToString("#0.00") + "】  申请人:【" + x.CnName + "】  申请时间:【" + x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss") + "】  原因:【" + x.Reason + "】").ToList());
                }

            }

            //载入模板
            WorkbookDesigner designer = new()
            {
                Workbook = new Workbook(excelTempPath)
            };

            designer.SetDataSource("Export", data);

            designer.Process();

            #region 渲染Cell批注
            var sheet = designer.Workbook.Worksheets[0];
            for (int i = 0; i < data.Count; i++)
            {
                string storageComment = $"C{i + 2}",
                       receiveComment = $"D{i + 2}",
                       storageCommentText = data[i].StorageLabel,
                       receiveCommentText = data[i].ReceiveLabel;
                if (!string.IsNullOrEmpty(storageCommentText))
                {
                    int storageIndex = sheet.Comments.Add(storageComment);
                    Aspose.Cells.Comment comment = sheet.Comments[storageIndex];
                    comment.Note = storageCommentText;
                    comment.Width = 500;
                    comment.Height = 200;
                    //comment.Font.Color = Color.Red;
                }
                if (!string.IsNullOrEmpty(receiveCommentText))
                {
                    int receiveIndex = sheet.Comments.Add(receiveComment);
                    Aspose.Cells.Comment comment = sheet.Comments[receiveIndex];
                    comment.Note = receiveCommentText;
                    comment.Width = 800;
                    comment.Height = 200;
                    //comment.Font.Color = Color.Red;
                }
            }

            #endregion


            string serverPath = $"{_url}{fileName}";
            designer.Workbook.Save($"{_excelPath}/{fileName}");

            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = new { url = serverPath };
            _jv.Msg = $"操作成功";
            return _jv;
        }

        /// <summary>
        /// 物品领用列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveList(GoodsReceiveListDTO dto)
        {
            //参数处理
            int[] typeLabel = Array.Empty<int>(),
                  userLabel = Array.Empty<int>(),
                  auditLabel = Array.Empty<int>(),
                  groupLabel = Array.Empty<int>();
            string[] userNameLabel = Array.Empty<string>();
            int currUserId = dto.CurrUserId;
            if (!string.IsNullOrEmpty(dto.TypeLabel))
            {
                typeLabel = dto.TypeLabel
                    .Split(',')
                    .Select(x =>
                    {
                        if (int.TryParse(x, out var id)) return id;
                        return id;
                    })
                    .ToArray();
            }
            if (!string.IsNullOrEmpty(dto.UserLabel))
            {
                userLabel = dto.UserLabel
                    .Split(',')
                    .Select(x =>
                    {
                        if (int.TryParse(x, out var id)) return id;
                        return id;
                    })
                    .ToArray();

                if (userLabel.Any())
                {
                    userNameLabel = await _sqlSugar.Queryable<Sys_Users>().Where(x => userLabel.Contains(x.Id)).Select(x => x.CnName).ToArrayAsync();
                }

            }
            if (!string.IsNullOrEmpty(dto.AuditLabel))
            {
                auditLabel = dto.AuditLabel
                    .Split(',')
                    .Select(x =>
                    {
                        if (int.TryParse(x, out var id)) return id;
                        return id;
                    })
                    .ToArray();

                if (auditLabel.Any(x => x == -1))
                {
                    auditLabel = auditLabel.Where(x => x != -1).ToArray();
                }

            }
            if (!string.IsNullOrEmpty(dto.GroupLabel))
            {
                groupLabel = dto.GroupLabel
                    .Split(',')
                    .Select(x =>
                    {
                        if (int.TryParse(x, out var id)) return id;
                        return id;
                    })
                    .ToArray();
            }

            //全部团组
            bool isAllGroups = false;
            if (groupLabel.Contains(-3)) isAllGroups = true;

            //物品ID和物品名称只能传一个
            if (dto.GoodsId > 0) dto.GoodsName = string.Empty;
            if (!string.IsNullOrEmpty(dto.GoodsName)) dto.GoodsId = 0;

            if (currUserId == 343) //陈湘OAId登录 只显示贵重物品审核信息
            {
                if (_goodsTypeIds.Any())
                {
                    var newArray = typeLabel.ToList();
                    newArray.AddRange(_goodsTypeIds);
                    typeLabel = newArray.ToArray();
                }
            }

            var beginBool = DateTime.TryParse(!string.IsNullOrEmpty(dto.BeginDt) ? $"{dto.BeginDt} 00:00:00" : string.Empty, out var begin);
            var endBool = DateTime.TryParse(!string.IsNullOrEmpty(dto.EndDt) ? $"{dto.EndDt} 00:00:00" : string.Empty, out var end);

            //新旧领用数据整合
            var oldDatas = _sqlSugar.Queryable<Pm_GoodsReceive>()
                .InnerJoin<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 && gr.GoodsId > 0)
                .Select((gr, gi, sd, u1, u2, di) => new GoodsReceiveListMobileView
                {
                    Id = gr.Id,
                    GroupId = gr.GroupId,
                    GroupName = di.TeamName,
                    GoodsId = gr.GoodsId,
                    GoodsName = gi.Name,
                    GoodsTypeId = gi.Type,
                    GoodsType = sd.Name,
                    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
                });

            var newDatas = _sqlSugar.Queryable<Pm_GoodsReceive>()
                .LeftJoin<Pm_GoodsReceiveDetails>((gr, grd) => gr.Id == grd.GoodsReceiveId)
                .LeftJoin<Pm_GoodsInfo>((gr, grd, gi) => grd.GoodsId == gi.Id)
                .LeftJoin<Sys_SetData>((gr, grd, gi, sd) => gi.Type == sd.Id)
                .LeftJoin<Sys_Users>((gr, grd, gi, sd, u1) => gr.AuditUserId == u1.Id)
                .LeftJoin<Sys_Users>((gr, grd, gi, sd, u1, u2) => gr.CreateUserId == u2.Id)
                .LeftJoin<Grp_DelegationInfo>((gr, grd, gi, sd, u1, u2, di) => gr.GroupId == di.Id)
                .Where((gr, grd, gi, sd, u1, u2, di) => gr.IsDel == 0 && grd.IsDel == 0 && gr.GoodsId < 1)
                .Select((gr, grd, gi, sd, u1, u2, di) => new GoodsReceiveListMobileView
                {
                    Id = gr.Id,
                    GroupId = gr.GroupId,
                    GroupName = di.TeamName,
                    GoodsId = grd.GoodsId,
                    GoodsName = gi.Name,
                    GoodsTypeId = gi.Type,
                    GoodsType = sd.Name,
                    Quantity = grd.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
                });

            var isIdSelect = false;
            var isNameSelect = false;
            if (dto.GoodsId > 0)
            {
                isIdSelect = true;
                dto.GoodsName = string.Empty;
            }
            if (!string.IsNullOrEmpty(dto.GoodsName))
            {
                isIdSelect = false;
                isNameSelect = true;
            }

            RefAsync<int> total = 0;
            var data = _sqlSugar.UnionAll(oldDatas, newDatas)
                .WhereIF(isIdSelect && !isNameSelect, x => x.GoodsId == dto.GoodsId)
                .WhereIF(!isIdSelect && isNameSelect, x => x.GoodsName.Contains(dto.GoodsName))
                .WhereIF(auditLabel.Length > 0, x => auditLabel.Contains((int)x.AuditStatus))
                .WhereIF(typeLabel.Length > 0, x => typeLabel.Contains(x.GoodsTypeId))
                .WhereIF(userNameLabel.Length > 0, x => userNameLabel.Contains(x.CreateUserName))
                .WhereIF(!isAllGroups && groupLabel.Length > 0, x => groupLabel.Contains(x.GroupId))
                .WhereIF(isAllGroups, x => x.GroupId > 0)
                .WhereIF(beginBool && endBool, x => x.CreateTime >= begin && x.CreateTime <= end)
                .OrderByDescending(x => x.CreateTime);

            //excel导出
            if (dto.IsExcelDownload)
            {
                var fileName = $"物资领用{Guid.NewGuid()}.xlsx";

                var excelTempPath = $"{_excelPath}Template/物资领用Temp.xlsx";
                if (!File.Exists(excelTempPath))
                {
                    _jv.Code = StatusCodes.Status204NoContent;
                    _jv.Msg = $"该模板文件不存在!";
                    return _jv;
                }

                _url = $"{_url}Office/Excel/GoodsFiles/";
                _excelPath = $"{_excelPath}GoodsFiles";
                if (!Directory.Exists(_excelPath))
                {
                    Directory.CreateDirectory(_excelPath);
                }

                //载入模板
                WorkbookDesigner designer = new()
                {
                    Workbook = new Workbook(excelTempPath)
                };

                var tableData = await data.ToListAsync();
                foreach (var item in tableData)
                {
                    var oldGroupName = item.GroupName;
                    item.GroupName = item.GroupId switch
                    {
                        0 => "其他物资(公司内部物资)",
                        -1 => "拜访客户所使用的物资",
                        -2 => "库存调整",
                        _ => oldGroupName
                    };

                    //审核相关处理
                    if (string.IsNullOrEmpty(item.AuditUserName))
                    {
                        var oldAuditDatas = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                           .LeftJoin<Sys_Users>((x, u) => x.AuditUserId == u.Id)
                           .Where((x, u) => x.IsDel == 0 && x.Type == 2 && x.DataId == item.Id)
                           .Select((x, u) => new
                           {
                               x.AuditTime,
                               u.CnName
                           })
                           .ToListAsync();
                        if (oldAuditDatas.Any())
                        {
                            item.AuditUserName = string.Join("、", oldAuditDatas.Select(x => x.CnName).ToArray());
                            if (!string.IsNullOrEmpty(item.AuditUserName))
                            {
                                item.AuditTime = oldAuditDatas.Last().AuditTime;
                            }
                            else item.AuditTime = DateTime.Now;
                        }
                        else
                        {
                            var newAuditDatas = await _sqlSugar.Queryable<Sys_AuditRecord>()
                                .InnerJoin<Sys_AuditFlow>((x, y) => x.FlowId == y.Id)
                               .Where((x, y) => x.IsDel == 0 && y.BusinessType == 1 && y.BusinessId == item.Id)
                               .Select((x, y) => new
                               {
                                   x.AuditTime,
                                   x.AuditorName
                               })
                               .ToListAsync();
                            if (newAuditDatas.Any())
                            {
                                item.AuditUserName = string.Join("、", newAuditDatas.Select(x => x.AuditorName).Distinct().ToArray());

                                if (!string.IsNullOrEmpty(item.AuditUserName))
                                {
                                    item.AuditTime = newAuditDatas.Last().AuditTime;
                                }
                                else item.AuditTime = DateTime.Now;
                            }
                        }
                    }
                }

                designer.SetDataSource("Export", tableData);

                designer.Process();

                string serverPath = $"{_url}{fileName}";
                designer.Workbook.Save($"{_excelPath}/{fileName}");

                _jv.Code = StatusCodes.Status200OK;
                _jv.Data = new { url = serverPath };
                _jv.Msg = $"操作成功";
                return _jv;
            }

            //返回分页数据
            var view = await data.ToPageListAsync(dto.PageIndex, dto.PageSize, total);

            foreach (var item in view)
            {
                //团组名称处理
                var oldGroupName = item.GroupName;
                item.GroupName = item.GroupId switch
                {
                    0 => "其他物资(公司内部物资)",
                    -1 => "拜访客户所使用的物资",
                    -2 => "库存调整",
                    _ => oldGroupName
                };
                //审核相关处理
                if (string.IsNullOrEmpty(item.AuditUserName))
                {
                    var oldAuditDatas = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                       .LeftJoin<Sys_Users>((x, u) => x.AuditUserId == u.Id)
                       .Where((x, u) => x.IsDel == 0 && x.Type == 2 && x.DataId == item.Id)
                       .Select((x, u) => new
                       {
                           x.AuditTime,
                           u.CnName
                       })
                       .ToListAsync();
                    if (oldAuditDatas.Any())
                    {
                        item.AuditUserName = string.Join("、", oldAuditDatas.Select(x => x.CnName).ToArray());
                        if (!string.IsNullOrEmpty(item.AuditUserName))
                        {
                            item.AuditTime = oldAuditDatas.Last().AuditTime;
                        }
                        else item.AuditTime = DateTime.Now;
                    }
                    else
                    {
                        var newAuditDatas = await _sqlSugar.Queryable<Sys_AuditRecord>()
                            .InnerJoin<Sys_AuditFlow>((x, y) => x.FlowId == y.Id)
                           .Where((x, y) => x.IsDel == 0 && y.BusinessType == 1 && y.BusinessId == item.Id)
                           .Select((x, y) => new
                           {
                               x.AuditTime,
                               x.AuditorName
                           })
                           .ToListAsync();
                        if (newAuditDatas.Any())
                        {
                            item.AuditUserName = string.Join("、", newAuditDatas.Select(x => x.AuditorName).Distinct().ToArray());

                            if (!string.IsNullOrEmpty(item.AuditUserName))
                            {
                                item.AuditTime = newAuditDatas.Last().AuditTime;
                            }
                            else item.AuditTime = DateTime.Now;
                        }
                    }
                }

                //权限前台验证
                var auditPers = new List<GoodsStorageAuditPerView>
                {
                    new() { AuditPer = true, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = GoodsAuditDepEnum.Hr_Reception.GetDescription() }
                };
                if (_goodsTypeIds.Contains(item.GoodsTypeId))
                {
                    auditPers.Add(new() { AuditPer = true, AuditDep = GoodsAuditDepEnum.Hr, ButtonText = GoodsAuditDepEnum.Hr.GetDescription() });
                }
                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>
        /// 物品领用详情
        /// </summary>
        /// <param name="portType"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveInfo(int portType, int id)
        {
            var data = await _sqlSugar.Queryable<Pm_GoodsReceive>()
                .LeftJoin<Pm_GoodsInfo>((gr, gi) => gr.GoodsId == gi.Id)
                .LeftJoin<Sys_Users>((gr, gi, u1) => gr.AuditUserId == u1.Id)
                .LeftJoin<Sys_Users>((gr, gi, u1, u2) => gr.CreateUserId == u2.Id)
                .LeftJoin<Grp_DelegationInfo>((gr, gi, u1, u2, di) => gr.GroupId == di.Id)
                .Where((gr, gi, u1, u2, di) => gr.IsDel == 0)
                .WhereIF(id > 0, (gr, gi, u1, u2, di) => gr.Id == id)
                .Select((gr, gi, u1, u2, di) => new GoodsReceiveInfoMobileView
                {
                    Id = gr.Id,
                    GroupId = gr.GroupId,
                    GroupName = di.TeamName,
                    GoodsId = gr.GoodsId,
                    GoodsName = gi.Name,
                    Quantity = gr.Quantity,
                    Reason = gr.Reason,
                    Remark = gr.Remark,
                    GoodsStorageInfo = gr.GoodsStorageInfo,
                    AuditStatus = gr.AuditStatus,
                    AuditUserId = gr.AuditUserId,
                    AuditUserName = u1.CnName,
                    AuditTime = gr.AuditTime,
                    CreateUserName = u2.CnName,
                    CreateTime = gr.CreateTime
                })
                .FirstAsync();

            if (!string.IsNullOrEmpty(data.GoodsStorageInfo))
            {
                var subData = new List<dynamic>();
                try
                {
                    var subData1 = JsonConvert.DeserializeObject<List<GoodsReceiveLinkStorageView>>(data.GoodsStorageInfo);
                    if (subData1.Count > 0)
                    {
                        string goodsStorageInfoStr = string.Empty;
                        var storageIds = subData1.Select(x => x.StorageId).ToList();
                        var storages = await _sqlSugar.Queryable<Pm_GoodsStorage>().Where(x => x.IsDel == 0 && storageIds.Contains(x.Id)).ToListAsync();
                        foreach (var item in subData1)
                        {
                            var storageInfo = storages.Find(x => x.Id == item.StorageId);
                            if (storageInfo != null)
                            {
                                subData.Add(new
                                {
                                    item.StorageId,
                                    storageInfo.BatchNo,
                                    RecsiveQuantity = item.Quantity
                                });
                                goodsStorageInfoStr += $"物品名称:{data.GoodsName} 批次号:{storageInfo.BatchNo} 领用数量:{item.Quantity} \r\n";
                            }
                        }
                        data.QuantityInfos = subData;
                        data.GoodsStorageInfoStr = goodsStorageInfoStr;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }

            _jv.Code = StatusCodes.Status200OK;
            _jv.Msg = $"操作成功";
            if (portType == 2 || portType == 3) //移动端
            {
                _jv.Data = data;
            }
            else if (portType == 1) //pc端
            {
                _jv.Data = _mapper.Map<GoodsReceiveInfoView>(data);
            }

            return _jv;
        }

        /// <summary>
        /// 物品领用 OP(Add Or Edit)
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveOp(GoodsReceiveOpDto dto, int currUserId)
        {
            var info = _mapper.Map<Pm_GoodsReceive>(dto);
            info.CreateUserId = currUserId;

            var auditEnums = new List<GoodsAuditEnum>() {
                    GoodsAuditEnum.Approved,    // 1
                    GoodsAuditEnum.UnApproved,  // 2
                    GoodsAuditEnum.OutConfirmed,// 5
                    GoodsAuditEnum.OutRejected  // 6
                };

            _sqlSugar.BeginTran();

            //物品现有库存
            var goodsInfo = _sqlSugar.Queryable<Pm_GoodsInfo>().First(x => x.Id == info.GoodsId);
            var stockQuantity = goodsInfo?.StockQuantity ?? 0.00M;

            //待审核 该物品数量
            var waitAuditQuantity = await _sqlSugar.Queryable<Pm_GoodsReceive>().Where(x => x.IsDel == 0 &&
                            x.GoodsId == dto.GoodsId &&
                            !auditEnums.Contains(x.AuditStatus)
                ).SumAsync(x => x.Quantity);

            //验证默认审核 多条 or 单条
            //出库确认默认审核状态
            var isAuditPer = GoodsAuditType(goodsInfo?.Type ?? 0);

            //验证默认审核 多条审核时添加
            var goodsAuditInfo1 = new Pm_GoodsAudit(2, GoodsAuditDepEnum.Hr_Reception, info.Id, GoodsConfirmEnum.WaitConfirm, currUserId);
            var goodsAuditInfo2 = new Pm_GoodsAudit(2, GoodsAuditDepEnum.Hr, info.Id, GoodsConfirmEnum.WaitConfirm, currUserId);
            var goodsAuditInfos = new List<Pm_GoodsAudit>() { goodsAuditInfo1 };

            //状态描述
            StringBuilder stringBuilder = new();
            stringBuilder.Append($"领用确认:状态:待确认  审核人:-  审核时间:-;<br/>");

            if (isAuditPer)
            {
                goodsAuditInfos.Add(goodsAuditInfo2);
                stringBuilder.Append($"人事部:状态:待确认  审核人:-  审核时间:-;<br/>");
            }

            info.StatusDesc = stringBuilder.ToString();

            if (info.Id > 0) //修改
            {
                //审核验证
                var selectInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.Id == info.Id);
                if (auditEnums.Contains(selectInfo.AuditStatus))
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"该条数据已执行操作({selectInfo.AuditStatus.GetEnumDescription()}),不可更改!";
                    return _jv;
                }

                //物品数量验证
                var editAfterQuantity = waitAuditQuantity - selectInfo.Quantity + info.Quantity;
                if (editAfterQuantity > stockQuantity)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"该物品现有库存不足,不可更改!请联系采购人员购买!";
                    return _jv;
                }

                var edit = await _sqlSugar.Updateable(info)
                    .UpdateColumns(x => new
                    {
                        x.GroupId,
                        x.Quantity,
                        x.Reason,
                        x.Remark,
                        x.StatusDesc,
                    })
                    .Where(x => x.Id == info.Id)
                    .ExecuteCommandAsync();
                if (edit > 0)
                {
                    var auditInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>().Where(x => x.DataId == info.Id).ToListAsync();
                    if (!auditInfos.Any()) await _sqlSugar.Insertable(goodsAuditInfos).ExecuteCommandAsync();

                    _sqlSugar.CommitTran();
                    _jv.Msg = $"操作成功!";
                    _jv.Code = StatusCodes.Status200OK;
                    return _jv;
                }
            }
            else if (info.Id < 1) //添加
            {
                //物品数量验证
                decimal addAgoQuantity = waitAuditQuantity + info.Quantity;
                if (addAgoQuantity > stockQuantity)
                {
                    _sqlSugar.RollbackTran();
                    _jv.Msg = $"该物品现有库存不足,不可更改!请联系采购人员购买!";
                    return _jv;
                }

                var add = await _sqlSugar.Insertable(info).ExecuteReturnIdentityAsync();
                if (add > 0)
                {
                    goodsAuditInfos.ForEach(x => x.DataId = add);
                    await _sqlSugar.Insertable(goodsAuditInfos).ExecuteCommandAsync();

                    _sqlSugar.CommitTran();
                    _jv.Msg = $"操作成功!";
                    _jv.Code = StatusCodes.Status200OK;
                    return _jv;
                }
            }
            _sqlSugar.RollbackTran();
            return _jv;
        }

        /// <summary>
        /// 物品领用 Audit
        /// </summary>
        /// <param name="idArray"></param>
        /// <param name="userId"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveAudit(int[] idArray, int userId, GoodsAuditEnum auditEnum)
        {
            if (idArray.Length < 1) return _jv;

            if (!Enum.IsDefined(typeof(GoodsAuditEnum), (int)auditEnum))
            {
                _jv.Msg = $"出库确认状态超出可用范围!";
                return _jv;
            }

            int receiveId = idArray[0];

            var currUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == userId)?.CnName ?? "-";

            _sqlSugar.BeginTran();
            var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>().FirstAsync(x => x.IsDel == 0 && receiveId == x.Id);

            if (receiveInfo == null)
            {
                _sqlSugar.RollbackTran();
                _jv.Msg = $"当前领用信息不存在!";
                return _jv;
            }

            var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == receiveInfo.GoodsId);

            int goodTypeId = goodsInfo?.Type ?? 0;

            //审核前状态
            var preChangeStatus = receiveInfo.AuditStatus;

            //状态验证
            //if (preChangeStatus == auditEnum)
            //{
            //    _sqlSugar.RollbackTran();
            //    _jv.Msg = $"该条数据状态已设置,不可重复设置!";
            //    return _jv;
            //}

            var isAuditPer = GoodsAuditType(goodTypeId);

            if (isAuditPer) //多人审核
            {
                var auditDep = GoodsAuditDepEnum.Hr_Reception;

                var auditInfo = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                    .FirstAsync(x => x.Type == 2 && x.DataId == receiveInfo.Id && x.Dep == GoodsAuditDepEnum.Hr_Reception);
                if (auditInfo != null && auditInfo.AuditStatus == GoodsConfirmEnum.Confirmed)
                {
                    auditDep = GoodsAuditDepEnum.Hr;

                    //多人审核的时候验证审核权限
                    var auditList = GoodsStorageConfirmAuditDep(2);
                    var auditDepInfo = auditList.Find(x => x.AuditorIds.Contains(userId));
                    if (auditDepInfo == null)
                    {
                        _jv.Msg = string.Format("未分配出库确认权限!");
                        _sqlSugar.RollbackTran();
                        return _jv;
                    }
                }

                // 确认中 确认 拒绝 
                _jv = await GoodsReceiveOutConfirmingMultiple(receiveInfo, userId, auditDep, auditEnum);

                //switch (auditEnum)
                //{
                //    case GoodsAuditEnum.Pending: //领用待确认(取消确认、取消拒绝)
                //        _jv = await GoodsReceivePending(preChangeStatus, receiveId, userId, currUserName, auditEnum);
                //        break;
                //    case GoodsAuditEnum.Approved: //领用确认
                //        _jv = await GoodsReceiveApproved(preChangeStatus, receiveId, userId, currUserName, auditEnum);
                //        break;
                //    case GoodsAuditEnum.UnApproved: //领用拒绝
                //        _jv = await GoodsReceiveUnApproved(preChangeStatus, receiveId, userId, currUserName, auditEnum);
                //        break;
                //    case GoodsAuditEnum.OutPending: //出库待确认(取消出库确认、取消出库拒绝)
                //        _jv = await GoodsReceiveOutPending(preChangeStatus, receiveInfo, userId, auditDep, auditEnum);
                //        break;
                //    case GoodsAuditEnum.OutConfirmed: //出库确认
                //        _jv = await GoodsReceiveOutConfirming(receiveInfo, userId, auditDep, auditEnum);
                //        break;
                //    case GoodsAuditEnum.OutRejected:  //出库拒绝
                //        _jv = await GoodsReceiveOutConfirming(receiveInfo, userId, auditDep, auditEnum);
                //        break;
                //}

            }
            else //单人审核 
            {
                //领用确认 --> 已确认 / 领用拒绝 --> 已拒绝
                _jv = await GoodsReceiveOutConfirmingSingle(receiveInfo, userId, currUserName, auditEnum);

            }

            if (_jv.Code == StatusCodes.Status200OK)
            {
                _sqlSugar.CommitTran();
                _jv.Msg = $"操作成功!";
                _jv.Data = auditEnum;
                return _jv;
            }

            _sqlSugar.RollbackTran();
            return _jv;
        }

        #region 多人审核状态变更

        /// <summary>
        /// 物品领用状态 - 领用待确认(取消确认、取消拒绝)
        /// </summary>
        /// <param name="preChangeStatus">更改前状态</param>
        /// <param name="receiveId"></param>
        /// <param name="userId"></param>
        /// <param name="userName"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceivePending(GoodsAuditEnum preChangeStatus, int receiveId, int userId, string userName, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;
            //领用待确认 操作范围
            var audirEnumPers = new List<GoodsAuditEnum>() {
                GoodsAuditEnum.Approved,
                GoodsAuditEnum.UnApproved
            };

            if (!audirEnumPers.Contains(preChangeStatus))
            {
                _jv.Msg = $"{GoodsAuditEnum.Approved.GetEnumDescription()}、{GoodsAuditEnum.UnApproved.GetEnumDescription()},状态下可取消操作!";
                return _jv;
            }

            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");
            var statusDesc = string.Format(@"领用确认:状态:{0}  审核人:{1}  审核时间:{2};<br/>人事部确认:状态:待确认  审核人:-  审核时间:-;<br/>财务部确认:状态:待确认  审核人:-  审核时间:-;", auditEnum.GetEnumDescription(), userName, currUserOpTime);
            auditEnum = GoodsAuditEnum.Pending;
            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    AuditUserId = userId,
                    AuditTime = currUserOpDt,
                    StatusDesc = statusDesc
                })
                .Where(x => x.Id == receiveId)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 物品领用状态 - 领用确认
        /// </summary>
        /// <param name="preChangeStatus">更改前状态</param>
        /// <param name="receiveId"></param>
        /// <param name="userId"></param>
        /// <param name="userName"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveApproved(GoodsAuditEnum preChangeStatus, int receiveId, int userId, string userName, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;
            if (preChangeStatus != GoodsAuditEnum.Pending)
            {
                _jv.Msg = $"{GoodsAuditEnum.Pending.GetEnumDescription()},状态下可取消操作!";
                return _jv;
            }

            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");
            var statusDesc = string.Format(@"领用确认:状态:{0}  审核人:{1}  审核时间:{2};<br/>人事部确认:状态:待确认  审核人:-  审核时间:-;<br/>财务部确认:状态:待确认  审核人:-  审核时间:-;", auditEnum.GetEnumDescription(), userName, currUserOpTime);
            auditEnum = GoodsAuditEnum.OutPending;
            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    AuditUserId = userId,
                    AuditTime = currUserOpDt,
                    StatusDesc = statusDesc
                })
                .Where(x => x.Id == receiveId)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 物品领用状态 - 领用拒绝
        /// </summary>
        /// <param name="preChangeStatus">更改前状态</param>
        /// <param name="receiveId"></param>
        /// <param name="userId"></param>
        /// <param name="userName"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveUnApproved(GoodsAuditEnum preChangeStatus, int receiveId, int userId, string userName, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;
            if (preChangeStatus != GoodsAuditEnum.Pending)
            {
                _jv.Msg = $"{GoodsAuditEnum.Pending.GetEnumDescription()},状态下可取消操作!";
                return _jv;
            }
            auditEnum = GoodsAuditEnum.UnApproved;
            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");
            var statusDesc = string.Format(@"领用确认:状态:{0}  审核人:{1}  审核时间:{2};<br/>人事部确认:状态:待确认  审核人:-  审核时间:-;<br/>财务部认:状态:待确认  审核人:-  审核时间:-;<br/>", auditEnum.GetEnumDescription(), userName, currUserOpTime);

            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    AuditUserId = userId,
                    AuditTime = currUserOpDt,
                    StatusDesc = statusDesc
                })
                .Where(x => x.Id == receiveId)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 物品领用状态 - 出库待确认(出库确认、出库拒绝)
        /// </summary>
        /// <param name="preChangeStatus">更改前状态</param>
        /// <param name="receiveId"></param>
        /// <param name="userId"></param>
        /// <param name="userName"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveOutPending(GoodsAuditEnum preChangeStatus, Pm_GoodsReceive receiveInfo, int userId, GoodsAuditDepEnum depEnum, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;
            //出库待确认 操作范围
            var audirEnumPers = new List<GoodsAuditEnum>() {
                GoodsAuditEnum.OutConfirmed,
                GoodsAuditEnum.OutRejected
            };

            if (!audirEnumPers.Contains(preChangeStatus))
            {
                _jv.Msg = $"{GoodsAuditEnum.OutConfirmed.GetEnumDescription()}、{GoodsAuditEnum.OutRejected.GetEnumDescription()},状态下可取消操作!";
                return _jv;
            }

            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");

            var auditInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                .Where(x => x.IsDel == 0 && x.DataId == receiveInfo.Id && x.Type == 2)
                .ToListAsync();

            auditEnum = GoodsAuditEnum.OutPending;

            var auditStatus = GoodsConfirmEnum.WaitConfirm;

            var auditInfo = auditInfos.Find(x => x.Dep == depEnum);
            if (auditInfo == null)
            {
                auditInfo = new Pm_GoodsAudit(2, depEnum, receiveInfo.Id, auditStatus, userId);
                var addStatus = await _sqlSugar.Insertable(auditInfo).ExecuteCommandAsync();
                if (addStatus < 1)
                {
                    _jv.Msg = $"出库确认取消操作失败!";
                    return _jv;
                }
                auditInfos.Add(auditInfo);
            }
            else
            {
                //移除旧数据
                auditInfos.Remove(auditInfo);
                auditInfo.AuditStatus = auditStatus;
                auditInfo.AuditUserId = userId;
                auditInfo.AuditTime = currUserOpDt;
                var updStatus = await _sqlSugar.Updateable<Pm_GoodsAudit>()
                    .SetColumns(x => new Pm_GoodsAudit()
                    {
                        AuditStatus = auditStatus,
                        AuditUserId = userId,
                        AuditTime = currUserOpDt
                    })
                    .Where(x => x.Id == auditInfo.Id)
                    .ExecuteCommandAsync();

                if (updStatus < 1)
                {
                    _jv.Msg = $"出库确认操作失败!";
                    return _jv;
                }

                //添加更新后的数据
                auditInfos.Add(auditInfo);
            }

            //处理状态描述
            StringBuilder statusDesc = new();

            var receiveUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == receiveInfo.AuditUserId)?.CnName ?? "-";
            string receiveStatusDesc = string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>",
                       "领用确认", GoodsAuditEnum.Approved.GetEnumDescription(), receiveUserName, receiveInfo.AuditTime.ToString("yyyy-MM-dd HH:mm:ss"));
            statusDesc.Append(receiveStatusDesc);
            foreach (var auditInf in auditInfos)
            {
                string userName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == auditInf.AuditUserId)?.CnName ?? "-";
                string userOpTime = !userName.Equals("-") ? auditInf.AuditTime.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                string auditInfStatusDesc = string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>",
                       auditInf.Dep.GetEnumDescription(), auditInf.AuditStatus.GetEnumDescription(), userName, currUserOpTime);
                statusDesc.Append(auditInfStatusDesc);
            }

            //批次库存信息
            string goodsStorageInfo = receiveInfo.GoodsStorageInfo;

            //出库确认取消是单独处理
            if (preChangeStatus == GoodsAuditEnum.OutConfirming)
            {
                if (auditInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() == 1)
                {
                    auditEnum = GoodsAuditEnum.OutConfirming;
                }
                //2.1 更改库存
                var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().Where(x => x.Id == receiveInfo.GoodsId).FirstAsync();
                goodsInfo.StockQuantity -= receiveInfo.Quantity;
                goodsInfo.OQ_Total += receiveInfo.Quantity;
                goodsInfo.LastUpdateTime = DateTime.Now;
                goodsInfo.LastUpdateUserId = userId;

                var editGoods = await _sqlSugar
                    .Updateable(goodsInfo)
                    .UpdateColumns(x => new
                    {
                        x.StockQuantity,
                        x.OQ_Total,
                        x.LastUpdateUserId,
                        x.LastUpdateTime,
                    })
                    .Where(x => x.Id == receiveInfo.GoodsId)
                    .ExecuteCommandAsync();

                if (editGoods < 1)
                {
                    _jv.Msg = $"库存更新失败!";
                    return _jv;
                }

                //2.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>();
                var receiveQuantity = 0.00M; //领用总数量
                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;
                    var storageUpd = storage;
                    //storageUpd.ReceiveQuantity += thisBatchReceiveQuantity;
                    batchStorageInfos.Add(storageUpd);
                }

                //2.2.1 更改批次库存
                if (goodsReceiveInfos.Count > 0)
                {
                    var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
                        .UpdateColumns(x => x.ReceiveQuantity)
                        .WhereColumns(x => x.Id)
                        .ExecuteCommandAsync();
                    if (edit1 < 1)
                    {
                        _jv.Msg = $"批次库存更新失败!";
                        return _jv;
                    }
                }

                //2.2.2 添加入库批次关联领用人
                if (goodsReceiveInfos.Count > 0)
                {
                    goodsStorageInfo = JsonConvert.SerializeObject(goodsReceiveInfos);
                }
            }

            var statusDesc1 = statusDesc.ToString();
            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    StatusDesc = statusDesc1,
                    GoodsStorageInfo = goodsStorageInfo
                })
                .Where(x => x.Id == receiveInfo.Id)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 物品领用状态 - 出库确认中、出库确认完成、出库确认拒绝
        /// </summary>
        /// <param name="receiveInfo"></param>
        /// <param name="userId"></param>
        /// <param name="depEnum"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveOutConfirming(Pm_GoodsReceive receiveInfo, int userId, GoodsAuditDepEnum depEnum, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;

            //更改前状态
            var preChangeStatus = receiveInfo.AuditStatus;

            if (preChangeStatus < GoodsAuditEnum.OutPending)
            {
                _jv.Msg = $"领用确认执行成功!才可执行出库确认或出库拒绝操作!";
                return _jv;
            }

            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");

            var auditInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                .Where(x => x.IsDel == 0 && x.DataId == receiveInfo.Id && x.Type == 2)
                .ToListAsync();

            var auditStatus = GoodsConfirmEnum.WaitConfirm;
            if (auditEnum == GoodsAuditEnum.OutRejected) auditStatus = GoodsConfirmEnum.UnApproved;
            else if (auditEnum == GoodsAuditEnum.OutConfirmed) auditStatus = GoodsConfirmEnum.Confirmed;

            var auditInfo = auditInfos.Find(x => x.Dep == depEnum);

            if (auditInfo == null)
            {
                auditInfo = new Pm_GoodsAudit(2, depEnum, receiveInfo.Id, auditStatus, userId);
                var addStatus = await _sqlSugar.Insertable(auditInfo).ExecuteCommandAsync();
                if (addStatus < 1)
                {
                    _jv.Msg = $"出库确认操作失败!";
                    return _jv;
                }
                auditInfos.Add(auditInfo);
            }
            else
            {
                //移除旧数据
                auditInfos.Remove(auditInfo);
                auditInfo.AuditStatus = auditStatus;
                auditInfo.AuditUserId = userId;
                auditInfo.AuditTime = currUserOpDt;
                var updStatus = await _sqlSugar.Updateable<Pm_GoodsAudit>()
                    .SetColumns(x => new Pm_GoodsAudit()
                    {
                        AuditStatus = auditStatus,
                        AuditUserId = userId,
                        AuditTime = currUserOpDt
                    })
                    .Where(x => x.Id == auditInfo.Id)
                    .ExecuteCommandAsync();

                if (updStatus < 1)
                {
                    _jv.Msg = $"出库确认操作失败!";
                    return _jv;
                }

                //添加更新后的数据
                auditInfos.Add(auditInfo);
            }

            //处理状态描述
            StringBuilder statusDesc = new();

            var receiveUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == receiveInfo.AuditUserId)?.CnName ?? "-";
            string receiveStatusDesc = string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>",
                       "领用确认", GoodsAuditEnum.Approved.GetEnumDescription(), receiveUserName, receiveInfo.AuditTime.ToString("yyyy-MM-dd HH:mm:ss"));
            statusDesc.Append(receiveStatusDesc);
            foreach (var auditInf in auditInfos)
            {
                string userName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == auditInf.AuditUserId)?.CnName ?? "-";
                string userOpTime = !userName.Equals("-") ? auditInf.AuditTime.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                string auditInfStatusDesc = string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>",
                       auditInf.Dep.GetEnumDescription(), auditInf.AuditStatus.GetEnumDescription(), userName, currUserOpTime);
                statusDesc.Append(auditInfStatusDesc);
            }

            if (preChangeStatus == auditEnum)
            {
                _jv.Msg = $"此操作已执行,不可重复操作!";
                return _jv;
            }

            //批次库存信息
            string goodsStorageInfo = receiveInfo.GoodsStorageInfo;

            //更改领用状态及库存
            if (auditInfos.Any(x => x.AuditStatus == GoodsConfirmEnum.UnApproved))
            {
                //出库确认拒绝
                auditEnum = GoodsAuditEnum.OutRejected;
            }
            else if (auditInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() == 2)
            {
                //1.出库确认完成
                auditEnum = GoodsAuditEnum.OutConfirmed;

                //2.更改前的状态为出库确认中 且 更改后的状态为出库确认完成 执行库存减操作
                if (preChangeStatus == GoodsAuditEnum.OutConfirming || preChangeStatus == GoodsAuditEnum.OutRejected)
                {
                    //2.1 更改库存
                    var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().Where(x => x.Id == receiveInfo.GoodsId).FirstAsync();
                    goodsInfo.StockQuantity -= receiveInfo.Quantity;
                    goodsInfo.OQ_Total += receiveInfo.Quantity;
                    goodsInfo.LastUpdateTime = DateTime.Now;
                    goodsInfo.LastUpdateUserId = userId;

                    var editGoods = await _sqlSugar
                        .Updateable(goodsInfo)
                        .UpdateColumns(x => new
                        {
                            x.StockQuantity,
                            x.OQ_Total,
                            x.LastUpdateUserId,
                            x.LastUpdateTime,
                        })
                        .Where(x => x.Id == receiveInfo.GoodsId)
                        .ExecuteCommandAsync();

                    if (editGoods < 1)
                    {
                        _jv.Msg = $"库存更新失败!";
                        return _jv;
                    }

                    //2.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>();
                    var receiveQuantity = 0.00M; //领用总数量
                    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;
                        var storageUpd = storage;
                        //storageUpd.ReceiveQuantity += thisBatchReceiveQuantity;
                        batchStorageInfos.Add(storageUpd);
                    }

                    //2.2.1 更改批次库存
                    if (goodsReceiveInfos.Count > 0)
                    {
                        var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
                            .UpdateColumns(x => x.ReceiveQuantity)
                            .WhereColumns(x => x.Id)
                            .ExecuteCommandAsync();
                        if (edit1 < 1)
                        {
                            _jv.Msg = $"批次库存更新失败!";
                            return _jv;
                        }
                    }

                    //2.2.2 添加入库批次关联领用人
                    if (goodsReceiveInfos.Count > 0)
                    {
                        goodsStorageInfo = JsonConvert.SerializeObject(goodsReceiveInfos);
                    }
                }

            }
            else if (auditInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() == 1)
            {
                //出库确认中
                auditEnum = GoodsAuditEnum.OutConfirming;

                if (preChangeStatus == GoodsAuditEnum.OutConfirmed)
                {
                    var goodsStorageInfo1 = receiveInfo.GoodsStorageInfo;
                    if (!string.IsNullOrEmpty(goodsStorageInfo))
                    {
                        var goodsStorageInfos = JsonConvert.DeserializeObject<List<GoodsReceiveLinkStorageView>>(goodsStorageInfo);
                        if (goodsStorageInfos.Any())
                        {
                            foreach (var item in goodsStorageInfos)
                            {
                                var newStorageInfo = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                                    .Where(x => x.IsDel == 0 && x.Id == item.StorageId)
                                    .FirstAsync();
                                if (newStorageInfo == null) continue;

                                var newEdit = await _sqlSugar.Updateable(newStorageInfo)
                                        .ReSetValue(x => x.ReceiveQuantity -= item.Quantity)
                                        .ExecuteCommandAsync();

                                if (newEdit < 1)
                                {
                                    _jv.Msg = $"批次领用库存更新失败!";
                                    return _jv;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                auditEnum = GoodsAuditEnum.OutPending;
            }

            var statusDesc1 = statusDesc.ToString();

            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    StatusDesc = statusDesc1,
                    GoodsStorageInfo = goodsStorageInfo,
                })
                .Where(x => x.Id == receiveInfo.Id)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="receiveInfo"></param>
        /// <param name="userId"></param>
        /// <param name="depEnum"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveOutConfirmingMultiple(Pm_GoodsReceive receiveInfo, int userId, GoodsAuditDepEnum depEnum, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;

            //更改前状态
            receiveInfo.CreateUserId = userId;
            var preChangeStatus = receiveInfo.AuditStatus;
            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");
            var receiveUserName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == receiveInfo.AuditUserId)?.CnName ?? "-";

            var auditInfos = await _sqlSugar.Queryable<Pm_GoodsAudit>()
                .Where(x => x.IsDel == 0 && x.DataId == receiveInfo.Id && x.Type == 2)
                .ToListAsync();

            var auditStatus = GoodsConfirmEnum.WaitConfirm;
            if (auditEnum == GoodsAuditEnum.UnApproved) auditStatus = GoodsConfirmEnum.UnApproved;
            else if (auditEnum == GoodsAuditEnum.Approved) auditStatus = GoodsConfirmEnum.Confirmed;

            var auditInfo = auditInfos.Find(x => x.Dep == depEnum);

            if (auditInfo == null)
            {
                auditInfo = new Pm_GoodsAudit(2, depEnum, receiveInfo.Id, auditStatus, userId)
                {
                    AuditUserId = userId
                };
                var addStatus = await _sqlSugar.Insertable(auditInfo).ExecuteCommandAsync();
                if (addStatus < 1)
                {
                    _jv.Msg = $"出库确认操作失败!";
                    return _jv;
                }
                auditInfos.Add(auditInfo);
            }
            else
            {
                //移除旧数据
                auditInfos.Remove(auditInfo);
                auditInfo.AuditStatus = auditStatus;
                auditInfo.AuditUserId = userId;
                auditInfo.AuditTime = currUserOpDt;
                var updStatus = await _sqlSugar.Updateable<Pm_GoodsAudit>()
                    .SetColumns(x => new Pm_GoodsAudit()
                    {
                        AuditStatus = auditStatus,
                        AuditUserId = userId,
                        AuditTime = currUserOpDt
                    })
                    .Where(x => x.Id == auditInfo.Id)
                    .ExecuteCommandAsync();

                if (updStatus < 1)
                {
                    _jv.Msg = $"出库确认操作失败!";
                    return _jv;
                }

                //添加更新后的数据
                auditInfos.Add(auditInfo);
            }
            auditInfos = auditInfos.OrderBy(x => x.Dep).ToList();
            //处理状态描述
            StringBuilder statusDesc = new();
            foreach (var auditInf in auditInfos)
            {
                string auditType = auditInf.Dep == GoodsAuditDepEnum.Hr ? "人事部" : "领用确认";
                string userName = _sqlSugar.Queryable<Sys_Users>().First(x => x.Id == auditInf.AuditUserId)?.CnName ?? "-";
                string userOpTime = !userName.Equals("-") ? auditInf.AuditTime.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                string auditInfStatusDesc = string.Format("{0}:状态:{1}  审核人:{2}  审核时间:{3};<br/>",
                       auditType, auditInf.AuditStatus.GetEnumDescription(), userName, currUserOpTime);
                statusDesc.Append(auditInfStatusDesc);
            }

            if (preChangeStatus == auditEnum)
            {
                _jv.Msg = $"此操作已执行,不可重复操作!";
                return _jv;
            }

            //批次库存信息
            string goodsStorageInfo = receiveInfo.GoodsStorageInfo;

            //更改领用状态及库存
            if (auditInfos.Any(x => x.AuditStatus == GoodsConfirmEnum.UnApproved))
            {
                //出库确认拒绝
                auditEnum = GoodsAuditEnum.OutRejected;

                if (preChangeStatus == GoodsAuditEnum.OutConfirmed)
                {
                    //回滚库存
                    _jv = await GoodsInventoryRollback(receiveInfo);
                    if (_jv.Code != StatusCodes.Status200OK) return _jv;
                }

            }
            else if (auditInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() == 2)
            {
                //1.出库确认完成
                auditEnum = GoodsAuditEnum.OutConfirmed;

                //2.更改前的状态为出库确认中 且 更改后的状态为出库确认完成 执行库存减操作
                if (preChangeStatus == GoodsAuditEnum.OutConfirming || preChangeStatus == GoodsAuditEnum.OutRejected)
                {
                    //2.1 更改库存
                    var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().Where(x => x.Id == receiveInfo.GoodsId).FirstAsync();
                    goodsInfo.StockQuantity -= receiveInfo.Quantity;
                    goodsInfo.OQ_Total += receiveInfo.Quantity;
                    goodsInfo.LastUpdateTime = DateTime.Now;
                    goodsInfo.LastUpdateUserId = userId;

                    var editGoods = await _sqlSugar
                        .Updateable(goodsInfo)
                        .UpdateColumns(x => new
                        {
                            x.StockQuantity,
                            x.OQ_Total,
                            x.LastUpdateUserId,
                            x.LastUpdateTime,
                        })
                        .Where(x => x.Id == receiveInfo.GoodsId)
                        .ExecuteCommandAsync();

                    if (editGoods < 1)
                    {
                        _jv.Msg = $"库存更新失败!";
                        return _jv;
                    }

                    //2.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>();
                    var receiveQuantity = 0.00M; //领用总数量
                    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;
                        var storageUpd = storage;
                        //storageUpd.ReceiveQuantity += thisBatchReceiveQuantity;
                        batchStorageInfos.Add(storageUpd);
                    }

                    //2.2.1 更改批次库存
                    if (goodsReceiveInfos.Count > 0)
                    {
                        var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
                            .UpdateColumns(x => x.ReceiveQuantity)
                            .WhereColumns(x => x.Id)
                            .ExecuteCommandAsync();
                        if (edit1 < 1)
                        {
                            _jv.Msg = $"批次库存更新失败!";
                            return _jv;
                        }
                    }

                    //2.2.2 添加入库批次关联领用人
                    if (goodsReceiveInfos.Count > 0)
                    {
                        goodsStorageInfo = JsonConvert.SerializeObject(goodsReceiveInfos);
                    }
                }

            }
            else if (auditInfos.Where(x => x.AuditStatus == GoodsConfirmEnum.Confirmed).Count() == 1)
            {
                //出库确认中
                auditEnum = GoodsAuditEnum.OutConfirming;

                if (preChangeStatus == GoodsAuditEnum.OutConfirmed)
                {
                    //回滚库存
                    _jv = await GoodsInventoryRollback(receiveInfo);
                    if (_jv.Code != StatusCodes.Status200OK) return _jv;
                }
            }
            else auditEnum = GoodsAuditEnum.OutPending;

            var statusDesc1 = statusDesc.ToString();

            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    StatusDesc = statusDesc1,
                    GoodsStorageInfo = goodsStorageInfo,
                })
                .Where(x => x.Id == receiveInfo.Id)
                .ExecuteCommandAsync();

            if (changeStatus > 0)
            {
                _jv.Code = StatusCodes.Status200OK;
            }

            return _jv;
        }

        /// <summary>
        /// 物品库存回滚
        /// </summary>
        /// <param name="receiveInfo"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsInventoryRollback(Pm_GoodsReceive receiveInfo)
        {
            var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == receiveInfo.GoodsId);

            //回滚库存
            var changeGoods = await _sqlSugar
                .Updateable(goodsInfo)
                .ReSetValue(it =>
                {
                    it.StockQuantity += receiveInfo.Quantity;
                    it.OQ_Total -= receiveInfo.Quantity;
                    it.LastUpdateTime = DateTime.Now;
                    it.LastUpdateUserId = receiveInfo.CreateUserId;
                })
                .ExecuteCommandAsync();

            if (changeGoods < 1)
            {
                _jv.Msg = $"库存回滚失败!";
                return _jv;
            }
            //批次领用记录
            _jv.Code = StatusCodes.Status200OK;
            var goodsStorageInfo = receiveInfo.GoodsStorageInfo;

            if (string.IsNullOrEmpty(goodsStorageInfo)) return _jv;

            var goodsStorageInfos = JsonConvert.DeserializeObject<List<GoodsReceiveLinkStorageView>>(goodsStorageInfo);

            if (!goodsStorageInfos.Any()) return _jv;

            foreach (var item in goodsStorageInfos)
            {
                var newStorageInfo = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                    .Where(x => x.IsDel == 0 && x.Id == item.StorageId)
                    .FirstAsync();
                if (newStorageInfo == null) continue;

                var newEdit = await _sqlSugar.Updateable(newStorageInfo)
                        .ReSetValue(x => x.ReceiveQuantity -= item.Quantity)
                        .ExecuteCommandAsync();

                if (newEdit < 1)
                {
                    _jv.Code = StatusCodes.Status400BadRequest;
                    _jv.Msg = $"批次领用库存更新失败!";
                    return _jv;
                }
            }

            _jv.Code = StatusCodes.Status200OK;
            return _jv;
        }

        #endregion

        #region 单人审核状态变更

        /// <summary>
        /// 物品领用状态 - 出库确认完成、出库确认拒绝
        /// </summary>
        /// <param name="receiveInfo"></param>
        /// <param name="userId"></param>
        /// <param name="currUserName"></param>
        /// <param name="auditEnum"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveOutConfirmingSingle(Pm_GoodsReceive receiveInfo, int userId, string currUserName, GoodsAuditEnum auditEnum)
        {
            _jv.Code = StatusCodes.Status400BadRequest;

            //状态操作范围验证
            var auditEnums = new List<GoodsAuditEnum>() {
                GoodsAuditEnum.Pending,
                GoodsAuditEnum.Approved,
                GoodsAuditEnum.UnApproved,
            };

            if (!auditEnums.Contains(auditEnum))
            {
                _jv.Msg = $"{GoodsAuditEnum.Pending.GetEnumDescription()}、{GoodsAuditEnum.OutConfirmed.GetEnumDescription()}、{GoodsAuditEnum.OutRejected.GetEnumDescription()},状态下可操作!";
                return _jv;
            }

            var currUserOpDt = DateTime.Now;
            var currUserOpTime = currUserOpDt.ToString("yyyy-MM-dd HH:mm:ss");

            //更改前状态
            var preChangeStatus = receiveInfo.AuditStatus;

            //前台状态验证
            var auditInfo = await _sqlSugar.Queryable<Pm_GoodsAudit>().FirstAsync(x => x.IsDel == 0 && x.Type == 2 && x.DataId == receiveInfo.Id);
            if (auditInfo == null)
            {
                var addInfo = new Pm_GoodsAudit(2, GoodsAuditDepEnum.Hr_Reception, receiveInfo.Id, GoodsConfirmEnum.WaitConfirm, userId);
                auditInfo = await _sqlSugar.Insertable(addInfo).ExecuteReturnEntityAsync();
                if (auditInfo == null)
                {
                    _jv.Msg = $"确认操作失败!";
                    return _jv;
                }
            }

            if (auditEnum == GoodsAuditEnum.Approved)
            {
                auditInfo.AuditStatus = GoodsConfirmEnum.Confirmed;
                auditEnum = GoodsAuditEnum.OutConfirmed;
            }
            else if (auditEnum == GoodsAuditEnum.UnApproved)
            {
                auditInfo.AuditStatus = GoodsConfirmEnum.UnApproved;
                auditEnum = GoodsAuditEnum.OutRejected;
            }

            if (preChangeStatus == auditEnum)
            {
                _jv.Msg = $"此操作已执行,不可重复操作!";
                return _jv;
            }

            //更新子表审核状态
            var updStatus = await _sqlSugar.Updateable<Pm_GoodsAudit>()
                    .SetColumns(x => new Pm_GoodsAudit()
                    {
                        AuditStatus = auditInfo.AuditStatus,
                        AuditUserId = userId,
                        AuditTime = currUserOpDt
                    })
                    .Where(x => x.Id == auditInfo.Id)
                    .ExecuteCommandAsync();

            if (updStatus < 1)
            {
                _jv.Msg = $"确认操作失败!";
                return _jv;
            }

            //处理状态描述
            StringBuilder statusDesc = new();
            statusDesc.Append(string.Format("领用确认:状态:{0}  审核人:{1}  审核时间:{2};", auditInfo.AuditStatus.GetEnumDescription(), currUserName, currUserOpTime));

            //批次库存信息
            string goodsStorageInfo = receiveInfo.GoodsStorageInfo;

            if (auditEnum == GoodsAuditEnum.OutConfirmed) //出库确认
            {
                //1 更改库存
                var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().Where(x => x.Id == receiveInfo.GoodsId).FirstAsync();
                goodsInfo.StockQuantity -= receiveInfo.Quantity;
                goodsInfo.OQ_Total += receiveInfo.Quantity;
                goodsInfo.LastUpdateTime = DateTime.Now;
                goodsInfo.LastUpdateUserId = userId;

                var editGoods = await _sqlSugar.Updateable(goodsInfo)
                    .UpdateColumns(x => new
                    {
                        x.StockQuantity,
                        x.OQ_Total,
                        x.LastUpdateUserId,
                        x.LastUpdateTime,
                    })
                    .Where(x => x.Id == receiveInfo.GoodsId)
                    .ExecuteCommandAsync();

                if (editGoods < 1)
                {
                    _jv.Msg = $"库存更新失败!";
                    return _jv;
                }

                //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>();
                var receiveQuantity = 0.00M; //领用总数量
                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;
                    var storageUpd = storage;
                    //storageUpd.ReceiveQuantity += thisBatchReceiveQuantity;
                    batchStorageInfos.Add(storageUpd);
                }

                //3 更改批次库存
                if (goodsReceiveInfos.Count > 0)
                {
                    var edit1 = await _sqlSugar.Updateable(batchStorageInfos)
                        .UpdateColumns(x => x.ReceiveQuantity)
                        .WhereColumns(x => x.Id)
                        .ExecuteCommandAsync();
                    if (edit1 < 1)
                    {
                        _jv.Msg = $"批次库存更新失败!";
                        return _jv;
                    }
                }

                //4 添加入库批次关联领用人
                if (goodsReceiveInfos.Count > 0)
                {
                    goodsStorageInfo = JsonConvert.SerializeObject(goodsReceiveInfos);
                }


            }
            else if (auditEnum == GoodsAuditEnum.OutRejected) //出库拒绝
            {
                //拒绝之前的状态为已完成 回滚库存
                if (preChangeStatus == GoodsAuditEnum.OutConfirmed)
                {
                    //回滚库存
                    var goodsInfo = await _sqlSugar.Queryable<Pm_GoodsInfo>().FirstAsync(x => x.Id == receiveInfo.GoodsId);

                    var changeGoods = await _sqlSugar
                        .Updateable(goodsInfo)
                        .ReSetValue(it =>
                        {
                            it.StockQuantity += receiveInfo.Quantity;
                            it.OQ_Total -= receiveInfo.Quantity;
                            it.LastUpdateTime = DateTime.Now;
                            it.LastUpdateUserId = userId;
                        })
                        .ExecuteCommandAsync();

                    if (changeGoods < 1)
                    {
                        _jv.Msg = $"库存回滚失败!";
                        return _jv;
                    }

                    //批次号库存 信息更新
                    var goodsStorageInfo1 = receiveInfo.GoodsStorageInfo;
                    if (!string.IsNullOrEmpty(goodsStorageInfo))
                    {
                        var goodsStorageInfos = JsonConvert.DeserializeObject<List<GoodsReceiveLinkStorageView>>(goodsStorageInfo);
                        if (goodsStorageInfos.Any())
                        {
                            foreach (var item in goodsStorageInfos)
                            {
                                var newStorageInfo = await _sqlSugar.Queryable<Pm_GoodsStorage>()
                                    .Where(x => x.IsDel == 0 && x.Id == item.StorageId)
                                    .FirstAsync();
                                if (newStorageInfo == null) continue;

                                var newEdit = await _sqlSugar.Updateable(newStorageInfo)
                                        .ReSetValue(x => x.ReceiveQuantity -= item.Quantity)
                                        .ExecuteCommandAsync();

                                if (newEdit < 1)
                                {
                                    _jv.Msg = $"批次领用库存更新失败!";
                                    return _jv;
                                }
                            }
                        }
                    }
                }
            }

            var statusDesc1 = statusDesc.ToString();

            var changeStatus = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    AuditStatus = auditEnum,
                    StatusDesc = statusDesc1,
                    GoodsStorageInfo = goodsStorageInfo,
                })
                .Where(x => x.Id == receiveInfo.Id)
                .ExecuteCommandAsync();

            if (changeStatus > 0) _jv.Code = StatusCodes.Status200OK;

            return _jv;
        }

        #endregion

        /// <summary>
        /// 物品领用 Del
        /// </summary>
        /// <param name="id"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveDel(int id, int currUserId)
        {
            _jv.Msg = $"操作失败";
            var receiveInfo = await _sqlSugar
                .Queryable<Pm_GoodsReceive>()
                .Where(x => x.IsDel == 0 && x.Id == id)
                .FirstAsync();
            if (receiveInfo.AuditStatus >= GoodsAuditEnum.Approved)
            {
                _jv.Msg = $"该条数据已进入审批流程,不可删除!";
                return _jv;
            }

            _sqlSugar.BeginTran();
            var edit = await _sqlSugar
                .Updateable<Pm_GoodsReceive>()
                .SetColumns(x => new Pm_GoodsReceive()
                {
                    IsDel = 1,
                    DeleteUserId = currUserId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                })
                .Where(x => x.Id == id)
                .ExecuteCommandAsync();
            if (edit < 1)
            {
                _sqlSugar.RollbackTran();
                return _jv;
            }
            var editSub = await _sqlSugar
                .Updateable<Pm_GoodsReceiveDetails>()
                .SetColumns(x => new Pm_GoodsReceiveDetails()
                {
                    IsDel = 1,
                    DeleteUserId = currUserId,
                    DeleteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                })
                .Where(x => x.GoodsReceiveId == id)
                .ExecuteCommandAsync();

            if (editSub > 0)
            {
                _sqlSugar.RollbackTran();
                return _jv;
            }

            _sqlSugar.CommitTran();
            _jv.Msg = $"操作成功!";
            _jv.Code = StatusCodes.Status200OK;
            return _jv;
        }


        #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 goodsName = dto.GoodsName;

            var sql = string.Format(@"SELECT
  ROW_NUMBER() OVER (ORDER BY CreateTime DESC) AS RowNumber,
  *
FROM
  (
    Select
      gr.Id,
      gr.GroupId,
      CASE
        WHEN gr.GroupId = 0 THEN '其他物资(公司内部物资)'
        WHEN gr.GroupId = -1 THEN '拜访客户所使用的物资'
        WHEN gr.GroupId = -2 THEN '库存调整'
        ELSE di.TeamName
      END [GroupName],
      gr.GoodsId,
      CASE
        WHEN gr.GoodsId = 0 THEN gr.GoodsName
        ELSE gi.Name
      END [GoodsName],
      gi.Type [GoodsTypeId],
      sd.Name [GoodsType],
      CASE
        WHEN gi.Type = 0
        OR gi.Type IS NULL THEN CASE
          WHEN af.TemplateId = 3 THEN 1
          ELSE 0
        END
        WHEN gi.Type = 1423 THEN 1
        ELSE 0
      END [IsValuable],
      gr.Quantity,
      gi.Unit,
      gr.Reason,
      gr.Remark,
      gr.AuditStatus,
      gr.StatusDesc,
      gr.AuditUserId,
      u1.CnName [AuditUserName],
      gr.AuditTime,
      u2.CnName [CreateUserName],
      gr.CreateTime
    FROM
      OA2023DB.dbo.Pm_GoodsReceive gr
      LEFT JOIN Pm_GoodsInfo gi ON gr.GoodsId = gi.Id
      LEFT JOIN Grp_DelegationInfo di ON gr.GroupId = di.Id
      LEFT JOIN Sys_Users u1 ON gr.AuditUserId = u1.Id
      LEFT JOIN Sys_Users u2 ON gr.CreateUserId = u2.Id
      LEFT JOIN Sys_AuditFlow af ON gr.Id = af.BusinessId
      LEFT JOIN Sys_SetData sd ON gi.Type = sd.Id
    WHERE
      gr.IsDel = 0
  ) Temp ");


            var checkValuableUserIds = new List<int>() {
                343 , //陈湘OAId
                309 , //赖红燕AId
            };

            var isValueable = false;
            if (checkValuableUserIds.Contains(currUserId)) //陈湘OAId登录 只显示贵重物品审核信息
            {
                isValueable = true;
            }
            RefAsync<int> total = 0;
            var view = await _sqlSugar.SqlQueryable<GoodsReceiveListMobileView>(sql)
                .WhereIF(isValueable, x => x.IsValuable == true)
                .WhereIF(!string.IsNullOrEmpty(goodsName), x => x.GoodsName.Contains(goodsName))
                .ToPageListAsync(dto.PageIndex, dto.PageSize, total);

            //普通物品领用审核模板
            var normAuditTemps = await _approvalProcessRep.GetTemplateByBusinessTypeAsync(2); //普通物品

            var normAuditUsers = new List<GoodsStorageAuditPerView>();
            normAuditTemps?.TempNodes.ForEach(x =>
            {
                var auditDep = GoodsAuditDepEnum.Hr_Reception;
                if (x.NodeName.Contains("人事部主管/经理审核")) auditDep = GoodsAuditDepEnum.Hr;
                else if (x.NodeName.Contains("前台审核")) auditDep = GoodsAuditDepEnum.Hr;
                x.NodeUsers.ForEach(y =>
                {
                    var userFlang = false;
                    if (y.UserId == currUserId) userFlang = true;
                    var info = new GoodsStorageAuditPerView() { ButtonText = x.NodeName, AuditDep = auditDep, AuditPer = userFlang };
                    normAuditUsers.Add(info);
                });
            });

            //贵重物品领用审核模板
            var valuableAuditTemps = await _approvalProcessRep.GetTemplateByBusinessTypeAsync(3); //贵重物品
            var valuableAuditUsers = new List<GoodsStorageAuditPerView>();
            valuableAuditTemps?.TempNodes.ForEach(x =>
            {
                var auditDep = GoodsAuditDepEnum.Hr_Reception;
                if (x.NodeName.Contains("人事部主管/经理审核")) auditDep = GoodsAuditDepEnum.Hr;
                else if (x.NodeName.Contains("前台审核")) auditDep = GoodsAuditDepEnum.Hr;
                x.NodeUsers.ForEach(y =>
                {
                    var userFlang = false;
                    if (y.UserId == currUserId) userFlang = true;
                    var info = new GoodsStorageAuditPerView() { ButtonText = x.NodeName, AuditDep = auditDep, AuditPer = userFlang };
                    valuableAuditUsers.Add(info);
                });
            });

            foreach (var item in view)
            {
                var details = $"暂无物品信息数据";

                //设置领用详情
                if (item.GoodsTypeId < 1)
                {
                    var detailsData = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
                    .LeftJoin<Pm_GoodsInfo>((grd, gi) => grd.GoodsId == gi.Id)
                    .LeftJoin<Sys_SetData>((grd, gi, sd) => gi.Type == sd.Id)
                    .Where((grd, gi, sd) => grd.IsDel == 0 && grd.GoodsReceiveId == item.Id)
                    .Select((grd, gi, sd) => new
                    {
                        gi.Name,
                        TypeName = sd.Name,
                        grd.Quantity,
                        grd.Remark
                    })
                    .ToListAsync();

                    if (detailsData.Any())
                    {
                        //设置领用数量 多个物品 计算领用合计
                        item.Quantity = detailsData.Sum(x => x.Quantity);

                        var text = new StringBuilder();
                        text.Append($"归属团组:{item.GroupName} <br/><br/>");
                        detailsData.ForEach(x =>
                        {
                            var str = $"物品名称:{x.Name}   物品类型:{x.TypeName}   领用数量:{x.Quantity}   备注:{x.Remark}<br/>";
                            text.Append(str);
                        });
                        details = text.ToString();
                    }
                }
                else details = $"归属团组/类型:{item.GroupName} <br/><br/>物品名称:{item.GoodsName}   物品类型:{item.GoodsType}   领用数量:{item.Quantity}   备注:{item.Remark}<br/>";

                item.GoodsDetails = details;

                //设置领用状态描述
                var auditRecords = await _sqlSugar.Queryable<Sys_AuditRecord>()
                    .InnerJoin<Sys_AuditFlow>((ar, af) => ar.FlowId == af.Id)
                    .Where((ar, af) => ar.IsDel == 0 && af.BusinessId == item.Id && af.BusinessType == 1)
                    .Select((ar, af) => new
                    {
                        ar.NodeId,
                        ar.NodeName,
                        ar.AuditResult,
                        ar.AuditorName,
                        ar.AuditTime
                    })
                    //.OrderBy((ar, af) => ar.AuditTime)
                    .ToListAsync();
                if (auditRecords.Any())
                {
                    var text = new StringBuilder();
                    auditRecords.ForEach(x =>
                    {
                        var statusText = x.AuditResult switch
                        {
                            0 => "待审核",
                            1 => "已审核",
                            2 => "已拒绝",
                            3 => "无需处理",
                            _ => "未知"
                        };

                        var auditTime = $"-";
                        if (x.AuditResult == 1 || x.AuditResult == 2 || x.AuditResult == 3) auditTime = x.AuditTime.ToString("yyyy-MM-dd HH:mm:ss");

                        var str = $"{x.NodeName}:状态:{statusText}  审核人:{x.AuditorName}  审核时间:{auditTime}<br/>";
                        text.Append(str);
                    });
                    item.StatusDesc = text.ToString();
                }


                //多情况下审核、操作权限验证
                if (item.GoodsTypeId == 0)
                {
                    int tempId = 2;
                    if (item.IsValuable) tempId = 3;

                    item.IsAuditPer = await _approvalProcessRep.VerifyAuditAuthAsync(tempId, 1, item.Id, currUserId);
                }
                else
                {
                    if (item.AuditStatus == GoodsAuditEnum.Pending)
                    {
                        item.IsAuditPer = normAuditTemps?.TempNodes.FirstOrDefault()?.NodeUsers.Any(x => x.UserId == currUserId) ?? false;
                    }
                    else if (item.AuditStatus == GoodsAuditEnum.OutConfirming)
                    {
                        item.IsAuditPer = valuableAuditTemps?.TempNodes.FirstOrDefault(x => x.NodeOrder == 1)?.NodeUsers.Any(x => x.UserId == currUserId) ?? false;
                    }
                }

                //前端权限验证
                if (item.IsValuable)
                {
                    item.AuditPers = valuableAuditUsers.ToArray();
                }
                else item.AuditPers = normAuditUsers.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>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveBatchOpAsync(GoodsReceiveBatchOpDto dto)
        {
            var goodsReceiveId = dto.Id;
            var currUserId = dto.CurrUserId;
            //请求参数处理
            var receiveInfo = new Pm_GoodsReceive()
            {
                Id = goodsReceiveId,
                GroupId = dto.GroupId,
                Reason = dto.Reason,
                Remark = dto.Remark,
                AuditStatus = GoodsAuditEnum.Pending,
                CreateUserId = currUserId,
            };
            var receiveDetails = _mapper.Map<Pm_GoodsReceiveDetails[]>(dto.ReceiveDetails);
            //receiveDetails.ForEach(x => { x.CreateUserId = dto.CurrUserId; });

            _sqlSugar.BeginTran();


            //审核状态验证 false:其他物品 true:贵重物品
            var isBatchVail = false;

            //物品库存验证
            int goodsIndex = 1;
            var goodsNames = new List<string>();
            foreach (var item in receiveDetails)
            {
                item.CreateUserId = currUserId;
                int goodsId = item.GoodsId;
                //物品验证
                var goodsInfo = _sqlSugar.Queryable<Pm_GoodsInfo>().First(x => x.IsDel == 0 && x.Id == goodsId);
                if (goodsInfo == null)
                {
                    _jv.Msg = $"第{goodsIndex}项物品不存在!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }
                goodsNames.Add(goodsInfo.Name);

                //物品库存验证
                var stockQuantity = goodsInfo.StockQuantity;
                var awaitAuditQuantity = await GoodsAwaitQuantityAsync(goodsId);
                stockQuantity -= awaitAuditQuantity;
                if (item.Quantity > stockQuantity)
                {
                    _jv.Msg = $"“{goodsInfo.Name}”物品库存不足!剩余库存:{stockQuantity} {goodsInfo.Unit}(待审数量:{awaitAuditQuantity});";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }

                //物品类型验证
                if (_goodsTypeIds.Contains(goodsInfo.Type)) isBatchVail = true;

                //入库批次关联领用人 更改批次库存
                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>();
                var receiveQuantity = 0.00M; //领用总数量
                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;
                    var storageUpd = storage;
                    //storageUpd.ReceiveQuantity += thisBatchReceiveQuantity;
                    batchStorageInfos.Add(storageUpd);
                }


                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) //添加
            {
                goodsReceiveId = await _sqlSugar.Insertable(receiveInfo).ExecuteReturnIdentityAsync();
                if (goodsReceiveId < 1)
                {
                    _jv.Msg = $"领用添加失败!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }

                receiveDetails.ForEach(x => { x.GoodsReceiveId = goodsReceiveId; });

                var receiveDetailsStatus = await _sqlSugar.Insertable(receiveDetails).ExecuteCommandAsync();
                if (receiveDetailsStatus < 1)
                {
                    _jv.Msg = $"领用明细添加失败!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }
            }
            else //修改
            {
                //更改前状态验证
                if (goodsReceiveInfo.AuditStatus != GoodsAuditEnum.Pending)
                {
                    _jv.Msg = $"领用状态在“领用待确认”,即可修改!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }

                var receiveStatus = await _sqlSugar.Updateable(receiveInfo).ExecuteCommandAsync();

                if (receiveStatus < 1)
                {
                    _jv.Msg = $"领用更新失败!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }

                //更新子表数据
                if (receiveDetails.Any())
                {
                    receiveDetails.ForEach(x => { x.GoodsReceiveId = receiveInfo.Id; });


                    var db_receiveDetails = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
                   .Where(x => x.IsDel == 0 && x.GoodsReceiveId == goodsReceiveId)
                   .ToListAsync();

                    var toDelete = db_receiveDetails.Where(p => !receiveDetails.Any(np => np.Id == p.Id)).ToList();
                    if (toDelete.Any())
                    {
                        var delStatus = _sqlSugar.Deleteable(toDelete).ExecuteCommand();
                        if (delStatus < 1)
                        {
                            _jv.Msg = $"领用明细旧数据删除失败!";
                            _sqlSugar.RollbackTran();
                            return _jv;
                        }
                    }

                    var addOrUpdStatus = await _sqlSugar.Storageable<Pm_GoodsReceiveDetails>(receiveDetails.ToList()).ExecuteCommandAsync();
                    if (addOrUpdStatus < 1)
                    {
                        _jv.Msg = $"领用明细更新失败!";
                        _sqlSugar.RollbackTran();
                        return _jv;
                    }
                }
            }

            #region 审批流程验证、创建
            //审核验证 物品含有贵重物品 使用贵重物品审批流程
            var auditTempInfo = new ApprovalProcessView();
            if (isBatchVail)  //贵重物品审核模板
            {
                auditTempInfo = await _approvalProcessRep.GetTemplateByBusinessTypeAsync(3);
            }
            else //其他物品审核模板
            {
                auditTempInfo = await _approvalProcessRep.GetTemplateByBusinessTypeAsync(2);
            }

            if (auditTempInfo == null)
            {
                _jv.Msg = $"未配置审核模板!";
                _sqlSugar.RollbackTran();
                return _jv;
            }

            if (auditTempInfo == null && !auditTempInfo.TempNodes.Any())
            {
                _jv.Msg = $"审核模板未配置节点!";
                _sqlSugar.RollbackTran();
                return _jv;
            }

            //创建审核流程
            var firstNode = auditTempInfo.TempNodes.OrderBy(x => x.NodeOrder).First();

            var flow = await _approvalProcessRep.GetFlowByBusinessAsync(goodsReceiveId, 1);

            int flowId;
            if (flow == null)
            {
                flow = new Sys_AuditFlow()
                {
                    BusinessId = goodsReceiveId,
                    BusinessType = 1,
                    TemplateId = auditTempInfo.Id,
                    CurrentNodeId = firstNode.Id,
                    Status = 1,
                };

                flowId = await _sqlSugar.Insertable(flow).ExecuteReturnIdentityAsync();
                if (flowId < 1)
                {
                    _jv.Msg = $"审核流程添加失败!";
                    _sqlSugar.RollbackTran();
                    return _jv;
                }
            }
            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
            {
                FlowId = flowId,
                NodeId = firstNode.Id,
                NodeName = firstNode.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;
            }

            _sqlSugar.CommitTran();
            _jv.Code = StatusCodes.Status200OK;
            _jv.Data = new { sign = goodsReceiveId };
            _jv.Msg = $"操作成功!";

            return _jv;
        }

        /// <summary>
        /// 物品领用 批量 List
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveBatchListAsync(GoodsReceiveBatchListDto dto)
        {
            int currUserId = dto.CurrUserId;
            string goodsName = dto.GoodsName;

            var showAllPeopleIds = new List<int>() {
                374, // 罗颖
                233, // 刘华举
                208, // 雷怡
                343, //  陈湘
            };
            var isShowAllPeople = showAllPeopleIds.Any(x => x == currUserId);

            RefAsync<int> total = 0;
            var receiveList = await _sqlSugar.Queryable<Pm_GoodsReceive>()
                .LeftJoin<Sys_Users>((x, y) => x.CreateUserId == y.Id)
                .Where((x, y) => x.IsDel == 0 && x.GoodsId == 0)
                .WhereIF(!string.IsNullOrEmpty(goodsName), (x, y) => x.GoodsName.Contains(goodsName))
                .WhereIF(!isShowAllPeople, (x, y) => x.CreateUserId == currUserId)
                .OrderByDescending((x, y) => x.CreateTime)
                .Select((x, y) => new GoodsReceiveBatchListView()
                {
                    Id = x.Id,
                    GoodsName = x.GoodsName,
                    AccumQty = SqlFunc.Subqueryable<Pm_GoodsReceiveDetails>().Where(z => z.IsDel == 0 && z.GoodsReceiveId == x.Id).Sum(z => z.Quantity),
                    Reason = x.Reason,
                    Remark = x.Remark,
                    Status = x.AuditStatus,
                    Applicant = y.CnName,
                    ApplyTime = x.CreateTime,
                })
                .ToPageListAsync(dto.PageIndex, dto.PageSize, total);

            foreach (var item in receiveList)
            {
                var detailsText = new StringBuilder();
                if (item.AccumQty > 0)
                {
                    var goodsInfos = await _sqlSugar.Queryable<Pm_GoodsReceiveDetails>()
                        .InnerJoin<Pm_GoodsInfo>((x, y) => x.GoodsId == y.Id)
                        .LeftJoin<Sys_SetData>((x, y, z) => y.Type == z.Id)
                        .Where((x, y, z) => x.IsDel == 0 && x.GoodsReceiveId == item.Id)
                        .Select((x, y, z) => new
                        {
                            goodsId = x.GoodsId,
                            goodsName = y.Name,
                            goodsType = z.Name,
                            quantity = x.Quantity,
                            remark = x.Remark,
                        })
                        .ToListAsync();

                    if (goodsInfos.Any())
                    {
                        int index = 1;
                        goodsInfos.ForEach(x =>
                        {
                            detailsText.Append($"{index}.{x.goodsName}({x.goodsType})  数量:{x.quantity:#0.00}  备注:{x.remark ?? "-"} <br/>");
                            index++;
                        });
                    }
                }
                else detailsText.Append($"暂无数据!");
                item.GoodsDetails = detailsText.ToString();
            }

            _jv.Code = StatusCodes.Status200OK;
            _jv.Msg = $"操作成功!";
            _jv.Data = receiveList;
            _jv.Count = total;
            return _jv;
        }

        /// <summary>
        /// 物品领用 批量 详情
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveBatchInfoAsync(int id)
        {
            var receiveInfo = await _sqlSugar.Queryable<Pm_GoodsReceive>()
                .Where(x => x.IsDel == 0 && x.Id == id)
                .FirstAsync();
            if (receiveInfo == null)
            {
                _jv.Msg = "暂无数据!";
                return _jv;
            }

            var info = new GoodsReceiveBatchView
            {
                Id = receiveInfo.Id,
                GroupId = receiveInfo.GroupId,
                Reason = receiveInfo.Reason,
                Remark = receiveInfo.Remark,
            };
            info.ReceiveDetails = await _sqlSugar
                .Queryable<Pm_GoodsReceiveDetails>()
                .LeftJoin<Pm_GoodsInfo>((x, y) => x.GoodsId == y.Id)
                .Where((x, y) => x.IsDel == 0 && x.GoodsReceiveId == receiveInfo.Id)
                .Select((x, y) => new GoodsReceiveDetailsView()
                {
                    Id = x.Id,
                    GoodsId = x.GoodsId,
                    GoodsName = y.Name,
                    Quantity = x.Quantity,
                    Remark = x.Remark,
                })
                .ToArrayAsync();
            _jv.Code = StatusCodes.Status200OK;
            _jv.Msg = $"操作成功!";
            _jv.Data = info;
            return _jv;
        }

        /// <summary>
        /// 物品领用 审核 通过
        /// </summary>
        /// <param name="id"></param>
        /// <param name="currUserId"></param>
        /// <returns></returns>
        public async Task<JsonView> GoodsReceiveApproveAsync(int id, int currUserId)
        {
            var appId = id;

            //验证审核流程
            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 auditStatus = await UpdateStatusAsync(appId, GoodsAuditEnum.OutConfirming);
                    if (!auditStatus)
                    {
                        _jv.Msg = $"审核状态更新失败!";
                        _sqlSugar.RollbackTran();
                        return _jv;
                    }

                    // 为下一个节点创建审核记录
                    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> GoodsAwaitQuantityAsync(int goodsId)
        {
            decimal quantity = 0.00M;
            //单条领用 待审核、确认中 物品数量
            var waitAuditQuantity = await _sqlSugar.Queryable<Pm_GoodsReceive>().Where(x => x.IsDel == 0 &&
                            x.GoodsId == goodsId &&
                            (x.AuditStatus == GoodsAuditEnum.Pending || x.AuditStatus == GoodsAuditEnum.OutConfirming)
                ).SumAsync(x => x.Quantity);

            //批量领用 待审核、确认中 物品数量 
            var waitAuditBatchQuantity = await _sqlSugar.Queryable<Pm_GoodsReceive>()
                .InnerJoin<Pm_GoodsReceiveDetails>((gr, grd) => gr.Id == grd.GoodsReceiveId)
                .Where((gr, grd) => gr.IsDel == 0 &&
                                    (gr.AuditStatus == GoodsAuditEnum.Pending || gr.AuditStatus == GoodsAuditEnum.OutConfirming) &&
                                    grd.GoodsId == goodsId
                )
                .Select((gr, grd) => new
                {
                    grd.GoodsReceiveId,
                    gr.AuditStatus,
                    grd.Quantity
                })
                .SumAsync(gr => gr.Quantity);

            quantity = waitAuditQuantity + waitAuditBatchQuantity;

            return quantity;
        }

        /// <summary>
        /// 更改领用状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public async Task<bool> UpdateStatusAsync(int id, GoodsAuditEnum status)
        {
            return await _sqlSugar.Updateable<Pm_GoodsReceive>()
                .SetColumns(x => x.AuditStatus == status)
                .Where(x => x.Id == id)
                .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、物品库存扣除
                goodsInfo.StockQuantity -= item.Quantity;
                goodsInfo.OQ_Total += item.Quantity;

                //2、入库批次关联领用人 更改批次库存
                var goodsStorages = await _sqlSugar
                    .Queryable<Pm_GoodsStorage>()
                    .Where(x => x.IsDel == 0 &&
                                x.GoodsId == item.GoodsId &&
                                x.ConfirmStatus == GoodsConfirmEnum.Confirmed &&
                                (x.Quantity - x.ReceiveQuantity) > 0
                        )
                    .OrderBy(x => x.CreateTime)
                    .ToListAsync();

                var goodsReceiveInfos = new List<GoodsReceiveLinkStorageView>();
                var batchStorageInfos = new List<Pm_GoodsStorage>();

                var receiveQuantity = 0.00M; //领用总数量
                foreach (var storage in goodsStorages)
                {
                    if (item.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 < storage.Quantity)
                    {
                        if (thisBatchSurplusQuantity == thisBatchReceiveQuantity || receiveQuantity == item.Quantity) 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
    }
}