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
}
}