Files
kunshan-bzfm-mes-backend/DOAN.Service/MES/Material/MmInventoryService.cs
git_rabbit 3d98d742e5 fix: 修复工单信息更新时机和材料出库记录操作符错误
修复ReportFlowService中工单信息更新逻辑,将其移至正确的位置以确保数据一致性
修正MmInventoryService中材料出库记录的操作符赋值错误,并补充遗漏的Operator字段
2026-03-02 19:50:54 +08:00

1312 lines
55 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DOAN.Model;
using DOAN.Model.BZFM;
using DOAN.Model.BZFM.Dto;
using DOAN.Model.MES.order;
using DOAN.Model.MES.product;
using DOAN.Repository;
using DOAN.Service.BZFM.IBZFMService;
using Infrastructure.Attribute;
using Infrastructure.Converter;
using Infrastructure.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
namespace DOAN.Service.BZFM
{
/// <summary>
/// 库存表Service业务层处理
/// </summary>
[AppService(ServiceType = typeof(IMmInventoryService), ServiceLifetime = LifeTime.Transient)]
public class MmInventoryService : BaseService<MmInventory>, IMmInventoryService
{
/// <summary>
/// 查询库存表列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<MmInventoryDto> GetList(MmInventoryQueryDto parm)
{
var predicate = QueryExp(parm);
var response = Queryable()
.Where(predicate.ToExpression())
.ToPage<MmInventory, MmInventoryDto>(parm);
return response;
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
public MmInventory GetInfo(int Id)
{
var response = Queryable().Where(x => x.Id == Id).First();
return response;
}
/// <summary>
/// 添加库存表
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MmInventory AddMmInventory(MmInventory model)
{
return Insertable(model).ExecuteReturnEntity();
}
/// <summary>
/// 修改库存表
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public int UpdateMmInventory(MmInventory model)
{
return Update(model, true);
}
/// <summary>
/// 查询导出表达式
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
private static Expressionable<MmInventory> QueryExp(MmInventoryQueryDto parm)
{
var predicate = Expressionable
.Create<MmInventory>()
.AndIF(
!string.IsNullOrEmpty(parm.MaterialCode),
m => m.MaterialCode == parm.MaterialCode
)
.AndIF(
!string.IsNullOrEmpty(parm.SupplierCode),
m => m.SupplierCode == parm.SupplierCode
)
.AndIF(
!string.IsNullOrEmpty(parm.WarehouseName),
m => m.WarehouseName.Contains(parm.WarehouseName)
)
.AndIF(
!string.IsNullOrEmpty(parm.WarehouseCode),
m => m.WarehouseCode.Contains(parm.WarehouseCode)
)
.AndIF(
!string.IsNullOrEmpty(parm.LocationCode),
m => m.LocationCode.Contains(parm.LocationCode)
)
.AndIF(
!string.IsNullOrEmpty(parm.SupplierName),
m => m.SupplierName.Contains(parm.SupplierName)
)
.AndIF(!string.IsNullOrEmpty(parm.BatchNo), m => m.BatchNo.Contains(parm.BatchNo));
return predicate;
}
public List<MmMaterialOption> GetMaterialOption()
{
try
{
return Context
.Queryable<MmMaterial>()
.Where(it => it.Status == "启用")
.Select(it => new MmMaterialOption
{
Id = it.Id,
MaterialCode = it.MaterialCode,
MaterialName = it.MaterialName,
CategoryCode = it.CategoryCode,
Specification = it.Specification,
SupplierCode = it.SupplierCode,
SupplierName = it.SupplierName,
Type = it.Type,
})
.OrderBy(it => it.Type)
.ToList();
}
catch (Exception)
{
throw;
}
}
public List<MmLocationOption> GetLocationOption()
{
try
{
return Context
.Queryable<MmLocation>()
.Where(it => it.Status == "启用")
.Select(it => new MmLocationOption
{
Id = it.Id,
WarehouseCode = it.WarehouseCode,
WarehouseName = it.WarehouseName,
LocationCode = it.LocationCode,
LocationName = it.LocationName,
LocationType = it.LocationType,
})
.ToList();
}
catch (Exception)
{
throw;
}
}
public List<MmTransactionOption> GetTransactionOption()
{
try
{
return Context
.Queryable<MmTransactionType>()
.Where(it => it.Status == "启用")
.Select(it => new MmTransactionOption
{
Label = it.TypeName,
Value = it.TypeCode,
})
.ToList();
}
catch (Exception)
{
throw;
}
}
// 入库单
public string CreateInboundReceipt(InboundReceiptDto parm)
{
try
{
DateTime nowDate = DateTime.Now;
// 计算有符号变动量(蓝单为正,红单为负)
decimal delta = GetSignedQuantity(parm.ReceiptType, parm.Quantity);
// 校验物料和库位
var mmMaterial = Context
.Queryable<MmMaterial>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.WhereIF(
!string.IsNullOrEmpty(parm.SupplierCode),
it => it.SupplierCode == parm.SupplierCode
)
.First();
if (mmMaterial == null)
return "物料不存在!";
var mmLocation = Context
.Queryable<MmLocation>()
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
if (mmLocation == null)
return "仓库编码或库位编码不存在!";
// 启用事务
Context.Ado.BeginTran();
// 获取现有库存(同物料、批次、库位)
var mmInventory = Context
.Queryable<MmInventory>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.Where(it => it.BatchNo == parm.BatchNo)
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
// 若不存在则新增;存在则更新
if (mmInventory == null)
{
var newInventory = new MmInventory()
{
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
SupplierCode = mmMaterial.SupplierCode,
SupplierName = mmMaterial.SupplierName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
BatchNo = parm.BatchNo,
CurrentQty = delta,
Unit = parm.Unit,
ExpiryDate = parm.ExpiryDate,
LastUpdatedTime = null,
ProductionDate = parm.ProductionDate,
CreatedTime = nowDate,
};
Context.Insertable(newInventory).ExecuteCommand();
}
else
{
mmInventory.CurrentQty += delta;
Context
.Updateable(mmInventory)
.UpdateColumns(it => it.CurrentQty)
.ExecuteCommand();
}
// 插入入库记录,入库单号使用自动增长策略(同日期按序号)
var inboundNo = GenerateReceiptNo("RK");
MmRecordInbound newRecord = new()
{
InboundNo = inboundNo,
BatchNo = parm.BatchNo,
Operator = parm.Operator,
StoveCode = parm.StoveCode,
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
SupplierCode = mmMaterial.SupplierCode,
SupplierName = mmMaterial.SupplierName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
//TODO 待调整(可能涉及记录汇总)
Quantity = delta,
Unit = parm.Unit,
ProductionDate = parm.ProductionDate,
Workorder = parm.Workorder,
WorkorderRaw = parm.WorkorderRaw,
ExpiryDate = parm.ExpiryDate,
CreatedTime = nowDate,
TransactionType = parm.TransactionType,
Remarks = parm.Remarks,
};
Context.Insertable(newRecord).ExecuteCommand();
Context.Ado.CommitTran();
return "ok";
}
catch (Exception ex)
{
// 回滚操作
Context.Ado.RollbackTran();
return ex.Message;
}
}
// 出库单
public string CreateOutboundReceipt(OutboundReceiptDto parm)
{
try
{
DateTime nowDate = DateTime.Now;
// 计算有符号变动量(蓝单为正,红单为负)
decimal delta = GetSignedQuantity(parm.ReceiptType, parm.Quantity);
Context.Ado.BeginTran();
MmInventory mmInventory = null;
if (parm.InventoryId == -1)
{
var mmMaterial = Context
.Queryable<MmMaterial>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.WhereIF(
!string.IsNullOrEmpty(parm.SupplierCode),
it => it.SupplierCode == parm.SupplierCode
)
.First();
if (mmMaterial == null)
return "物料不存在!";
var mmLocation = Context
.Queryable<MmLocation>()
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
if (mmLocation == null)
return "仓库编码或库位编码不存在!";
mmInventory = Context
.Queryable<MmInventory>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.Where(it => it.BatchNo == parm.BatchNo)
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
if (mmInventory == null)
{
if (parm.ReceiptType == 1)
{
//库存为0或者不存在不允许出库
Context.Ado.RollbackTran();
return "库存不存在,禁止出库!";
}
var newInventory = new MmInventory()
{
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
SupplierCode = mmMaterial.SupplierCode,
SupplierName = mmMaterial.SupplierName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
BatchNo = parm.BatchNo,
CurrentQty = -delta,
Unit = parm.Unit,
LastUpdatedTime = null,
CreatedTime = nowDate,
};
Context.Insertable(newInventory).ExecuteCommand();
mmInventory = newInventory;
}
else
{
if (mmInventory.CurrentQty - delta < 0)
{
Context.Ado.RollbackTran();
return "库存不足,无法出库!";
}
mmInventory.CurrentQty -= delta;
Context
.Updateable(mmInventory)
.UpdateColumns(it => it.CurrentQty)
.ExecuteCommand();
}
var outboundNo = GenerateReceiptNo("CK");
MmRecordOutbound newRecord = new()
{
OutboundNo = outboundNo,
BatchNo = parm.BatchNo,
StoveCode = parm.StoveCode,
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
SupplierCode = mmMaterial.SupplierCode,
SupplierName = mmMaterial.SupplierName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
//TODO 待调整(可能涉及记录汇总)
Quantity = -delta,
Unit = parm.Unit,
CreatedTime = nowDate,
TransactionType = parm.TransactionType,
Workorder = parm.Workorder,
WorkorderRaw = parm.WorkorderRaw,
OrderNo = parm.OrderNo,
Remarks = parm.Remarks,
Operator = parm.Operator,
};
Context.Insertable(newRecord).ExecuteCommand();
Context.Ado.CommitTran();
return "ok";
}
else
{
mmInventory = Context
.Queryable<MmInventory>()
.Where(it => it.Id == parm.InventoryId)
.First();
if (mmInventory == null)
{
if (parm.ReceiptType == 1)
{
//库存为0或者不存在不允许出库
Context.Ado.RollbackTran();
return "库存不存在,禁止出库!";
}
var newInventory = new MmInventory()
{
MaterialCode = mmInventory.MaterialCode,
MaterialName = mmInventory.MaterialName,
SupplierCode = mmInventory.SupplierCode,
SupplierName = mmInventory.SupplierName,
LocationCode = mmInventory.LocationCode,
LocationName = mmInventory.LocationName,
WarehouseCode = mmInventory.WarehouseCode,
WarehouseName = mmInventory.WarehouseName,
BatchNo = parm.BatchNo,
CurrentQty = -delta,
Unit = parm.Unit,
LastUpdatedTime = null,
CreatedTime = nowDate,
};
Context.Insertable(newInventory).ExecuteCommand();
mmInventory = newInventory;
}
else
{
if (mmInventory.CurrentQty - delta < 0)
{
Context.Ado.RollbackTran();
return "库存不足,无法出库!";
}
mmInventory.CurrentQty -= delta;
Context
.Updateable(mmInventory)
.UpdateColumns(it => it.CurrentQty)
.ExecuteCommand();
}
var outboundNo = GenerateReceiptNo("CK");
MmRecordOutbound newRecord = new()
{
OutboundNo = outboundNo,
BatchNo = parm.BatchNo,
StoveCode = parm.StoveCode,
Operator = parm.Operator,
MaterialCode = mmInventory.MaterialCode,
MaterialName = mmInventory.MaterialName,
SupplierCode = mmInventory.SupplierCode,
SupplierName = mmInventory.SupplierName,
LocationCode = mmInventory.LocationCode,
LocationName = mmInventory.LocationName,
WarehouseCode = mmInventory.WarehouseCode,
WarehouseName = mmInventory.WarehouseName,
//TODO 待调整(可能涉及记录汇总)
Quantity = -delta,
Unit = parm.Unit,
CreatedTime = nowDate,
TransactionType = parm.TransactionType,
Workorder = parm.Workorder,
WorkorderRaw = parm.WorkorderRaw,
OrderNo = parm.OrderNo,
Remarks = parm.Remarks,
};
Context.Insertable(newRecord).ExecuteCommand();
Context.Ado.CommitTran();
return "ok";
}
}
catch (Exception ex)
{
// 回滚操作
Context.Ado.RollbackTran();
return ex.Message;
}
}
/// <summary>
/// 根据单据类型与数量计算有符号变动量(蓝单为正,红单为负)
/// </summary>
/// <param name="receiptType">1 表示蓝单(正),其它为红单(负)</param>
/// <param name="quantity">1 表示蓝单(正),其它为红单(负)</param>
private static decimal GetSignedQuantity(int receiptType, decimal quantity)
{
return receiptType == 1 ? Math.Abs(quantity) : -Math.Abs(quantity);
}
/// <summary>
/// 生成单据编号,格式:{prefix}{yyyyMMdd}-{nnn}
/// 例如RK20251225-001
/// </summary>
private string GenerateReceiptNo(string prefix)
{
var datePart = DateTime.Now.ToString("yyyyMMdd");
var baseNo = prefix + datePart + "-";
// 尝试从入库/出库表中获取当天最大的编号后缀
try
{
if (prefix == "RK")
{
var last = Context
.Queryable<MmRecordInbound>()
.Where(it => it.InboundNo.StartsWith(prefix + datePart))
.OrderByDescending(it => it.InboundNo)
.Select(it => it.InboundNo)
.First();
if (string.IsNullOrEmpty(last))
{
return baseNo + "001";
}
var suf = last.Substring((prefix + datePart).Length).TrimStart('-', '_');
if (int.TryParse(suf, out var n))
{
return baseNo + (n + 1).ToString("D3");
}
return baseNo + "001";
}
else
{
var last = Context
.Queryable<MmRecordOutbound>()
.Where(it => it.OutboundNo.StartsWith(prefix + datePart))
.OrderByDescending(it => it.OutboundNo)
.Select(it => it.OutboundNo)
.First();
if (string.IsNullOrEmpty(last))
{
return baseNo + "001";
}
var suf = last.Substring((prefix + datePart).Length).TrimStart('-', '_');
if (int.TryParse(suf, out var n))
{
return baseNo + (n + 1).ToString("D3");
}
return baseNo + "001";
}
}
catch
{
return baseNo + "001";
}
}
/// <summary>
/// 导入数据
/// </summary>
/// <param name="formFile"></param>
/// <returns></returns>
public ImportResultDto ImportInventory(IFormFile formFile, string username)
{
string message = "导入成功";
List<MmInventoryExcelDto> inventoryList = new();
using (var stream = formFile.OpenReadStream())
{
try
{
IWorkbook workbook = new XSSFWorkbook(stream);
ISheet sheet = workbook.GetSheetAt(0);
#region excel
// 遍历每一行
for (int row = 1; row <= sheet.LastRowNum; row++)
{
IRow currentRow = sheet.GetRow(row);
if (currentRow != null) // 确保行不为空
{
MmInventoryExcelDto inventory = new MmInventoryExcelDto();
//00 ID
NPOI.SS.UserModel.ICell currentCell_00 = currentRow.GetCell(0);
inventory.Id = (int)currentCell_00?.NumericCellValue;
//02物料编码
NPOI.SS.UserModel.ICell currentCell_01 = currentRow.GetCell(1);
inventory.MaterialCode = currentCell_01?.ToString();
if (
currentCell_01 == null
|| string.IsNullOrEmpty(inventory.MaterialCode)
)
{
message = $"物料编码不可为空,第{row + 1}行";
break;
}
//03批次号
NPOI.SS.UserModel.ICell currentCell_02 = currentRow.GetCell(2);
inventory.BatchNo = currentCell_02?.ToString() ?? string.Empty;
//04当前库存量
NPOI.SS.UserModel.ICell currentCell_03 = currentRow.GetCell(3);
string currentQtyStr = currentCell_03?.ToString();
if (currentCell_03 == null || string.IsNullOrWhiteSpace(currentQtyStr))
{
message = $"当前库存量不可为空,第{row + 1}行";
break;
}
// 尝试转换为decimal
if (!decimal.TryParse(currentQtyStr, out decimal currentQty))
{
message = $"当前库存量格式错误(必须是数字),第{row + 1}行";
break;
}
// 验证数值范围(可根据业务需求调整)
//if (currentQty < 0)
//{
// message = $"当前库存量不能为负数,第{row + 1}行";
// break;
//}
inventory.CurrentQty = currentQty;
//05 仓库编码
NPOI.SS.UserModel.ICell currentCell_04 = currentRow.GetCell(4);
inventory.WarehouseCode = currentCell_04?.ToString();
if (
currentCell_04 == null
|| string.IsNullOrEmpty(inventory.WarehouseCode)
)
{
message = $"仓库编码不可为空,第{row + 1}行";
break;
}
//06 仓库名称
NPOI.SS.UserModel.ICell currentCell_05 = currentRow.GetCell(5);
inventory.WarehouseName = currentCell_05?.ToString();
if (
currentCell_05 == null
|| string.IsNullOrEmpty(inventory.WarehouseName)
)
{
message = $"仓库名称不可为空,第{row + 1}行";
break;
}
//07 库位编码
NPOI.SS.UserModel.ICell currentCell_06 = currentRow.GetCell(6);
inventory.LocationCode = currentCell_06?.ToString();
if (
currentCell_06 == null
|| string.IsNullOrEmpty(inventory.LocationCode)
)
{
message = $"仓库编码不可为空,第{row + 1}行";
break;
}
//08 库位名称
NPOI.SS.UserModel.ICell currentCell_07 = currentRow.GetCell(7);
inventory.LocationName = currentCell_07?.ToString();
if (
currentCell_07 == null
|| string.IsNullOrEmpty(inventory.LocationName)
)
{
message = $"库位名称不可为空,第{row + 1}行";
break;
}
//09 创建时间
NPOI.SS.UserModel.ICell currentCell_08 = currentRow.GetCell(8);
inventory.CreatedTime = currentCell_08?.DateCellValue ?? DateTime.Now;
inventoryList.Add(inventory);
}
}
#endregion
}
catch (Exception ex)
{
return null;
}
}
// TODO 3.调用SplitInsert方法实现导入操作,注意主键列的配置(建议优化为ID相同则修改不同则新增)
var x = Context
.Storageable(inventoryList)
//.SplitInsert(it => !it.Any())
//.WhereColumns(it => it.Id) //如果不是主键可以这样实现多字段it=>new{it.x1,it.x2}
.ToStorage();
var result = x.AsInsertable.ExecuteCommand();
var result2 = x.AsUpdateable.IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommand(); //插入可插入部分;
var importResult = new ImportResultDto
{
Message = message,
Inserted = x.InsertList.Count,
Updated = x.UpdateList.Count,
ErrorCount = x.ErrorList.Count,
IgnoredCount = x.IgnoreList.Count,
Deleted = x.DeleteList.Count,
Total = x.TotalList.Count,
};
//输出统计
Console.WriteLine(importResult);
// 4.收集错误与忽略信息返回导入结果ImportResultDto 提示需要修改IServer相关返回格式
foreach (var item in x.ErrorList)
{
importResult.Errors.Add(
new ImportErrorDto
{
MaterialCode = item.Item.MaterialCode,
Message = item.StorageMessage,
}
);
}
foreach (var item in x.IgnoreList)
{
importResult.Ignored.Add(
new ImportErrorDto
{
MaterialCode = item.Item.MaterialCode,
Message = item.StorageMessage,
}
);
}
return importResult;
}
/// <summary>
/// 导出物料表列表
/// </summary>
/// <returns></returns>
public PagedInfo<MmInventoryExcelDto> SelectInventoryList(
MmInventoryQueryDto inventory,
PagerInfo pager
)
{
// Use the same predicate builder as GetList to support consistent filtering
var predicate = QueryExp(inventory);
var query = Queryable()
.Where(predicate.ToExpression())
.Select(it => new MmInventoryExcelDto
{
Id = it.Id,
MaterialCode = it.MaterialCode,
BatchNo = it.BatchNo,
CurrentQty = it.CurrentQty,
WarehouseCode = it.WarehouseCode,
WarehouseName = it.WarehouseName,
LocationCode = it.LocationCode,
LocationName = it.LocationName,
CreatedTime = it.CreatedTime,
});
return query.ToPage(pager);
}
/// <summary>
/// 查询出/入记录列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<MmInventoryRecordDto> GetInOrOutRecord(MmInventoryRecordQueryDto parm)
{
PagedInfo<MmInventoryRecordDto> result = new PagedInfo<MmInventoryRecordDto>();
// 处理日期
if (parm.StartTime != null && parm.StartTime.Value > DateTime.MinValue)
{
parm.StartTime = DOANConvertDate.ConvertLocalDate(parm.StartTime.Value);
}
if (parm.EndTime != null && parm.EndTime.Value > DateTime.MinValue)
{
parm.EndTime = DOANConvertDate.ConvertLocalDate(parm.EndTime.Value);
}
// 查询入库记录
if (parm.SearchType == 1)
{
result = Context
.Queryable<MmRecordInbound>()
.WhereIF(
parm.StartTime != null && parm.StartTime.Value > DateTime.MinValue,
it => it.CreatedTime >= parm.StartTime
)
.WhereIF(
parm.EndTime != null && parm.EndTime.Value > DateTime.MinValue,
it => it.CreatedTime <= parm.EndTime
)
.WhereIF(
!string.IsNullOrEmpty(parm.TransactionType),
it => it.TransactionType == parm.TransactionType
)
.Where(it => it.MaterialCode == parm.MaterialCode)
.Where(it => it.SupplierCode == parm.SupplierCode)
.Where(it => it.LocationCode == parm.LocationCode)
.Where(it => it.BatchNo == parm.BatchNo)
.Select(it => new MmInventoryRecordDto()
{
Id = it.Id,
InboundNo = it.InboundNo,
MaterialCode = it.MaterialCode,
MaterialName = it.MaterialName,
SupplierCode = it.SupplierCode,
SupplierName = it.SupplierName,
LocationCode = it.LocationCode,
LocationName = it.LocationName,
WarehouseCode = it.WarehouseCode,
WarehouseName = it.WarehouseName,
BatchNo = it.BatchNo,
Quantity = it.Quantity,
TransactionType = it.TransactionType,
Operator = it.Operator,
CreatedTime = it.CreatedTime,
Workorder = it.Workorder,
WorkorderRaw = it.WorkorderRaw,
StoveCode = it.StoveCode,
Remarks = it.Remarks,
})
.OrderByDescending(it => it.CreatedTime)
.ToPage(parm);
}
// 查询出库记录
else if (parm.SearchType == 2)
{
result = Context
.Queryable<MmRecordOutbound>()
.WhereIF(
parm.StartTime != null && parm.StartTime.Value > DateTime.MinValue,
it => it.CreatedTime >= parm.StartTime
)
.WhereIF(
parm.EndTime != null && parm.EndTime.Value > DateTime.MinValue,
it => it.CreatedTime <= parm.EndTime
)
.WhereIF(
!string.IsNullOrEmpty(parm.TransactionType),
it => it.TransactionType == parm.TransactionType
)
.Where(it => it.MaterialCode == parm.MaterialCode)
//.Where(it => it.SupplierCode == parm.SupplierCode)
.Where(it => it.LocationCode == parm.LocationCode)
.Where(it => it.BatchNo == parm.BatchNo)
.Select(it => new MmInventoryRecordDto()
{
Id = it.Id,
OutboundNo = it.OutboundNo,
MaterialCode = it.MaterialCode,
MaterialName = it.MaterialName,
LocationCode = it.LocationCode,
LocationName = it.LocationName,
WarehouseCode = it.WarehouseCode,
WarehouseName = it.WarehouseName,
BatchNo = it.BatchNo,
Quantity = it.Quantity,
TransactionType = it.TransactionType,
Operator = it.Operator,
CreatedTime = it.CreatedTime,
Workorder = it.Workorder,
WorkorderRaw = it.WorkorderRaw,
OrderNo = it.OrderNo,
Remarks = it.Remarks,
})
.OrderByDescending(it => it.CreatedTime)
.ToPage(parm);
}
return result;
}
/// <summary>
/// 撤销单据,传入单据类型(1-入库单2-出库单)和ID
/// </summary>
/// <param name="parm"></param>
/// <returns>返回ok即为成功其他都是不成功</returns>
/// <exception cref="NotImplementedException"></exception>
public string RevokeReceipt(MmInventoryRevokeDto parm)
{
try
{
int _type = parm.Type;
int _id = parm.Id;
if (_type < -1 || _id < -1)
{
return $"传入参数有误,请检查:type-{_type},id-{_id}";
}
// type == 1 入库单
if (_type == 1)
{
MmRecordInbound recordInbound = Context
.Queryable<MmRecordInbound>()
.Where(it => it.Id == _id)
.First();
if (recordInbound == null)
{
return $"无此入库记录,请检查:type-{_type},id-{_id}";
}
if (recordInbound.Remarks == "已撤销")
{
return $"此记录已撤销过,不可重复撤销";
}
//做入库红单
InboundReceiptDto revokeRecepitDto = new()
{
ReceiptType = 2,
MaterialCode = recordInbound.MaterialCode,
BatchNo = recordInbound.BatchNo,
LocationCode = recordInbound.LocationCode,
WarehouseCode = recordInbound.WarehouseCode,
SupplierCode = recordInbound.SupplierCode,
StoveCode = recordInbound.StoveCode,
Workorder = recordInbound.Workorder,
WorkorderRaw = recordInbound.WorkorderRaw,
Operator = recordInbound.Operator,
Quantity = recordInbound.Quantity,
TransactionType = "入库红单",
Remarks = $"撤销操作,入库单号:{recordInbound.InboundNo}",
};
string result = CreateInboundReceipt(revokeRecepitDto);
if (result != "ok")
{
return result;
}
// 如果是成品入库则还要减少工单记录数量
Context.Ado.BeginTran();
if (recordInbound.TransactionType == "生产入库")
{
var workorderInfo = Context
.Queryable<ProWorkorder>()
.Where(it => it.Workorder == recordInbound.Workorder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单不存在";
}
// 数量调整
workorderInfo.ProductNum -= Math.Abs((int)recordInbound.Quantity);
if (workorderInfo.ProductNum < 0)
{
workorderInfo.ProductNum = 0;
}
Context.Updateable(workorderInfo).ExecuteCommand();
}
recordInbound.Remarks = "已撤销";
Context.Updateable(recordInbound).ExecuteCommand();
Context.Ado.CommitTran();
return result;
}
else
{
MmRecordOutbound recordOutbound = Context
.Queryable<MmRecordOutbound>()
.Where(it => it.Id == _id)
.First();
if (recordOutbound == null)
{
return $"无此出库记录,请检查:type-{_type},id-{_id}";
}
if (recordOutbound.Remarks == "已撤销")
{
return $"此记录已撤销过,不可重复撤销";
}
//做出库红单
OutboundReceiptDto revokeRecepitDto = new()
{
ReceiptType = 2,
MaterialCode = recordOutbound.MaterialCode,
BatchNo = recordOutbound.BatchNo,
LocationCode = recordOutbound.LocationCode,
WarehouseCode = recordOutbound.WarehouseCode,
OrderNo = recordOutbound.OrderNo,
Workorder = recordOutbound.Workorder,
WorkorderRaw = recordOutbound.WorkorderRaw,
Operator = recordOutbound.Operator,
Quantity = recordOutbound.Quantity,
TransactionType = "出库红单",
Remarks = $"撤销操作,出库单号:{recordOutbound.OutboundNo}",
};
string result = CreateOutboundReceipt(revokeRecepitDto);
if (result != "ok")
{
return result;
}
Context.Ado.BeginTran();
// 如果是根据工单领料撤销,还需要调整领料记录
if (
recordOutbound.TransactionType == "领料出库"
&& !string.IsNullOrEmpty(recordOutbound.WorkorderRaw)
)
{
var workorderInfo = Context
.Queryable<ProWorkorder>()
.Where(it => it.Workorder == recordOutbound.WorkorderRaw)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单不存在";
}
workorderInfo.ShipmentNum -= Math.Abs((int)recordOutbound.Quantity);
if (workorderInfo.ShipmentNum < 0)
{
workorderInfo.ShipmentNum = 0;
}
Context
.Updateable(workorderInfo)
.UpdateColumns(it => new { it.ShipmentNum })
.ExecuteCommand();
}
// 如果是出货则还要减少出货单库存和工单出货数量
if (recordOutbound.TransactionType == "出货出库")
{
var workorderInfo = Context
.Queryable<ProWorkorder>()
.Where(it => it.Workorder == recordOutbound.Workorder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单不存在";
}
// 判断订单号是否存在
var orderPurchase = Context
.Queryable<OrderPurchase>()
.Where(o => o.OrderNoMes == workorderInfo.CustomerOrder)
.First();
if (orderPurchase == null)
{
Context.Ado.RollbackTran();
return "订单号不存在";
}
// 数量调整
workorderInfo.ShipmentNum -= Math.Abs((int)recordOutbound.Quantity);
if (workorderInfo.ShipmentNum < 0)
{
workorderInfo.ShipmentNum = 0;
}
workorderInfo.CustomerOrder = string.Empty;
Context.Updateable(workorderInfo).ExecuteCommand();
// 修改采购订单是否完成
//int newQuantity = Context
// .Queryable<ProWorkorder>()
// .Where(it => it.CustomerOrder == orderPurchase.OrderNoMes)
// .Sum(it => it.ShipmentNum);
//orderPurchase.DeliveryQuantity = newQuantity;
orderPurchase.DeliveryQuantity -= Math.Abs((int)recordOutbound.Quantity);
if (orderPurchase.DeliveryQuantity > orderPurchase.DemandQuantity)
{
// 订单超额了
Context.Ado.RollbackTran();
return "订单超额了";
}
if (orderPurchase.DeliveryQuantity == orderPurchase.DemandQuantity)
{
orderPurchase.Orderindicator = 1;
}
else
{
orderPurchase.Orderindicator = -1;
}
int res = Context.Updateable(orderPurchase).ExecuteCommand();
}
recordOutbound.Remarks = "已撤销";
Context.Updateable(recordOutbound).ExecuteCommand();
Context.Ado.CommitTran();
return result;
}
}
catch (Exception e)
{
Context.Ado.RollbackTran();
return e.Message;
}
}
/// <summary>
/// 出货操作 成功返回ok
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public string Shipment(ShipmentDto parm)
{
try
{
DateTime nowDate = DateTime.Now;
// 计算有符号变动量(蓝单为正,红单为负)
decimal delta = GetSignedQuantity(parm.ReceiptType, parm.Quantity);
// 校验物料和库位
var mmMaterial = Context
.Queryable<MmMaterial>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.First();
if (mmMaterial == null)
return "物料不存在!";
var mmLocation = Context
.Queryable<MmLocation>()
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
if (mmLocation == null)
return "仓库编码或库位编码不存在!";
// 启用事务
Context.Ado.BeginTran();
// 订单关联处理
if (!string.IsNullOrEmpty(parm.CustomerOrder))
{
// 判断订单号是否存在
var orderPurchase = Context
.Queryable<OrderPurchase>()
.Where(o => o.OrderNoMes == parm.CustomerOrder)
.First();
if (orderPurchase == null)
{
Context.Ado.RollbackTran();
return "订单号不存在";
}
// 判断工单是否存在
if (!string.IsNullOrEmpty(parm.Workorder))
{
var workorderInfo = Context
.Queryable<ProWorkorder>()
.Where(it => it.Workorder == parm.Workorder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单不存在";
}
// 判断工单主体型号和订单物料号是否匹配
if (workorderInfo.productionCode != orderPurchase.MaterialCode)
{
Context.Ado.RollbackTran();
return "工单主体型号和订单物料号不匹配";
}
}
}
// 获取现有库存
var mmInventory = Context
.Queryable<MmInventory>()
.Where(it => it.MaterialCode == parm.MaterialCode)
.Where(it => it.BatchNo == parm.BatchNo)
.Where(it => it.WarehouseCode == parm.WarehouseCode)
.Where(it => it.LocationCode == parm.LocationCode)
.First();
// 库存检查
if (mmInventory == null)
{
if (parm.ReceiptType == 1)
{
Context.Ado.RollbackTran();
return "库存不存在,禁止出货!";
}
// 红单处理
var newInventory = new MmInventory()
{
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
SupplierCode = mmMaterial.SupplierCode,
SupplierName = mmMaterial.SupplierName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
BatchNo = parm.BatchNo,
CurrentQty = -delta,
Unit = mmMaterial.Unit,
LastUpdatedTime = null,
CreatedTime = nowDate,
};
Context.Insertable(newInventory).ExecuteCommand();
}
else
{
if (mmInventory.CurrentQty - delta < 0)
{
Context.Ado.RollbackTran();
return "库存不足,无法出货!";
}
// 更新库存
mmInventory.CurrentQty -= delta;
Context
.Updateable(mmInventory)
.UpdateColumns(it => it.CurrentQty)
.ExecuteCommand();
}
// 生成出货单号
var shipmentNo = GenerateReceiptNo("CH");
// 创建出货记录
MmRecordOutbound newRecord = new()
{
OutboundNo = shipmentNo,
BatchNo = parm.BatchNo,
Operator = parm.Operator,
MaterialCode = mmMaterial.MaterialCode,
MaterialName = mmMaterial.MaterialName,
LocationCode = mmLocation.LocationCode,
LocationName = mmLocation.LocationName,
WarehouseCode = mmLocation.WarehouseCode,
WarehouseName = mmLocation.WarehouseName,
Quantity = -delta,
Unit = mmMaterial.Unit,
CreatedTime = nowDate,
TransactionType = parm.TransactionType,
Workorder = parm.Workorder,
WorkorderRaw = parm.WorkorderRaw,
OrderNo = parm.CustomerOrder,
Remarks = parm.Remarks,
};
Context.Insertable(newRecord).ExecuteCommand();
// 更新工单和订单信息
if (
!string.IsNullOrEmpty(parm.CustomerOrder)
&& !string.IsNullOrEmpty(parm.Workorder)
)
{
// 获取当前工单信息
var workorderInfo = Context
.Queryable<ProWorkorder>()
.Where(it => it.Workorder == parm.Workorder)
.First();
// 计算累计出货数量使用delta值考虑单据类型的影响
int currentShipmentNum = workorderInfo.ShipmentNum;
int newShipmentNum = currentShipmentNum + (int)delta;
// 验证出货数量有效性
if (newShipmentNum < 0)
{
Context.Ado.RollbackTran();
return "累计出货数量不能为负数";
}
// 更新工单信息
Context
.Updateable<ProWorkorder>()
.Where(it => it.Workorder == parm.Workorder)
.SetColumns(it => it.ShipmentNum == newShipmentNum)
.SetColumns(it => it.CustomerOrder == parm.CustomerOrder)
.ExecuteCommand();
// 修改采购订单信息
var orderPurchase = Context
.Queryable<OrderPurchase>()
.Where(o => o.OrderNoMes == parm.CustomerOrder)
.First();
if (orderPurchase != null)
{
int newQuantity = Context
.Queryable<ProWorkorder>()
.Where(it => it.CustomerOrder == parm.CustomerOrder)
.Sum(it => it.ShipmentNum);
orderPurchase.DeliveryQuantity = newQuantity;
if (orderPurchase.DeliveryQuantity > orderPurchase.DemandQuantity)
{
Context.Ado.RollbackTran();
return "交货数量超过订单需求数量";
}
if (orderPurchase.DeliveryQuantity == orderPurchase.DemandQuantity)
{
orderPurchase.Orderindicator = 1;
}
else
{
orderPurchase.Orderindicator = -1;
}
Context.Updateable(orderPurchase).ExecuteCommand();
}
}
// 提交事务
Context.Ado.CommitTran();
return "ok";
}
catch (Exception ex)
{
// 回滚操作
Context.Ado.RollbackTran();
return ex.Message;
}
}
}
}