diff --git a/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Jobs/IssueJobs/SparePartIssueJobsController.cs b/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Jobs/IssueJobs/SparePartIssueJobsController.cs
new file mode 100644
index 000000000..ec8154019
--- /dev/null
+++ b/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Jobs/IssueJobs/SparePartIssueJobsController.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.AspNetCore.Mvc;
+using Win_in.Sfs.Auth.Application.Contracts;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Wms.Store.Application.Contracts;
+
+namespace Win_in.Sfs.Wms.Pda.Controllers.Jobs.IssueJobs;
+
+///
+/// 备件叫料PDA任务
+///
+[ApiController]
+[Route($"{PdaHostConst.ROOT_ROUTE}job/spare-part-issue")]
+public class SparePartIssueJobsController : AbpController
+{
+ private readonly ISparePartIssueJobAppService _sparePartIssueJobAppService;
+
+ private readonly IUserWorkGroupAppService _userWorkGroupAppService;
+
+ public SparePartIssueJobsController(ISparePartIssueJobAppService sparePartIssueJobAppService, IUserWorkGroupAppService userWorkGroupAppService)
+ {
+ _sparePartIssueJobAppService = sparePartIssueJobAppService;
+ _userWorkGroupAppService = userWorkGroupAppService;
+ }
+
+ ///
+ /// 获取列表
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("list")]
+ public virtual async Task> GetListAsync(int pageSize, int pageIndex,
+ bool isFinished)
+ {
+ var status = new List();
+ if (isFinished)
+ {
+ status.Add((int)EnumJobStatus.Done);
+ }
+ else
+ {
+ status.Add((int)EnumJobStatus.Open);
+ status.Add((int)EnumJobStatus.Wait);
+ status.Add((int)EnumJobStatus.Doing);
+ status.Add((int)EnumJobStatus.Partial);
+ }
+
+ var jsonStatus = JsonSerializer.Serialize(status);
+
+ var request = new SfsJobRequestInputBase
+ {
+ MaxResultCount = pageSize,
+ SkipCount = (pageIndex - 1) * pageSize,
+ Sorting = $"{nameof(ContainerJobDTO.CreationTime)} ASC",
+ Condition = new Condition
+ {
+ Filters = new List { new(nameof(ContainerJobDTO.JobStatus), jsonStatus, "In") }
+ }
+ };
+
+ var list = await _sparePartIssueJobAppService.GetPagedListByFilterAsync(request, true).ConfigureAwait(false);
+
+ return list;
+ }
+
+ ///
+ /// 承接任务
+ ///
+ ///
+ ///
+ [HttpPost("take/{id}")]
+ public virtual async Task TakeAsync(Guid id)
+ {
+ await _sparePartIssueJobAppService.AcceptAsync(id).ConfigureAwait(false);
+ }
+
+ ///
+ /// 取消承接任务
+ ///
+ ///
+ ///
+ [HttpPost("cancel-take/{id}")]
+ public virtual async Task CancelTakeAsync(Guid id)
+ {
+ await _sparePartIssueJobAppService.CancelAcceptAsync(id).ConfigureAwait(false);
+ }
+
+ ///
+ /// 执行任务明细
+ ///
+ ///
+ [HttpPost("ExecuteDetail/{masterId}")]
+ public async Task ExecuteDetailAsync(Guid masterId, Guid detailId, SparePartIssueJobDetailDTO issueJobDetailDto)
+ {
+ await _sparePartIssueJobAppService.ExecuteDetailAsync(masterId, detailId, issueJobDetailDto).ConfigureAwait(false);
+ }
+
+ ///
+ /// 获取任务数量
+ ///
+ ///
+ [HttpGet("count")]
+ public virtual async Task> CountAsync()
+ {
+ var status = new List
+ {
+ (int)EnumJobStatus.Open, (int)EnumJobStatus.Doing, (int)EnumJobStatus.Partial, (int)EnumJobStatus.Wait
+ };
+ var jsonStatus = JsonSerializer.Serialize(status);
+
+ var request = new SfsJobRequestInputBase
+ {
+ Sorting = $"{nameof(InspectJobDTO.Priority)} ASC",
+ Condition = new Condition
+ {
+ Filters = new List
+ {
+ //new(nameof(InspectJobDTO.WorkGroupCode),jsonCodes,"In"),
+ new(nameof(InspectJobDTO.JobStatus), jsonStatus, "In")
+ }
+ }
+ };
+
+ var count = await _sparePartIssueJobAppService.GetCountByFilterAsync(request).ConfigureAwait(false);
+
+ return Ok(count);
+ }
+
+ ///
+ /// 获取任务详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ public virtual async Task> GetAsync(Guid id)
+ {
+ var result = await _sparePartIssueJobAppService.GetAsync(id).ConfigureAwait(false);
+ return Ok(result);
+ }
+
+ ///
+ /// 根据Job Number 获取盘点任务列表
+ ///
+ ///
+ ///
+ [HttpGet("by-number/{jobNumber}")]
+ public virtual async Task> GetByNumberAsync(string jobNumber)
+ {
+ var jobDto = await _sparePartIssueJobAppService.GetByNumberAsync(jobNumber).ConfigureAwait(false);
+ if (jobDto == null)
+ {
+ throw new UserFriendlyException($"未找到编号为 {jobNumber} 的任务");
+ }
+
+ var wlgCodes = await _userWorkGroupAppService.GetCodsOfCurrentUserAsync().ConfigureAwait(false);
+ if (!wlgCodes.Contains(jobDto.WorkGroupCode))
+ {
+ return new NotFoundObjectResult($"任务属于工作组 {jobDto.WorkGroupCode}");
+ }
+
+ if (jobDto.JobStatus == EnumJobStatus.Doing && jobDto.AcceptUserId != CurrentUser.Id)
+ {
+ return new NotFoundObjectResult($"任务正在被 {jobDto.AcceptUserName} 处理");
+ }
+
+ return jobDto;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("by-request-number/{requestNumber}")]
+ public virtual async Task> GetByRequestNumberAsync(string requestNumber)
+ {
+ return await _sparePartIssueJobAppService.GetByRequestNumberAsync(requestNumber).ConfigureAwait(false);
+ }
+}
diff --git a/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Stores/IssueRequest/SparePartRequestController.cs b/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Stores/IssueRequest/SparePartRequestController.cs
new file mode 100644
index 000000000..ea3d14e04
--- /dev/null
+++ b/be/Hosts/WmsPda.Host/Win_in.Sfs.Wms.Pda.Host/Controllers/Stores/IssueRequest/SparePartRequestController.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.AspNetCore.Mvc;
+using Win_in.Sfs.Auth.Application.Contracts;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Wms.Store.Application.Contracts;
+
+namespace Win_in.Sfs.Wms.Pda.Controllers.Stores;
+
+///
+/// 备件叫料请求
+///
+[ApiController]
+[Route($"{PdaHostConst.ROOT_ROUTE}store/spare-part-request")]
+public class SparePartRequestController : AbpController
+{
+ private readonly ISparePartIssueRequestAppService _sparePartIssueRequestAppService;
+
+ private readonly IUserWorkGroupAppService _userWorkGroupAppService;
+
+ ///
+ ///
+ ///
+ public SparePartRequestController(ISparePartIssueRequestAppService sparePartIssueRequestAppService,
+ IUserWorkGroupAppService userWorkGroupAppService)
+ {
+ _sparePartIssueRequestAppService = sparePartIssueRequestAppService;
+ _userWorkGroupAppService = userWorkGroupAppService;
+ }
+
+ ///
+ /// 备件叫料申请
+ ///
+ ///
+ ///
+ [HttpPost("")]
+ public virtual async Task CreateAsync(SparePartIssueRequestEditInput input)
+ {
+ await _sparePartIssueRequestAppService.CreateAndHandleAsync(input).ConfigureAwait(false);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("list")]
+ public virtual async Task> GetListAsync(int pageSize, int pageIndex,
+ bool isFinished)
+ {
+ var status = new List();
+ if (isFinished)
+ {
+ status.Add((int)EnumRequestStatus.Completed);
+ }
+ else
+ {
+ status.Add((int)EnumRequestStatus.Partial);
+ status.Add((int)EnumRequestStatus.Handling);
+ status.Add((int)EnumRequestStatus.New);
+ }
+
+ var jsonStatus = JsonSerializer.Serialize(status);
+
+ var request = new SfsStoreRequestInputBase
+ {
+ MaxResultCount = pageSize,
+ SkipCount = (pageIndex - 1) * pageSize,
+ Sorting = $"{nameof(SparePartIssueRequestDTO.CreationTime)} ASC",
+ Condition = new Condition
+ {
+ Filters = new List { new(nameof(SparePartIssueRequestDTO.RequestStatus), jsonStatus, "In") }
+ }
+ };
+
+ var list = await _sparePartIssueRequestAppService.GetPagedListByFilterAsync(request, true).ConfigureAwait(false);
+
+ return list;
+ }
+
+ ///
+ ///
+ ///
+ [HttpPost("handle/{id}")]
+ public virtual async Task HandleAsync(Guid id)
+ {
+ await _sparePartIssueRequestAppService.HandleAsync(id).ConfigureAwait(false);
+ }
+
+ ///
+ /// 根据Job Number 获取盘点任务列表
+ ///
+ ///
+ ///
+ [HttpGet("by-number/{requestNumber}")]
+ public virtual async Task> GetByNumberAsync(string requestNumber)
+ {
+ var jobDto = await _sparePartIssueRequestAppService.GetByNumberAsync(requestNumber).ConfigureAwait(false);
+ if (jobDto == null)
+ {
+ throw new UserFriendlyException($"未找到编号为 {requestNumber} 的请求");
+ }
+
+ return jobDto;
+ }
+
+ ///
+ /// 获取任务详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ public virtual async Task> GetAsync(Guid id)
+ {
+ var result = await _sparePartIssueRequestAppService.GetAsync(id).ConfigureAwait(false);
+ return Ok(result);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("IsHasNewJob")]
+ public virtual async Task IsHasNewJobAsync(string requestNumber, List jobNumber)
+ {
+ return await _sparePartIssueRequestAppService.IsHasNewJobAsync(requestNumber, jobNumber).ConfigureAwait(false);
+ }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDTO.cs
new file mode 100644
index 000000000..74ab9f2cc
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDTO.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel.DataAnnotations;
+using Microsoft.EntityFrameworkCore;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+///
+/// 备件叫料任务
+///
+[Display(Name = "备件叫料任务")]
+public class SparePartIssueJobDTO : SfsJobDTOBase
+{
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { 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 SparePartRequestNumber { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDetailDTO.cs
new file mode 100644
index 000000000..6ae3e19c2
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/DTOs/SparePartIssueJobDetailDTO.cs
@@ -0,0 +1,519 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Win_in.Sfs.Shared.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueJobDetailDTO : SfsDetailDTOBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobAppService.cs
new file mode 100644
index 000000000..ac7a71a34
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobAppService.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public interface ISparePartIssueJobAppService
+ : ISfsJobAppServiceBase
+{
+ Task> GetByRequestNumberAsync(string requestNumber);
+
+ ///
+ /// 执行任务明细
+ ///
+ ///
+ Task ExecuteDetailAsync(Guid masterId, Guid detailId, SparePartIssueJobDetailDTO issueJobDetailDto);
+
+ Task CompleteAsync(Guid id);
+
+ ///
+ /// 请求点了完成,任务全部都完成
+ ///
+ ///
+ ///
+ Task CompleteByRequestNumberAsync(string requestNumber);
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobCheckInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobCheckInput.cs
new file mode 100644
index 000000000..9869c0960
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobCheckInput.cs
@@ -0,0 +1,6 @@
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueJobCheckInput : SfsJobCheckInputBase
+{
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobDetailInput.cs
new file mode 100644
index 000000000..e10989964
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobDetailInput.cs
@@ -0,0 +1,519 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Win_in.Sfs.Shared.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueJobDetailInput : SfsDetailInputBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobEditInput.cs
new file mode 100644
index 000000000..82cdeed81
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/Inputs/SparePartIssueJobEditInput.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueJobEditInput : 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 SparePartRequestNumber { get; set; }
+
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { 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 = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobPermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobPermissions.cs
new file mode 100644
index 000000000..6e7bb285b
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobPermissions.cs
@@ -0,0 +1,23 @@
+using Volo.Abp.Authorization.Permissions;
+using Win_in.Sfs.Wms.Store.Domain;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public static class SparePartIssueJobPermissions
+{
+
+ public const string Default = StorePermissions.GroupName + "." + nameof(SparePartIssueJob);
+ public const string Create = Default + "." + StorePermissions.CreateStr;
+ public const string Update = Default + "." + StorePermissions.UpdateStr;
+ public const string Delete = Default + "." + StorePermissions.DeleteStr;
+
+
+ public static void AddSparePartIssueJobPermission(this PermissionGroupDefinition permissionGroup)
+ {
+ var sparePartIssueJobPermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(SparePartIssueJob)));
+ sparePartIssueJobPermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr));
+ sparePartIssueJobPermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr));
+ sparePartIssueJobPermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr));
+
+ }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDTO.cs
new file mode 100644
index 000000000..6dae0533e
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDTO.cs
@@ -0,0 +1,48 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueNoteDTO : SfsStoreDTOBase, IHasJobNumber, IHasRequestNumber
+{
+
+ ///
+ /// 任务ID
+ ///
+ [Display(Name = "任务ID")]
+ public string JobNumber { get; set; }
+
+ ///
+ /// 请求代码
+ ///
+ [Display(Name = "请求代码")]
+ public string RequestNumber { get; set; }
+
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ ///
+ /// 已确认
+ ///
+ [Display(Name = "已确认")]
+ public bool Confirmed { get; set; }
+
+ ///
+ /// 确认时间
+ ///
+ [Display(Name = "确认时间")]
+ public DateTime? ConfirmTime { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDetailDTO.cs
new file mode 100644
index 000000000..b2d7ffcb4
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/DTOs/SparePartIssueNoteDetailDTO.cs
@@ -0,0 +1,519 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Win_in.Sfs.Shared.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueNoteDetailDTO : SfsDetailDTOBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteAppService.cs
new file mode 100644
index 000000000..3052a3ad3
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteAppService.cs
@@ -0,0 +1,14 @@
+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 ISparePartIssueNoteAppService : ISfsStoreMasterReadOnlyAppServiceBase
+{
+ Task CreateAsync(SparePartIssueNoteEditInput input);
+
+ Task ConfirmAsync(Guid id);
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteDetailInput.cs
new file mode 100644
index 000000000..82393b0b1
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteDetailInput.cs
@@ -0,0 +1,519 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Win_in.Sfs.Shared.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueNoteDetailInput : SfsDetailInputBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteEditInput.cs
new file mode 100644
index 000000000..8917c4cbb
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteEditInput.cs
@@ -0,0 +1,58 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueNoteEditInput : 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 = "明细列表")]
+ public List Details { get; set; }
+
+ ///
+ /// 请求号码
+ ///
+ [Display(Name = "请求号码")]
+ public string RequestNumber { get; set; }
+
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteImportInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteImportInput.cs
new file mode 100644
index 000000000..224dcfe75
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/Inputs/SparePartIssueNoteImportInput.cs
@@ -0,0 +1,36 @@
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueNoteImportInput : 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 EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ [Required(ErrorMessage = "{0}是必填项")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNotePermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNotePermissions.cs
new file mode 100644
index 000000000..5d0ef807f
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNotePermissions.cs
@@ -0,0 +1,20 @@
+using Volo.Abp.Authorization.Permissions;
+using Win_in.Sfs.Wms.Store.Domain;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public static class SparePartIssueNotePermissions
+{
+ public const string Default = StorePermissions.GroupName + "." + nameof(SparePartIssueNote);
+ public const string Create = Default + "." + StorePermissions.CreateStr;
+ public const string Update = Default + "." + StorePermissions.UpdateStr;
+ public const string Delete = Default + "." + StorePermissions.DeleteStr;
+
+ public static void AddSparePartIssueNotePermission(this PermissionGroupDefinition permissionGroup)
+ {
+ var sparePartIssueNotePermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(SparePartIssueNote)));
+ sparePartIssueNotePermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr));
+ sparePartIssueNotePermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr));
+ sparePartIssueNotePermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr));
+ }
+}
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 ba0036681..419cf52ce 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
@@ -28,6 +28,7 @@ public class StorePermissionDefinitionProvider : PermissionDefinitionProvider
storeGroup.AddPutawayNotePermission();
storeGroup.AddMaterialRequestPermission();
storeGroup.AddInjectionIssueRequestPermission();
+ storeGroup.AddSparePartIssueRequestPermission();
storeGroup.AddKittingIssueRequestPermission();
storeGroup.AddCoatingIssueRequestPermission();
storeGroup.AddAssembleIssueRequestPermission();
@@ -37,6 +38,7 @@ public class StorePermissionDefinitionProvider : PermissionDefinitionProvider
storeGroup.AddInjectionIssueNotePermission();
storeGroup.AddAssembleIssueNotePermission();
storeGroup.AddCoatingIssueNotePermission();
+ storeGroup.AddSparePartIssueNotePermission();
storeGroup.AddKittingIssueNotePermission();
storeGroup.AddThirdLocationNotePermission();
storeGroup.AddContainerNotePermission();
@@ -110,6 +112,7 @@ public class StorePermissionDefinitionProvider : PermissionDefinitionProvider
storeGroup.AddPutawayJobPermission();
storeGroup.AddIssueJobPermission();
storeGroup.AddInjectionIssueJobPermission();
+ storeGroup.AddSparePartIssueJobPermission();
storeGroup.AddKittingIssueJobPermission();
storeGroup.AddCoatingIssueJobPermission();
storeGroup.AddAssembleIssueJobPermission();
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDTO.cs
new file mode 100644
index 000000000..12f157808
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDTO.cs
@@ -0,0 +1,34 @@
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueRequestDTO : SfsStoreRequestDTOBase, IHasNumber
+{
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { 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/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDetailDTO.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDetailDTO.cs
new file mode 100644
index 000000000..c37257d9a
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/DTOs/SparePartIssueRequestDetailDTO.cs
@@ -0,0 +1,99 @@
+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 SparePartIssueRequestDetailDTO : SfsStoreDetailWithQtyDTOBase
+{
+ #region 目标库位信息
+
+ ///
+ /// 目标库位
+ ///
+ [Display(Name = "目标库位")]
+ [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储位")]
+ public string ToLocationErpCode { get; set; }
+
+ ///
+ /// 目标仓库
+ ///
+ [Display(Name = "目标仓库")]
+ public string ToWarehouseCode { get; set; }
+
+ #endregion
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { 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; }
+
+ ///
+ /// 需求箱数量
+ ///
+ [Display(Name = "需求箱数量")]
+ public decimal BoxQty { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/ISparePartIssueRequestAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/ISparePartIssueRequestAppService.cs
new file mode 100644
index 000000000..e930ba732
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/ISparePartIssueRequestAppService.cs
@@ -0,0 +1,16 @@
+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 ISparePartIssueRequestAppService
+ : ISfsStoreRequestMasterAppServiceBase
+
+{
+ Task CreateAndHandleAsync(SparePartIssueRequestEditInput input);
+ Task UpdateStatusCompletedAsync(string number);
+ Task IsHasNewJobAsync(string requestNumber,List jobNumber);
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestDetailInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestDetailInput.cs
new file mode 100644
index 000000000..82c797d70
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestDetailInput.cs
@@ -0,0 +1,91 @@
+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 SparePartIssueRequestDetailInput : SfsStoreDetailWithQtyInputBase
+{
+ #region 目标库位信息
+
+ ///
+ /// 目标库位
+ ///
+ [Display(Name = "目标库位")]
+ [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储位")]
+ public string ToLocationErpCode { get; set; }
+
+ ///
+ /// 目标仓库
+ ///
+ [Display(Name = "目标仓库")]
+ public string ToWarehouseCode { get; set; }
+
+ #endregion
+
+ ///
+ /// 生产线
+ ///
+ [Display(Name = "生产线")]
+ [StringLength(SfsEfCorePropertyConst.CodeLength, ErrorMessage = "{0}最多输入{1}个字符")]
+ public string ProdLine { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [Display(Name = "状态")]
+ public EnumRequestStatus RequestStatus { get; set; } = EnumRequestStatus.New;
+
+ ///
+ /// 已发数量
+ ///
+ [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; }
+
+ ///
+ /// 需求箱数量
+ ///
+ [Display(Name = "需求箱数量")]
+ public decimal BoxQty { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestEditInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestEditInput.cs
new file mode 100644
index 000000000..e10b805b6
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestEditInput.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public class SparePartIssueRequestEditInput : SfsStoreRequestCreateOrUpdateInputBase
+{
+ #region Base
+
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ ///
+ /// 明细列表
+ ///
+ [Display(Name = "明细列表")]
+ public List Details { get; set; } = new List();
+ #endregion
+
+ #region Create
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestImportInput.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestImportInput.cs
new file mode 100644
index 000000000..032cd4ac7
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/Inputs/SparePartIssueRequestImportInput.cs
@@ -0,0 +1,50 @@
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+[Display(Name = "叫料申请")]
+public class SparePartIssueRequestImportInput : SfsStoreImportInputBase
+{
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { 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.Contracts/Requests/IssueRequest/SparePartIssueRequests/SparePartIssueRequestPermissions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/SparePartIssueRequestPermissions.cs
new file mode 100644
index 000000000..bb4512266
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Requests/IssueRequest/SparePartIssueRequests/SparePartIssueRequestPermissions.cs
@@ -0,0 +1,22 @@
+using Volo.Abp.Authorization.Permissions;
+using Win_in.Sfs.Wms.Store.Domain;
+
+namespace Win_in.Sfs.Wms.Store.Application.Contracts;
+
+public static class SparePartIssueRequestPermissions
+{
+
+ public const string Default = StorePermissions.GroupName + "." + nameof(SparePartIssueRequest);
+ public const string Create = Default + "." + StorePermissions.CreateStr;
+ public const string Update = Default + "." + StorePermissions.UpdateStr;
+ public const string Delete = Default + "." + StorePermissions.DeleteStr;
+
+ public static void AddSparePartIssueRequestPermission(this PermissionGroupDefinition permissionGroup)
+ {
+ var sparePartIssueRequestPermission = permissionGroup.AddPermission(Default, StorePermissionDefinitionProvider.L(nameof(SparePartIssueRequest)));
+ sparePartIssueRequestPermission.AddChild(Create, StorePermissionDefinitionProvider.L(StorePermissions.CreateStr));
+ sparePartIssueRequestPermission.AddChild(Update, StorePermissionDefinitionProvider.L(StorePermissions.UpdateStr));
+ sparePartIssueRequestPermission.AddChild(Delete, StorePermissionDefinitionProvider.L(StorePermissions.DeleteStr));
+
+ }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAppService.cs
new file mode 100644
index 000000000..72645dc9c
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAppService.cs
@@ -0,0 +1,597 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Castle.Components.DictionaryAdapter;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using MyNamespace;
+using Volo.Abp;
+using Win_in.Sfs.Basedata.Application.Contracts;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+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;
+using Win_in.Sfs.Wms.Store.Jobs.IssueJobs.proxy;
+using Win_in.Sfs.Wms.Store.Notes;
+using Win_in.Sfs.Wms.Store.Options;
+
+namespace Win_in.Sfs.Wms.Store.Application;
+
+[Authorize]
+[Route($"{StoreConsts.RootPath}spare-part-issue-job")]
+public class SparePartIssueJobAppService
+ : SfsJobAppServiceBase,
+ ISparePartIssueJobAppService, ITransferLibCallback
+{
+ private readonly ISparePartIssueJobManager _sparePartIssueJobManager;
+ private readonly ILocationAppService _locationAppService;
+ private readonly ISparePartIssueNoteAppService _sparePartIssueNoteAppService;
+ private readonly IExpectOutAppService _expectOutAppService;
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly ITransferLibRequestAppService _transferLibRequestAppService;
+ private readonly IOptions _options;
+
+ protected ISparePartIssueRequestAppService SparePartIssueRequestAppService =>
+ LazyServiceProvider.LazyGetRequiredService();
+
+ public SparePartIssueJobAppService(
+ ISparePartIssueJobRepository repository, ISparePartIssueJobManager sparePartIssueJobManager,
+ ILocationAppService locationAppService,
+ ISparePartIssueNoteAppService sparePartIssueNoteAppService, IExpectOutAppService expectOutAppService
+ , IHttpClientFactory httpClientFactory
+ , IOptions options, ITransferLibRequestAppService transferLibRequestAppService) : base(
+ repository, sparePartIssueJobManager)
+ {
+ _sparePartIssueJobManager = sparePartIssueJobManager;
+ _locationAppService = locationAppService;
+ _sparePartIssueNoteAppService = sparePartIssueNoteAppService;
+ _expectOutAppService = expectOutAppService;
+ _httpClientFactory = httpClientFactory;
+ _options = options;
+ _transferLibRequestAppService = transferLibRequestAppService;
+ }
+
+ [HttpPost("add-many")]
+ public override async Task> CreateManyAsync(List inputs)
+ {
+ foreach (var input in inputs)
+ {
+ await CheckMinRowAndSetStatusAsync(input).ConfigureAwait(false);
+ await CheckDimensionalStorehouseAsync(input).ConfigureAwait(false);
+ }
+
+ var sparePartIssueJobDtos = await base.CreateManyAsync(inputs).ConfigureAwait(false);
+ foreach (var sparePartIssueJobDto in sparePartIssueJobDtos)
+ {
+ await CheckDimensionalStorehouseAsync(sparePartIssueJobDto).ConfigureAwait(false);
+ }
+
+ return sparePartIssueJobDtos;
+ }
+
+ [HttpPost("")]
+ public override async Task CreateAsync(SparePartIssueJobEditInput input)
+ {
+ await CheckMinRowAndSetStatusAsync(input).ConfigureAwait(false);
+ await CheckDimensionalStorehouseAsync(input).ConfigureAwait(false);
+
+ var sparePartIssueJobDto = await base.CreateAsync(input).ConfigureAwait(false);
+ await CheckDimensionalStorehouseAsync(sparePartIssueJobDto).ConfigureAwait(false);
+
+ return sparePartIssueJobDto;
+ }
+
+ [HttpPost("invalid")]
+ public override async Task CancelAsync(Guid id)
+ {
+ var sparePartJob = await _repository.GetAsync(id).ConfigureAwait(false);
+ if (sparePartJob == null)
+ {
+ throw new UserFriendlyException($"未找到ID为 {id} 的任务");
+ }
+
+ if (sparePartJob.JobStatus == EnumJobStatus.Open ||
+ sparePartJob.JobStatus == EnumJobStatus.Partial ||
+ sparePartJob.JobStatus == EnumJobStatus.Wait||
+ sparePartJob.JobStatus == EnumJobStatus.Doing)
+ {
+ await _expectOutAppService.RemoveByNumberAsync(sparePartJob.Number).ConfigureAwait(false);
+ await _transferLibRequestAppService.CancelByCallRequestNumberAsync(sparePartJob.SparePartRequestNumber)
+ .ConfigureAwait(false);
+
+ sparePartJob.JobStatus = EnumJobStatus.Cancelled;
+ await _repository.UpdateAsync(sparePartJob).ConfigureAwait(false);
+ }
+ else
+ {
+ throw new UserFriendlyException($"任务状态不是" +
+ $"{EnumJobStatus.Open.GetDisplayName()}、" +
+ $"{EnumJobStatus.Partial.GetDisplayName()}、" +
+ $"{EnumJobStatus.Doing.GetDisplayName()}、" +
+ $"{EnumJobStatus.Wait.GetDisplayName()}");
+ }
+ }
+
+ [HttpPost("by-request-number/{requestNumber}")]
+ public virtual async Task> GetByRequestNumberAsync(string requestNumber)
+ {
+ var entitys = await _repository.GetListAsync(p => p.SparePartRequestNumber == requestNumber)
+ .ConfigureAwait(false);
+ return ObjectMapper.Map, List>(entitys);
+ }
+
+ ///
+ /// 库移回调
+ ///
+ ///
+ ///
+ [HttpPost("Do-Call-Back")]
+ public async Task DoTransferLibCallbackAsync(TransferLibJobDTO dto)
+ {
+ var job = await _repository.FindAsync(p => p.Number == dto.CallJobNumber).ConfigureAwait(false);
+
+ if (job.JobStatus != EnumJobStatus.Wait)
+ {
+ throw new UserFriendlyException($"任务状态不是{EnumJobStatus.Wait.GetDisplayName()}");
+ }
+
+ var transferLibNoteDetail = dto.Details.First();
+
+ var jobDetail = job.Details.First();
+
+ job.JobStatus = EnumJobStatus.Open;
+
+ jobDetail.TransferLibFromArriveDate = transferLibNoteDetail.HandledFromArriveDate;
+ jobDetail.TransferLibFromContainerCode = transferLibNoteDetail.HandledFromContainerCode;
+ jobDetail.TransferLibFromExpireDate = transferLibNoteDetail.HandledFromExpireDate;
+ jobDetail.TransferLibFromLocationArea = transferLibNoteDetail.HandledFromLocationArea;
+ jobDetail.TransferLibFromLocationCode = transferLibNoteDetail.HandledFromLocationCode;
+ jobDetail.TransferLibFromLocationErpCode = transferLibNoteDetail.HandledFromLocationErpCode;
+ jobDetail.TransferLibFromLocationGroup = transferLibNoteDetail.HandledFromLocationGroup;
+ jobDetail.TransferLibFromLot = transferLibNoteDetail.HandledFromLot;
+ jobDetail.TransferLibFromPackingCode = transferLibNoteDetail.HandledFromPackingCode;
+ jobDetail.TransferLibFromProduceDate = transferLibNoteDetail.HandledFromProduceDate;
+ jobDetail.TransferLibFromQty = transferLibNoteDetail.HandledFromQty;
+ jobDetail.TransferLibFromSupplierBatch = transferLibNoteDetail.HandledFromSupplierBatch;
+ jobDetail.TransferLibFromWarehouseCode = transferLibNoteDetail.HandledFromWarehouseCode;
+
+ jobDetail.TransferLibToArriveDate = transferLibNoteDetail.HandledToArriveDate;
+ jobDetail.TransferLibToContainerCode = transferLibNoteDetail.HandledToContainerCode;
+ jobDetail.TransferLibToExpireDate = transferLibNoteDetail.HandledToExpireDate;
+ jobDetail.TransferLibToLocationArea = transferLibNoteDetail.HandledToLocationArea;
+ jobDetail.TransferLibToLocationCode = transferLibNoteDetail.HandledToLocationCode;
+ jobDetail.TransferLibToLocationErpCode = transferLibNoteDetail.HandledToLocationErpCode;
+ jobDetail.TransferLibToLocationGroup = transferLibNoteDetail.HandledToLocationGroup;
+ jobDetail.TransferLibToLot = transferLibNoteDetail.HandledToLot;
+ jobDetail.TransferLibToPackingCode = transferLibNoteDetail.HandledToPackingCode;
+ jobDetail.TransferLibToProduceDate = transferLibNoteDetail.HandledToProduceDate;
+ jobDetail.TransferLibToQty = transferLibNoteDetail.HandledToQty;
+ jobDetail.TransferLibToSupplierBatch = transferLibNoteDetail.HandledToSupplierBatch;
+ jobDetail.TransferLibToWarehouseCode = transferLibNoteDetail.HandledToWarehouseCode;
+
+ await _repository.UpdateAsync(job).ConfigureAwait(false);
+ }
+
+ ///
+ /// 执行任务明细
+ ///
+ ///
+ [HttpPost("ExecuteDetail/{masterId}")]
+ public async Task ExecuteDetailAsync(Guid masterId, Guid detailId, SparePartIssueJobDetailDTO issueJobDetailDto)
+ {
+ var sparePartIssueJob = await _repository.GetAsync(masterId).ConfigureAwait(false);
+ sparePartIssueJob.JobStatus = EnumJobStatus.Doing;
+
+ var sparePartIssueJobDto = ObjectMapper.Map(sparePartIssueJob);
+ sparePartIssueJobDto.Details = new List { issueJobDetailDto };
+ var sparePartIssueNoteEditInput = await BuildSparePartIssueNoteAsync(sparePartIssueJobDto).ConfigureAwait(false);
+ await _sparePartIssueNoteAppService.CreateAsync(sparePartIssueNoteEditInput).ConfigureAwait(false);
+
+ var issueJobDetail = ObjectMapper.Map(issueJobDetailDto);
+ var entityDetail = sparePartIssueJob.Details.Find(p => p.Id == detailId);
+ issueJobDetail.HandledFromQty = entityDetail.HandledFromQty;
+ issueJobDetail.HandledToQty = entityDetail.HandledToQty;
+
+ issueJobDetail.HandledToQty += issueJobDetailDto.HandledToQty;
+ issueJobDetail.HandledFromQty += issueJobDetailDto.HandledFromQty;
+ sparePartIssueJob.Details = new EditableList { issueJobDetail };
+
+ if (sparePartIssueJob.EnumIssueSendType == EnumIssueSendType.BoxQtyType) //按箱叫料 因为任务只有1箱 所以可以直接完成
+ {
+ if (issueJobDetailDto.RecommendToPackingCode != issueJobDetailDto.HandledToPackingCode)
+ {
+ await CheckPackingCodeIsUserAsync(issueJobDetailDto.HandledToPackingCode, sparePartIssueJob.Number).ConfigureAwait(false);
+ }
+
+ await UpdateRequestAndjobStatusDoneAsync(sparePartIssueJob, issueJobDetailDto, issueJobDetailDto.HandledToQty)
+ .ConfigureAwait(false);
+ await _expectOutAppService.RemoveByNumberAsync(sparePartIssueJob.Number).ConfigureAwait(false);
+ }
+ else
+ {
+ var detail = sparePartIssueJob.Details.First(p => p.Id == issueJobDetailDto.Id);
+ if (issueJobDetail.HandledToQty >= detail.RequestQty)
+ {
+ await UpdateRequestAndjobStatusDoneAsync(sparePartIssueJob, issueJobDetailDto,
+ issueJobDetailDto.HandledToQty).ConfigureAwait(false);
+ }
+ else
+ {
+ await RemoveExpectOutAsync(sparePartIssueJob, issueJobDetailDto, issueJobDetailDto.HandledToQty)
+ .ConfigureAwait(false);
+ }
+ }
+
+ await _repository.UpdateAsync(sparePartIssueJob).ConfigureAwait(false);
+ }
+
+ ///
+ /// 完成任务
+ ///
+ ///
+ ///
+ [HttpPost("Complete/{id}")]
+ public async Task CompleteAsync(Guid id)
+ {
+ var sparePartIssueJob = await _repository.FindAsync(id).ConfigureAwait(false);
+
+ sparePartIssueJob.JobStatus = EnumJobStatus.Done;
+
+ await _expectOutAppService.RemoveByNumberAsync(sparePartIssueJob.Number).ConfigureAwait(false);
+
+ await SparePartIssueRequestAppService.UpdateStatusCompletedAsync(sparePartIssueJob.SparePartRequestNumber)
+ .ConfigureAwait(false);
+ await _transferLibRequestAppService.CancelByCallRequestNumberAsync(sparePartIssueJob.SparePartRequestNumber)
+ .ConfigureAwait(false);
+
+ await _repository.UpdateAsync(sparePartIssueJob).ConfigureAwait(false);
+ }
+
+ ///
+ /// 请求点了完成,任务全部都完成
+ ///
+ ///
+ ///
+ [HttpPost("complete-by-request/{requestNumber}")]
+ public async Task CompleteByRequestNumberAsync(string requestNumber)
+ {
+ var sparePartIssueJobs = await _repository.GetListAsync(p => p.SparePartRequestNumber == requestNumber)
+ .ConfigureAwait(false);
+
+ foreach (var sparePartIssueJob in sparePartIssueJobs)
+ {
+ sparePartIssueJob.JobStatus = EnumJobStatus.Done;
+ await _repository.UpdateAsync(sparePartIssueJob).ConfigureAwait(false);
+ await _expectOutAppService.RemoveByNumberAsync(sparePartIssueJob.Number).ConfigureAwait(false);
+ await _transferLibRequestAppService.CancelByCallRequestNumberAsync(sparePartIssueJob.SparePartRequestNumber)
+ .ConfigureAwait(false);
+ }
+ }
+
+ #region 立库
+
+ ///
+ /// 立体库同步
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("sync-issue-job-stereo")]
+ public async Task SyncIssueJobStereoAsync(List input, string pLoc)
+ {
+ var ret = new ReusltObject();
+ ret.Code = "1";
+ ret.Message = "操作成功";
+ ret.OperateTime = DateTime.Now.ToString("yyyy-MM-dd");
+ try
+ {
+ var IssueJobToRestoDetailDTOs = new List();
+ var main = new IssueJobToRestoDTO();
+ main.OperatorName = CurrentUser.UserName;
+ foreach (var job in input)
+ {
+ foreach (var jobitem in job.Details)
+ {
+ IssueJobToRestoDetailDTOs.Add(new IssueJobToRestoDetailDTO
+ {
+ Count = jobitem.HandledToQty,
+ ProductNo = jobitem.ItemCode,
+ NeedSite = pLoc,
+ WorkNo = job.Number,
+ TaskNo = job.Number
+ });
+ }
+ }
+
+ main.Details = IssueJobToRestoDetailDTOs;
+ var httpclient = _httpClientFactory.CreateClient();
+#if DEBUG
+
+ var json = JsonSerializer.Serialize(main);
+ _options.Value.Address = "http://localhost:59094/"; //测试地址
+ _options.Value.Token = ""; //测试token
+ _options.Value.UserName = ""; //测试用户名
+ _options.Value.Password = ""; //测试密码
+
+#endif
+ if (!string.IsNullOrEmpty(_options.Value.Token))
+ {
+ var token = _options.Value.Token;
+ httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
+ }
+
+ if (!string.IsNullOrEmpty(_options.Value.UserName) && !string.IsNullOrEmpty(_options.Value.Password))
+ {
+ var username = _options.Value.UserName;
+ var password = _options.Value.Password;
+ httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
+ Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")));
+ }
+
+ var client = new IssueJobToRestoClient(_options.Value.Address, httpclient);
+ ret = await client.SyncIssueJobStereoAsync(main).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ ret = new ReusltObject();
+ ret.Code = "2";
+ ret.Message = ex.Message;
+ ret.OperateTime = DateTime.Now.ToString("yyyy-MM-dd");
+ }
+
+ return ret;
+ }
+
+ [HttpPost("receive-issue-job-stereo")]
+ public virtual async Task SyncReciveIssueJobStereoAsync(IssueRequestFromRestoDTO input)
+ {
+#if DEBUG
+ var json = JsonSerializer.Serialize(input);
+#endif
+ var errors = new List();
+ var ret = new ReusltObject { Code = "1", OperateTime = DateTime.Now.ToString("yyyy-MM-dd"), Message = "操作成功" };
+ try
+ {
+ if (input.Jobs.Count > 0)
+ {
+ var jobs = input.Jobs;
+ var numbers = jobs.Select(p => p.JobNumber);
+ var query = _repository.WithDetails()
+ .Where(p => numbers.Contains(p.Number));
+ var entities = query.ToList();
+ var dtos = ObjectMapper.Map, List>(entities);
+ if (input.Jobs.Count == entities.Count)
+ {
+ errors.Add("立体库提交出库任务和WMS任务不符,请核对! \n");
+ }
+
+ foreach (var itm in dtos)
+ {
+ var first = jobs.FirstOrDefault(p => p.JobNumber == itm.Number);
+ var itmDetails = itm.Details.ToList();
+ var details = new List();
+ foreach (var detail in first.Details)
+ {
+ var entity = itmDetails.FirstOrDefault(p => p.ItemCode == detail.ItemCode);
+ var dto = new SparePartIssueJobDetailDTO();
+ dto.HandledFromLocationCode = entity.HandledFromLocationCode;
+ dto.HandledToLocationCode = entity.HandledToLocationCode;
+ dto.ItemCode = detail.ItemCode;
+ dto.RecommendFromQty = detail.Qty;
+ dto.RecommendToQty = detail.Qty;
+ dto.HandledFromQty = detail.Qty;
+ dto.HandledToQty = detail.Qty;
+ dto.Status = entity.Status;
+ details.Add(dto);
+ }
+
+ itm.Details = details;
+ await CompleteAsync(itm.Id, itm).ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ errors.Add("立体库确认单据里无数据! \n");
+ }
+ }
+ catch (Exception ex)
+ {
+ ret = new ReusltObject
+ {
+ Code = "2", OperateTime = DateTime.Now.ToString("yyyy-MM-dd"), Message = ex.Message
+ };
+ return ret;
+ }
+
+ if (errors.Count > 0)
+ {
+ ret = new ReusltObject
+ {
+ Code = "2",
+ OperateTime = DateTime.Now.ToString("yyyy-MM-dd"),
+ Message = string.Join(",", errors.ToArray())
+ };
+ }
+
+ return ret;
+ }
+
+ #endregion
+
+ #region 私有
+
+ ///
+ /// 创建补料记录实体
+ ///
+ ///
+ ///
+ private async Task BuildSparePartIssueNoteAsync(SparePartIssueJobDTO sparePartIssueJobDto)
+ {
+ var sparePartIssueNoteCreateInput =
+ ObjectMapper.Map(sparePartIssueJobDto);
+ sparePartIssueNoteCreateInput.JobNumber = sparePartIssueJobDto.Number;
+
+ await Task.CompletedTask.ConfigureAwait(false);
+
+ return sparePartIssueNoteCreateInput;
+ }
+
+ ///
+ /// 判断是不是在最底层 如果不是则把状态变更为等待 并把库移推荐的From和To赋值
+ ///
+ ///
+ ///
+ private async Task CheckMinRowAndSetStatusAsync(SparePartIssueJobEditInput input)
+ {
+ var jobDetailInputdetail = input.Details.FirstOrDefault();
+
+ var loctionDto = await _locationAppService.GetByCodeAsync(jobDetailInputdetail.RecommendFromLocationCode)
+ .ConfigureAwait(false);
+
+ if (loctionDto.Type == EnumLocationType.RAW && loctionDto.RowCode != 1)
+ {
+ input.JobStatus = EnumJobStatus.Wait;
+ }
+ else if (loctionDto.Type == EnumLocationType.RAW && loctionDto.RowCode == 1)
+ {
+ jobDetailInputdetail.TransferLibFromArriveDate = jobDetailInputdetail.RecommendFromArriveDate;
+ jobDetailInputdetail.TransferLibFromContainerCode = jobDetailInputdetail.RecommendFromContainerCode;
+ jobDetailInputdetail.TransferLibFromExpireDate = jobDetailInputdetail.RecommendFromExpireDate;
+ jobDetailInputdetail.TransferLibFromLocationArea = jobDetailInputdetail.RecommendFromLocationArea;
+ jobDetailInputdetail.TransferLibFromLocationCode = jobDetailInputdetail.RecommendFromLocationCode;
+ jobDetailInputdetail.TransferLibFromLocationErpCode = jobDetailInputdetail.RecommendFromLocationErpCode;
+ jobDetailInputdetail.TransferLibFromLocationGroup = jobDetailInputdetail.RecommendFromLocationGroup;
+ jobDetailInputdetail.TransferLibFromLot = jobDetailInputdetail.RecommendFromLot;
+ jobDetailInputdetail.TransferLibFromPackingCode = jobDetailInputdetail.RecommendFromPackingCode;
+ jobDetailInputdetail.TransferLibFromProduceDate = jobDetailInputdetail.RecommendFromProduceDate;
+ jobDetailInputdetail.TransferLibFromQty = jobDetailInputdetail.RecommendFromQty;
+ jobDetailInputdetail.TransferLibFromSupplierBatch = jobDetailInputdetail.RecommendFromSupplierBatch;
+ jobDetailInputdetail.TransferLibFromWarehouseCode = jobDetailInputdetail.RecommendFromWarehouseCode;
+
+ jobDetailInputdetail.TransferLibToArriveDate = jobDetailInputdetail.RecommendToArriveDate;
+ jobDetailInputdetail.TransferLibToContainerCode = jobDetailInputdetail.RecommendToContainerCode;
+ jobDetailInputdetail.TransferLibToExpireDate = jobDetailInputdetail.RecommendToExpireDate;
+ jobDetailInputdetail.TransferLibToLot = jobDetailInputdetail.RecommendToLot;
+ jobDetailInputdetail.TransferLibToPackingCode = jobDetailInputdetail.RecommendToPackingCode;
+ jobDetailInputdetail.TransferLibToProduceDate = jobDetailInputdetail.RecommendToProduceDate;
+ jobDetailInputdetail.TransferLibToQty = jobDetailInputdetail.RecommendToQty;
+ jobDetailInputdetail.TransferLibToSupplierBatch = jobDetailInputdetail.RecommendToSupplierBatch;
+ jobDetailInputdetail.TransferLibToWarehouseCode = jobDetailInputdetail.TransferLibFromWarehouseCode;
+ jobDetailInputdetail.TransferLibToLocationArea = jobDetailInputdetail.TransferLibFromLocationArea;
+ jobDetailInputdetail.TransferLibToLocationCode = jobDetailInputdetail.TransferLibFromLocationCode;
+ jobDetailInputdetail.TransferLibToLocationErpCode = jobDetailInputdetail.TransferLibFromLocationErpCode;
+ jobDetailInputdetail.TransferLibToLocationGroup = jobDetailInputdetail.TransferLibFromLocationGroup;
+ }
+ }
+
+ ///
+ /// 判断是不是在立体库
+ ///
+ ///
+ ///
+ private async Task CheckDimensionalStorehouseAsync(SparePartIssueJobEditInput input)
+ {
+ var jobDetailInputdetail = input.Details.FirstOrDefault();
+
+ var loctionDto = await _locationAppService.GetByCodeAsync(jobDetailInputdetail.RecommendFromLocationCode)
+ .ConfigureAwait(false);
+
+ if (loctionDto.Type == EnumLocationType.DimensionalStorehouse)
+ {
+ input.JobStatus = EnumJobStatus.Wait;
+ }
+ }
+
+ ///
+ /// 判断是不是在立体库
+ ///
+ ///
+ ///
+ private async Task CheckDimensionalStorehouseAsync(SparePartIssueJobDTO sparePartIssueJobDto)
+ {
+ var jobDetailInputdetail = sparePartIssueJobDto.Details.FirstOrDefault();
+
+ var loctionDto = await _locationAppService.GetByCodeAsync(jobDetailInputdetail.RecommendFromLocationCode)
+ .ConfigureAwait(false);
+
+ if (loctionDto.Type == EnumLocationType.DimensionalStorehouse)
+ {
+ //TODO 立体库
+ var ret = await SyncIssueJobStereoAsync(new List { sparePartIssueJobDto },
+ loctionDto.Code).ConfigureAwait(false);
+ if (ret.Code != "1")
+ {
+ throw new UserFriendlyException($"调用立体库不成功!原因:{ret.Message}");
+ }
+ }
+ }
+
+ ///
+ /// 修改当前任务状态 和 该任务的请求状态
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task UpdateRequestAndjobStatusDoneAsync(SparePartIssueJob sparePartIssueJob,
+ SparePartIssueJobDetailDTO sparePartIssueJobDetailDto, decimal handledToQty)
+ {
+ if (sparePartIssueJob.JobStatus is EnumJobStatus.Closed or EnumJobStatus.Cancelled or EnumJobStatus.None
+ or EnumJobStatus.Done) //需要考虑下 多次提交的问题 所以不判断 进行中
+ {
+ throw new UserFriendlyException(
+ $"任务状态错误:编号为【{sparePartIssueJob.Number}】的任务状态为【{sparePartIssueJob.JobStatus.GetDisplayName()}】");
+ }
+
+ sparePartIssueJob.JobStatus = EnumJobStatus.Done;
+
+ await RemoveExpectOutAsync(sparePartIssueJob, sparePartIssueJobDetailDto, handledToQty).ConfigureAwait(false);
+
+ //await _expectOutAppService.RemoveByNumberAsync(sparePartIssueJob.Number).ConfigureAwait(false);
+
+ await SparePartIssueRequestAppService.UpdateStatusCompletedAsync(sparePartIssueJob.SparePartRequestNumber)
+ .ConfigureAwait(false);
+
+ await Task.CompletedTask.ConfigureAwait(false);
+ }
+
+ ///
+ /// 判断实际TO的箱码是否被占用
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task CheckPackingCodeIsUserAsync(string packingCode,string jobNumber)
+ {
+ var list = await _expectOutAppService.GetListByPackingCodeAsync(packingCode).ConfigureAwait(false);
+ list=list.Where(p => p.JobNumber != jobNumber).ToList();
+ if (list.Any())
+ {
+ throw new UserFriendlyException($"任务号【{list.First().JobNumber}】的任务,已占用【{packingCode}】箱码的库存。");
+ }
+ }
+
+ private async Task RemoveExpectOutAsync(SparePartIssueJob sparePartIssueJob,
+ SparePartIssueJobDetailDTO sparePartIssueJobDetailDto,
+ decimal handledToQty)
+ {
+ await _expectOutAppService.RemoveByNumberAndInventoryAsync(sparePartIssueJob.Number,
+ sparePartIssueJobDetailDto.ItemCode,
+ sparePartIssueJobDetailDto.HandledToLocationCode, sparePartIssueJobDetailDto.HandledToPackingCode,
+ sparePartIssueJobDetailDto.Status, sparePartIssueJobDetailDto.HandledToLot,
+ handledToQty).ConfigureAwait(false);
+ }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAutoMapperProfile.cs
new file mode 100644
index 000000000..0f90cc4bd
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobAutoMapperProfile.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 SparePartIssueJobAutoMapperProfile()
+ {
+ 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/SparePartIssueNotes/SparePartIssueNoteAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteAppService.cs
new file mode 100644
index 000000000..fa6908815
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteAppService.cs
@@ -0,0 +1,62 @@
+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}spare-part-issue-note")]
+public class SparePartIssueNoteAppService :
+ SfsStoreWithDetailsAppServiceBase,
+ ISparePartIssueNoteAppService
+{
+ private readonly ISparePartIssueNoteManager _sparePartIssueNoteManager;
+
+ public SparePartIssueNoteAppService(
+ ISparePartIssueNoteRepository repository,
+ ISparePartIssueNoteManager sparePartIssueNoteManager
+ ) : base(repository)
+ {
+ _sparePartIssueNoteManager = sparePartIssueNoteManager;
+ }
+
+ [HttpPost("")]
+ //[Authorize(SparePartIssueNotePermissions.Create)]
+ public override async Task CreateAsync(SparePartIssueNoteEditInput input)
+ {
+ var entity = ObjectMapper.Map(input);
+ await _sparePartIssueNoteManager.CreateAsync(entity).ConfigureAwait(false);
+ var dto = ObjectMapper.Map(entity);
+ return dto;
+ }
+
+ ///
+ /// 确认对应的记录单
+ ///
+ ///
+ ///
+ [HttpPost("confirm/{id}")]
+ public virtual async Task ConfirmAsync(Guid id)
+ {
+ var sparePartIssueNote= await _repository.GetAsync(id).ConfigureAwait(false);
+ sparePartIssueNote.Confirmed = true;
+ sparePartIssueNote=await _repository.UpdateAsync(sparePartIssueNote).ConfigureAwait(false);
+ await LocalEventBus.PublishAsync(new SfsConfirmedEntityEventData(sparePartIssueNote), false).ConfigureAwait(false);
+ return ObjectMapper.Map(sparePartIssueNote);
+ }
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteAutoMapperProfile.cs
new file mode 100644
index 000000000..2eb63b2f1
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteAutoMapperProfile.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 SparePartIssueNoteAutoMapperProfile()
+ {
+ 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/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAppService.cs
new file mode 100644
index 000000000..21729e608
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAppService.cs
@@ -0,0 +1,392 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Castle.Components.DictionaryAdapter;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using NUglify.Helpers;
+using Volo.Abp;
+using Win_in.Sfs.Basedata.Application.Contracts;
+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}spare-part-issue-request")]
+public class SparePartIssueRequestAppService : SfsStoreRequestAppServiceBase,
+ ISparePartIssueRequestAppService
+{
+ private readonly ISparePartIssueRequestManager _sparePartIssueRequestManager;
+ private readonly ILocationAppService _locationAppService;
+ private readonly IItemBasicAppService _itemBasicAppService;
+ private readonly IProductionLineAppService _productionLineAppService;
+ private readonly ISparePartIssueJobAppService _sparePartIssueJobAppService;
+ private readonly ITransactionTypeAppService _transactionTypeAppService;
+
+ public SparePartIssueRequestAppService(
+ ISparePartIssueRequestRepository repository,
+ ISparePartIssueRequestManager sparePartIssueRequestManager,
+ ILocationAppService locationAppService,
+ IItemBasicAppService itemBasicAppService,
+ IProductionLineAppService productionLineAppService,
+ ITransactionTypeAppService transactionTypeAppService,
+ ISparePartIssueJobAppService sparePartIssueJobAppService)
+ : base(repository, sparePartIssueRequestManager)
+ {
+ _sparePartIssueRequestManager = sparePartIssueRequestManager;
+ _locationAppService = locationAppService;
+ _itemBasicAppService = itemBasicAppService;
+ _productionLineAppService = productionLineAppService;
+ _transactionTypeAppService = transactionTypeAppService;
+ _sparePartIssueJobAppService = sparePartIssueJobAppService;
+ }
+
+ public override async Task HandleAsync(Guid id)
+ {
+ return await base.HandleAsync(id).ConfigureAwait(false);
+ }
+
+ public override async Task CancelAsync(Guid id)
+ {
+ var request = await _repository.GetAsync(id).ConfigureAwait(false);
+
+ var list = await _sparePartIssueJobAppService.GetByRequestNumberAsync(request.Number).ConfigureAwait(false);
+ if (list.Any())
+ {
+ foreach (var sparePartIssueJobDto in list)
+ {
+ if (sparePartIssueJobDto.JobStatus == EnumJobStatus.Open ||
+ sparePartIssueJobDto.JobStatus == EnumJobStatus.Partial ||
+ sparePartIssueJobDto.JobStatus == EnumJobStatus.Doing ||
+ sparePartIssueJobDto.JobStatus == EnumJobStatus.Wait)
+ {
+ await _sparePartIssueJobAppService.CancelAsync(sparePartIssueJobDto.Id).ConfigureAwait(false);
+ }
+ }
+ }
+
+ if (request.RequestStatus == EnumRequestStatus.Partial || request.RequestStatus == EnumRequestStatus.Handling ||
+ request.RequestStatus == EnumRequestStatus.New)
+ {
+ request.RequestStatus = EnumRequestStatus.Cancelled;
+ await _repository.UpdateAsync(request).ConfigureAwait(false);
+ }
+ else
+ {
+ throw new UserFriendlyException($"【{request.RequestStatus.GetDisplayName()}】状态不允许取消");
+ }
+
+ return ObjectMapper.Map(request);
+ }
+
+ public override async Task CompleteAsync(Guid id)
+ {
+ var sparePartIssueRequest = await _repository.GetAsync(id).ConfigureAwait(false);
+ if (sparePartIssueRequest.RequestStatus == EnumRequestStatus.Handling ||
+ sparePartIssueRequest.RequestStatus == EnumRequestStatus.Partial ||
+ sparePartIssueRequest.RequestStatus == EnumRequestStatus.New)
+ {
+ sparePartIssueRequest.RequestStatus = EnumRequestStatus.Completed;
+ }
+ else
+ {
+ throw new UserFriendlyException($"【{sparePartIssueRequest.RequestStatus.GetDisplayName()}】状态不允许完成");
+ }
+
+ await _sparePartIssueJobAppService.CompleteByRequestNumberAsync(sparePartIssueRequest.Number).ConfigureAwait(false);
+
+ return ObjectMapper.Map(await _repository
+ .UpdateAsync(sparePartIssueRequest)
+ .ConfigureAwait(false));
+ }
+
+ [HttpPost("")]
+ public override async Task CreateAsync(SparePartIssueRequestEditInput 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);
+ var productionLineDto = await _productionLineAppService.GetByLocationCodeAsync(detailInput.ToLocationCode)
+ .ConfigureAwait(false);
+ CheckProductionLine(productionLineDto, detailInput.ProdLine);
+
+ detailInput.ProdLine = productionLineDto.Code;
+
+ detailInput.ToLocationArea = toLocationDto.AreaCode;
+ detailInput.ToLocationGroup = toLocationDto.LocationGroupCode;
+ detailInput.ToWarehouseCode = toLocationDto.WarehouseCode;
+ detailInput.ToLocationErpCode = toLocationDto.ErpLocationCode;
+
+ detailInput.ItemDesc1 = itemBasicDto.Desc1;
+ detailInput.ItemDesc2 = itemBasicDto.Desc2;
+ detailInput.ItemName = itemBasicDto.Name;
+ detailInput.Uom = itemBasicDto.BasicUom;
+ detailInput.StdPackQty = itemBasicDto.StdPackQty;
+ detailInput.Status = EnumStatus.Open;
+
+ //因为是刚创建的 所以发料数一定是0
+ detailInput.IssuedQty = 0;
+ detailInput.RecommendType = EnumRecommendType.KITTING;
+ }
+
+ await SetRequestAutoPropertiesAsync(input).ConfigureAwait(false);
+ var entity = ObjectMapper.Map(input);
+
+ var result = await _sparePartIssueRequestManager.CreateByNumberAsync(entity).ConfigureAwait(false);
+
+ var dto = ObjectMapper.Map(result);
+
+ return dto;
+ }
+
+ [HttpPost("create-and-handle")]
+ public async Task CreateAndHandleAsync(SparePartIssueRequestEditInput input)
+ {
+ var sparePartIssueRequestDto = await CreateAsync(input).ConfigureAwait(false);
+
+ //await HandleAsync(sparePartIssueRequestDto.Id).ConfigureAwait(false);
+
+ return sparePartIssueRequestDto;
+ }
+
+ [HttpPost("UpdateStatusCompleted")]
+ public async Task UpdateStatusCompletedAsync(string number)
+ {
+ var sparePartIssueRequest = await _repository.FindAsync(p => p.Number == number).ConfigureAwait(false);
+
+ await UpdateSparePartIssueRequestDetailQtyAsync(sparePartIssueRequest, new EditableList())
+ .ConfigureAwait(false);
+
+ var sparePartIssueJobDtos = await _sparePartIssueJobAppService.GetByRequestNumberAsync(sparePartIssueRequest.Number)
+ .ConfigureAwait(false);
+
+ if (sparePartIssueJobDtos.Any(p =>
+ p.JobStatus == EnumJobStatus.Open || p.JobStatus == EnumJobStatus.Doing ||
+ p.JobStatus == EnumJobStatus.Partial))
+ {
+ return;
+ }
+
+ foreach (var detail in sparePartIssueRequest.Details)
+ {
+ if (detail.Qty >= detail.IssuedQty)
+ {
+ return;
+ }
+ }
+
+ CheckStatus(EnumRequestStatus.Completed, sparePartIssueRequest.RequestStatus);
+ sparePartIssueRequest.RequestStatus = EnumRequestStatus.Completed;
+ await _repository.UpdateAsync(sparePartIssueRequest).ConfigureAwait(false);
+ }
+
+ [HttpPost("IsHasNewJob")]
+ public async Task IsHasNewJobAsync(string requestNumber, List jobNumber)
+ {
+ var joblIssueJobDtos =
+ await _sparePartIssueJobAppService.GetByRequestNumberAsync(requestNumber).ConfigureAwait(false);
+ if (joblIssueJobDtos != null && joblIssueJobDtos.Any())
+ {
+ var jobNumberList = joblIssueJobDtos.Select(p => p.Number);
+
+ var difference = jobNumberList.Except(jobNumber);
+ if (difference.Any())
+ {
+ var result = "已生成任务号";
+ difference.ForEach(p => result += "【" + p + "】");
+ result += "的任务";
+ return result;
+ }
+
+ return "无任务生成,请检查库存";
+ }
+
+ return "无任务生成,请检查库存";
+ }
+
+ #region 私有
+
+ ///
+ /// 赋值Request业务属性
+ ///
+ ///
+ ///
+ private async Task SetRequestAutoPropertiesAsync(SparePartIssueRequestEditInput entity)
+ {
+ var tranType = await _transactionTypeAppService.GetByTransTypeAsync(EnumTransType.Issue, EnumTransSubType.None)
+ .ConfigureAwait(false);
+ Check.NotNull(tranType, "事务类型", "事务类型不存在");
+ entity.AutoSubmit = tranType.AutoSubmitRequest;
+ entity.AutoAgree = tranType.AutoAgreeRequest;
+ entity.AutoHandle = tranType.AutoHandleRequest;
+ entity.AutoCompleteJob = tranType.AutoCompleteJob;
+ entity.DirectCreateNote = tranType.DirectCreateNote;
+ }
+
+ ///
+ /// 修改请求的 已发 已收数量
+ ///
+ ///
+ ///
+ ///
+ private async Task UpdateSparePartIssueRequestDetailQtyAsync(SparePartIssueRequest sparePartIssueRequest,
+ List addSparePartIssueJobDtos)
+ {
+ //原有任务
+ var existSparePartIssueJobDtos = await _sparePartIssueJobAppService
+ .GetByRequestNumberAsync(sparePartIssueRequest.Number)
+ .ConfigureAwait(false);
+
+ //新增的任务和已有的任务总和
+ var allSparePartIssueJobDtos = new List();
+ allSparePartIssueJobDtos.AddRange(addSparePartIssueJobDtos);
+ allSparePartIssueJobDtos.AddRange(existSparePartIssueJobDtos);
+
+ var groupByItemCodeLocationCode = sparePartIssueRequest.Details.GroupBy(p =>
+ new { p.ItemCode, p.ToLocationCode });
+ foreach (var group in groupByItemCodeLocationCode)
+ {
+ foreach (var requestDetail in group)
+ {
+ //所有已发数量
+ decimal allIssuedQty = 0;
+
+ //所有已发数量
+ decimal allReceivedQty = 0;
+
+ foreach (var allSparePartIssueJobDto in allSparePartIssueJobDtos)
+ {
+ var jobDetailDtos = allSparePartIssueJobDto.Details.Where(p =>
+ p.ItemCode == group.Key.ItemCode && p.RequestLocationCode == group.Key.ToLocationCode);
+ //所有已发数量
+ allIssuedQty += jobDetailDtos.Sum(p => p.RequestQty);
+ //所有已发数量
+ allReceivedQty += jobDetailDtos.Sum(p => p.HandledToQty);
+ }
+
+ requestDetail.IssuedQty = allIssuedQty;
+ requestDetail.ReceivedQty = allReceivedQty;
+ }
+ }
+
+ await _repository.UpdateAsync(sparePartIssueRequest).ConfigureAwait(false);
+ }
+
+ #endregion
+
+ #region 校验
+
+ private void CheckStatus(EnumRequestStatus targetStatus, EnumRequestStatus nowStatus)
+ {
+ var validSourceStatuses = new List();
+ switch (targetStatus)
+ {
+ case EnumRequestStatus.None:
+ break;
+ case EnumRequestStatus.New:
+ break;
+ case EnumRequestStatus.Reviewing:
+ validSourceStatuses = new List { EnumRequestStatus.New };
+ break;
+ case EnumRequestStatus.Refused:
+ validSourceStatuses = new List { EnumRequestStatus.Reviewing };
+ break;
+ case EnumRequestStatus.Agreed:
+ validSourceStatuses = new List { EnumRequestStatus.Reviewing };
+ break;
+ case EnumRequestStatus.Handling:
+ validSourceStatuses = new List
+ {
+ EnumRequestStatus.Agreed, EnumRequestStatus.Partial
+ };
+ break;
+ case EnumRequestStatus.Completed:
+ validSourceStatuses = new List
+ {
+ EnumRequestStatus.Handling, EnumRequestStatus.Partial
+ };
+ break;
+ case EnumRequestStatus.Cancelled:
+ validSourceStatuses = new List
+ {
+ EnumRequestStatus.New, EnumRequestStatus.Reviewing, EnumRequestStatus.Agreed
+ };
+ break;
+ case EnumRequestStatus.Abort:
+ validSourceStatuses = new List
+ {
+ EnumRequestStatus.Handling, EnumRequestStatus.Partial
+ };
+ break;
+ case EnumRequestStatus.Partial:
+ {
+ validSourceStatuses = new List
+ {
+ EnumRequestStatus.Handling, EnumRequestStatus.Partial
+ };
+ break;
+ }
+ default:
+ throw new ArgumentOutOfRangeException(nameof(targetStatus), targetStatus, null);
+ }
+
+ if (!validSourceStatuses.Contains(nowStatus))
+ {
+ throw new UserFriendlyException(
+ $"当前状态为 {nowStatus.GetDisplayName()} ,无法变更为 {targetStatus.GetDisplayName()}");
+ }
+ }
+
+ 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()}】类型");
+ }
+ }
+
+ private void CheckProductionLine(ProductionLineDTO productionLineDto, string productionCode)
+ {
+ if (productionLineDto == null)
+ {
+ throw new UserFriendlyException($"未找到生产线【{productionCode}】");
+ }
+ }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAutoMapperProfile.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAutoMapperProfile.cs
new file mode 100644
index 000000000..bfc006962
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/IssuelRequests/SparePartIssueRequests/SparePartIssueRequestAutoMapperProfile.cs
@@ -0,0 +1,65 @@
+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 SparePartIssueRequestAutoMapperProfile()
+ {
+ CreateMap()
+ .ReverseMap();
+
+ CreateMap()
+ .ReverseMap();
+
+ CreateMap()
+ .IgnoreAuditedObjectProperties()
+ .Ignore(x => x.MasterID)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Number)
+ .Ignore(x => x.Id);
+
+ CreateMap()
+ .IgnoreAuditedObjectProperties()
+ .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.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 4e0c3b45a..f742e0b0c 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
@@ -16,6 +16,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile
MaterialRequestAutoMapperProfile();
InjectionIssueRequestAutoMapperProfile();
InjectionPlanRequestAutoMapperProfile();
+ SparePartIssueRequestAutoMapperProfile();
KittingIssueRequestAutoMapperProfile();
AssembleIssueRequestAutoMapperProfile();
ThirdLocationRequestAutoMapperProfile();
@@ -72,6 +73,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile
InjectionIssueNoteAutoMapperProfile();
InjectionPlanNoteAutoMapperProfile();
AssembleIssueNoteAutoMapperProfile();
+ SparePartIssueNoteAutoMapperProfile();
KittingIssueNoteAutoMapperProfile();
ThirdLocationNoteAutoMapperProfile();
ContainerNoteAutoMapperProfile();
@@ -116,6 +118,7 @@ public partial class StoreApplicationAutoMapperProfile : Profile
InjectionIssueJobAutoMapperProfile();
InjectionPlanJobAutoMapperProfile();
AssembleIssueJobAutoMapperProfile();
+ SparePartIssueJobAutoMapperProfile();
KittingIssueJobAutoMapperProfile();
ThirdLocationJobAutoMapperProfile();
ContainerJobAutoMapperProfile();
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobManager.cs
new file mode 100644
index 000000000..1546866db
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobManager.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueJobManager : IJobManager
+{
+ Task GetAsync(Expression> expression);
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobRepository.cs
new file mode 100644
index 000000000..d1af92978
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/ISparePartIssueJobRepository.cs
@@ -0,0 +1,6 @@
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueJobRepository : ISfsJobRepositoryBase
+{
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJob.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJob.cs
new file mode 100644
index 000000000..555d606cc
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJob.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
+using Win_in.Sfs.Shared.Domain.Entities;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+///
+/// 备件发料任务
+///
+[Display(Name = "备件发料任务")]
+public class SparePartIssueJob : SfsJobAggregateRootBase
+{
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 要料单号
+ ///
+ public string SparePartRequestNumber { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ [Display(Name = "使用在途库")]
+ public bool UseOnTheWayLocation { get; set; }
+
+ ///
+ /// 任务明细
+ ///
+ public override List Details { get; set; } = new List();
+
+ public EnumIssueSendType EnumIssueSendType { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDetail.cs
new file mode 100644
index 000000000..b393dffb8
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDetail.cs
@@ -0,0 +1,524 @@
+using System;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain;
+using Win_in.Sfs.Shared.Domain.Shared;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public class SparePartIssueJobDetail : SfsDetailEntityBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+
+ public void SetId(Guid id)
+ {
+ this.Id = id;
+ }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobManager.cs
new file mode 100644
index 000000000..a2098810d
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobManager.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.Users;
+using Volo.Abp.Validation;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Wms.Inventory.Application.Contracts;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public class SparePartIssueJobManager : SfsJobManagerBase, ISparePartIssueJobManager
+{
+ private readonly IBalanceAppService _balanceAppService;
+ private readonly IExpectOutAppService _expectOutAppService;
+
+ public SparePartIssueJobManager(
+ ISparePartIssueJobRepository repository,
+ IBalanceAppService balanceAppService,
+ IExpectOutAppService expectOutAppService) : base(repository)
+ {
+ _balanceAppService = balanceAppService;
+ _expectOutAppService = expectOutAppService;
+ }
+
+ ///
+ /// 执行任务 发料任务
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override async Task CompleteAsync(SparePartIssueJob input, ICurrentUser user)
+ {
+ var entity = await Repository.FindAsync(input.Id).ConfigureAwait(false);
+
+ var inputDetail = input.Details.First();
+ var detail = entity.Details.First();
+
+ var expectOutDtos = await _expectOutAppService.GetListByItemCodeAndStatusAndPackingCodeAsync(detail.ItemCode, detail.HandledFromLocationCode, detail.HandledFromPackingCode, detail.Status, detail.HandledFromLot).ConfigureAwait(false);
+ if (expectOutDtos.Any())
+ {
+ throw new UserFriendlyException($" 箱码:{detail.HandledFromPackingCode}," +
+ $" 物品代码:{detail.ItemCode}," +
+ $" 库位代码:{detail.HandledFromLocationCode}," +
+ $" 状态:{detail.Status}," +
+ $" 批次:{detail.HandledFromLot}" +
+ $" 的库存被占用【预计出】");
+ }
+
+ var balanceDto=await _balanceAppService.GetRealQtyByPackingCodeAndItemCodeAndLocationCodeAndStatusAsync(inputDetail.HandledFromPackingCode, inputDetail.ItemCode, inputDetail.HandledFromLocationCode, inputDetail.Status, inputDetail.HandledFromLot).ConfigureAwait(false);
+ if (balanceDto.Qty <= 0)
+ {
+ throw new UserFriendlyException($" 箱码:{detail.HandledFromPackingCode}," +
+ $" 物品代码:{detail.ItemCode}," +
+ $" 库位代码:{detail.HandledFromLocationCode}," +
+ $" 状态:{detail.Status}," +
+ $" 批次:{detail.HandledFromLot}" +
+ $" 的可用库存不大于0,现在为{balanceDto.Qty},请检查【库存数量】和【预计出】");
+ }
+
+ detail.HandledFromArriveDate = inputDetail.HandledFromArriveDate;
+ detail.HandledFromContainerCode = inputDetail.HandledFromContainerCode;
+ detail.HandledFromExpireDate = inputDetail.HandledFromExpireDate;
+ detail.HandledFromLocationArea = inputDetail.HandledFromLocationArea;
+ detail.HandledFromLocationCode = inputDetail.HandledFromLocationCode;
+ detail.HandledFromLocationErpCode = inputDetail.HandledFromLocationErpCode;
+ detail.HandledFromLocationGroup = inputDetail.HandledFromLocationGroup;
+ detail.HandledFromLot = inputDetail.HandledFromLot;
+ detail.HandledFromPackingCode = inputDetail.HandledFromPackingCode;
+ detail.HandledFromProduceDate = inputDetail.HandledFromProduceDate;
+ detail.HandledFromQty = inputDetail.HandledFromQty;
+ detail.HandledFromSupplierBatch = inputDetail.HandledFromSupplierBatch;
+ detail.HandledFromWarehouseCode = inputDetail.HandledFromWarehouseCode;
+
+ detail.HandledToArriveDate = inputDetail.HandledToArriveDate;
+ detail.HandledToContainerCode = inputDetail.HandledToContainerCode;
+ detail.HandledToExpireDate = inputDetail.HandledToExpireDate;
+ detail.HandledToLocationArea = inputDetail.HandledToLocationArea;
+ detail.HandledToLocationCode = inputDetail.HandledToLocationCode;
+ detail.HandledToLocationErpCode = inputDetail.HandledToLocationErpCode;
+ detail.HandledToLocationGroup = inputDetail.HandledToLocationGroup;
+ detail.HandledToLot = inputDetail.HandledToLot;
+ detail.HandledToPackingCode = inputDetail.HandledToPackingCode;
+ detail.HandledToProduceDate = inputDetail.HandledToProduceDate;
+ detail.HandledToQty = inputDetail.HandledToQty;
+ detail.HandledToSupplierBatch = inputDetail.HandledToSupplierBatch;
+ detail.HandledToWarehouseCode = inputDetail.HandledToWarehouseCode;
+
+ detail.HandledToPackingCode = string.Empty;
+ detail.HandledToLot = string.Empty;
+ detail.HandledToContainerCode = string.Empty;
+
+ return await base.CompleteAsync(entity, user).ConfigureAwait(false);
+ }
+
+ public async Task GetAsync(Expression> expression)
+ {
+ return await Repository.FindAsync(expression).ConfigureAwait(false);
+ }
+
+ #region 无用
+
+ public override Task> GetWorkingListByPackingAsync(string packingCode)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Task> GetWorkingListByContainerAsync(string containerCode)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void CheckDetails(SparePartIssueJob entity, AbpValidationResult result)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteManager.cs
new file mode 100644
index 000000000..d1391a3a8
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteManager.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueNoteManager : ISfsStoreManager
+{
+ Task ConfirmAsync(Guid id);
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteRepository.cs
new file mode 100644
index 000000000..dfea3eb8b
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/ISparePartIssueNoteRepository.cs
@@ -0,0 +1,6 @@
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueNoteRepository : ISfsStoreRepositoryBase
+{
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNote.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNote.cs
new file mode 100644
index 000000000..12ebea7b0
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNote.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp;
+using Win_in.Sfs.Shared.Domain.Entities;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+///
+/// 备件叫料记录
+///
+public class SparePartIssueNote : SfsStoreAggregateRootBase, IHasJobNumber, IHasRequestNumber
+{
+ ///
+ /// 任务ID
+ ///
+ [IgnoreUpdate]
+ public string JobNumber { get; set; }
+
+ ///
+ /// 明细列表
+ ///
+ public override List Details { get; set; } = new List();
+
+ public string RequestNumber { get; set; }
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ public bool UseOnTheWayLocation { get; set; }
+
+ ///
+ /// 确认时间
+ ///
+ [Display(Name = "确认时间")]
+ public DateTime? ConfirmTime { get; set; }
+
+ ///
+ /// 已确认
+ ///
+ [Display(Name = "已确认")]
+ public bool Confirmed { get; set; }
+
+ public EnumIssueSendType EnumIssueSendType { 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/SparePartIssueNotes/SparePartIssueNoteDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteDetail.cs
new file mode 100644
index 000000000..d36c4d424
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteDetail.cs
@@ -0,0 +1,519 @@
+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.Domain;
+
+public class SparePartIssueNoteDetail : SfsStoreDetailEntityBase
+{
+ #region 库存基础信息
+
+ ///
+ /// 物品代码
+ ///
+ public string ItemCode { get; set; }
+
+ ///
+ /// 物品名称
+ ///
+ public string ItemName { get; set; }
+
+ ///
+ /// 物品描述1
+ ///
+ public string ItemDesc1 { get; set; }
+
+ ///
+ /// 物品描述2
+ ///
+ public string ItemDesc2 { get; set; }
+
+ ///
+ /// 标包数量
+ ///
+ [Display(Name = "标包数量")]
+ [Column(TypeName = "decimal(18,6)")]
+ public decimal StdPackQty { get; set; }
+
+ ///
+ /// 库存状态
+ ///
+ public EnumInventoryStatus Status { get; set; }
+
+ ///
+ /// 计量单位
+ ///
+ public string Uom { get; set; }
+
+ #endregion
+
+ #region 请求信息
+
+ ///
+ /// 请求库位
+ ///
+ public string RequestLocationCode { get; set; }
+
+ ///
+ /// 到库区
+ ///
+ public string RequestLocationArea { get; set; }
+
+ ///
+ /// 到库位组
+ ///
+ public string RequestLocationGroup { get; set; }
+
+ ///
+ /// 到ERP库位
+ ///
+ public string RequestLocationErpCode { get; set; }
+
+ ///
+ /// 到仓库
+ ///
+ public string RequestWarehouseCode { get; set; }
+
+ ///
+ /// 在途库库位
+ ///
+ public string OnTheWayLocationCode { get; set; }
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { get; set; }
+
+ ///
+ /// 位置码
+ ///
+ public string PositionCode { get; set; }
+
+ ///
+ /// 推荐的类型
+ ///
+ public EnumRecommendType RecommendType { get; set; }
+
+ ///
+ /// 需求数量
+ ///
+ public decimal RequestQty { get; set; }
+
+ #endregion
+
+ #region 推荐来源
+
+ ///
+ /// 推荐来源托标签
+ ///
+ public string RecommendFromContainerCode { get; set; }
+
+ ///
+ /// 推荐来源箱标签
+ ///
+ public string RecommendFromPackingCode { get; set; }
+
+ ///
+ /// 推荐来源批次供应商批次
+ ///
+ public string RecommendFromSupplierBatch { get; set; }
+
+ ///
+ /// 推荐来源批次到货时间
+ ///
+ public DateTime RecommendFromArriveDate { get; set; }
+
+ ///
+ /// 推荐来源批次生产时间
+ ///
+ public DateTime RecommendFromProduceDate { get; set; }
+
+ ///
+ /// 推荐来源批次过期时间
+ ///
+ public DateTime RecommendFromExpireDate { get; set; }
+
+ ///
+ /// 推荐来源批次排序
+ ///
+ public string RecommendFromLot { get; set; }
+
+ ///
+ /// 推荐来源库位
+ ///
+ public string RecommendFromLocationCode { get; set; }
+
+ ///
+ /// 推荐来源库区
+ ///
+ public string RecommendFromLocationArea { get; set; }
+
+ ///
+ /// 推荐来源库位组
+ ///
+ public string RecommendFromLocationGroup { get; set; }
+
+ ///
+ /// 推荐来源ERP库位
+ ///
+ public string RecommendFromLocationErpCode { get; set; }
+
+ ///
+ /// 推荐来源仓库
+ ///
+ public string RecommendFromWarehouseCode { get; set; }
+
+ ///
+ /// 推荐来源数量
+ ///
+ public decimal RecommendFromQty { get; set; }
+
+ #endregion
+
+ #region 推荐目标
+
+ ///
+ /// 推荐目标托标签
+ ///
+ public string RecommendToContainerCode { get; set; }
+
+ ///
+ /// 推荐目标箱标签
+ ///
+ public string RecommendToPackingCode { get; set; }
+
+ ///
+ /// 推荐目标批次供应商批次
+ ///
+ public string RecommendToSupplierBatch { get; set; }
+
+ ///
+ /// 推荐目标批次到货时间
+ ///
+ public DateTime RecommendToArriveDate { get; set; }
+
+ ///
+ /// 推荐目标批次生产时间
+ ///
+ public DateTime RecommendToProduceDate { get; set; }
+
+ ///
+ /// 推荐目标批次过期时间
+ ///
+ public DateTime RecommendToExpireDate { get; set; }
+
+ ///
+ /// 推荐目标批次排序
+ ///
+ public string RecommendToLot { get; set; }
+
+ ///
+ /// 推荐目标库位
+ ///
+ public string RecommendToLocationCode { get; set; }
+
+ ///
+ /// 推荐目标库区
+ ///
+ public string RecommendToLocationArea { get; set; }
+
+ ///
+ /// 推荐目标库位组
+ ///
+ public string RecommendToLocationGroup { get; set; }
+
+ ///
+ /// 推荐目标ERP库位
+ ///
+ public string RecommendToLocationErpCode { get; set; }
+
+ ///
+ /// 推荐目标仓库
+ ///
+ public string RecommendToWarehouseCode { get; set; }
+
+ ///
+ /// 推荐目标数量
+ ///
+ public decimal RecommendToQty { get; set; }
+
+ #endregion
+
+ #region 库移来源
+
+ ///
+ /// 库移来源托标签
+ ///
+ public string TransferLibFromContainerCode { get; set; }
+
+ ///
+ /// 库移来源箱标签
+ ///
+ public string TransferLibFromPackingCode { get; set; }
+
+ ///
+ /// 库移来源批次供应商批次
+ ///
+ public string TransferLibFromSupplierBatch { get; set; }
+
+ ///
+ /// 库移来源批次到货时间
+ ///
+ public DateTime TransferLibFromArriveDate { get; set; }
+
+ ///
+ /// 库移来源批次生产时间
+ ///
+ public DateTime TransferLibFromProduceDate { get; set; }
+
+ ///
+ /// 库移来源批次过期时间
+ ///
+ public DateTime TransferLibFromExpireDate { get; set; }
+
+ ///
+ /// 库移来源批次排序
+ ///
+ public string TransferLibFromLot { get; set; }
+
+ ///
+ /// 库移来源库位
+ ///
+ public string TransferLibFromLocationCode { get; set; }
+
+ ///
+ /// 库移来源库区
+ ///
+ public string TransferLibFromLocationArea { get; set; }
+
+ ///
+ /// 库移来源库位组
+ ///
+ public string TransferLibFromLocationGroup { get; set; }
+
+ ///
+ /// 库移来源ERP库位
+ ///
+ public string TransferLibFromLocationErpCode { get; set; }
+
+ ///
+ /// 库移来源仓库
+ ///
+ public string TransferLibFromWarehouseCode { get; set; }
+
+ ///
+ /// 库移来源数量
+ ///
+ public decimal TransferLibFromQty { get; set; }
+
+ #endregion
+
+ #region 库移目标
+
+ ///
+ /// 库移目标托标签
+ ///
+ public string TransferLibToContainerCode { get; set; }
+
+ ///
+ /// 库移目标箱标签
+ ///
+ public string TransferLibToPackingCode { get; set; }
+
+ ///
+ /// 库移目标批次供应商批次
+ ///
+ public string TransferLibToSupplierBatch { get; set; }
+
+ ///
+ /// 库移目标批次到货时间
+ ///
+ public DateTime TransferLibToArriveDate { get; set; }
+
+ ///
+ /// 库移目标批次生产时间
+ ///
+ public DateTime TransferLibToProduceDate { get; set; }
+
+ ///
+ /// 库移目标批次过期时间
+ ///
+ public DateTime TransferLibToExpireDate { get; set; }
+
+ ///
+ /// 库移目标批次排序
+ ///
+ public string TransferLibToLot { get; set; }
+
+ ///
+ /// 库移目标库位
+ ///
+ public string TransferLibToLocationCode { get; set; }
+
+ ///
+ /// 库移目标库区
+ ///
+ public string TransferLibToLocationArea { get; set; }
+
+ ///
+ /// 库移目标库位组
+ ///
+ public string TransferLibToLocationGroup { get; set; }
+
+ ///
+ /// 库移目标ERP库位
+ ///
+ public string TransferLibToLocationErpCode { get; set; }
+
+ ///
+ /// 库移目标仓库
+ ///
+ public string TransferLibToWarehouseCode { get; set; }
+
+ ///
+ /// 库移目标数量
+ ///
+ public decimal TransferLibToQty { get; set; }
+
+ #endregion
+
+ #region 实际来源
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledFromContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledFromPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledFromSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledFromArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledFromProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledFromExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledFromLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledFromLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledFromLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledFromLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledFromLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledFromWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledFromQty { get; set; }
+
+ #endregion
+
+ #region 实际目标
+
+ ///
+ /// 实际目标托标签
+ ///
+ public string HandledToContainerCode { get; set; }
+
+ ///
+ /// 实际箱标签
+ ///
+ public string HandledToPackingCode { get; set; }
+
+ ///
+ /// 实际批次供应商批次
+ ///
+ public string HandledToSupplierBatch { get; set; }
+
+ ///
+ /// 实际批次到货时间
+ ///
+ public DateTime HandledToArriveDate { get; set; }
+
+ ///
+ /// 实际批次生产时间
+ ///
+ public DateTime HandledToProduceDate { get; set; }
+
+ ///
+ /// 实际批次过期时间
+ ///
+ public DateTime HandledToExpireDate { get; set; }
+
+ ///
+ /// 实际批次排序
+ ///
+ public string HandledToLot { get; set; }
+
+ ///
+ /// 实际库位
+ ///
+ public string HandledToLocationCode { get; set; }
+
+ ///
+ /// 实际库区
+ ///
+ public string HandledToLocationArea { get; set; }
+
+ ///
+ /// 实际库位组
+ ///
+ public string HandledToLocationGroup { get; set; }
+
+ ///
+ /// 实际ERP库位
+ ///
+ public string HandledToLocationErpCode { get; set; }
+
+ ///
+ /// 实际仓库
+ ///
+ public string HandledToWarehouseCode { get; set; }
+
+ ///
+ /// 实际数量
+ ///
+ public decimal HandledToQty { get; set; }
+
+ #endregion
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteManager.cs
new file mode 100644
index 000000000..4761961b0
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Notes/IssueNotes/SparePartIssueNotes/SparePartIssueNoteManager.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 SparePartIssueNoteManager : SfsStoreManagerBase, ISparePartIssueNoteManager
+{
+
+ public SparePartIssueNoteManager(
+ ISparePartIssueNoteRepository 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(SparePartIssueNote entity)
+ {
+ try
+ {
+ await LocalEventBus.PublishAsync(new SfsConfirmedEntityEventData(entity), false).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogDebug($"{nameof(SparePartIssueNote)} Confirmed Event:{ex.Message}", null);
+ Console.WriteLine(ex.Source);
+ throw;
+ }
+ }
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartIssueRequestRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartIssueRequestRepository.cs
new file mode 100644
index 000000000..8b790a88c
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartIssueRequestRepository.cs
@@ -0,0 +1,9 @@
+using Win_in.Sfs.Shared.Domain;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueRequestRepository : ISfsStoreRepositoryBase,
+ ISfsBulkRepositoryBase
+{
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartRequestManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartRequestManager.cs
new file mode 100644
index 000000000..5a4d9b272
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/ISparePartRequestManager.cs
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+using Win_in.Sfs.Shared.Domain;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public interface ISparePartIssueRequestManager : ISfsStoreRequestManager,
+ IBulkImportService
+{
+
+ Task CompleteAsync(string number);
+
+ Task CreateByNumberAsync(SparePartIssueRequest entity);
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequest.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequest.cs
new file mode 100644
index 000000000..b8407287c
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequest.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Win_in.Sfs.Shared.Domain.Entities;
+using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+///
+/// 备件叫料申请
+///
+public class SparePartIssueRequest : SfsStoreRequestAggregateRootBase
+{
+ ///
+ /// 叫料类型
+ ///
+ [Display(Name = "叫料类型")]
+ public EnumIssueRequestType IssueRequestType { get; set; }
+
+ ///
+ /// 使用在途库
+ ///
+ public bool UseOnTheWayLocation { get; set; }
+
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestDetail.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestDetail.cs
new file mode 100644
index 000000000..e27b79511
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestDetail.cs
@@ -0,0 +1,103 @@
+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.Domain;
+
+///
+/// 备件叫料申请明细
+///
+public class SparePartIssueRequestDetail : SfsStoreDetailWithQtyEntityBase, IHasToLocation
+{
+ #region 目标库位信息
+
+ ///
+ /// 目标库位
+ ///
+ [Display(Name = "目标库位")]
+ [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储位")]
+ public string ToLocationErpCode { get; set; }
+
+ ///
+ /// 目标仓库
+ ///
+ [Display(Name = "目标仓库")]
+ public string ToWarehouseCode { get; set; }
+
+ #endregion
+
+
+ ///
+ /// 生产线
+ ///
+ public string ProdLine { 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; }
+
+ ///
+ /// 需求箱数量
+ ///
+ [Display(Name = "需求箱数量")]
+ public decimal BoxQty { get; set; }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestManager.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestManager.cs
new file mode 100644
index 000000000..849a5edf0
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/IssueRequests/SparePartIssueRequests/SparePartIssueRequestManager.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Win_in.Sfs.Shared.Domain.Shared;
+using Win_in.Sfs.Shared.Event;
+
+namespace Win_in.Sfs.Wms.Store.Domain;
+
+public class SparePartIssueRequestManager
+ : SfsStoreRequestManagerBase
+ , ISparePartIssueRequestManager
+{
+ private readonly ISparePartIssueRequestRepository _repository;
+
+ public SparePartIssueRequestManager(
+ ISparePartIssueRequestRepository repository
+ ) : base(repository)
+ {
+ _repository = repository;
+ }
+
+ ///
+ /// 创建 同时 直接赋值Number 为了返回Number
+ ///
+ ///
+ ///
+ public virtual async Task CreateByNumberAsync(SparePartIssueRequest entity)
+ {
+ var number = string.IsNullOrEmpty(entity.Number)
+ ? await GenerateNumberAsync(nameof(SparePartIssueRequest), 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 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);
+ }
+ }
+
+ public Task ImportDataAsync(List entities, List deleteEntities = null)
+ {
+ throw new System.NotImplementedException();
+ }
+}
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 6e0fd5d9d..bdc511cb9 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 MaterialRequests { get; }
public DbSet InjectionIssueRequests { get; }
public DbSet InjectionPlanRequests { get; }
+ public DbSet SparePartIssueRequests { get; }
public DbSet KittingIssueRequests { get; }
public DbSet CoatingIssueRequests { get; }
public DbSet AssembleIssueRequest { get; }
@@ -86,6 +87,7 @@ public interface IStoreDbContext : IEfCoreDbContext
public DbSet InjectionIssueNotes { get; }
public DbSet InjectionPlanNotes { get; }
public DbSet AssembleIssueNotes { get; }
+ public DbSet SparePartIssueNotes { get; }
public DbSet KittingIssueNotes { get; }
public DbSet CoatingIssueNotes { get; }
public DbSet ThirdLocationNotes { get; }
@@ -120,6 +122,7 @@ public interface IStoreDbContext : IEfCoreDbContext
public DbSet InjectionIssueJobs { get; }
public DbSet InjectionPlanJobs { get; }
public DbSet AssembleIssueJobs { get; }
+ public DbSet SparePartIssueJobs { get; }
public DbSet KittingIssueJobs { get; }
public DbSet CoatingIssueJobs { get; }
public DbSet ThirdLocationJobs { get; }
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDbContextModelCreatingExtensions.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDbContextModelCreatingExtensions.cs
new file mode 100644
index 000000000..36869f4f6
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobDbContextModelCreatingExtensions.cs
@@ -0,0 +1,61 @@
+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 SparePartIssueJobDbContextModelCreatingExtensions
+{
+ public static void ConfigureSparePartIssueJob(this ModelBuilder builder, StoreModelBuilderConfigurationOptions options)
+ {
+ builder.Entity(b =>
+ {
+ //Configure table & schema name
+ b.ToTable(StoreDbProperties.JobDbTablePrefix + nameof(SparePartIssueJob), options.Schema);
+ //Configure ABP properties
+ b.ConfigureByConvention();
+ //Configure Sfs base properties
+ b.ConfigureSfsBase();
+ //Configure Job base properties
+ b.ConfigureJob();
+ //Properties
+ b.Property(q => q.SparePartRequestNumber).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.JobType).HasConversion();
+ b.Property(q => q.JobStatus).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(StoreDbProperties.JobDbTablePrefix + nameof(SparePartIssueJobDetail), options.Schema);
+ //Configure ABP properties
+ b.ConfigureByConvention();
+ //Configure Sfs base properties
+ b.ConfigureSfsBase();
+ //Configure Job base properties
+ //b.ConfigureJobRecommendFromDetail();
+ //Properties
+
+ b.Property(q => q.RequestLocationCode).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.ProdLine).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.OnTheWayLocationCode).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.PositionCode).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.OnTheWayLocationCode).HasMaxLength(SfsPropertyConst.CodeLength);
+ b.Property(q => q.PositionCode).HasMaxLength(SfsPropertyConst.CodeLength).IsRequired(false);
+ b.Property(q => q.RecommendType).HasMaxLength(SfsPropertyConst.CodeLength).HasConversion();
+ b.Property(q => q.Status).IsRequired().HasMaxLength(SfsPropertyConst.NameLength).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/SparePartIssueJobs/SparePartIssueJobEfCoreRepository.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobEfCoreRepository.cs
new file mode 100644
index 000000000..9afe84c81
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Jobs/IssueJobs/SparePartIssueJobs/SparePartIssueJobEfCoreRepository.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 SparePartIssueJobEfCoreRepository : SfsJobEfCoreRepositoryBase, ISparePartIssueJobRepository
+{
+ public SparePartIssueJobEfCoreRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider)
+ {
+ }
+}
diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Migrations/20240520070345_Update_SparePartIssue.Designer.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Migrations/20240520070345_Update_SparePartIssue.Designer.cs
new file mode 100644
index 000000000..b88597413
--- /dev/null
+++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.EntityFrameworkCore/Migrations/20240520070345_Update_SparePartIssue.Designer.cs
@@ -0,0 +1,34515 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Volo.Abp.EntityFrameworkCore;
+using Win_in.Sfs.Wms.Store.EntityFrameworkCore;
+
+#nullable disable
+
+namespace Win_in.Sfs.Wms.Store.Migrations
+{
+ [DbContext(typeof(StoreDbContext))]
+ [Migration("20240520070345_Update_SparePartIssue")]
+ partial class Update_SparePartIssue
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
+ .HasAnnotation("ProductVersion", "6.0.13")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
+
+ modelBuilder.Entity("Win_in.Sfs.Wms.Store.Domain.AssembleIssueJob", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("AcceptTime")
+ .HasColumnType("datetime2");
+
+ b.Property("AcceptUserId")
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("AcceptUserName")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("AssembleRequestNumber")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("CompleteTime")
+ .HasColumnType("datetime2");
+
+ b.Property("CompleteUserId")
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("CompleteUserName")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasMaxLength(40)
+ .HasColumnType("nvarchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("EnumIssueSendType")
+ .HasColumnType("int");
+
+ b.Property("ExtraProperties")
+ .HasColumnType("nvarchar(max)")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsAutoComplete")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false);
+
+ b.Property("IssueRequestType")
+ .HasColumnType("int");
+
+ b.Property("JobDescription")
+ .HasMaxLength(1024)
+ .HasColumnType("nvarchar(1024)");
+
+ b.Property("JobStatus")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("JobType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Number")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("Priority")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0);
+
+ b.Property("PriorityIncrement")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0);
+
+ b.Property("ProdLine")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("Remark")
+ .HasMaxLength(3072)
+ .HasColumnType("nvarchar(3072)")
+ .HasColumnName("Remark");
+
+ b.Property("TenantId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("TenantId");
+
+ b.Property("UpStreamJobNumber")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("UseOnTheWayLocation")
+ .HasColumnType("bit");
+
+ b.Property("WarehouseCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("WorkGroupCode")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("Worker")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Number")
+ .IsUnique();
+
+ b.ToTable("Job_AssembleIssueJob", (string)null);
+ });
+
+ modelBuilder.Entity("Win_in.Sfs.Wms.Store.Domain.AssembleIssueJobDetail", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("HandledFromArriveDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledFromContainerCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromExpireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledFromLocationArea")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromLocationCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromLocationErpCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromLocationGroup")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromLot")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromPackingCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromProduceDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledFromQty")
+ .HasColumnType("decimal(18,6)");
+
+ b.Property("HandledFromSupplierBatch")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledFromWarehouseCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToArriveDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledToContainerCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToExpireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledToLocationArea")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToLocationCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToLocationErpCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToLocationGroup")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToLot")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToPackingCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToProduceDate")
+ .HasColumnType("datetime2");
+
+ b.Property("HandledToQty")
+ .HasColumnType("decimal(18,6)");
+
+ b.Property("HandledToSupplierBatch")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HandledToWarehouseCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ItemCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ItemDesc1")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ItemDesc2")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ItemName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("MasterID")
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Number")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("OnTheWayLocationCode")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("PositionCode")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("ProdLine")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("RecommendFromArriveDate")
+ .HasColumnType("datetime2");
+
+ b.Property("RecommendFromContainerCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromExpireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("RecommendFromLocationArea")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromLocationCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromLocationErpCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromLocationGroup")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromLot")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromPackingCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromProduceDate")
+ .HasColumnType("datetime2");
+
+ b.Property("RecommendFromQty")
+ .HasColumnType("decimal(18,6)");
+
+ b.Property("RecommendFromSupplierBatch")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendFromWarehouseCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendToArriveDate")
+ .HasColumnType("datetime2");
+
+ b.Property("RecommendToContainerCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RecommendToExpireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("RecommendToLocationArea")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property