using System.Reflection.Emit; using Aop.Api.Domain; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.Extensitions.EventBus; using JNPF.FriendlyException; using JNPF.Logging; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev; using JNPF.VisualDev.Entitys.Dto.VisualDevModelData; using Mapster; using Microsoft.AspNetCore.Mvc; using Senparc.Weixin.Work.AdvancedAPIs.MailList; using SqlSugar; using Tnb.BasicData; using Tnb.BasicData.Entitys.Entity; using Tnb.EquipMgr.Entities; using Tnb.ProductionMgr.Entities; using Tnb.ProductionMgr.Entities.Dto; using Tnb.ProductionMgr.Entities.Enums; using Tnb.ProductionMgr.Interfaces; namespace Tnb.ProductionMgr { /// /// 生产计划管理 /// [ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 700)] [Route("api/[area]/[controller]/[action]")] [OverideVisualDev(ModuleId)] public class PrdMoService : IOverideVisualDevService, IPrdMoService, IDynamicApiController, ITransient { private const string ModuleId = "25567924238373"; private readonly ISqlSugarRepository _repository; private readonly IDataBaseManager _dataBaseManager; private readonly IUserManager _userManager; private readonly IDictionaryDataService _dictionaryDataService; public OverideVisualDevFunc OverideFuncs { get; } = new OverideVisualDevFunc(); public PrdMoService( ISqlSugarRepository repository, IDataBaseManager dataBaseManager, IUserManager userManager, IDictionaryDataService dictionaryDataService ) { _repository = repository; _dataBaseManager = dataBaseManager; _userManager = userManager; _dictionaryDataService = dictionaryDataService; OverideFuncs.DeleteAsync = Delete; } #region Get /// /// 根据产品ID获取模具列表 /// /// 产品ID /// /// ///
return results: ///
[ ///
{ ///
mold_code:模具编号 ///
mold_name:模具名称 ///
item_name:产品名称 ///
item_code:产品编号 ///
cavity_qty:模穴数 ///
} ///
] ///
[HttpGet("{itemId}")] public async Task GetMoldListByItemId(string itemId) { var db = _repository.AsSugarClient(); var list = await db.Queryable().InnerJoin((a, b) => a.item_id == b.id) .Where((a, b) => a.item_id == itemId) .Select((a, b) => new MoldListOutput { mold_id = a.id, mold_code = a.mold_code, mold_name = a.mold_name, item_name = b.product_name, cavity_qty = a.cavity_qty, item_code = b.product_code, }) .ToListAsync(); return list; } /// /// 根据模具Id获取设备列表 /// /// /// [HttpGet("{moldId}")] public async Task GetEquipmentListByMoldId(string moldId) { var items = await _repository.AsSugarClient().Queryable() .Where(it => it.mold_id == moldId) .Select(it => new EquipmentListOutput { eqp_id = it.id, eqp_code = it.eqp_code, eqp_type_code = it.eqp_type_code, eqp_machine_num = it.eqp_machine_num, tonnage = it.tonnage, task_list_qty = SqlFunc.Subqueryable().Where(x => x.eqp_id == it.id).Count(), estimated_end_date = SqlFunc.Subqueryable().Where(x => x.eqp_id == it.id).OrderByDesc(o => o.estimated_end_date).Select(x => x.estimated_end_date) }) .Mapper(x => { x.first_date = x.estimated_end_date.HasValue ? x.estimated_end_date.Value.ToString("yyyy-MM-dd HH:mm:ss") : ""; }) .ToListAsync(); return items; } /// /// 工单调整-生产任务重新排序 /// /// 设备ID /// 排序后生产任务列表 /// /// returns: ///
[ ///
{ ///
no:生产序号 ///
mo_id:工单编号 ///
group_flag:同组标识 ///
plan_qty:计划生产数量 ///
comple_qty:完成数量 ///
item_name:产品名称 ///
mold_code:模具编号 ///
} ///
] ///
[HttpGet("{eqpId}")] public async Task PrdTaskSort(string eqpId) { var taskStatusDic = await _dictionaryDataService.GetDicByTypeId(DictConst.PrdTaskStatusTypeId); var list = await _repository.AsSugarClient().Queryable() .Where(it => it.eqp_id == eqpId) .OrderBy(o => o.estimated_start_date) .ToListAsync(); var data = list.Select((x, idx) => new PrdTaskSortOutput { no = idx + 1, mo_id = x.mo_id, status = taskStatusDic.ContainsKey(x.status) ? taskStatusDic[x.status].ToString() : "", group_flag = x.group_flag, plan_qty = x.plan_qty, comple_qty = x.comple_qty, item_name = x.item_name, mold_code = x.mold_code, }) .ToList(); return data; } /// /// 查看生产任务操作记录 /// /// 任务ID /// [HttpGet("{taskId}")] public async Task GetMoOperRecord(string taskId) { var list = await _repository.AsSugarClient().Queryable().Where(it => it.id == taskId).ToListAsync(); var data = list.Adapt>(); var dic = await _dictionaryDataService.GetDicByTypeId(DictConst.PrdTaskStatusTypeId); _repository.AsSugarClient().ThenMapper(data, x => x.statusName = dic.ContainsKey(x.status) ? dic[x.status].ToString() : ""); return data; } #endregion #region Post /// /// 生产工单创建-生产工单下发 /// /// 生产工单下发输入参数 /// [HttpPut] public async Task WorkOrderIssue(MoCrInput input) { if (input is null) { throw new ArgumentNullException(nameof(input)); } var db = _repository.AsSugarClient(); //获取同组工单的Id,一起下发 var combineMoCodes = await db.Queryable().Where(it => input.WorkOrderIds.Contains(it.id)).Select(it => it.combine_mo_code).ToListAsync(); if (combineMoCodes?.Count > 0) { var moIds = await db.Queryable().Where(it => combineMoCodes.Contains(it.combine_mo_code) && !input.WorkOrderIds.Contains(it.id)).Select(it => it.id).ToListAsync(); input.WorkOrderIds = input.WorkOrderIds.Concat(moIds).ToList(); } var row = await db.Updateable() .SetColumns(it => new PrdMo { mo_status = DictConst.IssueId, icmo_status = DictConst.ToBeScheduledEncode }) .Where(it => input.WorkOrderIds.Contains(it.id)) .ExecuteCommandAsync(); return (row > 0); } /// /// 关联同组工单 /// /// 关联同组工单输入参数 /// [HttpPost] public async Task RelevancySameGroupMo(MoCrInput input) { (bool executeRes, string errMsg) multi = (true, ""); var list = await _repository.AsSugarClient().Queryable() .InnerJoin((a, b) => a.item_code == b.item_id) .Where((a, b) => input.WorkOrderIds.Contains(a.id)) .Select((a, b) => new { planDate = a.plan_start_date, mold_code = b.mold_code, }).ToListAsync(); var planDateAll = true; var moldIdAll = true; if (list?.Count > 0) { var planDate = list.FirstOrDefault()?.planDate; var moldCode = list.FirstOrDefault()?.mold_code; planDateAll = list.Skip(1).All(x => x.planDate == planDate); moldIdAll = list.Skip(1).All(x => x.mold_code == moldCode); if (planDateAll && moldIdAll) { var groupId = SnowflakeIdHelper.NextId(); multi.executeRes = await _repository.AsSugarClient().Updateable() .SetColumns(c => new PrdMo { combine_mo_code = groupId }) .Where(it => input.WorkOrderIds.Contains(it.id)) .ExecuteCommandHasChangeAsync(); } else { multi.executeRes = false; if (!planDateAll) { throw new AppFriendlyException("计划开始日期不一致", null); } if (!moldIdAll) { throw new AppFriendlyException("未关联到同一模具下", null); } } } return multi; } /// /// 取消关联 /// /// 取消关联输入参数 /// [HttpPost] public async Task CanelRelevancy(MoCrInput input) { return await _repository.AsSugarClient().Updateable() .SetColumns(c => new PrdMo { combine_mo_code = "" }) .Where(it => input.WorkOrderIds.Contains(it.id)) .ExecuteCommandHasChangeAsync(); } /// /// 生产工单-生产排产 /// /// ///
{ ///
Id:生产任务主键Id ///
MoType:工单类型 1、注塑/挤出 2、组装/包装 ///
MoId:工单Id ///
ItemId:产品编号 ///
ItemName:产品名称 ///
MoldId:模具Id ///
MoldName:模具名称 ///
EqpId:设备Id ///
EqpName:设备名称 ///
LineId:产线编号 ///
LineName:产线名称 ///
} /// /// [HttpPost] public async Task ProductionScheduling(ProductionSchedulingCrInput input) { var row = -1; if (input.mo_type.HasValue && input.mo_type.Value == 1) { input.id ??= SnowflakeIdHelper.NextId(); var entity = input.Adapt(); entity.status = DictConst.ToBeStartedEnCode; //任务单状态默认,待排产 entity.create_id = _userManager.UserId; entity.create_time = DateTime.Now; entity.prd_task_id = input.id; var db = _repository.AsSugarClient(); try { List entities = new(); List icmoEntities = new(); //根据工单Id查询同组工单号,进行同组工单排产处理 var combineMoCodes = await db.Queryable().Where(it => it.id == input.mo_id).Select(it => it.combine_mo_code).Distinct().ToListAsync(); if (combineMoCodes?.Count > 0) { entities = await db.Queryable().Where(it => combineMoCodes.Contains(it.combine_mo_code)).ToListAsync(); } await db.Ado.BeginTranAsync(); //同组工单排产 if (entities.Count > 0) { icmoEntities = entities.Select(x => new PrdTask { id = SnowflakeIdHelper.NextId(), item_id = x.id, item_code = x.item_code, mo_type = input.mo_type, plan_start_date = x.plan_start_date, plan_end_date = x.plan_end_date, }).ToList(); icmoEntities.ForEach(x => { x.status = DictConst.ToBeStartedEnCode; //任务单状态默认,待排产 x.create_id = _userManager.UserId; x.create_time = DateTime.Now; x.prd_task_id = x.id; }); row = await db.Insertable(icmoEntities).ExecuteCommandAsync(); var icmoRecords = icmoEntities.Adapt>(); icmoRecords.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.status ??= DictConst.ToBeStartedEnCode; x.create_id = _userManager.UserId; x.create_time = DateTime.Now; x.operator_name = _userManager.RealName; }); var icmoIds = icmoRecords.Select(it => it.task_id).Distinct().ToList(); var statusMany = icmoRecords.Select(it => it.status).Distinct().ToList(); //任务状态变更时插入操作记录 var logEntities = await db.Queryable().Where(it => icmoIds.Contains(it.task_id)).ToListAsync(); if (logEntities?.Count > 0) { var dbTaskStatusList = logEntities.Select(x => x.status).Distinct().ToList(); var ultimatelyStatus = statusMany.Except(dbTaskStatusList).ToList(); icmoRecords = icmoRecords.Where(x => ultimatelyStatus.Contains(x.status)).ToList(); } if (icmoRecords.Count > 0) { row = await db.Insertable(icmoRecords).ExecuteCommandAsync(); } } else { row = await db.Storageable(entity).ExecuteCommandAsync(); var taskLogEntity = input.Adapt(); taskLogEntity.id ??= SnowflakeIdHelper.NextId(); taskLogEntity.task_id = input.id; taskLogEntity.status ??= "ToBeStarted"; taskLogEntity.create_id = _userManager.UserId; taskLogEntity.create_time = DateTime.Now; taskLogEntity.operator_name = _userManager.RealName; //任务状态变更时插入操作记录 if (!db.Queryable().Where(it => it.task_id == input.id && it.status == taskLogEntity.status).Any()) { row = await db.Insertable(taskLogEntity).ExecuteCommandAsync(); } } if (row > 0) { if (icmoEntities?.Count > 0 && combineMoCodes?.FirstOrDefault() is not null) { var moList = await db.Queryable().Where(it => combineMoCodes.Contains(it.combine_mo_code)).ToListAsync(); var combinePlanQty = icmoEntities?.Sum(x => x.plan_qty); //合并工单后的计划数量 var combineScheduledQty = icmoEntities?.Sum(x => x.scheduled_qty); //合并后的已排产数量 if (combineScheduledQty < combinePlanQty) { icmoEntities!.ForEach(x => { var item = moList.Find(xx => xx.id == x.mo_id); if (item != null) { item.input_qty += x.scheduled_qty; item.mo_status = DictConst.WaitProductId; } }); } else { //如果已排产数量大于计划数量,修改工单状态为,待开工 if (combineScheduledQty >= combinePlanQty) { icmoEntities!.ForEach(x => { var item = moList.Find(xx => xx.id == x.mo_id); if (item != null) { item.input_qty += x.scheduled_qty; item.mo_status = DictConst.AlreadyId; } }); } } row = await db.Updateable(moList).ExecuteCommandAsync(); } else { var obj = (await db.Queryable().FirstAsync(it => it.id == input.mo_id)); obj.input_qty += entity.scheduled_qty; string moStatus = "", icmoStatus = ""; //判断,已排产数量>=计划数量时将状态改为 已排产 if (obj.input_qty >= obj.plan_qty) { moStatus = DictConst.AlreadyId; icmoStatus = DictConst.ToBeStartedEnCode; } else { //修改工单状态为待排产,同事修改已排产数量 moStatus = DictConst.WaitProductId; icmoStatus = DictConst.ToBeScheduledEncode; } row = await db.Updateable().SetColumns(it => new PrdMo { mo_status = moStatus, icmo_status = icmoStatus, input_qty = obj.input_qty }) .Where(it => it.id == entity.mo_id).ExecuteCommandAsync(); } } await db.Ado.CommitTranAsync(); } catch (Exception ex) { Log.Error("生产任务发布时发生错误", ex); await db.Ado.RollbackTranAsync(); } } return row > 0; } /// /// 生产任务下发,开始 、结束、完成 /// /// 输入参数 /// /// /// [HttpPost] public async Task PrdTaskRelease(PrdTaskReleaseUpInput input) { var row = -1; if (input is null) { throw new ArgumentNullException(nameof(input)); } if (input.TaskIds is null) { throw new ArgumentNullException(nameof(input.TaskIds)); } if (input.Behavior.IsNullOrWhiteSpace()) { throw new ArgumentException($"{nameof(input.Behavior)} not be null or empty"); } string SetTaskStatus(Behavior behavior) => behavior switch { Behavior.Release => DictConst.ToBeStartedEnCode, Behavior.Start => DictConst.InProgressEnCode, Behavior.Closed => DictConst.ClosedEnCode, Behavior.Compled => DictConst.ComplatedEnCode, _ => throw new NotImplementedException(), }; Behavior behavior = input.Behavior.ToEnum(); var status = SetTaskStatus(behavior); var db = _repository.AsSugarClient(); if (behavior == Behavior.Compled) { var list = await db.Queryable().Where(it => input.TaskIds.Contains(it.id)).Select(it => it).ToListAsync(); if (list?.Count > 0) { var schedQtySum = list.Sum(x => x.scheduled_qty); var planQtySum = list.Sum(x => x.plan_qty); if (schedQtySum < planQtySum) { throw new AppFriendlyException("任务数量必须大于等于生产计划数量,才可完成", 500); } } } row = await db.Updateable() .SetColumns(it => new PrdTask { status = status }) .Where(it => input.TaskIds.Contains(it.id)) .ExecuteCommandAsync(); return (row > 0); } /// /// 生产任务单修改 /// /// 生产任务单修改输入参数 /// /// [HttpPost] public async Task IcmoModify(IcmoUpInput input) { var row = -1; var db = _repository.AsSugarClient(); if (input.icmo_id.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(input.icmo_id)); var icmoItem = await db.Queryable().FirstAsync(it => it.id == input.icmo_id); switch (input.category) { case 1: //设备 var eqpItem = await db.Queryable().FirstAsync(it => it.id == input.eqp_id); icmoItem.eqp_id = eqpItem.id; icmoItem.eqp_type_code = eqpItem.eqp_type_code; if (input.scheduled_qty > icmoItem.plan_qty) { throw new AppFriendlyException("任务单数量不能大于计划数量", 500); } row = await db.Updateable().SetColumns(it => new PrdMo { input_qty = input.scheduled_qty }).Where(it => it.id == input.mo_id).ExecuteCommandAsync(); break; case 2: //模具 var moldItem = await db.Queryable().FirstAsync(it => it.id == input.mold_id); icmoItem.mold_id = moldItem.id; icmoItem.mold_code = moldItem.mold_code; icmoItem.mold_name = moldItem.mold_name; icmoItem.mold_cavity_qty = moldItem.cavity_qty; break; } row = await db.Updateable(icmoItem).ExecuteCommandAsync(); return (row > 0); } #endregion /// /// 删除 /// /// /// private async Task Delete(string id) { var db = _repository.AsSugarClient(); var result = await db.Ado.UseTranAsync(async () => { var row = -1; var prdTask = await db.Queryable().FirstAsync(it => it.id == id); row = await db.Deleteable().Where(it => it.id == id).ExecuteCommandAsync(); if (row > 0) { var prdMo = await db.Queryable().FirstAsync(it => it.id == prdTask.mo_id); if (prdMo is not null) { prdMo.input_qty += prdTask.scheduled_qty; prdMo.icmo_status = DictConst.ToBeScheduledEncode; row = await db.Updateable(prdMo).ExecuteCommandAsync(); } } return row > 0; }); if (!result.IsSuccess) throw Oops.Oh(ErrorCode.COM1002); } } }