diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/AssembleJobPermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/AssembleJobPermissions.cs new file mode 100644 index 000000000..ec726a250 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/AssembleJobPermissions.cs @@ -0,0 +1,27 @@ +using Volo.Abp.Authorization.Permissions; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public static class AssembleJobPermissions +{ + + public const string Default = StorePermissions.GroupName + "." + nameof(AssembleJob); + public const string Create = Default + "." + StorePermissions.CreateStr; + public const string Update = Default + "." + StorePermissions.UpdateStr; + public const string Delete = Default + "." + StorePermissions.DeleteStr; + + //自动发料任务 + public const string AutoAssembleJob = StorePermissions.GroupName + "." + nameof(AutoAssembleJob); + + public static void AddAssembleJobPermission(this PermissionGroupDefinition permissionGroup) + { + var AssembleJobPermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(AssembleJob))); + AssembleJobPermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr)); + AssembleJobPermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr)); + AssembleJobPermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr)); + + permissionGroup.AddPermission(AutoAssembleJob, StorePermissionDefinitionProvider.L(nameof(AutoAssembleJob))); + + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDTO.cs new file mode 100644 index 000000000..3e1f8691f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDTO.cs @@ -0,0 +1,46 @@ +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +/// +/// 装配发料任务 +/// +[Display(Name = "装配发料任务")] +public class AssembleJobDTO : SfsJobDTOBase +{ + /// + /// 叫料请求类型 + /// + [Display(Name = "叫料请求类型")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string RequestType { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 要货单号 + /// + [Display(Name = "要货单号")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string AssembleRequestNumber { get; set; } + + /// + /// 车间 + /// + [Display(Name = "车间")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Workshop { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + public bool UseOnTheWayLocation { get; set; } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDetailDTO.cs new file mode 100644 index 000000000..c89aa7d8f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/DTOs/AssembleJobDetailDTO.cs @@ -0,0 +1,112 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleJobDetailDTO : SfsJobRecommendFromDetailDTOBase, IHasToLocation +{ + + /// + /// 请求库位 + /// + [Display(Name = "请求库位")] + public string RequestLocationCode { get; set; } + + /// + /// 到库位 + /// + [Display(Name = "到库位")] + public string ToLocationCode { get; set; } + + /// + /// 到库区 + /// + [Display(Name = "到库区")] + public string ToLocationArea { get; set; } + + /// + /// 到库位组 + /// + [Display(Name = "到库位组")] + public string ToLocationGroup { get; set; } + + /// + /// 到ERP库位 + /// + [Display(Name = "到ERP库位")] + public string ToLocationErpCode { get; set; } + + /// + /// 到仓库 + /// + [Display(Name = "到仓库")] + public string ToWarehouseCode { get; set; } + + /// + /// 在途库库位 + /// + [Display(Name = "在途库库位")] + public string OnTheWayLocationCode { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + [Display(Name = "工作中心")] + public string WorkStation { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + public DateTime ExpiredTime { get; set; } + + /// + /// 工序 + /// + [Display(Name = "工序")] + public string Operation { get; set; } + + /// + /// 配送方式 + /// + [Display(Name = "配送方式")] + public EnumDistributionType DistributionType { get; set; } + + /// + /// 取整方式 + /// + [Display(Name = "取整方式")] + public EnumTruncType TruncType { get; set; } + + /// + /// 取整后数量 + /// + [Display(Name = "取整后数量")] + public decimal RoundedQty { get; set; } + + /// + /// 计划拆分规则 + /// + [Display(Name = "计划拆分规则")] + public EnumPlannedSplitRule PlannedSplitRule { get; set; } + + /// + /// 计划开始时间 + /// + [Display(Name = "计划开始时间")] + public DateTime PlanBeginTime { get; set; } + + /// + /// 每次配送数量 + /// + [Display(Name = "每次配送数量")] + public decimal DeliveryQty { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/IAssembleJobAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/IAssembleJobAppService.cs new file mode 100644 index 000000000..fae62f6c7 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/IAssembleJobAppService.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public interface IAssembleJobAppService + : ISfsJobAppServiceBase +{ + Task> CheckJobExistByItemCodeAndLocationCode(string itemCode, string locationCode); + + Task CancelByMaterialRequestAsync(string assembleNumber); + + Task> GetListByTypeAsync(SfsJobRequestInputBase requestInput, string requestType, + bool includeDetails = false, CancellationToken cancellationToken = default); + + Task> GetByRequestNumberAsync(string requestNumber); + + /// + /// 保存拆箱时涉及的明细修改 + /// + /// + Task SaveDetail_SplitPackingAsync(SplitPacking_UpdateJobDetailInput input); + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobCheckInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobCheckInput.cs new file mode 100644 index 000000000..ef75e7d73 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobCheckInput.cs @@ -0,0 +1,6 @@ +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleJobCheckInput : SfsJobCheckInputBase +{ + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobDetailInput.cs new file mode 100644 index 000000000..18b59ae9d --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobDetailInput.cs @@ -0,0 +1,134 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleJobDetailInput : SfsJobRecommendFromDetailInputBase, IHasToLocation +{ + + /// + /// 请求库位 + /// + [Display(Name = "请求库位")] + [Required(ErrorMessage = "{0}是必填项")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string RequestLocationCode { get; set; } + + /// + /// 到库位 + /// + [Display(Name = "到库位")] + [Required(ErrorMessage = "{0}是必填项")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ToLocationCode { get; set; } + + /// + /// 到库区 + /// + [Display(Name = "到库区")] + public string ToLocationArea { get; set; } + + /// + /// 到库位组 + /// + [Display(Name = "到库位组")] + public string ToLocationGroup { get; set; } + + /// + /// 到ERP库位 + /// + [Display(Name = "到ERP库位")] + [Required(ErrorMessage = "{0}是必填项")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ToLocationErpCode { get; set; } + + /// + /// 到仓库 + /// + [Display(Name = "到仓库")] + [Required(ErrorMessage = "{0}是必填项")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ToWarehouseCode { get; set; } + + /// + /// 在途库库位 + /// + [Display(Name = "在途库库位")] + public string OnTheWayLocationCode { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + [Display(Name = "工作中心")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string WorkStation { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + [Required(ErrorMessage = "{0}是必填项")] + public DateTime ExpiredTime { get; set; } + + /// + /// 工序 + /// + [Display(Name = "工序")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Operation { get; set; } + + /// + /// 配送方式 + /// + [Display(Name = "配送方式")] + public EnumDistributionType DistributionType { get; set; } + + /// + /// 取整方式 + /// + [Display(Name = "取整方式")] + public EnumTruncType TruncType { get; set; } + + /// + /// 取整后数量 + /// + [Display(Name = "取整后数量")] + public decimal RoundedQty { get; set; } + + /// + /// 计划拆分规则 + /// + [Display(Name = "计划拆分规则")] + public EnumPlannedSplitRule PlannedSplitRule { get; set; } + + /// + /// 计划开始时间 + /// + [Display(Name = "计划开始时间")] + public DateTime PlanBeginTime { get; set; } + + /// + /// 每次配送数量 + /// + [Display(Name = "每次配送数量")] + public decimal DeliveryQty { get; set; } + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobEditInput.cs new file mode 100644 index 000000000..8e719283c --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/AssembleJobs/Inputs/AssembleJobEditInput.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleJobEditInput : SfsJobCreateUpdateInputBase, ISfsJobCreateInput +{ + #region Create + /// + /// 上游任务编号 + /// + [Display(Name = "上游任务编号")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string UpStreamJobNumber { get; set; } + + /// + /// 要货单号 + /// + [Display(Name = "要货单号")] + [Required(ErrorMessage = "{0}是必填项")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string AssembleRequestNumber { get; set; } + + /// + /// 叫料请求类型 + /// + [Display(Name = "叫料请求类型")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string RequestType { get; set; } + + /// + /// 任务类型 + /// + [Display(Name = "任务类型")] + [Required(ErrorMessage = "{0}是必填项")] + public EnumJobType JobType { get; set; } + + /// + /// 是否自动完成 + /// + [Display(Name = "是否自动完成")] + [Required(ErrorMessage = "{0}是必填项")] + public bool IsAutoComplete { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + [Required(ErrorMessage = "{0}是必填项")] + public DateTime ExpiredTime { get; set; } + + /// + /// 任务明细 + /// + [Display(Name = "任务明细")] + [Required(ErrorMessage = "{0}是必填项")] + public List Details { get; set; } = new(); + + /// + /// 车间 + /// + [Display(Name = "车间")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Workshop { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + public bool UseOnTheWayLocation { get; set; } + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/AssembleNotePermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/AssembleNotePermissions.cs new file mode 100644 index 000000000..1b05f191c --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/AssembleNotePermissions.cs @@ -0,0 +1,30 @@ +using Volo.Abp.Authorization.Permissions; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public static class AssembleNotePermissions +{ + + public const string Default = StorePermissions.GroupName + "." + nameof(AssembleNote); + public const string Create = Default + "." + StorePermissions.CreateStr; + public const string Update = Default + "." + StorePermissions.UpdateStr; + public const string Delete = Default + "." + StorePermissions.DeleteStr; + + //自动发料记录 + public const string AutoAssembleNote = StorePermissions.GroupName + "." + nameof(AutoAssembleNote); + + //直接发料 + public const string DirectAssembleNote = StorePermissions.GroupName + "." + nameof(DirectAssembleNote); + + public static void AddAssembleNotePermission(this PermissionGroupDefinition permissionGroup) + { + var AssembleNotePermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(AssembleNote))); + AssembleNotePermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr)); + AssembleNotePermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr)); + AssembleNotePermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr)); + + permissionGroup.AddPermission(AutoAssembleNote, StorePermissionDefinitionProvider.L(nameof(AutoAssembleNote))); + permissionGroup.AddPermission(DirectAssembleNote, StorePermissionDefinitionProvider.L(nameof(DirectAssembleNote))); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDTO.cs new file mode 100644 index 000000000..6db88f8bb --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDTO.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleNoteDTO : SfsStoreDTOBase, IHasJobNumber, IHasRequestNumber +{ + + /// + /// 任务ID + /// + [Display(Name = "任务ID")] + public string JobNumber { get; set; } + + /// + /// 车间 + /// + [Display(Name = "车间")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Workshop { get; set; } + + /// + /// 请求代码 + /// + [Display(Name = "请求代码")] + public string RequestNumber { get; set; } + + /// + /// 叫料请求类型 + /// + [Display(Name = "叫料请求类型")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string RequestType { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + public bool UseOnTheWayLocation { get; set; } + + /// + /// 已确认 + /// + [Display(Name = "已确认")] + public bool Confirmed { get; set; } + + /// + /// 确认时间 + /// + [Display(Name = "确认时间")] + public DateTime? ConfirmTime { get; set; } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDetailDTO.cs new file mode 100644 index 000000000..cefbe75a5 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/DTOs/AssembleNoteDetailDTO.cs @@ -0,0 +1,42 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleNoteDetailDTO : SfsStoreRecommendFromDetailWithFromToDTOBase +{ + + /// + /// 发料时间 + /// + [Display(Name = "发料时间")] + public DateTime IssueTime { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + public DateTime ExpiredTime { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + [Display(Name = "工作中心")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string WorkStation { get; set; } + + /// + /// 在途库库位 + /// + [Display(Name = "在途库库位")] + public string OnTheWayLocationCode { get; set; } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/IAssembleNoteAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/IAssembleNoteAppService.cs new file mode 100644 index 000000000..af04bbaf4 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/IAssembleNoteAppService.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public interface IAssembleNoteAppService : ISfsStoreMasterReadOnlyAppServiceBase +{ + Task CreateAsync(AssembleNoteEditInput input); + + Task ConfirmAsync(Guid id); + + Task ConfirmAsync(string number); + + Task> GetListByTypeAsync(SfsStoreRequestInputBase requestInput, + string requestType, bool includeDetails = false, CancellationToken cancellationToken = default); + + Task> GetListUnConfirmedByTypeAsync(string requestType); +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteDetailInput.cs new file mode 100644 index 000000000..4a194dc44 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteDetailInput.cs @@ -0,0 +1,53 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleNoteDetailInput : SfsStoreRecommendFromDetailWithFromToInputBase +{ + + /// + /// 发料时间 + /// + [Display(Name = "发料时间")] + public DateTime IssueTime { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + public DateTime ExpiredTime { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + [Display(Name = "工作中心")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string WorkStation { get; set; } + + /// + /// 在途库库位 + /// + [Display(Name = "在途库库位")] + public string OnTheWayLocationCode { get; set; } + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteEditInput.cs new file mode 100644 index 000000000..b3c23c67f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteEditInput.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleNoteEditInput : SfsStoreCreateOrUpdateInputBase +{ + #region Base + /// + /// 已确认 + /// + [Display(Name = "已确认")] + public bool Confirmed { get; set; } + #endregion + + #region Create + /// + /// 发料记录号 + /// + [Display(Name = "发料记录号")] + public string Number { get; set; } + + /// + /// 任务ID + /// + [Display(Name = "任务ID")] + [Required(ErrorMessage = "{0}是必填项")] + public string JobNumber { get; set; } + + /// + /// 车间 + /// + [Display(Name = "车间")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Workshop { get; set; } + + /// + /// 明细列表 + /// + [Display(Name = "明细列表")] + public List Details { get; set; } + + /// + /// 请求号码 + /// + [Display(Name = "请求号码")] + public string RequestNumber { get; set; } + + /// + /// 叫料请求类型 + /// + [Display(Name = "叫料请求类型")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string RequestType { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + public bool UseOnTheWayLocation { get; set; } + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteImportInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteImportInput.cs new file mode 100644 index 000000000..415f3334c --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/AssembleNotes/Inputs/AssembleNoteImportInput.cs @@ -0,0 +1,33 @@ +using System.ComponentModel.DataAnnotations; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleNoteImportInput : SfsStoreImportInputBase, IHasJobNumber, IHasRequestNumber +{ + /// + /// 任务ID + /// + [Display(Name = "任务ID")] + public string JobNumber { get; set; } + + /// + /// 车间 + /// + [Display(Name = "车间")] + public string Workshop { get; set; } + + public string RequestNumber { get; set; } + + /// + /// 叫料请求类型 + /// + [Display(Name = "叫料请求类型")] + public string RequestType { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + [Required(ErrorMessage = "{0}是必填项")] + public bool UseOnTheWayLocation { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Permissions/StorePermissionDefinitionProvider.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Permissions/StorePermissionDefinitionProvider.cs index c99e2abe8..52618b9ac 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Permissions/StorePermissionDefinitionProvider.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Permissions/StorePermissionDefinitionProvider.cs @@ -27,9 +27,11 @@ public class StorePermissionDefinitionProvider : PermissionDefinitionProvider storeGroup.AddPutawayNotePermission(); storeGroup.AddMaterialRequestPermission(); storeGroup.AddInjectionRequestPermission(); + storeGroup.AddAssembleRequestPermission(); storeGroup.AddContainerRequestPermission(); storeGroup.AddIssueNotePermission(); storeGroup.AddInjectionNotePermission(); + storeGroup.AddAssembleNotePermission(); storeGroup.AddContainerNotePermission(); storeGroup.AddUnplannedReceiptNotePermission(); storeGroup.AddUnplannedIssueNotePermission(); @@ -93,6 +95,7 @@ public class StorePermissionDefinitionProvider : PermissionDefinitionProvider storeGroup.AddPutawayJobPermission(); storeGroup.AddIssueJobPermission(); storeGroup.AddInjectionJobPermission(); + storeGroup.AddAssembleJobPermission(); storeGroup.AddContainerJobPermission(); storeGroup.AddDeliverJobPermission(); storeGroup.AddPurchaseReturnJobPermission(); diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/AssembleRequestPermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/AssembleRequestPermissions.cs new file mode 100644 index 000000000..f7c0f9228 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/AssembleRequestPermissions.cs @@ -0,0 +1,27 @@ +using Volo.Abp.Authorization.Permissions; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public static class AssembleRequestPermissions +{ + + public const string Default = StorePermissions.GroupName + "." + nameof(AssembleRequest); + public const string Create = Default + "." + StorePermissions.CreateStr; + public const string Update = Default + "." + StorePermissions.UpdateStr; + public const string Delete = Default + "." + StorePermissions.DeleteStr; + + //自动叫料申请 + public const string AutoAssembleRequest = StorePermissions.GroupName + "." + nameof(AutoAssembleRequest); + + public static void AddAssembleRequestPermission(this PermissionGroupDefinition permissionGroup) + { + var AssembleRequestPermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(AssembleRequest))); + AssembleRequestPermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr)); + AssembleRequestPermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr)); + AssembleRequestPermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr)); + + permissionGroup.AddPermission(AutoAssembleRequest, StorePermissionDefinitionProvider.L(nameof(AutoAssembleRequest))); + + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDTO.cs new file mode 100644 index 000000000..7582d35a7 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDTO.cs @@ -0,0 +1,40 @@ +using System.ComponentModel.DataAnnotations; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleRequestDTO : SfsStoreRequestDTOBase, IHasNumber +{ + /// + /// 叫料类型 + /// + [Display(Name = "叫料类型")] + public string Type { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + public string ProdLine { get; set; } + + /// + /// 是否使用在途库 + /// + [Display(Name = "是否使用在途库")] + public bool IsUseOnTheWayLocation { get; set; } + + /// + /// 可用来源库位Json集合 + /// + public string FromLocationCodeJsonList { get; set; } + + /// + /// 叫料库位 + /// + public string ToLocationCode { get; set; } + + /// + /// 目标ERP储位 + /// + [Display(Name = "目标ERP储位")] + public string ToLocationErpCode { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDetailDTO.cs new file mode 100644 index 000000000..71a9dbcf0 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/DTOs/AssembleRequestDetailDTO.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleRequestDetailDTO : SfsStoreDetailWithQtyDTOBase +{ + /// + /// 已发数量 + /// + [Display(Name = "已发数量")] + public decimal IssuedQty { get; set; } + + /// + /// 已收数量 + /// + [Display(Name = "已收数量")] + public decimal ReceivedQty { get; set; } + + /// + /// 明细状态 + /// + [Display(Name = "明细状态")] + public EnumStatus Status { get; set; } + + /// + /// 请求未发 + /// + [Display(Name = "请求未发")] + [NotMapped] + public decimal ToBeIssuedQty => Qty - IssuedQty; + + /// + /// 已发未收 + /// + [Display(Name = "已发未收")] + [NotMapped] + public decimal ToBeReceivedQty => IssuedQty - ReceivedQty; + + /// + /// 请求未收 + /// + [Display(Name = "请求未收")] + [NotMapped] + public decimal NotFinishQty => Qty - ReceivedQty; + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/IAssembleRequestAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/IAssembleRequestAppService.cs new file mode 100644 index 000000000..34e3ec465 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/IAssembleRequestAppService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public interface IAssembleRequestAppService + : ISfsStoreRequestMasterAppServiceBase + +{ + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestDetailInput.cs new file mode 100644 index 000000000..befe44e2f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestDetailInput.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleRequestDetailInput : SfsStoreDetailWithQtyInputBase +{ + /// + /// 目标库位 + /// + [Display(Name = "目标库位")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ToLocationCode { get; set; } + + /// + /// 来源库区 + /// + [Display(Name = "来源库区")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string FromLocationArea { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + [Display(Name = "工作中心")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string WorkStation { get; set; } + + /// + /// 过期时间 + /// + [Display(Name = "过期时间")] + public DateTime ExpiredTime { get; set; } + + /// + /// 状态 + /// + [Display(Name = "状态")] + public EnumRequestStatus RequestStatus { get; set; } = EnumRequestStatus.New; + + /// + /// ERP储位 + /// + [Display(Name = "ERP储位")] + public string ToLocationErpCode { get; set; } + + /// + /// 已发数量 + /// + [Display(Name = "已发数量")] + public decimal IssuedQty { get; set; } + + /// + /// 已收数量 + /// + [Display(Name = "已收数量")] + public decimal ReceivedQty { get; set; } + + /// + /// 明细状态 + /// + [Display(Name = "明细状态")] + public EnumStatus Status { get; set; } + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } + + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestEditInput.cs new file mode 100644 index 000000000..2dbba1a36 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestEditInput.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +public class AssembleRequestEditInput : SfsStoreRequestCreateOrUpdateInputBase +{ + #region Base + /// + /// 车间 + /// + [Display(Name = "车间")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Workshop { get; set; } + + /// + /// 生产线 + /// + [Display(Name = "生产线")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string ProdLine { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + public bool UseOnTheWayLocation { get; set; } + #endregion + + #region Create + /// + /// 要货单号 + /// + [Display(Name = "要货单号")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string Number { get; set; } + + /// + /// 叫料类型 + /// + [Display(Name = "叫料类型")] + public string Type { get; set; } + + /// + /// 备料计划单号 + /// + [Display(Name = "备料计划单号")] + [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")] + public string PreparationPlanNumber { get; set; } + + /// + /// 明细列表 + /// + [Display(Name = "明细列表")] + public List Details { get; set; } = new List(); + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestImportInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestImportInput.cs new file mode 100644 index 000000000..d5fe8bc84 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/MaterialRequests/AssembleRequests/Inputs/AssembleRequestImportInput.cs @@ -0,0 +1,53 @@ +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Application.Contracts; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application.Contracts; + +[Display(Name = "叫料申请")] +public class AssembleRequestImportInput : SfsStoreImportInputBase +{ + /// + /// 叫料类型 + /// + [Display(Name = "叫料类型")] + [Required(ErrorMessage = "{0}是必填项")] + [ImporterHeader(Name = "叫料类型")] + [ExporterHeader(DisplayName = "叫料类型")] + [ValueMapping("人工拉动", EnumMaterialRequestType.Issue_Manual)] + public string Type { get; set; } + + /// + /// 物品代码 + /// + [Display(Name = "物品代码")] + [Required] + public string ItemCode { get; set; } + + /// + /// 目标库位 + /// + [Display(Name = "目标库位")] + [Required] + public string ToLocationCode { get; set; } + + /// + /// 来源库区 + /// + [Display(Name = "调出库区")] + [Required] + public string FromLocationArea { get; set; } + + /// + /// 数量 + /// + [Display(Name = "数量")] + [Required(ErrorMessage = "{0}是必填项")] + public decimal Qty { get; set; } + + /// + /// 备注 + /// + [Display(Name = "备注")] + public string Remark { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAppService.cs new file mode 100644 index 000000000..e58d26e1b --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAppService.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.ObjectMapping; +using Win_in.Sfs.Basedata.Domain.Shared; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; +using Win_in.Sfs.Wms.Store.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application; + +[Authorize] +[Route($"{StoreConsts.RootPath}assemble-job")] +public class AssembleJobAppService + : SfsJobAppServiceBase, + IAssembleJobAppService +{ + private readonly IAssembleJobManager _assembleJobManager; + + public AssembleJobAppService( + IAssembleJobRepository repository, IAssembleJobManager assembleJobManager + ) : base(repository, assembleJobManager) + { + _assembleJobManager = assembleJobManager; + } + + /// + /// 根据物品和库位 检查是否存在发料任务 + /// + /// + /// + /// + /// + [Authorize] + [HttpGet("check-job-exist")] + public virtual async Task> CheckJobExistByItemCodeAndLocationCode(string itemCode, + string locationCode) + { + var entities = await _repository.GetListAsync(c => + c.Details.Any(p => + (p.ItemCode == itemCode && p.RecommendFromLocationCode == locationCode) || + (p.ItemCode == itemCode && p.ToLocationCode == locationCode)) + && (c.JobStatus == EnumJobStatus.Open || c.JobStatus == EnumJobStatus.Doing), true).ConfigureAwait(false); + var dtos = ObjectMapper.Map, List>(entities); + return dtos; + } + + [HttpPost("cancel-by-request/{assembleNumber}")] + public virtual async Task CancelByMaterialRequestAsync(string assembleNumber) + { + var entities = await _repository.GetListAsync(p => p.AssembleRequestNumber == assembleNumber).ConfigureAwait(false); + foreach (var entity in entities) + { + await _assembleJobManager.CancelAsync(entity).ConfigureAwait(false); + } + } + + [HttpPost("invalid")] + public override async Task CancelAsync(Guid id) + { + var assembleJob = await _repository.GetAsync(id).ConfigureAwait(false); + if (assembleJob == null) + { + throw new UserFriendlyException($"未找到ID为 {id} 的任务"); + } + + await _assembleJobManager.CancelAsync(assembleJob).ConfigureAwait(false); + + } + + /// + /// 根据叫料请求类型获取发料任务 + /// + /// + /// + /// 叫料请求类型: + /// 人工拉动:Issue_Manual; + /// 线边拉动:Issue_WIP; + /// + /// + /// + /// + [HttpPost("by-type/{requestType}")] + public virtual async Task> GetListByTypeAsync(SfsJobRequestInputBase requestInput, + string requestType, bool includeDetails = false, CancellationToken cancellationToken = default) + { + Expression> expression = p => p.RequestType == requestType; + if (requestInput.Condition.Filters?.Count > 0) + { + expression = expression.And(requestInput.Condition.Filters.ToLambda()); + } + + return await GetPagedListAsync(expression, requestInput.SkipCount, requestInput.MaxResultCount, + requestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false); + + } + + [HttpPost("by-request-number/{requestNumber}")] + public virtual async Task> GetByRequestNumberAsync(string requestNumber) + { + var entitys = await _repository.GetListAsync(p => p.AssembleRequestNumber == requestNumber).ConfigureAwait(false); + return ObjectMapper.Map, List>(entitys); + } + + /// + /// 保存拆箱时涉及的明细修改 + /// + /// + [HttpPost("save-detail-split-packing")] + public virtual async Task SaveDetail_SplitPackingAsync(SplitPacking_UpdateJobDetailInput input) + { + var job = await _repository.FindAsync(p => p.Number == input.Number).ConfigureAwait(false); + AssembleJobDetail detail = job.Details.FirstOrDefault(p => p.RecommendPackingCode == input.FromPackingCode ); /*&& p.HandledQty == input.FromQty*/ + if (detail == null) + { + //throw new UserFriendlyException($"根据HandledPackingCode={input.FromPackingCode}取AssembleJobDetail表为空!"); + throw new UserFriendlyException($"根据RecommendPackingCode={input.FromPackingCode}取AssembleJobDetail表为空!"); + } + //插入目标箱 + var newDetail = CommonHelper.CloneObj(detail); + newDetail.SetId(GuidGenerator.Create()); + newDetail.RecommendPackingCode = input.ToPackingCode; + newDetail.RecommendQty = input.ToQty; + newDetail.HandledPackingCode = detail.HandledPackingCode.HasValue() ? input.ToPackingCode : null; //源实际实际箱码有值,则新记录实际箱码有值 + newDetail.HandledQty = detail.HandledQty > 0 ? input.ToQty : 0; + //newDetail.CreationTime = CommonHelper.CurTime; + job.Details.Add(newDetail); + //修改源箱 + detail.RecommendQty = input.FromQty - input.ToQty; + detail.HandledQty = detail.HandledQty > 0 ? input.FromQty - input.ToQty : 0; + var entity = await _repository.UpdateAsync(job).ConfigureAwait(false); + var ret = ObjectMapper.Map(entity); + return ret; + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAutoMapperProfile.cs new file mode 100644 index 000000000..d60824554 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleJobs/AssembleJobAutoMapperProfile.cs @@ -0,0 +1,29 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application; + +public partial class StoreApplicationAutoMapperProfile : Profile +{ + private void AssembleJobAutoMapperProfile() + { + CreateMap() + .ReverseMap(); + + CreateMap() + ; + + CreateMap() + ; + + CreateMap() + .IgnoreAuditedObjectProperties() + .Ignore(x => x.MasterID) + .Ignore(x => x.TenantId) + .Ignore(x => x.Number) + .Ignore(x => x.Id); + + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAppService.cs new file mode 100644 index 000000000..32675638b --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAppService.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Entities; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Event; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; +using Win_in.Sfs.Wms.Store.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application; + +[Authorize] +[Route($"{StoreConsts.RootPath}assemble-note")] +public class AssembleNoteAppService : + SfsStoreWithDetailsAppServiceBase, + IAssembleNoteAppService +{ + private readonly IAssembleNoteManager _assembleNoteManager; + + public AssembleNoteAppService( + IAssembleNoteRepository repository, + IAssembleNoteManager assembleNoteManager + ) : base(repository) + { + _assembleNoteManager = assembleNoteManager; + } + + [HttpPost("")] + //[Authorize(AssembleNotePermissions.Create)] + public override async Task CreateAsync(AssembleNoteEditInput input) + { + var entity = ObjectMapper.Map(input); + await _assembleNoteManager.CreateAsync(entity).ConfigureAwait(false); + var dto = ObjectMapper.Map(entity); + return dto; + } + + /// + /// 确认对应的记录单 + /// + /// + /// + [HttpPost("confirm/{id}")] + public virtual async Task ConfirmAsync(Guid id) + { + var assembleNote= await _repository.GetAsync(id).ConfigureAwait(false); + assembleNote.Confirmed = true; + assembleNote=await _repository.UpdateAsync(assembleNote).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new SfsConfirmedEntityEventData(assembleNote), false).ConfigureAwait(false); + return ObjectMapper.Map(assembleNote); + } + + [HttpPost("confirm-by-number/{number}")] + public virtual async Task ConfirmAsync(string number) + { + var entity = await _repository.FindAsync(p => p.Number == number).ConfigureAwait(false); + Check.NotNull(entity, nameof(AssembleNote)); + var result = await _assembleNoteManager.ConfirmAsync(entity.Id).ConfigureAwait(false); + var dto = ObjectMapper.Map(result); + return dto; + } + /// + /// 根据叫料请求类型获取发料记录 + /// + /// + /// + /// 叫料请求类型: + /// 人工拉动:Issue_Manual; + /// 线边拉动:Issue_WIP; + /// + /// + /// + /// + [HttpPost("by-type/{requestType}")] + public virtual async Task> GetListByTypeAsync(SfsStoreRequestInputBase requestInput, + string requestType, bool includeDetails = false, CancellationToken cancellationToken = default) + { + Expression> expression = p => p.RequestType == requestType; + if (requestInput.Condition.Filters?.Count > 0) + { + expression = expression.And(requestInput.Condition.Filters.ToLambda()); + } + + return await GetPagedListAsync(expression, requestInput.SkipCount, requestInput.MaxResultCount, + requestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false); + } + + [HttpGet("list/un-confirmed/{requestType}")] + public virtual async Task> GetListUnConfirmedByTypeAsync(string requestType) + { + var entities = await _repository.GetListAsync(c => !c.Confirmed && c.RequestType == requestType) + .ConfigureAwait(false); + + var dtos = ObjectMapper.Map, List>(entities); + + return dtos; + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAutoMapperProfile.cs new file mode 100644 index 000000000..04a6875d3 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/AssembleNotes/AssembleNoteAutoMapperProfile.cs @@ -0,0 +1,31 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application; + +public partial class StoreApplicationAutoMapperProfile : Profile +{ + private void AssembleNoteAutoMapperProfile() + { + CreateMap() + .ReverseMap(); + + CreateMap(); + + CreateMap() + .IgnoreAuditedObjectProperties() + .Ignore(x => x.MasterID) + .Ignore(x => x.TenantId) + .Ignore(x => x.Number) + .Ignore(x => x.Id); + + CreateMap() + .IgnoreAuditedObjectProperties() + .Ignore(x => x.TenantId) + .Ignore(x => x.Number) + .Ignore(x => x.Id); + ; + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAppService.cs new file mode 100644 index 000000000..567997a51 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAppService.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Office.PowerPoint.Y2021.M06.Main; +using IdentityModel; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.ObjectMapping; +using Win_in.Sfs.Basedata.Application.Contracts; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Shared.Event; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; +using Win_in.Sfs.Wms.Store.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Application; + +/// +/// 装配叫料 +/// +[Authorize] +[Route($"{StoreConsts.RootPath}assemble-request")] +public class AssembleRequestAppService : SfsStoreRequestAppServiceBase, + IAssembleRequestAppService +{ + private readonly IAssembleRequestManager _assembleRequestManager; + private readonly IItemStoreRelationAppService _itemStoreRelationApp; + private readonly IAreaAppService _areaApp; + private readonly ILocationAppService _locationAppService; + private readonly IItemBasicAppService _itemBasicAppService; + private readonly IProductionLineAppService _productionLineAppService; + private readonly IInjectionJobAppService _issueJobAppService; + public AssembleRequestAppService( + IAssembleRequestRepository repository, + IAssembleRequestManager assembleRequestManager, + IPreparationPlanManager preparationPlanManager, + IItemStoreRelationAppService itemStoreRelationApp, + IAreaAppService areaApp, + ILocationAppService locationAppService, + IItemBasicAppService itemBasicAppService, + IProductionLineAppService productionLineAppService, + IInjectionJobAppService issueJobAppService) + : base(repository, assembleRequestManager) + { + _assembleRequestManager = assembleRequestManager; + _itemStoreRelationApp = itemStoreRelationApp; + _areaApp = areaApp; + _locationAppService = locationAppService; + _itemBasicAppService = itemBasicAppService; + _productionLineAppService = productionLineAppService; + _issueJobAppService = issueJobAppService; + } + + + #region 东阳V2 + + public override async Task HandleAsync(Guid id) + { + var entity = await _repository.GetAsync(id).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new SfsHandledEntityEventData(entity), false).ConfigureAwait(false); + return ObjectMapper.Map(entity); + } + + [HttpPost("")] + //[Authorize(AssembleRequestPermissions.Create)] + public override async Task CreateAsync(AssembleRequestEditInput input) + { + foreach (var item in input.Details) + { + if (item.Qty <= 0) + { + throw new UserFriendlyException($"{item.ItemCode} 物料的需求量必须大于0"); + } + } + + foreach (var detailInput in input.Details) //赋值生产线 + { + var toLocationDto = await _locationAppService.GetByCodeAsync(detailInput.ToLocationCode).ConfigureAwait(false); + CheckLocation(toLocationDto, detailInput.ToLocationCode); + var itemBasicDto = await _itemBasicAppService.GetByCodeAsync(detailInput.ItemCode).ConfigureAwait(false); + CheckItemBasic(itemBasicDto, detailInput.ItemCode); + + detailInput.ProdLine = detailInput.ToLocationCode; + detailInput.ToLocationErpCode = toLocationDto.ErpLocationCode; + } + + input.AutoSubmit = true; + input.AutoAgree = true; + input.AutoHandle = true; + input.AutoCompleteJob = false; + input.DirectCreateNote = false; + + var entity = ObjectMapper.Map(input); + + var result = await _assembleRequestManager.CreateAsync(entity).ConfigureAwait(false); + + var dto = ObjectMapper.Map(result); + + return dto; + } + + //[Authorize(AssembleRequestPermissions.Create)] + [HttpPost("create-and-handle")] + public async Task CreateAndHandleAsync(AssembleRequestEditInput input) + { + var assembleRequestDto = await CreateAsync(input).ConfigureAwait(false); + + await HandleAsync(assembleRequestDto.Id).ConfigureAwait(false); + + return assembleRequestDto; + } + + #endregion + + /// + /// 根据类型 获取叫料申请 + /// + /// + /// + [HttpGet("list/by-type/{type}")] + public virtual async Task> GetListByTypeAsync(string type) + { + var entities = await _repository.GetListAsync(c => c.Type == type).ConfigureAwait(false); + + var dtos = ObjectMapper.Map, List>(entities); + + return dtos; + } + + #region 导入 + + /// + /// 用来重写 导入数据时可以加工数据 + /// + /// + /// + protected override async Task> ImportProcessingEntityAsync( + Dictionary dictionary) + { + var addList = dictionary.Where(p => p.Value == EntityState.Added).Select(p => p.Key); + + foreach (var assembleRequest in addList) + { + assembleRequest.Worker = CurrentUser.GetUserName(); + assembleRequest.CreatorId = CurrentUser.Id; + if (assembleRequest.Type == EnumTransSubType.Issue_Manual.GetDisplayName()) + { + assembleRequest.Type = EnumTransSubType.Issue_Manual.ToString(); + } + + foreach (var detail in assembleRequest.Details) + { + var locationDto = await _locationAppService.GetByCodeAsync(detail.ToLocationCode).ConfigureAwait(false); + CheckLocation(locationDto, detail.ToLocationCode); + + var itemBasicDto = await _itemBasicAppService.GetByCodeAsync(detail.ItemCode).ConfigureAwait(false); + CheckItemBasic(itemBasicDto, detail.ItemCode); + + detail.ToLocationArea = locationDto.AreaCode; + detail.ToLocationErpCode = locationDto.ErpLocationCode; + detail.ToLocationGroup = locationDto.LocationGroupCode; + detail.ToWarehouseCode = locationDto.WarehouseCode; + detail.ItemDesc1 = itemBasicDto.Desc1; + detail.ItemDesc2 = itemBasicDto.Desc2; + detail.ItemName = itemBasicDto.Name; + detail.Uom = itemBasicDto.BasicUom; + } + } + + return dictionary; + } + + /// + /// 导入验证 + /// + /// + /// + /// + protected override async Task ValidateImportModelAsync(AssembleRequestImportInput model, + List validationRresult) + { + _ = new Dictionary(); + _ = await CheckItemBasicAsync(model, validationRresult).ConfigureAwait(false); + _ = await CheckLocationAsync(model, validationRresult).ConfigureAwait(false); + await CheckAreaAsync(model, validationRresult).ConfigureAwait(false); + await CheckStoreRelationAsync(model, validationRresult).ConfigureAwait(false); + } + + #region 校验 + + protected override async Task ValidateImportEntities(Dictionary dict) + { + foreach (var entity in dict.Keys) + { + var tranType = await TransactionTypeAclService + .GetByTransTypeAsync(EnumTransType.Issue, EnumTransSubType.None).ConfigureAwait(false); + + Check.NotNull(tranType, "事务类型", "事务类型不存在"); + + entity.AutoCompleteJob = tranType.AutoCompleteJob; + entity.AutoSubmit = tranType.AutoSubmitRequest; + entity.AutoAgree = tranType.AutoAgreeRequest; + entity.AutoHandle = tranType.AutoHandleRequest; + entity.DirectCreateNote = tranType.DirectCreateNote; + } + + return await base.ValidateImportEntities(dict).ConfigureAwait(false); + } + + protected async Task CheckItemBasicAsync(AssembleRequestImportInput importInput, + List validationRresult) + { + var item = await _itemBasicAppService.GetByCodeAsync(importInput.ItemCode).ConfigureAwait(false); + if (item == null) + { + validationRresult.Add(new ValidationResult($"物品代码{importInput.ItemCode}不存在", new[] { "物品代码" })); + } + else if (item.StdPackQty == 0) + { + validationRresult.Add( + new ValidationResult($"物品代码{importInput.ItemCode}的物品信息中标准包装等于0或不存在", new[] { "标准包装" })); + } + + return item; + } + + protected async Task CheckLocationAsync(AssembleRequestImportInput importInput, + List validationRresult) + { + var location = await _locationAppService.GetByCodeAsync(importInput.ToLocationCode).ConfigureAwait(false); + if (location == null) + { + validationRresult.Add(new ValidationResult($"目标库位{importInput.ToLocationCode}不存在", new[] { "目标库位" })); + } + + return location; + } + + protected async Task CheckAreaAsync(AssembleRequestImportInput importInput, + List validationRresult) + { + var area = await _areaApp.GetByCodeAsync(importInput.FromLocationArea).ConfigureAwait(false); + if (area == null) + { + validationRresult.Add(new ValidationResult($"调出库区{importInput.FromLocationArea}不存在", new[] { "调出库区" })); + } + } + + protected async Task CheckStoreRelationAsync(AssembleRequestImportInput importInput, + List validationRresult) + { + var itemStoreRelation = await _itemStoreRelationApp + .GetFirstAsync(importInput.ItemCode, importInput.ToLocationCode).ConfigureAwait(false); + if (itemStoreRelation == null) + { + validationRresult.Add(new ValidationResult( + $"物品代码{importInput.ItemCode}与目标库位{importInput.ToLocationCode}不存在对应关", new[] { "物品库位对应关系" })); + } + } + + #endregion + + #endregion + + #region 校验 + + private void CheckItemBasic(ItemBasicDTO ItemBasicDto, string itemCode) + { + if (ItemBasicDto == null) + { + throw new UserFriendlyException($"物品代码为【{itemCode}】不存在"); + } + } + + private void CheckLocation(LocationDTO LocationDto, string LocationCode) + { + if (LocationDto == null) + { + throw new UserFriendlyException($"库位代码为【{LocationCode}】不存在"); + } + + if (LocationDto.Type != EnumLocationType.WIP) + { + throw new UserFriendlyException($"库位代码【{LocationCode}】不是【{EnumLocationType.WIP.GetDisplayName()}】类型"); + } + } + + + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAutoMapperProfile.cs new file mode 100644 index 000000000..182f8a6ed --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/MaterialRequests/AssembleRequests/AssembleRequestAutoMapperProfile.cs @@ -0,0 +1,72 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Application; + +public partial class StoreApplicationAutoMapperProfile : Profile +{ + private void AssembleRequestAutoMapperProfile() + { + CreateMap() + .ReverseMap(); + + CreateMap() + .ReverseMap(); + + CreateMap() + .IgnoreAuditedObjectProperties() + .Ignore(x => x.ToLocationArea) + .Ignore(x => x.ToLocationGroup) + .Ignore(x => x.ToWarehouseCode) + .Ignore(x => x.MasterID) + .Ignore(x => x.TenantId) + .Ignore(x => x.Number) + .Ignore(x => x.Id); + + CreateMap() + .IgnoreAuditedObjectProperties() + .ForMember(x => x.Type, y => y.MapFrom(t => t.Type.ToString())) + .Ignore(x => x.ProdLine) + .Ignore(x => x.UseOnTheWayLocation) + .Ignore(x => x.Details) + .Ignore(x => x.Remark) + .Ignore(x => x.TenantId) + .Ignore(x => x.Number) + .Ignore(x => x.RequestStatus) + .Ignore(x => x.ConcurrencyStamp) + .Ignore(x => x.ExtraProperties) + .Ignore(x => x.ActiveDate) + .Ignore(x => x.Remark); + + CreateMap() + .IgnoreAuditedObjectProperties() + .ForMember(x => x.Status, y => y.MapFrom(t => EnumStatus.Open)) + .Ignore(x => x.ToLocationErpCode) + .Ignore(x => x.ToWarehouseCode) + .Ignore(x => x.ToLocationArea) + .Ignore(x => x.ToLocationGroup) + .Ignore(x => x.ItemName).Ignore(x => x.ItemDesc1).Ignore(x => x.ItemDesc2) + .Ignore(x => x.ProdLine) + .Ignore(x => x.WorkStation) + .Ignore(x => x.ExpiredTime) + .Ignore(x => x.IssuedQty) + .Ignore(x => x.ReceivedQty) + .Ignore(x => x.ToBeIssuedQty) + .Ignore(x => x.ToBeReceivedQty) + .Ignore(x => x.NotFinishQty) + .Ignore(x => x.StdPackQty) + .Ignore(x => x.Uom) + .Ignore(x => x.TenantId) + .Ignore(x => x.MasterID) + .Ignore(x => x.Number) + .Ignore(x => x.Id) + .Ignore(x => x.Remark); + CreateMap() + .IgnoreAuditedObjectProperties() + .Ignore(x => x.RequestStatus) + .Ignore(x => x.ConcurrencyStamp).Ignore(x => x.Id); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/StoreApplicationAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/StoreApplicationAutoMapperProfile.cs index a6b97f3ea..8c64426d3 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/StoreApplicationAutoMapperProfile.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/StoreApplicationAutoMapperProfile.cs @@ -15,6 +15,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile ItemTransformRequestAutoMapperProfile(); MaterialRequestAutoMapperProfile(); InjectionRequestAutoMapperProfile(); + AssembleRequestAutoMapperProfile(); ProductionReturnRequestAutoMapperProfile(); ProductReceiptRequestAutoMapperProfile(); UnplannedIssueRequestAutoMapperProfile(); @@ -66,6 +67,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile IsolationNoteAutoMapperProfile(); IssueNoteAutoMapperProfile(); InjectionNoteAutoMapperProfile(); + AssembleNoteAutoMapperProfile(); ContainerNoteAutoMapperProfile(); ItemTransformNoteAutoMapperProfile(); JisDeliverNoteAutoMapperProfile(); @@ -100,6 +102,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile InspectJobAutoMapperProfile(); IssueJobAutoMapperProfile(); InjectionJobAutoMapperProfile(); + AssembleJobAutoMapperProfile(); ContainerJobAutoMapperProfile(); JisDeliverJobAutoMapperProfile(); ProductReceiveJobAutoMapperProfile(); diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJob.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJob.cs new file mode 100644 index 000000000..74b1b7e0d --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJob.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Win_in.Sfs.Shared.Domain.Entities; + +namespace Win_in.Sfs.Wms.Store.Domain; + +/// +/// 装配发料任务 +/// +[Display(Name = "装配发料任务")] +public class AssembleJob : SfsJobAggregateRootBase +{ + /// + /// 叫料请求类型 + /// + [IgnoreUpdate] + public string RequestType { get; set; } + + /// + /// 生产线 + /// + [IgnoreUpdate] + public string ProdLine { get; set; } + + /// + /// 要货单号 + /// + [IgnoreUpdate] + public string AssembleRequestNumber { get; set; } + + /// + /// 车间 + /// + [IgnoreUpdate] + public string Workshop { get; set; } + + /// + /// 使用在途库 + /// + [Display(Name = "使用在途库")] + [IgnoreUpdate] + public bool UseOnTheWayLocation { get; set; } + + /// + /// 任务明细 + /// + [IgnoreUpdate] + public override List Details { get; set; } = new List(); + + /// + /// 设置任务明细的实际库位和实际数量 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task BuildDetail(Guid id, string handledLocationCode, string handledLocationErpCode, + string handledWarehouseCode, decimal handledQty, string handledSupplierBatch, DateTime handledArriveDate, DateTime handledProduceDate, DateTime handledExpireDate, + string handledContainerCode, string handledLot, string handledPackingCode) + { + var detail = GetDetail(id); + detail.HandledFromLocationCode = handledLocationCode; + detail.HandledFromLocationErpCode = handledLocationErpCode; + detail.HandledFromWarehouseCode = handledWarehouseCode; + detail.HandledQty = handledQty; + detail.HandledSupplierBatch = handledSupplierBatch; + detail.HandledArriveDate = handledArriveDate; + detail.HandledProduceDate = handledProduceDate; + detail.HandledExpireDate = handledExpireDate; + detail.HandledContainerCode = handledContainerCode; + detail.HandledLot = handledLot; + detail.HandledPackingCode = handledPackingCode; + await Task.CompletedTask.ConfigureAwait(false); + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobDetail.cs new file mode 100644 index 000000000..02d48d84f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobDetail.cs @@ -0,0 +1,108 @@ +using System; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public class AssembleJobDetail : SfsJobRecommendFromDetailEntityBase, IHasToLocation +{ + /// + /// 请求库位 + /// + public string RequestLocationCode { get; set; } + + /// + /// 到库位 + /// + public string ToLocationCode { get; set; } + + /// + /// 到库区 + /// + public string ToLocationArea { get; set; } + + /// + /// 到库位组 + /// + public string ToLocationGroup { get; set; } + + /// + /// 到ERP库位 + /// + public string ToLocationErpCode { get; set; } + + /// + /// 到仓库 + /// + public string ToWarehouseCode { get; set; } + + /// + /// 在途库库位 + /// + public string OnTheWayLocationCode { get; set; } + + /// + /// 生产线 + /// + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + public string WorkStation { get; set; } + + /// + /// 过期时间 + /// + public DateTime ExpiredTime { get; set; } + + /// + /// 工序 + /// + public string Operation { get; set; } + + /// + /// 配送方式 + /// + public EnumDistributionType DistributionType { get; set; } + + /// + /// 取整方式 + /// + public EnumTruncType TruncType { get; set; } + + /// + /// 取整后数量 + /// + public decimal RoundedQty { get; set; } + + /// + /// 计划拆分规则 + /// + public EnumPlannedSplitRule PlannedSplitRule { get; set; } + + /// + /// 计划开始时间 + /// + public DateTime PlanBeginTime { get; set; } + + /// + /// 每次配送数量 + /// + public decimal DeliveryQty { get; set; } + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } + + public void SetId(Guid id) + { + this.Id = id; + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobManager.cs new file mode 100644 index 000000000..cd421f475 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/AssembleJobManager.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Volo.Abp.Users; +using Volo.Abp.Validation; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public class AssembleJobManager : SfsJobManagerBase, IAssembleJobManager +{ + + public AssembleJobManager( + IAssembleJobRepository repository + ) : base(repository) + { + } + + /// + /// 执行任务 发料任务 + /// + /// + /// + /// + /// + public override async Task CompleteAsync(AssembleJob input, ICurrentUser user) + { + var entity = await Repository.FindAsync(input.Id).ConfigureAwait(false); + + foreach (var detail in input.Details) + { + //发料子任务 赋值实际转移 + await entity.BuildDetail(detail.Id, + detail.HandledFromLocationCode, + detail.HandledFromLocationErpCode, + detail.HandledFromWarehouseCode, + detail.HandledQty, + detail.HandledSupplierBatch, + detail.HandledArriveDate, + detail.HandledProduceDate, + detail.HandledExpireDate, + detail.HandledContainerCode, + detail.HandledLot, + detail.HandledPackingCode).ConfigureAwait(false); + } + + return await base.CompleteAsync(entity, user).ConfigureAwait(false); + } + + public override void CheckDetails(AssembleJob entity, AbpValidationResult result) + { + var details = entity.Details; + foreach (var detail in details) + { + if (detail.HandledFromLocationCode == null) + { + result.Errors.Add(new ValidationResult($"{detail.HandledFromLocationCode} 不能为空")); + } + + } + } + + public override async Task> GetWorkingListByPackingAsync(string packingCode) + { + return await Repository.GetListAsync(c => c.Details.Any(p => p.RecommendPackingCode == packingCode) && c.JobStatus != EnumJobStatus.Closed && c.JobStatus != EnumJobStatus.Cancelled, true).ConfigureAwait(false); + + } + + public override async Task> GetWorkingListByContainerAsync(string containerCode) + { + return await Repository.GetListAsync(c => c.Details.Any(p => p.RecommendContainerCode == containerCode) && c.JobStatus != EnumJobStatus.Closed && c.JobStatus != EnumJobStatus.Cancelled, true).ConfigureAwait(false); + + } + + public async Task GetAsync(Expression> expression) + { + return await Repository.FindAsync(expression).ConfigureAwait(false); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobManager.cs new file mode 100644 index 000000000..480cf0cfd --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobManager.cs @@ -0,0 +1,10 @@ +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public interface IAssembleJobManager : IJobManager +{ + Task GetAsync(Expression> expression); +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobRepository.cs new file mode 100644 index 000000000..568570c1e --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/AssembleJobs/IAssembleJobRepository.cs @@ -0,0 +1,6 @@ +namespace Win_in.Sfs.Wms.Store.Domain; + +public interface IAssembleJobRepository : ISfsJobRepositoryBase +{ + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNote.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNote.cs new file mode 100644 index 000000000..6dd11ef37 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNote.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp; +using Win_in.Sfs.Shared.Domain.Entities; + +namespace Win_in.Sfs.Wms.Store.Domain; + +/// +/// 装配发料记录 +/// +public class AssembleNote : SfsStoreAggregateRootBase, IHasJobNumber, IHasRequestNumber +{ + /// + /// 任务ID + /// + [IgnoreUpdate] + public string JobNumber { get; set; } + + /// + /// 车间 + /// + [IgnoreUpdate] + public string Workshop { get; set; } + + /// + /// 明细列表 + /// + [IgnoreUpdate] + public override List Details { get; set; } = new List(); + + [IgnoreUpdate] + public string RequestNumber { get; set; } + + /// + /// 叫料请求类型 + /// + [IgnoreUpdate] + public string RequestType { get; set; } + + /// + /// 使用在途库 + /// + [IgnoreUpdate] + public bool UseOnTheWayLocation { get; set; } + + /// + /// 确认时间 + /// + [Display(Name = "确认时间")] + [IgnoreUpdate] + public DateTime? ConfirmTime { get; set; } + + /// + /// 已确认 + /// + [Display(Name = "已确认")] + public bool Confirmed { get; set; } + + public void Confirm(DateTime confirmTime) + { + + CheckStatus(Confirmed); + Confirmed = true; + ConfirmTime = confirmTime; + } + + private static void CheckStatus(bool confirmed) + { + if (confirmed) + { + throw new UserFriendlyException($"当前状态为 【已确认】 ,无法再次确认!"); + } + + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteDetail.cs new file mode 100644 index 000000000..ee2f8a389 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteDetail.cs @@ -0,0 +1,43 @@ +using System; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public class AssembleNoteDetail : SfsStoreRecommendFromDetailWithFromToEntityBase +{ + + /// + /// 发料时间 + /// + public DateTime IssueTime { get; set; } + + /// + /// 过期时间 + /// + public DateTime ExpiredTime { get; set; } + + /// + /// 生产线 + /// + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + public string WorkStation { get; set; } + + /// + /// 在途库库位 + /// + public string OnTheWayLocationCode { get; set; } + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteManager.cs new file mode 100644 index 000000000..1f658983e --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/AssembleNoteManager.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp; +using Volo.Abp.Uow; +using Win_in.Sfs.Shared.Event; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public class AssembleNoteManager : SfsStoreManagerBase, IAssembleNoteManager +{ + + public AssembleNoteManager( + IAssembleNoteRepository repository + ) : base(repository) + { + } + + [UnitOfWork] + public virtual async Task ConfirmAsync(Guid id) + { + var entity = await Repository.FindAsync(id).ConfigureAwait(false); + Check.NotNull(entity, EntityClassName); + entity.Confirm(Clock.Now); + await PublishConfirmedAsync(entity).ConfigureAwait(false); + return await Repository.UpdateAsync(entity).ConfigureAwait(false); + } + private async Task PublishConfirmedAsync(AssembleNote entity) + { + try + { + await LocalEventBus.PublishAsync(new SfsConfirmedEntityEventData(entity), false).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.LogDebug($"{nameof(AssembleNote)} Confirmed Event:{ex.Message}", null); + Console.WriteLine(ex.Source); + throw; + } + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteManager.cs new file mode 100644 index 000000000..9a9ad6da1 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteManager.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading.Tasks; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public interface IAssembleNoteManager : ISfsStoreManager +{ + Task ConfirmAsync(Guid id); + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteRepository.cs new file mode 100644 index 000000000..280ab1dfd --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/AssembleNotes/IAssembleNoteRepository.cs @@ -0,0 +1,6 @@ +namespace Win_in.Sfs.Wms.Store.Domain; + +public interface IAssembleNoteRepository : ISfsStoreRepositoryBase +{ + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequest.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequest.cs new file mode 100644 index 000000000..579e97ee1 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequest.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Win_in.Sfs.Shared.Domain.Entities; + +namespace Win_in.Sfs.Wms.Store.Domain; + +/// +/// 装配申请 +/// +public class AssembleRequest : SfsStoreRequestAggregateRootBase +{ + /// + /// 叫料类型 + /// + [Display(Name = "叫料类型")] + [IgnoreUpdate] + public string Type { get; set; } + + /// + /// 生产线 + /// + [IgnoreUpdate] + public string ProdLine { get; set; } + + /// + /// 使用在途库 + /// + public bool UseOnTheWayLocation { get; set; } + + /// + /// 明细列表 + /// + [IgnoreUpdate] + public override List Details { get; set; } = new List(); +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestDetail.cs new file mode 100644 index 000000000..97c0a711d --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestDetail.cs @@ -0,0 +1,105 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Win_in.Sfs.Shared.Domain; +using Win_in.Sfs.Shared.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Domain; + +/// +/// 装配申请明细 +/// +public class AssembleRequestDetail : SfsStoreDetailWithQtyEntityBase, IHasToLocation +{ + /// + /// 到库位 + /// + public string ToLocationCode { get; set; } + + /// + /// 到库区 + /// + public string ToLocationArea { get; set; } + + /// + /// 到库位组 + /// + public string ToLocationGroup { get; set; } + + /// + /// 到ERP库位 + /// + public string ToLocationErpCode { get; set; } + + /// + /// 到仓库 + /// + public string ToWarehouseCode { get; set; } + + /// + /// 来源库区 + /// + public string FromLocationArea { get; set; } + + // /// + // /// 在途库库位 + // /// + // public string OnTheWayLocationCode { get; set; } + + /// + /// 生产线 + /// + public string ProdLine { get; set; } + + /// + /// 工作中心 + /// + public string WorkStation { get; set; } + + /// + /// 过期时间 + /// + public DateTime ExpiredTime { get; set; } + + /// + /// 已发数量 + /// + public decimal IssuedQty { get; set; } + + /// + /// 已收数量 + /// + public decimal ReceivedQty { get; set; } + + /// + /// 明细状态 + /// + public EnumStatus Status { get; set; } + + /// + /// 请求未发 还未发送的数量 + /// + [NotMapped] + public decimal ToBeIssuedQty => Qty - IssuedQty; + + /// + /// 已发未收 + /// + [NotMapped] + public decimal ToBeReceivedQty => IssuedQty - ReceivedQty; + + /// + /// 请求未收 + /// + [NotMapped] + public decimal NotFinishQty => Qty - ReceivedQty; + + /// + /// 位置码 + /// + public string PositionCode { get; set; } + + /// + /// 推荐类型 + /// + public EnumRecommendType RecommendType { get; set; } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestManager.cs new file mode 100644 index 000000000..94040930d --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/AssembleRequestManager.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Math; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Shared.Event; +using static Win_in.Sfs.Wms.Store.Domain.Shared.StoreSettings; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public class AssembleRequestManager + : SfsStoreRequestManagerBase + , IAssembleRequestManager +{ + private readonly IAssembleRequestRepository _repository; + private readonly IIssueJobRepository _issueJobRepository; + + public AssembleRequestManager( + IAssembleRequestRepository repository + , IIssueJobRepository issueJobRepository + ) : base(repository) + { + _repository = repository; + _issueJobRepository = issueJobRepository; + } + + + #region 东阳V2 + + #endregion + + + /// + /// 创建 + /// + /// + /// + public virtual async Task CreateBynNumberAsync(AssembleRequest entity) + { + var number = string.IsNullOrEmpty(entity.Number) ? await GenerateNumberAsync(nameof(AssembleRequest), entity.ActiveDate).ConfigureAwait(false) : entity.Number; + entity.SetIdAndNumberWithDetails(GuidGenerator, number); + entity.Submit(); + entity.Agree(); + entity.RequestStatus = EnumRequestStatus.Partial; + await LocalEventBus.PublishAsync(new SfsHandledEntityEventData(entity), false) + .ConfigureAwait(false); + await _repository.InsertAsync(entity).ConfigureAwait(false); + return entity; + } + + public virtual async Task UpdateDetailsAsync(AssembleRequest newEntity) + { + var oldEntity = await Repository.FindAsync(newEntity.Id, true).ConfigureAwait(false); + if(oldEntity!=null) + { + foreach (var newDetail in newEntity.Details) + { + oldEntity.ReplaceDetail(newDetail.Id, newDetail); + } + + foreach (var detail in oldEntity.Details) + { + SetMaterialRequestDetailStatus(detail); + } + + await SetMaterialRequestStatusAsync(oldEntity).ConfigureAwait(false); + + await Repository.UpdateAsync(oldEntity).ConfigureAwait(false); + } + + } + + private void SetMaterialRequestDetailStatus(AssembleRequestDetail detail) + { + if (detail.ReceivedQty >= detail.Qty)//执行的时候 实际收料 多余 要料数 + { + detail.Status = EnumStatus.Close; + } + else + { + detail.Status = EnumStatus.Open; + } + } + + private async Task SetMaterialRequestStatusAsync(AssembleRequest materialRequest) + { + if (materialRequest.Details.All(p => p.Status == EnumStatus.Close)) + { + materialRequest.RequestStatus = EnumRequestStatus.Completed; + } + else + { + var issueJobs = await _issueJobRepository.GetListAsync(t => t.MaterialRequestNumber == materialRequest.Number).ConfigureAwait(false); + if (issueJobs.Count > 0) + { + if (issueJobs.All(t => t.JobStatus is EnumJobStatus.Done or EnumJobStatus.Closed or EnumJobStatus.Cancelled)) + { + if (materialRequest.Details.All(p => p.ReceivedQty >= p.Qty)) + { + materialRequest.RequestStatus = EnumRequestStatus.Completed; + } + else + { + materialRequest.RequestStatus = EnumRequestStatus.Partial; + } + } + else + { + materialRequest.RequestStatus = EnumRequestStatus.Partial; + } + } + else + { + materialRequest.RequestStatus = EnumRequestStatus.Partial; + } + } + } + + public virtual async Task CompleteAsync(string number) + { + var entity = await GetByNumberAsync(number).ConfigureAwait(false); + if (entity != null && !entity.Details.Any(p => p.ToBeIssuedQty > 0)) + { + await CompleteAsync(entity).ConfigureAwait(false); + } + } + + + #region 导入 + + /// + /// 执行导入 + /// + public virtual async Task ImportDataAsync(List mergeEntities, List deleteEntities = null) + { + if (deleteEntities != null && deleteEntities.Count > 0) + { + await _repository.BulkDeleteAsync(deleteEntities).ConfigureAwait(false); + } + + await CreateManyAsync(mergeEntities).ConfigureAwait(false); + } + + #endregion + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestManager.cs new file mode 100644 index 000000000..653efecd3 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestManager.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; + +namespace Win_in.Sfs.Wms.Store.Domain; + +using Win_in.Sfs.Shared.Domain; + +public interface IAssembleRequestManager : ISfsStoreRequestManager, + IBulkImportService +{ + + Task UpdateDetailsAsync(AssembleRequest entity); + + Task CompleteAsync(string number); + + Task CreateBynNumberAsync(AssembleRequest entity); +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestRepository.cs new file mode 100644 index 000000000..a661ff0f8 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/AssembleRequests/IAssembleRequestRepository.cs @@ -0,0 +1,9 @@ +using Win_in.Sfs.Shared.Domain; + +namespace Win_in.Sfs.Wms.Store.Domain; + +public interface IAssembleRequestRepository : ISfsStoreRepositoryBase, + ISfsBulkRepositoryBase +{ + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/IStoreDbContext.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/IStoreDbContext.cs index 33e6c1708..9f178d167 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/IStoreDbContext.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/IStoreDbContext.cs @@ -22,6 +22,7 @@ public interface IStoreDbContext : IEfCoreDbContext public DbSet ProductReceiptRequests { get; } public DbSet MaterialRequests { get; } public DbSet InjectionRequests { get; } + public DbSet AssembleRequests { get; } public DbSet ContainerRequests { get; } public DbSet DeliverRequests { get; } public DbSet InspectRequests { get; } @@ -77,6 +78,7 @@ public interface IStoreDbContext : IEfCoreDbContext public DbSet WarehouseTransferNotes { get; } public DbSet IssueNotes { get; } public DbSet InjectionNotes { get; } + public DbSet AssembleNotes { get; } public DbSet ContainerNotes { get; } public DbSet UnplannedReceiptNotes { get; } public DbSet UnplannedIssueNotes { get; } @@ -103,6 +105,7 @@ public interface IStoreDbContext : IEfCoreDbContext public DbSet PutawayJobs { get; } public DbSet IssueJobs { get; } public DbSet InjectionJobs { get; } + public DbSet AssembleJobs { get; } public DbSet ContainerJobs { get; } public DbSet DeliverJobs { get; } public DbSet JisDeliverJobs { get; } diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobDbContextModelCreatingExtensions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobDbContextModelCreatingExtensions.cs new file mode 100644 index 000000000..3945e66f1 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobDbContextModelCreatingExtensions.cs @@ -0,0 +1,69 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Shared.EntityFrameworkCore; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public static class AssembleJobDbContextModelCreatingExtensions +{ + public static void ConfigureAssembleJob(this ModelBuilder builder, StoreModelBuilderConfigurationOptions options) + { + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(StoreDbProperties.JobDbTablePrefix + nameof(AssembleJob), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsBase(); + //Configure Job base properties + b.ConfigureJob(); + //Properties + b.Property(q => q.RequestType).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.AssembleRequestNumber).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.Workshop).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength); + //Relations + b.HasMany(q => q.Details).WithOne().HasForeignKey(d => d.MasterID).IsRequired(); + //Indexes + b.HasIndex(q => new { q.Number }).IsUnique(); + }); + + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(StoreDbProperties.JobDbTablePrefix + nameof(AssembleJobDetail), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsBase(); + //Configure Job base properties + b.ConfigureJobRecommendFromDetail(); + //Properties + b.Property(q => q.ExpiredTime).IsRequired(); + b.Property(q => q.ToLocationCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationErpCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToWarehouseCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationArea).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationGroup).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RequestLocationCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.WorkStation).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.Operation).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.DistributionType).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.TruncType).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.PlannedSplitRule).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.OnTheWayLocationCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.PositionCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RecommendType).HasMaxLength(SfsPropertyConst.CodeLength).HasConversion(); + + //Relations + //None + + //Indexes + //b.HasIndex(q => new { q.PackingCode }).IsUnique(); + }); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobEfCoreRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobEfCoreRepository.cs new file mode 100644 index 000000000..6430424b9 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/AssembleJobs/AssembleJobEfCoreRepository.cs @@ -0,0 +1,11 @@ +using Volo.Abp.EntityFrameworkCore; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public class AssembleJobEfCoreRepository : SfsJobEfCoreRepositoryBase, IAssembleJobRepository +{ + public AssembleJobEfCoreRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteDbContextModelCreatingExtensions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteDbContextModelCreatingExtensions.cs new file mode 100644 index 000000000..f13daeb61 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteDbContextModelCreatingExtensions.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public static class AssembleNoteDbContextModelCreatingExtensions +{ + public static void ConfigureAssembleNote(this ModelBuilder builder, StoreModelBuilderConfigurationOptions options) + { + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(options.TablePrefix + nameof(AssembleNote), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsStoreBase(); + + //Properties + b.Property(q => q.RequestNumber).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RequestType).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.Workshop).HasMaxLength(SfsPropertyConst.NameLength); + b.Property(q => q.Remark).HasMaxLength(SfsPropertyConst.RemarkLength); + + //Relations + b.HasMany(q => q.Details).WithOne().HasForeignKey(d => d.MasterID).IsRequired(); + + //Indexes + b.HasIndex(q => new { q.Number }).IsUnique(); + }); + + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(options.TablePrefix + nameof(AssembleNoteDetail), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsStoreBase(); + //Configure Sfs store detail properties + b.ConfigureSfsStoreDetailBase(); + + //Properties + b.Property(q => q.IssueTime).IsRequired(); + b.Property(q => q.ExpiredTime).IsRequired(); + b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.NameLength); + b.Property(q => q.WorkStation).HasMaxLength(SfsPropertyConst.NameLength); + b.Property(q => q.OnTheWayLocationCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.FromStatus).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.ToStatus).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.PositionCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RecommendType).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + + //Relations + + //Indexes + b.HasIndex(q => new { q.Number, q.FromPackingCode, q.FromLocationCode, q.ToLocationCode }).IsUnique(); + b.HasIndex(q => new { q.FromPackingCode }); + }); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteEfCoreRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteEfCoreRepository.cs new file mode 100644 index 000000000..4ab8d2677 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Notes/IssueNotes/AssembleNotes/AssembleNoteEfCoreRepository.cs @@ -0,0 +1,11 @@ +using Volo.Abp.EntityFrameworkCore; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public class AssembleNoteEfCoreRepository : SfsStoreEfCoreRepositoryBase, IAssembleNoteRepository +{ + public AssembleNoteEfCoreRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestDbContextModelCreatingExtensions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestDbContextModelCreatingExtensions.cs new file mode 100644 index 000000000..8d53f0ac3 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestDbContextModelCreatingExtensions.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public static class AssembleRequestDbContextModelCreatingExtensions +{ + public static void ConfigureAssembleRequest(this ModelBuilder builder, StoreModelBuilderConfigurationOptions options) + { + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(options.TablePrefix + nameof(AssembleRequest), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsStoreBase(); + + //Properties + b.Property(q => q.Type).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RequestStatus).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + + //Relations + b.HasMany(q => q.Details).WithOne().HasForeignKey(d => d.MasterID).IsRequired(); + + //Indexes + b.HasIndex(q => new { q.Number }).IsUnique(); + }); + + builder.Entity(b => + { + //Configure table & schema name + b.ToTable(options.TablePrefix + nameof(AssembleRequestDetail), options.Schema); + //Configure ABP properties + b.ConfigureByConvention(); + //Configure Sfs base properties + b.ConfigureSfsStoreBase(); + //Configure Sfs store detail properties + b.ConfigureSfsStoreDetailBase(); + //Properties + b.Property(q => q.ToLocationCode).IsRequired().HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationErpCode).IsRequired().HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToWarehouseCode).IsRequired().HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationArea).IsRequired().HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ToLocationGroup).IsRequired().HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.ExpiredTime).IsRequired(); + b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.WorkStation).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.IssuedQty).HasPrecision(18, 6); + b.Property(q => q.ReceivedQty).HasPrecision(18, 6); + b.Property(q => q.Status).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + b.Property(q => q.PositionCode).HasMaxLength(SfsPropertyConst.CodeLength); + b.Property(q => q.RecommendType).HasMaxLength(SfsPropertyConst.NameLength).HasConversion(); + + //Relations + + //Indexes + b.HasIndex(q => new { q.Number, q.ItemCode, q.ToLocationCode }).IsUnique(); + b.HasIndex(q => new { q.ItemCode }); + }); + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestEfCoreRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestEfCoreRepository.cs new file mode 100644 index 000000000..7541df1ec --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Requests/MaterialRequests/AssembleRequests/AssembleRequestEfCoreRepository.cs @@ -0,0 +1,11 @@ +using Volo.Abp.EntityFrameworkCore; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.EntityFrameworkCore; + +public class AssembleRequestEfCoreRepository : SfsStoreEfCoreRepositoryBase, IAssembleRequestRepository +{ + public AssembleRequestEfCoreRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContext.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContext.cs index 78760e319..714637c10 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContext.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContext.cs @@ -22,6 +22,7 @@ public class StoreDbContext : AbpDbContext, IStoreDbContext public DbSet ProductReceiptRequests { get; set; } public DbSet MaterialRequests { get; set; } public DbSet InjectionRequests { get; set; } + public DbSet AssembleRequests { get; set; } public DbSet ContainerRequests { get; set; } public DbSet DeliverRequests { get; set; } public DbSet InspectRequests { get; set; } @@ -77,6 +78,7 @@ public class StoreDbContext : AbpDbContext, IStoreDbContext public DbSet WarehouseTransferNotes { get; set; } public DbSet IssueNotes { get; set; } public DbSet InjectionNotes { get; set; } + public DbSet AssembleNotes { get; set; } public DbSet ContainerNotes { get; set; } public DbSet UnplannedReceiptNotes { get; set; } public DbSet UnplannedIssueNotes { get; set; } @@ -103,6 +105,7 @@ public class StoreDbContext : AbpDbContext, IStoreDbContext public DbSet PutawayJobs { get; set; } public DbSet IssueJobs { get; set; } public DbSet InjectionJobs { get; set; } + public DbSet AssembleJobs { get; set; } public DbSet ContainerJobs { get; set; } public DbSet DeliverJobs { get; set; } public DbSet JisDeliverJobs { get; set; } diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContextModelCreatingExtensions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContextModelCreatingExtensions.cs index b9229727a..cd0750295 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContextModelCreatingExtensions.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreDbContextModelCreatingExtensions.cs @@ -48,6 +48,7 @@ public static class StoreDbContextModelCreatingExtensions builder.ConfigurePurchaseReceiptRequest(options); builder.ConfigureMaterialRequest(options); builder.ConfigureInjectionRequest(options); + builder.ConfigureAssembleRequest(options); builder.ConfigureDeliverRequest(options); builder.ConfigureContainerRequest(options); builder.ConfigureInspectRequest(options); @@ -84,6 +85,7 @@ public static class StoreDbContextModelCreatingExtensions builder.ConfigureWarehouseTransferNote(options); builder.ConfigureIssueNote(options); builder.ConfigureInjectionNote(options); + builder.ConfigureAssembleNote(options); builder.ConfigureContainerNote(options); builder.ConfigureUnplannedReceiptNote(options); builder.ConfigureUnplannedIssueNote(options); @@ -110,6 +112,7 @@ public static class StoreDbContextModelCreatingExtensions builder.ConfigurePutawayJob(options); builder.ConfigureIssueJob(options); builder.ConfigureInjectionJob(options); + builder.ConfigureAssembleJob(options); builder.ConfigureContainerJob(options); builder.ConfigureDeliverJob(options); builder.ConfigureJisDeliverJob(options); diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreEntityFrameworkCoreModule.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreEntityFrameworkCoreModule.cs index 4dfd83642..997949441 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreEntityFrameworkCoreModule.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/StoreEntityFrameworkCoreModule.cs @@ -59,6 +59,7 @@ public class StoreEntityFrameworkCoreModule : AbpModule context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); + context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); @@ -100,6 +101,7 @@ public class StoreEntityFrameworkCoreModule : AbpModule context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); + context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); @@ -128,6 +130,7 @@ public class StoreEntityFrameworkCoreModule : AbpModule context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); + context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); context.Services.AddTransient(); @@ -193,6 +196,8 @@ public class StoreEntityFrameworkCoreModule : AbpModule orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); + options.Entity(orderOptions => + orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => @@ -246,6 +251,8 @@ public class StoreEntityFrameworkCoreModule : AbpModule orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); + options.Entity(orderOptions => + orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => @@ -319,6 +326,8 @@ public class StoreEntityFrameworkCoreModule : AbpModule orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); + options.Entity(orderOptions => + orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Details)); options.Entity(orderOptions => diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Jobs/AssembleJobAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Jobs/AssembleJobAutoMapperProfile.cs new file mode 100644 index 000000000..f1cecd7c7 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Jobs/AssembleJobAutoMapperProfile.cs @@ -0,0 +1,92 @@ +using System; +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Shared.Application; +using Win_in.Sfs.Wms.Inventory.Application.Contracts; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Event; + +public partial class StoreEventAutoMapperProfile : Profile +{ + private void AssembleJobAutoMapperProfile() + { + + CreateMap() + .ForMember(x => x.JobNumber, y => y.MapFrom(d => d.Number)) + .ForMember(x => x.RequestNumber, y => y.MapFrom(d => d.AssembleRequestNumber)) + .ForMember(x => x.ActiveDate, y => y.MapFrom(d => DateTime.Now)) + .ForMember(x => x.Worker, y => y.MapFrom(d => d.CompleteUserName)) + .Ignore(x => x.Confirmed) + .Ignore(x => x.Number) + .Ignore(x => x.ConfirmTime); + + CreateMap() + .ForMember(x => x.FromPackingCode, y => y.MapFrom(d => d.HandledPackingCode)) + .ForMember(x => x.ToPackingCode, y => y.MapFrom(d => d.HandledPackingCode)) + .ForMember(x => x.SupplierBatch, y => y.MapFrom(d => d.HandledSupplierBatch)) + .ForMember(x => x.ArriveDate, y => y.MapFrom(d => d.HandledArriveDate)) + .ForMember(x => x.ProduceDate, y => y.MapFrom(d => d.HandledProduceDate)) + .ForMember(x => x.ExpireDate, y => y.MapFrom(d => d.HandledExpireDate)) + .ForMember(x => x.FromLot, y => y.MapFrom(d => d.HandledLot)) + .ForMember(x => x.ToLot, y => y.MapFrom(d => d.HandledLot)) + .ForMember(x => x.ToContainerCode, y => y.MapFrom(d => d.HandledContainerCode)) + .ForMember(x => x.FromContainerCode, y => y.MapFrom(d => d.HandledContainerCode)) + .ForMember(x => x.FromStatus, y => y.MapFrom(d => d.Status)) + .ForMember(x => x.ToStatus, y => y.MapFrom(d => d.Status)) + .ForMember(x => x.Qty, y => y.MapFrom(d => d.HandledQty)) + .ForMember(x => x.IssueTime, y => y.MapFrom(d => DateTime.Now)) + .ForMember(x => x.FromLocationCode, y => y.MapFrom(d => d.HandledFromLocationCode)) + .ForMember(x => x.FromLocationArea, y => y.MapFrom(d => d.HandledFromLocationArea)) + .ForMember(x => x.FromLocationGroup, y => y.MapFrom(d => d.HandledFromLocationGroup)) + .ForMember(x => x.FromLocationErpCode, y => y.MapFrom(d => d.HandledFromLocationErpCode)) + .ForMember(x => x.FromWarehouseCode, y => y.MapFrom(d => d.HandledFromWarehouseCode)) + .ForMember(x => x.ToLocationCode, y => y.MapFrom(d => d.ToLocationCode)) + .Ignore(x => x.ToLocationArea) + .Ignore(x => x.ToLocationGroup) + .Ignore(x => x.ToLocationErpCode) + ; + + CreateMap() + .MapExpectInOutFrom() + .Ignore(x => x.Worker) + .Ignore(x => x.SerialNumber) + .Ignore(x => x.ExtraProperties) + ; + + CreateMap() + .MapExpectInOutFrom() + .Ignore(x => x.Worker) + .Ignore(x => x.SerialNumber) + .Ignore(x => x.ExtraProperties); + + CreateMap() + .ForMember(x => x.RequestNumber, y => y.MapFrom(d => d.AssembleRequestNumber)) + .Ignore(x => x.Confirmed) + .Ignore(x => x.JobNumber) + .Ignore(x => x.ActiveDate) + ; + CreateMap() + .ForMember(x => x.Qty, y => y.MapFrom(d => d.HandledQty)) + .ForMember(x => x.IssueTime, y => y.MapFrom(d => DateTime.Now)) + .ForMember(x => x.FromPackingCode, y => y.MapFrom(d => d.HandledPackingCode)) + .ForMember(x => x.ToPackingCode, y => y.MapFrom(d => d.HandledPackingCode)) + .ForMember(x => x.FromContainerCode, y => y.MapFrom(d => d.HandledContainerCode)) + .ForMember(x => x.ToContainerCode, y => y.MapFrom(d => d.HandledContainerCode)) + .ForMember(x => x.FromLot, y => y.MapFrom(d => d.HandledLot)) + .ForMember(x => x.ToLot, y => y.MapFrom(d => d.HandledLot)) + .ForMember(x => x.SupplierBatch, y => y.MapFrom(d => d.HandledSupplierBatch)) + .ForMember(x => x.ArriveDate, y => y.MapFrom(d => d.HandledArriveDate)) + .ForMember(x => x.ProduceDate, y => y.MapFrom(d => d.HandledProduceDate)) + .ForMember(x => x.ExpireDate, y => y.MapFrom(d => d.ExpiredTime)) + .ForMember(x => x.FromLocationCode, y => y.MapFrom(d => d.HandledFromLocationCode)) + .ForMember(x => x.FromLocationArea, y => y.MapFrom(d => d.HandledFromLocationArea)) + .ForMember(x => x.FromLocationGroup, y => y.MapFrom(d => d.HandledFromLocationGroup)) + .ForMember(x => x.FromLocationErpCode, y => y.MapFrom(d => d.HandledFromLocationErpCode)) + .ForMember(x => x.FromWarehouseCode, y => y.MapFrom(d => d.HandledFromWarehouseCode)) + .ForMember(x => x.FromStatus, y => y.MapFrom(d => d.Status)) + .ForMember(x => x.ToStatus, y => y.MapFrom(d => d.Status)) + ; + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/AssembleNoteAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/AssembleNoteAutoMapperProfile.cs new file mode 100644 index 000000000..15033a58a --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/AssembleNoteAutoMapperProfile.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Wms.Inventory.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Event; + +public partial class StoreEventAutoMapperProfile : Profile +{ + private void AssembleNoteAutoMapperProfile() + { + CreateMap() + .Ignore(x => x.DocNumber) + .Ignore(x => x.JobNumber) + .Ignore(x => x.Worker) + .Ignore(x => x.TransType) + .Ignore(x => x.ExtraProperties) + .Ignore(x => x.TransSubType) + ; + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/InjectionNoteAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/InjectionNoteAutoMapperProfile.cs new file mode 100644 index 000000000..14299295f --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Notes/InjectionNoteAutoMapperProfile.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Wms.Inventory.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Event; + +public partial class StoreEventAutoMapperProfile : Profile +{ + private void InjectionNoteAutoMapperProfile() + { + CreateMap() + .Ignore(x => x.DocNumber) + .Ignore(x => x.JobNumber) + .Ignore(x => x.Worker) + .Ignore(x => x.TransType) + .Ignore(x => x.ExtraProperties) + .Ignore(x => x.TransSubType) + ; + } + +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/AssembleRequestAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/AssembleRequestAutoMapperProfile.cs new file mode 100644 index 000000000..dcf76a76b --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/AssembleRequestAutoMapperProfile.cs @@ -0,0 +1,135 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using Win_in.Sfs.Shared.Application; +using Win_in.Sfs.Wms.Inventory.Application.Contracts; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; + +namespace Win_in.Sfs.Wms.Store.Event; + +public partial class StoreEventAutoMapperProfile : Profile +{ + private void AssembleRequestAutoMapperProfile() + { + CreateMap() + .ForMember(x => x.AssembleRequestNumber, y => y.MapFrom(d => d.Number)) + .ForMember(x => x.RequestType, y => y.MapFrom(d => d.Type)) + .Ignore(x => x.WarehouseCode) + .Ignore(x => x.Workshop) + .Ignore(x => x.UpStreamJobNumber) + .Ignore(x => x.JobType) + .Ignore(x => x.IsAutoComplete) + .Ignore(x => x.ExpiredTime) + .Ignore(x => x.JobDescription) + .Ignore(x => x.JobStatus) + .Ignore(x => x.WorkGroupCode) + .Ignore(x => x.Priority) + .Ignore(x => x.PriorityIncrement) + .Ignore(x => x.AcceptUserId) + .Ignore(x => x.AcceptTime) + .Ignore(x => x.AcceptUserName) + .Ignore(x => x.CompleteUserId) + .Ignore(x => x.CompleteUserName) + .Ignore(x => x.CompleteTime) + .Ignore(x => x.Details) + ; + + CreateMap() + .ForMember(x => x.RequestLocationCode, y => y.MapFrom(d => d.ToLocationCode)) + .Ignore(x => x.RecommendFromLocationArea) + .Ignore(x => x.RecommendFromLocationGroup) + .Ignore(x => x.HandledFromLocationArea) + .Ignore(x => x.HandledFromLocationGroup) + .Ignore(x => x.RecommendFromWarehouseCode) + .Ignore(x => x.HandledFromWarehouseCode) + .Ignore(x => x.OnTheWayLocationCode) + .Ignore(x => x.DistributionType) + .Ignore(x => x.RoundedQty) + .Ignore(x => x.Operation) + .Ignore(x => x.ExpiredTime) + .Ignore(x => x.TruncType) + .Ignore(x => x.PlanBeginTime) + .Ignore(x => x.PlannedSplitRule) + .Ignore(x => x.DeliveryQty) + .Ignore(x => x.Status) + .Ignore(x => x.RecommendContainerCode) + .Ignore(x => x.StdPackQty) + .Ignore(x => x.RecommendPackingCode) + .Ignore(x => x.HandledContainerCode) + .Ignore(x => x.HandledPackingCode) + .Ignore(x => x.RecommendSupplierBatch) + .Ignore(x => x.RecommendProduceDate) + .Ignore(x => x.RecommendArriveDate) + .Ignore(x => x.RecommendExpireDate) + .Ignore(x => x.HandledFromLocationCode) + .Ignore(x => x.HandledFromLocationErpCode) + .Ignore(x => x.HandledUom) + .Ignore(x => x.RecommendFromLocationErpCode) + .Ignore(x => x.HandledExpireDate) + .Ignore(x => x.HandledLot) + .Ignore(x => x.HandledArriveDate) + .Ignore(x => x.HandledProduceDate) + .Ignore(x => x.HandledQty) + .Ignore(x => x.RecommendQty) + .Ignore(x => x.Uom) + .Ignore(x => x.HandledSupplierBatch) + .Ignore(x => x.RecommendFromLocationCode) + .Ignore(x => x.RecommendLot) + .IgnoreIHasRecommendAndHandledFrom(); + + CreateMap() + .ForMember(x => x.RecommendArriveDate, y => y.MapFrom(d => d.ArriveDate)) + .ForMember(x => x.RecommendContainerCode, y => y.MapFrom(d => d.ContainerCode)) + .ForMember(x => x.RecommendExpireDate, y => y.MapFrom(d => d.ExpireDate)) + .ForMember(x => x.RecommendFromLocationCode, y => y.MapFrom(d => d.LocationCode)) + .ForMember(x => x.RecommendFromLocationErpCode, y => y.MapFrom(d => d.LocationErpCode)) + .ForMember(x => x.RecommendFromWarehouseCode, y => y.MapFrom(d => d.WarehouseCode)) + .ForMember(x => x.RecommendFromLocationArea, y => y.MapFrom(d => d.LocationArea)) + .ForMember(x => x.RecommendFromLocationGroup, y => y.MapFrom(d => d.LocationGroup)) + .ForMember(x => x.RecommendLot, y => y.MapFrom(d => d.Lot)) + .ForMember(x => x.RecommendPackingCode, y => y.MapFrom(d => d.PackingCode)) + .ForMember(x => x.RecommendProduceDate, y => y.MapFrom(d => d.ProduceDate)) + .ForMember(x => x.RecommendQty, y => y.MapFrom(d => d.Qty)) + .ForMember(x => x.RecommendSupplierBatch, y => y.MapFrom(d => d.SupplierBatch)) + .ForMember(x => x.Uom, y => y.MapFrom(d => d.Uom)).Ignore(x => x.HandledArriveDate) + .Ignore(x => x.HandledFromLocationArea) + .Ignore(x => x.HandledFromLocationGroup) + .Ignore(x => x.ToLocationErpCode) + .Ignore(x => x.ToWarehouseCode) + .Ignore(x => x.ToLocationArea) + .Ignore(x => x.ToLocationGroup) + .Ignore(x => x.HandledFromWarehouseCode) + .Ignore(x => x.RequestLocationCode) + .Ignore(x => x.ToLocationCode) + .Ignore(x => x.ProdLine) + .Ignore(x => x.WorkStation) + .Ignore(x => x.HandledContainerCode) + .Ignore(x => x.HandledExpireDate) + .Ignore(x => x.HandledFromLocationCode) + .Ignore(x => x.HandledFromLocationErpCode) + .Ignore(x => x.HandledLot) + .Ignore(x => x.HandledPackingCode) + .Ignore(x => x.HandledProduceDate) + .Ignore(x => x.HandledQty) + .Ignore(x => x.HandledSupplierBatch) + .Ignore(x => x.HandledUom) + .Ignore(x => x.Remark) + .Ignore(x => x.OnTheWayLocationCode) + .Ignore(x => x.DistributionType) + .Ignore(x => x.RoundedQty) + .Ignore(x => x.Operation) + .Ignore(x => x.ExpiredTime) + .Ignore(x => x.TruncType) + .Ignore(x => x.PlanBeginTime) + .Ignore(x => x.PlannedSplitRule) + .Ignore(x => x.DeliveryQty) + .Ignore(x => x.RequestLocationCode) + .Ignore(x => x.ToLocationCode) + .Ignore(x => x.ProdLine) + .Ignore(x => x.WorkStation) + .Ignore(x => x.PositionCode) + .Ignore(x => x.RecommendType) + .IgnoreIHasRecommendAndHandledFrom(); + + } +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/InjectionRequestAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/InjectionRequestAutoMapperProfile.cs index 2d2aef453..b927aa03d 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/InjectionRequestAutoMapperProfile.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/AutoMapperProfiles/Requests/InjectionRequestAutoMapperProfile.cs @@ -15,6 +15,7 @@ public partial class StoreEventAutoMapperProfile : Profile .ForMember(x => x.InjectionRequestNumber, y => y.MapFrom(d => d.Number)) .ForMember(x => x.RequestType, y => y.MapFrom(d => d.Type)) .Ignore(x => x.WarehouseCode) + .Ignore(x => x.Workshop) .Ignore(x => x.UpStreamJobNumber) .Ignore(x => x.JobType) .Ignore(x => x.IsAutoComplete) diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Jobs/AssembleJobEventHandler.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Jobs/AssembleJobEventHandler.cs new file mode 100644 index 000000000..8834827b7 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Jobs/AssembleJobEventHandler.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.EventBus; +using Volo.Abp.Uow; +using Win_in.Sfs.Basedata.Application.Contracts; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Shared.Event; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; +using Win_in.Sfs.Wms.Store.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Event.BusinessJob; + +public class AssembleJobEventHandler : + StoreEventHandlerBase + , ILocalEventHandler> +{ + private const EnumTransType TransType = EnumTransType.Issue; + + private readonly IAssembleNoteAppService _assembleNoteAppService; + private readonly ILocationAppService _locationAppService; + + public AssembleJobEventHandler(IAssembleNoteAppService assembleNoteAppService, ILocationAppService locationAppService) + { + _assembleNoteAppService = assembleNoteAppService; + _locationAppService = locationAppService; + } + + /// + /// 执行后 + /// + /// + /// + [UnitOfWork] + public virtual async Task HandleEventAsync(SfsCompletedEntityEventData eventData) + { + var entity = eventData.Entity; + var assembleNote = await BuildAssembleNoteAsync(entity).ConfigureAwait(false); + await _assembleNoteAppService.CreateAsync(assembleNote).ConfigureAwait(false); + } + + #region 私有 + + /// + /// 创建补料记录实体 + /// + /// + /// + private async Task BuildAssembleNoteAsync(AssembleJob entity) + { + var assembleNoteCreateInput = ObjectMapper.Map(entity); + assembleNoteCreateInput.JobNumber = entity.Number; + var locationCodes = assembleNoteCreateInput.Details.Select(p => p.ToLocationCode).Distinct().ToList(); + var locations = await _locationAppService.GetByCodesAsync(locationCodes).ConfigureAwait(false); + + assembleNoteCreateInput.Details.RemoveAll(p => p.Qty == 0); + + foreach (var detail in assembleNoteCreateInput.Details) + { + var location = locations.First(p => p.Code == detail.ToLocationCode); + await RemovePackingCodeAndContainerCodeAndLotAsync(detail, location.Type).ConfigureAwait(false); //去箱 去托 去批 + + detail.ToLocationArea = location.AreaCode; + detail.ToLocationGroup = location.LocationGroupCode; + detail.ToLocationErpCode = location.ErpLocationCode; + detail.ToWarehouseCode = location.WarehouseCode; + } + + return assembleNoteCreateInput; + } + + /// + /// 去除箱码 托码 批次 + /// + private async Task RemovePackingCodeAndContainerCodeAndLotAsync(AssembleNoteDetailInput assembleNoteDetail, + EnumLocationType locationType) + { + switch (locationType) + { + case EnumLocationType.WIP: + { + //用开关控制 发料到线边后去除箱码和托码 ??? + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToWip.IsRemovePackingCode) + .ConfigureAwait(false)) + { + assembleNoteDetail.ToPackingCode = ""; + } + + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToWip.IsRemoveContainerCode) + .ConfigureAwait(false)) + { + assembleNoteDetail.ToContainerCode = ""; + } + + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToWip.IsRemoveLot).ConfigureAwait(false)) + { + assembleNoteDetail.ToLot = ""; + } + + break; + } + case EnumLocationType.SEMI: + { + //用开关控制 发料到后去除箱码和托码 ??? + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToSemi.IsRemovePackingCode) + .ConfigureAwait(false)) + { + assembleNoteDetail.ToPackingCode = ""; + } + + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToSemi.IsRemoveContainerCode) + .ConfigureAwait(false)) + { + assembleNoteDetail.ToContainerCode = ""; + } + + if (await SettingManager.IsTrueAsync(StoreSettings.Issue.ToSemi.IsRemoveLot).ConfigureAwait(false)) + { + assembleNoteDetail.ToLot = ""; + } + + break; + } + } + } + + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/AssembleRequestEventHandler.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/AssembleRequestEventHandler.cs new file mode 100644 index 000000000..796227276 --- /dev/null +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/AssembleRequestEventHandler.cs @@ -0,0 +1,283 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FluentValidation.Validators; +using Volo.Abp; +using Volo.Abp.EventBus; +using Volo.Abp.SettingManagement; +using Win_in.Sfs.Basedata.Application.Contracts; +using Win_in.Sfs.Shared.Domain.Shared; +using Win_in.Sfs.Shared.Event; +using Win_in.Sfs.Wms.Inventory.Application.Contracts; +using Win_in.Sfs.Wms.Store.Application.Contracts; +using Win_in.Sfs.Wms.Store.Domain; +using Win_in.Sfs.Wms.Store.Domain.Shared; + +namespace Win_in.Sfs.Wms.Store.Event.BusinessRequest; + +public class AssembleRequestEventHandler + : StoreEventHandlerBase + , ILocalEventHandler> + , ILocalEventHandler> + , ILocalEventHandler> + , ILocalEventHandler> + , ILocalEventHandler>> +{ + private readonly IAssembleJobAppService _assembleJobAppService; + private readonly IProductionLineAppService _productionLineAppService; + private readonly IAssembleRequestManager _assembleRequestManager; + private readonly ILocationAppService _locationAppService; + private readonly IBalanceAppService _balanceAppService; + + public AssembleRequestEventHandler( + IAssembleJobAppService assembleJobAppService + , IProductionLineAppService productionLineAppService + , IAssembleRequestManager assembleRequestManager + , ILocationAppService locationAppService + , IBalanceAppService balanceAppService) + { + _assembleJobAppService = assembleJobAppService; + _productionLineAppService = productionLineAppService; + _assembleRequestManager = assembleRequestManager; + _locationAppService = locationAppService; + _balanceAppService = balanceAppService; + } + + /// + /// 创建后 + /// + /// Event data + public virtual async Task HandleEventAsync(SfsCreatedEntityEventData eventData) + { + var entity = eventData.Entity; + + //if (entity.AutoSubmit) + //{ + // await _assembleRequestManager.SubmitAsync(entity).ConfigureAwait(false); + //} + } + + /// + /// 批量创建后 + /// + /// Event data + public virtual async Task HandleEventAsync(SfsCreatedEntityEventData> eventData) + { + var entitys = eventData.Entity; + foreach (var entity in entitys) + { + if (entity.AutoSubmit) + { + await _assembleRequestManager.SubmitAsync(entity).ConfigureAwait(false); + } + + } + } + + /// + /// 执行后 + /// + /// + /// + public virtual async Task HandleEventAsync(SfsHandledEntityEventData eventData) + { + var entity = eventData.Entity; + var assembleJobs = await BuildAssembleJobAsync(entity).ConfigureAwait(false); + if (assembleJobs.Any()) + { + await _assembleJobAppService.CreateManyAsync(assembleJobs).ConfigureAwait(false); + } + } + + /// + /// 驳回后 + /// + /// + /// + public virtual async Task HandleEventAsync(SfsAbortedEntityEventData eventData) + { + + } + + /// + /// 完成后 + /// + /// + /// + public virtual async Task HandleEventAsync(SfsCompletedEntityEventData eventData) + { + _ = eventData.Entity; + // await _assembleJobAppService.CompleteByAssembleRequestAsync(entity.Number); + + await Task.CompletedTask.ConfigureAwait(false); + } + + #region 私有 + + private async Task> BuildAssembleJobAsync + (AssembleRequest assembleRequest) + { + var jobs = new List(); + + var transactionType = await TransactionTypeAclService.GetByTransTypeAsync(EnumTransType.Issue, EnumTransSubType.None).ConfigureAwait(false);//库存事务 + + var toLocationCodes = assembleRequest.Details.Select(p => p.ToLocationCode).Distinct().ToList();//所有发送库位的集合 + var toLocations = await _locationAppService.GetByCodesAsync(toLocationCodes).ConfigureAwait(false);//所有库位的集合 + + var assembleRequestDetails = assembleRequest.Details.Where(p => p.ToBeIssuedQty > 0);//所有还没发送物品的集合 + foreach (var assembleRequestDetail in assembleRequestDetails)//如果有还有剩余未叫料的数量 则创建新的任务 + { + var toLocation = toLocations.FirstOrDefault(p => p.Code == assembleRequestDetail.ToLocationCode);//判断目标库位是否存在 + Check.NotNull(toLocation, "库位代码", $"库位 {assembleRequestDetail.ToLocationCode} 不存在"); + + //创建详情 + var jobDetails = await BuildAssembleJobDetailInputsAsync(assembleRequest, assembleRequestDetail, transactionType, toLocation.LocationGroupCode).ConfigureAwait(false); + if (!jobDetails.Any()) + { + continue; + } + + var fromLocationCode = jobDetails[0].RecommendFromLocationCode; + var fromLocation = await _locationAppService.GetByCodeAsync(fromLocationCode).ConfigureAwait(false); + var job = jobs.FirstOrDefault(p => p.WorkGroupCode == fromLocation?.WorkGroupCode); + if (job == null || job.Details.Any(p => p.ToLocationCode != assembleRequestDetail.ToLocationCode)) + { + job = BuildAssembleJobCreateInput(assembleRequest, fromLocation); + jobs.Add(job); + } + job.Details.AddRange(jobDetails); + if (assembleRequestDetail.ToBeIssuedQty < 0) + { + assembleRequestDetail.Status = EnumStatus.Close; + } + } + + jobs = jobs.Where(p => p.Details.Any()).ToList(); + + var openRequestDetails = + assembleRequest.Details.Where(p => p.Status != EnumStatus.Close).ToList(); + + if (!openRequestDetails.Any()) + { + return jobs; + } + + + var enableMultipleCreateAssembleJob = await SettingManager.IsTrueAsync(StoreSettings.MaterialRequest.EnableMultipleCreateIssueJob).ConfigureAwait(false); + if (enableMultipleCreateAssembleJob) + { + + //assembleRequest.Partial(); + } + else + { + var sb = new StringBuilder(); + foreach (var openRequestDetail in openRequestDetails) + { + sb.AppendLine($"{openRequestDetail.ItemCode}请求数量 {openRequestDetail.Qty},可用库存数量 {openRequestDetail.IssuedQty}"); + } + throw new UserFriendlyException($"{sb} 可用库存数量不足, 无法生成发料任务"); + } + return jobs; + } + + private AssembleJobEditInput BuildAssembleJobCreateInput(AssembleRequest assembleRequest, LocationDTO fromLocation) + { + AssembleJobEditInput job; + job = ObjectMapper.Map(assembleRequest); + job.JobType = EnumJobType.IssueJob; + job.JobStatus = EnumJobStatus.Open; + job.WorkGroupCode = fromLocation.WorkGroupCode; + job.WarehouseCode = fromLocation.WarehouseCode; + job.ProdLine = fromLocation.LocationGroupCode; + job.Worker = assembleRequest.Worker; + if (string.IsNullOrEmpty(job.Worker)) + { + job.Worker = "admin"; + } + job.AssembleRequestNumber = assembleRequest.Number; + return job; + } + + private async Task> BuildAssembleJobDetailInputsAsync(AssembleRequest assembleRequest, + AssembleRequestDetail assembleRequestDetail, TransactionTypeDTO transactionType, string toLocationGroupCode) + { + var jobDetails = new List(); + var input = new RecommendBalanceRequestInput() + { + ItemCode = assembleRequestDetail.ItemCode, + Qty = assembleRequestDetail.ToBeIssuedQty, + LocationTypes = transactionType.OutLocationTypes, + LocationAreas = new List { assembleRequestDetail.FromLocationArea }, + Statuses = transactionType.OutInventoryStatuses, + }; + //获取推荐库存 + var recommendList = await _balanceAppService.GetRecommendBalancesAsync(input).ConfigureAwait(false); + //没有推荐库存时 跳过此明细 不生成任务 + if (recommendList.Count != 0) + { + foreach (var recommend in recommendList) + { + //拿走需求量 + var detail = await BuildAssembleJobDetailAsync(assembleRequestDetail, recommend, toLocationGroupCode).ConfigureAwait(false); + if (assembleRequest.UseOnTheWayLocation) + { + //获取在途库 + var locationDto = await _locationAppService.GetFirstByTypeAsync(EnumLocationType.TRANSPORT).ConfigureAwait(false); + + detail.OnTheWayLocationCode = locationDto.Code; + } + + jobDetails.Add(detail); + assembleRequestDetail.IssuedQty += recommend.Qty; + + //await _assembleRequestManager.UpdateDetailsAsync(assembleRequest).ConfigureAwait(false); + + } + } + return jobDetails; + } + + private async Task BuildAssembleJobDetailAsync(AssembleRequestDetail assembleRequestDetail, BalanceDTO balance, string toLocationGroupCode) + { + + //ProductionLineDTO prodLine = await _productionLineAppService.GetByLocationGroupCodeAsync(toLocationGroupCode).ConfigureAwait(false); + + var detail = ObjectMapper.Map(balance); + detail.RequestLocationCode = assembleRequestDetail.ToLocationCode; + detail.WorkStation = assembleRequestDetail.WorkStation; + detail.ExpiredTime = assembleRequestDetail.ExpiredTime; + detail.PositionCode = assembleRequestDetail.PositionCode; + detail.RecommendType = assembleRequestDetail.RecommendType; + + detail.RecommendPackingCode = balance.PackingCode; + detail.RecommendContainerCode = balance.ContainerCode; + detail.RecommendSupplierBatch = balance.SupplierBatch; + detail.RecommendProduceDate = balance.ProduceDate; + detail.RecommendExpireDate = balance.ExpireDate; + detail.RecommendLot = balance.Lot; + detail.RecommendProduceDate = balance.ProduceDate; + detail.RecommendArriveDate = balance.ArriveDate; + detail.RecommendFromLocationArea = balance.LocationArea; + detail.RecommendFromLocationCode = balance.LocationCode; + detail.RecommendFromLocationErpCode = balance.LocationErpCode; + detail.RecommendFromLocationGroup = balance.LocationGroup; + detail.RecommendFromWarehouseCode = balance.WarehouseCode; + detail.RecommendQty = balance.Qty; + detail.Uom = balance.Uom; + + detail.ToLocationCode = assembleRequestDetail.ToLocationCode; + detail.ToLocationErpCode = assembleRequestDetail.ToLocationErpCode; + detail.ToLocationArea = assembleRequestDetail.ToLocationArea; + detail.ToWarehouseCode = assembleRequestDetail.ToWarehouseCode; + + //detail.ProdLine = prodLine == null ? toLocationGroupCode : prodLine.Code; + detail.ProdLine = toLocationGroupCode; + await Task.CompletedTask.ConfigureAwait(false); + return detail; + + } + + #endregion +} diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/StoreEventAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/StoreEventAutoMapperProfile.cs index 303d94bc3..682288fa9 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/StoreEventAutoMapperProfile.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/StoreEventAutoMapperProfile.cs @@ -36,6 +36,7 @@ public partial class StoreEventAutoMapperProfile : Profile InspectJobAutoMapperProfile(); IssueJobAutoMapperProfile(); InjectionJobAutoMapperProfile(); + AssembleJobAutoMapperProfile(); JisDeliverJobAutoMapperProfile(); ProductionReturnJobAutoMapperProfile(); ProductReceiveJobAutoMapperProfile(); @@ -66,11 +67,14 @@ public partial class StoreEventAutoMapperProfile : Profile InventoryTransferNoteAutoMapperProfile(); IsolationNoteAutoMapperProfile(); IssueNoteAutoMapperProfile(); + InjectionNoteAutoMapperProfile(); + AssembleNoteAutoMapperProfile(); ItemTransformNoteAutoMapperProfile(); JisDeliverNoteAutoMapperProfile(); JisProductReceiptNoteAutoMapperProfile(); MaterialRequestAutoMapperProfile(); InjectionRequestAutoMapperProfile(); + AssembleRequestAutoMapperProfile(); ProductionReturnRequestAutoMapperProfile(); ProductionReturnNoteAutoMapperProfile(); ProductReceiptNoteAutoMapperProfile();