using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Aspose.Cells.Drawing; using Dm; using JNPF.Common.Contracts; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.Extras.CollectiveOAuth.Config; using JNPF.FriendlyException; using JNPF.Systems.Interfaces.System; using Mapster; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis; using NPOI.OpenXmlFormats.Wordprocessing; using Polly.Timeout; using Spire.Pdf.Widget; using SqlSugar; using Tnb.BasicData.Entities; using Tnb.BasicData.Entities.Enums; using Tnb.Common.Utils; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 库房业务类(出入库) /// public class WareHouseService : BaseWareHouseService, IWareHouseService { private readonly ISqlSugarClient _db; private readonly IDictionaryDataService _dictionaryDataService; public WareHouseService(ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService) { _db = repository.AsSugarClient(); _dictionaryDataService = dictionaryDataService; } /// /// 根据载具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, carry_name = a.carry_name, location_id = b.id, location_name = b.location_name, warehouse_id = c.id, warehouse_name = c.whname, }) .ToListAsync(); return items; } /// /// 库房业务,入库、出库申请新增修改功能 /// /// /// [HttpPost] public async Task ApplyFor(InOutStockApplyforUpInput input) { // bill_line,location_id,delivery_date,carry_id,carry_code if (input == null) throw new ArgumentNullException("input"); var isOk = false; switch (input.inoutStockType) { case EnumInOutStockType.In: var wmsInstockD = input.Adapt(); var wmsInstockCodes = input.InstockCodes.Adapt>(); if (wmsInstockCodes?.Count > 0) { wmsInstockCodes.ForEach(x => { if (x.id.IsNullOrWhiteSpace()) { x.id = SnowflakeIdHelper.NextId(); } x.bill_d_id = wmsInstockD.id; }); } isOk = await _update(wmsInstockD, wmsInstockCodes); break; case EnumInOutStockType.Out: var wmsOutstockD = input.Adapt(); var wmsOutstockCodes = input.InstockCodes.Adapt>(); if (wmsOutstockCodes?.Count > 0) { wmsOutstockCodes.ForEach(x => { if (x.id.IsNullOrWhiteSpace()) { x.id = SnowflakeIdHelper.NextId(); } x.bill_d_id = wmsOutstockD.id; }); } isOk = await _update(wmsOutstockD, wmsOutstockCodes); break; } if (!isOk) throw Oops.Oh(ErrorCode.COM1001); } /// /// 根据明细Id获取出入库明细信息 /// /// /// [HttpGet] public async Task GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input) { dynamic result = null; var dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID); switch (input.inoutStockType) { case EnumInOutStockType.In: result = await _db.Queryable() .Where(a => a.id == input.bill_d_id) .Select(a => new InStockDetailOutput { id = a.id, bill_id = a.bill_id, unit_id = a.unit_id, code_batch = a.code_batch, warehouse_id = a.warehouse_id, line_status = a.line_status, reason = a.reason, pr_qty = a.pr_qty, qty = a.qty, price = a.price, tax_price = a.tax_price, print_qty = a.print_qty, scan_qty = a.scan_qty, material_code = a.material_code, amount = a.amount, all_amount = a.all_amount, CodeDetails = SqlFunc.Subqueryable().Where(it => it.bill_d_id == a.id).ToList(), }) .Mapper(it => it.line_status = dic.ContainsKey(it.line_status) ? dic[it.line_status]?.ToString()! : "") .ToListAsync(); break; case EnumInOutStockType.Out: result = await _db.Queryable() .Where(a => a.id == input.bill_d_id) .Select(a => new OutStockDetailOutput { id = a.id, bill_id = a.bill_id, unit_id = a.unit_id, code_batch = a.code_batch, warehouse_id = a.warehouse_id, line_status = a.line_status, price = a.price, tax_price = a.tax_price, material_code = a.material_code, amount = a.amount, all_amount = a.all_amount, CodeDetails = SqlFunc.Subqueryable().Where(it => it.bill_d_id == a.id).ToList(), }) .Mapper(it => it.line_status = dic.ContainsKey(it.line_status) ? dic[it.line_status]?.ToString()! : "") .ToListAsync(); break; } return result; } /// /// 入库策略 /// /// [HttpGet] public async Task> InStockStrategy([FromQuery] InStockStrategyQuery input) { var items = await _db.Queryable().Where(it => it.wh_id == input.warehouse_id && it.is_lock == 0 && it.is_use == "0" && it.is_type == "0").OrderBy(it => new { it.layers, it.loc_line, it.loc_column }, OrderByType.Asc).ToListAsync(); return items.Take(input.Size).ToList(); } /// /// 出库策略 /// /// [HttpGet] public async Task OutStockStrategy() { return Task.FromResult(true); } /// /// 生成预任务 /// /// /// /// public async Task GenPreTask(List preTasks) { var row = await _db.Insertable(preTasks).ExecuteCommandAsync(); return row > 0; } /// /// 生成预任务后续处理 /// /// [NonAction] public async Task GenTaskHandleAfter(GenPreTaskUpInput input) { try { await _db.Ado.BeginTranAsync(); //根据载具移入Id,回更单据状态 await _db.Updateable().SetColumns(it => new WmsMoveInstock { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == input.PreTaskId).ExecuteCommandAsync(); //根据生成的预任务,插入预任务操作记录 await _db.Insertable(input.PreTaskRecords).ExecuteCommandAsync(); //根据载具ID,更新是否锁定和赋值起始库位 await _db.Updateable().SetColumns(it => new WmsCarryH { is_lock = 1, location_id = input.CarryStartLocationId, location_code = input.CarryStartLocationCode }).Where(it => it.id == input.CarryId).ExecuteCommandAsync(); //根据所有库位更新库位的锁定状态为“锁定” await _db.Updateable().SetColumns(it => new BasLocation { is_lock = 1 }).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync(); await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); } } /// /// 路径算法 /// /// /// /// public async Task> PathAlgorithms(string pStartId, string pEndId) { var roads = await _db.Queryable().ToListAsync(); var points = await LocPathCalcAlgorithms(pStartId, pEndId, roads); return points; } #region PrivateMethods private async Task> LocPathCalcAlgorithms(string pStartId, string pEndId, List roads) { var points = await _db.Queryable().ToListAsync(); List results = new(); List subRoads = new(); Dictionary isVisited = roads.Select(x => x.startpoint_id).Distinct().ToDictionary(x => x, x => false); List pointIds = new(); List codes = new(); Dp dp = new(); dp.DpFunc(roads, subRoads, pointIds, isVisited, pStartId, pEndId); foreach (var pid in pointIds) { var point = points.Find(x => x.id == pid); if (point != null) { results.Add(point); } } #region dijkstra //var points = await _db.Queryable().ToListAsync(); //var startObj = points.Find(x => x.id == pStartId); //var endObj = points.Find(x => x.id == pEndId); //var sIndex = points.IndexOf(startObj); //var eIndex = points.IndexOf(endObj); //if (eIndex < sIndex) //{ // var tempIndex = sIndex; // sIndex = eIndex; // eIndex = tempIndex; // var temp = points[sIndex]; // points[sIndex] = points[eIndex]; // points[eIndex] = temp; //} ////MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId); //var vexs = points.Select(p => p.id).ToArray(); //EData[] edges = new EData[roads.Count]; //for (int i = 0; i < edges.Length; i++) //{ // var start = roads[i].startpoint_id; // var end = roads[i].endpoint_id; // var weight = roads[i].distance; // edges[i] = new EData(start, end, weight); //} //Dijkstra pG = new(vexs, edges); //int[] prev = new int[pG.mVexs.Length]; //int[] dist = new int[pG.mVexs.Length]; //List vertexs = new() { startObj }; //pG.CalcDijkstra(sIndex, prev, dist); //var pointIds = points.Select(p => p.id).ToList(); //List result = new(); //GetPoints(pointIds, prev, result, eIndex); //var items =new List(); //foreach (var item in prev.Where(x=>x!=0)) //{ // if (points[item] != null) // { // items.Add(points[item].point_code); // } //} //var @strings = string.Join(",", items.OrderBy(o=>o)); //var shortestPathPoints = points.FindAll(x => result.Contains(x.id)); //if (shortestPathPoints.IndexOf(startObj) < 0) //{ // shortestPathPoints.Add(startObj); //} //List results = new() { startObj }; //var isVisited = shortestPathPoints.ToDictionary(x => x.id, x => false); //var isVisited2 = shortestPathPoints.ToDictionary(x => x.id, x => false); //isVisited[pStartId] = true; //MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId); //results.Add(endObj); #endregion return results; } /// /// 获取匹配的最短路径节点 /// /// /// /// /// /// /// private void MatchPoint(List results, List roads, List shortestPathPoints, Dictionary isVisited, string pStartId, string pEndId) { var sRoads = roads.Where(x => x.startpoint_id == pStartId).ToList(); for (int j = 0; j < sRoads.Count; j++) { var sPoint = shortestPathPoints.Find(x => x.id == sRoads[j].endpoint_id); if (sPoint != null && isVisited.ContainsKey(sPoint.id) && !isVisited[sPoint.id] && sPoint.id != pEndId) { var code = sPoint.point_code; results.Add(sPoint); isVisited[sPoint.id] = true; MatchPoint(results, roads, shortestPathPoints, isVisited, sPoint.id, pEndId); } } } /// /// 根据终止节点获取最短路径顶点 /// /// /// /// /// private static void GetPoints(List pointIds, int[] prev, List result, int eIdx) { var index = eIdx; while (index != 0) { result.Add(pointIds[index]); index = prev[index]; } } private async Task _update(T1 entity, List entities) where T1 : BaseEntity, new() where T2 : BaseEntity, new() { var isOk = false; try { await _db.Ado.BeginTranAsync(); isOk = await _db.Updateable(entity).ExecuteCommandHasChangeAsync(); if (entities?.Count > 0) { var row = await _db.Storageable(entities).ExecuteCommandAsync(); isOk = row > 0; } await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); } return isOk; } #endregion } }