Files
WMS-Api/src/WMS.Web.Domain/Services/OutStockService.cs
18942506660 65bf0d273d 调整
2023-11-23 16:04:06 +08:00

260 lines
12 KiB
C#

using AutoMapper;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WMS.Web.Core.Dto;
using WMS.Web.Core.Dto.Erp;
using WMS.Web.Core.Dto.Inventory;
using WMS.Web.Core.Dto.Login;
using WMS.Web.Core.Dto.OutStock;
using WMS.Web.Core.Dto.TakeStock;
using WMS.Web.Core.Help;
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.Values;
using WMS.Web.Domain.Values.Erp;
namespace WMS.Web.Domain.Services
{
/// <summary>
/// 出库服务
/// </summary>
public class OutStockService : IOutStockService
{
private readonly IMapper _mapper;
private readonly ILoginService _loginService;
public readonly IBasicsRepositories _transactionRepositories;
private readonly IOutStockRepositories _outStockRepositories;
private readonly IOutStockTaskRepositories _outStockTaskRepositories;
private readonly IOutStockTaskService _outStockTaskService;
private readonly IErpService _erpService;
private readonly ISerialNumberService _serialNumberService;
private readonly IBoxInventoryService _boxInventoryService;
private readonly IInventoryInOutDetailsService _inventoryInOutDetailsService;
private readonly IBoxInventoryRepositories _boxInventoryRepositories;
public OutStockService(IMapper mapper, ILoginService loginService,
IBasicsRepositories transactionRepositories,
IOutStockRepositories outStockRepositories, IOutStockTaskRepositories outStockTaskRepositories,
IOutStockTaskService outStockTaskService, IErpService erpService, ISerialNumberService serialNumberService,
IBoxInventoryService boxInventoryService, IInventoryInOutDetailsService inventoryInOutDetailsService,
IBoxInventoryRepositories boxInventoryRepositories)
{
_mapper = mapper;
_loginService = loginService;
_transactionRepositories = transactionRepositories;
_outStockRepositories = outStockRepositories;
_outStockTaskRepositories = outStockTaskRepositories;
_outStockTaskService = outStockTaskService;
_erpService = erpService;
_serialNumberService = serialNumberService;
_boxInventoryService = boxInventoryService;
_inventoryInOutDetailsService = inventoryInOutDetailsService;
_boxInventoryRepositories = boxInventoryRepositories;
}
/// <summary>
/// 出库单
/// </summary>
/// <param name="dto"></param>
/// <param name="loginInfo"></param>
/// <returns></returns>
public async Task<Result> Save(SaveOutStockRequest dto, LoginInDto loginInfo)
{
var outStockTask = await _outStockTaskRepositories.Get(dto.TaskId);
if (outStockTask.Status == OutStockStatus.Already)
return Result.ReFailure(ResultCodes.OutStockTaskAlready);
if (outStockTask.Status == OutStockStatus.Repeal)
return Result.ReFailure(ResultCodes.OutStockTaskRepeal);
//上传的物料在任务单里没有找到不能出库
var ex = dto.Details.Select(s => s.MaterialId).Except(outStockTask.Details.Select(s => s.MaterialId)).ToList();
if (ex.Count() > 0 && dto.Method == 2)
return Result.ReFailure(ResultCodes.OutStockMaterialError);
//1.需要验证物料对应箱和序列号是否存在库存
//如果是按箱出库从库存拿取数据
if (dto.Method == 1)
{
var boxs = dto.Details.Select(s => s.BoxId).ToList();
dto.Details.Clear();
//获取箱子对应的所有库存
var boxInventoryList = await _boxInventoryRepositories.GetList(boxs);
//过滤掉不同仓库和不同组织的
boxInventoryList = boxInventoryList.Where(w => w.StockCode == outStockTask.StockCode && w.OrgCode == outStockTask.OrgCode).ToList();
//组装dto
var boxInventoryDetails = boxInventoryList.SelectMany(s => s.Details).ToList();
foreach (var b in boxInventoryDetails)
{
var num = boxInventoryDetails.Where(w => w.MaterialId == b.MaterialId).Sum(s => s.Qty);
var taskDetail = outStockTask.Details.FirstOrDefault(f => f.MaterialId == b.MaterialId);
if (taskDetail == null) return Result.ReFailure(ResultCodes.BoxOutStockTaskMaterialError);
//箱子里该物料的总数量大于出库单(应出库数量-已出库数量) 不能出库
if (num > (taskDetail.AccruedQty - taskDetail.RealityQty))
return Result.ReFailure(ResultCodes.BoxNumberError);
var box = boxInventoryList.FirstOrDefault(f => f.Id == b.Fid);
if (box == null) return Result.ReFailure(ResultCodes.BoxNoData);
var dtod = _mapper.Map<SaveOutStockDetailsRequest>(b);
dtod.BoxId = box.BoxId;
dtod.SubStockId = box.SubStockId;
dto.Details.Add(dtod);
}
}
var mIds = dto.Details.GroupBy(g => g.MaterialId).Select(s => s.Key).ToList();
OutStock entity = new OutStock();
foreach (var mid in mIds)
{
//任务单明细
var tDetail = outStockTask.Details.FirstOrDefault(f => f.MaterialId == mid);
var dtoDetails = dto.Details.Where(w => w.MaterialId == mid);
var qty = dtoDetails.Sum(s => s.Qty);
if (tDetail == null) continue;
var res = outStockTask.OutStock(mid, qty);
if (!res.IsSuccess) return res;
var outd = _mapper.Map<OutStockDetails>(tDetail);
//循环添加erp同步明细
foreach (var c in res.Data)
{
var tErpDetail = tDetail.ErpDetails.FirstOrDefault(f => f.SourceBillNo.Equals(c.sourceBillNo));
var oErpDetail = _mapper.Map<OutStockErpDetails>(tErpDetail);
oErpDetail.Qty = c.qty;
outd.ErpDetails.Add(oErpDetail);
}
var boxs = dto.Details.Where(w => w.MaterialId == mid).ToList();
outd.BoxsDetails = _mapper.Map<List<OutStockBoxsDetails>>(boxs);
outd.Qty = qty;
outd.SerialNumbers.AddRange(dtoDetails.SelectMany(s => s.SerialNumbers));
entity.Details.Add(outd);
}
entity.Create(loginInfo.UserInfo.StaffId, outStockTask);
#region dto
List<BoxInventoryGenerateDto> inventoryList = new List<BoxInventoryGenerateDto>();
var boxIds = dto.Details.GroupBy(g => g.BoxId).Select(s => s.Key).ToList();
foreach (var boxId in boxIds)
{
var inventoryDetail = dto.Details.Where(w => w.BoxId == boxId).Select(s => new BoxInventoryGenerateDetailsDto()
{
MaterialId = s.MaterialId,
Qty = s.Qty,
SerialNumbers = s.SerialNumbers
}).ToList();
BoxInventoryGenerateDto inventory = new BoxInventoryGenerateDto()
{
BoxId = boxId,
InventoryInOutMethod = dto.Method,
StockCode = outStockTask.StockCode,
SubStockId = dto.Details.FirstOrDefault(f => f.BoxId == boxId)?.SubStockId ?? 0,// outStockTask.Details.First().SubStockId,
Details = inventoryDetail
};
inventoryList.Add(inventory);
}
List<InventoryInOutDetailsGenerateDto> generateList = dto.Details.Select(s => new InventoryInOutDetailsGenerateDto()
{
BoxId = s.BoxId,
InventoryInOutType = 2,
OrderBillNo = outStockTask.BillNo,
Qty = s.Qty,
StockCode = outStockTask.StockCode,
MaterialId = s.MaterialId,
SubStockId = s.SubStockId,
OrgCode = outStockTask.OrgCode,
OrderType = 1,
}).ToList();
#endregion
IDbContextTransaction _transaction = _transactionRepositories.GetTransaction();
Result res_Rollback = Result.ReSuccess();
bool isSuccess = true;
//修改库存
//var res_Inventory = await _boxInventoryService.HandlBoxInventory(inventoryList, false);
//if (!res_Inventory.IsSuccess) res_Rollback = res_Inventory;
if (res_Rollback.IsSuccess)
{
entity = await _outStockRepositories.Add(entity, false);
if (entity == null) res_Rollback = Result.ReFailure(ResultCodes.DateWriteError);
}
if (res_Rollback.IsSuccess)
{
outStockTask = await _outStockTaskRepositories.Edit(outStockTask, false);
if (outStockTask == null) res_Rollback = Result.ReFailure(ResultCodes.DateWriteError);
}
if (res_Rollback.IsSuccess)
{
var res_change = await _serialNumberService.OutStock(entity, loginInfo, false);
if (!res_change.IsSuccess) res_Rollback = res_change;
}
//if (res_Rollback.IsSuccess)
//{
// res_Inventory = await _inventoryInOutDetailsService.GenerateInOrOutDetails(generateList, false);
// if (!res_Inventory.IsSuccess) res_Rollback = res_Inventory;
//}
//提交事务
isSuccess = _transactionRepositories.CommitTransaction(res_Rollback.IsSuccess ? false : true, _transaction);
if (!res_Rollback.IsSuccess) return res_Rollback;
if (!isSuccess)
return Result.ReFailure(ResultCodes.DateWriteError);
return Result.ReSuccess();
}
/// <summary>
/// 同步金蝶
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<Result> Sync(OperateRequest dto, LoginInDto loginInfo)
{
var list = await _outStockRepositories.GetEntityList(dto.Ids);
foreach (var entity in list)
{
if (entity.SuccessSync) continue;
List<string> failList = entity.SuccessSyncFail.Clone();//同步失败的来源单号
//找到单据里需要同步的单据
var sourcNos = entity.Details.SelectMany(s => s.ErpDetails).GroupBy(s => s.SourceBillNo).Select(s => s.Key);
foreach (var s in failList)
{
var erp_details = entity.Details.SelectMany(s => s.ErpDetails).Select(s => s.Erp_DetailId).ToList();
var erpDto = new ErpPushDto()
{
FormId = FormIdParam.SAL_DELIVERYNOTICE.ToString(),
Numbers = new List<string>() { s },
Type = "",
DetailsId = string.Join(",", erp_details)
};
//下推金蝶
var res = await this.Push(erpDto);
if (res.IsSuccess)
entity.SyncSuccess(s, loginInfo.UserInfo.StaffId);
else
entity.SyncFail(res.Message, loginInfo.UserInfo.StaffId);
}
entity.SuccessSync = entity.SuccessSyncFail.Count() > 0 ? false : true;
//最好一条一条执行,否则执行失败 但是金蝶那边又同步成功 就会造成数据比价乱
var isSuccess = await _outStockRepositories.Edit(entity, true);
if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError);
}
return Result.ReSuccess();
}
/// <summary>
/// 下推
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
private async Task<Result> Push(ErpPushDto dto)
{
var res = await _erpService.Push(dto);
return Result.ReSuccess();
}
}
}