public IList<InventoryTransaction> ReturnProductRawMaterial(ReturnInput returnInput, DateTime effectiveDate)
        {
            #region 出生产线
            #region 查询生产线上物料
            IList<ProductLineLocationDetail> productLineLocationDetailList = null;
            if (returnInput.ProductLineLocationDetailId.HasValue)
            {
                string hql = "from ProductLineLocationDetail where Id = ? and IsClose = ? ";

                IList<object> para = new List<object>();
                para.Add(returnInput.ProductLineLocationDetailId.Value);
                para.Add(false);

                productLineLocationDetailList = this.genericMgr.FindAll<ProductLineLocationDetail>(hql, para.ToArray());

                if (productLineLocationDetailList != null && productLineLocationDetailList.Count > 0)
                {
                    OrderMaster orderMaster = this.genericMgr.FindById<OrderMaster>(productLineLocationDetailList[0].OrderNo);
                    FlowMaster flowMaster = this.genericMgr.FindById<FlowMaster>(productLineLocationDetailList[0].ProductLine);
                    Location location = this.genericMgr.FindById<Location>(productLineLocationDetailList[0].LocationFrom);
                    Item item = this.genericMgr.FindById<Item>(productLineLocationDetailList[0].Item);
                    returnInput.OrderNo = orderMaster.OrderNo;
                    returnInput.OrderType = orderMaster.Type;
                    returnInput.OrderSubType = orderMaster.SubType;
                    returnInput.TraceCode = productLineLocationDetailList[0].TraceCode;
                    returnInput.Item = productLineLocationDetailList[0].Item;
                    returnInput.Uom = item.Uom;
                    returnInput.BaseUom = item.Uom;
                    returnInput.UnitQty = 1;
                    returnInput.QualityType = productLineLocationDetailList[0].QualityType;
                    returnInput.HuId = productLineLocationDetailList[0].HuId;
                    returnInput.LotNo = productLineLocationDetailList[0].LotNo;
                    returnInput.CurrentProductLine = flowMaster;
                    returnInput.ProductLine = flowMaster.Code;
                    returnInput.CurrentLocationTo = location;
                }
            }
            else
            {
                string hql = "from ProductLineLocationDetail where ProductLine = ? and Item = ? and QualityType = ? and IsClose = ? ";
                IList<object> para = new List<object>();
                para.Add(returnInput.ProductLine);
                para.Add(returnInput.Item);
                para.Add(returnInput.QualityType);
                para.Add(false);

                if (!string.IsNullOrWhiteSpace(returnInput.ProductLineFacility))
                {
                    hql += " and ProductLineFacility = ?";
                    para.Add(returnInput.ProductLineFacility);
                }

                if (!string.IsNullOrWhiteSpace(returnInput.OrderNo))
                {
                    hql += " and OrderNo = ?";
                    para.Add(returnInput.OrderNo);

                    if (!string.IsNullOrWhiteSpace(returnInput.TraceCode))
                    {
                        hql += " and TraceCode = ?";
                        para.Add(returnInput.TraceCode);
                    }

                    if (returnInput.Operation.HasValue)
                    {
                        hql += " and Operation = ?";
                        para.Add(returnInput.Operation.Value);

                        if (!string.IsNullOrWhiteSpace(returnInput.OpReference))
                        {
                            hql += " and OpReference = ?";
                            para.Add(returnInput.OpReference);
                        }
                        else
                        {
                            //hql += " and OpReference is null";
                        }
                    }
                    else
                    {
                        //hql += " and Operation is null";
                    }
                }

                if (!string.IsNullOrWhiteSpace(returnInput.HuId))
                {
                    hql += " and HuId = ?";
                    para.Add(returnInput.HuId);
                }

                //hql += " order by CreateDate desc";  //
                productLineLocationDetailList = this.genericMgr.FindAll<ProductLineLocationDetail>(hql, para.ToArray());
            }
            #endregion

            #region 回冲生产线物料
            List<InventoryTransaction> issInventoryTransactionList = new List<InventoryTransaction>();
            decimal remainQty = returnInput.Qty * returnInput.UnitQty;  //转为库存单位
            if (productLineLocationDetailList != null && productLineLocationDetailList.Count > 0)
            {
                #region 循环扣减物料
                foreach (ProductLineLocationDetail productLineLocationDetail in productLineLocationDetailList)
                {
                    if (remainQty == 0)
                    {
                        break;
                    }

                    if (productLineLocationDetail.RemainBackFlushQty == 0)
                    {
                        continue;
                    }

                    InventoryTransaction inventoryTransaction = new InventoryTransaction();

                    if (productLineLocationDetail.RemainBackFlushQty >= remainQty)
                    {
                        productLineLocationDetail.VoidQty += remainQty;
                        inventoryTransaction.Qty = -remainQty;   //出库位负数
                        remainQty = 0;
                        if (productLineLocationDetail.RemainBackFlushQty == 0)
                        {
                            productLineLocationDetail.IsClose = true;
                        }
                    }
                    else
                    {
                        remainQty -= productLineLocationDetail.RemainBackFlushQty;
                        inventoryTransaction.Qty = -productLineLocationDetail.RemainBackFlushQty;   //出库位负数
                        productLineLocationDetail.VoidQty += productLineLocationDetail.RemainBackFlushQty;
                        productLineLocationDetail.IsClose = true;
                    }
                    inventoryTransaction.LocationLotDetailId = productLineLocationDetail.Id;
                    inventoryTransaction.Location = productLineLocationDetail.ProductLine;
                    inventoryTransaction.OrgLocation = productLineLocationDetail.LocationFrom;
                    inventoryTransaction.Bin = productLineLocationDetail.ProductLineFacility;
                    inventoryTransaction.Item = productLineLocationDetail.Item;
                    inventoryTransaction.HuId = productLineLocationDetail.HuId;
                    inventoryTransaction.LotNo = productLineLocationDetail.LotNo;
                    inventoryTransaction.IsCreatePlanBill = false;
                    inventoryTransaction.IsConsignment = productLineLocationDetail.IsConsignment;
                    inventoryTransaction.PlanBill = productLineLocationDetail.PlanBill;
                    if (inventoryTransaction.IsConsignment)
                    {
                        inventoryTransaction.PlanBillQty = inventoryTransaction.Qty;
                    }
                    inventoryTransaction.ActingBill = null;
                    inventoryTransaction.ActingBillQty = 0;
                    inventoryTransaction.QualityType = productLineLocationDetail.QualityType;
                    inventoryTransaction.IsATP = productLineLocationDetail.QualityType == com.Sconit.CodeMaster.QualityType.Qualified;
                    inventoryTransaction.IsFreeze = false;
                    inventoryTransaction.OccupyType = com.Sconit.CodeMaster.OccupyType.None;

                    issInventoryTransactionList.Add(inventoryTransaction);
                    this.genericMgr.Update(productLineLocationDetail);
                }
                #endregion
            }

            if (remainQty > 0)
            {
                if (!string.IsNullOrWhiteSpace(returnInput.HuId))
                {
                    throw new BusinessException("退料条码{0}在生产线{1}上不存在或余额不足。", returnInput.HuId, returnInput.ProductLine);
                }
                else
                {
                    throw new BusinessException("退料零件{0}在生产线{1}上余额不足。", returnInput.Item, returnInput.ProductLine);

                }
            }
            #endregion

            #region 记录退生产线事务
            if (issInventoryTransactionList.Count == 0)
            {
                throw new TechnicalException("Return InventoryTransaction is empty.");
            }

            RecordLocationTransaction(returnInput, effectiveDate, issInventoryTransactionList, true);
            #endregion
            #endregion

            #region 入库位
            var groupedInventoryTransactionList = from trans in issInventoryTransactionList
                                                  group trans by new
                                                  {
                                                      LocationTo = !string.IsNullOrWhiteSpace(returnInput.LocationTo) ? returnInput.LocationTo : trans.OrgLocation,
                                                      IsConsignment = trans.IsConsignment,
                                                      PlanBill = trans.PlanBill
                                                  } into result
                                                  select new
                                                  {
                                                      LocationTo = result.Key.LocationTo,
                                                      IsConsignment = result.Key.IsConsignment,
                                                      PlanBill = result.Key.PlanBill,
                                                      //Qty = result.Sum(trans => -trans.Qty),
                                                      Qty = result.Sum(trans => trans.Qty),
                                                  };

            List<InventoryTransaction> rctInventoryTransactionList = new List<InventoryTransaction>();
            foreach (var trans in groupedInventoryTransactionList)
            {
                InventoryIO inventoryIO = new InventoryIO();

                inventoryIO.Location = trans.LocationTo;
                inventoryIO.Item = returnInput.Item;
                inventoryIO.HuId = returnInput.HuId;
                inventoryIO.LotNo = returnInput.LotNo;
                inventoryIO.Qty = -trans.Qty;    //入库为正数
                inventoryIO.QualityType = returnInput.QualityType;
                inventoryIO.IsATP = returnInput.QualityType == com.Sconit.CodeMaster.QualityType.Qualified;
                inventoryIO.IsFreeze = false;
                inventoryIO.IsCreatePlanBill = false;
                inventoryIO.IsConsignment = trans.IsConsignment;
                inventoryIO.PlanBill = trans.PlanBill;
                inventoryIO.ActingBill = null;
                inventoryIO.TransactionType = com.Sconit.CodeMaster.TransactionType.RCT_MIN_RTN; //生产投料退库入库
                inventoryIO.OccupyType = com.Sconit.CodeMaster.OccupyType.None; //应该是非占用的零件才能投料
                //inventoryIO.OccupyReferenceNo = ipDetail.CurrentOccupyReferenceNo;
                inventoryIO.IsVoid = false;
                inventoryIO.EffectiveDate = effectiveDate;
                //inventoryIO.ManufactureParty = ;

                rctInventoryTransactionList.AddRange(RecordInventory(inventoryIO));
            }
            //记录出库事务
            RecordLocationTransaction(returnInput, effectiveDate, rctInventoryTransactionList, false);
            #endregion

            issInventoryTransactionList.AddRange(rctInventoryTransactionList);

            return issInventoryTransactionList;
        }
        private void RecordLocationTransaction(ReturnInput returnInput, DateTime effectiveDate, IList<InventoryTransaction> inventoryTransactionList, bool isIssue)  //isIssue区分是退料出生产线还是退料入库
        {
            var groupedInventoryTransactionList = from trans in inventoryTransactionList
                                                  group trans by new
                                                  {
                                                      //为了能够退料回原投料库位,要对LocationTo分组,如果指定了退料的出库库位则按照出库库位分组。
                                                      LocationTo = !string.IsNullOrWhiteSpace(returnInput.LocationTo) ? returnInput.LocationTo : (isIssue ? trans.OrgLocation : trans.Location),
                                                      IsConsignment = trans.IsConsignment,
                                                      PlanBill = trans.PlanBill,
                                                      ActingBill = trans.ActingBill
                                                  } into result
                                                  select new
                                                  {
                                                      LocationTo = result.Key.LocationTo,
                                                      IsConsignment = result.Key.IsConsignment,
                                                      PlanBill = result.Key.PlanBill,
                                                      ActingBill = result.Key.ActingBill,
                                                      //Qty = result.Sum(trans => isIssue ? -trans.Qty : trans.Qty),
                                                      Qty = result.Sum(trans => trans.Qty),
                                                      //PlanBillQty = result.Sum(trans => isIssue ? -trans.PlanBillQty : trans.PlanBillQty),
                                                      PlanBillQty = result.Sum(trans => trans.PlanBillQty),
                                                      //ActingBillQty = result.Sum(trans => isIssue ? -trans.ActingBillQty : trans.ActingBillQty),
                                                      ActingBillQty = result.Sum(trans => trans.ActingBillQty),
                                                      InventoryTransactionList = result.ToList()
                                                  };


            DateTime dateTimeNow = DateTime.Now;

            foreach (var trans in groupedInventoryTransactionList)
            {
                LocationTransaction locationTransaction = new LocationTransaction();
                if (returnInput.OrderNo != null)
                {
                    locationTransaction.OrderNo = returnInput.OrderNo;
                    locationTransaction.OrderType = returnInput.OrderType;
                    locationTransaction.OrderSubType = returnInput.OrderSubType;
                    //locationTransaction.OrderDetailSequence =
                    //locationTransaction.OrderDetailId =
                    //locationTransaction.OrderBomDetId = 
                }
                //locationTransaction.IpNo = 
                //locationTransaction.IpDetailId = 
                //locationTransaction.IpDetailSequence = 
                //locationTransaction.ReceiptNo = 
                //locationTransaction.ReceiptDetailId = 
                //locationTransaction.ReceiptDetailSequence = 
                //locationTransaction.SequenceNo = 
                locationTransaction.TraceCode = returnInput.TraceCode;
                locationTransaction.Item = returnInput.Item;
                locationTransaction.Uom = returnInput.Uom;
                locationTransaction.BaseUom = returnInput.BaseUom;
                locationTransaction.Qty = trans.Qty / returnInput.UnitQty;
                locationTransaction.UnitQty = returnInput.UnitQty;
                locationTransaction.IsConsignment = trans.IsConsignment;
                if (trans.IsConsignment && trans.PlanBill.HasValue)
                {
                    locationTransaction.PlanBill = trans.PlanBill.Value;
                }
                locationTransaction.PlanBillQty = trans.PlanBillQty / returnInput.UnitQty;
                if (trans.ActingBill.HasValue)
                {
                    locationTransaction.ActingBill = trans.ActingBill.Value;
                }
                locationTransaction.ActingBillQty = trans.ActingBillQty / returnInput.UnitQty;
                locationTransaction.QualityType = returnInput.QualityType;
                locationTransaction.HuId = returnInput.HuId;
                locationTransaction.LotNo = returnInput.LotNo;
                locationTransaction.TransactionType = isIssue ? com.Sconit.CodeMaster.TransactionType.ISS_MIN_RTN : com.Sconit.CodeMaster.TransactionType.RCT_MIN_RTN;
                locationTransaction.IOType = isIssue ? com.Sconit.CodeMaster.TransactionIOType.Out : com.Sconit.CodeMaster.TransactionIOType.In;
                locationTransaction.PartyFrom = returnInput.CurrentProductLine.PartyFrom;
                //如果指定了退料库位,直接取缓存的退料区域。如果没有指定,则查找原来投料的库位区域
                locationTransaction.PartyTo = !string.IsNullOrWhiteSpace(returnInput.LocationTo) ? returnInput.CurrentLocationTo.Region : this.genericMgr.FindById<Location>(trans.LocationTo).Region;
                locationTransaction.LocationFrom = returnInput.ProductLine;  //记录投料入的生产线
                locationTransaction.LocationTo = trans.LocationTo;
                locationTransaction.LocationIOReason = string.Empty;
                locationTransaction.EffectiveDate = effectiveDate;
                locationTransaction.CreateUserId = SecurityContextHolder.Get().Id;
                locationTransaction.CreateDate = dateTimeNow;

                this.genericMgr.Create(locationTransaction);

                RecordLocationTransactionDetail(locationTransaction, trans.InventoryTransactionList);
            }
        }
 public IList<InventoryTransaction> ReturnProductRawMaterial(ReturnInput returnInput)
 {
     return ReturnProductRawMaterial(returnInput, DateTime.Now);
 }