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.Threading.Tasks; using WMS.Web.Core.Dto; using WMS.Web.Core.Dto.Erp; using WMS.Web.Core.Dto.Erp.TakeStock; using WMS.Web.Core.Dto.Inventory; using WMS.Web.Core.Dto.Login; using WMS.Web.Core.Dto.TakeStock; 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 { /// /// 盘点单服务 /// public class TakeStockService : ITakeStockService { private readonly IMapper _mapper; private readonly ILoginService _loginService; public readonly IBasicsRepositories _transactionRepositories; private readonly ITakeStockRepositories _takeStockRepositories; private readonly ILoginRepositories _loginRepositories; private readonly ISingleDataService _singleDataService; private readonly IErpService _erpService; private readonly ILogger _logger; private readonly IBoxInventoryService _boxInventoryService; private readonly IErpBasicDataExtendService _erpBasicDataExtendService; private readonly ISerialNumberService _serialNumberService; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly ISerialNumbersRepositories _serialNumberRepositories; public TakeStockService(IMapper mapper, ILoginService loginService, IBasicsRepositories transactionRepositories, ITakeStockRepositories takeStockRepositories, ILoginRepositories loginRepositories, ISingleDataService singleDataService, IErpService erpService, ILogger logger, IBoxInventoryService boxInventoryService, IErpBasicDataExtendService erpBasicDataExtendService, ISerialNumberService serialNumberService, IServiceScopeFactory serviceScopeFactory, ISerialNumbersRepositories serialNumberRepositories) { _mapper = mapper; _loginService = loginService; _transactionRepositories = transactionRepositories; _takeStockRepositories = takeStockRepositories; _loginRepositories = loginRepositories; _singleDataService = singleDataService; _erpService = erpService; _logger = logger; _boxInventoryService = boxInventoryService; _erpBasicDataExtendService = erpBasicDataExtendService; _serialNumberService = serialNumberService; _serviceScopeFactory = serviceScopeFactory; _serialNumberRepositories = serialNumberRepositories; } /// /// 保存 /// /// /// /// public async Task Save(List dto, LoginInDto loginInfo) { _logger.LogInformation($"盘点保存:{JsonConvert.SerializeObject(dto)} 盘点人:{loginInfo.UserInfo.StaffId}"); //dto = dto.Where(w => w.AfterQty != w.BeforeQty).ToList(); if (dto.Count() == 0) return Result.ReSuccess(); if (dto.GroupBy(g => g.BoxId).Count() > 1) return Result.ReFailure(ResultCodes.TakeStockBoxError); var serialNumbersBoxInventoryList = await GetSerialNumbersBoxInventory(dto); List list = new List(); var profitList = dto.Where(w => w.AfterQty >= w.BeforeQty).ToList();//盘盈 var lossList = dto.Where(w => w.AfterQty < w.BeforeQty).ToList();//盘亏 if (profitList.Count() > 0) { TakeStock takeStock = new TakeStock(); takeStock.Create(loginInfo.UserInfo.StaffId, TakeStockType.Profit); takeStock.Details = _mapper.Map>(profitList); var subIds = takeStock.Details.Select(s => s.SubStockId).ToList(); var subStocks = await _transactionRepositories.GetSubUcStockAsync(subIds, loginInfo.UserInfo.CompanyId); foreach (var d in takeStock.Details) { var subStock = subStocks.FirstOrDefault(f => f.Id == d.SubStockId); d.OrgCode = subStock?.ErpOrgCode; d.StockCode = subStock?.StockCode; if ((d.StockCode.Equals("HD") || d.StockCode.Equals("GD")) && string.IsNullOrEmpty(d.Erp_SubStockCode)) return Result.ReFailure(ResultCodes.TakeStockErpSubStockError); } if (takeStock.Details.GroupBy(g => g.StockCode).Count() > 1) return Result.ReFailure(ResultCodes.TakeStockStockError); list.Add(takeStock); } if (lossList.Count() > 0) { TakeStock takeStock = new TakeStock(); takeStock.Create(loginInfo.UserInfo.StaffId, TakeStockType.Loss); takeStock.Details = _mapper.Map>(lossList); var subIds = takeStock.Details.Select(s => s.SubStockId).ToList(); var subStocks = await _transactionRepositories.GetSubUcStockAsync(subIds, loginInfo.UserInfo.CompanyId); foreach (var d in takeStock.Details) { var subStock = subStocks.FirstOrDefault(f => f.Id == d.SubStockId); d.OrgCode = subStock?.ErpOrgCode; d.StockCode = subStock?.StockCode; if ((d.StockCode.Equals("HD") || d.StockCode.Equals("GD")) && string.IsNullOrEmpty(d.Erp_SubStockCode)) return Result.ReFailure(ResultCodes.TakeStockErpSubStockError); } if (takeStock.Details.GroupBy(g => g.StockCode).Count() > 1) return Result.ReFailure(ResultCodes.TakeStockStockError); list.Add(takeStock); } IDbContextTransaction _transaction = _transactionRepositories.GetTransaction(); Result res_Rollback = Result.ReSuccess(); bool isSuccess = true; if (res_Rollback.IsSuccess) { isSuccess = await _takeStockRepositories.AddRange(list, false); if (!isSuccess) res_Rollback = Result.ReFailure(ResultCodes.DateWriteError); } if (res_Rollback.IsSuccess) { var res_change = await _serialNumberService.TakeStock(list, loginInfo, false); if (!res_change.IsSuccess) res_Rollback = res_change; } if (res_Rollback.IsSuccess) { var res_Inventory = await _boxInventoryService.GenerateTakeBox(list, serialNumbersBoxInventoryList, 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); ////同步金蝶 //OperateRequest oRequest = new OperateRequest(); //oRequest.Ids = list.Select(s => s.Id).ToList(); //await Sync(oRequest, false); return Result.ReSuccess(); } /// /// 同步金蝶 /// /// /// public Task Sync(OperateRequest dto, bool isRepeatSync = true) { return Task.FromResult(Result.ReSuccess()); //var list = _takeStockRepositories.GetEntityList(dto.Ids).GetAwaiter().GetResult(); //var isSuccess = true; //if (isRepeatSync) //{ // list = list.Where(w => w.SuccessSync == SyncStatus.Fail).ToList(); // list.ForEach(f => f.RepeatSync()); // isSuccess = _takeStockRepositories.EditEntityList(list, true).GetAwaiter().GetResult(); //} //Task.Run(async () => // { // foreach (var entity in list) // { // var res = await Loss_Profit(entity); // if (!res.IsSuccess) // _logger.LogError($"盘点同步失败:{res.Message}"); // } // }); //if (isSuccess) // return Task.FromResult(Result.ReSuccess()); //else // return Task.FromResult(Result.ReFailure(ResultCodes.DateWriteError)); } /// /// 盘盈盘亏同步金蝶 /// /// /// public async Task Loss_Profit(TakeStock entity) { _logger.LogInformation($"盘点同步金蝶: {JsonConvert.SerializeObject(entity)}"); try { var scope = _serviceScopeFactory.CreateScope(); var sc_erpService = scope.ServiceProvider.GetRequiredService(); var sc_erpBasicDataExtendService = scope.ServiceProvider.GetRequiredService(); var sc_takeStockRepositories = scope.ServiceProvider.GetRequiredService(); var details = entity.Details.Where(w => w.FinalQty > 0).ToList(); if (details.Count() == 0) { entity.Sync(true, "", SyncStatus.Success, ""); await sc_takeStockRepositories.Edit(entity, true); return Result.ReSuccess(); } var materials_result = await sc_erpService.BillQueryForMaterial(); if (!materials_result.IsSuccess) return Result.ReFailure(ResultCodes.ErpMaterialError); var materials = materials_result.Data.ToList(); var subs = await _erpService.BillQueryForSubStock(); List<(string materialNumber, string orgCode, string stockCode, int subStockId)> requestInventory = new List<(string materialNumber, string orgCode, string stockCode, int subStockId)>(); foreach (var d in details) { int subStockId = subs.Data.FirstOrDefault(w => w.OrgCode.Equals(d.OrgCode) && w.StockCode.Equals(d.Erp_SubStockCode))?.Id ?? 0; requestInventory.Add((_erpBasicDataExtendService.GetMaterialNumber(materials, d.MaterialId), d.OrgCode, d.StockCode, subStockId)); }; var res_s = await sc_erpService.BillQueryForInventory(requestInventory); if (!res_s.IsSuccess) { entity.Sync(false, res_s.Message, SyncStatus.Fail, ""); await sc_takeStockRepositories.Edit(entity, true); _logger.LogInformation($"及时库存获取异常->错误:{res_s.Message} 数据: {JsonConvert.SerializeObject(entity)}"); return Result.ReFailure(res_s.Message, res_s.Status); } //组装dto #region 组装dto //子仓库 ORICO_JD:1000008 GD:1000005 HD:1000007 AD:1000004 List detils = new List(); foreach (var d in details) { int subStockId = subs.Data.FirstOrDefault(w => w.OrgCode.Equals(d.OrgCode) && w.StockCode.Equals(d.Erp_SubStockCode))?.Id ?? 0; var number = _erpBasicDataExtendService.GetMaterialNumber(materials, d.MaterialId); var erpInventory = res_s.Data.FirstOrDefault(f => f.MaterialNumber == number && f.StockCode == d.StockCode && f.OrgCode == d.OrgCode && f.Erp_SubStockId == subStockId); decimal qty = erpInventory?.Qty ?? 0; var unitNumber = _erpBasicDataExtendService.GetMaterialUnitNumber(materials, d.MaterialId); detils.Add(new ErpTakeStockDetailsSaveDto() { FOwnerid = new ErpNumberDto(d.OrgCode), FKeeperId = new ErpNumberDto(d.OrgCode), MaterialId = new ErpNumberDto(_erpBasicDataExtendService.GetMaterialNumber(materials, d.MaterialId)), UnitId = new ErpNumberDto(unitNumber), //物料带出来 StockId = new ErpNumberDto(d.StockCode), SubStockId = new ErpSubStockDto(d.StockCode, d.Erp_SubStockCode), BeforeQty = qty, AfterQty = entity.ResultType == TakeStockType.Profit ? (qty + d.FinalQty) : ((qty - d.FinalQty) > 0 ? (qty - d.FinalQty) : 0), FinalQty = entity.ResultType == TakeStockType.Profit ? d.FinalQty : 0, LossQty = entity.ResultType == TakeStockType.Loss ? d.FinalQty : 0, Fnote = d.Remark }); } ErpTakeStockSaveDto dto = new ErpTakeStockSaveDto() { BillNo = entity.BillNo, StockOrgId = new ErpNumberDto(entity.Details[0].OrgCode), Type = new ErpNumberDto(entity.ResultType == TakeStockType.Loss ? "PK01_SYS" : "PY01_SYS"), Date = entity.Date, Details = detils }; #endregion //判断盘盈盘亏 FormIdParam type = entity.ResultType == TakeStockType.Loss ? FormIdParam.STK_StockCountLoss : FormIdParam.STK_StockCountGain; //操作金蝶 var resSync = await ErpOperate(dto, type, scope); entity.Sync(resSync.result.IsSuccess, resSync.result.Message, resSync.syncStatus, resSync.erpBillNo); await sc_takeStockRepositories.Edit(entity, true); return Result.ReSuccess(); } catch (Exception ex) { _logger.LogError($"盘点同步金蝶: {ex.ToString()}"); return Result.ReFailure(ResultCodes.NoDateError); } } /// /// 同步金蝶操作 /// /// /// /// private async Task<(Result result, SyncStatus syncStatus, string erpBillNo)> ErpOperate(ErpTakeStockSaveDto dto, FormIdParam type, IServiceScope scope) { var sc_erpService = scope.ServiceProvider.GetRequiredService(); string formId = type.ToString(); _logger.LogInformation($"盘点单->开始同步金蝶 单号:{dto.BillNo} 数据: {JsonConvert.SerializeObject(dto)}"); var res_s = await sc_erpService.Save(dto, formId); if (!res_s.IsSuccess) { _logger.LogInformation($"盘点单->保存失败 单号:{dto.BillNo} 错误:{res_s.Message}"); return (Result.ReFailure(res_s.Message, res_s.Status), SyncStatus.Fail, ""); } //提交 _logger.LogInformation($"盘点单->保存成功 开始提交 单号:{dto.BillNo}"); ErpOperateDto o_dto = new ErpOperateDto(formId, res_s.Data);//res_s.Data var res = await sc_erpService.Submit(o_dto, formId); if (!res.IsSuccess) { //如果提交失败 //1.则调删单接口 //var del_res = await _erpService.Delete(o_dto, formId); //if (!del_res.IsSuccess) // _logger.LogError($"盘盈盘亏同步金蝶 单号:{dto.BillNo} 提交失败原因: {res.Message} 删单失败原因:{del_res.Message}"); _logger.LogInformation($"盘点单->提交失败 单号:{dto.BillNo} 错误:{res.Message}"); return (res, SyncStatus.SubmitFail, o_dto.Numbers.First()); } //审核 _logger.LogInformation($"盘点单->提交成功 开始审核 单号:{dto.BillNo}"); res = await sc_erpService.Audit(o_dto, formId); if (!res.IsSuccess) { //如果审核失败 //1.调反审核接口 //2.调删除接口 //var noAudit_res = await _erpService.NoAudit(o_dto, formId); //if (!noAudit_res.IsSuccess) //{ // _logger.LogError($"盘盈盘亏同步金蝶 单号:{dto.BillNo} 审核失败原因: {res.Message} 反审核失败原因:{noAudit_res.Message}"); // return res; //} //var del_res = await _erpService.Delete(o_dto, formId); //if (!del_res.IsSuccess) // _logger.LogError($"盘盈盘亏同步金蝶 单号:{dto.BillNo} 审核失败原因: {res.Message} 删单失败原因:{del_res.Message}"); _logger.LogInformation($"盘点单->审核失败 单号:{dto.BillNo} 错误:{res.Message}"); return (res, SyncStatus.CheckFail, o_dto.Numbers.First()); } _logger.LogInformation($"同步金蝶成功"); return (Result.ReSuccess(), SyncStatus.Success, o_dto.Numbers.First()); } /// /// 获取改变了箱的序列号 /// /// /// private async Task> GetSerialNumbersBoxInventory(List dto) { List list = new List(); var sNs = dto.SelectMany(s => s.SerialNumbers).ToList(); var entityList = await _serialNumberRepositories.GetEntityList(sNs); foreach (var s in sNs) { var entity = entityList.FirstOrDefault(f => f.SerialNumber.Equals(s)); if (entity == null) continue; var d = dto.FirstOrDefault(f => f.SerialNumbers.Contains(s)); if (d.BoxId != entity.BoxId) { list.Add(new SerialNumbersBoxInventoryDto() { BoxId = entity.BoxId, MaterialId = d.MaterialId, SerialNumber = s }); } } return list; } } }