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);
        }
Ejemplo n.º 2
0
        public object IncreaseMaterialPurchaseItem([FromBody] IEnumerable <MaterialPurchaseItem> purchaseItems)
        {
            if (purchaseItems == null)
            {
                return(Result.GenError <Result>(Error.ParamError));
            }

            purchaseItems = purchaseItems.Where(x => x.Count > 0);
            if (!purchaseItems.Any())
            {
                return(Result.GenError <Result>(Error.MaterialPurchaseItemNotExist));
            }

            if (purchaseItems.Any(x => x.Id == 0))
            {
                return(Result.GenError <Result>(Error.MaterialPurchaseItemNotExist));
            }

            if (purchaseItems.Count() != purchaseItems.GroupBy(x => x.Id).Count())
            {
                return(Result.GenError <Result>(Error.MaterialPurchaseItemDuplicate));
            }

            var purchaseItemIds  = purchaseItems.Select(x => x.Id).Distinct();
            var oldPurchaseItems = MaterialPurchaseItemHelper.Instance.GetByIds <MaterialPurchaseItem>(purchaseItemIds);

            if (oldPurchaseItems.Count() != purchaseItemIds.Count())
            {
                return(Result.GenError <Result>(Error.MaterialPurchaseItemNotExist));
            }
            if (oldPurchaseItems.Any(x => x.ErpId == 0))
            {
                return(Result.GenError <Result>(Error.MaterialPurchaseItemNotBuy));
            }

            var purchaseIds    = oldPurchaseItems.Select(x => x.PurchaseId).Distinct();
            var purchases      = MaterialPurchaseHelper.Instance.GetByIds <MaterialPurchase>(purchaseIds).ToDictionary(x => x.Id);
            var createUserId   = Request.GetIdentityInformation();
            var markedDateTime = DateTime.Now;
            var result         = new DataResult();

            #region 新编号
            var unknow = "无";
            foreach (var purchaseItem in oldPurchaseItems)
            {
                if ((purchaseItem.Class + purchaseItem.Category).IsNullOrEmpty())
                {
                    purchaseItem.Category = unknow;
                }
                if (purchaseItem.Name.IsNullOrEmpty())
                {
                    return(Result.GenError <Result>(Error.MaterialNameNotEmpty));
                }
                if (purchaseItem.Specification.IsNullOrEmpty())
                {
                    purchaseItem.Specification = unknow;
                }
                if (purchaseItem.Supplier.IsNullOrEmpty())
                {
                    purchaseItem.Supplier = unknow;
                }
            }

            var erpBills = oldPurchaseItems.Select(x =>
            {
                var purchase = purchases.ContainsKey(x.PurchaseId) ? purchases[x.PurchaseId] : null;
                return(new OpMaterial
                {
                    Id = x.Id,
                    ////借用,透传物料单id
                    BillId = x.BillId,
                    Code = x.Code,
                    Category = x.Category.IsNullOrEmpty() ? x.Class : x.Category,
                    Name = x.Name,
                    Supplier = x.Supplier,
                    Specification = x.Specification,
                    Site = "",
                    Price = x.Price,
                    Number = purchaseItems.FirstOrDefault(y => x.Id == y.Id)?.Count ?? 0,
                    Unit = x.Unit,
                    Remark = x.Remark,
                    File = x.File,
                    FileUrl = x.FileUrl,
                    RelatedPerson = purchase?.Name ?? "",
                    Purpose = $"Erp采购-{x.Order ?? ""}-{purchase?.ErpId.ToString() ?? ""}",
                });
            }).ToList();

            if (erpBills.Any(x => x.Code.IsNullOrEmpty()))
            {
                return(Result.GenError <Result>(Error.MaterialBillNotEmpty));
            }
            var codes    = erpBills.Select(x => x.Code).Distinct();
            var allBills = new Dictionary <int, Material>();
            allBills.AddRange(MaterialHelper.GetDetails(codes).ToDictionary(x => x.BillId));
            foreach (var bill in erpBills)
            {
                //var b = allBills.Values.FirstOrDefault(x => x.Code == bill.Code
                //                                    && x.Category == bill.Category
                //                                    && x.Name == bill.Name
                //                                    && x.Specification == bill.Specification);
                var b = allBills.Values.FirstOrDefault(x => x.Category == bill.Category &&
                                                       x.Name == bill.Name &&
                                                       x.Specification == bill.Specification);
                if (b == null)
                {
                    if (allBills.Values.Any(x => x.Code == bill.Code))
                    {
                        var bb     = allBills.Values.FirstOrDefault(x => x.Code == bill.Code);
                        var errmsg = $"货品编号异常,{bill.Code}";
                        if (bb.Category != bill.Category)
                        {
                            errmsg += $",类别:(100${bill.Category}$:222,${bb.Category}$)";
                        }
                        if (bb.Name != bill.Name)
                        {
                            errmsg += $",名称:(100,${bill.Name}$:222,${bb.Name}$)";
                        }
                        if (bb.Specification != bill.Specification)
                        {
                            errmsg += $",规格:(100,${bill.Specification}$:222,${bb.Specification}$)";
                        }
                        return(new
                        {
                            errno = 1,
                            errmsg,
                        });
                        //return Result.GenError<Result>(Error.MaterialCodeError);
                    }
                    bill.BillId = 0;
                    continue;
                }

                if (b.Code != bill.Code)
                {
                    result.datas.Add($"data:{b.BillId}, {b.Code}, erp: {bill.Code}");
                }
                if (b.BillId == 0)
                {
                    return(Result.GenError <Result>(Error.ParamError));
                }
                bill.BillId          = b.BillId;
                bill.Code            = b.Code;
                bill.CategoryId      = b.CategoryId;
                bill.NameId          = b.NameId;
                bill.SpecificationId = b.SpecificationId;
                bill.SiteId          = b.SiteId;
                bill.Site            = b.Site;
            }

            if (result.datas.Any())
            {
                result.errno = Error.MaterialCodeError;
                return(result);
            }
            #region 新货品
            var bills = erpBills.Where(x => x.CategoryId == 0 || x.NameId == 0 || x.SpecificationId == 0 || x.SupplierId == 0 || (x.SiteId == 0 && !x.Site.IsNullOrEmpty()) || x.BillId == 0);
            if (bills.Any())
            {
                #region 新位置
                var notExistSite = bills.Where(x => x.SiteId == 0 && !x.Site.IsNullOrEmpty());
                var newSites     = notExistSite.Select(x => x.Site).Distinct();
                if (newSites.Any())
                {
                    var data = MaterialSiteHelper.GetDetails(newSites).ToDictionary(x => x.Site);
                    if (data.Count() != newSites.Count())
                    {
                        MaterialSiteHelper.Instance.Add(newSites.Where(x => !data.ContainsKey(x)).Select(x => new MaterialSite
                        {
                            CreateUserId   = createUserId,
                            MarkedDateTime = markedDateTime,
                            Site           = x
                        }));
                        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;
                        }
                        else
                        {
                            return(Result.GenError <Result>(Error.MaterialSiteNotEmpty));
                        }
                    }
                }
                #endregion

                #region 新类别
                var notExistCategories = bills.Where(x => x.CategoryId == 0);
                var newCategories      = notExistCategories.GroupBy(x => x.Category).Select(y => y.Key);
                if (newCategories.Any())
                {
                    var data = MaterialCategoryHelper.GetDetails(newCategories).ToDictionary(x => x.Category);
                    if (data.Count() != newCategories.Count())
                    {
                        MaterialCategoryHelper.Instance.Add(newCategories.Where(x => !data.ContainsKey(x)).Select(x => new MaterialCategory
                        {
                            CreateUserId   = createUserId,
                            MarkedDateTime = markedDateTime,
                            Category       = x
                        }));
                        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;
                        }
                        else
                        {
                            return(Result.GenError <Result>(Error.MaterialCategoryNotEmpty));
                        }
                    }
                }
                #endregion

                #region 新名称
                var notExistNames = bills.Where(x => x.NameId == 0);
                var newNames      = notExistNames.Select(x => x.Name).Distinct();
                if (newNames.Any())
                {
                    var data = MaterialNameHelper.GetDetails(newNames).ToDictionary(x => x.Name);
                    if (data.Count() != newNames.Count())
                    {
                        MaterialNameHelper.Instance.Add(newNames.Where(x => !data.ContainsKey(x)).Select(x => new MaterialName
                        {
                            CreateUserId   = createUserId,
                            MarkedDateTime = markedDateTime,
                            Name           = x
                        }));
                        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;
                        }
                        else
                        {
                            return(Result.GenError <Result>(Error.MaterialNameNotEmpty));
                        }
                    }
                }

                #endregion

                #region 新规格
                var notExistSpecifications = bills.Where(x => x.SpecificationId == 0);
                var newSpecifications      = notExistSpecifications.Select(x => x.Specification).Distinct();
                if (newSpecifications.Any())
                {
                    var data = MaterialSpecificationHelper.GetDetails(newSpecifications).ToDictionary(x => x.Specification);
                    if (data.Count() != newSpecifications.Count())
                    {
                        MaterialSpecificationHelper.Instance.Add(newSpecifications.Where(x => !data.ContainsKey(x)).Select(x => new MaterialSpecification
                        {
                            CreateUserId   = createUserId,
                            MarkedDateTime = markedDateTime,
                            Specification  = x
                        }));
                        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;
                        }
                        else
                        {
                            return(Result.GenError <Result>(Error.MaterialSpecificationNotEmpty));
                        }
                    }
                }

                #endregion

                #region 供应商
                var notExistSuppliers = bills.Where(x => x.SupplierId == 0);
                var newSuppliers      = notExistSuppliers.Select(x => x.Supplier).Distinct();
                if (newSuppliers.Any())
                {
                    var data = MaterialSupplierHelper.GetDetails(newSuppliers).ToDictionary(x => x.Supplier);
                    if (data.Count() != newSuppliers.Count())
                    {
                        MaterialSupplierHelper.Instance.Add(newSuppliers.Where(x => !data.ContainsKey(x)).Select(x => new MaterialSupplier
                        {
                            CreateUserId   = createUserId,
                            MarkedDateTime = markedDateTime,
                            Supplier       = x
                        }));
                        data = MaterialSupplierHelper.GetDetails(newSuppliers).ToDictionary(x => x.Supplier);
                    }
                    foreach (var bill in notExistSuppliers)
                    {
                        var key = bill.Supplier;
                        if (data.ContainsKey(key))
                        {
                            bill.SupplierId = data[key].Id;
                        }
                        else
                        {
                            return(Result.GenError <Result>(Error.MaterialSupplierNotEmpty));
                        }
                    }
                }

                #endregion

                #region 新编号
                var billI_0s = bills.Where(x => x.BillId == 0);
                if (billI_0s.Any())
                {
                    var errCodes = bills.GroupBy(x => new { x.CategoryId, x.NameId, x.SpecificationId }).Where(x => x.Count() > 1);
                    if (errCodes.Any())
                    {
                        return(Result.GenError <Result>(Error.MaterialCodeError));
                    }
                    MaterialBillHelper.Instance.Add(billI_0s.Select(x => new MaterialBill
                    {
                        CreateUserId    = createUserId,
                        MarkedDateTime  = markedDateTime,
                        Code            = x.Code,
                        CategoryId      = x.CategoryId,
                        NameId          = x.NameId,
                        SpecificationId = x.SpecificationId,
                        Unit            = x.Unit,
                        Stock           = x.Stock,
                        Remark          = x.Remark ?? "",
                        Images          = x.Images ?? "[]",
                        File            = x.File ?? "",
                        FileUrl         = x.FileUrl ?? "",
                    }));

                    var code_0s = billI_0s.Select(x => x.Code).Distinct();
                    var bill_0s = MaterialBillHelper.GetDetails(code_0s).ToDictionary(x => x.Code);
                    foreach (var bill in billI_0s)
                    {
                        var key = bill.Code;
                        if (bill_0s.ContainsKey(key))
                        {
                            bill.BillId = bill_0s[key].Id;
                        }
                    }

                    allBills.AddRange(bill_0s.Values.ToDictionary(x => x.Id, x =>
                    {
                        var y    = ClassExtension.CopyTo <MaterialBillDetail, Material>(x);
                        y.BillId = x.Id;
                        y.Exist  = false;
                        return(y);
                    }));
                }
                #endregion
            }
            #endregion

            #endregion

            var originBatch = MaterialBatchHelper.GetBatch(createUserId, markedDateTime);
            var addBatches  = erpBills.GroupBy(x => new { x.BillId, x.SupplierId }).Select(x =>
            {
                var bill               = x.First();
                var price              = bill.Price;
                originBatch.BillId     = x.Key.BillId;
                originBatch.Price      = price;
                originBatch.SupplierId = x.Key.SupplierId;
                bill.Number            = x.Sum(a => a.Number);
                return(new MaterialBatch(originBatch, bill));
            });

            MaterialBatchHelper.Instance.Add(addBatches);

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

            #region 更新
            var existBill = allBills.Where(x => erpBills.Any(y => y.BillId == x.Key) && x.Value.Exist).ToDictionary(x => x.Key, x => x.Value);
            if (existBill.Any())
            {
                foreach (var(key, bill) in existBill)
                {
                    bill.OldNumber = bill.Number;
                    bill.Number   += erpBills.Where(x => x.BillId == bill.Id).Sum(y => y.Number);
                    bill.InTime    = markedDateTime;
                }
                MaterialHelper.Increase(existBill.Values);
            }
            #endregion

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

            foreach (var erpBill in erpBills)
            {
                var oldMaterialPurchaseItem = oldPurchaseItems.FirstOrDefault(x => x.Id == erpBill.Id);
                if (oldMaterialPurchaseItem != null)
                {
                    oldMaterialPurchaseItem.BillId   = erpBill.BillId;
                    oldMaterialPurchaseItem.ThisCode = erpBill.Code;
                }
            }
            var logs = erpBills.Select(x =>
            {
                x.Type      = MaterialOp.入库;
                var batches = new List <MaterialBatch>();
                var batch   = newBatches[new Tuple <int, int, int>(originBatch.BatchId, x.BillId, x.SupplierId)];
                batches.Add(batch);
                var log = new MaterialLog(createUserId, markedDateTime, x.Type, x.Purpose ?? $"Erp采购", x.Number,
                                          allBills[x.BillId].Number, x.RelatedPerson, createUserId, allBills[x.BillId], batches);
                log.ItemId = x.Id;
                return(log);
            }).ToList();

            foreach (var item in oldPurchaseItems)
            {
                var purchaseItem = purchaseItems.FirstOrDefault(x => x.Id == item.Id);
                if (purchaseItem != null)
                {
                    if (item.Stock == 0)
                    {
                        item.IncreaseTime = markedDateTime;
                    }

                    item.MarkedDateTime = markedDateTime;
                    item.Stock         += purchaseItem.Count;
                    item.Count          = purchaseItem.Count;
                }
            }
            MaterialPurchaseItemHelper.Increase(oldPurchaseItems);
            if (allBills.Keys.Any())
            {
                HMaterialHelper.UpdateBillPrice(allBills.Keys);
            }
            Task.Run(() =>
            {
                if (logs.Any())
                {
                    MaterialLogHelper.Instance.Add(logs);
                }
            });
            //TimerHelper.MaterialRecovery(true);
            result.datas.AddRange(newBatches.Values.Select(x => new
            {
                x.Time,
                x.Id,
                x.BillId,
                x.Batch,
                x.Supplier,
                x.Price,
                allBills[x.BillId].Code,
                allBills[x.BillId].Name,
                allBills[x.BillId].Specification,
                allBills[x.BillId].Category,
                allBills[x.BillId].Site
            }));

            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));
        }