public DataResult PostMaterialBill([FromBody] IEnumerable <MaterialBillDetail> bills)
        {
            if (bills == null || !bills.Any())
            {
                return(Result.GenError <DataResult>(Error.ParamError));
            }

            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 result    = new DataResult();
            var sameCodes = bills.GroupBy(x => new { x.Category, x.Name, x.Specification })
                            //.ToDictionary(x=>x.Key, x=>x.Count()).Where(x => x.Value> 1)
                            .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);
            }

            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()).ToList();
            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).ToList();
            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).ToList();
            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).ToList();
            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 新
            var createUserId   = Request.GetIdentityInformation();
            var markedDateTime = DateTime.Now;
            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

            foreach (var bill in bills)
            {
                bill.CreateUserId   = createUserId;
                bill.MarkedDateTime = markedDateTime;
                bill.Remark         = bill.Remark ?? "";
                bill.Images         = bill.Images ?? "[]";
            }
            MaterialBillHelper.Instance.Add(bills);
            return(Result.GenError <DataResult>(Error.Success));
        }
        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));
        }