263 lines
11 KiB
C#
263 lines
11 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using Aspose.Cells.Drawing;
|
||
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 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.Dto;
|
||
using Tnb.WarehouseMgr.Entities.Enums;
|
||
using Tnb.WarehouseMgr.Interfaces;
|
||
|
||
namespace Tnb.WarehouseMgr
|
||
{
|
||
/// <summary>
|
||
/// 库房业务类(出入库)
|
||
/// </summary>
|
||
[ApiDescriptionSettings(Tag = ModuleConsts.Tag, Area = ModuleConsts.Area, Order = 700)]
|
||
[Route("api/[area]/[controller]/[action]")]
|
||
public class WareHouseService : IWareHouseService, IDynamicApiController, ITransient
|
||
{
|
||
private readonly ISqlSugarClient _db;
|
||
public WareHouseService(ISqlSugarRepository<WmsInstockH> repository)
|
||
{
|
||
_db = repository.AsSugarClient();
|
||
}
|
||
/// <summary>
|
||
/// 根据载具Id带出库位、仓库信息
|
||
/// </summary>
|
||
/// <param name="carryId">载具id</param>
|
||
/// <remarks>
|
||
/// returns:
|
||
/// <br/>{
|
||
/// <br/> carry_id:载具Id
|
||
/// <br/> carry_name:载具名称
|
||
/// <br/> location_id:库位Id
|
||
/// <br/> location_name:库位名称
|
||
/// <br/> warehouse_id:库房Id
|
||
/// <br/> warehouse_name:库房名称
|
||
/// <br/>}
|
||
/// </remarks>
|
||
[HttpGet]
|
||
public async Task<dynamic> GetLocationAndWorkHouseByCarryId([FromRoute] string carryId)
|
||
{
|
||
var items = await _db.Queryable<WmsCarryH>().LeftJoin<BasLocation>((a, b) => a.location_id == b.id)
|
||
.LeftJoin<BasWarehouse>((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;
|
||
}
|
||
/// <summary>
|
||
/// 库房业务,入库、出库申请新增修改功能
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[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<WmsInstockD>();
|
||
var wmsInstockCodes = input.InstockCodes.Adapt<List<WmsInstockCode>>();
|
||
wmsInstockCodes.ForEach(x =>
|
||
{
|
||
if (x.id.IsNullOrWhiteSpace())
|
||
{
|
||
x.id = SnowflakeIdHelper.NextId();
|
||
}
|
||
});
|
||
isOk = await _update<WmsInstockD, WmsInstockCode>(wmsInstockD, wmsInstockCodes);
|
||
break;
|
||
case EnumInOutStockType.Out:
|
||
var wmsOutstockD = input.Adapt<WmsOutstockD>();
|
||
var wmsOutstockCodes = input.InstockCodes.Adapt<List<WmsOutstockCode>>();
|
||
wmsOutstockCodes.ForEach(x =>
|
||
{
|
||
if (x.id.IsNullOrWhiteSpace())
|
||
{
|
||
x.id = SnowflakeIdHelper.NextId();
|
||
}
|
||
});
|
||
isOk = await _update<WmsOutstockD, WmsOutstockCode>(wmsOutstockD, wmsOutstockCodes);
|
||
break;
|
||
}
|
||
if (!isOk) throw Oops.Oh(ErrorCode.COM1001);
|
||
}
|
||
/// <summary>
|
||
/// 根据明细Id获取出入库明细信息
|
||
/// </summary>
|
||
/// <param name="billDId"></param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<dynamic> GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input)
|
||
{
|
||
dynamic result = null;
|
||
switch (input.inoutStockType)
|
||
{
|
||
case EnumInOutStockType.In:
|
||
result = await _db.Queryable<WmsInstockD>()
|
||
.Where(a => a.id == input.bill_d_id)
|
||
.Select(a => new InStockDetailOutput
|
||
{
|
||
bill_id = a.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,
|
||
CodeDetails = SqlFunc.Subqueryable<WmsInstockCode>().Where(it => it.bill_d_id == a.id).ToList(),
|
||
}).ToListAsync();
|
||
|
||
break;
|
||
case EnumInOutStockType.Out:
|
||
result = await _db.Queryable<WmsOutstockCode>().Where(it => it.bill_d_id == input.bill_d_id).ToListAsync();
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
private async Task<bool> _update<T1, T2>(T1 entity, List<T2> entities) where T1 : BaseEntity<string>, new() where T2 : BaseEntity<string>, new()
|
||
{
|
||
var isOk = false;
|
||
try
|
||
{
|
||
await _db.Ado.BeginTranAsync();
|
||
isOk = await _db.Updateable(entity).ExecuteCommandHasChangeAsync();
|
||
isOk = await _db.Updateable(entities).ExecuteCommandHasChangeAsync();
|
||
await _db.Ado.CommitTranAsync();
|
||
}
|
||
catch (Exception)
|
||
{
|
||
await _db.Ado.RollbackTranAsync();
|
||
}
|
||
return isOk;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径算法
|
||
/// </summary>
|
||
/// <param name="pStartId"></param>
|
||
/// <param name="pEndId"></param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task PathAlgorithms(string pStartId, string pEndId)
|
||
{
|
||
var roads = await _db.Queryable<WmsRoad>().ToListAsync();
|
||
await LocPathCalcAlgorithms(pStartId, pEndId, roads);
|
||
}
|
||
private async Task LocPathCalcAlgorithms(string pStartId, string pEndId, List<WmsRoad> roads)
|
||
{
|
||
var points = await _db.Queryable<WmsPointH>().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);
|
||
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<WmsPointH> pG = new(vexs, edges);
|
||
int[] prev = new int[pG.mVexs.Length];
|
||
int[] dist = new int[pG.mVexs.Length];
|
||
List<WmsPointH> vertexs = new() { startObj };
|
||
pG.CalcDijkstra(sIndex, prev, dist);
|
||
var pointIds = points.Select(p => p.id).ToList();
|
||
List<string> result = new();
|
||
GetPoints(pointIds, prev, result, eIndex);
|
||
var shortestPathPoints = points.FindAll(x => result.Contains(x.id));
|
||
shortestPathPoints.Add(points.Find(x => x.id == pStartId));
|
||
List<WmsPointH> results = new() { startObj };
|
||
var isVisited = shortestPathPoints.ToDictionary(x => x.id, x => false);
|
||
isVisited[pStartId] = true;
|
||
MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId);
|
||
results.Add(endObj);
|
||
string str = null;
|
||
}
|
||
/// <summary>
|
||
/// 获取匹配的最短路径节点
|
||
/// </summary>
|
||
/// <param name="results"></param>
|
||
/// <param name="roads"></param>
|
||
/// <param name="shortestPathPoints"></param>
|
||
/// <param name="isVisited"></param>
|
||
/// <param name="pStartId"></param>
|
||
/// <param name="pEndId"></param>
|
||
private void MatchPoint(List<WmsPointH> results, List<WmsRoad> roads, List<WmsPointH> shortestPathPoints, Dictionary<string, bool> 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);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 根据终止节点获取最短路径顶点
|
||
/// </summary>
|
||
/// <param name="pointIds"></param>
|
||
/// <param name="prev"></param>
|
||
/// <param name="result"></param>
|
||
/// <param name="eIdx"></param>
|
||
private static void GetPoints(List<string> pointIds, int[] prev, List<string> result, int eIdx)
|
||
{
|
||
var index = eIdx;
|
||
while (index != 0)
|
||
{
|
||
result.Add(pointIds[index]);
|
||
index = prev[index];
|
||
}
|
||
}
|
||
}
|
||
}
|