using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.Enums;
using WIDESEA_Core;
using WIDESEA_DTO.Stock;
using WIDESEA_Model.Models;
using WIDESEA_Core.Helper;
using WIDESEA_Common.OtherEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
using MailKit.Search;
using WIDESEA_External.Model;
using WIDESEA_Core.CodeConfigEnum;
using Microsoft.AspNetCore.Mvc;
using WIDESEA_DTO.ERP;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
namespace WIDESEA_TaskInfoService
{
public partial class TaskService
{
///
/// 选择库存生成出库任务
///
///
///
public WebResponseContent Outbound(int id)
{
WebResponseContent content = new WebResponseContent();
try
{
Dt_StockInfo stockInfo = _stockRepository.StockInfoRepository.Db.Queryable().Where(x => x.Id == id).Includes(x => x.Details).First();
if (stockInfo == null)
{
return content.Error($"未找到库存");
}
Dt_LocationInfo locationInfo = _basicRepository.LocationInfoRepository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode);
if (locationInfo != null && (locationInfo.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || locationInfo.EnableStatus == EnableStatusEnum.Normal.ObjToInt()) && locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt() && stockInfo.StockStatus == StockStatusEmun.入库完成.ObjToInt())
{
List tasks = GetTasks(new List() { stockInfo }, TaskTypeEnum.Outbound);
if (tasks == null || tasks.Count <= 0)
{
return content.Error($"生成任务失败");
}
//处理库存数据
stockInfo.StockStatus = (int)StockStatusEmun.出库锁定;
LocationStatusEnum locationStatus = (LocationStatusEnum)locationInfo.LocationStatus;
locationInfo.LocationStatus = (int)LocationStatusEnum.Lock;
//判断是否有出库单信息
_unitOfWorkManage.BeginTran();
//更新库存状态
_stockRepository.StockInfoRepository.UpdateData(stockInfo);
//更新货位状态
_basicService.LocationInfoService.UpdateLocationStatus(locationInfo, stockInfo.PalletType, LocationStatusEnum.Lock, stockInfo.WarehouseId);
//新建任务
BaseDal.AddData(tasks);
//加入货位变动记录
_recordService.LocationStatusChangeRecordSetvice.AddLocationStatusChangeRecord(locationInfo, locationStatus, LocationStatusEnum.Lock, LocationChangeType.OutboundAssignLocation, stockInfo.Details.FirstOrDefault()?.OrderNo ?? "", tasks[0].TaskNum);
_unitOfWorkManage.CommitTran();
PushTasksToWCS(tasks);
content.OK();
}
else
{
content.Error($"货位出库条件不满足");
}
}
catch (Exception ex)
{
content.Error(ex.Message);
}
return content;
}
///
/// 选定库存生成盘点单出库
///
///
///
public WebResponseContent TakeOutbound(List stockViews)
{
WebResponseContent content = new WebResponseContent();
try
{
if (stockViews.Select(x=>x.WarehouseId).Distinct().Count()>=2)
{
return content.Error($"请选择同一仓库库存进行盘点");
}
List ids = stockViews.Select(x => x.StockId).ToList();
//获取库存
List stockInfos = _stockRepository.StockInfoRepository.Db.Queryable().Where(x => ids.Contains(x.Id)).Includes(x => x.Details).ToList();
if (stockInfos.Count!= stockViews.Count)
{
StockViewDTO? stockViewDTO = stockViews.FirstOrDefault(x=> !stockInfos.Select(x=>x.PalletCode).ToList().Contains(x.PalletCode));
return content.Error($"未找到{stockViewDTO?.PalletCode}库存");
}
//获取货位
List locStrs = stockInfos.Select(x => x.LocationCode).ToList();
List locationInfos =_basicRepository.LocationInfoRepository.QueryData(x=> locStrs.Contains(x.LocationCode));
if (stockInfos.Count != locationInfos.Count)
{
string? locStr = locStrs.FirstOrDefault(x=> !locationInfos.Select(x => x.LocationCode).ToList().Contains(x));
return content.Error($"未找到{locStr}货位数据");
}
Dt_TakeStockOrder takeStockOrder = new Dt_TakeStockOrder()
{
WarehouseId = stockInfos.FirstOrDefault().WarehouseId,
TakeStockStatus = TakeStockStatusEnum.盘点中.ObjToInt(),
Details = new List()
};
foreach (var item in stockInfos)
{
if (item.Details.Count<=0)
{
return content.Error($"未找到{item.PalletCode}库存明细数据");
}
Dt_LocationInfo? locationInfo = locationInfos.FirstOrDefault(x=>x.LocationCode==item.LocationCode);
if (locationInfo != null && (locationInfo.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || locationInfo.EnableStatus == EnableStatusEnum.Normal.ObjToInt()) && locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt() && item.StockStatus == StockStatusEmun.入库完成.ObjToInt())
{
//创建明细
Dt_TakeStockOrderDetail takeStockOrderDetail = new Dt_TakeStockOrderDetail()
{
MaterielCode= item.Details.FirstOrDefault().MaterielCode,
MaterielName=item.Details.FirstOrDefault().MaterielName ?? "无物料名称",
BatchNo=item.Details.FirstOrDefault().BatchNo,
MaterielSpec=item.Details.FirstOrDefault().MaterielSpec ?? "无物料规格",
LocationCode=item.LocationCode,
TakePalletCode=item.PalletCode,
TakeDetalStatus=TakeStockDetailStatusEnum.盘点出库中.ObjToInt(),
Unit=item.Details.FirstOrDefault().Unit ?? "无单位",
SysQty=item.Details.Sum(x=>x.StockQuantity),
Qty=0
};
takeStockOrder.Details.Add(takeStockOrderDetail);
}
else
{
content.Error($"货位或库存状态不满足出库条件");
}
}
List tasks = GetTasks(stockInfos, TaskTypeEnum.OutInventory);
if (tasks == null || tasks.Count <= 0)
{
return content.Error($"生成任务失败");
}
stockInfos.ForEach(x =>
{
x.StockStatus = StockStatusEmun.出库锁定.ObjToInt();
});
LocationStatusEnum locationStatus = LocationStatusEnum.Lock;
_unitOfWorkManage.BeginTran();
//更新库存状态
_stockRepository.StockInfoRepository.UpdateData(stockInfos);
_inboundRepository.TakeStockOrderRepository.Db.InsertNav(takeStockOrder).Include(x=>x.Details).ExecuteCommand();
//新建任务
BaseDal.AddData(tasks);
//加入货位变动记录
_recordService.LocationStatusChangeRecordSetvice.AddLocationStatusChangeRecord(locationInfos, locationStatus, LocationChangeType.OutboundAssignLocation, "", tasks?.Select(x => x.TaskNum).ToList());
_basicService.LocationInfoService.Repository.UpdateLocationStatus(locationInfos, locationStatus);
_unitOfWorkManage.CommitTran();
PushTasksToWCS(tasks);
content.OK();
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
content.Error(ex.Message);
}
return content;
}
///
/// 生成成品出库任务
///
/// 出库订单号
/// 站台地址
///
public async Task OutProductTask(int[] keys, string StationCode, int Grade)
{
WebResponseContent content = new WebResponseContent();
try
{
if (StationCode.IsNullOrEmpty())
{
return await Task.FromResult(content.Error("线体输入错误"));
}
//获取成品出库订单
List _ProOutOrderDetails = await _outboundRepository.ProOutOrderDetailRepository.QueryDataAsync(x => keys.Contains(x.Id) && x.ProOrderDetailStatus== OrderDetailStatusEnum.New.ObjToInt());
if (_ProOutOrderDetails.Count<=0)
{
return await Task.FromResult(content.Error("勾选订单明细状态为出库中"));
}
List tasks = new List();
List stockSelectViews = new List();
List proStockInfos = new List();
List proOutOrderDetails = new List();
List outProStockInfos = new List();
List locationInfos = new List();
(List, List?, List?, List?, List?) result =
OutProductTaskDataHandle(_ProOutOrderDetails);
if (result.Item2 != null && result.Item2.Count > 0)
{
proStockInfos.AddRange(result.Item2);
}
if (result.Item3 != null && result.Item3.Count > 0)
{
proOutOrderDetails.AddRange(result.Item3);
}
if (result.Item4 != null && result.Item4.Count > 0)
{
outProStockInfos.AddRange(result.Item4);
}
if (result.Item5 != null && result.Item5.Count > 0)
{
locationInfos.AddRange(result.Item5);
}
if (result.Item1 != null && result.Item1.Count > 0)
{
Dt_Task? task = BaseDal.QueryData(x=>x.TaskType==TaskTypeEnum.OutProduct.ObjToInt()).OrderBy(x=>x.Grade).FirstOrDefault();
//更新出库目的位置
result.Item1.ForEach(x =>
{
x.TargetAddress = StationCode;
if (Grade==1 || task==null)
{
x.Grade = 127;
}
else
{
if (task.Grade==0 || task.Grade==1)
{
x.Grade = 1;
}
else
{
x.Grade = task.Grade - 1;
}
}
});
tasks.AddRange(result.Item1);
}
//处理出库数据
return await Task.FromResult(GenerateOutboundTaskDataUpdate(tasks, proStockInfos, proOutOrderDetails, outProStockInfos, locationInfos));
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
content.Error(ex.Message);
}
return content;
}
///
/// 人工选定库存出库
///
///
public WebResponseContent OutProductSelect(int orderDetailId,List proStockViews)
{
WebResponseContent content = new WebResponseContent();
try
{
//获取出库单明细
Dt_ProOutOrderDetail proOutOrderDetail = _outboundRepository.ProOutOrderDetailRepository.QueryFirst(x=>x.Id==orderDetailId);
if (proOutOrderDetail == null)
{
return content.Error("订单明细不存在");
}
if (proOutOrderDetail.ProOrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
{
return content.Error("当前的明细单已完成");
}
//获取出库单据
Dt_ProOutOrder proOutOrder = _outboundRepository.ProOutOrderRepository.Db.Queryable().Where(x=>x.Id==proOutOrderDetail.ProOrderId).Includes(x => x.Details).First();
if (proOutOrder==null)
{
return content.Error("出库单据不存在");
}
if (proOutOrder.ProOrderStatus>=OutOrderStatusEnum.出库完成.ObjToInt())
{
return content.Error($"{proOutOrder.ProOutOrderNo}出库单已完成");
}
if ((proOutOrderDetail.QtyPcs-proOutOrderDetail.OverQtyPcs)> proStockViews.Sum(x=>x.SumStocks))
{
return content.Error($"需满足{proOutOrderDetail.QtyPcs - proOutOrderDetail.OverQtyPcs}出库量");
}
//获取所有库存
List proStockInfos = _stockRepository.ProStockInfoRepository.Db.Queryable().Where(b => b.LocationCode == "成品待发货区" && b.StockStatus == StockStatusEmun.平库入库完成.ObjToInt() && (b.ShipmentOrder == null || b.ShipmentOrder == "")).Includes(x => x.proStockInfoDetails).Where(x => x.proStockInfoDetails.Any(v => v.ProductCode == proOutOrderDetail.PCode)).ToList();
//获取已完成数量
int OverCount = proOutOrder.Details.Where(x => x.ProOrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count();
List outStockInfos=new List();
List outStockInfoDetails=new List();
List stockOutItems = new List();
foreach (var item in proStockViews.OrderBy(x => x.SumStocks))
{
//获取当前库存
Dt_ProStockInfo? proStockInfo = proStockInfos.FirstOrDefault(x => x.Id == item.ProStockId);
if (proStockInfo!=null && proStockInfo.proStockInfoDetails.Count>0)
{
proStockInfo.ShipmentOrder = proOutOrder.ProOutOrderNo;
proStockInfo.StockStatus = StockStatusEmun.平库待发货.ObjToInt();
//剩余数量
float Amount = proOutOrderDetail.QtyPcs - proOutOrderDetail.LockQtyPcs;
if (Amount > item.SumStocks)
{
proOutOrderDetail.LockQtyPcs += item.SumStocks;
Dt_ProStockInfoDetail proStockInfoDetail = proStockInfo.proStockInfoDetails.FirstOrDefault();
proStockInfoDetail.OutboundQuantity = proStockInfoDetail.StockPcsQty;
proStockInfoDetail.OutSETQty = proStockInfoDetail.SETQty;
proStockInfoDetail.OutDetailSaleNo = proOutOrderDetail.SaleOrder;
outStockInfoDetails.Add(proStockInfoDetail);
}
else
{
Dt_ProStockInfoDetail proStockInfoDetail = proStockInfo.proStockInfoDetails.FirstOrDefault();
float intervalSet = proStockInfoDetail.StockPcsQty / proStockInfoDetail.SETQty;
proStockInfoDetail.OutboundQuantity += Amount;
proStockInfoDetail.OutSETQty += (Amount / intervalSet);
proOutOrderDetail.LockQtyPcs += Amount;
proStockInfoDetail.OutDetailSaleNo = proOutOrderDetail.SaleOrder;
outStockInfoDetails.Add(proStockInfoDetail);
}
if (proOutOrderDetail.QtyPcs==proOutOrderDetail.LockQtyPcs)
{
proOutOrderDetail.ProOrderDetailStatus = OrderDetailStatusEnum.Over.ObjToInt();
}
outStockInfos.Add(proStockInfo);
}
else
{
return content.Error("未找到成品库存");
}
}
List deleteStocks=new List();
List deleteStockDetails = new List();
List updateStocks = new List();
List updateStockDetails = new List();
if (proOutOrderDetail.ProOrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt() && (OverCount+1)== proOutOrder.Details.Count)
{
proOutOrder.ProOrderStatus=OutOrderStatusEnum.出库完成.ObjToInt();
//获取所有已扫码待发货的库存
List AllOutStocks = _stockRepository.ProStockInfoRepository.Db.Queryable()
.Where(x => x.ShipmentOrder == proOutOrder.ProOutOrderNo && x.StockStatus == StockStatusEmun.平库待发货.ObjToInt())
.Includes(x => x.proStockInfoDetails).ToList();
AllOutStocks.ForEach(x =>
{
outStockInfoDetails.AddRange(x.proStockInfoDetails);
});
outStockInfos.AddRange(AllOutStocks);
foreach (var item in outStockInfoDetails)
{
StockOutItemsItem outItemsItem = new StockOutItemsItem()
{
PartNum = item.ProductCode,
Rev = item.ProductVersion,
SoNumber = item.OutDetailSaleNo,
BatchNumber = item.BagNo,
QtyPcs = item.OutboundQuantity,
QtySet = item.OutSETQty
};
stockOutItems.Add(outItemsItem);
if (item.OutboundQuantity == item.StockPcsQty)
{
Dt_ProStockInfo proStockInfo = outStockInfos.FirstOrDefault(x => x.Id == item.ProStockId);
if (proStockInfo != null)
{
deleteStocks.Add(proStockInfo);
deleteStockDetails.Add(item);
}
else
{
return content.Error("未找到上报的库存数据");
}
}
if (item.OutboundQuantity < item.StockPcsQty)
{
Dt_ProStockInfo proStockInfo = outStockInfos.FirstOrDefault(x => x.Id == item.ProStockId);
if (proStockInfo != null)
{
proStockInfo.StockStatus = StockStatusEmun.平库入库完成.ObjToInt();
proStockInfo.ShipmentOrder = "";
updateStocks.Add(proStockInfo);
item.StockPcsQty -= item.OutboundQuantity;
item.OutboundQuantity = 0;
item.OutSETQty = 0;
updateStockDetails.Add(item);
}
else
{
return content.Error("未找到上报的库存数据");
}
}
}
}
Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseId == proOutOrder.WarehouseId);
_unitOfWorkManage.BeginTran();
if (proOutOrder.ProOrderStatus == OutOrderStatusEnum.出库完成.ObjToInt())
{
//成品库存记录变动待加入
ERPProOutOrderModel proOutOrderModel = new ERPProOutOrderModel()
{
Way = 1,
StockOutCode = _outboundService.OutboundOrderService.CreateCodeByRule(nameof(RuleCodeEnum.ProOutCOdeRule)),
ConfirmedUserNo = App.User.UserName,
AssignUserNo = App.User.UserName,
WarehouseCode = warehouse.WarehouseCode,
ShipDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
DeliverplanCode = proOutOrder.ProOutOrderNo,
Remark = proOutOrder.Remark,
StockOutItems = stockOutItems
};
_stockRepository.ProStockInfoRepository.DeleteAndMoveIntoHty(deleteStocks, OperateTypeEnum.自动完成);
_stockRepository.ProStockInfoDetailRepository.DeleteAndMoveIntoHty(deleteStockDetails, OperateTypeEnum.自动完成);
if (updateStockDetails.Count>0)
{
_stockRepository.ProStockInfoRepository.UpdateData(updateStocks);
updateStockDetails.ForEach(x =>
{
x.OutDetailSaleNo = "";
});
_stockRepository.ProStockInfoDetailRepository.UpdateData(updateStockDetails);
}
string response = _invokeERPService.InvokeProOutApi(proOutOrderModel);
ErpRequestContent erpRequestContent = response.DeserializeObject();
if (erpRequestContent.res != 1)
{
throw new Exception("同步ERP失败,错误信息:" + erpRequestContent.Data);
}
}
else
{
_stockRepository.ProStockInfoRepository.UpdateData(outStockInfos);
_stockRepository.ProStockInfoDetailRepository.UpdateData(outStockInfoDetails);
_outboundRepository.ProOutOrderDetailRepository.UpdateData(proOutOrderDetail);
_outboundRepository.ProOutOrderRepository.UpdateData(proOutOrder);
}
_unitOfWorkManage.CommitTran();
content.OK("成功");
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
content.Error(ex.Message);
}
return content;
}
///
/// 处理出库数据
///
public WebResponseContent GenerateOutboundTaskDataUpdate(List tasks, List? proStockInfos = null, List? proOutOrderDetails = null, List? outProStockInfos = null, List? locationInfos = null)
{
try
{
_unitOfWorkManage.BeginTran();
//获取成品出库单主表
Dt_ProOutOrder proOutOrder = _outboundRepository.ProOutOrderRepository.QueryFirst(x => x.Id == proOutOrderDetails.FirstOrDefault().ProOrderId);
if (proOutOrder!=null && proOutOrder.ProOrderStatus == OutOrderStatusEnum.未开始.ObjToInt())
{
proOutOrder.ProOrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
_outboundRepository.ProOutOrderRepository.UpdateData(proOutOrder);
}
BaseDal.AddData(tasks);
if (proStockInfos != null && proStockInfos.Count > 0 && proOutOrderDetails != null && proOutOrderDetails.Count > 0 && outProStockInfos != null && outProStockInfos.Count > 0 && locationInfos != null && locationInfos.Count > 0)
{
proStockInfos.ForEach(x =>
{
x.StockStatus = StockStatusEmun.出库锁定.ObjToInt();
});
WebResponseContent content = _outboundService.ProOutOrderDetailService.LockOutboundStockDataUpdate(proStockInfos, proOutOrderDetails, outProStockInfos, locationInfos, tasks: tasks);
if (!content.Status)
{
_unitOfWorkManage.RollbackTran();
return content;
}
}
else if (proOutOrderDetails != null && proOutOrderDetails.Count > 0)
{
proOutOrderDetails.ForEach(x =>
{
x.ProOrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
});
_outboundRepository.ProOutOrderDetailRepository.UpdateData(proOutOrderDetails);
}
_unitOfWorkManage.CommitTran();
PushTasksToWCS(tasks);
return WebResponseContent.Instance.OK();
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
return WebResponseContent.Instance.Error(ex.Message);
}
}
///
/// 处理成品出库数据
///
///
public (List, List?, List?, List?, List?) OutProductTaskDataHandle(List proOutOrderDetails)
{
List tasks = new List();
List proStockInfos = new List();
List assignOutOrderDetails = new List();
List outProStockInfos=new List();
List locationInfos = new List();
//分配库存
(List, List, List, List) result = _outboundService.ProOutOrderDetailService.AssignProStockOut(proOutOrderDetails);
if (result.Item1!=null&&result.Item1.Count>0)
{
//获取成品单
Dt_ProOutOrder proOutOrder = _outboundRepository.ProOutOrderRepository.QueryFirst(x => x.Id == proOutOrderDetails.FirstOrDefault().ProOrderId);
if (proOutOrder==null)
{
throw new Exception("未找到成品订单");
}
TaskTypeEnum typeEnum = proOutOrder.ProOrderType switch
{
(int)OutProTypeEnum.ProOut => TaskTypeEnum.OutProduct,
(int)OutProTypeEnum.SendProOut => TaskTypeEnum.OutSendProduct,
_ => new TaskTypeEnum()
};
tasks = GetTasks(result.Item1, typeEnum);
result.Item2.ForEach(x =>
{
x.ProOrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
});
result.Item3.ForEach(x =>
{
x.Status = OutLockStockStatusEnum.出库中.ObjToInt();
});
tasks.ForEach(x => x.OrderNo = proOutOrder.ProOutOrderNo);
proStockInfos = result.Item1;
proOutOrderDetails = result.Item2;
outProStockInfos = result.Item3;
locationInfos = result.Item4;
}
else
{
throw new Exception("无可分配库存");
}
return (tasks, proStockInfos, proOutOrderDetails, outProStockInfos, locationInfos);
}
///
/// 生成任务
///
///
///
///
public List GetTasks(List stockInfos, TaskTypeEnum taskType)
{
List tasks = new List();
string groupId = DateTime.Now.ToString("yyMMddHHmmss");
for (int i = 1; i <= stockInfos.Count; i++)
{
Dt_ProStockInfo stockInfo = stockInfos[i-1];
if (i%5==0)
{
groupId= DateTime.Now.AddSeconds(i).ToString("yyMMddHHmmss");
}
if (stockInfo != null)
{
Dt_LocationInfo locationInfo = _basicService.LocationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode);
if (!tasks.Exists(x => x.PalletCode == stockInfo.PalletCode))
{
Dt_Task task = new()
{
CurrentAddress = stockInfo.LocationCode,
Grade = 0,
PalletCode = stockInfo.PalletCode,
NextAddress = "",
Roadway = locationInfo.RoadwayNo,
SourceAddress = stockInfo.LocationCode,
TargetAddress = "",
TaskStatus = TaskStatusEnum.New.ObjToInt(),
TaskType = taskType.ObjToInt(),
TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)),
PalletType = stockInfo.PalletType,
WarehouseId = stockInfo.WarehouseId,
GroupId= groupId,
MaterielCode = stockInfo.proStockInfoDetails.Where(x => x.ProStockId == stockInfo.Id).FirstOrDefault()?.ProductCode,
Quantity = (float)stockInfo.proStockInfoDetails.Where(x => x.ProStockId == stockInfo.Id).Sum(x=> x.StockPcsQty)
};
tasks.Add(task);
}
}
}
return tasks;
}
///
/// 库存数据转出库任务
///
///
///
public List GetTasks(List stockInfos, TaskTypeEnum taskType)
{
List tasks = new List();
for (int i = 0; i < stockInfos.Count; i++)
{
Dt_StockInfo stockInfo = stockInfos[i];
if (stockInfo != null)
{
Dt_LocationInfo locationInfo = _basicService.LocationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode);
if (!tasks.Exists(x => x.PalletCode == stockInfo.PalletCode))
{
Dt_Task task = new()
{
CurrentAddress = stockInfo.LocationCode,
Grade = 0,
PalletCode = stockInfo.PalletCode,
NextAddress = "",
Roadway = locationInfo.RoadwayNo,
SourceAddress = stockInfo.LocationCode,
TargetAddress = "",
TaskStatus = TaskStatusEnum.New.ObjToInt(),
TaskType = taskType.ObjToInt(),
TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)),
PalletType = stockInfo.PalletType,
WarehouseId = stockInfo.WarehouseId,
};
if (taskType != TaskTypeEnum.OutEmpty)
{
task.MaterielCode = stockInfo.Details?.Where(x => x.StockId == stockInfo.Id).FirstOrDefault()?.MaterielCode;
task.Quantity = (float)stockInfo.Details?.Where(x => x.StockId == stockInfo.Id).Sum(x => x.StockQuantity);
}
if (stockInfo.StockLength>0)
{
task.TaskLength = stockInfo.StockLength;
}
tasks.Add(task);
}
}
}
return tasks;
}
///
/// 出库任务数据处理
///
///
///
///
///
public (List, List?, List?, List?, List?) OutboundTaskDataHandle(int orderDetailId, List stockSelectViews)
{
List tasks = new List();
Dt_OutboundOrderDetail outboundOrderDetail = _outboundService.OutboundOrderDetailService.Repository.QueryFirst(x => x.Id == orderDetailId);
if (outboundOrderDetail == null)
{
throw new Exception("未找到出库单明细信息");
}
if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity)
{
throw new Exception("选择数量超出单据数量");
}
List? stockInfos = null;
Dt_OutboundOrderDetail? orderDetail = null;
List? outStockLockInfos = null;
List? locationInfos = null;
if (outboundOrderDetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt())
{
(List, Dt_OutboundOrderDetail, List, List) result = _outboundService.OutboundOrderDetailService.AssignStockOutbound(outboundOrderDetail, stockSelectViews);
if (result.Item1 != null && result.Item1.Count > 0)
{
Dt_OutboundOrder outboundOrder = _outboundService.OutboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetail.OrderId);
TaskTypeEnum typeEnum = outboundOrder.OrderType switch
{
(int)OutOrderTypeEnum.Issue => TaskTypeEnum.Outbound,
(int)OutOrderTypeEnum.Allocate => TaskTypeEnum.OutAllocate,
(int)OutOrderTypeEnum.Quality => TaskTypeEnum.OutQuality,
_ => new TaskTypeEnum()
};
tasks = GetTasks(result.Item1, typeEnum);
result.Item2.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
result.Item3.ForEach(x =>
{
x.Status = OutLockStockStatusEnum.出库中.ObjToInt();
});
stockInfos = result.Item1;
orderDetail = result.Item2;
outStockLockInfos = result.Item3;
locationInfos = result.Item4;
}
else
{
throw new Exception("无库存");
}
}
else
{
List stockLockInfos = _outboundService.OutboundStockLockInfoService.GetByOrderDetailId(outboundOrderDetail.OrderId, OutLockStockStatusEnum.已分配);
if (stockLockInfos != null && stockLockInfos.Count > 0)
{
List stocks = _stockService.StockInfoService.Repository.GetStockInfosByPalletCodes(stockLockInfos.Select(x => x.PalletCode).Distinct().ToList());
tasks = GetTasks(stocks, TaskTypeEnum.Outbound);
}
}
return (tasks, stockInfos, orderDetail == null ? null : new List { orderDetail }, outStockLockInfos, locationInfos);
}
///
/// 出库任务数据处理
///
///
///
///
///
public (List, List?, List?, List?, List?) OutboundTaskDataHandle(int[] keys)
{
List tasks = new List();
List outboundOrderDetails = _outboundService.OutboundOrderDetailService.Repository.QueryData(x => keys.Contains(x.Id));
if (outboundOrderDetails == null || outboundOrderDetails.Count == 0)
{
throw new Exception("未找到出库单明细信息");
}
if (outboundOrderDetails.FirstOrDefault(x => x.OrderDetailStatus > OrderDetailStatusEnum.New.ObjToInt() && x.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt()) != null)
{
throw new Exception("所选出库单明细存在出库中或已完成");
}
List? stockInfos = null;
List? orderDetails = null;
List? outStockLockInfos = null;
List? locationInfos = null;
//if (outboundOrderDetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt())
{
(List, List, List, List) result = _outboundService.OutboundOrderDetailService.AssignStockOutbound(outboundOrderDetails);
if (result.Item1 != null && result.Item1.Count > 0)
{
Dt_OutboundOrder outboundOrder =_outboundService.OutboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetails.FirstOrDefault().OrderId);
TaskTypeEnum typeEnum = outboundOrder.OrderType switch
{
(int)OutOrderTypeEnum.Issue => TaskTypeEnum.Outbound,
(int)OutOrderTypeEnum.Allocate=> TaskTypeEnum.OutAllocate,
(int)OutOrderTypeEnum.Quality => TaskTypeEnum.OutQuality,
_ =>new TaskTypeEnum()
};
tasks = GetTasks(result.Item1, typeEnum);
tasks.ForEach(x =>
{
x.OrderNo = outboundOrder.UpperOrderNo;
});
result.Item2.ForEach(x =>
{
x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
});
result.Item3.ForEach(x =>
{
x.Status = OutLockStockStatusEnum.出库中.ObjToInt();
});
stockInfos = result.Item1;
orderDetails = result.Item2;
outStockLockInfos = result.Item3;
locationInfos = result.Item4;
}
else
{
throw new Exception("无库存");
}
}
//else
//{
// List stockLockInfos = _outboundService.OutboundStockLockInfoService.GetByOrderDetailId(outboundOrderDetail.OrderId, OutLockStockStatusEnum.已分配);
// if (stockLockInfos != null && stockLockInfos.Count > 0)
// {
// List stocks = _stockService.StockInfoService.Repository.GetStockInfosByPalletCodes(stockLockInfos.Select(x => x.PalletCode).Distinct().ToList());
// tasks = GetTasks(stocks);
// }
//}
return (tasks, stockInfos, orderDetails, outStockLockInfos, locationInfos);
}
///
/// 生成出库任务
///
///
///
///
public WebResponseContent GenerateOutboundTask(int orderDetailId, List stockSelectViews)
{
try
{
(List, List?, List?, List?, List?) result = OutboundTaskDataHandle(orderDetailId, stockSelectViews);
WebResponseContent content = GenerateOutboundTaskDataUpdate(result.Item1, result.Item2, result.Item3, result.Item4, result.Item5);
return content;
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error(ex.Message);
}
}
///
/// 平库直接出库
///
///
///
///
public WebResponseContent GeneratePKOutboundTask(int orderDetailId, List stockSelectViews)
{
try
{
#region MyRegion
Dt_OutboundOrderDetail OrderDetail = _outboundService.OutboundOrderDetailService.Repository.QueryFirst(x => x.Id == orderDetailId);
if (OrderDetail == null)
{
throw new Exception("未找到出库单明细信息");
}
if (OrderDetail.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
throw new Exception("出库单已完成");
Dt_OutboundOrder outboundOrder = BaseDal.Db.Queryable().Where(x => x.Id == OrderDetail.OrderId).Includes(x => x.Details).First();
if (outboundOrder == null)
{
return WebResponseContent.Instance.Error($"未找到出库单信息");
}
Dt_Warehouse warehouse = _basicService.WarehouseService.Repository.QueryFirst(x => x.WarehouseId == outboundOrder.WarehouseId);
List outStocks = _stockService.StockInfoService.Repository.GetStockInfosByPalletCodes(stockSelectViews.Select(x => x.PalletCode).ToList());
if (outStocks.Count < 1) return WebResponseContent.Instance.Error($"库存不足");
List outStockLockInfos = new List();
List upStocks = new List();
List deStocks = new List();
List upstockDetails = new List();
List destockDetails = new List();
outStocks.ForEach(x =>
{
x.Details.Where(x => x.MaterielCode == OrderDetail.MaterielCode).ToList().ForEach(v =>
{
float OriginalQuantity = v.StockQuantity;
float assignQuantity = 0;//分配数量
float assignAmount = OrderDetail.OrderQuantity - OrderDetail.OverOutQuantity;//待出数量
if (assignAmount > 0)
{
if (v.StockQuantity >= assignAmount)
{
assignQuantity = assignAmount;
v.StockQuantity -= assignAmount;
OrderDetail.OverOutQuantity += assignAmount;
OrderDetail.LockQuantity += assignAmount;
upstockDetails.Add(v);
}
else
{
assignQuantity = v.StockQuantity;
OrderDetail.OverOutQuantity += v.StockQuantity;
OrderDetail.LockQuantity += v.StockQuantity;
v.StockQuantity = 0;
destockDetails.Add(v);
}
Dt_OutStockLockInfo outStockLockInfo = new Dt_OutStockLockInfo()
{
PalletCode = x.PalletCode,
AssignQuantity = assignQuantity,
MaterielCode = OrderDetail.MaterielCode,
BatchNo = v.BatchNo,
LocationCode = x.LocationCode,
MaterielName = v.MaterielName,
OrderDetailId = OrderDetail.Id,
OrderNo = outboundOrder.OrderNo,
OrderType = outboundOrder.OrderType,
OriginalQuantity = OriginalQuantity,
Status = OutLockStockStatusEnum.出库完成.ObjToInt(),
StockId = x.Id,
TaskNum = 0,
OrderQuantity = OrderDetail.OrderQuantity,
Unit = OrderDetail.Unit,
ProductionDate = v.ProductionDate,
EffectiveDate = v.EffectiveDate
};
outStockLockInfos.Add(outStockLockInfo);
}
});
int overCount = x.Details.Where(x => x.StockQuantity == 0).Count();
if (overCount == x.Details.Count) deStocks.Add(x);
else upStocks.Add(x);
});
outboundOrder.OrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
OrderDetail.OrderDetailStatus = OrderDetail.OrderQuantity > OrderDetail.OverOutQuantity ? OrderDetailStatusEnum.AssignOverPartial.ObjToInt() : OrderDetailStatusEnum.Over.ObjToInt();
if (OrderDetail.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
{
int overCount = outboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count();
if (outboundOrder.Details.Count - 1 == overCount)
outboundOrder.OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt();
}
_unitOfWorkManage.BeginTran();
_outboundService.OutboundStockLockInfoService.AddData(outStockLockInfos);
_outboundService.OutboundOrderService.UpdateData(outboundOrder);
_outboundService.OutboundOrderDetailService.UpdateData(OrderDetail);
_stockRepository.StockInfoRepository.UpdateData(upStocks);
_stockRepository.StockInfoRepository.DeleteData(deStocks);
_stockRepository.StockInfoDetailRepository.UpdateData(upstockDetails);
_stockRepository.StockInfoDetailRepository.DeleteData(destockDetails);
_unitOfWorkManage.CommitTran();
#endregion
#region 上报ERP
if (outboundOrder.OrderStatus == OutOrderStatusEnum.出库完成.ObjToInt() && outboundOrder.OrderType==OutOrderTypeEnum.Issue.ObjToInt())
{
//List eRPPickModels = new List();
//outStockLockInfos.ForEach(x =>
//{
// ERPPickItemModel pickItemModel = new ERPPickItemModel()
// {
// Lotno = x.BatchNo,
// Qty = x.AssignQuantity.ToString(),
// Location = warehouse.WarehouseCode
// };
// ERPPickModel pickModel = new ERPPickModel()
// {
// Rowindex = OrderDetail.RowNo,
// Material = OrderDetail.MaterielCode,
// Qty = pickItemModel.Qty,
// Dataitem = new List { pickItemModel }
// };
// eRPPickModels.Add(pickModel);
//});
//ERPIssueItemModel issueItemModel = new ERPIssueItemModel()
//{
// Pickcode = outboundOrder.UpperOrderNo,
// PickList = eRPPickModels
//};
//ERPIssueModel issueModel = new ERPIssueModel()
//{
// UniqueTag = outboundOrder.Id.ToString(),
// Code = _outboundService.OutboundOrderService.CreateCodeByRule(nameof(RuleCodeEnum.FLCodeRule)),
// WarehouseCode = warehouse.WarehouseCode,
// Docremark = "",
// Deptno = outboundOrder.DepartmentCode,
// Deptname = outboundOrder.DepartmentName,
// Createtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
// Createuser = App.User.UserName,
// Issitem = new List() { issueItemModel }
//};
_invokeERPService.InvokeOutStandardsApi(_outboundService.OutboundOrderService.GetERPIssueModel(outboundOrder, warehouse.WarehouseCode));
}
#endregion
return WebResponseContent.Instance.OK();
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error(ex.Message);
}
}
///
/// 生成出库任务后数据更新到数据库
///
///
///
///
///
///
///
public WebResponseContent GenerateOutboundTaskDataUpdate(List tasks, List? stockInfos = null, List? outboundOrderDetails = null, List? outStockLockInfos = null, List? locationInfos = null)
{
try
{
_unitOfWorkManage.BeginTran();
BaseDal.AddData(tasks);
if (stockInfos != null && stockInfos.Count > 0 && outboundOrderDetails != null && outboundOrderDetails.Count > 0 && outStockLockInfos != null && outStockLockInfos.Count > 0 && locationInfos != null && locationInfos.Count > 0)
{
stockInfos.ForEach(x =>
{
x.StockStatus = StockStatusEmun.出库锁定.ObjToInt();
});
outboundOrderDetails.ForEach(x =>
{
x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
});
Dt_OutboundOrder outboundOrder = _outboundRepository.OutboundOrderRepository.QueryFirst(x => x.Id == outboundOrderDetails.FirstOrDefault().OrderId);
if (outboundOrder.OrderStatus != OutOrderStatusEnum.出库中.ObjToInt())
{
_outboundRepository.OutboundOrderRepository.UpdateData(outboundOrder);
}
WebResponseContent content = _outboundService.OutboundOrderDetailService.LockOutboundStockDataUpdate(stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos, tasks: tasks);
if (!content.Status)
{
_unitOfWorkManage.RollbackTran();
return content;
}
}
else if (outboundOrderDetails != null && outboundOrderDetails.Count > 0)
{
outboundOrderDetails.ForEach(x =>
{
x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
});
Dt_OutboundOrder outboundOrder = _outboundRepository.OutboundOrderRepository.QueryFirst(x=>x.Id== outboundOrderDetails.FirstOrDefault().OrderId);
if (outboundOrder.OrderStatus!=OutOrderStatusEnum.出库中.ObjToInt())
{
_outboundRepository.OutboundOrderRepository.UpdateData(outboundOrder);
}
_outboundService.OutboundOrderDetailService.Repository.UpdateData(outboundOrderDetails);
}
_unitOfWorkManage.CommitTran();
PushTasksToWCS(tasks);
return WebResponseContent.Instance.OK();
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
return WebResponseContent.Instance.Error(ex.Message);
}
}
///
/// 生成出库任务
///
/// 出库单明细主键
///
public WebResponseContent GenerateOutboundTasks(int[] keys)
{
try
{
List tasks = new List();
List stockSelectViews = new List();
List stockInfos = new List();
List outboundOrderDetails = new List();
List outStockLockInfos = new List();
List locationInfos = new List();
(List, List?, List?, List?, List?) result = OutboundTaskDataHandle(keys);
if (result.Item2 != null && result.Item2.Count > 0)
{
stockInfos.AddRange(result.Item2);
}
if (result.Item3 != null && result.Item3.Count > 0)
{
outboundOrderDetails.AddRange(result.Item3);
}
if (result.Item4 != null && result.Item4.Count > 0)
{
outStockLockInfos.AddRange(result.Item4);
}
if (result.Item5 != null && result.Item5.Count > 0)
{
locationInfos.AddRange(result.Item5);
}
if (result.Item1 != null && result.Item1.Count > 0)
{
tasks.AddRange(result.Item1);
}
WebResponseContent content = GenerateOutboundTaskDataUpdate(tasks, stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos);
return content;
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
return WebResponseContent.Instance.Error(ex.Message);
}
}
///
/// 生成出库任务
///
/// 出库单主键
///
public WebResponseContent GenerateOutboundTaskByHeadId(int outboundId)
{
try
{
List keys = _outboundService.OutboundOrderDetailService.Repository.QueryData(x => x.Id, x => x.OrderId == outboundId);
return GenerateOutboundTasks(keys.ToArray());
}
catch (Exception ex)
{
_unitOfWorkManage.RollbackTran();
return WebResponseContent.Instance.Error(ex.Message);
}
}
#region
/////
///// 生成出库任务
/////
///// 出库单明细主键
/////
//public WebResponseContent MESPPGenerateOutboundTasks(int[] keys)
//{
// try
// {
// List tasks = new List();
// List stockSelectViews = new List();
// List stockInfos = new List();
// List outboundOrderDetails = new List();
// List outStockLockInfos = new List();
// List locationInfos = new List();
// (List, List?, List?, List?, List?) result = MESPPOutboundTaskDataHandle(keys);
// if (result.Item2 != null && result.Item2.Count > 0)
// {
// stockInfos.AddRange(result.Item2);
// }
// if (result.Item3 != null && result.Item3.Count > 0)
// {
// outboundOrderDetails.AddRange(result.Item3);
// }
// if (result.Item4 != null && result.Item4.Count > 0)
// {
// outStockLockInfos.AddRange(result.Item4);
// }
// if (result.Item5 != null && result.Item5.Count > 0)
// {
// locationInfos.AddRange(result.Item5);
// }
// if (result.Item1 != null && result.Item1.Count > 0)
// {
// tasks.AddRange(result.Item1);
// }
// WebResponseContent content = MESPPGenerateOutboundTaskDataUpdate(tasks, stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos);
// return content;
// }
// catch (Exception ex)
// {
// _unitOfWorkManage.RollbackTran();
// return WebResponseContent.Instance.Error(ex.Message);
// }
//}
/////
///// 出库任务数据处理
/////
/////
/////
/////
/////
//public (List, List?, List?, List?, List?) MESPPOutboundTaskDataHandle(int[] keys)
//{
// List tasks = new List();
// List outboundOrderDetailss = _outboundService.MesPPOutboundOrderDetailService.Repository.QueryData(x => keys.Contains(x.Id));
// List outboundOrderDetails = BaseDal.Db.Queryable().Where(x => keys.Contains(x.Id)).ToList();
// if (outboundOrderDetails == null || outboundOrderDetails.Count == 0)
// {
// throw new Exception("未找到出库单明细信息");
// }
// if (outboundOrderDetails.FirstOrDefault(x => x.OrderDetailStatus > OrderDetailStatusEnum.New.ObjToInt() && x.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt()) != null)
// {
// throw new Exception("所选出库单明细存在出库中或已完成");
// }
// List? stockInfos = null;
// List? orderDetails = null;
// List? outStockLockInfos = null;
// List? locationInfos = null;
// //if (outboundOrderDetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt())
// {
// (List, List, List, List) result = _outboundService.MesPPOutboundOrderDetailService.AssignStockOutbound(outboundOrderDetails);
// if (result.Item1 != null && result.Item1.Count > 0)
// {
// Dt_MesPPOutboundOrder outboundOrder = _outboundService.MesPPOutboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetails.FirstOrDefault().OrderId);
// TaskTypeEnum typeEnum = outboundOrder.OrderType switch
// {
// (int)OutOrderTypeEnum.Issue => TaskTypeEnum.Outbound,
// (int)OutOrderTypeEnum.Allocate => TaskTypeEnum.OutAllocate,
// (int)OutOrderTypeEnum.Quality => TaskTypeEnum.OutQuality,
// _ => new TaskTypeEnum()
// };
// tasks = GetTasks(result.Item1, typeEnum);
// result.Item2.ForEach(x =>
// {
// x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
// });
// result.Item3.ForEach(x =>
// {
// x.Status = OutLockStockStatusEnum.出库中.ObjToInt();
// });
// stockInfos = result.Item1;
// orderDetails = result.Item2;
// outStockLockInfos = result.Item3;
// locationInfos = result.Item4;
// }
// else
// {
// throw new Exception("无库存");
// }
// }
// //else
// //{
// // List stockLockInfos = _outboundService.OutboundStockLockInfoService.GetByOrderDetailId(outboundOrderDetail.OrderId, OutLockStockStatusEnum.已分配);
// // if (stockLockInfos != null && stockLockInfos.Count > 0)
// // {
// // List stocks = _stockService.StockInfoService.Repository.GetStockInfosByPalletCodes(stockLockInfos.Select(x => x.PalletCode).Distinct().ToList());
// // tasks = GetTasks(stocks);
// // }
// //}
// return (tasks, stockInfos, orderDetails, outStockLockInfos, locationInfos);
//}
/////
///// 生成出库任务后数据更新到数据库
/////
/////
/////
/////
/////
/////
/////
//public WebResponseContent MESPPGenerateOutboundTaskDataUpdate(List tasks, List? stockInfos = null, List? outboundOrderDetails = null, List? outStockLockInfos = null, List? locationInfos = null)
//{
// try
// {
// _unitOfWorkManage.BeginTran();
// BaseDal.AddData(tasks);
// if (stockInfos != null && stockInfos.Count > 0 && outboundOrderDetails != null && outboundOrderDetails.Count > 0 && outStockLockInfos != null && outStockLockInfos.Count > 0 && locationInfos != null && locationInfos.Count > 0)
// {
// stockInfos.ForEach(x =>
// {
// x.StockStatus = StockStatusEmun.出库锁定.ObjToInt();
// });
// WebResponseContent content = _outboundService.MesPPOutboundOrderDetailService.LockOutboundStockDataUpdate(stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos, tasks: tasks);
// if (!content.Status)
// {
// _unitOfWorkManage.RollbackTran();
// return content;
// }
// }
// else if (outboundOrderDetails != null && outboundOrderDetails.Count > 0)
// {
// outboundOrderDetails.ForEach(x =>
// {
// x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
// });
// _outboundService.MesPPOutboundOrderDetailService.Repository.UpdateData(outboundOrderDetails);
// }
// _unitOfWorkManage.CommitTran();
// PushTasksToWCS(tasks);
// return WebResponseContent.Instance.OK();
// }
// catch (Exception ex)
// {
// _unitOfWorkManage.RollbackTran();
// return WebResponseContent.Instance.Error(ex.Message);
// }
//}
#endregion
}
}