262 lines
13 KiB
C#
262 lines
13 KiB
C#
using AutoMapper;
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
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;
|
|
using WMS.Web.Domain.Values.Single;
|
|
|
|
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;
|
|
private readonly ILogger<OutStockService> _logger;
|
|
private readonly IBoxRepositories _boxRepositories;
|
|
private readonly ISingleDataService _singleDataService;
|
|
public OutStockService(IMapper mapper, ILoginService loginService,
|
|
IBasicsRepositories transactionRepositories,
|
|
IOutStockRepositories outStockRepositories, IOutStockTaskRepositories outStockTaskRepositories,
|
|
IOutStockTaskService outStockTaskService, IErpService erpService, ISerialNumberService serialNumberService,
|
|
IBoxInventoryService boxInventoryService, IInventoryInOutDetailsService inventoryInOutDetailsService,
|
|
IBoxInventoryRepositories boxInventoryRepositories, ILogger<OutStockService> logger, IBoxRepositories boxRepositories,
|
|
ISingleDataService singleDataService)
|
|
{
|
|
_mapper = mapper;
|
|
_loginService = loginService;
|
|
_transactionRepositories = transactionRepositories;
|
|
_outStockRepositories = outStockRepositories;
|
|
_outStockTaskRepositories = outStockTaskRepositories;
|
|
_outStockTaskService = outStockTaskService;
|
|
_erpService = erpService;
|
|
_serialNumberService = serialNumberService;
|
|
_boxInventoryService = boxInventoryService;
|
|
_inventoryInOutDetailsService = inventoryInOutDetailsService;
|
|
_boxInventoryRepositories = boxInventoryRepositories;
|
|
_logger = logger;
|
|
_boxRepositories = boxRepositories;
|
|
_singleDataService = singleDataService;
|
|
}
|
|
/// <summary>
|
|
/// 出库单
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <param name="loginInfo"></param>
|
|
/// <returns></returns>
|
|
public async Task<Result> Save(SaveOutStockRequest dto, LoginInDto loginInfo)
|
|
{
|
|
_logger.LogInformation($"出库:{JsonConvert.SerializeObject(dto)} 操作人:{loginInfo.UserInfo.StaffId}");
|
|
var outStockTask = await _outStockTaskRepositories.Get(dto.TaskId);
|
|
if (outStockTask == null) return Result.ReFailure(ResultCodes.OutStockTaskNoData);
|
|
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);
|
|
var boxIds = dto.Details.Select(s => s.BoxId).ToList();
|
|
var boxInventoryList = await _boxInventoryRepositories.GetList(boxIds);
|
|
foreach (var boxid in boxIds)
|
|
{
|
|
var inventory = boxInventoryList.FirstOrDefault(f => f.BoxId == boxid);
|
|
if (inventory == null)
|
|
{
|
|
var box = await _boxRepositories.Get(boxid);
|
|
return Result.ReFailure($"箱号:{box?.BoxBillNo} 不存在库存", 70008);
|
|
}
|
|
if (!inventory.StockCode.Equals(outStockTask.StockCode))
|
|
{
|
|
var box = await _boxRepositories.Get(boxid);
|
|
var stockCodeName = _singleDataService.GetSingleData(SingleAction.StocksJoinOrgCode, loginInfo.UserInfo.CompanyId, outStockTask.StockCode + outStockTask.OrgCode);
|
|
return Result.ReFailure($"箱号:{box?.BoxBillNo}在仓库:{stockCodeName} 不存在库存", 70009);
|
|
}
|
|
}
|
|
|
|
//1.需要验证物料对应箱和序列号是否存在库存
|
|
//如果是按箱出库从库存拿取数据
|
|
if (dto.Method == 1)
|
|
{
|
|
dto.Details.Clear();
|
|
//获取箱子对应的所有库存
|
|
//过滤掉不同仓库和不同组织的
|
|
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, loginInfo.UserInfo.StaffId);
|
|
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.Erp_DetailId == c.erpDetailId);
|
|
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, dto.Method);
|
|
|
|
IDbContextTransaction _transaction = _transactionRepositories.GetTransaction();
|
|
Result res_Rollback = Result.ReSuccess();
|
|
bool isSuccess = true;
|
|
//修改库存
|
|
|
|
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)
|
|
{
|
|
var res_Inventory = await _boxInventoryService.GenerateOutStockBox(entity, 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)
|
|
{
|
|
await SalOutStock(entity, loginInfo);
|
|
}
|
|
return Result.ReSuccess();
|
|
}
|
|
/// <summary>
|
|
/// 同步金蝶销售出库
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task<Result> SalOutStock(OutStock entity, LoginInDto loginInfo)
|
|
{
|
|
if (entity.Type != OutStockType.Sal) return Result.ReSuccess();
|
|
if (entity.SuccessSync != SyncStatus.Fail) return Result.ReSuccess();
|
|
List<string> failList = entity.Details.SelectMany(s => s.ErpDetails)
|
|
.Where(w => w.SuccessSync == SyncStatus.Fail).GroupBy(g => g.SourceBillNo)
|
|
.Select(s => s.Key).ToList();//同步失败的来源单号
|
|
//找到单据里需要同步的单据
|
|
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 },
|
|
TargetFormId = FormIdParam.SAL_OUTSTOCK.ToString(),
|
|
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, SyncStatus.Fail);
|
|
}
|
|
//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();
|
|
}
|
|
}
|
|
}
|