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);
        }
        public object IncreaseMaterial([FromBody] IncreaseMaterial materialManagement)
        {
            if (materialManagement.Bill == null)
            {
                return(Result.GenError <Result>(Error.ParamError));
            }

            foreach (var bill in materialManagement.Bill)
            {
                bill.Type = bill.HaveBatch ? MaterialOp.退库 : 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.MaterialBackNoBillError));
            }
            //退库必须指定批次
            if (mBills.Any(x => x.Type == MaterialOp.退库 && !x.HaveBatch))
            {
                return(Result.GenError <Result>(Error.MaterialBackNoBatchError));
            }
            var result   = new DataResult();
            var billIds  = mBills.Select(x => x.BillId).Where(x => x != 0).Distinct();
            var allBills = new Dictionary <int, Material>();

            if (billIds.Any())
            {
                allBills.AddRange(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;

            #region 新货品
            var bills = mBills.Where(x => x.CategoryId == 0 || x.NameId == 0 || x.SpecificationId == 0 || x.BillId == 0);
            if (bills.Any())
            {
                if (bills.Any(x => x.CategoryId == 0 && x.Category.IsNullOrEmpty()) ||
                    bills.Any(x => x.NameId == 0 && x.Name.IsNullOrEmpty()) ||
                    bills.Any(x => x.SpecificationId == 0 && x.Specification.IsNullOrEmpty()))
                {
                    return(Result.GenError <DataResult>(Error.ParamError));
                }
                var sameCodes = bills.GroupBy(x => new { x.Category, x.Name, x.Specification })
                                .Where(x => x.Count() > 1)
                                .Select(x => bills.FirstOrDefault(y => x.Key.Category == y.Category && x.Key.Name == y.Name && x.Key.Specification == y.Specification)?.Code ?? "");
                if (sameCodes.Any())
                {
                    result.errno = Error.MaterialBillCategoryNameSpecificationDuplicate;
                    result.datas.AddRange(sameCodes);
                    return(result);
                }

                sameCodes = bills.GroupBy(x => x.Code).Where(y => y.Count() > 1).Select(z => z.Key);
                if (sameCodes.Any())
                {
                    result.errno = Error.MaterialBillDuplicate;
                    result.datas.AddRange(sameCodes);
                    return(result);
                }

                var codes = bills.Select(y => y.Code).Distinct();
                sameCodes = MaterialBillHelper.GetBills(codes).Select(x => x.Code);
                if (sameCodes.Any())
                {
                    result.errno = Error.MaterialBillIsExist;
                    result.datas.AddRange(sameCodes);
                    return(result);
                }

                foreach (var bill in bills)
                {
                    bill.BillId = 0;
                }

                var categoryIds = bills.Select(x => x.CategoryId).Where(x => x != 0).Distinct();
                var cnt         = MaterialCategoryHelper.Instance.GetCountByIds(categoryIds);
                if (cnt != categoryIds.Count())
                {
                    return(Result.GenError <DataResult>(Error.MaterialCategoryNotExist));
                }
                var nameIds = bills.Select(x => x.NameId).Where(x => x != 0).Distinct();
                cnt = MaterialNameHelper.Instance.GetCountByIds(nameIds);
                if (cnt != nameIds.Count())
                {
                    return(Result.GenError <DataResult>(Error.MaterialNameNotExist));
                }
                var specificationIds = bills.Select(x => x.SpecificationId).Where(x => x != 0).Distinct();
                cnt = MaterialSpecificationHelper.Instance.GetCountByIds(specificationIds);
                if (cnt != specificationIds.Count())
                {
                    return(Result.GenError <DataResult>(Error.MaterialSpecificationNotExist));
                }

                var siteIds = bills.Select(x => x.SiteId).Where(x => x != 0).Distinct();
                cnt = MaterialSiteHelper.Instance.GetCountByIds(siteIds);
                if (cnt != siteIds.Count())
                {
                    return(Result.GenError <DataResult>(Error.MaterialSiteNotExist));
                }

                if (categoryIds.Any() && nameIds.Any() && specificationIds.Any())
                {
                    sameCodes = MaterialBillHelper.GetBills(categoryIds, nameIds, specificationIds).Select(x => x.Code);
                    if (sameCodes.Any())
                    {
                        result.errno = Error.MaterialBillCategoryNameSpecificationDuplicate;
                        result.datas.AddRange(sameCodes);
                        return(result);
                    }
                }

                #region 新位置
                var notExistSite = bills.Where(x => x.SiteId == 0 && !x.Site.IsNullOrEmpty());
                var newSites     = notExistSite.Select(x => x.Site).Distinct();
                if (newSites.Any())
                {
                    var sameStr = MaterialSiteHelper.GetDetails(newSites);
                    if (sameStr.Any())
                    {
                        result.errno = Error.MaterialSiteIsExist;
                        result.datas.AddRange(sameStr);
                        return(result);
                    }
                }
                #endregion

                #region 新类别
                var notExistCategories = bills.Where(x => x.CategoryId == 0);
                var newCategories      = notExistCategories.Select(x => x.Category).Distinct();
                if (newCategories.Any())
                {
                    var sameStr = MaterialCategoryHelper.GetDetails(newCategories);
                    if (sameStr.Any())
                    {
                        result.errno = Error.MaterialCategoryIsExist;
                        result.datas.AddRange(sameStr);
                        return(result);
                    }
                }
                #endregion

                #region 新名称
                var notExistNames = bills.Where(x => x.NameId == 0);
                var newNames      = notExistNames.Select(x => x.Name).Distinct();
                if (newNames.Any())
                {
                    var sameStr = MaterialNameHelper.GetDetails(newNames);
                    if (sameStr.Any())
                    {
                        result.errno = Error.MaterialNameIsExist;
                        result.datas.AddRange(sameStr);
                        return(result);
                    }
                }
                #endregion

                #region 新规格
                var notExistSpecifications = bills.Where(x => x.SpecificationId == 0);
                var newSpecifications      = notExistSpecifications.Select(x => x.Specification).Distinct();
                if (newSpecifications.Any())
                {
                    var sameStr = MaterialSpecificationHelper.GetDetails(newSpecifications);
                    if (sameStr.Any())
                    {
                        result.errno = Error.MaterialSpecificationIsExist;
                        result.datas.AddRange(sameStr);
                        return(result);
                    }
                }
                #endregion

                #region 新
                if (newSites.Any())
                {
                    MaterialSiteHelper.Instance.Add(newSites.Select(x => new MaterialSite
                    {
                        CreateUserId   = createUserId,
                        MarkedDateTime = markedDateTime,
                        Site           = x
                    }));
                    var data = MaterialSiteHelper.GetDetails(newSites).ToDictionary(x => x.Site);
                    foreach (var bill in notExistSite)
                    {
                        var key = bill.Site;
                        if (data.ContainsKey(key))
                        {
                            bill.SiteId = data[key].Id;
                        }
                    }
                }

                if (newCategories.Any())
                {
                    MaterialCategoryHelper.Instance.Add(newCategories.Select(x => new MaterialCategory
                    {
                        CreateUserId   = createUserId,
                        MarkedDateTime = markedDateTime,
                        Category       = x
                    }));
                    var data = MaterialCategoryHelper.GetDetails(newCategories).ToDictionary(x => x.Category);
                    foreach (var bill in notExistCategories)
                    {
                        var key = bill.Category;
                        if (data.ContainsKey(key))
                        {
                            bill.CategoryId = data[key].Id;
                        }
                    }
                }

                if (newNames.Any())
                {
                    MaterialNameHelper.Instance.Add(newNames.Select(x => new MaterialName
                    {
                        CreateUserId   = createUserId,
                        MarkedDateTime = markedDateTime,
                        Name           = x
                    }));
                    var data = MaterialNameHelper.GetDetails(newNames).ToDictionary(x => x.Name);
                    foreach (var bill in notExistNames)
                    {
                        var key = bill.Name;
                        if (data.ContainsKey(key))
                        {
                            bill.NameId = data[key].Id;
                        }
                    }
                }

                if (newSpecifications.Any())
                {
                    MaterialSpecificationHelper.Instance.Add(newSpecifications.Select(x => new MaterialSpecification
                    {
                        CreateUserId   = createUserId,
                        MarkedDateTime = markedDateTime,
                        Specification  = x
                    }));
                    var data = MaterialSpecificationHelper.GetDetails(newSpecifications).ToDictionary(x => x.Specification);
                    foreach (var bill in notExistSpecifications)
                    {
                        var key = bill.Specification;
                        if (data.ContainsKey(key))
                        {
                            bill.SpecificationId = data[key].Id;
                        }
                    }
                }
                #endregion
            }

            bills = mBills.Where(x => x.BillId == 0);
            if (bills.Any())
            {
                foreach (var bill in bills)
                {
                    bill.CreateUserId   = createUserId;
                    bill.MarkedDateTime = markedDateTime;
                    bill.Remark         = bill.Remark ?? "";
                    bill.Images         = bill.Images ?? "[]";
                }
                MaterialBillHelper.Instance.Add(bills);
            }

            var billId_0 = mBills.Where(x => x.BillId == 0);
            if (billId_0.Any())
            {
                var billIds_0 = MaterialBillHelper.GetBills(billId_0.Select(x => x.Code)).ToDictionary(x => x.Code);
                foreach (var bill in billId_0)
                {
                    if (billIds_0.ContainsKey(bill.Code))
                    {
                        var exist = billIds_0[bill.Code];
                        bill.BillId = exist.Id;
                    }
                }
                allBills.AddRange(billIds_0.Values.ToDictionary(x => x.Id, x => (Material)x));
            }
            #endregion

            var oldBatches = new Dictionary <int, MaterialBatch>();
            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));
                }
                if (!batchBills.All(x => x.Batches.All(y => oldBatches.ContainsKey(y.Id) && oldBatches[y.Id].BillId == x.BillId)))
                {
                    return(Result.GenError <DataResult>(Error.MaterialBatchNotContain));
                }
                var mergeBatch = bIds.Select(x =>
                {
                    var oldBatch = oldBatches[x];
                    var batches  = batchBills.Where(y => y.BillId == oldBatch.BillId).SelectMany(y => y.Batches.Where(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].Number - oldBatches[x.Id].Left < x.Number);
                if (much.Any())
                {
                    result = new DataResult {
                        errno = Error.ProductionPlanBillActualConsumeLess
                    };
                    result.datas.AddRange(much.Select(x => $"{x.Batch} {allBills[x.BillId].Code} {x.Supplier}"));
                    return(result);
                }
            }

            //计划退库
            var pBills    = mBills.Where(x => x.PlanId != 0);
            var plans     = new Dictionary <int, ProductPlan>();
            var planBills = new Dictionary <Tuple <int, int>, ProductPlanBill>();
            if (pBills.Any())
            {
                var actualPlanBill = pBills.Select(x => new OpMaterial
                {
                    PlanId        = x.PlanId,
                    BillId        = x.BillId,
                    Number        = pBills.Where(y => y.PlanId == x.PlanId && y.BillId == x.BillId).Sum(y => y.Number),
                    Purpose       = pBills.FirstOrDefault(y => y.PlanId == x.PlanId && y.BillId == x.BillId)?.Purpose ?? "",
                    RelatedPerson = pBills.FirstOrDefault(y => y.PlanId == x.PlanId && y.BillId == x.BillId)?.RelatedPerson ?? "",
                });
                var planIds = pBills.Select(x => x.PlanId).Distinct();
                plans.AddRange(ProductPlanHelper.Instance.GetAllByIds <ProductPlan>(planIds).ToDictionary(x => x.Id));
                var planBillIds = pBills.Select(x => x.BillId).Distinct();
                planBills.AddRange(ProductPlanBillHelper.GetPlanBills(planIds, planBillIds).ToDictionary(x => new Tuple <int, int>(x.PlanId, x.BillId)));
                var notExist = pBills.Where(x => !planBills.ContainsKey(new Tuple <int, int>(x.PlanId, x.BillId)));
                if (notExist.Any())
                {
                    result = new DataResult {
                        errno = Error.ProductionPlanBillNotExist
                    };
                    result.datas.AddRange(notExist.Where(x => plans.ContainsKey(x.PlanId) && allBills.ContainsKey(x.BillId)).Select(y => new { plans[y.PlanId].Plan, allBills[y.BillId].Code }));
                    return(result);
                }

                var notEnough = actualPlanBill.Where(x => planBills.ContainsKey(new Tuple <int, int>(x.PlanId, x.BillId)) &&
                                                     planBills[new Tuple <int, int>(x.PlanId, x.BillId)].ActualConsumption < x.Number);
                if (notEnough.Any())
                {
                    result = new DataResult {
                        errno = Error.ProductionPlanBillActualConsumeLess
                    };
                    result.datas.AddRange(notEnough.Where(x => plans.ContainsKey(x.PlanId) && allBills.ContainsKey(x.BillId)).Select(y => new { plans[y.PlanId].Plan, allBills[y.BillId].Code }));
                    return(result);
                }

                foreach (var bill in actualPlanBill)
                {
                    var key = new Tuple <int, int>(bill.PlanId, bill.BillId);
                    planBills[key].MarkedDateTime     = markedDateTime;
                    planBills[key].ActualConsumption -= bill.Number;
                }
            }

            var           noBatchBills = mBills.Where(x => !x.HaveBatch);
            var           newBatches   = new Dictionary <Tuple <int, int, int>, MaterialBatch>();
            MaterialBatch originBatch  = null;
            if (noBatchBills.Any())
            {
                var suppliers = noBatchBills.Select(x => x.Supplier).Distinct();
                var data      = MaterialSupplierHelper.GetDetails(suppliers).ToDictionary(x => x.Supplier);
                foreach (var bill in noBatchBills)
                {
                    var key = bill.Supplier;
                    if (data.ContainsKey(key))
                    {
                        bill.SupplierId = data[key].Id;
                    }
                }

                var newSuppliers = noBatchBills.Where(x => x.SupplierId == 0).Select(x => x.Supplier).Distinct();
                if (newSuppliers.Any())
                {
                    MaterialSupplierHelper.Instance.Add(newSuppliers.Select(x => new MaterialSupplier
                    {
                        CreateUserId   = createUserId,
                        MarkedDateTime = markedDateTime,
                        Supplier       = x
                    }));
                    data = MaterialSupplierHelper.GetDetails(newSuppliers).ToDictionary(x => x.Supplier);
                    foreach (var bill in noBatchBills)
                    {
                        var key = bill.Supplier;
                        if (data.ContainsKey(key))
                        {
                            bill.SupplierId = data[key].Id;
                        }
                    }
                }

                originBatch = MaterialBatchHelper.GetBatch(createUserId, markedDateTime);
                var addBatches = noBatchBills.GroupBy(x => new { x.BillId, x.SupplierId }).Select(x =>
                {
                    originBatch.BillId     = x.Key.BillId;
                    originBatch.SupplierId = x.Key.SupplierId;
                    var manage             = noBatchBills.First(y => x.Key.BillId == y.BillId && x.Key.SupplierId == y.SupplierId);
                    manage.Number          = noBatchBills.Where(y => x.Key.BillId == y.BillId && x.Key.SupplierId == y.SupplierId).Sum(a => a.Number);
                    return(new MaterialBatch(originBatch, manage));
                });

                MaterialBatchHelper.Instance.Add(addBatches);
                var bIds = addBatches.Select(x => x.BillId).Distinct();
                var sIds = addBatches.Select(x => x.SupplierId).Distinct();
                newBatches.AddRange(MaterialBatchHelper.GetDetails(originBatch.BatchId, bIds, sIds)
                                    .ToDictionary(x => new Tuple <int, int, int>(x.BatchId, x.BillId, x.SupplierId)));
            }

            #region 更新
            var existBills = MaterialHelper.GetDetails(billIds);
            foreach (var bill in existBills)
            {
                bill.Number += mBills.Where(x => x.BillId == bill.BillId).Sum(y => y.Number);
                bill.InTime  = markedDateTime;
            }

            MaterialHelper.Increase(existBills);
            #endregion

            #region 添加
            var addBill = mBills.Where(x => existBills.All(y => y.BillId != x.BillId));
            if (addBill.Any())
            {
                MaterialHelper.Instance.Add(addBill.GroupBy(y => y.BillId).Select(
                                                x => new
                {
                    BillId = x.Key,
                    InTime = markedDateTime,
                    Number = addBill.Where(z => z.BillId == x.Key).Sum(a => a.Number)
                }));
            }
            #endregion

            var logs = mBills.Select(x =>
            {
                var batches = new List <MaterialBatch>();
                //退库
                if (x.Type == MaterialOp.退库)
                {
                    batches.AddRange(x.Batches.Select(y =>
                    {
                        var batch            = oldBatches[y.Id];
                        batch.MarkedDateTime = markedDateTime;
                        batch.InTime         = markedDateTime;
                        batch.Left          += y.Number;
                        var z   = ClassExtension.CopyTo <MaterialBatchSimple, MaterialBatch>(y);
                        z.Batch = batch.Batch;
                        z.Price = batch.Price;
                        return(z);
                    }));
                }
                //入库
                else
                {
                    var batch = newBatches[new Tuple <int, int, int>(originBatch.BatchId, x.BillId, x.SupplierId)];
                    batches.Add(batch);
                }

                var plan = x.PlanId != 0 ? plans[x.PlanId] : null;
                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.UpdateIncreaseLeft(oldBatches.Values);
            }

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

                if (logs.Any())
                {
                    MaterialLogHelper.Instance.Add(logs);
                }
                if (allBills.Keys.Any())
                {
                    HMaterialHelper.UpdateBillPrice(allBills.Keys);
                }
            });

            return(Result.GenError <Result>(Error.Success));
        }