using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Filters;
using Siger.ApiCommon.Result;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.AppSettings;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Utility.Helpers;
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.Extensions;
using Siger.Middlelayer.Log;

namespace Siger.ApiWMS.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    public class LocationController : BaseController
    {
        private readonly Isiger_wms_storage_location_typeRepository locationType;
        private readonly Isiger_wms_stock_detailRepository trace;
        private readonly Isiger_wms_storage_typeRepository waveHouseType;
        private readonly Isiger_wms_storage_location_typeRepository locationtype;
        private readonly Isiger_wms_storage_locationRepository location;
        private readonly Isiger_wms_storageRepository storage;
        private readonly Isiger_wms_stockRepository stock;
        private readonly Isiger_wms_stock_access_order_detailRepository orderdetail;
        private readonly IUnitOfWork _unitOfWork;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="locationType"></param>
        /// <param name="trace"></param>
        /// <param name="waveHouseType"></param>
        /// <param name="locationtype"></param>
        /// <param name="location"></param>
        /// <param name="storage"></param>
        /// <param name="stock"></param>
        /// <param name="orderdetail"></param>
        /// <param name="unitOfWork"></param>
        public LocationController(Isiger_wms_storage_location_typeRepository locationType, Isiger_wms_stock_detailRepository trace, 
            Isiger_wms_storage_typeRepository waveHouseType, Isiger_wms_storage_location_typeRepository locationtype, 
            Isiger_wms_storage_locationRepository location, Isiger_wms_storageRepository storage, Isiger_wms_stockRepository stock, 
            Isiger_wms_stock_access_order_detailRepository orderdetail, IUnitOfWork unitOfWork)
        {
            this.locationType = locationType;
            this.trace = trace;
            this.waveHouseType = waveHouseType;
            this.locationtype = locationtype;
            this.location = location;
            this.storage = storage;
            this.stock = stock;
            this.orderdetail = orderdetail;
            _unitOfWork = unitOfWork;
        }


        /// <summary>
        /// 获取储位类别列表
        /// </summary>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetLocationTypeList(int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            var data = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList();
            var totalCount = data.Count;
            var dic = new Dictionary<int, string>();
            data.ForEach(f =>
            {
                dic.Add(f.id, f.name);
            });
            var result = new List<ResponseLocationTypeList>();
            data.Skip((page - 1) * pageSize).Take(pageSize).ToList().ForEach(f =>
            {
                try
                {
                    result.Add(new ResponseLocationTypeList
                    {
                        id = f.id,
                        name = f.name,
                        parent = f.parentid == 0 ? "0" : dic[f.parentid],
                        parentid = f.parentid
                    });
                }
                catch (Exception)
                {

                }

            });
            return new PagedObjectResult(result, totalCount, page, pageSize);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IActionResult GetLocationTypeListNoPage()
        {

            var list = new List<LevelSectionTree>();
            //获取所有的仓库
            var data = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList();

            foreach (var item in data)
            {
                var tree = new LevelSectionTree
                {
                    id = item.id,
                    name = item.name,
                    pid = item.parentid,
                    open = true,
                };
                list.Add(tree);
            }
            var response = new ResponseLevelSectionChildren(Utility.ConvertToTree(list));
            return new ObjectResult(response);
        }
        /// <summary>
        /// 新增储位类别
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddLocationType([FromBody]RequestAddLocationType req)
        {
            if (locationtype.IsExist(f => f.name == req.name && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            if (req.pid != 0)
            {
                if (!locationtype.IsExist(f => f.id == req.pid && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                    throw new BadRequestException(RequestEnum.LocationPidNotExist);
            }
            //同一条记录只允许存在一条子级
            if (locationtype.IsExist(f => f.status == (int)RowState.Valid && f.parentid == req.pid && f.projectid == ProjectId))
            {
                throw new BadRequestException(RequestEnum.ExistSonStorageType);
            }
            int count = 0;
            int pid = req.pid;
            while (pid != 0)
            {
                count++;
                var entity = locationtype.Get(f => f.status == (int)RowState.Valid && f.id == pid && f.projectid == ProjectId);
                pid = entity.parentid;

            }
            if (count >= 4)
            {
                throw new BadRequestException(RequestEnum.LevelCountError);
            }

            locationtype.Insert(new siger_wms_storage_location_type
            {
                name = req.name,
                parentid = req.pid,
                projectid = ProjectId,
                creator = UserId,
                create_time = DateTime.Now,
                updator = UserId,
                update_time = DateTime.Now,
                status = (int)RowState.Valid
            });
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 更新储位类别
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UpdateLocationType([FromBody]RequestUpdateLocationType req)
        {
            if (!locationtype.IsExist(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.NoData);
            if (req.pid != 0)
            {
                if (!locationtype.IsExist(f => f.id == req.pid && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                    throw new BadRequestException(RequestEnum.LocationPidNotExist);
            }
            var entity = locationtype.Get(f => f.id == req.id && f.projectid == ProjectId);
            if (entity.id == req.pid)
                throw new BadRequestException(RequestEnum.LocationPidCanNotBySelf);
            if (locationtype.IsExist(f => f.name == req.name && f.id != req.id && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            //同一条记录只允许存在一条子级
            if (locationtype.IsExist(f => f.status == (int)RowState.Valid && f.parentid == req.pid && f.id != req.id && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.RecordExits);
            }
            //update start
            entity.name = req.name;
            entity.parentid = req.pid;
            entity.updator = UserId;
            entity.update_time = DateTime.Now;

            //update end
            locationtype.Update(entity);
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 删除储位类别
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult DelLocationType([FromBody]RequestDelLocationType req)
        {
            if (!locationtype.IsExist(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            var entity = locationtype.Get(f => f.id == req.id && f.projectid == ProjectId);
            if (entity == null)
                throw new BadRequestException(CommonEnum.NoData);
            //存在子级
            if (locationtype.IsExist(f => f.status == (int)RowState.Valid && f.parentid == req.id && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.LayerNotClean);
            }
            //存在此列表记录
            if (location.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.typeid == req.id).Any())
            {
                throw new BadRequestException(RequestEnum.CategoryBindLocationData);
            }

            entity.status = (int)RowState.Invalid;
            entity.update_time = DateTime.Now;
            entity.updator = UserId;

            locationtype.Update(entity);
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }
        /// <summary>
        /// 储位类别树
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetLocationTypeTree()
        {
            var list = new List<LevelSectionTree>();
            //获取所有的仓库
            //将储位保存在仓库下
            var wavehousetypeids = waveHouseType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).Select(f => f.id).ToList();
            var typeids = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).Select(f => f.id).ToList();
            var wavehouse = storage.GetList(f => f.status == (int)RowState.Valid && wavehousetypeids.Contains(f.typeid) && f.projectid == ProjectId).ToList();
            foreach (var item in wavehouse)
            {
                var tree = new LevelSectionTree
                {
                    id = item.id,
                    name = item.name,
                    pid = 0,
                    open = true,
                    title = item.name,
                    level = 0
                };
                var data = location.GetList(f => f.storageid == item.id && f.status == (int)RowState.Valid && typeids.Contains(f.typeid) && f.projectid == ProjectId);
                var tmp = new List<LevelSectionTree>();
                foreach (var j in data)
                {
                    tmp.Add(new LevelSectionTree
                    {
                        id = j.id,
                        name = j.realname,
                        pid = j.parentid,
                        open = true,
                        title = item.name,
                        level = 1
                    });
                }
                tree.children = Utility.ConvertToTree(tmp).ToList();
                list.Add(tree);
            }
            var response = new ResponseLevelSectionChildren(Utility.ConvertToTree(list));

            return new ObjectResult(response);
        }

        /// <summary>
        /// 储位列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetLocationList(int id, int isWavehouse, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            //获取储位类别最后一级id
            int totalCount;
            var data = SearchLocation(page, pageSize, out totalCount, true, id, isWavehouse);

            return new PagedObjectResult(data, totalCount, page, pageSize);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IActionResult GetLastLocation(int storageid,int locationid)
        {
            if (locationid != 0)
            {
                var locationInfo = location.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId&&f.id == locationid);
                if(locationInfo==null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }
                else
                {
                    storageid = locationInfo.storageid;
                }
            }

            var parentid = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).Select(f => f.parentid).ToList();
            var typeids = locationtype.GetList(f => f.status == (int)RowState.Valid && !parentid.Contains(f.id) && f.projectid == ProjectId).Select(f => f.id).ToList();
            IEnumerable<siger_wms_storage_location> tmp;
            if (storageid == 0)
            {
                tmp = location.GetList(f => f.status == (int)RowState.Valid && typeids.Contains(f.typeid) && f.projectid == ProjectId);
            }
            else
            {
                tmp = location.GetList(f => f.storageid == storageid && f.status == (int)RowState.Valid && typeids.Contains(f.typeid) && f.projectid == ProjectId);
            }
            
            var locationData = tmp.Select(f => new
            {
                f.id,
                f.name
            }).ToList();
            return new ObjectResult(locationData);
        }

        private List<ResponseLocationList> SearchLocation(int page, int pageSize, out int totalCount, bool paged = true, int id = 0, int isWavehouse = 0)
        {
            var locationData = new List<siger_wms_storage_location>();
            var locationType = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList();
            var parentid = locationType.Select(f => f.parentid).ToList();
            var typeids = locationtype.GetList(f => f.status == (int)RowState.Valid && !parentid.Contains(f.id) && f.projectid == ProjectId).Select(f => f.id).ToList();

            var locationAllData = location.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId);

            //所有id
            List<int> ids = new List<int>();
            //保存每次查询到的id，用作下一次查询时的参数
            var tmpIDs = new List<int>();
            if (id != 0 && isWavehouse == 0)
            {
                var entity = location.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.id == id);
                if (entity == null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }
                ids.Add(entity.id);
                tmpIDs.Add(entity.id);
                var hasData = true;
                while (hasData)
                {
                    tmpIDs = location.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && tmpIDs.Contains(f.parentid)).Select(f => f.id).ToList();
                    if (tmpIDs.Count() == 0)
                    {
                        hasData = false;
                    }
                    ids.AddRange(tmpIDs);
                }
                locationAllData = locationAllData.Where(f => ids.Contains(f.id));
            }
            if (id != 0 && isWavehouse == 1)
            {
                locationAllData = locationAllData.Where(f => f.storageid == id);
            }
            //最后一级的数据
            if (!paged)
            {
                totalCount = 0;
                locationData = locationAllData.Where(f => typeids.Contains(f.typeid)).ToList();
            }
            else
            {
                totalCount = locationAllData.Where(f => typeids.Contains(f.typeid)).Count();//location.GetList(f => f.status == (int)RowState.Valid && typeids.Contains(f.typeid) && f.projectid == ProjectId).Count();
                locationData = locationAllData.Where(f => typeids.Contains(f.typeid)).Skip((page - 1) * pageSize).Take(pageSize).ToList();
            }
            Dictionary<int, string> waveHouseDic = new Dictionary<int, string>();
            storage.GetList(f => f.projectid == ProjectId).Select(f => new { f.id, f.name }).ToList().ForEach(f =>
            {
                waveHouseDic.Add(f.id, f.name);
            });
            //获取区域信息
            //拼接各个区域的数据
            var result = new List<ResponseLocationList>();

            foreach (var item in locationData)
            {
                try
                {
                    int pid = item.parentid;
                    var tmp = new ResponseLocationList
                    {
                        id = item.id,
                        pid = item.parentid,
                        storageName = waveHouseDic.ContainsKey(item.storageid) ? waveHouseDic[item.storageid] : "",
                        serialNumber = item.serial_number,
                        state = item.status,
                        field = new List<FiledName>(),
                        warehouseId = item.storageid,
                        storeID = item.locationid,
                    };
                    int i = 1;
                    var locatype = locationType.FirstOrDefault(q => q.id == item.typeid);
                    tmp.field.Add(new FiledName
                    {
                        locationid = item.id,
                        val = item.realname,
                        id = item.typeid,
                        name = locatype?.name ?? ""
                    });
                    while (pid != 0)
                    {
                        var entity = location.Get(pid);
                        if (entity == null)
                            break;
                        //处理顺序问题
                        locatype = locationType.FirstOrDefault(q => q.id == entity.typeid);
                        tmp.field.Add(new FiledName
                        {
                            locationid = entity.id,
                            val = entity.realname,
                            id = entity.typeid,
                            name = locatype?.name ?? ""
                        });
                        pid = entity.parentid;

                        //避免因为数据异常导致死循环
                        if (i > 4)
                        {
                            break;
                        }
                        i++;
                    }
                    if (tmp.field.Any())
                    {
                        tmp.field.Reverse();
                    }                    
                    result.Add(tmp);
                }
                catch (Exception e)
                {
                    Logger.WriteLineError(e.Message);
                }

            }
            return result;
        }

        /// <summary>
        /// 删除储位
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult DelLocation(RequestDelBusiness req)
        {
            if (!location.IsExist(f => f.status == (int)RowState.Valid && f.id == req.id && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            //存在子级
            if (locationtype.IsExist(f => f.status == (int)RowState.Valid && f.parentid == req.id && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.LayerNotClean);
            }
            var entity = location.Get(req.id);
            entity.status = (int)RowState.Invalid;
            entity.update_time = DateTime.Now;
            entity.updator = UserId;
            location.Update(entity);

            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        private void CheckCount(int pid)
        {
            int currentCount = 1;
            while (pid != 0)
            {
                var entity = location.Get(f => f.id == pid && f.projectid == ProjectId);
                if (entity != null)
                    pid = entity.parentid;

                if (currentCount >= 4)
                {
                    throw new BadRequestException(RequestEnum.LocationCountError);
                }
                currentCount++;
            }
        }

        [HttpGet]
        public IActionResult GetTemplate()
        {
          

            return new ObjectResult(CreateLocationTypeTemplate());
        }
        private string CreateLocationTypeTemplate()
        {
            var columnNames = new List<string>();
            //var titles = _levelRepository.GetLevelTitles(0, ProjectId);
            var titles = locationType.GetList(f => f.projectid == ProjectId && f.status != 0).OrderBy(o => o.id).Select(s => s.name);
            columnNames.AddRange(titles);
            var helper = new EpPlusForSectionHelper();
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"西格云平台-仓库储位入模板_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);
            helper.GenerateExcel(columnNames, fileName);
            
            return $"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}";
        }

        /// <summary>
        /// 储位模板下载
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult DownloadTemplate()
        {
            var list = new List<List<string>>() { GetExcelTitle() };

            var fileName = Utility.GetExcelFileName("Location");
            CommonExcelHelper.Generate(list, fileName);

            var result = Utility.GetExcelFileDisplayName(Path.GetFileName(fileName));
            return new ObjectResult(result);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IActionResult GetTitle()
        {
            var data = new List<string>();
            var range = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).OrderBy(f => f.id).Select(f => f.name).ToList();
            data.AddRange(range);
            return new ObjectResult(data);
        }
        /// <summary>
        /// 模板标题
        /// </summary>
        /// <returns></returns>
        private List<string> GetExcelTitle()
        {
            var data = new List<string>(){
                "ID",
                "仓库"
            };
            var range = locationtype.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).OrderBy(f => f.id).Select(f => f.name).ToList();
            data.AddRange(range);
            data.Add("是否停用");
            data.Add("编号");
            return data;
        }

        /// <summary>
        /// 导入储位
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> ImportLocation(IFormFile file)
        {
            if (file == null)
            {
                file = HttpContext.Request.Form.Files.First();
            }
            var filePath = Utility.GetExcelTmpFileName("Location", file.FileName);
            using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate))
            {
                await file.CopyToAsync(fileStream);
            }
            var err = new StringBuilder();
            var data = CommonExcelHelper.GetValue(filePath);
            bool first = true;
            foreach (var item in data)
            {
                if (first)
                {
                    first = !first;
                    continue;
                }
                try
                {
                    //if (item.Count != 7)
                    //    throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.LocationImportFormatError));

                    var entity = new siger_wms_storage_location();
                    //update start
                    if (!storage.IsExist(q => q.name == item[1] && q.status == (int)RowState.Valid && q.projectid == ProjectId))
                    {
                        throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.LocationTypeNotExist));
                    }
                    int storageid = storage.Get(q => q.name == item[1] && q.status == (int)RowState.Valid && q.projectid == ProjectId).id;
                    entity.storageid = storageid;

                    //检测区域等信息
                    for (int i = 2; i < item.Count - 2; i++)
                    {
                        if (i != item.Count - 2 - 1)
                        {
                            if (!location.IsExist(q => q.realname == item[i] && q.projectid == ProjectId))
                            {
                                throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.LocationTypeNotExist));
                            }
                        }

                        //获取最后两条记录的id
                        if (i == item.Count - 2 - 1)
                        {
                            entity.realname = item[i];
                            entity.typeid = locationtype.Get(q => q.name == data[0][i] && q.projectid == ProjectId).id;
                            var parentData = location.Get(q => q.realname == item[i - 1] && q.projectid == ProjectId);
                            if (parentData == null)
                            {
                                throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.LocationPidNotExist));
                            }
                            entity.parentid = parentData.id;
                            entity.name = $"{parentData.name} -> {entity.realname}";
                            CheckCount(entity.parentid);

                            //同级下不允许重名
                            if (location.IsExist(f => f.realname == item[i] && f.projectid == ProjectId && f.parentid == entity.parentid))
                                throw new Exception(EnumHelper.GetEnumDesc(CommonEnum.RecordExits));
                        }
                    }
                    entity.create_time = DateTime.Now;
                    entity.creator = UserId;
                    entity.projectid = ProjectId;
                    entity.serial_number = Utility.GenSerialNumber();
                    entity.updator = UserId;
                    entity.update_time = DateTime.Now;
                    entity.status = (int)RowState.Valid;

                    //update end
                    location.Insert(entity);
                    if (_unitOfWork.Commit() <= 0)
                        throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.ImportFailed));
                }
                catch (Exception e)
                {
                    err.Append("第[" + item.First() + "]行导入异常" + e.Message + "\n");
                }

            }
            if (!string.IsNullOrEmpty(err.ToString()))
            {
                throw new Exception(err.ToString());
            }
            return Ok();
        }

        /// <summary>
        /// 导出储位
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportLocation()
        {
            var data = SearchLocation(0, 0, out int count, false);
            var excelData = new List<List<string>>();
            //title
            excelData.Add(GetExcelTitle());
            //data
            foreach (var item in data)
            {
                var tmp = new List<string>();
                tmp.Add(item.storeID.ToString());
                tmp.Add(item.storageName);
                tmp.AddRange(item.field.Select(q => q.val));
                tmp.Add(item.state == (int)RowState.Valid ? "否" : "是");
                tmp.Add(item.serialNumber);
                excelData.Add(tmp);
            }

            var fileName = Utility.GetExcelFileName("LocationExport");
            CommonExcelHelper.Generate(excelData, fileName);

            var result = Utility.GetExcelFileDisplayName(Path.GetFileName(fileName));
            return new ObjectResult(result);
        }

        /// <summary>
        /// 库存变更
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult ChangeLocation([FromBody]RequestChangeLocation req)
        {
            var data = stock.GetList(f => req.stockIDs.Contains(f.id) && f.projectid == ProjectId && f.status == (int)RowState.Valid).ToList();
            siger_wms_storage_location locationdata;
            if (string.IsNullOrEmpty(req.code))
            {
                locationdata = location.Get(f => f.id == req.locationidafter && f.status == (int)RowState.Valid);
            }
            else
            {
                locationdata = location.Get(f => f.serial_number == req.code && f.status == (int)RowState.Valid);
            }
            var pids = locationType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).Select(f => f.parentid);
            //获取储位最后一层的类别
            var lastlocationType = locationType.GetList(f => f.status == (int)RowState.Valid && !pids.Contains(f.id) && f.projectid == ProjectId).Select(f => f.id);
            if (string.IsNullOrEmpty(req.code) && !location.IsExist(f => f.id == req.locationidafter && f.status == (int)RowState.Valid && lastlocationType.Contains(f.typeid) && f.projectid == ProjectId))
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            if (!string.IsNullOrEmpty(req.code) && !location.IsExist(f => f.serial_number == req.code && f.status == (int)RowState.Valid && lastlocationType.Contains(f.typeid) && f.projectid == ProjectId))
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            if (locationdata == null)
            {
                throw new BadRequestException(RequestEnum.LocationError);
            }
            var endstorage = storage.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.id == locationdata.storageid);
            if (endstorage == null)
            {
                throw new BadRequestException(RequestEnum.StorageError);
            }
            var username = orderdetail.GetUserName(UserId);
            foreach (var item in data.ToList())
            {
                var tmpLocation = location.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.id == item.storage_location_id);
                if (tmpLocation == null)
                {
                    continue;
                }
                if (tmpLocation.storageid != endstorage.id)
                {
                    throw new BadRequestException(RequestEnum.StorageDeny);
                }
                var billID = trace.Get(f => f.stockNo == item.stockNo)?.billID ?? "";
                var tmp = new siger_wms_stock_detail
                {
                    billID = billID,
                    stockNo = item.stockNo,
                    type = (int)traceType.LocationChange,
                    inventory = item.material_id,
                    inventoryName = item.material_name,
                    inventorySN = item.material_pn,
                    inventorySpec = item.material_spec,
                    locationid = item.storage_location_id,
                    locationname = locationdata.name,
                    batch = item.batch_number,
                    no = item.serial_number,
                    userid = UserId,
                    username = username.ToString(),
                    updatetime = DateTime.Now,
                    state = (int)RowState.Valid,
                    projectid = ProjectId,
                    allqty = item.quantity,
                    qty = item.quantity,
                    businessid = item.businessid,
                    businessName = orderdetail.GetBusinessName(item.businessid, ProjectId)
                };
                trace.Insert(tmp);
                item.storage_location_id = locationdata.id;
                item.update_time = DateTime.Now;
                item.updator = UserId;
                stock.Update(item);
            }
            if (_unitOfWork.Commit() <= 0)
                throw new BadRequestException(CommonEnum.Fail);
            return Ok();
        }

        /// <summary>
        /// 获取在库的物料信息
        /// </summary>
        /// <param name="businessid"></param>
        /// <param name="pn"></param>
        /// <param name="type">物料管理模式:批量、批次、序号</param>
        /// <param name="filter"></param>
        /// <param name="locationid"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public IActionResult GetInventory(int businessid, string pn, int type, string filter, int locationid, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            IQueryable<siger_wms_stock> data = stock.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.quantity > 0 && f.stock_state == (int)StockEnum.InWavehouse);
            if (!string.IsNullOrEmpty(pn))
            {
                data = data.Where(f => f.material_pn == pn.Trim());
            }
            if (businessid != 0)
            {
                data = data.Where(f => f.businessid == businessid);
            }
            switch ((managemodel)type)
            {
                case managemodel.Batch:
                    data = data.Where(f => f.manage_model == ((int)managemodel.Batch).ToString());
                    if (!string.IsNullOrEmpty(filter))
                    {
                        data = data.Where(f => f.batch_number == filter);
                    }
                    break;
                case managemodel.No:
                    data = data.Where(f => f.manage_model == ((int)managemodel.No).ToString());
                    if (!string.IsNullOrEmpty(filter))
                    {
                        data = data.Where(f => f.serial_number == filter);
                    }
                    break;
                case managemodel.Group:
                    data = data.Where(f => f.manage_model == ((int)managemodel.Group).ToString());
                    if (!string.IsNullOrEmpty(filter))
                    {
                        data = data.Where(f => f.material_pn == filter);
                    }
                    if (locationid != 0)
                    {
                        data = data.Where(f => f.storage_location_id == locationid);
                    }
                    break;
                default:
                    if (locationid != 0)
                    {
                        data = data.Where(f => f.storage_location_id == locationid);
                    }
                    break;
            }
            var totalValue = data.Count();
            var result = new List<ResponseGetInventory>();
            var locationids = data.Select(f => f.storage_location_id).Distinct().ToList();
            var locationDic = location.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToDictionary(f => f.id, f => f.name);
            foreach (var item in data.ToList())
            {
                var tmp = Mapper<siger_wms_stock, ResponseGetInventory>.Map(item);
                var locationData = location.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.id == tmp.storage_location_id);
                if(locationData==null)
                {
                    continue;
                }
                tmp.storageID = locationData.storageid;
                //将供应商信息存入详情中
                if (item.category != WaveHousingType.Production.ToString() &&
                    item.category != WaveHousingType.ProductionOut.ToString())
                {
                    //供应商信息
                    var businessName = location.GetBusinessName(item.businessid, ProjectId);
                    tmp.businessName = businessName;
                }
                if (locationDic.TryGetValue(item.storage_location_id, out string snValue))
                {
                    tmp.storage_location_name = snValue;
                    result.Add(tmp);
                }
            }
            result = result.Skip((page - 1) * pageSize).Take(pageSize).ToList();
            return new PagedObjectResult(result, totalValue, page, pageSize);
        }
        /// <summary>
        /// 库存调整列表
        /// </summary>
        /// <param name="businessid"></param>
        /// <param name="filter"></param>
        /// <param name="locationid"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public IActionResult GetInventoryWithoutNo(int businessid,string filter, int locationid, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            IQueryable<siger_wms_stock> data = stock.GetList(f => f.manage_model != ((int)managemodel.No).ToString() && f.status == (int)RowState.Valid && f.projectid == ProjectId && f.quantity > 0 && f.stock_state == (int)StockEnum.InWavehouse);
            if (!string.IsNullOrEmpty(filter))
            {
                data = data.Where(f => f.material_pn == filter);
            }
            if (locationid != 0)
            {
                data = data.Where(f => f.storage_location_id == locationid);
            }
            if(businessid!=0)
            {
                data = data.Where(f=>f.businessid==businessid);
            }
            var totalCount = data.Count();
            data = data.Skip((page - 1) * pageSize).Take(pageSize);
            var result = new List<ResponseGetInventory>();
            var locationids = data.Select(f => f.storage_location_id).Distinct().ToList();
            var locationDic = location.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToDictionary(f => f.id, f => f.name);
            foreach (var item in data.ToList())
            {
                var tmp = Mapper<siger_wms_stock, ResponseGetInventory>.Map(item);
                tmp.storage_location_name = locationDic[item.storage_location_id];
                tmp.businessName = orderdetail.GetBusinessName(item.businessid, ProjectId);
                result.Add(tmp);
            }
            return new PagedObjectResult(result, totalCount, page, pageSize);
        }

        [HttpPost]
        public IActionResult AddLocation([FromBody]RequestAddLocationModel req)
        { 
            if (req.storeID.ToInt() <= 0 || req.storeArr == null || !req.storeArr.Any() || req.warehouseid <= 0)
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }
            var locationTypes = locationtype.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid).ToList();
            if (!locationTypes.Any())
            {
                throw new BadRequestException(RequestEnum.LocationTypeNotFound);
            }
            var sonLocationTypes = GetSonTypes(0, locationTypes).ToList();

            if(req.storeArr.Count != sonLocationTypes.Count)
            {
                throw new BadRequestException(RequestEnum.LocationLevelError);
            }

            foreach(var store in req.storeArr)
            {
                if (string.IsNullOrEmpty(store.val))
                {
                    throw new BadRequestException(RequestEnum.ParameterMiss);
                }
            }

            var locationTypeId = sonLocationTypes.LastOrDefault()?.id ?? 0;
            var waveHouse = storage.Get(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.id == req.warehouseid);
            if (waveHouse == null)
            {
                throw new BadRequestException(RequestEnum.WaveHouseIDNotExist);
            }

            if (req.storeArr.Count != locationTypes.Count)
            {
                throw new BadRequestException(RequestEnum.LocationCountError);
            }            
            foreach (var Location in req.storeArr)
            {
                if (Location.id == locationTypeId)
                {
                    var locationIdExist = location.Get(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.typeid == locationTypeId &&
                        q.locationid == req.storeID.ToInt() && q.storageid == req.warehouseid);
                    if (locationIdExist != null)
                    {
                        throw new BadRequestException(RequestEnum.IDExist);
                    }
                }
                //判断名称重复
                //if (req.storeArr.Count(q => q.val == Location.val) > 1)
                //{
                //    throw new BadRequestException(RequestEnum.DataExist);
                //}
                //var loca = location.Get(q => q.realname == Location.val && q.projectid == ProjectId);
                //if (loca != null)
                //{
                //    throw new BadRequestException(RequestEnum.DataExist);
                //}
            }

            var ids = new List<int>();
            var parentid = 0;
            foreach (var locationType in sonLocationTypes)
            {
                var Location = req.storeArr.FirstOrDefault(q => q.id == locationType.id);
                if (Location == null)
                {
                    throw new BadRequestException(CommonEnum.Fail);//TODO
                }
                var tmp = new siger_wms_storage_location
                {
                    storageid = req.warehouseid,
                    parentid = parentid,
                    name = "",
                    realname = Location.val,
                    typeid = Location.id,
                    serial_number = Utility.GenSerialNumber(),
                    creator = UserId,
                    create_time = DateTime.Now,
                    updator = UserId,
                    update_time = DateTime.Now,
                    projectid = ProjectId,
                    status = req.status == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid,
                    locationid = Location.id == locationTypeId ? req.storeID.ToInt() : 0
                };
                parentid = InsertLocation(tmp, waveHouse.name);
                if (parentid > 0)
                {
                    ids.Add(parentid);
                    continue;
                }
                else
                {
                    foreach (var id in ids)
                    {
                        location.Delete(id);
                    }
                    throw new BadRequestException(CommonEnum.Fail);//TODO
                }
            }
            return new ObjectResult(CommonEnum.Succefull);
        }
        private int InsertLocation(siger_wms_storage_location tmp, string waveHouseName)
        {
            int id = 0;
            location.Insert(tmp);
            if (_unitOfWork.Commit() <= 0)
            {
                return id;
            }

            //更新编号、层级名称
            var sn = new StringBuilder();
            sn.Append(tmp.id);
            var parent = location.Get(f => f.id == tmp.parentid && tmp.parentid != 0 && f.projectid == ProjectId && f.status == (int)RowState.Valid);
            var parentname = "";
            if (parent != null)
            {
                parentname = parent.name;
            }
            while (parent != null)
            {
                sn.Insert(0, parent.id + "_");
                parent = location.Get(f => f.id == parent.parentid && parent.parentid != 0 && f.projectid == ProjectId && f.status == (int)RowState.Valid);
            }
            //仓库
            sn.Insert(0, tmp.storageid + "_");
            tmp.serial_number = sn.ToString();

            //上级为仓库
            if (tmp.parentid == 0)
            {
                tmp.name = $"{waveHouseName} -> {tmp.realname}";
            }
            else
            {
                tmp.name = $"{parentname} -> {tmp.realname}";
            }
            location.Update(tmp);
            if (_unitOfWork.Commit() <= 0)
            {
                return id;
            }

            return tmp.id;
        }
        [HttpPost]
        public IActionResult UpdateLocation([FromBody]RequestAddLocationModel req)
        {
            if (req.storeID.ToInt() <= 0 || req.storeArr == null || !req.storeArr.Any() || req.warehouseid <= 0)
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }
            var locationTypes = locationtype.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid).ToList();
            if (!locationTypes.Any())
            {
                throw new BadRequestException(RequestEnum.LocationTypeNotFound);
            }
            var sonLocationTypes = GetSonTypes(0, locationTypes).ToList();

            if (req.storeArr.Count != sonLocationTypes.Count)
            {
                throw new BadRequestException(RequestEnum.LocationLevelError);
            }

            foreach (var store in req.storeArr)
            {
                if (string.IsNullOrEmpty(store.val))
                {
                    throw new BadRequestException(RequestEnum.ParameterMiss);
                }
            }

            var locationTypeId = sonLocationTypes.LastOrDefault()?.id ?? 0;
            var waveHouse = storage.Get(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.id == req.warehouseid);
            if (waveHouse == null)
            {
                throw new BadRequestException(RequestEnum.WaveHouseIDNotExist);
            }

            if (req.storeArr.Count != locationTypes.Count)
            {
                throw new BadRequestException(RequestEnum.LocationCountError);
            }
            
            foreach (var Location in req.storeArr)
            {
                if(Location.id == locationTypeId)
                {
                    var locationIdExist = location.Get(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.typeid == locationTypeId &&
                        q.locationid == req.storeID.ToInt() && q.id != Location.locationid.ToInt() && q.storageid == req.warehouseid);
                    if (locationIdExist != null)
                    {
                        throw new BadRequestException(RequestEnum.IDExist);
                    }
                }
                //判断名称重复
                //if (req.storeArr.Count(q => q.val == Location.val) > 1)
                //{
                //    throw new BadRequestException(RequestEnum.DataExist);
                //}
                //var loca = location.Get(q => q.realname == Location.val && q.projectid == ProjectId && q.id != Location.locationid.ToInt());
                //if (loca != null)
                //{
                //    throw new BadRequestException(RequestEnum.DataExist);
                //}
            }

            var ids = new List<int>();
            foreach (var locationType in sonLocationTypes)
            {
                var Location = req.storeArr.FirstOrDefault(q => q.id == locationType.id);
                if (Location == null)
                {
                    throw new BadRequestException(CommonEnum.Fail);//TODO
                }
                var tmp = location.Get(q => q.projectid == ProjectId && q.id == Location.locationid.ToInt());
                tmp.status = req.status == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid;
                tmp.storageid = req.warehouseid;
                tmp.locationid = req.storeID.ToInt();
                tmp.realname = Location.val;
                if (tmp.parentid == 0)
                {
                    tmp.locationid = Location.id == locationTypeId ? req.storeID.ToInt() : 0;
                    tmp.name = $"{waveHouse.name} -> {tmp.realname}";
                }
                location.Update(tmp);
            }
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }
        private IEnumerable<siger_wms_storage_location_type> GetSonTypes(int id, List<siger_wms_storage_location_type> types)
        {
            var query = from c in types where c.parentid == id select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonTypes(t.id, types)));
        }


        [HttpGet]
        public IActionResult GetLocationTree(int warehouseid)
        {
            var locationTypes = locationtype.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid).ToList();
            var sonLocationTypes = GetSonTypes(0, locationTypes).ToList();
            var lastLocationId = sonLocationTypes.LastOrDefault()?.id ?? 0;
            var allLocas = location.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid).ToList();
            var locations = allLocas.Where(q => q.typeid == lastLocationId);
            if(warehouseid > 0)
            {
                locations = locations.Where(q => q.storageid == warehouseid);
            }
            var locationTreeList = new List<LevelSectionTree>();
            foreach(var loca in locations)
            {
                var locas = GetParentLocations(loca.id, allLocas.Select(q => new LevelSectionTree
                {
                    id = q.id,
                    pid = q.parentid,
                    title = q.realname,
                    name = q.realname
                }));
                locationTreeList.AddRange(locas);
            }
            var locationTree = locationTreeList.GroupBy(q => q.id).Select(q => q.FirstOrDefault()).ToList();

            return new ObjectResult(ConvertToTree(locationTree));
        }

        private IEnumerable<LevelSectionTree> GetParentLocations(int pid, IEnumerable<LevelSectionTree> types)
        {
            var query = from c in types where c.id == pid select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLocations(t.pid, types)));
        }

        private IList<LevelSectionTree> ConvertToTree(IEnumerable<LevelSectionTree> models)
        {
            var section = new Dictionary<int, LevelSectionTree>();
            foreach (var item in models)
            {
                section.Add(item.id, item);
            }
            var result = new List<LevelSectionTree>();
            foreach (var item in section.Values)
            {
                if (item.pid == 0)
                {
                    result.Add(item);
                }
                else
                {
                    if (section.ContainsKey(item.pid))
                    {
                        section[item.pid].AddChilrden(item);
                    }
                }
            }
            return result;
        }
    }
}