public object ConsumeMaterial([FromBody] ConsumeMaterial materialManagement)
        {
            if (materialManagement.Bill == null)
            {
                return(Result.GenError <Result>(Error.ParamError));
            }

            foreach (var bill in materialManagement.Bill)
            {
                bill.Type = MaterialOp.出库;
                bill.CorrectNumber();
            }
            var mBills = materialManagement.Bill.Where(x => x.Number > 0);

            if (!mBills.Any())
            {
                return(Result.GenError <Result>(Error.MaterialNotEmpty));
            }

            //出库时物料必须存在
            if (mBills.Any(x => x.Type == MaterialOp.出库 && x.BillId == 0))
            {
                return(Result.GenError <Result>(Error.MaterialBillNotExist));
            }

            var billIds = mBills.Select(x => x.BillId).Distinct();

            if (!billIds.Any())
            {
                return(Result.GenError <Result>(Error.MaterialNotEmpty));
            }

            var allBills = MaterialHelper.GetDetails(billIds).ToDictionary(x => x.BillId);

            if (allBills.Count() != billIds.Count())
            {
                return(Result.GenError <Result>(Error.MaterialBillNotExist));
            }

            var         createUserId   = Request.GetIdentityInformation();
            var         markedDateTime = DateTime.Now;
            ProductPlan plan           = null;

            if (materialManagement.PlanId != 0)
            {
                plan = ProductPlanHelper.Instance.Get <ProductPlan>(materialManagement.PlanId);
                if (plan == null)
                {
                    return(Result.GenError <Result>(Error.ProductionPlanNotExist));
                }
            }

            var result = new DataResult();

            #region 检验库存
            var consumeBills = billIds.Select(x => new OpMaterial
            {
                BillId = x,
                Number = mBills.Where(y => y.BillId == x).Sum(z => z.Number)
            }).ToList();
            var less = consumeBills.Where(x => x.Number > allBills[x.BillId].Number).Select(x => allBills[x.BillId].Code);
            if (less.Any())
            {
                result.errno = Error.MaterialLess;
                result.datas.AddRange(less);
                return(result);
            }
            var oldBatches = new Dictionary <int, MaterialBatch>();
            var upIds      = new Dictionary <int, int>();
            //出库指定的批次
            var batchBills = mBills.Where(x => x.HaveBatch);
            if (batchBills.Any())
            {
                var bIds = batchBills.SelectMany(x => x.Batches.Select(y => y.Id)).Distinct();
                oldBatches.AddRange(MaterialBatchHelper.GetDetails(bIds).ToDictionary(x => x.Id));
                if (bIds.Count() != oldBatches.Count())
                {
                    return(Result.GenError <DataResult>(Error.MaterialBatchNotExist));
                }
                var mergeBatch = bIds.Select(x =>
                {
                    var oldBatch = oldBatches[x];
                    var batches  = batchBills.Where(y => y.BillId == oldBatch.BillId).SelectMany((Func <OpMaterial, IEnumerable <MaterialBatchSimple> >)(y => y.Batches.Where((Func <MaterialBatchSimple, bool>)(z => z.Id == oldBatch.Id))));
                    return(new MaterialBatch
                    {
                        Id = oldBatch.Id,
                        BatchId = oldBatch.BatchId,
                        Batch = oldBatch.Batch,
                        BillId = oldBatch.BillId,
                        SupplierId = oldBatch.SupplierId,
                        Number = batches.Sum(y => y.Number),
                    });
                });
                var much = mergeBatch.Where(x => oldBatches[x.Id].Left < x.Number);
                if (much.Any())
                {
                    result = new DataResult {
                        errno = Error.MaterialBatchLeftLess
                    };
                    result.datas.AddRange(much.Select(x => $"{x.Batch} {allBills[x.BillId].Code} {x.Supplier}"));
                    return(result);
                }
            }

            var noBatchBills = mBills.Where(x => !x.HaveBatch);
            if (noBatchBills.Any())
            {
                var noBillIds     = noBatchBills.Select(x => x.BillId).Distinct();
                var noZeroBatches = MaterialBatchHelper.GetDetailsNoZero(noBillIds)
                                    .GroupBy(x => x.BillId).ToDictionary(x => x.Key);
                //.GroupBy(x => x.BillId).ToDictionary(x => x.Key, x => x.Select(y => y));

                var mergeBatch = noBillIds.Select(billId =>
                {
                    var batches = noBatchBills.Where(y => y.BillId == billId);
                    var number  = batches.Sum(y => y.Number);
                    return(new MaterialBatch
                    {
                        BillId = billId,
                        Number = number,
                    });
                });
                var noZeroMergeBatch = noBillIds.Select(billId =>
                {
                    var left = noZeroBatches.ContainsKey(billId) ? noZeroBatches[billId].Sum(y => y.Left) : 0;
                    return(new MaterialBatch
                    {
                        BillId = billId,
                        Left = left,
                    });
                }).ToDictionary(x => x.BillId);
                var much = mergeBatch.Where(x => noZeroMergeBatch[x.BillId].Left < x.Number);
                if (much.Any())
                {
                    result = new DataResult {
                        errno = Error.MaterialBatchLeftLess
                    };
                    result.datas.AddRange(much.Select(x => $"{x.Batch} {allBills[x.BillId].Code} {x.Supplier}"));
                    return(result);
                }

                foreach (var bill in noBatchBills)
                {
                    var number = bill.Number;
                    foreach (var batch in noZeroBatches[bill.BillId].OrderBy(x => x.Time))
                    {
                        if (number <= 0)
                        {
                            break;
                        }
                        if (!upIds.ContainsKey(batch.Id))
                        {
                            upIds.Add(batch.Id, 0);
                        }

                        var n = 0m;
                        if (number > batch.Left)
                        {
                            number -= batch.Left;
                            n       = batch.Left;
                        }
                        else
                        {
                            n      = number;
                            number = 0;
                        }
                        var z = ClassExtension.CopyTo <MaterialBatch, MaterialBatchSimple>(batch);
                        z.Number = n;
                        bill.Batches.Add(z);
                    }
                }
                oldBatches.AddRange(noZeroBatches.Values.SelectMany(x => x.Where(y => upIds.ContainsKey(y.Id))).ToDictionary(x => x.Id));
            }

            #endregion

            #region 计划领料
            var planChangeBill = new List <ProductPlanBill>();
            var planAddBill    = new List <ProductPlanBill>();
            if (materialManagement.PlanId != 0)
            {
                var planBill = ProductPlanBillHelper.GetPlanBills(materialManagement.PlanId, billIds).ToDictionary(x => x.BillId);
                #region 更新
                var existBill = consumeBills.Where(x => planBill.ContainsKey(x.BillId));
                if (existBill.Any())
                {
                    foreach (var bill in existBill)
                    {
                        planBill[bill.BillId].MarkedDateTime     = markedDateTime;
                        planBill[bill.BillId].ActualConsumption += bill.Number;
                        planChangeBill.Add(planBill[bill.BillId]);
                    }
                }
                #endregion

                #region 添加额外领用的物料
                var extraBill = consumeBills.Where(x => !planBill.ContainsKey(x.BillId));
                if (extraBill.Any())
                {
                    planAddBill.AddRange(extraBill.Select(x => new ProductPlanBill
                    {
                        CreateUserId      = createUserId,
                        MarkedDateTime    = markedDateTime,
                        PlanId            = materialManagement.PlanId,
                        BillId            = x.BillId,
                        ActualConsumption = x.Number,
                        Extra             = true,
                    }));
                }
                #endregion
            }
            #endregion

            var logs = mBills.Select(x =>
            {
                var batches = new List <MaterialBatch>();
                batches.AddRange(x.Batches.Select(y =>
                {
                    var batch            = oldBatches[y.Id];
                    batch.MarkedDateTime = markedDateTime;
                    batch.OutTime        = markedDateTime;
                    batch.Left          -= y.Number;
                    var z   = ClassExtension.CopyTo <MaterialBatchSimple, MaterialBatch>(y);
                    z.Batch = batch.Batch;
                    z.Price = batch.Price;
                    return(z);
                }));
                var log = new MaterialLog(createUserId, markedDateTime, x.Type, x.Purpose, x.Number,
                                          allBills[x.BillId].Number, x.RelatedPerson, createUserId, allBills[x.BillId], batches, plan);
                return(log);
            }).ToList();
            if (oldBatches.Any())
            {
                MaterialBatchHelper.UpdateConsumeLeft(oldBatches.Values);
            }

            Task.Run(() =>
            {
                if (planChangeBill.Any())
                {
                    ProductPlanBillHelper.UpdateActualConsumptions(planChangeBill);
                }

                if (planAddBill.Any())
                {
                    ProductPlanBillHelper.Instance.Add(planAddBill);
                }
                if (logs.Any())
                {
                    MaterialLogHelper.Instance.Add(logs);
                }
                if (allBills.Keys.Any())
                {
                    HMaterialHelper.UpdateBillPrice(allBills.Keys);
                }
            });
            try
            {
                #region 消耗
                foreach (var bill in consumeBills)
                {
                    allBills[bill.BillId].OutTime = markedDateTime;
                    allBills[bill.BillId].Number -= bill.Number;
                }
                MaterialHelper.Consume(allBills.Values);
                #endregion
            }
            catch (Exception e)
            {
                Log.Error(allBills.Values.ToJSON());
                Log.Error(e);
            }

            return(result);
        }