using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Data.Wms;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.WmsRepository.Entities;
using Siger.Middlelayer.WmsRepository.Repositories.Interface;
using Siger.Middlelayer.WmsRepository.Request;
using Siger.Middlelayer.WmsRepository.Response;
using Siger.Middlelayer.Common.Log;

namespace Siger.Middlelayer.WmsRepository.Repositories
{
    internal class siger_wms_stockRepository : WMSRepositoryBase<siger_wms_stock>, Isiger_wms_stockRepository
    {
        private readonly object lockObj = new object();
        private readonly ApiWmsDbContext dbContext;
        public siger_wms_stockRepository(ApiWmsDbContext context) : base(context)
        {
            dbContext = context;
        }

        public List<ResponseCheckIn> CheckIn(int projectId, int userId, RequestWaveHousing req, Isiger_wms_storage_locationRepository location, bool isReceiving)
        {
            if (req.count <= 0)
                throw new BadRequestException(RequestEnum.CountError);
            //检测单据是否存在
            //调拨接收
            if (isReceiving)
            {
                if (!dbContext.siger_wms_transfer_order_detail.Any(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == projectId))
                    throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            //正常入库
            else
            {
                if (!dbContext.siger_wms_stock_access_order_detail.Any(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == projectId))
                    throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            //检测选择的储位是否为最后一级储位
            var pids = dbContext.siger_wms_storage_location_type.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId).Select(f => f.parentid);
            var lastlocationType = dbContext.siger_wms_storage_location_type.Where(f => f.status == (int)RowState.Valid && !pids.Contains(f.id) && f.projectid == projectId).Select(f => f.id);
            if (!dbContext.siger_wms_storage_location.Any(f => f.id == req.locationid && f.status == (int)RowState.Valid && lastlocationType.Contains(f.typeid) && f.projectid == projectId))
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }

            //保存序号入库中的生成所有序号
            var stockNo = Guid.NewGuid().ToStr();
            string manage_mode;
            int qty;//总数
            int access_quantity;//现有
            int orderid;//单据id
            var Nos = new List<string>();
            siger_wms_transfer_order_detail receiveEntity = null;
            siger_wms_stock_access_order_detail stockEntity = null;
            siger_wms_stock_access_order stockOrderData = null;
            siger_wms_transfer_order receiveOrderData = null;

            string order_number = "";
            int material_id;
            string material_pn = "";
            string material_name = "";
            string material_spec = "";
            if (isReceiving)
            {
                receiveEntity = dbContext.siger_wms_transfer_order_detail.FirstOrDefault(f => f.id == req.id && f.projectid == projectId && f.status == (int)RowState.Valid);
                if (receiveEntity == null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }
                //查询管理模式
                var material = dbContext.siger_tr_materials.FirstOrDefault(f => f.id == receiveEntity.material_id && f.projectId == projectId && f.status == (int)RowState.Valid);
                if (material == null)
                {
                    throw new BadRequestException(RequestEnum.MaterialNotExist);
                }
                manage_mode = material.manage_mode;
                qty = receiveEntity.quantity;
                access_quantity = receiveEntity.receive_quantity;
                orderid = receiveEntity.orderid;
                material_id = receiveEntity.material_id;
                material_pn = receiveEntity.material_pn;
                material_name = receiveEntity.material_name;
                material_spec = receiveEntity.material_spec;
            }
            else
            {
                stockEntity = dbContext.siger_wms_stock_access_order_detail.FirstOrDefault(f => f.id == req.id && f.projectid == projectId && f.status == (int)RowState.Valid);
                if (stockEntity == null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }
                manage_mode = stockEntity.manage_mode;
                qty = stockEntity.quantity;
                access_quantity = stockEntity.access_quantity;
                orderid = stockEntity.orderid;
                material_id = stockEntity.material_id;
                material_pn = stockEntity.material_pn;
                material_name = stockEntity.material_name;
                material_spec = stockEntity.material_spec;
            }

            //check管理模式
            if (int.TryParse(manage_mode, out int mode))
            {
                if ((int)req.type != mode)
                {
                    throw new BadRequestException(RequestEnum.ManageModeNotMatching);
                }
            }
            if (qty < (access_quantity + req.count))
            {
                throw new BadRequestException(RequestEnum.CountInsufficient);
            }
            //审核通过才允许入库
            int storageid;//单据中的仓库
            if (isReceiving)
            {
                receiveOrderData = dbContext.siger_wms_transfer_order.FirstOrDefault(f => f.id == orderid && f.status == (int)RowState.Valid && f.projectid == projectId);
                if (receiveOrderData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                //待接收、接收中
                if (receiveOrderData.order_status != (int)AlloactionStatu.WaittingReceiving && receiveOrderData.order_status != (int)AlloactionStatu.Receiving)
                {
                    throw new BadRequestException(RequestEnum.ErrorState);
                }
                storageid = receiveOrderData.end_storage_id;
                order_number = receiveOrderData.order_number;
            }
            else
            {
                stockOrderData = dbContext.siger_wms_stock_access_order.FirstOrDefault(f => f.access_type == (int)WaveHouseType.In && f.id == orderid && f.status == (int)RowState.Valid
                                        && f.projectid == projectId);
                if (stockOrderData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                if (stockOrderData.order_status != (int)WaveHousingState.Checked && stockOrderData.order_status != (int)WaveHousingState.WaveHousing)
                {
                    throw new BadRequestException(RequestEnum.ErrorState);
                }
                storageid = stockOrderData.storageid;
                order_number = stockOrderData.order_number;
            }

            //储位是否为待入库仓
            var locationdata = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.id == req.locationid && f.status == (int)RowState.Valid);
            if (locationdata == null)
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            if (locationdata.storageid != storageid)
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            var tracedata = new siger_wms_stock_detail(stockNo, req.UserId, GetUserName(userId), req.ProjectId);
            if (isReceiving)
            {
                tracedata.type = (int)traceType.AllocationReceive;
                //供应商信息
                if (req.businessID != 0)
                {
                    //将供应商信息存入详情中
                    //供应商信息
                    var businessName = GetBusinessName(req.businessID, projectId);
                    tracedata.businessid = req.businessID;
                    tracedata.businessName = businessName;
                }
            }
            else
            {
                tracedata.type = (int)traceType.WaveHousing;
                if (req.businessID != 0)
                {
                    //将供应商信息存入详情中
                    if (stockOrderData.category != WaveHousingType.Production.ToString() &&
                        stockOrderData.category != WaveHousingType.ProductionOut.ToString() &&
                        stockOrderData.category != WaveHousingType.OtherOut.ToString())
                    {
                        //供应商信息
                        var businessName = GetBusinessName(req.businessID, projectId);
                        tracedata.businessid = req.businessID;
                        tracedata.businessName = businessName;
                    }
                }
                else
                {
                    if (stockOrderData.category != EnumHelper.GetEnumDesc(WaveHousingType.Production))
                    {
                        throw new BadRequestException(RequestEnum.BusinessNameNotNull);
                    }
                }
            }

            tracedata.billID = order_number;
            tracedata.inventory = material_id;
            tracedata.inventorySN = material_pn;
            tracedata.inventoryName = material_name;
            tracedata.allqty = qty;
            tracedata.qty = req.count;
            tracedata.userid = userId;
            tracedata.username = GetUserName(userId);
            tracedata.updatetime = DateTime.Now;
            tracedata.state = (int)RowState.Valid;
            tracedata.projectid = projectId;
            tracedata.locationid = req.locationid;
            tracedata.locationname = locationdata.name;
            tracedata.inventorySpec = material_spec;

            switch (req.type)
            {
                //批次
                case managemodel.Batch:
                    if (req.productingTime == null || req.productingTime == DateTime.MinValue)
                    {
                        tracedata.productingtime = DateTime.Now;
                    }
                    else
                    {
                        tracedata.productingtime = (DateTime)req.productingTime;
                    }
                    //每次都生成批次号
                    tracedata.fromsourcebatch = req.useSourceBatch == 0 ? 0 : 1;
                    if (tracedata.fromsourcebatch == 1)
                    {

                        if (!string.IsNullOrEmpty(req.batchCode))
                        {
                            tracedata.batch = req.batchCode;
                            if (!isReceiving)
                            {
                                stockEntity.batch_number = tracedata.batch;
                            }
                        }
                        else
                        {
                            var result = "";
                            GetBillIDs(Settings.SystemBatchPre, projectId);
                            tracedata.batch = result;
                            if (!isReceiving)
                            {
                                stockEntity.batch_number = tracedata.batch;
                            }
                        }
                    }
                    else
                    {
                        var result = GetBillIDs(Settings.SystemBatchPre, projectId);
                        tracedata.batch = result;
                        if (!isReceiving)
                        {
                            stockEntity.batch_number = tracedata.batch;
                        }
                    }
                    dbContext.siger_wms_stock_detail.Add(tracedata);
                    break;
                //序号
                case managemodel.No:
                    if (req.useSourceBatch == 1)
                    {
                        req.count = 1;
                    }
                    for (int i = 0; i < req.count; i++)
                    {
                        //序号入库只能一件件入
                        tracedata = new siger_wms_stock_detail(stockNo, req.UserId, GetUserName(userId), req.ProjectId);
                        tracedata.locationid = req.locationid;
                        if (isReceiving)
                        {
                            tracedata.type = (int)traceType.AllocationReceive;
                        }
                        else
                        {
                            tracedata.type = (int)traceType.WaveHousing;
                        }
                        tracedata.billID = order_number;
                        tracedata.inventory = material_id;
                        tracedata.inventorySN = material_pn;
                        tracedata.inventoryName = material_name;
                        tracedata.allqty = qty;
                        tracedata.qty = 1;
                        tracedata.userid = userId;
                        tracedata.username = GetUserName(userId);
                        tracedata.updatetime = DateTime.Now;
                        tracedata.state = (int)RowState.Valid;
                        tracedata.projectid = projectId;
                        tracedata.fromsourcebatch = req.useSourceBatch == 0 ? 0 : 1;
                        tracedata.locationname = locationdata.name;
                        tracedata.inventorySpec = material_spec;
                        if (req.businessID != 0)
                        {
                            if (isReceiving)
                            {
                                //将供应商信息存入详情中
                                if (receiveOrderData.order_status == (int)AlloactionStatu.Receiving ||
                                    receiveOrderData.order_status == (int)AlloactionStatu.WaittingReceiving)
                                {
                                    //供应商信息
                                    var businessName = GetBusinessName(req.businessID, projectId);
                                    tracedata.businessid = req.businessID;
                                    tracedata.businessName = businessName;
                                }
                            }
                            else
                            {
                                //将供应商信息存入详情中
                                if (stockOrderData.category != WaveHousingType.Production.ToString() &&
                                    stockOrderData.category != WaveHousingType.ProductionOut.ToString() &&
                                    stockOrderData.category != WaveHousingType.OtherOut.ToString())
                                {
                                    //供应商信息
                                    var businessName = GetBusinessName(req.businessID, projectId);
                                    tracedata.businessid = req.businessID;
                                    tracedata.businessName = businessName;
                                }
                            }
                        }
                        else
                        {
                            if (stockOrderData.category != EnumHelper.GetEnumDesc(WaveHousingType.Production))
                            {
                                throw new BadRequestException(RequestEnum.BusinessNameNotNull);
                            }
                        }

                        if (string.IsNullOrEmpty(req.No))
                        {
                            var inventoryLevel = location.GenInventoryLevel(material_id, projectId);
                            tracedata.no = GetSn(inventoryLevel);
                            if (!isReceiving)
                            {
                                stockEntity.serial_number = tracedata.no;
                            }
                        }
                        else
                        {
                            tracedata.no = req.No.Trim();
                            if (!isReceiving)
                            {
                                stockEntity.serial_number = tracedata.no;
                            }
                        }

                        dbContext.siger_wms_stock_detail.Add(tracedata);
                        Nos.Add(tracedata.no);
                    }
                    break;
                case managemodel.Group:
                    dbContext.siger_wms_stock_detail.Add(tracedata);
                    break;
                default:
                    break;
            }

            //更新数量
            if (isReceiving)
            {
                receiveEntity.receive_quantity += req.count;
                receiveEntity.updator = userId;
                receiveEntity.update_time = DateTime.Now;
                dbContext.siger_wms_transfer_order_detail.Update(receiveEntity);
                //更新单据状态
                if (receiveOrderData.order_status == (int)AlloactionStatu.WaittingReceiving)
                {
                    receiveOrderData.order_status = (int)AlloactionStatu.Receiving;
                }

                receiveOrderData.update_time = DateTime.Now;
                receiveOrderData.updator = userId;

                dbContext.siger_wms_transfer_order.Update(receiveOrderData);
            }
            else
            {
                stockEntity.access_quantity += req.count;
                stockEntity.updator = userId;
                stockEntity.update_time = DateTime.Now;
                dbContext.siger_wms_stock_access_order_detail.Update(stockEntity);
                //更新单据状态
                if (stockOrderData.order_status == (int)WaveHousingState.Checked)
                {
                    stockOrderData.order_status = (int)WaveHousingState.WaveHousing;
                }

                stockOrderData.update_time = DateTime.Now;
                stockOrderData.updator = userId;

                dbContext.siger_wms_stock_access_order.Update(stockOrderData);
            }

            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }

            //根据入库情况更新单据信息
            if (isReceiving)
            {
                if (!dbContext.siger_wms_transfer_order_detail.Any(f => f.orderid == receiveOrderData.id && f.status == (int)RowState.Valid && f.projectid == projectId && f.receive_quantity != f.quantity))
                {
                    receiveOrderData.order_status = (int)AlloactionStatu.Finish;
                    dbContext.siger_wms_transfer_order.Update(receiveOrderData);
                }
            }
            else
            {
                if (!dbContext.siger_wms_stock_access_order_detail.Any(f => f.orderid == stockOrderData.id && f.status == (int)RowState.Valid && f.projectid == projectId && f.access_quantity != f.quantity))
                {
                    stockOrderData.order_status = (int)WaveHousingState.Finish;
                    dbContext.siger_wms_stock_access_order.Update(stockOrderData);
                }
            }

            //添加库存
            var stockdata = dbContext.siger_wms_stock.FirstOrDefault(f => f.storage_location_id == req.locationid && f.material_id == req.id && f.status == (int)RowState.Valid &&
                                                    f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId);
            switch (req.type)
            {
                case managemodel.Batch:
                    if (!string.IsNullOrEmpty(req.batchCode))
                    {
                        stockdata = dbContext.siger_wms_stock.FirstOrDefault(f => f.batch_number == req.batchCode && f.storage_location_id == req.locationid && f.material_id == req.id &&
                                        f.status == (int)RowState.Valid && f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.businessid == req.businessID);
                    }
                    break;
                case managemodel.No:
                    if (!string.IsNullOrEmpty(req.No))
                    {
                        stockdata = dbContext.siger_wms_stock.FirstOrDefault(f => f.serial_number == req.No && f.status == (int)RowState.Valid &&
                                            f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.businessid == req.businessID);
                    }
                    break;
                case managemodel.Group:
                    break;
                default:
                    break;
            }
            //更新库存
            var stockResult = new List<ResponseCheckIn>();
            var tmp = new siger_wms_stock { stockNo = stockNo };
            if (stockdata == null)
            {
                int count = req.count;
                if (req.type == managemodel.No)
                {
                    for (int i = 0; i < req.count; i++)
                    {
                        try
                        {
                            tmp.storage_location_id = req.locationid;
                            tmp.material_id = material_id;
                            tmp.manage_model = manage_mode;
                            tmp.material_name = material_name;
                            tmp.material_pn = material_pn;
                            tmp.material_spec = material_spec;
                            tmp.category = manage_mode;
                            tmp.batch_number = "";
                            tmp.serial_number = Nos[i];
                            tmp.quantity = 1;
                            tmp.create_time = DateTime.Now;
                            tmp.creator = userId;
                            tmp.update_time = DateTime.Now;
                            tmp.updator = userId;
                            tmp.projectid = projectId;
                            tmp.status = (int)RowState.Valid;
                            tmp.stock_state = (int)StockEnum.InWavehouse;
                            tmp.businessid = req.businessID;
                            dbContext.siger_wms_stock.Add(tmp);
                            stockResult.Add(new ResponseCheckIn
                            {
                                code = tmp.serial_number,
                                time = tmp.update_time.ToString(UnixTimeHelper.DateFormat),
                                material_name = tmp.material_name,
                                material_spec = tmp.material_spec,
                                material_id = material_id,
                            });
                        }
                        catch (Exception)
                        {
                            throw new BadRequestException(RequestEnum.GenNoError);
                        }
                    }
                    AddStockChange(storageid, material_id, req.count, projectId);
                }
                else
                {
                    try
                    {
                        tmp.storage_location_id = req.locationid;
                        tmp.material_id = material_id;
                        tmp.manage_model = manage_mode;
                        tmp.material_name = material_name;
                        tmp.material_pn = material_pn;
                        tmp.material_spec = material_spec;
                        tmp.category = manage_mode;
                        tmp.batch_number = tracedata.batch;
                        tmp.serial_number = "";
                        tmp.quantity = count;
                        tmp.create_time = DateTime.Now;
                        tmp.creator = userId;
                        tmp.update_time = DateTime.Now;
                        tmp.updator = userId;
                        tmp.projectid = projectId;
                        tmp.status = (int)RowState.Valid;
                        tmp.stock_state = (int)StockEnum.InWavehouse;
                        tmp.businessid = req.businessID;

                        dbContext.siger_wms_stock.Add(tmp);
                        stockResult.Add(new ResponseCheckIn
                        {
                            code = tmp.batch_number,
                            time = tmp.update_time.ToString(UnixTimeHelper.DateFormat),
                            material_name = tmp.material_name,
                            material_spec = tmp.material_spec,
                            material_id = material_id,
                        });
                        AddStockChange(storageid, material_id, count, projectId);
                    }
                    catch (Exception)
                    {
                        throw new BadRequestException(RequestEnum.GenNoError);
                    }
                }
            }
            else
            {
                if (req.type == managemodel.No)
                {
                    throw new BadRequestException(RequestEnum.NoExist);
                }
                stockdata.quantity += req.count;
                dbContext.siger_wms_stock.Update(stockdata);
            }
            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
            //init tlm test record
            foreach (var item in stockResult)
            {
                var toolData = dbContext.siger_project_toollife_tool.Where(f => f.project_id == projectId && f.status != 0 && f.material_id == item.material_id).OrderByDescending(o => o.id).FirstOrDefault();
                if (toolData != null)
                {
                    dbContext.siger_project_toollife_detection_record.Add(new ProjectToollifeDetectionRecordEntityEx
                    {
                        OrderNumber = Guid.NewGuid().ToStr(),
                        CreateTime = DateTime.Now,
                        Creator = userId,
                        Editor = userId,
                        Projectid = projectId,
                        result = 0,
                        State = 1,
                        ToolId = toolData.id,
                        ToolType = toolData.category,
                        StockId = tmp?.id ?? 0,
                        serial_number = req.type == managemodel.No ? tmp.serial_number : tmp.batch_number,
                        manage_model = req.type
                    });
                }
                var imsData = dbContext.siger_project_ims_tool.Where(f => f.project_id == projectId && f.status != 0 && f.material_id == item.material_id).OrderByDescending(o => o.id).FirstOrDefault();
                if (imsData != null)
                {
                    dbContext.siger_project_ims_detection_record.Add(new ProjectIMSDetectionRecordEntityEx
                    {
                        OrderNumber = Guid.NewGuid().ToStr(),
                        CreateTime = DateTime.Now,
                        Creator = userId,
                        Editor = userId,
                        Projectid = projectId,
                        result = 0,
                        State = 1,
                        ToolId = toolData.id,
                        ToolType = toolData.category,
                        StockId = tmp?.id ?? 0,
                        serial_number = req.type == managemodel.No ? tmp.serial_number : tmp.batch_number,
                        manage_model = req.type
                    });
                }
                if (dbContext.SaveChanges() <= 0)
                {
                    throw new BadRequestException(CommonEnum.Fail);
                }
            }
            return stockResult;
        }

        public List<ResponseCheckIn> CheckIn(RequestWaveHousing req)
        {
            var isReceiving = req.isReceiving == 1;
            var projectId = req.ProjectId;
            var mid = req.UserId;
            var stockNo = Guid.NewGuid().ToString();
            var materialId = 0;//物料id
            var storageid = 0;//仓库id
            var tracedata = new siger_wms_stock_detail(stockNo, req.UserId, GetUserName(req.UserId), req.ProjectId);//历史
            var stockModel = new siger_wms_stock { projectid = req.ProjectId, create_time = tracedata.updatetime };//stock
            var Nos = new List<string>();
            if (req.count <= 0)
            {
                throw new BadRequestException(RequestEnum.CountError);
            }
            //检测选择的储位是否为最后一级储位
            var pids = dbContext.siger_wms_storage_location_type.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId).Select(f => f.parentid);
            var lastlocationType = dbContext.siger_wms_storage_location_type.Where(f => f.status == (int)RowState.Valid && !pids.Contains(f.id) && f.projectid == projectId).Select(f => f.id);
            if (!dbContext.siger_wms_storage_location.Any(f => f.id == req.locationid && f.status == (int)RowState.Valid && lastlocationType.Contains(f.typeid) && f.projectid == projectId))
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            //储位是否为待入库仓
            var locationData = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.id == req.locationid && f.status == (int)RowState.Valid);
            if (locationData == null)
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            //init location
            tracedata.locationid = req.locationid;
            tracedata.locationname = locationData.name;

            //调拨接收
            if (isReceiving)
            {
                //check
                var transferDetailData = dbContext.siger_wms_transfer_order_detail.FirstOrDefault(f => f.projectid == projectId && f.status != 0 && f.id == req.id);
                if (transferDetailData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                var transferData = dbContext.siger_wms_transfer_order.FirstOrDefault(f => f.id == transferDetailData.orderid && f.status != 0 && f.projectid == projectId);
                if (transferData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                //待接收、接收中
                if (transferData.order_status != (int)AlloactionStatu.WaittingReceiving && transferData.order_status != (int)AlloactionStatu.Receiving)
                {
                    throw new BadRequestException(RequestEnum.ErrorState);
                }
                if (locationData.storageid != transferData.end_storage_id)
                {
                    throw new BadRequestException(RequestEnum.LocationError);
                }
                //数量
                if (transferDetailData.quantity < (req.count + transferDetailData.receive_quantity))
                {
                    throw new BadRequestException(RequestEnum.CountInsufficient);
                }
                //更新单据状态
                transferDetailData.receive_quantity += req.count;
                transferDetailData.updator = req.UserId;
                transferDetailData.update_time = DateTime.Now;
                dbContext.siger_wms_transfer_order_detail.Update(transferDetailData);
                if (transferData.order_status == (int)AlloactionStatu.WaittingReceiving)
                {
                    transferData.order_status = (int)AlloactionStatu.Receiving;
                }
                transferData.update_time = DateTime.Now;
                transferData.updator = req.UserId;
                if (!dbContext.siger_wms_transfer_order_detail.Any(f => f.orderid == transferData.id && f.status == (int)RowState.Valid && f.projectid == projectId && f.receive_quantity != f.quantity))
                {
                    transferData.order_status = (int)AlloactionStatu.Finish;
                }
                dbContext.siger_wms_transfer_order.Update(transferData);

                //init model
                tracedata.type = (int)traceType.AllocationReceive;
                //init供应商信息
                if (req.businessID != 0)
                {
                    //将供应商信息存入详情中
                    //供应商信息
                    var businessName = GetBusinessName(req.businessID, projectId);
                    tracedata.businessid = req.businessID;
                    tracedata.businessName = businessName;
                }
                //init
                tracedata.billID = transferDetailData.order_number;
                tracedata.inventory = transferDetailData.material_id;
                tracedata.inventorySN = transferDetailData.material_pn;
                tracedata.inventoryName = transferDetailData.material_name;
                tracedata.inventorySpec = transferDetailData.material_spec;
                tracedata.allqty = transferDetailData.quantity;
                tracedata.qty = req.count;
                storageid = transferData.end_storage_id;
                materialId = transferDetailData.material_id;
            }
            //正常入库
            else
            {
                //check
                var stockDetailData = dbContext.siger_wms_stock_access_order_detail.FirstOrDefault(f => f.projectid == projectId && f.status != 0 && f.id == req.id);
                if (stockDetailData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                var stockData = dbContext.siger_wms_stock_access_order.FirstOrDefault(f => f.access_type == (int)WaveHouseType.In && f.id == stockDetailData.orderid && f.status != 0 && f.projectid == projectId);
                if (stockData == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                if (stockData.order_status != (int)WaveHousingState.Checked && stockData.order_status != (int)WaveHousingState.WaveHousing)
                {
                    throw new BadRequestException(RequestEnum.ErrorState);
                }
                if (locationData.storageid != stockData.storageid)
                {
                    throw new BadRequestException(RequestEnum.LocationError);
                }
                //数量
                if (stockDetailData.quantity < (req.count + stockDetailData.access_quantity))
                {
                    throw new BadRequestException(RequestEnum.CountInsufficient);
                }
                //更新单据状态
                stockDetailData.access_quantity += req.count;
                stockDetailData.updator = req.UserId;
                stockDetailData.update_time = DateTime.Now;
                dbContext.siger_wms_stock_access_order_detail.Update(stockDetailData);
                if (stockData.order_status == (int)WaveHousingState.Checked)
                {
                    stockData.order_status = (int)WaveHousingState.WaveHousing;
                }
                stockData.update_time = DateTime.Now;
                stockData.updator = req.UserId;
                var cruentExist = stockDetailData.quantity == stockDetailData.access_quantity;
                var detailExist = dbContext.siger_wms_stock_access_order_detail.Any(f => f.orderid == stockData.id && f.status == (int)RowState.Valid && f.projectid == projectId && f.id != stockDetailData.id && f.access_quantity != f.quantity);
                if (!detailExist && cruentExist)
                {
                    stockData.order_status = (int)WaveHousingState.Finish;
                }
                dbContext.siger_wms_stock_access_order.Update(stockData);

                //init model
                tracedata.type = (int)traceType.WaveHousing;
                //init供应商信息
                //将供应商信息存入详情中
                if (stockData.category != WaveHousingType.Production.ToString() &&
                    stockData.category != WaveHousingType.ProductionOut.ToString() &&
                    stockData.category != WaveHousingType.OtherOut.ToString() &&
                    req.businessID != 0)
                {
                    //供应商信息
                    var businessName = GetBusinessName(req.businessID, projectId);
                    tracedata.businessid = req.businessID;
                    tracedata.businessName = businessName;
                }
                else if (stockData.category != WaveHousingType.Production.ToString())
                {
                    throw new BadRequestException(RequestEnum.BusinessNameNotNull);
                }
                //init
                tracedata.billID = stockData.order_number;
                tracedata.inventory = stockDetailData.material_id;
                tracedata.inventorySN = stockDetailData.material_pn;
                tracedata.inventoryName = stockDetailData.material_name;
                tracedata.inventorySpec = stockDetailData.material_spec;
                tracedata.allqty = stockDetailData.quantity;
                tracedata.qty = req.count;
                storageid = stockData.storageid;
                materialId = stockDetailData.material_id;
            }
            //管理模式(latest)
            var materialModel = dbContext.siger_tr_materials.FirstOrDefault(f => f.projectId == projectId && f.status != 0 && f.id == materialId);
            if (materialModel.manage_mode.ToInt() != (int)req.type)
            {
                throw new BadRequestException(RequestEnum.ManageModeNotMatching);
            }
            //添加库存
            var wmsStockData = dbContext.siger_wms_stock.FirstOrDefault(f => f.storage_location_id == req.locationid && f.material_id == req.id && f.status == (int)RowState.Valid &&
                                                    f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId);

            switch (req.type)
            {
                //批次
                case managemodel.Batch:
                    //wmsStock
                    if (!string.IsNullOrEmpty(req.batchCode))
                    {
                        wmsStockData = dbContext.siger_wms_stock.FirstOrDefault(f => f.batch_number == req.batchCode && f.storage_location_id == req.locationid && f.material_id == req.id &&
                                        f.status == (int)RowState.Valid && f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.businessid == req.businessID);
                    }
                    if (req.productingTime == null || req.productingTime == DateTime.MinValue)
                    {
                        tracedata.productingtime = DateTime.Now;
                    }
                    else
                    {
                        tracedata.productingtime = (DateTime)req.productingTime;
                    }
                    //每次都生成批次号
                    tracedata.fromsourcebatch = req.useSourceBatch == 0 ? 0 : 1;
                    if (tracedata.fromsourcebatch == 1)
                    {

                        if (!string.IsNullOrEmpty(req.batchCode))
                        {
                            tracedata.batch = req.batchCode;
                            if (!isReceiving)
                            {
                                stockModel.batch_number = tracedata.batch;
                            }
                        }
                        else
                        {
                            tracedata.batch = "";
                            if (!isReceiving)
                            {
                                stockModel.batch_number = tracedata.batch;
                            }
                        }
                    }
                    else
                    {
                        tracedata.batch = GetBillIDs(Settings.SystemBatchPre, projectId);
                        if (!isReceiving)
                        {
                            stockModel.batch_number = tracedata.batch;
                        }
                    }
                    dbContext.siger_wms_stock_detail.Add(tracedata);
                    break;
                //序号
                case managemodel.No:
                    //wmsStock
                    if (!string.IsNullOrEmpty(req.No))
                    {
                        wmsStockData = dbContext.siger_wms_stock.FirstOrDefault(f => f.serial_number == req.No && f.status == (int)RowState.Valid &&
                                            f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.businessid == req.businessID);
                    }

                    if (req.useSourceBatch == 1)
                    {
                        req.count = 1;
                    }
                    for (int i = 0; i < req.count; i++)
                    {
                        //序号入库只能一件件入
                        var detail = Mapper<siger_wms_stock_detail, siger_wms_stock_detail>.Map(tracedata);
                        detail.qty = 1;
                        if (string.IsNullOrEmpty(req.No))
                        {
                            var inventoryLevel = GenInventoryLevel(tracedata.inventory, projectId);
                            detail.no = GetSn(inventoryLevel);
                        }
                        else
                        {
                            detail.no = req.No.Trim();
                        }
                        if (!isReceiving)
                        {
                            stockModel.serial_number = detail.no;
                        }
                        dbContext.siger_wms_stock_detail.Add(detail);
                        Nos.Add(detail.no);
                    }
                    break;
                case managemodel.Group:
                    dbContext.siger_wms_stock_detail.Add(tracedata);
                    break;
                default:
                    break;
            }

            //更新库存
            var stockResult = new List<ResponseCheckIn>();

            if (wmsStockData == null)
            {
                wmsStockData = new siger_wms_stock
                {
                    stockNo = stockNo,
                    material_id = tracedata.inventory,
                    manage_model = ((int)req.type).ToStr(),
                    material_name = tracedata.inventoryName,
                    material_pn = tracedata.inventorySN,
                    material_spec = tracedata.inventorySpec,
                    category = ((int)req.type).ToStr(),
                    batch_number = string.Empty,
                    serial_number = string.Empty,
                    quantity = 1,
                    create_time = DateTime.Now,
                    creator = req.UserId,
                    update_time = DateTime.Now,
                    updator = req.UserId,
                    projectid = projectId,
                    status = (int)RowState.Valid,
                    stock_state = (int)StockEnum.InWavehouse,
                    businessid = req.businessID,
                    storage_location_id = req.locationid
                };
                if (req.type == managemodel.No)
                {
                    for (int i = 0; i < req.count; i++)
                    {
                        var newStock = Mapper<siger_wms_stock, siger_wms_stock>.Map(wmsStockData);
                        newStock.serial_number = Nos[i];
                        dbContext.siger_wms_stock.Add(newStock);
                        stockResult.Add(new ResponseCheckIn
                        {
                            code = newStock.serial_number,
                            time = newStock.update_time.ToString(UnixTimeHelper.DateFormat),
                            material_name = newStock.material_name,
                            material_spec = newStock.material_spec,
                            material_id = newStock.material_id,
                        });
                    }
                }
                else
                {
                    wmsStockData.batch_number = tracedata.batch;
                    wmsStockData.quantity = req.count;
                    dbContext.siger_wms_stock.Add(wmsStockData);
                    stockResult.Add(new ResponseCheckIn
                    {
                        code = wmsStockData.batch_number,
                        time = wmsStockData.update_time.ToString(UnixTimeHelper.DateFormat),
                        material_name = wmsStockData.material_name,
                        material_spec = wmsStockData.material_spec,
                        material_id = wmsStockData.material_id,
                    });
                }
                AddStockChange(storageid, wmsStockData.material_id, req.count, projectId);
            }
            else
            {
                if (req.type == managemodel.No)
                {
                    throw new BadRequestException(RequestEnum.NoExist);
                }
                stockModel.quantity += req.count;
                dbContext.siger_wms_stock.Update(stockModel);
            }
            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
            var newStockData = GetList(f => f.projectid == projectId && f.status != 0 && f.stockNo == stockNo).ToList();
            foreach (var item in newStockData)
            {
                //init tlm or ims test record
                var toolData = dbContext.siger_project_toollife_tool.Where(f => f.project_id == projectId && f.status != 0 && f.material_id == item.material_id).OrderByDescending(o => o.id).FirstOrDefault();
                var imsData = dbContext.siger_project_ims_tool.Where(f => f.project_id == projectId && f.status != 0 && f.material_id == item.material_id).OrderByDescending(o => o.id).FirstOrDefault();
                if (toolData != null)
                {
                    dbContext.siger_project_toollife_detection_record.Add(new ProjectToollifeDetectionRecordEntityEx
                    {
                        OrderNumber = Guid.NewGuid().ToStr(),
                        CreateTime = DateTime.Now,
                        Creator = req.UserId,
                        Editor = req.UserId,
                        Projectid = projectId,
                        result = 0,
                        State = 1,
                        ToolId = toolData.id,
                        ToolType = toolData.category,
                        StockId = item.id,
                        serial_number = !string.IsNullOrEmpty(item.serial_number) ? item.serial_number : !string.IsNullOrEmpty(item.batch_number) ? item.batch_number : "",
                        manage_model = req.type
                    });
                    if (dbContext.SaveChanges() <= 0)
                    {
                        throw new BadRequestException(CommonEnum.Fail);
                    }
                }
                if (imsData != null)
                {
                    dbContext.siger_project_ims_detection_record.Add(new ProjectIMSDetectionRecordEntityEx
                    {
                        OrderNumber = Guid.NewGuid().ToStr(),
                        CreateTime = DateTime.Now,
                        Creator = req.UserId,
                        Editor = req.UserId,
                        Projectid = projectId,
                        result = 0,
                        State = 1,
                        ToolId = imsData.id,
                        ToolType = imsData.category,
                        StockId = item.id,
                        serial_number = !string.IsNullOrEmpty(item.serial_number) ? item.serial_number : !string.IsNullOrEmpty(item.batch_number) ? item.batch_number : "",
                        manage_model = req.type
                    });
                    if (dbContext.SaveChanges() <= 0)
                    {
                        throw new BadRequestException(CommonEnum.Fail);
                    }
                }
            }
            return stockResult;
        }

        public IEnumerable<ResponseInventoryInfo> GetAllocationInventoryList(int projectId, string billCode)
        {
            int i = 0;
            if (string.IsNullOrEmpty(billCode))
            {
                var data = dbContext.siger_tr_materials.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId);
                var result = data.Select(f => f.pn).Distinct().ToList().Select(f => new ResponseInventoryInfo
                {
                    id = i++,
                    name = f
                });
                return result.ToList();
            }
            else
            {
                var data = dbContext.siger_wms_transfer_order_detail.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.order_number == billCode.Trim());
                var result = data.Select(f => f.material_pn).Distinct().ToList().Select(f => new ResponseInventoryInfo
                {
                    id = i++,
                    name = f
                });
                return result.ToList();
            }
            throw new System.NotImplementedException();
        }

        public IEnumerable<ResponseIdName> GetBusinessList(int materialID, int projectId)
        {
            var businessid = new List<int>();
            if (materialID == 0)
            {
                businessid = dbContext.siger_tr_material_supplier.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId).Select(f => f.supplier_id).ToList();
            }
            else
            {
                businessid = dbContext.siger_tr_material_supplier.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId && f.material_id == materialID).Select(f => f.supplier_id).ToList();
            }
            var result = dbContext.siger_wms_bussinese_contacts.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId &&
                                                      f.supply_type == (int)WMSEnum.Business && businessid.Contains(f.id)).Select(f => new ResponseIdName
                                                      {
                                                          id = f.id,
                                                          name = f.name
                                                      }).ToList();
            return result;
        }

        public IEnumerable<siger_tr_materials> GetInventoryList(int businessID, int projectId)
        {
            //筛选此供应商的所有物料信息 
            if (businessID != 0)
            {
                var materialIDs = dbContext.siger_tr_material_supplier.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId && f.supplier_id == businessID).Select(f => f.material_id).Distinct().ToList();
                return dbContext.siger_tr_materials.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId && materialIDs.Contains(f.id));
            }
            return dbContext.siger_tr_materials.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId);
        }

        public IEnumerable<ResponseeInventory> GetList(int storageid, string invantorysn, int pid, managemodel type, string filter, int businessID)
        {
            var allData = GetList(f => f.status == (int)RowState.Valid && f.stock_state == (int)StockEnum.InWavehouse && f.projectid == pid && f.quantity > 0);
            if (storageid != 0)
            {
                var locationids = dbContext.siger_wms_storage_location.Where(f => f.status == (int)RowState.Valid && f.projectid == pid && f.storageid == storageid).Select(f => f.id).ToList();
                allData = allData.Where(f => locationids.Contains(f.storage_location_id));
            }
            if (!string.IsNullOrEmpty(invantorysn))
            {
                allData = allData.Where(f => f.material_pn == invantorysn && f.projectid == pid);
            }
            switch (type)
            {
                case managemodel.Batch:
                    if (!string.IsNullOrEmpty(filter))
                    {
                        allData = allData.Where(f => f.batch_number == filter);
                    }
                    break;
                case managemodel.No:
                    if (!string.IsNullOrEmpty(filter))
                    {
                        allData = allData.Where(f => f.serial_number == filter);
                    }
                    break;
                case managemodel.Group:
                    break;
                default:
                    break;
            }
            //20200407 入库是无供应商号？
            if (businessID != 0)
            {
                allData = allData.Where(f => f.businessid == businessID);
            }
            var result = from data in allData.ToList()
                         join r in dbContext.siger_wms_storage_location on data.storage_location_id equals r.id
                         select new ResponseeInventory
                         {
                             id = data.id,
                             storage_location_id = data.storage_location_id,
                             storage_location_name = r.name,
                             material_id = data.material_id,
                             stock_state = data.stock_state,
                             material_name = data.material_name,
                             material_pn = data.material_pn,
                             material_spec = data.material_spec,
                             manage_model = data.manage_model,
                             category = data.category,
                             serial_number = data.serial_number,
                             batch_number = data.batch_number,
                             quantity = data.quantity,
                             creator = data.creator,
                             create_time = data.create_time,
                             updator = data.updator,
                             update_time = data.update_time,
                             projectid = data.projectid,
                             status = data.status,
                             option = data.option,
                             businessid = data.businessid,
                             businessName = GetBusinessName(data.businessid, pid),
                         };
            var ret = result.ToList();
            foreach (var item in ret)
            {
                var toolData = dbContext.siger_project_toollife_tool.FirstOrDefault(f => f.material_id == item.material_id && f.project_id == pid && f.status != 0);
                var material=dbContext.siger_tr_materials.FirstOrDefault(f => f.id == item.material_id && f.projectId == pid && f.status != 0);
                item.warehouse_min = material?.min_stock ?? 0;
                item.tool_number = toolData?.number ?? "";
                item.tool_type = toolData == null ? 0 : (int)toolData.category;
            }
            return ret;
        }

        public IEnumerable<ResponseeInventory> GetList(int businessid, int storageid, string invantorysn, int locationid, int page, int pageSize, int projectId, out int totalCount, bool paging = true, string batch = "", string no = "")
        {
            var allData = GetList(f => f.status == (int)RowState.Valid && f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.quantity > 0);
            if (businessid != 0)
            {
                allData = allData.Where(f => f.businessid == businessid);
            }
            if (!string.IsNullOrEmpty(batch))
            {
                allData = allData.Where(f => f.batch_number == batch.Trim());
            }
            if (!string.IsNullOrEmpty(no))
            {
                allData = allData.Where(f => f.serial_number == no.Trim());
            }
            if (0 != storageid)
            {
                var locationids = dbContext.siger_wms_storage_location.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.storageid == storageid).Select(f => f.id).ToList();
                allData = allData.Where(f => locationids.Contains(f.storage_location_id));
            }
            if (!string.IsNullOrEmpty(invantorysn))
            {
                allData = allData.Where(f => f.material_pn == invantorysn);
            }
            if (0 != locationid)
            {
                allData = allData.Where(f => f.storage_location_id == locationid);
            }

            totalCount = allData.Count();
            if (paging)
            {
                allData = Paging(allData, page, pageSize);
            }
            var result = from data in allData.ToList()
                         join r in dbContext.siger_wms_storage_location on data.storage_location_id equals r.id
                         select new ResponseeInventory
                         {
                             id = data.id,
                             storage_location_id = data.storage_location_id,
                             storage_location_name = r.name,
                             material_id = data.material_id,
                             stock_state = data.stock_state,
                             material_name = data.material_name,
                             material_pn = data.material_pn,
                             material_spec = data.material_spec,
                             manage_model = data.manage_model,
                             category = data.category,
                             serial_number = data.serial_number ?? "NA",
                             batch_number = data.batch_number ?? "NA",
                             quantity = data.quantity,
                             creator = data.creator,
                             create_time = data.create_time,
                             updator = data.updator,
                             update_time = data.update_time,
                             projectid = data.projectid,
                             status = data.status,
                             option = data.option,
                             businessid = data.businessid,
                             businessName = GetBusinessName(data.businessid, projectId)
                         };
            return result.OrderByDescending(o=>o.create_time).ToList();
        }

        public IEnumerable<ResponseeInventory> GetListForApp(string code,int projectId)
        {
            var allData = GetList(f => f.status == (int)RowState.Valid && f.stock_state == (int)StockEnum.InWavehouse && f.projectid == projectId && f.quantity > 0);
            if (!string.IsNullOrEmpty(code))
            {
                allData = allData.Where(f => f.batch_number == code || f.serial_number == code);
            }
            var result = from data in allData.ToList()
                         join tool in dbContext.siger_project_toollife_tool on data.material_id equals tool.material_id into temp
                         from tool in temp.DefaultIfEmpty()
                         join r in dbContext.siger_wms_storage_location on data.storage_location_id equals r.id
                         select new ResponseeInventory
                         {
                             id = data.id,
                             storage_location_id = data.storage_location_id,
                             storage_location_name = r.name,
                             material_id = data.material_id,
                             stock_state = data.stock_state,
                             material_name = data.material_name,
                             material_pn = data.material_pn,
                             material_spec = data.material_spec,
                             manage_model = data.manage_model,
                             category = data.category,
                             serial_number = data.serial_number ?? "NA",
                             batch_number = data.batch_number ?? "NA",
                             quantity = data.quantity,
                             creator = data.creator,
                             create_time = data.create_time,
                             updator = data.updator,
                             update_time = data.update_time,
                             projectid = data.projectid,
                             status = data.status,
                             option = data.option,
                             businessid = data.businessid,
                             businessName = GetBusinessName(data.businessid, projectId),
                             tool_number = tool == null ? "" : tool.number,
                             tool_type = tool == null ? 0 : tool.category_id,
                         };
            var ret = result.ToList();
            foreach (var item in ret)
            {
                var toolData = dbContext.siger_project_toollife_tool.FirstOrDefault(f => f.material_id == item.material_id);
                item.tool_number = toolData?.number ?? "";
                item.tool_type = toolData?.category_id ?? 0;
            }
            return result.OrderByDescending(o => o.create_time).ToList();
        }

        public string GetSn(string snValue)
        {
            siger_wms_id t;
            lock (lockObj)
            {
                t = new siger_wms_id
                {
                    day = DateTime.Now,
                    type = (int)Settings.SN
                };
                dbContext.siger_wms_id.Add(t);
                dbContext.SaveChanges();
                var count = dbContext.siger_wms_id.Where(f => f.day > t.day.Date && f.day <= t.day.AddDays(1).Date && f.type == (int)Settings.SN).Count();
                t.code = $"{count.ToString("D6")}";
                //add new
                //calc count in this day
                //gen sn by count
                dbContext.siger_wms_id.Update(t);
                dbContext.SaveChanges();

            }
            if (t != null)
            {
                var result = $"{snValue}{DateTime.Now.ToString("yyyyMMdd")}{t.code}";
                return result;
            }

            return string.Empty;
        }

        public ResponseStockChangeHistory GetStockChangeHistory(int storageid, string sn, DateTime start, DateTime end, int projectId, traceType type)
        {
            Expression<Func<siger_wms_stock_detail, bool>> snExpression = f => true;
            if (!string.IsNullOrEmpty(sn))
            {
                snExpression = f => f.inventorySN == sn;
            }
            Expression<Func<siger_wms_stock_detail, bool>> startExpression = f => true;
            Expression<Func<siger_wms_stock_detail, bool>> endExpression = f => true;
            if (start != null && start != DateTime.MinValue)
            {
                startExpression = f => f.updatetime >= start;
            }
            if (end != null && start != DateTime.MinValue)
            {
                endExpression = f => f.updatetime <= end;
            }
            Expression<Func<siger_wms_stock_detail, bool>> baseExpression = f => f.type == (int)type && f.projectid == projectId;
            var finalExpression = baseExpression.And(snExpression).And(startExpression).And(endExpression);

            var data = dbContext.siger_wms_stock_detail.Where(finalExpression);
            if (storageid != 0)
            {
                var locationids = dbContext.siger_wms_storage_location.Where(f => f.storageid == storageid &&
                                    f.projectid == projectId && f.status == (int)RowState.Valid).Select(f => f.id);
                data = data.Where(f => locationids.Contains(f.locationid));
            }
            if (!data.Any())
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            data = data.OrderBy(f => f.updatetime);
            var min = data.Min(f => f.updatetime);

            //汇总数据
            var result = new ResponseStockChangeHistory
            {
                //qty
                y = new List<int>(),
                //time
                x = new List<string>()
            };
            var day = min.Date;
            var tmpCount = 0;
            foreach (var item in data)
            {
                if (item.updatetime.Date != day)
                {
                    result.y.Add(tmpCount);
                    result.x.Add(day.ToString(UnixTimeHelper.DateFormat));
                    day = item.updatetime.Date;
                    tmpCount = item.qty;
                }
                else
                {
                    tmpCount += item.qty;
                }
            }
            result.y.Add(tmpCount);
            result.x.Add(day.ToString(UnixTimeHelper.DateFormat));
            return result;
        }

        /// <summary>
        /// 出入库明细
        /// </summary>
        /// <param name="derect">1：入库  2：出库</param>
        /// <param name="projectId"></param>
        /// <param name="access_Id"></param>
        /// <param name="storageId"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <param name="totalCount"></param>
        /// <returns></returns>
        public IEnumerable<StockDetail> GetStockDetails(int derect, int projectId, int access_Id, int storageId, DateTime start, DateTime end, int page, int pageSize, out int totalCount)
        {

            Expression<Func<StockDetail, bool>> FunType = f => true;
            Expression<Func<StockDetail, bool>> FunWH = f => true;
            Expression<Func<StockDetail, bool>> FunTime = f => f.UpdateTime >= start && f.UpdateTime <= end;

            var query = from ao in dbContext.siger_wms_stock_access_order
                        join aod in dbContext.siger_wms_stock_access_order_detail on ao.id equals aod.orderid
                        join std in dbContext.siger_wms_stock_detail on ao.order_number equals std.billID

                        where
                           ao.projectid == projectId && std.type == derect
                        select new StockDetail
                        {
                            Access_Id = ao.access_type,
                            Access_Type = ao.category,
                            StoreageId = ao.storageid,
                            Code = ao.order_number,
                            Pn = std.inventorySN,
                            PnDesc = std.inventoryName,
                            PnSpec = std.inventorySpec,
                            Total = std.allqty,
                            InPut = std.qty,
                            UpdateTime = std.updatetime,
                            User = std.username ?? "NA",
                            Mode = EnumHelper.GetEnumDesc((managemodel)int.Parse(aod.manage_mode))
                        };

            if (access_Id != 0)
                FunType = q => q.Access_Id == access_Id;

            if (storageId != 0)
                FunWH = q => q.StoreageId == storageId;

            var predicate = FunType.And(FunWH).And(FunTime);
            totalCount = query.Count(predicate);

            var data = query.Where(predicate).Skip((page - 1) * pageSize).Take(pageSize).ToList();

            return data;
        }
        /// <summary>
        /// 出入库汇总
        /// </summary>
        /// <param name="derect">1：入库  2：出库</param>
        /// <param name="projectId"></param>
        /// <param name="access_Id"></param>
        /// <param name="storageId"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <param name="totalCount"></param>
        /// <returns></returns>
        public IEnumerable<StockTotal> GetStockTotal(int derect, int projectId, int access_Id, int storageId, DateTime start, DateTime end, int page, int pageSize, out int totalCount)
        {
            Expression<Func<StockDetail, bool>> FunType = f => true;
            Expression<Func<StockDetail, bool>> FunWH = f => true;
            Expression<Func<StockDetail, bool>> FunTime = f => f.UpdateTime >= start && f.UpdateTime <= end;

            var query = from ao in dbContext.siger_wms_stock_access_order
                        join std in dbContext.siger_wms_stock_detail on ao.order_number equals std.billID
                        join str in dbContext.siger_wms_storage on ao.storageid equals str.id
                        where
                           ao.projectid == projectId && std.type == derect
                        select new StockDetail
                        {
                            Access_Id = ao.access_type,
                            Access_Type = ao.category,
                            Storeage = str.name,
                            StoreageId = ao.storageid,
                            Code = ao.order_number,
                            Pn = std.inventorySN,
                            PnDesc = std.inventoryName,
                            PnSpec = std.inventorySpec,
                            Total = std.allqty,
                            InPut = std.qty,
                            UpdateTime = std.updatetime
                        };
            if (access_Id != 0)
                FunType = q => q.Access_Id == access_Id;

            if (storageId != 0)
                FunWH = q => q.StoreageId == storageId;

            var predicate = FunType.And(FunWH).And(FunTime);
            var data = query.Where(predicate).ToList();
            var grpStoreage = data.GroupBy(g => g.StoreageId);


            var response = new List<StockTotal>();
            foreach (var d in grpStoreage)
            {
                var sid = d.Key;
                var slst = d.ToList();
                var st = new StockTotal
                {
                    Name = slst.FirstOrDefault().Storeage

                };
                var grpPn = slst.GroupBy(g => g.Pn);
                foreach (var p in grpPn)
                {
                    var pn = p.Key;
                    var pnlst = p.ToList();

                    st.Pn = pn;
                    st.PnDesc = pnlst.FirstOrDefault().PnDesc;
                    st.PnType = pnlst.FirstOrDefault().PnSpec;

                    st.Count = pnlst.Sum(s => s.InPut);


                }
                response.Add(st);
            }
            totalCount = response.Count;

            var responsedata = response.Skip((page - 1) * pageSize).Take(pageSize).ToList();
            return responsedata;
        }

        public IEnumerable<ResponseStockSummary> StockSummary(int id, int projectId, int page, int pageSize, out int totalCount, bool paging = true)
        {
            Expression<Func<siger_wms_stock, bool>> wavehouseExpression = f => true;

            if (id != 0)
            {
                //获取仓库下所有储位
                //根据储位过滤库存信息
                var locationids = dbContext.siger_wms_storage_location.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.storageid == id).Select(f => f.id).ToList();
                wavehouseExpression = f => locationids.Contains(f.storage_location_id);
            }
            Expression<Func<siger_wms_stock, bool>> stockExpression = f => f.status == (int)RowState.Valid && f.projectid == projectId && f.stock_state == (int)StockEnum.InWavehouse;
            var expression = wavehouseExpression.And(stockExpression);
            var data = GetList(expression);

            var tmp = from info in data
                      join location in dbContext.siger_wms_storage_location on info.storage_location_id equals location.id into tmp1
                      from locationInfo in tmp1.DefaultIfEmpty()
                      join wavehouse in dbContext.siger_wms_storage on locationInfo.storageid equals wavehouse.id into re
                      from r in re.DefaultIfEmpty()
                      select new
                      {
                          info.id,
                          r.name,
                          info.manage_model,
                          info.material_id,
                          info.material_name,
                          info.material_pn,
                          info.material_spec,
                          info.quantity
                      };

            var result = new List<ResponseStockSummary>();
            //根据仓库分组
            var wavehouseFilter = tmp.GroupBy(f => f.name);
            foreach (var item in wavehouseFilter)
            {
                //根据物料分组
                var materialFilter = item.GroupBy(f => f.material_id);
                foreach (var j in materialFilter)
                {
                    var tmpData = new ResponseStockSummary()
                    {
                        name = item.FirstOrDefault().name
                    };
                    tmpData.manage_model = j.FirstOrDefault().manage_model;
                    tmpData.material_id = j.FirstOrDefault().material_id;
                    tmpData.material_name = j.FirstOrDefault().material_name;
                    tmpData.material_pn = j.FirstOrDefault().material_pn;
                    tmpData.material_spec = j.FirstOrDefault().material_spec;
                    tmpData.count = j.Sum(f => f.quantity);
                    result.Add(tmpData);
                }
            }
            totalCount = result.Count();
            if (paging)
            {
                result = result.Skip((page - 1) * pageSize).Take(pageSize).ToList();
            }
            return result;
        }

        private string GenInventoryLevel(int material_id, int ProjectId)
        {
            var entity = dbContext.siger_tr_materials.FirstOrDefault(f => f.id == material_id && f.status == (int)RowState.Valid && f.projectId == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            var result = new StringBuilder();
            int typeid = entity.typeid;
            while (0 != typeid)
            {
                var type = dbContext.siger_tr_material_type.FirstOrDefault(f => f.id == typeid && f.status == (int)RowState.Valid && f.projectId == ProjectId);
                if (type == null)
                {
                    throw new BadRequestException(RequestEnum.ErrorMaterialType);
                }
                result.Insert(0, type.tcode);
                typeid = type.parentid;
            }
            //添加最高的TOP层级
            result.Insert(0, CommonConst.MATERIALTYPE_PARENTNAME);

            return result.ToString();
        }
        /// <summary>
        /// 同步刀具信息
        /// </summary>
        /// <param name="request"></param>
        /// <param name="pid"></param>
        /// <returns></returns>
        public bool SyncToolData(RequestPurchaseTools request, int pid)
        {
            if (request.data == null || !request.data.Any())
            {
                Logger.WriteLineError($"{request.purchase_order}data error!");
                return false;
            }
            var material_codes = request.data.Select(s => s.material_code).Distinct();
            var storage = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.projectid == pid && f.status != 0 && f.name == request.location);
            var user = dbContext.siger_project_user.FirstOrDefault(f => f.name == request.create_user && f.projectid == pid && f.status != 0);

            var accessWoList = new List<string>();

            foreach (var material_code in material_codes)
            {
                var material = dbContext.siger_tr_materials.FirstOrDefault(f => f.projectId == pid && f.status != 0 && f.pn == material_code);
                if (material == null)
                {
                    //TODO
                    return false;
                }
                var inventoryLevel = GenInventoryLevel(material.id, pid);
                //insert siger_wms_stock_access_order
                var order = new siger_wms_stock_access_order()
                {
                    access_type = 1,
                    audit_desc = string.Empty,
                    audit_fail_reason = string.Empty,
                    option = string.Empty,
                    origin_order_number = string.Empty,
                    storageid = storage?.storageid ?? 0,
                    category_code = request.inbound_type.ToInt(),
                    category = EnumHelper.EnumToList<WaveHousingType>().FirstOrDefault(f => f.EnumValue == request.inbound_type.ToInt())?.EnumName ?? "",
                    update_time = default,
                    projectid = pid,
                    order_status = request.audit == "1" ? (int)WaveHousingState.Finish : (int)WaveHousingState.Failed,
                    order_number = request.purchase_order,
                    auditor = user?.mid ?? 0,
                    creator = user?.mid ?? 0,
                    updator = user?.mid ?? 0,
                    audit_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                    create_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                    contactid = material.supplier.ToInt(),
                    accessWo = IdHelper.Generate<string>(),
                };
                accessWoList.Add(order.accessWo);
                dbContext.siger_wms_stock_access_order.Add(order);
                //insert siger_wms_stock
                var stock = new siger_wms_stock
                {
                    projectid = pid,
                    category = order.category_code.ToStr(),
                    serial_number = GetSn(inventoryLevel),
                    create_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                    update_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                    updator = user?.mid ?? 0,
                    storage_location_id = storage?.id ?? 0,
                    businessid = material.supplier.ToInt(),
                    stock_state = 1,
                    creator = user?.mid ?? 0,
                    batch_number = string.Empty,
                    manage_model = "1",
                    material_id = material.id,
                    material_name = material.name,
                    material_pn = material.pn,
                    material_spec = material.spec,
                    quantity = request.data.Where(f => f.material_code == material_code).Select(s => s.purchase_qty.ToInt()).Sum(),
                    stockNo = IdHelper.Generate<string>(),
                    option = string.Empty,
                };
                dbContext.siger_wms_stock.Add(stock);
                foreach (var item in request.data.Where(f => f.material_code == material_code))
                {
                    //insert siger_wms_stock_access_order_detail
                    var orderDetail = new siger_wms_stock_access_order_detail
                    {
                        access_quantity = item.purchase_qty.ToInt(),
                        quantity = item.purchase_qty.ToInt(),
                        auditor = user?.mid ?? 0,
                        creator = user?.mid ?? 0,
                        updator = user?.mid ?? 0,
                        audit_desc = string.Empty,
                        audit_fail_reason = string.Empty,
                        batch_number = stock.batch_number,
                        projectid = pid,
                        businessid = material.supplier.ToInt(),
                        manage_mode = stock.manage_model,
                        material_id = stock.material_id,
                        material_name = stock.material_name,
                        material_pn = stock.material_pn,
                        material_spec = stock.material_spec,
                        orderid = 0,
                        serial_number = stock.serial_number,
                        storage_location_id = stock.storage_location_id,
                        stock_number = string.Empty,
                        unit = material.unit,
                        audit_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                        create_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                        update_time = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                        accessWo = order.accessWo
                    };
                    dbContext.siger_wms_stock_access_order_detail.Add(orderDetail);

                    var supplierData = dbContext.siger_wms_bussinese_contacts.FirstOrDefault(f => f.projectid == pid && f.status != 0 && f.id == material.supplier.ToInt());
                    var stockDetail = new siger_wms_stock_detail
                    {
                        allqty = orderDetail.quantity,
                        batch = orderDetail.batch_number,
                        businessid = orderDetail.businessid,
                        username = user?.name ?? "",
                        userid = user?.id ?? 0,
                        billID = request.purchase_order,
                        businessName = supplierData.name,
                        inventory = material.id,
                        inventoryName = material.name,
                        inventorySN = material.pn,
                        inventorySpec = material.spec,
                        locationid = orderDetail.storage_location_id,
                        locationname = storage.name,
                        no = orderDetail.serial_number,
                        productingtime = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                        updatetime = UnixTimeHelper.ConvertStringDateTime(request.create_time),
                        projectid = pid,
                        qty = 1,
                        state = 1,
                        stockNo = stock.stockNo,
                        type = (int)traceType.WaveHousing,
                    };
                    //tempStockDetailList.Add(stockDetail);
                    dbContext.siger_wms_stock_detail.Add(stockDetail);
                }
            }

            if (dbContext.SaveChanges() <= 0)
            {
                return false;
            }

            foreach (var accessWo in accessWoList)
            {
                var id = dbContext.siger_wms_stock_access_order.First(f => f.accessWo == accessWo).id;
                var details = dbContext.siger_wms_stock_access_order_detail.Where(f => f.accessWo == accessWo).ToList();
                foreach (var detail in details)
                {
                    detail.orderid = id;
                    dbContext.siger_wms_stock_access_order_detail.Update(detail);
                }
            }

            if (dbContext.SaveChanges() <= 0)
            {
                return false;
            }

            return true;
        }
    }
}

