using SqlSugar.Extensions;
|
using System;
|
using System.Collections.Generic;
|
using System.Drawing.Drawing2D;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEA_Common;
|
using WIDESEA_Common.OrderEnum;
|
using WIDESEA_Common.StockEnum;
|
using WIDESEA_Common.TaskEnum;
|
using WIDESEA_Common.WareHouseEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.BaseServices;
|
using WIDESEA_IWMsInfoServices;
|
using WIDESEA_Model.Models;
|
|
|
namespace WIDESEA_WMsInfoServices
|
{
|
public class Inventory_BatchServices : ServiceBase<Dt_Inventory_Batch, IRepository<Dt_Inventory_Batch>>, IInventory_BatchServices
|
{
|
private IMessageInfoService _messageInfoService;
|
private IMaterielInfoService _materielInfoService;
|
private IInventoryInfoService _inventoryInfoService;
|
private ISupplyTaskService _supplyTaskService;
|
public Inventory_BatchServices(IRepository<Dt_Inventory_Batch> BaseDal, IMessageInfoService messageInfoService, IMaterielInfoService materielInfoService, IInventoryInfoService inventoryInfoService, ISupplyTaskService supplyTaskService) : base(BaseDal)
|
{
|
_messageInfoService = messageInfoService;
|
_materielInfoService = materielInfoService;
|
_inventoryInfoService = inventoryInfoService;
|
_supplyTaskService = supplyTaskService;
|
}
|
|
public IRepository<Dt_Inventory_Batch> Repository => BaseDal;
|
|
|
/// <summary>
|
/// 调拨单 修改了库存信息,以及业务数量
|
/// </summary>
|
/// <param name="saveModel"></param>
|
/// <returns></returns>
|
//public override WebResponseContent UpdateData(SaveModel saveModel)
|
//{
|
// try
|
// {
|
// string WareCode = WarehouseEnum.大件库.ObjToInt().ToString("000");
|
// var qty = saveModel.MainData["availableQuantity"].ObjToInt();//用户输入的数量
|
// var id = saveModel.MainData["id"].ObjToInt();//库存批次的id
|
// var materielCode = saveModel.MainData["materielCode"].ToString();
|
// var batchNo = saveModel.MainData["batchNo"].ToString();
|
|
// var materielInfo = _materielInfoService.Repository.QueryFirst(x => x.MaterielCode == materielCode);
|
// if (materielInfo == null) return WebResponseContent.Instance.Error($"请维护药品编号【{materielCode}】的信息");
|
// if (!Enum.IsDefined(typeof(MaterielSourceTypeEnum), materielInfo.MaterielSourceType))
|
// return WebResponseContent.Instance.Error($"请设置药品编号【{materielCode}】的属性分类");
|
// if (materielInfo.MaterielSourceType == MaterielSourceTypeEnum.PurchasePart)
|
// return WebResponseContent.Instance.Error($"药品编号【{materielCode}】的属性分类为大件,不可调拨");
|
|
// List<Dt_InventoryInfo> dt_InventoryInfos = _inventoryInfoService.Repository.QueryData(x => x.MaterielCode == materielInfo.MaterielCode && x.BatchNo == batchNo && x.StockStatus == StockStatusEmun.入库完成.ObjToInt() && x.AvailableQuantity > 0 && x.WarehouseCode == WareCode).OrderBy(x => x.InDate).ToList();
|
// if (dt_InventoryInfos.Count < 1) return WebResponseContent.Instance.Error($"物料编号【{materielInfo.MaterielCode}】大件库无库存!请及时补充库存!");
|
|
// var StockQty = dt_InventoryInfos.Sum(x => x.AvailableQuantity);
|
// if (StockQty < qty) return WebResponseContent.Instance.Error($"调拨数量不可大于大件库可用数量,大件库可用数量为【{StockQty}】");
|
|
// // 检查大件库中是否存在散件
|
// decimal totalLooseQty = 0;
|
// foreach (var inventory in dt_InventoryInfos)
|
// {
|
// var looseQty = inventory.AvailableQuantity % materielInfo.BoxQty;
|
// if (looseQty > 0)
|
// {
|
// totalLooseQty += looseQty;
|
// }
|
// }
|
|
// decimal Qty = 0; // 实际调拨总数量
|
// decimal businessQtyToAdd = 0; // 需要添加到业务数量的数量
|
// List<Dt_SupplyTask> supplyTasks = new List<Dt_SupplyTask>();
|
// Dt_DeliveryOrder deliveryOrder = new Dt_DeliveryOrder()
|
// {
|
// Out_no = DateTime.Now.ToString("yyMMddHHmmss"),
|
// Warehouse_no = WareCode,
|
// Out_type = OutOrderTypeEnum.Allocate.ObjToInt().ToString(),
|
// OutStatus = "新建",
|
// Details = new List<Dt_DeliveryOrderDetail>()
|
// };
|
|
// // 情况1:大件库有散件,且用户输入数量小于等于散件总数,一次性调拨所有散件
|
// if (totalLooseQty > 0 && qty <= totalLooseQty)
|
// {
|
// decimal remainingLooseQty = totalLooseQty;
|
|
// foreach (var item in dt_InventoryInfos)
|
// {
|
// if (remainingLooseQty <= 0) break;
|
|
// var looseQty = item.AvailableQuantity % materielInfo.BoxQty;
|
// if (looseQty > 0)
|
// {
|
// // 一次性调拨该库存记录中的所有散件
|
// item.OutboundQuantity += looseQty;
|
// item.AvailableQuantity -= looseQty;
|
// Qty += looseQty;
|
// businessQtyToAdd += looseQty;
|
// remainingLooseQty -= looseQty;
|
|
// // 添加供应任务
|
// Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
// {
|
// WarehouseCode = item.WarehouseCode,
|
// BatchNo = item.BatchNo,
|
// MaterielName = item.MaterielName,
|
// MaterielCode = item.MaterielCode,
|
// MaterielSpec = item.MaterielSpec,
|
// TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
// TaskType = TaskTypeEnum.AllocatOut.ObjToInt(),
|
// CreateDate = DateTime.Now,
|
// Creater = App.User.UserName ?? "System",
|
// LocationCode = item.LocationCode,
|
// OrderNo = deliveryOrder.Out_no,
|
// Modifier = item.ValidityPeriod,//效期
|
// StockQuantity = looseQty,
|
// SupplyQuantity = 0,
|
// Remark = "散件调拨出库(一次性清理)"
|
// };
|
// supplyTasks.Add(supplyTask);
|
// }
|
// }
|
// }
|
// // 情况2:大件库有散件,但用户输入数量大于散件总数,或者大件库没有散件,按原来整箱逻辑
|
// else
|
// {
|
// // 如果大件库有散件但用户要调拨更多,先清理散件
|
// decimal allocatedLooseQty = 0;
|
// if (totalLooseQty > 0)
|
// {
|
// foreach (var item in dt_InventoryInfos)
|
// {
|
// var looseQty = item.AvailableQuantity % materielInfo.BoxQty;
|
// if (looseQty > 0)
|
// {
|
// // 一次性调拨该库存记录中的所有散件
|
// item.OutboundQuantity += looseQty;
|
// item.AvailableQuantity -= looseQty;
|
// allocatedLooseQty += looseQty;
|
// Qty += looseQty;
|
// businessQtyToAdd += looseQty;
|
|
// // 添加供应任务
|
// Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
// {
|
// WarehouseCode = item.WarehouseCode,
|
// BatchNo = item.BatchNo,
|
// MaterielName = item.MaterielName,
|
// MaterielCode = item.MaterielCode,
|
// MaterielSpec = item.MaterielSpec,
|
// TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
// TaskType = TaskTypeEnum.AllocatOut.ObjToInt(),
|
// CreateDate = DateTime.Now,
|
// Creater = App.User.UserName ?? "System",
|
// LocationCode = item.LocationCode,
|
// OrderNo = deliveryOrder.Out_no,
|
// StockQuantity = looseQty,
|
// Modifier = item.ValidityPeriod,//效期
|
// SupplyQuantity = 0,
|
// Remark = "散件调拨出库(一次性清理)"
|
// };
|
// supplyTasks.Add(supplyTask);
|
// }
|
// }
|
// }
|
|
// // 计算还需要调拨的整箱数量
|
// var remainingQty = qty - allocatedLooseQty;
|
// if (remainingQty > 0)
|
// {
|
// var zx = (int)Math.Ceiling((decimal)remainingQty / materielInfo.BoxQty); // 需要的整箱数
|
|
// foreach (var item in dt_InventoryInfos)
|
// {
|
// decimal taskQty = 0;
|
// if (zx < 1) break;
|
|
// // 计算当前库存可提供的完整箱数
|
// var availableFullBoxes = item.AvailableQuantity / materielInfo.BoxQty;
|
// var boxesToTransfer = Math.Min(availableFullBoxes, zx);
|
|
// if (boxesToTransfer > 0)
|
// {
|
// var transferQty = boxesToTransfer * materielInfo.BoxQty;
|
// taskQty += transferQty;
|
// Qty += transferQty;
|
// businessQtyToAdd += transferQty;
|
// zx -= (int)boxesToTransfer;
|
|
// item.OutboundQuantity += transferQty;
|
// item.AvailableQuantity -= transferQty;
|
|
// // 添加供应任务
|
// Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
// {
|
// WarehouseCode = item.WarehouseCode,
|
// BatchNo = item.BatchNo,
|
// MaterielName = item.MaterielName,
|
// MaterielCode = item.MaterielCode,
|
// MaterielSpec = item.MaterielSpec,
|
// TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
// TaskType = TaskTypeEnum.AllocatOut.ObjToInt(),
|
// CreateDate = DateTime.Now,
|
// Creater = App.User.UserName ?? "System",
|
// LocationCode = item.LocationCode,
|
// OrderNo = deliveryOrder.Out_no,
|
// Modifier = item.ValidityPeriod,//效期
|
// StockQuantity = taskQty,
|
// SupplyQuantity = 0,
|
// Remark = "整箱调拨出库"
|
// };
|
// supplyTasks.Add(supplyTask);
|
// }
|
// }
|
|
// // 检查整箱数量是否足够
|
// if (zx > 0)
|
// {
|
// return WebResponseContent.Instance.Error($"整箱库存不足,无法完成调拨。还需要{zx}箱");
|
// }
|
// }
|
// }
|
|
// // 更新业务数量:业务数量 = 原来的业务数量 + 实际调拨总数量
|
// materielInfo.Business_qty += businessQtyToAdd;
|
|
// // 添加出库单明细
|
// Dt_DeliveryOrderDetail deliveryOrderDetail = new Dt_DeliveryOrderDetail()
|
// {
|
// Batch_num = batchNo,
|
// Order_Outqty = 0,
|
// Order_qty = Qty,
|
// CreateDate = DateTime.Now,
|
// Creater = App.User.UserName ?? "System",
|
// Goods_no = materielCode,
|
// OotDetailStatus = "新建",
|
// Status = 2,
|
// Reservoirarea = WareCode
|
// };
|
// deliveryOrder.Details.Add(deliveryOrderDetail);
|
|
// // 添加调拨入库单
|
// Dt_CabinOrder cabinOrder = new Dt_CabinOrder()
|
// {
|
// Order_no = deliveryOrder.Out_no,
|
// Order_type = InOrderTypeEnum.Allocat.ObjToInt().ToString(),
|
// Warehouse_no = "001",
|
// OdrderStatus = "新建",
|
// Details = new List<Dt_CabinOrderDetail>()
|
// };
|
// foreach (var item in deliveryOrder.Details)
|
// {
|
// Dt_CabinOrderDetail orderDetail = new Dt_CabinOrderDetail()
|
// {
|
// Reservoirarea = cabinOrder.Warehouse_no,
|
// Goods_no = item.Goods_no,
|
// Order_qty = item.Order_qty,
|
// Batch_num = item.Batch_num,
|
// OrderDetailStatus = "新建",
|
// Status = 0
|
// };
|
// cabinOrder.Details.Add(orderDetail);
|
// }
|
|
// Db.Ado.BeginTran();
|
// _materielInfoService.UpdateData(materielInfo);
|
// _inventoryInfoService.Repository.UpdateData(dt_InventoryInfos);
|
// _supplyTaskService.AddData(supplyTasks);
|
// if (deliveryOrder.Details.Count > 0) Db.InsertNav(deliveryOrder).Include(x => x.Details).ExecuteCommand();
|
// if (cabinOrder.Details.Count > 0) Db.InsertNav(cabinOrder).Include(x => x.Details).ExecuteCommand();
|
// Db.Ado.CommitTran();
|
|
// return WebResponseContent.Instance.OK($"调拨出入库单生成成功!实际调拨数量:{(int)Qty}");
|
// }
|
// catch (Exception ex)
|
// {
|
// Db.Ado.RollbackTran();
|
// return WebResponseContent.Instance.Error(ex.Message);
|
// }
|
//}
|
|
|
/// <summary>
|
/// 调拨单
|
/// </summary>
|
/// <param name="saveModel"></param>
|
/// <returns></returns>
|
public override WebResponseContent UpdateData(SaveModel saveModel)
|
{
|
try
|
{
|
string WareCode = WarehouseEnum.大件库.ObjToInt().ToString("000");
|
var qty = saveModel.MainData["availableQuantity"].ObjToInt(); // 用户输入的数量
|
var id = saveModel.MainData["id"].ObjToInt(); // 库存批次的id
|
var materielCode = saveModel.MainData["materielCode"].ToString();
|
var batchNo = saveModel.MainData["batchNo"].ToString();
|
|
var materielInfo = _materielInfoService.Repository.QueryFirst(x => x.MaterielCode == materielCode);
|
if (materielInfo == null) return WebResponseContent.Instance.Error($"请维护药品编号【{materielCode}】的信息");
|
if (!Enum.IsDefined(typeof(MaterielSourceTypeEnum), materielInfo.MaterielSourceType))
|
return WebResponseContent.Instance.Error($"请设置药品编号【{materielCode}】的属性分类");
|
if (materielInfo.MaterielSourceType == MaterielSourceTypeEnum.PurchasePart)
|
return WebResponseContent.Instance.Error($"药品编号【{materielCode}】的属性分类为大件,不可调拨");
|
|
List<Dt_InventoryInfo> dt_InventoryInfos = _inventoryInfoService.Repository.QueryData(x => x.MaterielCode == materielInfo.MaterielCode && x.BatchNo == batchNo && x.StockStatus == StockStatusEmun.入库完成.ObjToInt() && x.AvailableQuantity > 0 && x.WarehouseCode == WareCode).OrderBy(x => x.InDate).ToList();
|
if (dt_InventoryInfos.Count < 1) return WebResponseContent.Instance.Error($"物料编号【{materielInfo.MaterielCode}】大件库无库存!请及时补充库存!");
|
|
var StockQty = dt_InventoryInfos.Sum(x => x.AvailableQuantity);
|
if (StockQty < qty) return WebResponseContent.Instance.Error($"调拨数量不可大于大件库可用数量,大件库可用数量为【{StockQty}】");
|
|
// 检查大件库中是否存在散件
|
decimal totalLooseQty = 0;
|
foreach (var inventory in dt_InventoryInfos)
|
{
|
var looseQty = inventory.AvailableQuantity % materielInfo.BoxQty;
|
if (looseQty > 0)
|
{
|
totalLooseQty += looseQty;
|
}
|
}
|
|
decimal Qty = 0; // 实际调拨总数量
|
decimal businessQtyToAdd = 0; // 需要添加到业务数量的数量
|
List<Dt_SupplyTask> supplyTasks = new List<Dt_SupplyTask>();
|
Dt_DeliveryOrder deliveryOrder = new Dt_DeliveryOrder()
|
{
|
Out_no = DateTime.Now.ToString("yyMMddHHmmss"),
|
Warehouse_no = WareCode,
|
Out_type = OutOrderTypeEnum.Allocate.ObjToInt().ToString(),
|
OutStatus = "新建",
|
Details = new List<Dt_DeliveryOrderDetail>()
|
};
|
|
// 情况1:大件库有散件,且用户输入数量小于等于散件总数,只调拨所有散件
|
if (totalLooseQty > 0 && qty <= totalLooseQty)
|
{
|
decimal remainingLooseQty = totalLooseQty;
|
|
foreach (var item in dt_InventoryInfos)
|
{
|
if (remainingLooseQty <= 0) break;
|
|
var looseQty = item.AvailableQuantity % materielInfo.BoxQty;
|
if (looseQty > 0)
|
{
|
// 一次性调拨该库存记录中的所有散件
|
item.OutboundQuantity += looseQty;
|
item.AvailableQuantity -= looseQty;
|
Qty += looseQty;
|
businessQtyToAdd += looseQty;
|
remainingLooseQty -= looseQty;
|
|
// 添加供应任务
|
Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
{
|
WarehouseCode = item.WarehouseCode,
|
BatchNo = item.BatchNo,
|
MaterielName = item.MaterielName,
|
MaterielCode = item.MaterielCode,
|
MaterielSpec = item.MaterielSpec,
|
TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
TaskType = TaskTypeEnum.AllocatOut.ObjToInt(),
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName ?? "System",
|
LocationCode = item.LocationCode,
|
OrderNo = deliveryOrder.Out_no,
|
Modifier = item.ValidityPeriod, // 效期
|
StockQuantity = looseQty,
|
SupplyQuantity = 0,
|
Remark = "散件调拨出库(一次性清理)"
|
};
|
supplyTasks.Add(supplyTask);
|
}
|
}
|
}
|
// 情况2:大件库有散件,但用户输入数量大于散件总数,或者大件库没有散件
|
else
|
{
|
// 计算补充的整箱数量
|
decimal remainingAfterLoose = qty - totalLooseQty;
|
decimal additionalBoxesNeeded = 0;
|
|
if (remainingAfterLoose > 0)
|
{
|
// 向上取整计算需要的额外整箱数
|
additionalBoxesNeeded = Math.Ceiling(remainingAfterLoose / materielInfo.BoxQty); //向上取整:
|
}
|
|
// 总调拨量 = 所有散件 + 补充的整箱
|
Qty = totalLooseQty + (additionalBoxesNeeded * materielInfo.BoxQty);
|
|
// 开始实际调拨
|
decimal remainingQty = Qty;
|
|
// 先调拨所有散件
|
if (totalLooseQty > 0)
|
{
|
foreach (var item in dt_InventoryInfos)
|
{
|
if (remainingQty <= 0) break;
|
|
var looseQty = item.AvailableQuantity % materielInfo.BoxQty;
|
if (looseQty > 0)
|
{
|
// 调拨该库存记录中的所有散件
|
decimal transferLooseQty = Math.Min(looseQty, remainingQty);
|
item.OutboundQuantity += transferLooseQty;
|
item.AvailableQuantity -= transferLooseQty;
|
businessQtyToAdd += transferLooseQty;
|
remainingQty -= transferLooseQty;
|
}
|
}
|
}
|
|
// 如果还有剩余需要调拨的数量(补充的整箱),从整箱中调拨
|
if (remainingQty > 0)
|
{
|
foreach (var item in dt_InventoryInfos)
|
{
|
if (remainingQty <= 0) break;
|
|
// 计算当前库存的完整箱数量(已扣除散件)
|
decimal availableFullBoxes = item.AvailableQuantity / materielInfo.BoxQty;
|
if (availableFullBoxes > 0)
|
{
|
// 计算需要从该库存调拨的箱数
|
decimal boxesToTransfer = Math.Min(availableFullBoxes, remainingQty / materielInfo.BoxQty);
|
decimal transferQty = boxesToTransfer * materielInfo.BoxQty;
|
|
item.OutboundQuantity += transferQty;
|
item.AvailableQuantity -= transferQty;
|
businessQtyToAdd += transferQty;
|
remainingQty -= transferQty;
|
}
|
}
|
}
|
|
// 检查是否调拨完成
|
if (remainingQty > 0)
|
{
|
return WebResponseContent.Instance.Error($"库存不足,无法完成调拨。还需要{remainingQty}个");
|
}
|
|
// 创建一个总任务,而不是多个任务
|
if (Qty > 0)
|
{
|
// 使用第一个库存记录的信息创建任务
|
var firstInventory = dt_InventoryInfos.FirstOrDefault(x => x.OutboundQuantity > 0);
|
if (firstInventory != null)
|
{
|
Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
{
|
WarehouseCode = firstInventory.WarehouseCode,
|
BatchNo = firstInventory.BatchNo,
|
MaterielName = firstInventory.MaterielName,
|
MaterielCode = firstInventory.MaterielCode,
|
MaterielSpec = firstInventory.MaterielSpec,
|
TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
TaskType = TaskTypeEnum.AllocatOut.ObjToInt(),
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName ?? "System",
|
LocationCode = firstInventory.LocationCode,
|
OrderNo = deliveryOrder.Out_no,
|
Modifier = firstInventory.ValidityPeriod, // 效期
|
StockQuantity = Qty, // 总调拨数量
|
SupplyQuantity = 0,
|
Remark = additionalBoxesNeeded > 0 ?
|
$"调拨出库 {Qty}个(散件{totalLooseQty}个 + 整箱{additionalBoxesNeeded}箱,用户需求{qty}个)" :
|
$"调拨出库 {Qty}个(散件,用户需求{qty}个)"
|
};
|
supplyTasks.Add(supplyTask);
|
}
|
}
|
}
|
|
// 更新业务数量:业务数量 = 原来的业务数量 + 实际调拨总数量
|
materielInfo.Business_qty += businessQtyToAdd;
|
|
// 添加出库单明细
|
Dt_DeliveryOrderDetail deliveryOrderDetail = new Dt_DeliveryOrderDetail()
|
{
|
Batch_num = batchNo,
|
Order_Outqty = 0,
|
Order_qty = Qty,
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName ?? "System",
|
Goods_no = materielCode,
|
OotDetailStatus = "新建",
|
Status = 2,
|
Reservoirarea = WareCode
|
};
|
deliveryOrder.Details.Add(deliveryOrderDetail);
|
|
// 添加调拨入库单
|
Dt_CabinOrder cabinOrder = new Dt_CabinOrder()
|
{
|
Order_no = deliveryOrder.Out_no,
|
Order_type = InOrderTypeEnum.Allocat.ObjToInt().ToString(),
|
Warehouse_no = "001",
|
OdrderStatus = "新建",
|
Details = new List<Dt_CabinOrderDetail>()
|
};
|
foreach (var item in deliveryOrder.Details)
|
{
|
Dt_CabinOrderDetail orderDetail = new Dt_CabinOrderDetail()
|
{
|
Reservoirarea = cabinOrder.Warehouse_no,
|
Goods_no = item.Goods_no,
|
Order_qty = item.Order_qty,
|
Batch_num = item.Batch_num,
|
OrderDetailStatus = "新建",
|
Status = 0
|
};
|
cabinOrder.Details.Add(orderDetail);
|
}
|
|
Db.Ado.BeginTran();
|
_materielInfoService.UpdateData(materielInfo);
|
_inventoryInfoService.Repository.UpdateData(dt_InventoryInfos);
|
_supplyTaskService.AddData(supplyTasks);
|
if (deliveryOrder.Details.Count > 0) Db.InsertNav(deliveryOrder).Include(x => x.Details).ExecuteCommand();
|
if (cabinOrder.Details.Count > 0) Db.InsertNav(cabinOrder).Include(x => x.Details).ExecuteCommand();
|
Db.Ado.CommitTran();
|
|
return WebResponseContent.Instance.OK($"调拨出入库单生成成功!实际调拨数量:{(int)Qty}");
|
}
|
catch (Exception ex)
|
{
|
Db.Ado.RollbackTran();
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
|
|
|
/// <summary>
|
/// 移库/将一个库区的库位移到另一个库位
|
/// </summary>
|
/// <param name="id"></param>
|
/// <returns></returns>
|
public WebResponseContent TransferInventory(int[] keys)
|
{
|
try
|
{
|
List<Dt_DeliveryOrder> deliveryOrders = new List<Dt_DeliveryOrder>();
|
Dt_CabinOrder cabinOrder = null; // 只有一个入库单
|
List<Dt_SupplyTask> supplyTasks = new List<Dt_SupplyTask>();
|
List<Dt_InventoryInfo> _InventoryInfos = new List<Dt_InventoryInfo>();
|
List<Dt_MaterielInfo> materielInfos = new List<Dt_MaterielInfo>();
|
List<Dt_Inventory_Batch> batchUpdates=new List<Dt_Inventory_Batch>();
|
|
// 先根据id找到到这个物料以及批次
|
var inventory_Batches = BaseDal.QueryData(x => keys.Contains(x.Id)).ToList();
|
|
// 收集所有涉及的库位
|
var allWarehouses = new List<string>();
|
foreach (var item in inventory_Batches)
|
{
|
var inventoryInfos = _inventoryInfoService.Repository.QueryData(x =>
|
x.MaterielCode == item.MaterielCode && x.BatchNo == item.BatchNo).ToList();
|
|
if (inventoryInfos.Count > 0)
|
{
|
allWarehouses.AddRange(inventoryInfos.Select(x => x.WarehouseCode));
|
}
|
}
|
|
var distinctWarehouses = allWarehouses.Distinct().ToList();
|
|
// 确定移位类型和目标库位
|
bool has001 = distinctWarehouses.Contains("001");
|
bool has002 = distinctWarehouses.Contains("002");
|
bool has003 = distinctWarehouses.Contains("003");
|
bool has010 = distinctWarehouses.Contains("010");
|
|
string targetWarehouseCode;
|
bool isSameWarehouseShift = false;
|
|
#region 规则
|
// 规则1:如果同时存在001和002,全部移到002
|
if (has001 && has002)
|
{
|
targetWarehouseCode = "002";
|
}
|
// 规则2:如果只有001,移到002
|
else if (has001 && !has002)
|
{
|
targetWarehouseCode = "002";
|
}
|
// 规则3:如果只有002,在002内移位
|
else if (has002 && !has001)
|
{
|
targetWarehouseCode = "002";
|
isSameWarehouseShift = true;
|
}
|
// 规则4:如果只有003,在003内移位
|
else if (has003 && distinctWarehouses.Count == 1)
|
{
|
targetWarehouseCode = "003";
|
isSameWarehouseShift = true;
|
}
|
// 规则5:如果只有010,在010内移位
|
else if (has010 && distinctWarehouses.Count == 1)
|
{
|
targetWarehouseCode = "010";
|
isSameWarehouseShift = true;
|
}
|
else
|
{
|
throw new Exception("无效的库存组合或跨库房移位不允许");
|
}
|
#endregion
|
|
|
// 先判断这个是否有待出库数量,以及盘点差异数
|
foreach (var item in inventory_Batches)
|
{
|
#region 判断是否创建
|
var supplyTask1 = _supplyTaskService.Repository.QueryData(x => x.MaterielCode == item.MaterielCode && x.BatchNo == item.BatchNo && x.TaskType == TaskTypeEnum.TransferOut.ObjToInt()).ToList();
|
if (supplyTask1.Count>0) throw new Exception($"物料编号【{item.MaterielCode}】批次号【{item.BatchNo}】已存在移库任务,请先完成当前移库任务");
|
|
// 查找任务中是否存在待盘点任务
|
supplyTask1 = _supplyTaskService.Repository.QueryData(x => x.MaterielCode == item.MaterielCode && x.BatchNo == item.BatchNo && x.TaskStatus == SupplyStatusEnum.NewCheck.ObjToInt()).ToList();
|
if (supplyTask1.Count > 0) throw new Exception($"物料编号【{item.MaterielCode}】批次号【{item.BatchNo}】已存在盘点任务,请先完成当前盘点任务");
|
|
// 查找任务中是否存在出库任务
|
supplyTask1 = _supplyTaskService.Repository.QueryData(x => x.MaterielCode == item.MaterielCode && x.BatchNo == item.BatchNo && x.TaskStatus == SupplyStatusEnum.NewOut.ObjToInt()).ToList();
|
if (supplyTask1.Count > 0) throw new Exception($"物料编号【{item.MaterielCode}】批次号【{item.BatchNo}】已存在出库任务,请先完成当前出库任务");
|
#endregion
|
|
// 查找库存信息
|
var inventoryInfos = _inventoryInfoService.Repository.QueryData(x => x.MaterielCode == item.MaterielCode && x.BatchNo == item.BatchNo).ToList();
|
if (inventoryInfos.Count > 0)
|
{
|
// 计算该物料批次的总库存数量(所有库位)
|
decimal totalStockQuantity = inventoryInfos.Sum(x => x.StockQuantity);
|
|
// 直接更新批次对象的字段
|
item.OutboundQuantity += totalStockQuantity;
|
item.AvailableQuantity -= totalStockQuantity;
|
|
// 添加到更新列表(如果还没添加过)
|
if (!batchUpdates.Any(x => x.Id == item.Id))
|
{
|
batchUpdates.Add(item);
|
}
|
|
|
|
// 创建入库单(只有一个)
|
if (cabinOrder == null)
|
{
|
cabinOrder = new Dt_CabinOrder()
|
{
|
Order_no = $"RK{targetWarehouseCode}{DateTime.Now.ToString("yyMMddHHmmss")}",
|
Order_type = "40", // 移位入库
|
OdrderStatus = "新建",
|
Warehouse_no = targetWarehouseCode,
|
Details = new List<Dt_CabinOrderDetail>()
|
};
|
}
|
|
// 添加入库明细(总数量)
|
Dt_CabinOrderDetail cabinOrderDetail = new Dt_CabinOrderDetail()
|
{
|
Batch_num = item.BatchNo,
|
Order_Inqty = 0,
|
Order_qty = totalStockQuantity, // 所有库位的总数量
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName,
|
Goods_no = item.MaterielCode,
|
OrderDetailStatus = "新建",
|
Status = targetWarehouseCode == "001" ? 0 : 2,
|
Reservoirarea = targetWarehouseCode,
|
};
|
|
// 检查是否已有相同物料批次的入库明细
|
var existingDetail = cabinOrder.Details.FirstOrDefault(x =>
|
x.Goods_no == item.MaterielCode && x.Batch_num == item.BatchNo);
|
|
if (existingDetail != null)
|
{
|
// 如果已存在,合并数量
|
existingDetail.Order_qty += totalStockQuantity;
|
}
|
else
|
{
|
// 添加入库
|
cabinOrder.Details.Add(cabinOrderDetail);
|
}
|
|
// 根据库房号来进行分组,为每个源库位创建出库单
|
foreach (var items in inventoryInfos.GroupBy(x => x.WarehouseCode))
|
{
|
string sourceWarehouseCode = items.Key;
|
|
//// 如果是同库房移位且源库位就是目标库位,跳过(不移到自身)
|
//if (isSameWarehouseShift && sourceWarehouseCode == targetWarehouseCode)
|
// continue;
|
|
// 查找到该库房号的出库单
|
var deliveryOrder = deliveryOrders.Where(x => x.Warehouse_no == sourceWarehouseCode).FirstOrDefault();
|
bool isNull = false;
|
if (deliveryOrder == null)
|
{
|
isNull = true;
|
deliveryOrder = new Dt_DeliveryOrder()
|
{
|
Out_no = $"YK{sourceWarehouseCode}{DateTime.Now.ToString("yyMMddHHmmss")}{new Random().Next(1000, 9999)}",
|
Out_type = "30", // 移位出库
|
OutStatus = "新建",
|
Warehouse_no = sourceWarehouseCode,
|
Details = new List<Dt_DeliveryOrderDetail>()
|
};
|
}
|
|
var Status = sourceWarehouseCode == "001" ? 0 : 2; // 判断是否为立库区域
|
Dt_DeliveryOrderDetail deliveryOrderDetail = new Dt_DeliveryOrderDetail()
|
{
|
Batch_num = item.BatchNo,
|
Order_Outqty = 0,
|
Order_qty = items.Select(x => x.StockQuantity).Sum(), // 该库位的数量
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName,
|
Goods_no = item.MaterielCode,
|
OotDetailStatus = "新建",
|
Status = Status,
|
Reservoirarea = sourceWarehouseCode,
|
};
|
|
deliveryOrder.Details.Add(deliveryOrderDetail);
|
if (isNull) deliveryOrders.Add(deliveryOrder);
|
|
#region 创建移库出库任务
|
foreach (var inventory in items)
|
{
|
// 保存原来的库存数量
|
decimal originalStockQuantity = inventory.StockQuantity;
|
|
// 更新库存信息:增加待出库数量,减少可用库存
|
inventory.OutboundQuantity += originalStockQuantity;
|
inventory.AvailableQuantity -= originalStockQuantity;
|
|
Dt_SupplyTask supplyTask = new Dt_SupplyTask()
|
{
|
WarehouseCode = inventory.WarehouseCode,
|
TaskStatus = SupplyStatusEnum.NewOut.ObjToInt(),
|
BatchNo = inventory.BatchNo,
|
MaterielName = inventory.MaterielName,
|
MaterielCode = inventory.MaterielCode,
|
MaterielSpec = inventory.MaterielSpec,
|
TaskType = TaskTypeEnum.TransferOut.ObjToInt(),
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName,
|
LocationCode = inventory.LocationCode,
|
OrderNo = deliveryOrder.Out_no,
|
StockQuantity = inventory.StockQuantity,
|
Modifier = inventory.ValidityPeriod, // 效期
|
SupplyQuantity = 0,
|
Remark = isSameWarehouseShift ?
|
$"在{sourceWarehouseCode}库房内移位" :
|
$"从{sourceWarehouseCode}移库到{targetWarehouseCode}",
|
};
|
supplyTasks.Add(supplyTask);
|
_InventoryInfos.Add(inventory);
|
}
|
#endregion
|
}
|
}
|
}
|
|
// 检查是否有需要移位的库存
|
if (cabinOrder == null || cabinOrder.Details.Count == 0)
|
throw new Exception("没有需要移位的库存");
|
|
_InventoryInfos.ForEach(x =>
|
{
|
x.StockStatus = StockStatusEmun.移位中.ObjToInt();
|
});
|
|
Db.Ado.BeginTran();
|
_materielInfoService.UpdateData(materielInfos);
|
_inventoryInfoService.UpdateData(_InventoryInfos);
|
_supplyTaskService.AddData(supplyTasks);
|
BaseDal.UpdateData(batchUpdates);
|
|
// 批量插入出库单(每个源库位一个)
|
foreach (var deliveryOrder in deliveryOrders)
|
{
|
if (deliveryOrder.Details.Count > 0)
|
Db.InsertNav(deliveryOrder).Include(x => x.Details).ExecuteCommand();
|
}
|
|
// 插入入库单(只有一个)
|
if (cabinOrder != null && cabinOrder.Details.Count > 0)
|
Db.InsertNav(cabinOrder).Include(x => x.Details).ExecuteCommand();
|
|
Db.Ado.CommitTran();
|
|
string message = isSameWarehouseShift ?
|
"库内货位调整单生成成功!" :
|
"移库出入库单生成成功!";
|
|
return WebResponseContent.Instance.OK(message);
|
}
|
catch (Exception ex)
|
{
|
Db.Ado.RollbackTran();
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
/// <summary>
|
/// 库存过期预警
|
/// </summary>
|
/// <returns></returns>
|
public WebResponseContent GetExpiredAndlow()
|
{
|
WebResponseContent content = new WebResponseContent();
|
try
|
{
|
DateTime dateTime = DateTime.Now.AddDays(30).Date;
|
DateTime dateTime60 = DateTime.Now.AddDays(60).Date;
|
DateTime dateTime180 = DateTime.Now.AddDays(180).Date;
|
|
|
List<Dt_Inventory_Batch> inventory_Batches = BaseDal.QueryData(x => x.ValidityPeriod < dateTime || x.ValidityPeriod < dateTime60 || x.ValidityPeriod < dateTime180).ToList();
|
foreach (var item in inventory_Batches)
|
{
|
var day = (item.ValidityPeriod - DateTime.Now).Days;
|
string d = $"还有{day}天过期";
|
if (day < 0) d = $"已过期{Math.Abs(day)}天";
|
_messageInfoService.AddMessageInfo(MessageGroupByEnum.InventoryExceedAlarm, "物料名称:" + item.MaterielName, $"物料编号【{item.MaterielCode}】物料批次【{item.BatchNo}】{d}", messageRemark: $"物料编号【{item.MaterielCode}】物料批次【{item.BatchNo}】");
|
}
|
}
|
catch (Exception ex)
|
{
|
content.Error(ex.Message);
|
}
|
return content;
|
}
|
|
|
}
|
}
|