Files
WMS-Api/src/WMS.Web.Domain/Services/InStockService.cs
tongfei 3f357c6bde 优化
2024-03-12 14:18:39 +08:00

847 lines
42 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 AutoMapper;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using WMS.Web.Core.Dto;
using WMS.Web.Core.Dto.ChangeBoxRecord;
using WMS.Web.Core.Dto.Erp;
using WMS.Web.Core.Dto.Erp.Org;
using WMS.Web.Core.Dto.InStock;
using WMS.Web.Core.Dto.InStockTask;
using WMS.Web.Core.Dto.Inventory;
using WMS.Web.Core.Dto.Login;
using WMS.Web.Core.Internal.Results;
using WMS.Web.Domain.Entitys;
using WMS.Web.Domain.Infrastructure;
using WMS.Web.Domain.IService;
using WMS.Web.Domain.IService.Public;
using WMS.Web.Domain.Mappers;
using WMS.Web.Domain.Values;
using WMS.Web.Domain.Values.Erp;
namespace WMS.Web.Domain.Services
{
/// <summary>
/// 入库单服务
/// </summary>
public class InStockService : IInStockService
{
private readonly IMapper _mapper;
private readonly IErpService _erpService;
private readonly ILoginService _loginService;
private readonly ISerialNumberService _serialNumberService;
private readonly ISerialNumbersRepositories _serialNumbersRepositories;
private readonly IInStockTaskBoxRepositories _inStockTaskBoxRepositories;
private readonly IChangeMoveBoxService _changeMoveBoxService;
private readonly IBoxRepositories _boxRepositories;
private readonly IBoxInventoryService _boxInventoryService;
private readonly IBasicsRepositories _basicsRepositories;
private readonly IInStockRepositories _inStockRepositories;
private readonly IInStockTaskRepositories _inStockTaskRepositories;
private readonly IErpBasicDataExtendService _erpBasicDataExtendService;
private readonly IBoxInventoryRepositories _boxInventoryRepositories;
private readonly ILogger<InStockService> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public InStockService(IMapper mapper, ISerialNumbersRepositories serialNumbersRepositories, IErpService erpService, IBoxInventoryService boxInventoryService, ISerialNumberService serialNumberService, ILoginService loginService, IBoxRepositories boxRepositories,
IBasicsRepositories basicsRepositories, IErpBasicDataExtendService erpBasicDataExtendService, IChangeMoveBoxService changeMoveBoxService, IInStockTaskBoxRepositories inStockTaskBoxRepositories,
IInStockRepositories inStockRepositories, IInStockTaskRepositories inStockTaskRepositories, IBoxInventoryRepositories boxInventoryRepositories, ILogger<InStockService> logger, IServiceScopeFactory serviceScopeFactory)
{
_logger = logger;
_mapper = mapper;
_erpService = erpService;
_loginService = loginService;
_serviceScopeFactory = serviceScopeFactory;
_boxInventoryService = boxInventoryService;
_serialNumberService = serialNumberService;
_boxRepositories = boxRepositories;
_changeMoveBoxService = changeMoveBoxService;
_basicsRepositories = basicsRepositories;
_inStockRepositories = inStockRepositories;
_inStockTaskBoxRepositories = inStockTaskBoxRepositories;
_inStockTaskRepositories = inStockTaskRepositories;
_erpBasicDataExtendService = erpBasicDataExtendService;
_serialNumbersRepositories = serialNumbersRepositories;
_boxInventoryRepositories = boxInventoryRepositories;
}
/// <summary>
/// 同步-金蝶
/// </summary>
/// <param name="dto"></param>
/// <param name="loginInfo"></param>
/// <returns></returns>
public Task<Result> Sync(OperateRequest dto, LoginInDto loginInfo, bool isRepeatSync = true)
{
var list = _inStockRepositories.GetList(dto.Ids).GetAwaiter().GetResult();
var isSuccess = true;
if (isRepeatSync)
{
list = list.Where(w => w.SuccessSync == SyncStatus.Fail).ToList();
list.ForEach(f => f.RepeatSync());
isSuccess = _inStockRepositories.UpdateRange(list, true).GetAwaiter().GetResult();
}
Task.Run(async () =>
{
foreach (var entity in list)
{
var res = await this.PurchaseInStock(entity, loginInfo);
if (!res.IsSuccess)
_logger.LogError($"入库单同步失败:{res.Message}");
}
});
return Task.FromResult(Result.ReSuccess());
}
/// <summary>
/// 收货
/// </summary>
/// <param name="dto"></param>
/// <param name="loginInfo"></param>
/// <returns></returns>
public async Task<Result> Receive(UpdateInStockTaskRequest dto, LoginInDto loginInfo)
{
IDbContextTransaction _transaction = _basicsRepositories.GetTransaction();
bool isRollback = false;
bool isTransaction = false;
var result = await this.Receive(dto, loginInfo.UserInfo.StaffId, isTransaction);
if (!result.IsSuccess) isRollback = true;
//提交事务
var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction);
if (!isSuccess)
return Result.ReFailure(ResultCodes.DateWriteError);
return Result.ReSuccess();
}
/// <summary>
/// 上架-采购订单
/// </summary>
/// <param name="instock"></param>
/// <param name="loginInfo"></param>
/// <returns></returns>
public async Task<Result> Shelf(PurchaseShelfRequest instock, LoginInDto loginInfo)
{
IDbContextTransaction _transaction = _basicsRepositories.GetTransaction();
bool isRollback = false;
bool isTransaction = false;
//1.添加入库单同步金蝶在save方法里面进行
var save_result = await this.ShelfSave(instock, InstockType.Purchase, loginInfo, isTransaction);
if (!save_result.IsSuccess) isRollback = true;
//实体
var entity = save_result.Data;
//提交事务
var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction);
if (!isSuccess)
return Result.ReFailure(ResultCodes.DateWriteError);
//同步金蝶
if (entity.Type == InstockType.Purchase)
{
OperateRequest oRequest = new OperateRequest();
oRequest.Ids.Add(entity.Id);
await Sync(oRequest, loginInfo,false);
}
return Result.ReSuccess();
}
/// <summary>
/// 非采购单上架
/// </summary>
/// <param name="dto"></param>
/// <param name="loginInDto"></param>
/// <returns></returns>
public async Task<Result> ShelfNoPurchase(NoPurchaseShelfRequest dto, LoginInDto loginInDto)
{
_logger.LogInformation($"非采购入库:{JsonConvert.SerializeObject(dto)} 操作人:{loginInDto.UserInfo.StaffId+loginInDto.UserInfo.Nickname}");
IDbContextTransaction _transaction = _basicsRepositories.GetTransaction();
bool isRollback = false;
bool isTransaction = false;
//保存非采购上架的数据
var shelfSave_result = await this.ShelfNoPurchaseSave(dto, loginInDto, isTransaction);
if (!shelfSave_result.IsSuccess) isRollback = true;
//提交事务
var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction);
if (!isSuccess)
return shelfSave_result;
return Result.ReSuccess();
}
/// <summary>
/// 获取任务单:根据箱号信息
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<Result<BoxInStockTaskDto>> GetInfoByBox(BoxInStockTaskRequest dto)
{
//1.1.找到箱对应的物料信息
var box = await _boxRepositories.GetByNo(dto.BoxBillNo);
if (box == null)
return Result<BoxInStockTaskDto>.ReFailure(ResultCodes.BoxNoData);
//1.获取物料集合
var materials_result = await _erpService.BillQueryForMaterial();
var materials = new List<ErpMaterialDto>();
if (materials_result.IsSuccess)
materials = materials_result.Data.ToList();
//1.先判断:箱号已经绑定了入库任务单中;备注:业务说法就是箱是否收货了
var tast_box = await _inStockTaskBoxRepositories.GetBy(dto.BoxBillNo);
if (tast_box == null)
return Result<BoxInStockTaskDto>.ReFailure(ResultCodes.Box_NoBind_Task_Data);
//2.1判断箱是否上架过了
var isExist = await _boxInventoryRepositories.IsExist(box.Id);
if (isExist)
return Result<BoxInStockTaskDto>.ReFailure(ResultCodes.BoxIsTrueShelf);
//1.2找到任务单
var tast = await _inStockTaskRepositories.Get(tast_box.TaskId);
if (tast == null)
return Result<BoxInStockTaskDto>.ReFailure(ResultCodes.InStockTaskNoData);
//1.2.1判断箱子绑定的物料明细数据的仓库,是不是用户所选的仓库;不是则提示:箱号仓库不对
foreach (var item in tast_box.Details)
{
var tast_det = tast.Details.Where(t => t.ErpDetailId == item.ErpDetailId).FirstOrDefault();
if (tast_det != null && tast_det.StockCode != dto.StockCode)
return Result<BoxInStockTaskDto>.ReFailure(ResultCodes.BoxBindTaskDetailsIdNotChoose);
}
//3.组装返回数据
var result = new BoxInStockTaskDto();
result.SourceBillNo = tast.SourceBillNo;
result.TaskId = tast.Id;
result.BoxId = box.Id;
//获取:当前箱的与收货绑定的信息
foreach (var item in tast_box.Details)
{
var current_task_det = tast.Details.Where(x => x.ErpDetailId == item.ErpDetailId).FirstOrDefault();
if (current_task_det != null)
{
//3.2映射返回明细对象
var box_task_detail = new BoxDetailsInStockTaskDto();
box_task_detail.SupplierId = current_task_det.SupplierId;
box_task_detail.OrgId = current_task_det.OrgId;
box_task_detail.ReceiveQty = current_task_det.ReceiveQty;
box_task_detail.AccruedQty = current_task_det.AccruedQty;
box_task_detail.ErpDetailId = item.ErpDetailId;
box_task_detail.MaterialId = item.MaterialId;
box_task_detail.BoxMaterialQty = item.ReceiveQty;
box_task_detail.MaterialName = _erpBasicDataExtendService.GetMaterialName(materials, item.MaterialId);
box_task_detail.MaterialNumber = _erpBasicDataExtendService.GetMaterialNumber(materials, item.MaterialId);
box_task_detail.Specifications = _erpBasicDataExtendService.GetMaterialSpecifications(materials, item.MaterialId);
result.Details.Add(box_task_detail);
}
}
return Result<BoxInStockTaskDto>.ReSuccess(result);
}
/// <summary>
/// 采购上架-保存
/// </summary>
/// <param name="dto"></param>
/// <param name="staffId"></param>
/// <param name="isTransaction"></param>
/// <returns></returns>
private async Task<Result<InStock>> ShelfSave(PurchaseShelfRequest dto, InstockType type, LoginInDto loginInfo, bool isTransaction = true)
{
//1.获取来源单
var taskIds = dto.Details.GroupBy(x => x.TaskId).Select(x => x.Key).ToList();
var tasks = await _inStockTaskRepositories.GetList(taskIds);
if (tasks == null || tasks.Count==0)
return Result<InStock>.ReFailure(ResultCodes.SourceBillNoDateError);
////1.1.2判断上架数量不能超过应入库数量
//var dtoTotalDetails = dto.Details.GroupBy(x => new { x.ErpDetailId }).Select(x => new { ErpDetailId = x.Key.ErpDetailId, Qty = x.Sum(t => t.Qty) }).ToList();
//foreach (var item in tasks.SelectMany(x => x.Details).ToList())
//{
// var current_det = dtoTotalDetails.Where(x => x.ErpDetailId == item.ErpDetailId).FirstOrDefault();
// if (current_det != null && current_det.ErpDetailId == item.ErpDetailId && (item.AccruedQty - item.RealityQty) < current_det.Qty)
// return Result<InStock>.ReFailure(ResultCodes.ShelfNoPurchaseSave_Qty_Error);
//}
// 组织集合
var orgs = new List<ErpOrgDto>();
var orgs_result = await _erpService.BillQueryForOrg();
if (orgs_result.IsSuccess)
orgs = orgs_result.Data.ToList();
var currentOrg = orgs.Where(x => x.Number == dto.OrgCode).FirstOrDefault();
var entity = new InStock();
entity.Type = type;
entity.OrgId = currentOrg == null ? 0 : currentOrg.Id;
entity.StockCode = dto.StockCode;
entity.OrgCode = dto.OrgCode;
entity.SubStockId = dto.SubStockId;
entity.Method = InventoryInOutMethod.Box;
entity.Details = _mapper.Map<List<InStockDetails>>(dto.Details);
entity.Create(loginInfo.UserInfo.StaffId);
//组装erp明细
entity.ErpDetails = dto.Details.GroupBy(x => new { x.ErpDetailId, x.MaterialId, x.SourceBillNo })
.Select(x => new InStockErpDetails
{
ErpDetailId = x.Key.ErpDetailId,
MaterialId = x.Key.MaterialId,
SourceBillNo = x.Key.SourceBillNo,
Qty = x.Sum(t => t.Qty)
}).ToList();
//序列号集:箱里面的
var serialNumbers = await _serialNumbersRepositories.GetEntityListByBoxIds(dto.Details.GroupBy(x => x.BoxId).Select(x => x.Key).ToList());
//赋值序列号
entity.Details.ForEach(x =>
{
var current_box_serNums = serialNumbers.Where(t => t.BoxId == x.BoxId).ToList();
if (current_box_serNums != null)
{
var current_box_mat_serNums = current_box_serNums.Where(t => t.MaterialId == x.MaterialId).Select(t => t.SerialNumber).ToList();
x.SerialNumbers.AddRange(current_box_mat_serNums);
}
});
entity = await _inStockRepositories.Add(entity, isTransaction);
if (entity == null)
return Result<InStock>.ReFailure(ResultCodes.DateWriteError);
//处理添加入库汇总明细
var totalDetails = dto.Details.GroupBy(x => new { x.TaskId, x.SourceBillNo, x.SupplierId, x.MaterialId })
.Select(x => new InStockTotalDetails
{
InStockId = entity.Id,
TaskId = x.Key.TaskId,
SourceBillNo = x.Key.SourceBillNo,
SupplierId = x.Key.SupplierId,
MaterialId = x.Key.MaterialId,
Qty = x.Sum(t => t.Qty),
SerialNumbers = x.SelectMany(t => t.SerialNumbers).ToList()
}).ToList();
var isSuccess = await _inStockRepositories.AddRangeTotalDetails(totalDetails, isTransaction);
if (!isSuccess)
return Result<InStock>.ReFailure(ResultCodes.DateWriteError);
//反写任务单的已交数量
if (tasks != null && tasks.Count != 0)
{
foreach (var task in tasks)
{
task.Details.ForEach(x =>
{
var current_entityDets = dto.Details.Where(t => t.ErpDetailId == x.ErpDetailId && t.MaterialId==x.MaterialId).ToList();
if (current_entityDets != null && current_entityDets.Count != 0 && x.ErpDetailId == current_entityDets.FirstOrDefault().ErpDetailId)
{
var current_entityDet_matQty = current_entityDets.Sum(x => x.Qty);
x.RealityQty = x.RealityQty + current_entityDet_matQty;
}
});
task.Shelf(loginInfo.UserInfo.StaffId);
}
isSuccess = await _inStockTaskRepositories.UpdateRange(tasks, isTransaction);
if (!isSuccess)
return Result<InStock>.ReFailure(ResultCodes.DateWriteError);
}
//保存成功后:序列号跟踪流程添加
var serialNumber_result = await _serialNumberService.InStock(entity, loginInfo, isTransaction);
if (!serialNumber_result.IsSuccess)
return Result<InStock >.ReFailure(serialNumber_result);
//箱库存变动
var boxInventoryResult = await _boxInventoryService.GenerateInStockBox(entity, isTransaction);
if (!boxInventoryResult.IsSuccess)
return Result<InStock>.ReFailure(boxInventoryResult);
return Result<InStock>.ReSuccess(entity);
}
/// <summary>
/// 非采购上架-保存
/// </summary>
/// <param name="dto"></param>
/// <param name="loginInfo"></param>
/// <param name="isTransaction"></param>
/// <returns></returns>
private async Task<Result> ShelfNoPurchaseSave(NoPurchaseShelfRequest dto, LoginInDto loginInfo, bool isTransaction = true)
{
//1.1过滤的明细0数量入库的明细要过滤掉
dto.Boxs.ForEach(x =>
{
x.Details.RemoveAll(t => t.Qty == 0);
});
//1.获取来源单
var task = await _inStockTaskRepositories.Get(dto.TaskId);
if (task == null)
return Result.ReFailure(ResultCodes.SourceBillNoDateError);
//1.1.2判断上架数量不能超过应入库数量
var dtoDetails = dto.Boxs.SelectMany(x => x.Details).ToList();
var dtoTotalDetails = dtoDetails.GroupBy(x => new { x.ErpDetailId }).Select(x => new { ErpDetailId = x.Key.ErpDetailId, Qty = x.Sum(t => t.Qty) }).ToList();
foreach (var item in task.Details)
{
var current_det = dtoTotalDetails.Where(x => x.ErpDetailId == item.ErpDetailId).FirstOrDefault();
if (current_det != null && current_det.ErpDetailId == item.ErpDetailId && (item.AccruedQty - item.RealityQty) < current_det.Qty)
return Result.ReFailure(ResultCodes.ShelfNoPurchaseSave_Qty_Error);
}
//2.生成:入库单
var entity = new InStock();
entity.Type = task.Type;
entity.OrgId = task.Details.Select(x => x.OrgId).FirstOrDefault();
entity.StockCode = dto.StockCode;
entity.OrgCode = dto.OrgCode;
entity.SubStockId = dto.SubStockId;
entity.Method = dto.ShelfMethod == (int)ShelfMethod.Box ? InventoryInOutMethod.Box : InventoryInOutMethod.Product;
entity.Details = new List<InStockDetails>();
var temps = new List<InStockDetails>();
//3.遍历box信息,并拼装入库单明细
foreach (var box in dto.Boxs)
{
//3.1先数据映射
var dets = _mapper.Map<List<InStockDetails>>(box.Details);
//3.2遍历赋值boxID和仓库和仓位和来源单和供应商和组织
dets.ForEach(item =>
{
item.TaskId = dto.TaskId;
item.SourceBillNo = task.SourceBillNo;
item.BoxId = box.BoxId;
//item.SubStockId = dto.SubStockId;
//item.StockCode = dto.StockCode;
//item.OrgCode = dto.OrgCode;
//item.OrgId = task.Details.Select(x => x.OrgId).FirstOrDefault();
});
//3.3添加到临时集合中
temps.AddRange(dets);
}
//3.4给对象明细赋值
entity.Details = temps;
//4.创建
entity.Create(loginInfo.UserInfo.StaffId);
//序列号集:箱里面的
var serialNumbers = await _serialNumbersRepositories.GetEntityListByBoxIds(dto.Boxs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList());
if (dto.ShelfMethod == (int)ShelfMethod.Box)
{
//赋值序列号
entity.Details.ForEach(x =>
{
var current_box_serNums = serialNumbers.Where(t => t.BoxId == x.BoxId).ToList();
if (current_box_serNums != null)
{
var current_box_mat_serNums = current_box_serNums.Where(t => t.MaterialId == x.MaterialId).Select(t => t.SerialNumber).ToList();
x.SerialNumbers.AddRange(current_box_mat_serNums);
}
});
}
//5.1保存入库单信息
entity = await _inStockRepositories.Add(entity, isTransaction);
if (entity == null)
return Result.ReFailure(ResultCodes.DateWriteError);
//处理添加入库汇总明细
var totalDetails = dto.Boxs.SelectMany(x => x.Details).GroupBy(x => new { x.MaterialId })
.Select(x => new InStockTotalDetails
{
InStockId = entity.Id,
TaskId = dto.TaskId,
SourceBillNo = task.SourceBillNo,
MaterialId = x.Key.MaterialId,
Qty = x.Sum(t => t.Qty),
SerialNumbers = x.SelectMany(t => t.SerialNumbers).ToList()
}).ToList();
var isSuccess = await _inStockRepositories.AddRangeTotalDetails(totalDetails, isTransaction);
if (!isSuccess)
return Result.ReFailure(ResultCodes.DateWriteError);
//反写:任务单的已交数量
if (task != null)
{
task.Details.ForEach(x =>
{
var current_entityDets = entity.Details.Where(t => t.ErpDetailId == x.ErpDetailId && t.MaterialId==x.MaterialId).ToList();
if (current_entityDets != null && current_entityDets.Count != 0 && x.ErpDetailId == current_entityDets.FirstOrDefault().ErpDetailId)
{
var current_entityDet_matQty = current_entityDets.Sum(x => x.Qty);
x.ReceiveQty = x.ReceiveQty + current_entityDet_matQty;
x.DeliveredQty = x.DeliveredQty + current_entityDet_matQty;
x.RealityQty = x.RealityQty + current_entityDet_matQty;
}
});
task.NoPurchaseShelf(loginInfo.UserInfo.StaffId);
task = await _inStockTaskRepositories.Update(task, isTransaction);
if (task == null)
return Result.ReFailure(ResultCodes.DateWriteError);
}
//6.当按产品上架:就要调用改箱的操作;
if (dto.ShelfMethod == (int)ShelfMethod.Product)
{
////通过序列号,获取序列号对应的箱
//var cureent_serialNumbs = await _serialNumbersRepositories.GetEntityList(dto.Boxs.SelectMany(x => x.Details).SelectMany(x => x.SerialNumbers).ToList());
//var current_boxIds = cureent_serialNumbs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList();
////当前序列号对应的箱的集合信息
//var current_boxs = await _boxRepositories.GetEntityList(current_boxIds);
////要改箱的数据集合
//var ganenrateChangeBoxs = new List<SaveChangeBoxRecordRequest>();
////当前按产品上架的箱子
//var dto_box = dto.Boxs.FirstOrDefault();
////遍历:序列号对应多个箱
//foreach (var boxId in current_boxIds)
//{
// if (dto_box.BoxId != boxId)
// {
// var box = current_boxs.Where(x => x.Id == boxId).FirstOrDefault();
// //遍历:明细
// var changeBox = new SaveChangeBoxRecordRequest();
// changeBox.DestBoxId = dto_box.BoxId;
// changeBox.SubStockId = dto.SubStockId;
// foreach (var item in dto_box.Details)
// {
// var boxDet = box.Details.Where(t => t.MaterialId == item.MaterialId).FirstOrDefault();
// if (boxDet != null && boxDet.MaterialId == item.MaterialId)
// {
// var changeBoxRD = new SaveChangeBoxRecordDetailsRequest();
// changeBoxRD.MaterialId = item.MaterialId;
// changeBoxRD.Qty = item.Qty;
// changeBoxRD.SerialNumbers = item.SerialNumbers;
// changeBox.Details.Add(changeBoxRD);
// }
// }
// //当明细存在,则要有原箱的情况下进行改箱
// if (changeBox.Details.Count != 0)
// {
// changeBox.SrcBoxId = boxId;
// ganenrateChangeBoxs.Add(changeBox);
// }
// }
//}
////没有原箱的情况下,要改箱操作对象
//var serialNub_isNotHaveBOx = new List<string>();
//var serialNumbs = dto.Boxs.SelectMany(x => x.Details).SelectMany(x => x.SerialNumbers).ToList();
//foreach (var item in serialNumbs)
//{
// var current_IsHaveBox_serialNub = cureent_serialNumbs.Where(x => x.SerialNumber == item).Any();
// if (!current_IsHaveBox_serialNub)
// serialNub_isNotHaveBOx.Add(item);
//}
//if (serialNub_isNotHaveBOx.Count != 0)
//{
// var changeBox_tag = new SaveChangeBoxRecordRequest();
// changeBox_tag.DestBoxId = dto_box.BoxId;
// changeBox_tag.SrcBoxId = 0;
// changeBox_tag.SubStockId = dto.SubStockId;
// foreach (var item in dto_box.Details)
// {
// //遍历:明细
// var changeBoxRD = new SaveChangeBoxRecordDetailsRequest();
// changeBoxRD.MaterialId = item.MaterialId;
// changeBoxRD.Qty = item.Qty;
// changeBoxRD.SerialNumbers = item.SerialNumbers;
// changeBox_tag.Details.Add(changeBoxRD);
// }
// ganenrateChangeBoxs.Add(changeBox_tag);
//}
////改箱保存操作--弃用
//var changeBoxSave_Result = await _changeMoveBoxService.ChangeBox_InStock(entity, loginInfo, isTransaction);
//if (!changeBoxSave_Result.IsSuccess)
// return changeBoxSave_Result;
}
//6.1序列号跟踪流程添加;备注:和上面的改箱操作后会记录序列号轨迹不冲突;
var serialNumber_result = await _serialNumberService.InStock(entity, loginInfo, isTransaction);
if (!serialNumber_result.IsSuccess)
return serialNumber_result;
//箱库存变动
var boxInventoryResult = await _boxInventoryService.GenerateInStockBox(entity, isTransaction);
if (!boxInventoryResult.IsSuccess)
return boxInventoryResult;
return Result.ReSuccess();
}
/// <summary>
/// 修改-入库任务信息
/// </summary>
/// <param name="dto"></param>
/// <param name="staffId"></param>
/// <param name="isReceive"></param>
/// <param name="isTransaction"></param>
/// <returns></returns>
public async Task<Result<InStockTask>> Receive(UpdateInStockTaskRequest dto, int staffId, bool isTransaction)
{
//1.修改任务单的数据
var entity = await _inStockTaskRepositories.Get(dto.Id);
if (entity == null)
return Result<InStockTask>.ReFailure(ResultCodes.DateWriteError);
entity = _mapper.Map(dto, entity);
entity.Receive(staffId);
//子集单独映射
entity.Details.ForEach(x =>
{
//当前明细收货的明细可以通过erp明细ID获取唯一一个;并变更收货数量
var current_dto_det = dto.Details.Where(t => t.ErpDetailId == x.ErpDetailId).FirstOrDefault();
if (current_dto_det != null && x.ErpDetailId == current_dto_det.ErpDetailId && x.MaterialId==current_dto_det.MaterialId)
x.ReceiveQty = x.ReceiveQty + current_dto_det.ReceiveQty;
});
//2.修改箱和任务单的绑定关系,先判断箱没有被收货过
var dto_boxIds = dto.Boxs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList();
var taskBoxList = await _inStockTaskBoxRepositories.GetListBy(dto_boxIds);
if (taskBoxList != null && taskBoxList.Count != 0)
return Result<InStockTask>.ReFailure(ResultCodes.InStockTaskBoxIsHaveData);
//3.组装绑定关系表,要添加的集合
var boxEntitys = await _boxRepositories.GetEntityList(dto_boxIds);
var taskBoxAdd = new List<InStockTaskBox>();
foreach (var item in dto.Boxs)
{
var taskBox = _mapper.Map<InStockTaskBox>(item);
taskBox.TaskId = entity.Id;
var current_dto_box_dets = boxEntitys.Where(x => x.Id == item.BoxId).SelectMany(x => x.Details).ToList();
taskBox.Details = _mapper.Map<List<InStockTaskBoxDetails>>(current_dto_box_dets);
taskBox.Details.ForEach(x => { x.ErpDetailId = item.ErpDetailId; });
taskBoxAdd.Add(taskBox);
}
var isSuccess = await _inStockTaskBoxRepositories.AddRange(taskBoxAdd, isTransaction);
if (!isSuccess)
return Result<InStockTask>.ReFailure(ResultCodes.DateWriteError);
//数据库操作
var result = await _inStockTaskRepositories.Update(entity, isTransaction);
if (result == null)
return Result<InStockTask>.ReFailure(ResultCodes.DateWriteError);
return Result<InStockTask>.ReSuccess(entity);
}
/// <summary>
/// 批量修改-入库任务信息
/// </summary>
/// <param name="ids"></param>
/// <param name="staffId"></param>
/// <param name="isReceive"></param>
/// <param name="isTransaction"></param>
/// <returns></returns>
public async Task<Result> UpdateRange(List<int> ids, int staffId, bool isReceive, bool isTransaction = true)
{
var entitys = await _inStockTaskRepositories.GetList(ids);
if (entitys == null || entitys.Count == 0)
return Result.ReFailure(ResultCodes.DateWriteError);
foreach (var item in entitys)
{
if (isReceive)
item.Receive(staffId);
else
item.Shelf(staffId);
}
var isSuccess = await _inStockTaskRepositories.UpdateRange(entitys, isTransaction);
if (isSuccess)
return Result.ReSuccess();
else
return Result.ReFailure(ResultCodes.DateWriteError);
}
/// <summary>
/// 采购订单物料明细和箱物料明细-对比
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<Result<ContrastMaterialsResponse>> Contrast(ContrastMaterialsRequest dto)
{
//1.找到任务单的明细信息
var task = await _inStockTaskRepositories.Get(dto.TaskId);
if (task == null)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.OrderNoData);
//1.1筛选出对应仓库的明细
var task_details = task.Details.Where(x => x.StockCode == dto.StockCode).ToList();
//2.找到箱对应的物料信息:多个箱
var boxs = await _boxRepositories.GetEntityListByNos(dto.BoxBillNos);
if (boxs == null || boxs.Count == 0)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.BoxNoData);
//3.判断箱里面对应的物料是否存在;不存在就报错
foreach (var item in boxs)
{
if(item.Details==null || item.Details.Count==0)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.BoxMateriaNoData);
}
//判断箱是否存在库存:有的话就提示“箱号已上架入库”
var boxInventory = await _boxInventoryRepositories.GetList(boxs.Select(x => x.Id).ToList());
if (boxInventory != null && boxInventory.Count != 0)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.BoxInventoryHaveInventoryError);
//合并多个箱明细的数据:相同物料数量合并
var boxDetails = boxs.SelectMany(x => x.Details).GroupBy(x => x.MaterialId).Select(x => new { MaterialId = x.Key, Qty = x.Sum(t => t.Qty) }).ToList();
//采购单:要对比数量
if (task.Type == InstockType.Purchase)
{
//3.比对false为比对失败;
bool isRight = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId && t.AccruedQty >= x.Qty)) && boxDetails.Count <= task_details.Count;
if (!isRight)
{
var qtyIsError = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId && t.AccruedQty < x.Qty));
if (boxDetails.Count > task_details.Count && qtyIsError)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.Contrast_Purchase_Error);
else if (qtyIsError)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.Contrast_Qty_Error);
else
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.Contrast_Purchase_Count_Error);
}
}
//非采购单:不要对比数量,只对比物料
else
{
//3.比对false为比对失败;
bool isRight = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId)) && boxDetails.Count <= task_details.Count;
if (!isRight)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.Contrast_Count_Error);
}
//4.是否任务单存在绑定箱号判断:存在的话,就不能收货或者非采购上架
var taskBoxList = await _inStockTaskBoxRepositories.GetListBy(dto.BoxBillNos);
if (taskBoxList != null && taskBoxList.Count != 0)
return Result<ContrastMaterialsResponse>.ReFailure(ResultCodes.BoxHaveError);
//4.返回对比结果true为比对成功并把箱ID和箱号返回
var response = new ContrastMaterialsResponse();
foreach (var box in boxs)
{
var r_box = new ContrastBoxResponse();
r_box.BoxBillNo = box.BoxBillNo;
r_box.BoxId = box.Id;
r_box.TotalCount = box.Details.Sum(x => x.Qty);
r_box.Details = _mapper.Map<List<ContrastBoxDetailsResponse>>(box.Details);
response.Boxs.Add(r_box);
}
return Result<ContrastMaterialsResponse>.ReSuccess(response);
}
/// <summary>
/// 采购:同步金蝶
/// </summary>
/// <param name="entity"></param>
/// <param name="loginInfo"></param>
/// <returns></returns>
private async Task<Result> PurchaseInStock(InStock entity, LoginInDto loginInfo)
{
var scope = _serviceScopeFactory.CreateScope();
var sc_InStockRepositories = scope.ServiceProvider.GetRequiredService<IInStockRepositories>();
if (entity.Type != InstockType.Purchase) return Result.ReSuccess();
if (entity.SuccessSync == SyncStatus.Success) return Result.ReSuccess();
var erpDetails = entity.ErpDetails.Where(w => w.SuccessSync == SyncStatus.SyncIng).ToList();
foreach (var s in erpDetails)
{
var erp_details = entity.ErpDetails
.Where(w => w.SourceBillNo.Equals(s)).Select(s => s.ErpDetailId).ToList();
var erpDto = new ErpPushDto()
{
RuleId = "PUR_PurchaseOrder-STK_InStock",//转换规则内码 采购订单下推采购入库单
FormId = FormIdParam.PUR_PurchaseOrder.ToString(),
TargetFormId = FormIdParam.STK_InStock.ToString(),
DetailsId = s.ErpDetailId.ToString(),
IsDraftWhenSaveFail=true
};
//下推金蝶
var res = await this.Push(erpDto, s, entity.BillNo, scope);
if (res.result.IsSuccess)
entity.SyncSuccess(s.ErpDetailId, loginInfo?.UserInfo?.StaffId ?? 0, res.erpBillNo);
else
entity.SyncFail(res.result.Message, s.ErpDetailId, loginInfo?.UserInfo?.StaffId ?? 0, res.syncStatus);
}
//最好一条一条执行,否则执行失败 但是金蝶那边又同步成功 就会造成数据比价乱
var isSuccess = await sc_InStockRepositories.Update(entity, true);
if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError);
return Result.ReSuccess();
}
/// <summary>
/// 下推
/// </summary>
/// <param name="dto"></param>
/// <param name="erpDetail"></param>
/// <param name="billNo"></param>
/// <returns></returns>
private async Task<(Result result, SyncStatus syncStatus, string erpBillNo)> Push(ErpPushDto dto, InStockErpDetails erpDetail, string billNo, IServiceScope scope)
{
var sc_erpService = scope.ServiceProvider.GetRequiredService<IErpService>();
var res = await sc_erpService.Push(dto);
if (!res.IsSuccess)
{
_logger.LogInformation($"入库单->下推失败 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId} 错误:{res.Message}");
return (Result.ReFailure(res.Message, res.Status), SyncStatus.Fail, "");
}
string id = res.Data;
var resPurchaseInStock = await sc_erpService.BillQueryForPurchaseInStock(id);
var purchaseInStock = resPurchaseInStock.Data;
purchaseInStock.Details[0].Qty = erpDetail.Qty;
string formId = dto.TargetFormId.ToString();
_logger.LogInformation($"入库单->开始同步金蝶 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId} 数据: {JsonConvert.SerializeObject(dto)}");
var res_s = await sc_erpService.Save<ErpPurchaseInStockSaveDto>(purchaseInStock, formId);
if (!res_s.IsSuccess)
{
_logger.LogInformation($"入库单->修改数量失败 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId} 错误:{res_s.Message}");
return (Result.ReFailure(res_s.Message, res_s.Status), SyncStatus.SubmitFail, id);
}
//提交
_logger.LogInformation($"入库单->保存成功 开始提交 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId}");
ErpOperateDto o_dto = new ErpOperateDto(formId, res_s.Data);//res_s.Data
var resSubmit = await sc_erpService.Submit(o_dto, formId);
if (!resSubmit.IsSuccess)
{
_logger.LogInformation($"入库单->提交失败 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId} 错误:{resSubmit.Message}");
return (resSubmit, SyncStatus.SubmitFail, o_dto.Numbers.First());
}
//审核
_logger.LogInformation($"入库单->提交成功 开始审核 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId}");
resSubmit = await sc_erpService.Audit(o_dto, formId);
if (!resSubmit.IsSuccess)
{
_logger.LogInformation($"入库单->审核失败 单号:{billNo} erp明细Id:{erpDetail.ErpDetailId} 错误:{resSubmit.Message}");
return (resSubmit, SyncStatus.CheckFail, o_dto.Numbers.First());
}
_logger.LogInformation($"入库单->同步金蝶成功->单号:{billNo} erp明细Id:{erpDetail.ErpDetailId}");
return (Result.ReSuccess(), SyncStatus.Success, o_dto.Numbers.First());
}
}
}