using Microsoft.AspNetCore.Http;
|
using Org.BouncyCastle.Asn1.Ocsp;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEA_Common.StockEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.BaseServices;
|
using WIDESEA_DTO.Outbound;
|
using WIDESEA_IBasicService;
|
using WIDESEA_IOutboundService;
|
using WIDESEA_IStockService;
|
using WIDESEA_Model.Models;
|
|
namespace WIDESEA_OutboundService
|
{
|
internal class SplitPackageService : ServiceBase<Dt_SplitPackageRecord, IRepository<Dt_SplitPackageRecord>>, ISplitPackageService
|
{
|
private readonly IUnitOfWorkManage _unitOfWorkManage;
|
public IRepository<Dt_SplitPackageRecord> Repository => BaseDal;
|
|
private readonly IStockInfoService _stockInfoService;
|
private readonly IStockInfoDetailService _stockInfoDetailService;
|
private readonly IOutStockLockInfoService _outStockLockInfoService;
|
private readonly IDailySequenceService _dailySequenceService;
|
|
public SplitPackageService(IRepository<Dt_SplitPackageRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, IDailySequenceService dailySequenceService) : base(BaseDal)
|
{
|
_unitOfWorkManage = unitOfWorkManage;
|
_stockInfoService = stockInfoService;
|
_outStockLockInfoService = outStockLockInfoService;
|
_stockInfoDetailService = stockInfoDetailService;
|
_dailySequenceService = dailySequenceService;
|
}
|
|
/// <summary>
|
/// 拆包拆箱操作
|
/// </summary>
|
public async Task<WebResponseContent> SplitPackage(SplitPackageDto request)
|
{
|
try
|
{
|
_unitOfWorkManage.BeginTran();
|
|
// 1. 验证出库锁定信息
|
var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.OrderNo == request.OrderNo &&
|
x.PalletCode == request.PalletCode &&
|
x.CurrentBarcode == request.OriginalBarcode &&
|
x.Status == 1)
|
.FirstAsync();
|
|
if (lockInfo == null)
|
return WebResponseContent.Instance.Error("未找到有效的出库锁定信息");
|
|
// 2. 检查剩余锁定数量
|
decimal remainingLockQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty;
|
if (request.SplitQuantity > remainingLockQuantity)
|
return WebResponseContent.Instance.Error($"拆包数量不能大于剩余锁定数量,剩余:{remainingLockQuantity}");
|
|
var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
|
.Where(x => x.Barcode == request.OriginalBarcode)
|
.FirstAsync();
|
|
var seq = await _dailySequenceService.GetNextSequenceAsync();
|
// 3. 生成新条码
|
string newBarcode = "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
|
|
decimal remainingQty = remainingLockQuantity - request.SplitQuantity;
|
// 4. 创建新的出库锁定信息(新条码)
|
var newLockInfo = new Dt_OutStockLockInfo
|
{
|
|
OrderNo = lockInfo.OrderNo,
|
OrderDetailId = lockInfo.OrderDetailId,
|
BatchNo = lockInfo.BatchNo,
|
MaterielCode = lockInfo.MaterielCode,
|
MaterielName = lockInfo.MaterielName,
|
StockId = lockInfo.StockId,
|
OrderQuantity = remainingQty,
|
OriginalQuantity = remainingQty,
|
AssignQuantity = remainingQty, // 新条码分配数量
|
PickedQty = 0, // 新条码未拣选
|
LocationCode = lockInfo.LocationCode,
|
PalletCode = lockInfo.PalletCode,
|
TaskNum = lockInfo.TaskNum,
|
Status = (int)OutLockStockStatusEnum.出库中,
|
Unit = lockInfo.Unit,
|
SupplyCode = lockInfo.SupplyCode,
|
OrderType=lockInfo.OrderType,
|
CurrentBarcode = newBarcode, // 新条码
|
OriginalLockQuantity = request.SplitQuantity,
|
IsSplitted = 1,
|
ParentLockId = lockInfo.Id // 记录父级锁定ID
|
};
|
await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
|
|
// 5. 更新原锁定信息的分配数量(减少拆包数量)
|
lockInfo.AssignQuantity -= request.SplitQuantity;
|
await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
|
|
// 6. 记录拆包历史(用于追踪)
|
var splitHistory = new Dt_SplitPackageRecord
|
{
|
FactoryArea = lockInfo.FactoryArea,
|
TaskNum=lockInfo.TaskNum,
|
OutStockLockInfoId = lockInfo.Id,
|
StockId = stockDetail?.StockId ?? 0,
|
Operator = App.User.UserName,
|
IsReverted = false,
|
OriginalBarcode = lockInfo.CurrentBarcode,
|
NewBarcode = newBarcode,
|
SplitQty = request.SplitQuantity,
|
RemainQuantity = lockInfo.RemainQuantity - request.SplitQuantity,
|
MaterielCode = lockInfo.MaterielCode,
|
SplitTime = DateTime.Now,
|
OrderNo = request.OrderNo,
|
PalletCode = request.PalletCode,
|
Status = (int)SplitPackageStatusEnum.已拆包
|
};
|
await Db.Insertable(splitHistory).ExecuteCommandAsync();
|
|
_unitOfWorkManage.CommitTran();
|
|
// 7. 回传新条码给MES
|
// await SendBarcodeToMES(newBarcode, request.MaterielCode, request.SplitQuantity);
|
|
return WebResponseContent.Instance.OK("拆包成功", new
|
{
|
NewBarcode = newBarcode,
|
NewLockInfoId = newLockInfo.Id
|
});
|
}
|
catch (Exception ex)
|
{
|
_unitOfWorkManage.RollbackTran();
|
return WebResponseContent.Instance.Error($"拆包失败: {ex.Message}");
|
}
|
}
|
|
// 撤销拆包
|
public async Task<WebResponseContent> RevertSplitPackage(string originalBarcode)
|
{
|
try
|
{
|
_unitOfWorkManage.BeginTran();
|
// 查找最近的未撤销拆包记录
|
var splitPackage = await Db.Queryable<Dt_SplitPackageRecord>()
|
.Where(x => x.OriginalBarcode == originalBarcode && !x.IsReverted)
|
.OrderByDescending(x => x.CreateDate)
|
.FirstAsync();
|
|
if (splitPackage == null)
|
return WebResponseContent.Instance.Error("未找到拆包记录");
|
|
// 检查新条码是否已拣选
|
var newOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.CurrentBarcode == splitPackage.NewBarcode)
|
.FirstAsync();
|
|
if (newOutStockInfo.Status == 2)
|
return WebResponseContent.Instance.Error("新条码已拣选,无法撤销拆包");
|
|
// 还原原出库详情数量
|
var originalOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.CurrentBarcode == originalBarcode)
|
.FirstAsync();
|
|
originalOutStockInfo.AssignQuantity += splitPackage.SplitQty;
|
await _outStockLockInfoService.Db.Updateable(originalOutStockInfo).ExecuteCommandAsync();
|
|
// 删除新出库详情记录
|
await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
|
.Where(x => x.CurrentBarcode == splitPackage.NewBarcode)
|
.ExecuteCommandAsync();
|
|
// 标记拆包记录为已撤销
|
splitPackage.IsReverted = true;
|
await Db.Updateable(splitPackage).ExecuteCommandAsync();
|
|
_unitOfWorkManage.CommitTran();
|
return WebResponseContent.Instance.OK("撤销拆包成功");
|
|
}
|
catch (Exception ex)
|
{
|
_unitOfWorkManage.RollbackTran();
|
return WebResponseContent.Instance.Error($"撤销拆包失败:{ex.Message}");
|
}
|
}
|
|
// 获取拆包信息
|
public async Task<WebResponseContent> GetSplitPackageInfo(string orderNo, string palletCode, string barcode)
|
{
|
var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.OrderNo == orderNo &&
|
x.PalletCode == palletCode &&
|
x.CurrentBarcode == barcode &&
|
x.Status == 1)
|
.FirstAsync();
|
|
if (outStockInfo == null)
|
return WebResponseContent.Instance.Error("未找到对应的出库信息");
|
|
//var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
|
// .Where(x => x.Barcode == barcode)
|
// .FirstAsync();
|
|
return WebResponseContent.Instance.OK("", new
|
{
|
MaterielCode = outStockInfo.MaterielCode,
|
RemainQuantity = outStockInfo.RemainQuantity,
|
Unit = outStockInfo.Unit
|
});
|
}
|
/// <summary>
|
/// 获取可拆包的出库锁定信息
|
/// </summary>
|
public async Task<WebResponseContent> GetSplitableLockInfos(int orderDetailId)
|
{
|
var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Includes(x => x.StockInfo)
|
.Where(x => x.OrderDetailId == orderDetailId &&
|
x.Status == (int)OutLockStockStatusEnum.出库中 &&
|
x.AssignQuantity > x.PickedQty) // 还有未拣选数量
|
.Select(x => new
|
{
|
x.Id,
|
x.PalletCode,
|
x.LocationCode,
|
x.MaterielCode,
|
LockQuantity = x.AssignQuantity - x.PickedQty,
|
x.CurrentBarcode,
|
x.IsSplitted,
|
StockDetails = x.StockInfo.Details.Where(d => d.MaterielCode == x.MaterielCode)
|
.Select(d => new
|
{
|
d.Barcode,
|
AvailableQuantity = d.StockQuantity - d.OutboundQuantity
|
})
|
.ToList()
|
})
|
.ToListAsync();
|
|
return WebResponseContent.Instance.OK(null, lockInfos);
|
}
|
}
|
}
|