using System;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Aop.Api.Domain;
using Aspose.Cells;
using JNPF;
using JNPF.Common.Contracts;
using JNPF.Common.Core.Manager;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Manager;
using JNPF.Common.Security;
using JNPF.FriendlyException;
using JNPF.Systems.Interfaces.System;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NetTaste;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.OpenXmlFormats.Dml;
using NPOI.SS.Formula.Functions;
using Org.BouncyCastle.Crypto;
using SqlSugar;
using Tnb.BasicData.Entities;
using Tnb.Common.Extension;
using Tnb.Common.Redis;
using Tnb.Common.Utils;
using Tnb.ProductionMgr.Entities;
using Tnb.QcMgr.Entities;
using Tnb.WarehouseMgr.Entities;
using Tnb.WarehouseMgr.Entities.Configs;
using Tnb.WarehouseMgr.Entities.Consts;
using Tnb.WarehouseMgr.Entities.Dto;
using Tnb.WarehouseMgr.Entities.Dto.Inputs;
using Tnb.WarehouseMgr.Entities.Dto.Outputs;
using Tnb.WarehouseMgr.Entities.Dto.Queries;
using Tnb.WarehouseMgr.Entities.Entity;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
namespace Tnb.WarehouseMgr
{
///
/// 库房业务类(出入库)
///
public class WareHouseService : DevServBase, IWareHouseService
{
private readonly ISqlSugarClient _db;
private readonly IDictionaryDataService _dictionaryDataService;
private readonly IBillRullService _billRullService;
private readonly IUserManager _userManager;
private readonly ICacheManager _cacheManager;
private readonly IElevatorControlService _elevatorControlService;
private readonly IWmsCarryBindService _wmsCarryBindService;
private static readonly Dictionary _elevatorAgvCtlStatusMap = new(StringComparer.OrdinalIgnoreCase);
private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build();
private static Dictionary locMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
private readonly IConfiguration _configuration;
private readonly RedisData _redisData;
public static SemaphoreSlim s_floor2CreatePretask = new(1);
public Func AddUnExecuteTask { get; set; }
public WareHouseService(ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, RedisData redisData,
IBillRullService billRullService, IUserManager userManager, ICacheManager cacheManager, IElevatorControlService elevatorControlService,
IWmsCarryBindService wmsCarryBindService
//IConfiguration configuration
) : base(repository.AsSugarClient())
{
_db = repository.AsSugarClient();
_dictionaryDataService = dictionaryDataService;
_billRullService = billRullService;
_userManager = userManager;
_cacheManager = cacheManager;
_elevatorControlService = elevatorControlService;
_redisData = redisData;
_wmsCarryBindService = wmsCarryBindService;
//_configuration = configuration;
}
///
/// 根据载具Id带出库位、仓库信息
///
/// 载具id
///
/// returns:
///
{
///
carry_id:载具Id
///
carry_name:载具名称
///
location_id:库位Id
///
location_name:库位名称
///
warehouse_id:库房Id
///
warehouse_name:库房名称
///
}
///
[HttpGet]
public async Task GetLocationAndWorkHouseByCarryId([FromRoute] string carryId)
{
var items = await _db.Queryable().LeftJoin((a, b) => a.location_id == b.id)
.LeftJoin((a, b, c) => b.wh_id == c.id)
.Where(a => a.id == carryId)
.Select((a, b, c) => new
{
carry_id = a.id,
a.carry_name,
location_id = b.id,
b.location_name,
warehouse_id = c.id,
warehouse_name = c.whname,
})
.ToListAsync();
return items ?? Enumerable.Empty();
}
///
/// 库房业务,入库、出库申请新增修改功能
///
///
///
[HttpPost]
public async Task ApplyFor(InOutStockApplyforUpInput input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
async Task _updateLocalFunc(InOutStockApplyforUpInput input)
where TStockD : BaseEntity, new()
where TStockCode : BaseEntity, IInOutStockCode, new()
{
TStockD instockD = input.Adapt();
global::System.Collections.Generic.List? stockCodes = input.InstockCodes?.Adapt>();
if (stockCodes?.Count > 0)
{
stockCodes.ForEach(x =>
{
if (x.id.IsNullOrWhiteSpace())
{
x.id = SnowflakeIdHelper.NextId();
}
x.bill_d_id = instockD.id;
});
}
return await Update(instockD, stockCodes!);
}
bool isOk = input.inoutStockType switch
{
EnumInOutStockType.In => await _updateLocalFunc(input),
EnumInOutStockType.Out => await _updateLocalFunc(input),
_ => throw new ArgumentOutOfRangeException(nameof(input.inoutStockType), $"Not expected EnumInOutStockType value: {input.inoutStockType}"),
};
if (!isOk)
{
throw Oops.Oh(ErrorCode.COM1001);
}
}
///
/// 根据明细Id获取出入库明细信息
///
///
[HttpGet]
public async Task GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input)
{
dynamic? result = input.inoutStockType switch
{
EnumInOutStockType.In => await FetchInOutStockCodesById(input.bill_d_id),
EnumInOutStockType.Out => await FetchInOutStockCodesById(input.bill_d_id),
_ => throw new NotImplementedException(),
};
return result ?? Enumerable.Empty();
}
///
/// 入库策略
///
///
[HttpGet]
public async Task> InStockStrategy([FromQuery] InStockStrategyQuery input)
{
List items = new();
try
{
WmsInstockPolicies policy = await _db.CopyNew().Queryable().Where(it => it.status == 1).FirstAsync();
if (policy == null)
{
throw new AppFriendlyException("没有可用的策略", 500);
}
Expression> whereExp = Expressionable.Create()
.And(it => it.wh_id == input.warehouse_id)
.And(it => it.is_lock == 0)
.And(it => it.is_type == ((int)EnumLocationType.存储库位).ToString())
.And(it => it.is_use == ((int)EnumCarryStatus.空闲).ToString())
.ToExpression();
items = await _db.CopyNew().Queryable().Where(whereExp).OrderBy(policy.policy).ToListAsync();
}
catch (Exception)
{
throw;
}
return items.Take(input.Size).ToList();
}
///
/// 是否为一楼出库工位
///
///
///
public string[] GetFloor1OutstockLocation()
{
return new string[3] { WmsWareHouseConst.FinishproductOutstockStation1 , WmsWareHouseConst.FinishproductOutstockStation2
, WmsWareHouseConst.FinishproductOutstockStation3 };
}
///
/// 出库策略-销售出库下发
///
///
[HttpGet]
public async Task>> OutStockStrategy_saleRelease([FromQuery] OutStockStrategyQuery input)
{
Expressionable whereExprable = Expressionable.Create()
.And((a, b, c) => a.is_lock == 0 && c.is_lock == 0)
.And((a, b, c) => !string.IsNullOrEmpty(a.location_id))
.And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString())
.And((a, b, c) => a.out_status == "0")
.And((a, b, c) => c.wh_id == input.warehouse_id)
.AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id)
.AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch)
.AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification)
.AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no)
.AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id);
Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace()
? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString()
: (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString();
_ = whereExprable.And(carryStatusFilterExp);
Expression> whereExpr = whereExprable.ToExpression();
SqlSugarClient cyDb = _db.CopyNew();
List> items = cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id)
.LeftJoin((a, b, c) => a.location_id == c.id)
.Where(whereExpr)
//.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty())
.OrderBy("a.location_code,layers,loc_line,loc_column")
.Select((a, b, c) => new
{
WmsCarryH = a,
WmsCarryCode = b,
BasLocation = c,
codeqty = b.codeqty
}).ToList().Select(r =>
{
input.qty = input.qty - r.codeqty;
// 出库数量与托盘上的数量不一致需要进行分拣
if (input.qty < 0)
{
r.WmsCarryCode.codeqty = input.qty + r.codeqty;
return new Tuple("分拣任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation);
}
else
{
// 正常预任务出库
return new Tuple("预任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation);
}
}).ToList();
return items;
}
public async Task> OutStockStrategy([FromQuery] OutStockStrategyQuery input)
{
Expressionable whereExprable = Expressionable.Create()
.And((a, b, c) => a.is_lock == 0)
.And((a, b, c) => !string.IsNullOrEmpty(a.location_id))
.And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString())
.And((a, b, c) => a.out_status == "0")
.And((a, b, c) => c.wh_id == input.warehouse_id)
.AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id)
.AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch)
.AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification)
.AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no)
.AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id);
Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace()
? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString()
: (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString();
_ = whereExprable.And(carryStatusFilterExp);
Expression> whereExpr = whereExprable.ToExpression();
SqlSugarClient cyDb = _db.CopyNew();
WmsInstockPolicies policy = await cyDb.Queryable().Where(it => it.status == 1).FirstAsync();
if (policy == null)
{
throw new AppFriendlyException("没有可用策略", 500);
}
List items = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id)
.LeftJoin((a, b, c) => a.location_id == c.id)
.Where(whereExpr)
//.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty())
.OrderBy(policy.policy)
.Select()
.ToListAsync();
return input.Size > 0 ? items.Take(input.Size).ToList() : items;
}
///
/// 判断CTU是否可以放货
///
///
[HttpPost]
[AllowAnonymous]
public async Task CheckPut(CheckPutInput input)
{
Logger.Information("联核请求CheckPut接口传入参数为:" + JsonConvert.SerializeObject(input));
Dictionary putdic = new Dictionary();
putdic.Add("SSX-011-006", new string[] { "YTCS", "AllowEmptyIn_CS06" });
putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7允许入箱" });
putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9允许入箱" });
putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10允许入箱" });
putdic.Add("SSX-021-003", new string[] { "YTCS", "AllowCtuEmptyIn_CS03" });
putdic.Add("SSX-021-001", new string[] { "YTCS", "AllowCtuEmptyIn_CS01" });
putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowCtuFullOut_CS04", });
putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowCtuFullOut_CS02", });
var strs = new string[] { };
if (!putdic.ContainsKey(input.targetName))
throw new AppFriendlyException("点位" + input.targetName + "不存在", 500);
strs = putdic.Where(p => p.Key == input.targetName).First().Value;
bool flag = await _redisData.HashExist(strs[0], strs[1]);
if (!flag)
{
throw new AppFriendlyException("点位" + input.targetName + "不存在", 500);
}
string data = await _redisData.GetHash(strs[0], strs[1]);
Logger.Information("联核请求CheckPut接口查询X2Server数据:" + data);
JObject? res = JsonConvert.DeserializeObject(data);
bool result = res != null && res["Value"] != null ? res.Value("Value") : false;
if (!result)
throw new AppFriendlyException("点位" + input.targetName + "不可放", 500);
Logger.Information("联核请求CheckPut接口结果:CTU可放货" + data);
}
///
/// 判断CTU是否可以取货
///
///
public async Task Check(string code, string action)
{
Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action}");
Dictionary putdic = new Dictionary();
Dictionary getdic = new Dictionary();
putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowCtuFullOut_CS04", });
putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowCtuFullOut_CS02", });
getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowAgvEmptyOut_CS01" });
getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowAgvEmptyOut_CS03" });
putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2允许入空箱", });
getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2允许取满箱" });
putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3允许入空箱", });
getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3允许取满箱" });
putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4允许入空箱", });
getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4允许取满箱" });
putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5允许入空箱", });
getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5允许取满箱" });
putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6允许入空箱", });
getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6允许取满箱" });
putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7允许入空箱", });
getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7允许取满箱" });
var strs = new string[] { };
if (action == "LOAD")//取货
{
if (!getdic.ContainsKey(code))
{
return false;
}
strs = getdic.Where(p => p.Key == code).First().Value;
bool flag = _redisData.HashExist(strs[0], strs[1]).Result;
if (!flag)
{
Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action} flag:{flag} ");
return false;
}
string data = _redisData.GetHash(strs[0], strs[1]).Result;
JObject? res = JsonConvert.DeserializeObject(data);
bool result = res != null && res["Value"] != null ? res.Value("Value") : false;
if (!result)
return false;
return true;
}
else if (action == "UNLOAD")//放货
{
if (!putdic.ContainsKey(code))
return false;
strs = putdic.Where(p => p.Key == code).First().Value;
bool flag = _redisData.HashExist(strs[0], strs[1]).Result;
if (!flag)
{
Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action} flag:{flag} ");
return false;
}
string data = _redisData.GetHash(strs[0], strs[1]).Result;
JObject? res = JsonConvert.DeserializeObject(data);
bool result = res != null && res["Value"] != null ? res.Value("Value") : false;
if (!result)
return false;
return true;
}
return false;
}
public async Task SsxControl(WmsDistaskH disTask, string action)
{
Logger.Information($"输送线控制SsxControl传入参数: {JsonConvert.SerializeObject(disTask)} {action}");
Dictionary putdic = new Dictionary();
Dictionary getdic = new Dictionary();
getdic.Add("SSX-021-005", new string[] { "YTCS", "FullOut_CS05Done", "true" });
getdic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11出箱完毕", "true" });
getdic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12出箱完毕", "true" });
getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线上层允许出箱3", "true" });
getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线上层允许出箱1", "true" });
getdic.Add("SSX-011-008", new string[] { "东面提升机输送线", "入库输送线8出箱完毕", "true" });
getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2AGV允许入满箱", "true" });
getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3AGV允许入满箱", "true" });
getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4AGV允许入满箱", "true" });
getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5AGV允许入满箱", "true" });
getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6AGV允许入满箱", "true" });
getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7AGV允许入满箱", "true" });
putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7入箱完毕", "true" });
putdic.Add("SSX-011-006", new string[] { "YTCS", "EmptyIn_CS06Done", "true" });
putdic.Add("SSX-021-003", new string[] { "YTCS", "AgvFullIn_CS03Done", "true" });
putdic.Add("SSX-021-001", new string[] { "YTCS", "CtuEmptyIn_CS01Done", "true" });
putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线下层允许入箱4", "true" });
putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线下层允许入箱2", "true" });
putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9入箱完毕", "true" });
putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10入箱完毕", "true" });
putdic.Add("YCLCKBGW", new string[] { "CP8", "PutDoneEmptyBox", "true" });
putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2AGV允许出空箱", "true" });
putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3AGV允许出空箱", "true" });
putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4AGV允许出空箱", "true" });
putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5AGV允许出空箱", "true" });
putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6AGV允许出空箱", "true" });
putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7AGV允许出空箱", "true" });
if (action == "LOAD")//取货
{
if (getdic.Keys.Contains(disTask.startlocation_code))
{
var strarr = getdic.Where(p => p.Key == disTask.startlocation_code).First().Value;
Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase)
{
["DevName"] = strarr[0],
["token"] = _eleCtlCfg.token,
["TagName"] = strarr[1],
["Value"] = strarr[2],
};
Logger.Information($"SsxControlLOAD:{JsonConvert.SerializeObject(dicCommand)}");
var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand);
Logger.Information($"SsxControlLOAD:{str}");
}
}
else if (action == "UNLOAD")//放货
{
if (putdic.Keys.Contains(disTask.endlocation_code))
{
var strarr = putdic.Where(p => p.Key == disTask.endlocation_code).First().Value;
Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase)
{
["DevName"] = strarr[0],
["token"] = _eleCtlCfg.token,
["TagName"] = strarr[1],
["Value"] = strarr[2],
};
Logger.Information($"SsxControlUNLOAD:{dicCommand}");
var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand);
Logger.Information($"SsxControlUNLOAD:{str}");
}
}
}
///
/// // 二楼机械臂
///
///
public async Task Floor2MechanicalComplete(WmsDistaskH disTask, string action)
{
List rackAreaPoints = new List();
// 二楼料架区点位
rackAreaPoints.Add("AS01");
rackAreaPoints.Add("AS02");
rackAreaPoints.Add("AX01");
rackAreaPoints.Add("AX02");
if (disTask.area_code == "E")
{
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】收到到货完成信号 传入参数: {disTask.bill_code} {action}");
SqlSugarClient db = _db.CopyNew();
if (action == "UNLOAD")
{
// 去料架区放货
if (rackAreaPoints.Contains(disTask.endlocation_code))
{
ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.endpoint_code);
if (WmsMechanicalArmHs.Count() == 0)
{
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配");
return false;
}
WmsMechanicalArmH target = WmsMechanicalArmHs.First();
// 回写料架和AGV确认
await db.Updateable().SetColumns(r => new WmsMechanicalArmH
{
agvconfirm = 1,
rackid = disTask.carry_id,
rackcode = disTask.carry_code
}).Where(r => r.id == target.id).ExecuteCommandAsync();
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV已到货");
}
else // 去暂存仓放货
{
// 回写料架料箱绑定表的库位
ISugarQueryable WmsCarryCodes = db.Queryable()
.InnerJoin((a, b) => b.membercarry_id == a.carry_id)
.Where((a, b) => b.carry_id == disTask.carry_id);
var WmsCarryCodeList = WmsCarryCodes.ToList();
WmsCarryCodeList.ForEach(r =>
{
r.location_id = disTask.endlocation_id;
r.location_code = disTask.endlocation_code;
});
await db.Updateable(WmsCarryCodeList).ExecuteCommandAsync();
}
}
else
{
// 去暂存仓取货
if (rackAreaPoints.Contains(disTask.endlocation_code))
{
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在暂存仓取货完成");
}
else // 去料架区取货
{
ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.startpoint_code);
if (WmsMechanicalArmHs.Count() == 0)
{
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行起点{disTask.endpoint_code} 与料架区的点位不匹配");
return false;
}
WmsMechanicalArmH target = WmsMechanicalArmHs.First();
if (target.note == "上升降机")
{
bool result = await Floor2UpDownMachinecode_SetTag($"上升降机满托{target.stackingposition}移走", "true");
Logger.LogInformation($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}");
if (!result)
{
throw new Exception($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}");
}
}
else if (target.note == "下升降机")
{
bool result = await Floor2UpDownMachinecode_SetTag($"下升降机空托{target.stackingposition}移走", "true");
Logger.LogInformation($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}");
if (!result)
{
throw new Exception($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}");
}
}
//回写出库单状态
await db.Updateable().SetColumns(r => new WmsEmptyOutstockH
{
bindrackcomplete = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID
}).Where(r => r.bill_code == target.outbill).ExecuteCommandAsync();
// 重置料架区
await db.Updateable().SetColumns(r => new WmsMechanicalArmH
{
stackingcount = 0,
barcodes = "",
outbill = "",
maxnum = 0,
iscreatepretask = 0,
rackcode = "",
rackid = "",
agvconfirm = 0,
mechanicalconfirm = 0
}).Where(r => r.id == target.id).ExecuteCommandAsync();
Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在料架区取货完成");
}
}
}
return true;
}
private async Task Floor2UpDownMachinecode_SetTag(string tag, string value)
{
string DevName = "东面提升机输送线";
Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase)
{
["DevName"] = DevName,
["token"] = _eleCtlCfg.token,
["TagName"] = tag,
["Value"] = value,
};
string result = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand);
// 测试
//JObject valueJson = new JObject();
//valueJson["Value"] = value;
//bool res = await _redisData.HSet(DevName, tag, valueJson.ToString());
//return true;
return result.Contains("Ok");
}
///
/// 生成任务执行
///
///
[HttpPost]
public async Task GenTaskExecute()
{
CTUTaskExecute();
await s_taskExecuteSemaphore.WaitAsync();
Stopwatch sw = Stopwatch.StartNew();
CancellationTokenSource agvCts = new();
SqlSugarClient db = _db.CopyNew();
try
{
//获取所有未下发的预任务申请
Logger.Information("【GenTaskExecute】 开始获取未下发的预任务...");
ISugarQueryable sugarQueryable = db.Queryable().InnerJoin((a, b) => a.startlocation_id == b.location_id && a.carry_id == b.id)
.InnerJoin((a, b, c) => a.area_id == c.id)
.InnerJoin((a, b, c, d) => a.endlocation_id == d.id && d.is_use == "0")
.Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && !string.IsNullOrWhiteSpace(a.startlocation_id))
.OrderBy(a => new { priority = SqlFunc.Desc(a.priority), a.bill_code })
.Select((a, b, c, d) => new WmsPretaskH
{
move_num = c.move_num,
third_eqp_type = c.third_eqp_type,
}, true);
Logger.Information("【GenTaskExecute】 执行SQL: " + sugarQueryable.ToSqlString());
List preTasks = await sugarQueryable.ToListAsync();
//List executedPreTasks = await db.Queryable().Where(it => it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID).ToListAsync();
List agvElevatorTasks = preTasks
.Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) &&
!it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase))
.ToList();
var elePreTasks = preTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList();
var normalPreTasks = preTasks.Where(it => it.area_code != "B" && !agvElevatorTasks.Concat(elePreTasks).Select(x => x.endlocation_code).Contains(it.endlocation_code)).ToList();
//Logger.Information("【GenTaskExecute】 电梯预任务elePreTasks:" + JsonConvert.SerializeObject(elePreTasks));
//Logger.Information("【GenTaskExecute】 AGV/CTU/KIVA预任务normalPreTasks:" + JsonConvert.SerializeObject(normalPreTasks));
//Logger.Information("【GenTaskExecute】 AGV电梯预任务agvElevatorTasks:" + JsonConvert.SerializeObject(agvElevatorTasks));
/* IEnumerable firstEleGrp = agvElevatorTasks.GroupBy(g => g.endlocation_code).Select(t => t.OrderBy(o => o.bill_code).FirstOrDefault());
agvElevatorTasks = firstEleGrp?.ToList() ?? Enumerable.Empty().ToList()!;
*/
//如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行
var equalEndLocPreTasks = elePreTasks.Select(x => x.endlocation_code).Intersect(agvElevatorTasks.Select(x => x.endlocation_code));
if (equalEndLocPreTasks.Any())
{
Logger.Information("【GenTaskExecute】 执行:如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行 ");
agvElevatorTasks = agvElevatorTasks.Where(x => !equalEndLocPreTasks.Contains(x.endlocation_code)).ToList();
}
preTasks = normalPreTasks.Concat(agvElevatorTasks).Concat(elePreTasks).ToList();
//一楼中储仓CTU
List ids = preTasks.Select(x => x.id).Distinct().ToList();
List? preTaskCodes = await db.Queryable().Where(it => ids.Contains(it.bill_id)).ToListAsync();
if (preTasks.Count > 0)
{
//根据预任务管理区分组,获取到所有分组后的预任务,遍历每个预任务 是否为任务链,通过管理区ID
List> preTaskGroups = preTasks.GroupBy(g => g.area_code).ToList();
List disTasks = new();
List distaskCodes = new();
foreach (IGrouping? itGroup in preTaskGroups)
{
List items = itGroup.Adapt>();
for (int i = 0, cnt = items.Count; i < cnt; i++)
{
items[i].id = SnowflakeIdHelper.NextId();
items[i].status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID;
}
int moveNum = itGroup.First().move_num;
int itemsCount = items.Count;
int mod = itemsCount % moveNum > 0 ? (itemsCount / moveNum) + 1 : itemsCount / moveNum;
WmsDistaskH[] arrary = items.ToArray();
//for (int i = 1; i <= mod; i++)
{
if (moveNum >= 1)
{
List areaPreTasks = itGroup.ToList();
if (areaPreTasks.Any(x => x.third_eqp_type.ToEnum() != EnumTaskChainType.CTU))
{
Logger.Information("非CTU任务链生成");
for (int i = 0; i < items.Count; i++)
{
var num = (i + 1);
var x = items[i];
string groupCode = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result;
x.is_chain = 0;
x.groups = groupCode;
x.bill_code = $"{groupCode}-1";
}
}
else if ((moveNum >= areaPreTasks.Count && areaPreTasks.Count > 1) || moveNum <= areaPreTasks.Count)
{
Logger.Information("CTU任务链生成");
string groupCode = await _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE);
items.ForEach(x => x.is_chain = 1);
int start = 0;
int end = Math.Min(itemsCount, moveNum);
List arrList = new(mod);
while (start < itemsCount)
{
WmsDistaskH[] subArray = arrary[start..end];
arrList.Add(subArray);
start = end;
end = Math.Min(end + moveNum, arrary.Length);
}
foreach (WmsDistaskH[] arr in arrList)
{
for (int j = 1, len = arr.Length; j <= len; j++)
{
arr[j - 1].groups = groupCode;
arr[j - 1].bill_code = $"{groupCode}-{j}";
}
}
}
}
}
if (preTaskCodes?.Count > 0)
{
foreach (WmsDistaskH disTask in items)
{
List curPreTaskCodes = preTaskCodes.FindAll(x => x.bill_id == disTask.pretask_id);
List curDisTaskCodes = curPreTaskCodes.Adapt>();
curDisTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = disTask.id;
x.create_time = DateTime.Now;
});
distaskCodes.AddRange(curDisTaskCodes);
}
}
disTasks.AddRange(items);
}
await db.Ado.BeginTranAsync();
int row = await db.Insertable(disTasks).ExecuteCommandAsync();
Logger.Information("【GenTaskExecute】 插入任务执行表数据: " + JsonConvert.SerializeObject(disTasks));
if (preTaskCodes?.Count > 0)
{
row = await db.Insertable(distaskCodes).ExecuteCommandAsync();
Logger.Information("【GenTaskExecute】 插入任务执行条码表数据: " + JsonConvert.SerializeObject(disTasks));
}
if (row > 0)
{
List preTaskIds = preTasks.Select(x => x.id).ToList();
List preTaskBill_codes = preTasks.Select(x => x.bill_code).ToList();
row = await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync();
Logger.Information("【GenTaskExecute】 更改这些预任务执行状态为 已下发: " + JsonConvert.SerializeObject(preTaskBill_codes));
}
await db.Ado.CommitTranAsync();
Logger.Information("【GenTaskExecute】 预任务执行完成");
Logger.Information($"【GenTaskExecute】_eleCtlCfg.Environment={_eleCtlCfg.Environment}");
if (string.Equals(_eleCtlCfg.Environment, ElevatorConsts.EnvironmentName, StringComparison.OrdinalIgnoreCase))
{
//呼梯操作
//获取目标库位为电梯库位的任务
Logger.Information("【GenTaskExecute】操作设备");
var agvDTTasks = disTasks.Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) &&
!it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList();
foreach (var task in agvDTTasks)
{
ElevagorInfoQuery q = new() { endlocation_id = task.endlocation_id };
Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}");
var e = await FindElevatorFromPars(q);
Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}");
if (e != null)
{
task.device_id = e.device_id;
}
}
List<(string endlocation_code, string device_id, string id, int start_floor)> endLocCodes = agvDTTasks
.Select(it => (it.endlocation_code, it.device_id, it.id, it.start_floor)).ToList();
var callLiftCnt = endLocCodes?.Count ?? 0;
Logger.Information($"【GenTaskExecute】呼梯任务数:{callLiftCnt}");
if (endLocCodes?.Count > 0)
{
if (endLocCodes.Select(x => x.device_id).All(x => !x.IsNullOrWhiteSpace()))
{
Logger.Information("【GenTaskExecute】呼梯操作");
_ = CallingLanding(endLocCodes);
}
else
{
Logger.Error("【GenTaskExecute】呼梯失败,没有设备ID");
return;
}
}
//执行电梯任务
List? elevatorTasks = disTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList();
Logger.Information($"【GenTaskExecute】当前电梯任务数:{elevatorTasks?.Count ?? 0}");
if (elevatorTasks?.Count > 0)
{
foreach (WmsDistaskH? elevatorTask in elevatorTasks)
{
ElevagorInfoQuery q = new() { endlocation_id = elevatorTask.endlocation_id };
Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}");
var e = await FindElevatorFromPars(q);
Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}");
if (e != null)
{
elevatorTask.device_id = e.device_id;
}
_ = ExecuteTargetFloorTask(elevatorTask);
}
}
List agvTasks = disTasks.Where(it => !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList();
if (agvTasks?.Count > 0)
{
Logger.Information($"【GenTaskExecute】Agv任务数量:{agvTasks.Count},taskCodes:{string.Join(",", agvTasks.Select(x => x.bill_code).Distinct())}");
_ = AgvDispatch(agvTasks, agvCts.Token);
}
}
}
}
catch (Exception ex) when (ex is HttpRequestException hReqEx)
{
agvCts.Cancel();
}
catch (Exception ex)
{
Logger.Error("生成预任务执行时出现错误", ex);
Logger.Error(ex.StackTrace!);
await db.Ado.RollbackTranAsync();
throw;
}
finally
{
_ = s_taskExecuteSemaphore.Release();
agvCts.Dispose();
}
}
///
/// 获取电梯根据任务单号
///
///
/// taskCode:子任务编号
/// endlocation_id:目标库位ID
///
///
protected async Task FindElevatorFromPars(ElevagorInfoQuery input)
{
var whereExpable = Expressionable.Create()
.And((a, b, c) => a.enabled == 1);
Logger.Information($"【FindElevatorFromPars】 {JsonConvert.SerializeObject(input)}");
if (!input.taskCode.IsNullOrEmpty())
{
whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.taskCode), (a, b, c) => c.bill_code == input.taskCode);
}
if (!input.endlocation_id.IsNullOrEmpty())
{
whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.endlocation_id), (a, b, c) => b.location_id == input.endlocation_id);
}
if (!input.startlocation_id.IsNullOrEmpty())
{
whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.startlocation_id), (a, b, c) => b.location_id == input.startlocation_id);
}
ISugarQueryable queryable = _db.CopyNew().Queryable().InnerJoin((a, b) => a.id == b.bill_id)
.InnerJoin((a, b, c) => b.location_code == c.endlocation_code || b.location_code == c.startlocation_code)
.Where(whereExpable.ToExpression())
.WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-R", input.sourceName), (a, b, c) => c.startpoint_code == input.sourceName)
.WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-C", input.sourceName), (a, b, c) => c.endpoint_code == input.sourceName)
.Select((a, b, c) => new WmsElevatorH
{
bill_code = c.bill_code,
device_id = a.elevator_id,
end_floor = c.end_floor
}, true);
var ele = await queryable.FirstAsync();
Logger.Information($"【FindElevatorFromPars】 " + queryable.ToSqlString());
return ele;
}
#region CTU
///
/// 生成CTU任务执行
///
///
[HttpPost]
public async Task CTUTaskExecute()
{
try
{
Dictionary indic = new Dictionary();
indic.Add("SSX-021-005", new string[] { "YTCS", "CallCtuFullIn_CS05" });
indic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11呼叫CTU" });
indic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12呼叫CTU" });
var db = _db.CopyNew();
List CTUTasks = await db.Queryable()
.InnerJoin((a, b) => a.area_id == b.id)
.Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID)
.Where((a, b) => b.code == "B")//一楼中储仓
.OrderBy(a => a.create_id)
.Select((a, b) => new WmsPretaskH
{
move_num = b.move_num,
third_eqp_type = b.third_eqp_type,
}, true).ToListAsync();
List TaskCodes = await db.Queryable().Where(it => CTUTasks.Select(p => p.id).ToList().Contains(it.bill_id)).ToListAsync();
Logger.Information($@"【CTUTaskExecute】 获取任务TaskCodes: {JsonConvert.SerializeObject(TaskCodes)}");
var InTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID).ToList();
var OutTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID).ToList();
//Logger.Information($@"【CTUTaskExecute】 获取任务InTasks: {JsonConvert.SerializeObject(InTasks)}");
//Logger.Information($@"【CTUTaskExecute】 获取任务OutTasks: {JsonConvert.SerializeObject(OutTasks)}");
var OriginDistaskHs = await db.Queryable()
.InnerJoin((a, b) => a.area_id == b.id)
.Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID)
.OrderBy(a => a.bill_code)
.ToListAsync();
//Logger.Information($@"【CTUTaskExecute】 OriginDistaskHs: {JsonConvert.SerializeObject(OriginDistaskHs)}");
List DistaskHs = new List();
List UpDistaskHs = new List();
List DistaskCodes = new List();
var inCtuExec = new List();
var outCtuExec = new List();
foreach (var item in InTasks)
{
/*
if (indic.Keys.Contains(item.startlocation_code))
{
var strs = indic.Where(p => p.Key == item.startlocation_code).First().Value;
bool flag = _redisData.HashExist(strs[0], strs[1]).Result;
if (!flag)
continue;
string data = _redisData.GetHash(strs[0], strs[1]).Result;
JObject? res = JsonConvert.DeserializeObject(data);
bool result = res != null && res["Value"] != null ? res.Value("Value") : false;
if (!result)
continue;
}*/
WmsDistaskH distaskH = item.Adapt();
distaskH.id = SnowflakeIdHelper.NextId();
distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID;
distaskH.is_chain = 1;
distaskH.create_time = DateTime.Now;
var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH);
distaskH.groups = billcode.Substring(0, billcode.Length - 2);
distaskH.bill_code = billcode;
var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1));
Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到inCtuExec");
if (num == item.move_num)
{
distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID;
inCtuExec.Add(distaskH);
if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any())
{
OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID);
UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList());
inCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList());
}
if (DistaskHs.Where(p => p.groups == distaskH.groups).Any())
{
DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID);
inCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList());
}
}
List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id);
List disTaskCodes = preTaskCodes.Adapt>();
disTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = distaskH.id;
x.create_time = DateTime.Now;
});
DistaskHs.Add(distaskH);
DistaskCodes.AddRange(disTaskCodes);
}
foreach (var item in OutTasks)
{
WmsDistaskH distaskH = item.Adapt();
distaskH.id = SnowflakeIdHelper.NextId();
distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID;
distaskH.is_chain = 1;
distaskH.create_time = DateTime.Now;
var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH);
distaskH.groups = billcode.Substring(0, billcode.Length - 2);
distaskH.bill_code = billcode;
var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1));
Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到outCtuExec");
if (num == item.move_num)
{
distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID;
outCtuExec.Add(distaskH);
if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any())
{
OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID);
UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList());
outCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList());
}
if (DistaskHs.Where(p => p.groups == distaskH.groups).Any())
{
DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID);
outCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList());
}
}
List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id);
List disTaskCodes = preTaskCodes.Adapt>();
disTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = distaskH.id;
x.create_time = DateTime.Now;
});
DistaskHs.Add(distaskH);
DistaskCodes.AddRange(disTaskCodes);
}
await db.Ado.BeginTranAsync();
int row = 0;
if (UpDistaskHs.Count > 0)
{
await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => UpDistaskHs.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync();
}
if (DistaskHs.Count > 0)
{
row = await db.Insertable(DistaskHs).ExecuteCommandAsync();
}
if (DistaskCodes.Count > 0)
{
await db.Insertable(DistaskCodes).ExecuteCommandAsync();
}
if (row > 0)
{
List preTaskIds = DistaskHs.Select(x => x.pretask_id).ToList();
await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync();
}
await db.Ado.CommitTranAsync();
//判断
Logger.Information($"【CTUTaskExecute】 判断单据状态(status)是否为26126851525157 {JsonConvert.SerializeObject(DistaskHs)}");
if (DistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID).Any())
{
var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value);
timer = new Timer(TimerExec, null, TimeSpan.FromMinutes(time), TimeSpan.FromMinutes(time));
}
//Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务inCtuExec: {JsonConvert.SerializeObject(inCtuExec)}");
if (inCtuExec.Count > 0)
{
Logger.Information($"开始执行CTU入库任务: {JsonConvert.SerializeObject(inCtuExec)}");
//呼叫ctu入库
// await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => inCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync();
// await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => inCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync();
CancellationTokenSource Ctu = new();
await CallingCTU(inCtuExec, Ctu.Token, 1);
Ctu.Dispose();
}
//Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务outCtuExec: {JsonConvert.SerializeObject(outCtuExec)}");
if (outCtuExec.Count > 0)
{
Logger.Information($"开始执行CTU出库任务: {JsonConvert.SerializeObject(outCtuExec)}");
//呼叫ctu出库
// await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => outCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync();
// await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => outCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync();
CancellationTokenSource Ctu = new();
await CallingCTU(outCtuExec, Ctu.Token, 0);
Ctu.Dispose();
}
}
catch (Exception ex)
{
}
}
//判断生成bill_code
private string GetBillCode(List OriginDistaskH, List NewdistaskHs, WmsDistaskH distaskH)
{
string BillCode = string.Empty;
//入库
if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID)
{
var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList();
var newdistaskHs = NewdistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList();
if ((orgdistaskHs.Count + newdistaskHs.Count) == 0)
{
var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result;
BillCode = $"{groups}-1";
}
else
{
var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups;
BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1);
}
}
else if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID)
{
var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList();
var newdistaskHs = NewdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList();
if ((orgdistaskHs.Count + newdistaskHs.Count) == 0)
{
var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result;
BillCode = $"{groups}-1";
}
else
{
var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups;
BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1);
}
}
return BillCode;
}
private Timer? timer;
private async void TimerExec(object e)
{
try
{
SqlSugarClient db = _db.CopyNew();
var list = db.Queryable().InnerJoin((a, b) => a.area_id == b.id)
.Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID)
.OrderBy(a => a.bill_code)
.ToList();
var data = list.GroupBy(p => p.groups).Select(p => new
{
groups = p.Key,
time = p.Max(a => a.create_time)
}).ToList();
var date = DateTime.Now;
var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value);
foreach (var item in data)
{
if (date.Subtract(item.time).Minutes >= time)
{
var execlist = list.Where(p => p.groups == item.groups).ToList();
await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => execlist.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync();
// await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => execlist.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync();
CancellationTokenSource Ctu = new();
int type = execlist.First().task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID ? 1 : 0;
await CallingCTU(execlist, Ctu.Token, type);
Ctu.Dispose();
}
}
}
catch (Exception ex)
{
}
finally
{
timer?.Dispose();
}
}
private async Task CallingCTU(List distaskHs, CancellationToken token, int type)
{
try
{
AgvRequestConfig requestCfg = App.Configuration.Build();
string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl;
var taskChainCodeDic = distaskHs.Where(t => !t.groups.IsNullOrWhiteSpace()).GroupBy(g => g.groups!)
.ToDictionary(x => x.Key, x => x.Select(it => new
{
taskCode = it.bill_code,
sourceName = it.startpoint_code,
targetName = it.endpoint_code,
containerCode = it.carry_code,
}));
foreach ((string k, object v) in taskChainCodeDic)
{
dynamic reqBody = new ExpandoObject();
reqBody.taskChainCode = k;
reqBody.type = (int)EnumTaskChainType.CTU;
reqBody.sequential = false;
reqBody.taskChainPriority = 0;
reqBody.taskList = v;
reqBody.inOut = type;
Logger.Information($"【CallingCTU】 CTU任务下发 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} type:{(type == 0 ? "CTU出库" : "CTU入库")}");
dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token);
Logger.Information($"【CallingCTU】 CTU任务下发 接收到联核/task-chain/create接口信息:{respBody}");
}
}
catch (Exception ex)
{
Logger.Information($"【CallingCTU】 CTU任务下发 请求联核/task-chain/create接口失败 异常信息:{ex}");
}
}
#endregion
///
/// 呼梯操作
///
///
///
private async Task CallingLanding(List<(string endlocation_code, string device_id, string id, int floorNO)> endLocCodes)
{
Logger.Information($"【CallingLanding】 开始呼梯操作.............");
try
{
foreach ((_, string devId, string disTaskId, int floorNO) in endLocCodes)
{
Logger.Information($"【CallingLanding】 devId:{devId}");
if (!s_elevatorMap.TryGetValue(devId, out object? elevatorCode))
{
continue;
}
string? devName = elevatorCode.ToString();
Logger.Information($"【CallingLanding】 电梯编号:{devName}");
Logger.Information($"【CallingLanding】 当前:{devName.Match(@"\d+")}#梯");
await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1);
(int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = (-1, -1, -1, -1, -1);
Logger.Information("【CallingLanding】 获取电梯AGV运行状态");
if (!_elevatorAgvCtlStatusMap.TryGetValue(devId, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态)
{
var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" };
do
{
eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);
await Task.Delay(1000);
} while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态);
Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}");
_elevatorAgvCtlStatusMap[devId] = eleStatusMulti.agvStatus;
}
else
{
Logger.Information("【CallingLanding】 AGV运行状态:" + agvCtlStatus);
}
Logger.Information($"【CallingLanding】 任务开始目标楼层为:{floorNO}");
int floorN = await GetRealFloor(floorNO);
//如果电梯在当前楼层则不呼梯
if (floorN == eleStatusMulti.curFloorNo)
{
Logger.Information($"【CallingLanding】 {devName.Match(@"\d+")}#,在当前楼层,无需呼梯");
continue;
}
Logger.Information($"【CallingLanding】 实际目标楼层为:{floorN}");
WmsElevatorUnexecute elevatorQueueItem = new()
{
distask_id = disTaskId,
elevator_id = devId,
elevator_code = devName,
floor = floorN, //5代表4楼
task_status = "待执行",
create_id = _userManager.UserId,
create_time = DateTime.Now
};
List elevatorQueue = await _db.Queryable().Where(it => it.distask_id == disTaskId && it.task_status == "执行中").ToListAsync();
if ((elevatorQueue.IsNull() || elevatorQueue.Count < 1) && floorN != eleStatusMulti.curFloorNo)
{
Logger.Information($"【CallingLanding】 判断当前电梯{devName.Match(@"\d+")}#梯 无任务在做执行呼梯");
elevatorQueueItem.task_status = "执行中";
bool callLiftRes = await _elevatorControlService.CallLift(devName, floorN, CancellationToken.None);
string successful = "成功", fail = "失败";
string callLiftResult = callLiftRes ? successful : fail;
Logger.Information($"{devName.Match(@"\d+")}#, 呼梯结果:{callLiftResult}");
}
else
{
Logger.Information("【CallingLanding】 当前有任务在做,不会呼梯");
}
//如果当前电梯有任务在做,将当前呼梯任务放入待执行队列
_ = await _db.Insertable(elevatorQueueItem).ExecuteCommandAsync();
Logger.Information("【CallingLanding】 呼梯任务执行完成");
}
}
catch (Exception ex)
{
Logger.Error("【CallingLanding】 呼梯操作错误", ex);
Logger.Error($"【CallingLanding】 呼梯操作错误堆栈跟踪:{Environment.NewLine}{ex.StackTrace}");
throw;
}
}
///
/// 执行到目标楼层电梯任务
///
///
///
private async Task ExecuteTargetFloorTask(WmsDistaskH disTask)
{
//收到放货确认通知,向电梯发送到3楼的指令
Logger.Information($"开始执行电梯任务,任务ID:{disTask.id}");
try
{
if (!s_elevatorMap.TryGetValue(disTask.device_id, out object? elevatorCode))
{
Logger.Information($"开始执行电梯任务,没有取到设备{disTask.device_id}的 elevatorCode! s_elevatorMap: {JsonConvert.SerializeObject(s_elevatorMap)}");
return;
}
string devName = s_elevatorMap[disTask.device_id]?.ToString() ?? _eleCtlCfg.DevName3;
Logger.Information($"当前:{devName.Match(@"\d+")}#梯");
var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" };
(int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);
if (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态)
{
_ = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1);
}
if (!_elevatorAgvCtlStatusMap.TryGetValue(disTask.id, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态)
{
do
{
eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);
await Task.Delay(1000);
} while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态);
Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}");
_elevatorAgvCtlStatusMap[disTask.id] = eleStatusMulti.agvStatus;
}
int doorStatus = -1;
bool closeDoorRes = await _elevatorControlService.SendOpenCloseCmd(devName, 4); //向电梯发送前门关门指令
Logger.Information($"关门结果:{closeDoorRes}");
do
{
doorStatus = await _elevatorControlService.GetTagAsync(devName, ElevatorConsts.DoorStatus);
await Task.Delay(1000);
} while (doorStatus != 4);
Logger.Information($"当前门状态:{doorStatus}");
int floor = await GetRealFloor(disTask.end_floor);
Logger.Information($"目标楼层:{floor}");
//发送到目标楼的指令
dynamic reuslt = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor);
//电梯任务手动执行任务状态上报
(int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) tuple = (-1, -1, -1, -1, -1);
do
{
tuple = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None);
await Task.Delay(1000);
} while (tuple.sysStatus != 3 || tuple.runStatus != 0);
Logger.Information($"sysStatus:{tuple.sysStatus},runStatus:{tuple.runStatus},floorNo:{tuple.floorNo},disTask.end_floor={disTask.end_floor}");
if (tuple.sysStatus.ToEnum() == EnumSysStatus.正常状态 && tuple.runStatus.ToEnum() == EnumRunStatus.停梯)
{
Logger.Information($"disTask.require_id={disTask.require_id}");
List disTaskIds = new() { disTask.id };
var upInput = new { disTaskIds = disTask.id };
TaskExecuteAfterUpInput teaUpInput = new()
{
disTaskIds = disTaskIds,
};
await TaskExecuteAfter(teaUpInput);
TaskCompleUpInput tcUpInput = new()
{
disTaskIds = disTaskIds,
};
await TaskComplate(tcUpInput);
Logger.Information("电梯任务执行完成");
}
}
catch (Exception ex)
{
Logger.Error("执行到目标楼层电梯任务失败", ex);
throw;
}
}
///
/// Agv调度
///
///
///
///
private async Task AgvDispatch(List disTasks, CancellationToken token)
{
Logger.Information("【AgvDispatch】 Agv任务执行....");
List kiva = new List();
// 一楼中储仓
kiva.Add("ZSSSXCTU02");
kiva.Add("ZSSSXCTU01");
List floor2 = new List();
// 二楼暂存仓
floor2.Add("AS01");
floor2.Add("AS02");
floor2.Add("AX01");
floor2.Add("AX02");
//调用AGV创建任务链接口
try
{
AgvRequestConfig requestCfg = App.Configuration.Build();
string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl;
Logger.Information($"【AgvDispatch】 Agv任务执行的disTasks:{JsonConvert.SerializeObject(disTasks)}");
var taskChainCodeDic = disTasks.Where(t => !t.groups.IsNullOrWhiteSpace()).GroupBy(g => g.groups!)
.ToDictionary(x => x.Key, x => x.Select(it => new
{
taskCode = it.bill_code,
sourceName = it.startpoint_code,
targetName = it.endpoint_code,
containerCode = it.carry_code,
shelfNumber = floor2.Contains(it.startlocation_code) || floor2.Contains(it.endlocation_code) ? it.carry_code : "" // 二楼暂存仓传料架
}));
Logger.Information($"【AgvDispatch】 Agv任务执行的taskChainCodeDic:{JsonConvert.SerializeObject(taskChainCodeDic)}");
foreach ((string k, object v) in taskChainCodeDic)
{
var typeflag = false;
var dis = disTasks.Where(p => p.groups == k).First();
if (kiva.Contains(dis.startlocation_code) || kiva.Contains(dis.endlocation_code) || floor2.Contains(dis.startlocation_code) || floor2.Contains(dis.endlocation_code))
{
typeflag = true;
}
dynamic reqBody = new ExpandoObject();
reqBody.taskChainCode = k;
reqBody.type = typeflag ? (int)EnumTaskChainType.KIVA : (int)EnumTaskChainType.AGV;
reqBody.sequential = false;
reqBody.taskChainPriority = 0;
reqBody.taskList = v;
reqBody.floor = dis.end_floor;
Logger.Information($"【AgvDispatch】 Agv任务执行 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} ");
dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token);
Logger.Information($"【AgvDispatch】 Agv任务执行 接收到联核/task-chain/create接口信息:{respBody}");
}
}
catch (Exception ex)
{
Logger.Information($"【AgvDispatch】 agv任务执行 请求联核/task-chain/create接口失败 异常信息:{ex}");
throw;
}
}
///
/// 任务执行
///
///
///
[HttpPost]
public async Task TaskExecute(TaskExecuteUpInput input)
{
try
{
await _db.Ado.BeginTranAsync();
//更任务执行
for (int i = 0, cnt = input.disTaskIds.Count; i < cnt; i++)
{
_ = input.EqpIds?.Count > 0
? await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID, device_id = input.EqpIds[i] }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync()
: await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
//await _db.Updateable().SetColumns(it => setColVal).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
}
List preTaskIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => it.pretask_id).ToListAsync();
if (preTaskIds.Count > 0)
{
//更预任务申请表状态
_ = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
Logger.Error("任务执行失败", ex);
await _db.Ado.RollbackTranAsync();
throw;
}
}
///
/// 任务执行取操作返回(后续操作)
///
///
[HttpPost]
public async Task TaskExecuteAfter(TaskExecuteAfterUpInput input)
{
//更新任务执行表单据状态
try
{
await _db.Ado.BeginTranAsync();
_ = await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID, act_start_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
//清空载具库位数据
var carryAndLocIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => new { it.carry_id, it.startlocation_id }).ToListAsync();
if (carryAndLocIds?.Count > 0)
{
List carryIds = carryAndLocIds.Select(x => x.carry_id).ToList();
_ = await _db.Updateable().SetColumns(it => new WmsCarryH { location_id = null, location_code = null }).Where(it => carryIds.Contains(it.id)).ExecuteCommandAsync();
}
//更新起始库位,状态改为空闲、锁定状态,未锁定
if (carryAndLocIds?.Count > 0)
{
List startLocationIds = carryAndLocIds.Select(x => x.startlocation_id).ToList();
_ = await _db.Updateable().SetColumns(it => new BasLocation { is_use = ((int)EnumCarryStatus.空闲).ToString(), is_lock = 0 }).Where(it => startLocationIds.Contains(it.id)).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
Logger.Error("设备取返回操作失败", ex);
await _db.Ado.RollbackTranAsync();
}
}
///
/// 任务完成
///
///
[HttpPost]
public async Task TaskComplate(TaskCompleUpInput input)
{
try
{
await _db.Ado.BeginTranAsync();
//更新任务执行表,单据状态为 完成
_ = await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID, act_end_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
List disTasks = await _db.Queryable().InnerJoin((a, b) => a.carry_id == b.id).Where(a => input.disTaskIds.Contains(a.id)).Select((a, b) => new WmsDistaskH { carry_status = b.carry_status }, true).ToListAsync();
if (disTasks?.Count > 0)
{
// 更新预任务申请表,单据状态为 已完成
List preTaskIds = disTasks.Select(x => x.pretask_id).ToList();
_ = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync();
//更新电梯任务数量
_ = await _db.Updateable().SetColumns(it => new WmsElevatorH { task_nums = it.task_nums - 1}).Where(it => disTasks.Select(x => x.area_code).Contains(it.area_code)).ExecuteCommandAsync();
// 更新中储仓任务数量
_ = await _db.Updateable().SetColumns(it => new BasLocation { task_nums = it.task_nums - 1 }).Where(it => disTasks.Where(r => r.startlocation_code.Contains("SSX-111-011") || r.startlocation_code.Contains("SSX-111-012")).Select(x => x.startlocation_code).Contains(it.location_code)).ExecuteCommandAsync();
//更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位
List<(string carry_id, string carry_status, string endlocation_id, string endlocation_code)> multiList = disTasks.Select(it => (it.carry_id, it.carry_status, it.endlocation_id, it.endlocation_code)).ToList();
Dictionary locWhIdMap = await _db.Queryable().Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ToDictionaryAsync(it => it.id, it => it.wh_id);
List carryIts = new();
List carryCodeIts = new();
List locIts = new();
for (int i = 0, cnt = multiList.Count; i < cnt; i++)
{
WmsCarryH carry = new()
{
id = multiList[i].carry_id,
is_lock = 0,
location_id = multiList[i].endlocation_id,
location_code = multiList[i].endlocation_code
};
string endLocId = multiList[i].endlocation_id;
WmsCarryCode carryCode = new()
{
warehouse_id = locWhIdMap.ContainsKey(endLocId) ? locWhIdMap[endLocId].ToString() : "",
location_id = multiList[i].endlocation_id,
location_code = multiList[i].endlocation_code
};
carryIts.Add(carry);
carryCodeIts.Add(carryCode);
BasLocation loc = new()
{
id = multiList[i].endlocation_id,
is_lock = 0,
is_use = multiList[i].carry_status
};
if (multiList[i].carry_status.ToEnum() == EnumCarryStatus.空闲)
{
loc.is_use = ((int)EnumCarryStatus.占用).ToString();
}
locIts.Add(loc);
}
Logger.Information($@"TaskComplate 更新carryIts: {JsonConvert.SerializeObject(carryIts)}");
Logger.Information($@"TaskComplate 更新carryCodeIts: {JsonConvert.SerializeObject(carryCodeIts)}");
_ = await _db.Updateable(carryIts).UpdateColumns(it => new { it.is_lock, it.location_id, it.location_code }).ExecuteCommandAsync();
//更新条码的库位和仓库信息
_ = await _db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).Where(it => multiList.Select(x => x.carry_id).Contains(it.carry_id)).ExecuteCommandAsync();
//更新库位信息,使用状态为 使用,锁定状态为未锁定
_ = await _db.Updateable(locIts).UpdateColumns(it => new { it.is_use, it.is_lock }).ExecuteCommandAsync();
/* var loginType= _userManager?.LoginType ?? "web";
Log.Information($"_userManager.LoginType={loginType}");
*/ //更新业务主表的单据状态
foreach (WmsDistaskH? dt in disTasks)
{
// 销售出库
if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSSALERELEASE_ID)
{
// TODO 一楼工位放货完成后更新出库明细的实际出库数量
if (dt.start_floor == 1 && dt.end_floor == 1)
{
WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync();
await _db.Updateable().SetColumns(r => r.purchase_prqty == r.purchase_prqty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync();
CarryCodeUnbindInput carryCodeUnbindInput = new CarryCodeUnbindInput();
carryCodeUnbindInput.carry_id = dt.carry_id;
await _wmsCarryBindService.CarryCodeUnbind(carryCodeUnbindInput);
}
}
// 成品调拨入库
else if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSTRANSFERINSTOCK_ID)
{
if (dt.start_floor == 3 && dt.end_floor == 3)
{
WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync();
await _db.Updateable().SetColumns(r => r.qty == r.qty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync();
}
}
List disTaskCodes = await _db.Queryable().Where(it => it.bill_id == dt.id).ToListAsync();
WareHouseUpInput upInput = new() { bizTypeId = dt.biz_type, requireId = dt.require_id!, distaskCodes = disTaskCodes, carryIds = disTasks.Select(x => x.carry_id).ToList() };
/*if (!_userManager?.LoginType.IsNullOrEmpty() ?? false)
{
upInput.loginType = "app";
}
else
{
upInput.loginType = "web";
}*/
upInput.loginType = "web";//(!string.IsNullOrEmpty(_userManager?.LoginType) ? "app" : "web") ?? "web";
if (dt.is_sign == 1 && dt.chain_type == "3")
{
await DoUpdate(upInput);
}
}
}
await _db.Ado.CommitTranAsync();
Logger.Information("任务操作完成");
}
catch (Exception ex)
{
Logger.Error($"任务结束失败", ex);
Logger.Error($"任务结束失败堆栈异常", ex);
await _db.Ado.RollbackTranAsync();
throw;
}
finally
{
_ = GenTaskExecute();
}
}
///
/// 出入库策略启用、禁用状态修改
///
///
///
[HttpPost]
public async Task ModifyPoliciesStatus(ModifyEnabledInput input)
{
async Task _updateStatus(ModifyEnabledInput input) where T : BaseEntity, IUpdatePoliciesStatus, new()
{
T obj = new() { status = input.status };
_ = await _db.Updateable(obj).UpdateColumns(it => it.status).Where(it => input.ids.Contains(it.id)).ExecuteCommandAsync();
}
switch (input.strategyType)
{
case EnumInOutStockType.In:
await _updateStatus(input);
break;
case EnumInOutStockType.Out:
await _updateStatus(input);
break;
}
}
///
/// 生成预任务
///
/// 预任务集合
/// 预任务编码集合
///
public async Task GenPreTask(List preTasks, List preTaskCodes)
{
//如果预任务出现起终库位相同,则删除对应预任务
//modifiy by ly on 20230922 将当前预任务操作者设为四场管理员
preTasks.ForEach(pt =>
{
pt.org_id = WmsWareHouseConst.AdministratorOrgId;
pt.create_id = WmsWareHouseConst.AdministratorUserId;
});
if (preTasks.FindAll(it => it.startlocation_id == it.endlocation_id)?.Count > 0)
{
_ = preTasks.RemoveAll(it => it.startlocation_id == it.endlocation_id);
}
List> grpList = preTasks.OrderBy(o => o.bill_code).GroupBy(g => g.carry_id).ToList();
if (grpList?.Count > 0)
{
foreach (IGrouping? grp in grpList)
{
WmsPretaskH[] arr = grp.ToArray();
if (arr.Length > 1)
{
WmsPretaskH[] subArr = arr[..^1];
System.Array.ForEach(subArr, a => a.chain_type = "1");
}
}
}
int row = await _db.Insertable(preTasks).ExecuteCommandAsync();
if (preTaskCodes?.Count > 0)
{
row = await _db.Insertable(preTaskCodes).ExecuteCommandAsync();
}
var eleP = preTasks.Find(x => x.area_code.Contains("ELE"));
if (eleP != null)
{
row = await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => it.area_code == eleP.area_code).ExecuteCommandAsync();
}
// 累加终点库位任务数
row = await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1)
.Where(it => preTasks.Select(r => r.endlocation_id).Contains(it.id)).ExecuteCommandAsync();
return row > 0;
}
///
/// 生成预任务后续处理
///
///
[NonAction]
public async Task GenInStockTaskHandleAfter(GenPreTaskUpInput input, Expression> setCarryColumnsExp, Expression> setLocaionColumbExp)
{
try
{
await _db.Ado.BeginTranAsync();
//根据生成的预任务,插入预任务操作记录
if (input.PreTaskRecord != null)
{
_ = await _db.Insertable(input.PreTaskRecord).ExecuteCommandAsync();
}
if (input.PreTaskHandleCodes.Count > 0)
{
_ = await _db.Insertable(input.PreTaskHandleCodes).ExecuteCommandAsync();
}
//根据载具ID,更新是否锁定和赋值起始库位
if (setCarryColumnsExp != null)
{
Expression> whereExp = input.CarryIds?.Count > 0 ? it => input.CarryIds.Contains(it.id) : it => it.id == input.CarryId;
_ = await _db.Updateable().SetColumns(setCarryColumnsExp).Where(whereExp).ExecuteCommandAsync();
}
if (input.CarryStartLocationId.IsNullOrWhiteSpace() == false)
{
_ = await _db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync();
}
//根据所有库位更新库位的锁定状态为“锁定”
if (setLocaionColumbExp != null && input.LocationIds?.Count > 0)
{
_ = await _db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
///
/// 路径算法
///
///
///
///
[NonAction]
public async Task> PathAlgorithms(string pStartId, string pEndId)
{
/*
var sp= await _db.Queryable().Where(it => it.id == pStartId).FirstAsync();
var ep = await _db.Queryable().Where(it => it.id == pEndId).FirstAsync();
if (sp.area_code == "B" || ep.area_code == "B")
{
List Points = new List();
var zp = await _db.Queryable().Where(it => it.point_code == "ZSCJZJD").FirstAsync();
Points.Add(sp);
Points.Add(ep);
Points.Add(zp);
Points.ForEach(p =>
{
p.area_code = zp.area_code;
p.area_id = zp.area_id;
});
return Points;
}*/
List roads = await _db.Queryable().Where(it => it.status == 1).ToListAsync();
List points = await LocPathCalcAlgorithms(pStartId, pEndId, roads);
try
{
if (points?.FindAll(x => x.location_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0)
{
//查询当前电梯点
List curEleDs = await _db.Queryable().InnerJoin((a, b) => a.bill_id == b.id).Where((a, b) => points.Select(x => x.id).Contains(a.point_id)).ToListAsync();
Logger.Information($"curEleDs==null :{curEleDs == null},curEleDs:{string.Join(",", curEleDs.Select(x => x.bill_id))}");
//如果有电梯点,则会进行电梯的均匀分配
if (curEleDs?.Count > 0)
{
//当前电梯
WmsElevatorH curEle = await _db.Queryable().SingleAsync(it => it.id == curEleDs.First().bill_id);
//同电梯组电梯
List sGpEle = await _db.Queryable().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id && it.enabled == 1).ToListAsync();
if (curEle.enabled == 0 && (sGpEle == null || sGpEle.Count < 1))
{
throw new AppFriendlyException("电梯被禁用或未配置", 500);
}
if ((sGpEle == null || sGpEle.Count < 1) && curEle.enabled == 1)
{
return points;
}
if (sGpEle?.Count > 0 && curEle.enabled == 0)
{
return points;
}
//判断电梯组中各电梯任务数
if (sGpEle.FindAll(x => Math.Abs(x.task_nums - curEle.task_nums) % 2 == 1)?.Count > 0)
{
List sGpDs = await _db.Queryable().Where(it => it.bill_id == sGpEle.First().id).ToListAsync();
if (sGpDs?.Count > 0)
{
List sGpPoints = await _db.Queryable().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync();
string sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id;
string eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id;
List sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads);
List elePoints = new();
foreach (WmsElevatorD pt in curEleDs)
{
WmsPointH? elePoint = sGpPoints.Find(x => x.floor == pt.floor);
if (elePoint != null)
{
elePoints.Add(elePoint);
}
}
List eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads);
_ = elePoints.Remove(elePoints.First());
_ = elePoints.Remove(elePoints.Last());
points.Clear();
points.AddRange(sFPoints);
points.AddRange(elePoints);
points.AddRange(eFPoints);
}
}
}
}
}
catch (Exception ex)
{
Logger.Error("路径算法异常", ex);
throw;
}
return points;
}
///
/// 路径算法 当出现多个载具同时出库,可能需要进入电梯时
///
///
///
///
///
[NonAction]
public async Task> PathAlgorithmsEle(string pStartId, string pEndId, int ele)
{
List roads = await _db.Queryable