diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application.Contracts/Entities/Prices/PriceListDtoBase.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application.Contracts/Entities/Prices/PriceListDtoBase.cs index ce1e9d91..52dd4a22 100644 --- a/code/src/Modules/SettleAccount/src/SettleAccount.Application.Contracts/Entities/Prices/PriceListDtoBase.cs +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application.Contracts/Entities/Prices/PriceListDtoBase.cs @@ -413,6 +413,210 @@ namespace Win.Sfs.SettleAccount.Entities.Prices [Display(Name = "是否作废")] public bool IsCancel { get; set; } } + #endregion + + #region 印度价格 + /// + /// 印度价格 + /// + public class PriceListYinDuDto : AuditedEntityDto + { + /// + /// 客户零件号 + /// + [Display(Name = "客户零件号")] + public string LU { get; set; } + + /// + /// 价格 + /// + [Display(Name = "价格")] + public decimal Price { get; set; } + + /// + /// 开始时间 + /// + [Display(Name = "开始时间")] + public DateTime BeginDate { set; get; } + + /// + /// 结束时间 + /// + [Display(Name = "结束时间")] + public DateTime EndDate { set; get; } + + /// + /// 客户编码 + /// + [Display(Name = "客户编码")] + public string ClientCode { get; set; } + + /// + /// 合同签订时间 + /// + [Display(Name = "合同签订时间")] + public DateTime Date { get; set; } + + /// + /// 合同号 + /// + [Display(Name = "合同号")] + public string ContractNo { get; set; } + /// + /// 是否作废 + /// + [Display(Name = "是否作废")] + public bool IsCancel { get; set; } + } + + /// + /// 印度价格导出 + /// + [Display(Name = "备件价格")] + public class PriceListYinDuExportDto + { + /// + /// 客户零件号 + /// + [Display(Name = "客户零件号")] + [ExporterHeader(DisplayName = "客户零件号")] + public string LU { get; set; } + /// + /// 价格 + /// + [Display(Name = "价格")] + [ExporterHeader(DisplayName = "价格")] + public decimal Price { get; set; } + /// + /// 开始时间 + /// + [Display(Name = "开始时间")] + [ExporterHeader(DisplayName = "开始时间")] + public DateTime BeginDate { set; get; } + /// + /// 结束时间 + /// + [Display(Name = "结束时间")] + [ExporterHeader(DisplayName = "结束时间")] + public DateTime EndDate { set; get; } + /// + /// 客户编码 + /// + [Display(Name = "客户编码")] + [ExporterHeader(DisplayName = "客户编码")] + public string ClientCode { get; set; } + /// + /// 合同签订时间 + /// + [Display(Name = "合同签订时间")] + [ExporterHeader(DisplayName = "合同签订时间")] + public DateTime Date { get; set; } + /// + /// 合同号 + /// + [Display(Name = "合同号")] + [ExporterHeader(DisplayName = "合同号")] + public string ContractNo { get; set; } + /// + /// 是否作废 + /// + [Display(Name = "是否作废")] + [ExporterHeader(DisplayName = "是否已经停用")] + [ValueMapping("否", false)] + [ValueMapping("是", true)] + public bool IsCancel { get; set; } + } + + /// + /// 印度价格导入 + /// + [Importer(HeaderRowIndex = 22)] + public class PriceListYinDuImportDto + { + /// + /// 合同签订时间 + /// + [ImporterHeader(IsIgnore = true)] + [ExcelImporterHeadDesc(Row = 1, Cell = 1)] + public string Date { get; set; } + /// + /// 合同号 + /// + [ImporterHeader(IsIgnore = true)] + [ExcelImporterHeadDesc(Row = 2, Cell = 1)] + public string ContractNo { get; set; } + /// + /// 零件号 + /// + [Display(Name = "零件号")] + [Required(ErrorMessage = "{0}是必填项")] + [ImporterHeader(Name = "Part No.")] + public string PartNo { get; set; } + /// + /// 价格 + /// + [ImporterHeader(Name = "Total Price")] + public decimal TotalPrice { get; set; } + /// + /// 开始时间 + /// + [ImporterHeader(Name = "Valid From")] + public DateTime ValidFrom { get; set; } + /// + /// 结束时间 + /// + [ImporterHeader(Name = "Valid To")] + public DateTime ValidTo { get; set; } + /// + /// 客户编码 + /// + [ImporterHeader(Name = "Plant")] + public string Plant { get; set; } + /// + /// ES1 + /// + [ImporterHeader(Name = "ES1")] + public string ES1 { get; set; } + /// + /// ES2 + /// + [ImporterHeader(Name = "ES2")] + public string ES2 { get; set; } + } + + public class PriceListYinDuRequestDto : RequestInputBase + { + [Display(Name = "开始时间")] + public DateTime BeginDate { get; set; } + [Display(Name = "结算时间")] + public DateTime EndDate { get; set; } + [Display(Name = "价格")] + public decimal Price { get; set; } + [Display(Name = "物料编号")] + public string MaterialCode { get; set; } + [Display(Name = "价格类型")] + public int Type { get; set; } + + public Guid ParentId { set; get; } + + public int FileType { set; get; } + + public string Version { set; get; } + + public virtual List Filters { get; set; } = new List(); + } + + /// + /// UpdateDto + /// + public class PriceListYinDuUpdateDto : EntityDto + { + /// + /// 是否作废 + /// + [Display(Name = "是否作废")] + public bool IsCancel { get; set; } + } + #endregion } -#endregion diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceBJ.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceBJ.cs index f7817915..e2c56dc6 100644 --- a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceBJ.cs +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceBJ.cs @@ -55,10 +55,10 @@ namespace Win.Sfs.SettleAccount.Entities.Prices /// * 备件价格单筛选 Plant(客户编码) 为(1049)的数据 /// * 客户零件号为 PartNo+6个空格+ES1+ES2 /// * 根据 合同日期、客户编码、零件号、开始时间、结束时间分组导入(过滤重复数据) - /// 数据校验 + /// * 数据校验 /// * 同一合同日期、客户编码、零件号 不能存在时间交集 /// * 判断同一个零件号时间区间是否连续 - /// 作废旧合同日期的数据 + /// * 作废旧合同日期的数据 /// * 比较新导入的数据和数据库中老数据(同一零件号、旧合同日期的数据修改状态为作废) /// [HttpPost] diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceYinDu.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceYinDu.cs new file mode 100644 index 00000000..6a59e00c --- /dev/null +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/Prices/PriceListAppServiceYinDu.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using EFCore.BulkExtensions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Shouldly; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Caching; +using Win.Abp.Snowflakes; +using Win.Sfs.BaseData.ImportExcelCommon; +using Win.Sfs.SettleAccount.CommonManagers; +using Win.Sfs.SettleAccount.Constant; +using Win.Sfs.SettleAccount.Entities.BQ.Dtos; +using Win.Sfs.SettleAccount.ExcelImporter; +using Win.Sfs.SettleAccount.ExportReports; +using Win.Sfs.Shared.RepositoryBase; + +namespace Win.Sfs.SettleAccount.Entities.Prices +{ + /// + /// 印度件价格 + /// + [AllowAnonymous] + [Route("api/settleaccount/[controller]/[action]")] + public class PriceListAppServiceYinDu : SettleAccountApplicationBase + { + /// + /// 数据上下文 + /// + private readonly SettleAccountDbContext _settleAccountDbContext; + private readonly INormalEfCoreRepository _repository; + + public PriceListAppServiceYinDu( + SettleAccountDbContext settleAccountDbContext, + INormalEfCoreRepository repository, + IDistributedCache cache, + IExcelImportAppService excelImportService, + ISnowflakeIdGenerator snowflakeIdGenerator, + ICommonManager commonManager + ) : base(cache, excelImportService, snowflakeIdGenerator, commonManager) + { + _settleAccountDbContext = settleAccountDbContext; + _repository = repository; + } + + #region 导入、导出 + /// + /// 导入 + /// + /// + /// + /// + [HttpPost] + public async Task ImportAsync([FromForm] IFormFileCollection files, string version) + { + var checkList = new List(); + var _exportImporter = new ExportImporter(); + var result = await _exportImporter.UploadExcelImportByHeadDesc(files, _excelImportService).ConfigureAwait(false); + var filter = new List + { + "1049" + }; + result = result.Where(p => filter.Contains(p.Plant)).ToList(); + result.FindAll(t => !string.IsNullOrEmpty(t.ES1) || !string.IsNullOrEmpty(t.ES2)).ForEach(t => t.PartNo = t.PartNo + new string(' ', 6) + t.ES1 + t.ES2); + var newPrice = ObjectMapper.Map, List>(result); + newPrice = newPrice.GroupBy(p => new { p.Date, p.ClientCode, p.LU, p.BeginDate, p.EndDate }).Select(p => p.FirstOrDefault()).ToList(); + + #region 校验 + if (newPrice.Any()) + { + var query = from item1 in newPrice + join item2 in newPrice + on new { item1.Date, item1.ClientCode, item1.LU } equals new { item2.Date, item2.ClientCode, item2.LU } + where (item1.BeginDate > item2.BeginDate && item1.EndDate < item2.EndDate) || (item2.BeginDate > item1.BeginDate && item2.EndDate < item1.EndDate) || (item1.BeginDate == item2.BeginDate && item1.EndDate != item2.EndDate) || (item1.BeginDate != item2.BeginDate && item1.EndDate == item2.EndDate) + select item1; + var repeat = query.Distinct().ToList(); + foreach (var item in repeat) + { + checkList.Add(new ErrorExportDto(string.Empty, string.Empty, string.Empty, string.Empty, item.LU, string.Empty, $"合同号:{item.ContractNo},合同签订时间:{item.Date:yyyy-MM-dd},时间区间存在交集", string.Empty)); + } + + //foreach (var item in CheckPriceListContinuity(newPrice)) + //{ + // checkList.Add(new ErrorExportDto(string.Empty, string.Empty, string.Empty, string.Empty, item.LU, string.Empty, $"合同号:{item.ContractNo},合同签订时间:{item.Date:yyyy-MM-dd},时间区间【{item.BeginDate:yyyy-MM-dd}至{item.EndDate:yyyy-MM-dd}】不连续", string.Empty)); + //} + } + if (checkList.Count > 0) + { + var fileName = await ExportErrorReportAsync(checkList).ConfigureAwait(false); + return new JsonResult(new { code = ApplicationConsts.ImportFailCode, message = "导入失败", fileName }); + } + #endregion + + newPrice.ForEach(t => t.IsCancel = true); + newPrice.GroupBy(t => new { t.ClientCode, t.LU }) + .SelectMany(t => + { + var data = t.OrderByDescending(t => t.Date).First().Date; + return t.Where(t => t.Date == data); + }) + .ForEach(t => t.IsCancel = false); + + var importLus = newPrice.Select(t => t.LU).Distinct().ToList(); + var oldPrices = _settleAccountDbContext.Set() + .Where(t => t.IsCancel == false) + .Where(t => importLus.Contains(t.LU)) + .ToList(); + //系统中合同日期比导入文件中的合同日期晚 + var oldPriceNewDate = from oldPriceItem in oldPrices + from newPriceItem in newPrice.FindAll(t => t.IsCancel == false) + where oldPriceItem.ClientCode == newPriceItem.ClientCode && oldPriceItem.LU == newPriceItem.LU && oldPriceItem.Date > newPriceItem.Date + select new { oldPriceItem, newPriceItem }; + oldPrices.ForEach(t => t.IsCancel = true); + if (oldPriceNewDate.Any()) + { + oldPrices.FindAll(t => t.IsCancel == true && oldPriceNewDate.Select(t => t.oldPriceItem).Contains(t)).ForEach(t => t.IsCancel = false); + newPrice.FindAll(t => t.IsCancel == false && oldPriceNewDate.Select(t => t.newPriceItem).Contains(t)).ForEach(t => t.IsCancel = true); + } + foreach (var item in newPrice) + { + item.Update(GuidGenerator.Create()); + } + using var transaction = await _settleAccountDbContext.Database.BeginTransactionAsync().ConfigureAwait(false); + try + { + await _settleAccountDbContext.BulkUpdateAsync(oldPrices).ConfigureAwait(false); + await _settleAccountDbContext.BulkInsertAsync(newPrice).ConfigureAwait(false); + await transaction.CommitAsync().ConfigureAwait(false); + } + catch (Exception) + { + await transaction.RollbackAsync().ConfigureAwait(false); + return new JsonResult(new { Code = 200, Message = "导入失败" }); + } + return new JsonResult(new { Code = 200, Message = "导入成功" }); + + } + + /// + /// 价格表时间是否连续 + /// + private List CheckPriceListContinuity(List priceList) + { + var result = new List(); + if (priceList.Count <= 1) + { + return result; // 只有一个或零个价格条目 + } + + var dateGroups = priceList.GroupBy(t => t.Date); + foreach (var dateGroup in dateGroups) + { + var clientCodeGroups = dateGroup.GroupBy(t => t.ClientCode); + foreach (var clientCodeGroup in clientCodeGroups) + { + if (clientCodeGroup.ToList().Count <= 1) + { + continue; + } + var sortedList = clientCodeGroup.OrderBy(t => t.LU).ThenBy(t => t.BeginDate).ToList(); + for (var i = 1; i < sortedList.Count; i++) + { + if (sortedList[i].LU == sortedList[i - 1].LU && sortedList[i].BeginDate != sortedList[i - 1].EndDate.AddDays(1)) + { + result.Add(sortedList[i]); + } + } + } + } + + return result; // 所有价格时间都连续 + } + + /// + /// 导出 + /// + [HttpPost] + public async Task ExportAsync(RequestDto input) + { + string fileName = $"印度件价格_{Guid.NewGuid()}.xlsx"; + var entities = await _repository.GetListByFilterAsync(input.Filters, input.Sorting, int.MaxValue, 0, true).ConfigureAwait(false); + var dtos = ObjectMapper.Map, List>(entities); + + ExportImporter _exportImporter = new ExportImporter(); + var result = await _exportImporter.ExcelExporter(dtos).ConfigureAwait(false); + result.ShouldNotBeNull(); + + await _excelImportService.SaveBlobAsync(new SaveExcelImportInputDto { Name = fileName, Content = result }).ConfigureAwait(false); + return fileName; + } + #endregion + + #region CURD + /// + /// 获取列表 + /// + [HttpPost] + public async Task> GetListAsync(RequestDto input) + { + var entities = await _repository.GetListByFilterAsync(input.Filters, input.Sorting, input.MaxResultCount, input.SkipCount, true).ConfigureAwait(false); + var totalCount = await _repository.GetCountByFilterAsync(input.Filters).ConfigureAwait(false); + var dtos = ObjectMapper.Map, List>(entities); + return new PagedResultDto(totalCount, dtos); + } + + /// + /// 修改实体 + /// + [HttpPost] + public async Task UpdateAsync(PriceListYinDuUpdateDto input) + { + var entity = await _settleAccountDbContext.Set().FindAsync(input.Id).ConfigureAwait(false); + entity.IsCancel = input.IsCancel; + if (entity.IsCancel == false) + { + var existPrices = _settleAccountDbContext.Set() + .Where(t => t.LU == entity.LU) + .Where(t => t.IsCancel == false) + .Where(t => t.Id != entity.Id) + .ToList(); + + var existPrice = existPrices.Find(t => (entity.BeginDate >= t.BeginDate && entity.BeginDate < t.EndDate) || (t.BeginDate >= entity.BeginDate && t.BeginDate < entity.EndDate)); + if (existPrice != null) + { + throw new UserFriendlyException($"无法启用!此记录启用时间区间与区间【{existPrice.BeginDate:yyyy-MM-dd}至{existPrice.EndDate:yyyy-MM-dd}】存在交集", "400"); + } + } + await _settleAccountDbContext.SaveChangesAsync().ConfigureAwait(false); + var dto = ObjectMapper.Map(entity); + return dto; + } + #endregion + } +} diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application/SettleAccountApplicationAutoMapperProfile.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application/SettleAccountApplicationAutoMapperProfile.cs index d58fc0b1..13ace9f7 100644 --- a/code/src/Modules/SettleAccount/src/SettleAccount.Application/SettleAccountApplicationAutoMapperProfile.cs +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application/SettleAccountApplicationAutoMapperProfile.cs @@ -104,6 +104,7 @@ namespace Win.Sfs.SettleAccount CreateMapPriceListBJVersion(); CreateMapPriceListBJ(); + CreateMapPriceListYinDu(); #endregion #region 派格 @@ -501,6 +502,24 @@ namespace Win.Sfs.SettleAccount CreateMap().ReverseMap(); } + /// + /// 印度价格 + /// + private void CreateMapPriceListYinDu() + { + CreateMap() + .ForMember(x => x.LU, y => y.MapFrom(y => y.PartNo)) + .ForMember(x => x.Price, y => y.MapFrom(y => y.TotalPrice)) + .ForMember(x => x.BeginDate, y => y.MapFrom(y => y.ValidFrom)) + .ForMember(x => x.EndDate, y => y.MapFrom(y => y.ValidTo)) + .ForMember(x => x.ClientCode, y => y.MapFrom(y => y.Plant)) + .ForMember(x => x.Date, y => y.MapFrom(y => DateTime.ParseExact(y.Date, "dd.MM.yyyy", System.Globalization.CultureInfo.CurrentCulture))); ; + + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + } + private void CreateMapInvoiceSettledDiff() {