feat(mes): 增加盘号管理和库存搜索功能
- 新增 MesQcNcrService 注入支持
- 添加 reelNo 盘号字段到 MesWmMaterialStockAdjustReqVO
- 在 MesWmMaterialStockPageReqVO 中增加 mdmItemId、itemName 和 vendorName 搜索条件
- 实现库存列表按物料名称和供应商名称模糊查询功能
- 完善批次盘号匹配校验逻辑
- 优化销售退货批次验证流程
- 添加盘号相关的单元测试用例
- 修复 SQL 查询中的二进制比较语法问题
| | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Positive; |
| | | import jakarta.validation.constraints.Size; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | |
| | | @Schema(description = "æ¹æ¬¡å·ï¼æ°å»ºæ¹æ¬¡æ¶ä¼ å
¥ï¼ç³»ç»èªå¨åå»ºæ¹æ¬¡è®°å½ï¼", example = "BATCH001") |
| | | private String batchCode; |
| | | |
| | | @Schema(description = "çå·ï¼æ°å»ºæ¹æ¬¡æ¶æå·¥å¡«åï¼", example = "PHCS") |
| | | @Size(max = 128, message = "çå·ä¸è½è¶
è¿128个å符") |
| | | private String reelNo; |
| | | |
| | | @Schema(description = "çäº§æ¥æï¼æ°å»ºæ¹æ¬¡æ¶ä¼ å
¥ï¼", example = "2025-01-01") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) |
| | | @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY) |
| | |
| | | @Schema(description = "åå ", example = "çç¹è°æ´") |
| | | private String reason; |
| | | |
| | | } |
| | | } |
| | |
| | | @Schema(description = "ç©æç¼å·", example = "1") |
| | | private Long itemId; |
| | | |
| | | @Schema(description = "MDM ç©æç¼å·") |
| | | private Long mdmItemId; |
| | | |
| | | @Schema(description = "ç©æåç§°æç¼ç ï¼æ¨¡ç³æ¥è¯¢ï¼") |
| | | private String itemName; |
| | | |
| | | @Schema(description = "ä¾åºååç§°ï¼æ¨¡ç³æ¥è¯¢ï¼") |
| | | private String vendorName; |
| | | |
| | | @Schema(description = "æ¹æ¬¡å·", example = "B20260101") |
| | | private String batchCode; |
| | | |
| | |
| | | package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO; |
| | |
| | | LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>() |
| | | .inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds) |
| | | .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) |
| | | .eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getMdmItemId()) |
| | | .likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) |
| | |
| | | .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId()) |
| | | .eqIfPresent(MesWmMaterialStockDO::getFrozen, reqVO.getFrozen()); |
| | | if (StrUtil.isNotBlank(reqVO.getItemName())) { |
| | | String keyword = "%" + reqVO.getItemName().trim() + "%"; |
| | | wrapper.apply("item_id IN (SELECT id FROM mdm_item WHERE (name LIKE {0} OR code LIKE {0}) AND deleted = 0)", keyword); |
| | | } |
| | | if (StrUtil.isNotBlank(reqVO.getVendorName())) { |
| | | wrapper.apply("vendor_id IN (SELECT id FROM srm_supplier WHERE name LIKE {0} AND deleted = 0)", |
| | | "%" + reqVO.getVendorName().trim() + "%"); |
| | | } |
| | | wrapper.ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) |
| | | .orderByAsc(MesWmMaterialStockDO::getReceiptTime); |
| | | // èæä»è¿æ»¤ï¼Service å±å·²å° virtualFilter è§£æä¸º virtualWarehouseIdï¼ |
| | |
| | | + "JOIN mes_wm_batch b ON b.id = d.batch_id AND b.deleted = 0 AND b.item_id = d.item_id " |
| | | + "WHERE d.deleted = 0 AND s.sale_order_id = #{orderId} AND s.status = #{finishedStatus} " |
| | | + "AND d.item_id = #{itemId} AND l.item_id = #{itemId} AND i.product_id = #{itemId} " |
| | | + "AND BINARY i.reel_no = BINARY b.reel_no " |
| | | + "AND CAST(i.reel_no AS BINARY) = CAST(b.reel_no AS BINARY) " |
| | | + "AND d.batch_id = #{batchId}") |
| | | Long countFinishedSaleBatch(@Param("orderId") Long orderId, @Param("itemId") Long itemId, |
| | | @Param("batchId") Long batchId, @Param("finishedStatus") Integer finishedStatus); |
| | |
| | | MesMdItemDO item = mdItemService.getItem(pageReqVO.getItemId()); |
| | | if (item != null && item.getMdmItemId() != null) { |
| | | itemIds = SetUtils.asSet(item.getMdmItemId()); |
| | | } else { |
| | | return PageResult.empty(); |
| | | } |
| | | } |
| | | // 1.3 è§£æ virtualFilterï¼è½¬æ¢ä¸ºèæä» warehouseId |
| | |
| | | private MesWmBatchDO resolveBatch(MesWmMaterialStockAdjustReqVO reqVO, MesMdmItemDO item) { |
| | | // å³ä½¿ç©ææªå¯ç¨æ®éæ¹æ¬¡ç®¡çï¼ä¹è¦ä¿çå¹¶æ ¡éªçå·è¿½æº¯æ¹æ¬¡ã |
| | | if (reqVO.getBatchId() != null) { |
| | | return batchService.validateBatchExists(reqVO.getBatchId(), reqVO.getItemId()); |
| | | MesWmBatchDO existing = batchService.validateBatchExists(reqVO.getBatchId(), reqVO.getItemId()); |
| | | if (StrUtil.isNotBlank(reqVO.getReelNo()) |
| | | && !Objects.equals(StrUtil.trim(reqVO.getReelNo()), StrUtil.trim(existing.getReelNo()))) { |
| | | throw exception(WM_BATCH_REEL_MISMATCH); |
| | | } |
| | | return existing; |
| | | } |
| | | |
| | | // 1. æªæå®è¿½æº¯æ¹æ¬¡ä¸ç©ææªå¯ç¨æ¹æ¬¡ç®¡çï¼è¿å null |
| | | if (Boolean.FALSE.equals(item.getIsBatchManaged())) { |
| | | if (Boolean.FALSE.equals(item.getIsBatchManaged()) && StrUtil.isBlank(reqVO.getReelNo())) { |
| | | return null; |
| | | } |
| | | |
| | |
| | | MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO() |
| | | .setItemId(reqVO.getItemId()) |
| | | .setBatchCode(reqVO.getBatchCode()) |
| | | .setReelNo(StrUtil.trimToNull(reqVO.getReelNo())) |
| | | .setVendorId(reqVO.getVendorId()) |
| | | .setProduceDate(reqVO.getProduceDate() != null ? reqVO.getProduceDate().atStartOfDay() : null) |
| | | .setExpireDate(reqVO.getExpireDate() != null ? reqVO.getExpireDate().atStartOfDay() : null) |
| | |
| | | MesWmProductSalesStatusEnum.FINISHED.getStatus()) == 0) { |
| | | throw exception(WM_RETURN_SALES_BATCH_NOT_SHIPPED); |
| | | } |
| | | // æå·¥å
¥åºæ¹æ¬¡å¯è½æ²¡æå®¢æ·ï¼ä»
å¨è®¢åçå·å已宿åºåºé½å·²éªè¯åå
许éè´§ã |
| | | if (batch != null && (batch.getClientId() != null || reelNumbers.isEmpty())) { |
| | | batchService.validateBatchExists(batch.getId(), reqVO.getItemId(), returnSales.getClientId(), null); |
| | | } |
| | | } else if (batch != null) { |
| | | batchService.validateBatchExists(batch.getId(), reqVO.getItemId(), returnSales.getClientId(), null); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | // æ ¡éªæ¹æ¬¡åå¨ä¸å±äºå½åç©æåå®¢æ· |
| | | if (batchId != null) { |
| | | // ä»ç¶åè·å客æ·IDï¼æ ¡éªæ¹æ¬¡å½å± |
| | | return batchService.validateBatchExists(batchId, itemId, returnSales.getClientId(), null); |
| | | return batchService.validateBatchExists(batchId, itemId); |
| | | } |
| | | return null; |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.returnissue.MesWmReturnIssueLineService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.returnsales.MesWmReturnSalesLineService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.ncr.MesQcNcrService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | | import org.junit.jupiter.api.Test; |
| | |
| | | private AdminUserApi adminUserApi; |
| | | @MockitoBean |
| | | private MesQcIndicatorResultService indicatorResultService; |
| | | @MockitoBean |
| | | private MesQcNcrService ncrService; |
| | | |
| | | @Test |
| | | public void testFinishRqc_successWithReturnIssue() { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.materialstock; |
| | | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockAdjustReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | class MesWmMaterialStockReelTest { |
| | | @Test |
| | | void manualReelCreatesTraceableBatchEvenWhenBatchManagementIsDisabled() { |
| | | var service = new MesWmMaterialStockServiceImpl(); |
| | | var batches = mock(MesWmBatchService.class); |
| | | ReflectionTestUtils.setField(service, "batchService", batches); |
| | | var item = new MesMdmItemDO(); |
| | | item.setIsBatchManaged(false); |
| | | var request = new MesWmMaterialStockAdjustReqVO(); |
| | | request.setItemId(1L); |
| | | request.setReelNo(" PHCS "); |
| | | MesWmBatchDO batch = MesWmBatchDO.builder().id(2L).reelNo("PHCS").build(); |
| | | when(batches.getOrGenerateBatchCode(any())).thenReturn(batch); |
| | | assertSame(batch, ReflectionTestUtils.invokeMethod(service, "resolveBatch", request, item)); |
| | | verify(batches).getOrGenerateBatchCode(argThat((MesWmBatchGenerateReqVO v) -> "PHCS".equals(v.getReelNo()))); |
| | | } |
| | | |
| | | @Test |
| | | void existingBatchCannotBeRelabelled() { |
| | | var service = new MesWmMaterialStockServiceImpl(); |
| | | var batches = mock(MesWmBatchService.class); |
| | | ReflectionTestUtils.setField(service, "batchService", batches); |
| | | var request = new MesWmMaterialStockAdjustReqVO(); |
| | | request.setItemId(1L); request.setBatchId(2L); request.setReelNo("PHCS"); |
| | | when(batches.validateBatchExists(2L, 1L)).thenReturn(MesWmBatchDO.builder().id(2L).build()); |
| | | assertThrows(RuntimeException.class, () -> ReflectionTestUtils.invokeMethod(service, "resolveBatch", request, new MesMdmItemDO())); |
| | | verify(batches, never()).getOrGenerateBatchCode(any()); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.materialstock; |
| | | |
| | | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import javax.sql.DataSource; |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | |
| | | class MesWmMaterialStockSearchTest extends BaseDbUnitTest { |
| | | @Resource private MesWmMaterialStockMapper mapper; |
| | | @Resource private DataSource dataSource; |
| | | |
| | | @Test void filtersItemNameCodeVendorAndMdmIdBeforePagination() { |
| | | JdbcTemplate jdbc = new JdbcTemplate(dataSource); |
| | | jdbc.execute("ALTER TABLE mes_wm_material_stock ADD COLUMN IF NOT EXISTS frozen_quantity DECIMAL(14,2)"); |
| | | jdbc.execute("ALTER TABLE mes_wm_material_stock ADD COLUMN IF NOT EXISTS reserved_quantity DECIMAL(14,2)"); |
| | | jdbc.execute("ALTER TABLE mes_wm_material_stock ADD COLUMN IF NOT EXISTS in_transit_quantity DECIMAL(14,2)"); |
| | | jdbc.execute("CREATE TABLE IF NOT EXISTS mdm_item (id BIGINT PRIMARY KEY, name VARCHAR(100), code VARCHAR(100), deleted BOOLEAN)"); |
| | | jdbc.execute("CREATE TABLE IF NOT EXISTS srm_supplier (id BIGINT PRIMARY KEY, name VARCHAR(100), deleted BOOLEAN)"); |
| | | jdbc.update("INSERT INTO mdm_item VALUES (901, '黿¸æ', 'E2E-901', FALSE), (902, 'é»èª', 'E2E-902', FALSE)"); |
| | | jdbc.update("INSERT INTO srm_supplier VALUES (801, 'æµè¯ä¾åºå', FALSE), (802, 'å
¶ä»ä¾åºå', FALSE)"); |
| | | jdbc.update("INSERT INTO mes_wm_material_stock (item_id, vendor_id, quantity) VALUES (901, 801, 1), (902, 802, 1)"); |
| | | var req = new MesWmMaterialStockPageReqVO(); |
| | | req.setItemName("æ¸æ"); |
| | | assertEquals(1L, mapper.selectPage(req, null, null, null).getTotal()); |
| | | req.setItemName("E2E-901"); |
| | | req.setVendorName("æµè¯"); |
| | | assertEquals(1L, mapper.selectPage(req, null, null, null).getTotal()); |
| | | req.setMdmItemId(902L); |
| | | assertEquals(0L, mapper.selectPage(req, null, null, null).getTotal()); |
| | | req.setItemName("ä¸åå¨"); |
| | | req.setMdmItemId(null); |
| | | assertEquals(0L, mapper.selectPage(req, null, null, null).getTotal()); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.productsales; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.*; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.wm.stockreserve.MesWmStockReserveService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.junit.jupiter.api.extension.ExtendWith; |
| | | import org.mockito.InjectMocks; |
| | | import org.mockito.Mock; |
| | | import org.mockito.junit.jupiter.MockitoExtension; |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | @ExtendWith(MockitoExtension.class) |
| | | class MesWmProductSalesOrderWritebackTest { |
| | | @InjectMocks private MesWmProductSalesServiceImpl service; |
| | | @Mock private MesWmProductSalesMapper mapper; |
| | | @Mock private MesWmProductSalesLineService lines; |
| | | @Mock private MesWmProductSalesDetailService details; |
| | | @Mock private MesWmStockReserveService reserves; |
| | | @Mock private MesWmTransactionService transactions; |
| | | @Mock private MesWmSalesReelGuard reelGuard; |
| | | @Mock private ErpSaleOrderApi orders; |
| | | |
| | | @Test void completedSaleWritesQuantityToSelectedOrderItem() { |
| | | when(mapper.selectById(1L)).thenReturn(MesWmProductSalesDO.builder().id(1L).code("TEST") |
| | | .status(MesWmProductSalesStatusEnum.APPROVED.getStatus()).build()); |
| | | var line = MesWmProductSalesLineDO.builder().id(2L).salesId(1L).saleOrderItemId(3L) |
| | | .quantity(BigDecimal.ONE).build(); |
| | | when(lines.getProductSalesLineListBySalesId(1L)).thenReturn(List.of(line)); |
| | | when(lines.getProductSalesLine(2L)).thenReturn(line); |
| | | when(details.getProductSalesDetailListBySalesId(1L)).thenReturn(List.of( |
| | | MesWmProductSalesDetailDO.builder().lineId(2L).batchId(5L).quantity(BigDecimal.ONE).build())); |
| | | var item = new ErpSaleOrderItemRespDTO(); |
| | | item.setOrderId(4L); |
| | | when(orders.getSaleOrderItem(3L)).thenReturn(CommonResult.success(item)); |
| | | service.finishProductSales(1L); |
| | | verify(orders).updateOrderItemOutCount(3L, BigDecimal.ONE); |
| | | verify(orders).updateOrderOutStatus(4L); |
| | | verify(reelGuard).validate(line, 5L); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.productsales; |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper; |
| | | import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
| | | import org.apache.ibatis.annotations.Select; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; |
| | | |
| | | class SalesBatchQueryParserTest { |
| | | @Test void shipmentBatchQueryCanBeParsedByMybatisInterceptor() throws Exception { |
| | | String sql = String.join("", MesWmProductSalesDetailMapper.class |
| | | .getMethod("countFinishedSaleBatch", Long.class, Long.class, Long.class, Integer.class) |
| | | .getAnnotation(Select.class).value()).replaceAll("#\\{[^}]+}", "?"); |
| | | assertDoesNotThrow(() -> CCJSqlParserUtil.parse(sql)); |
| | | } |
| | | } |
| | |
| | | |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | |
| | | |
| | | @MockitoBean |
| | | private MesWmReturnSalesDetailService returnSalesDetailService; |
| | | @MockitoBean |
| | | private MesMdmItemService mdmItemService; |
| | | @MockitoBean |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | @MockitoBean |
| | | private MesWmProductSalesDetailMapper productSalesDetailMapper; |
| | | |
| | | @Test |
| | | public void testUpdateReturnSalesLineWhenRqcFinish_allPass() { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.service.wm.returnsales; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLineSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.util.List; |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | class ReturnSalesManualBatchReelTest { |
| | | @Test void manualBatchRequiresMatchingReelAndCompletedShipment() { |
| | | var service = new MesWmReturnSalesLineServiceImpl(); |
| | | var returns = mock(MesWmReturnSalesService.class); |
| | | var items = mock(MesMdmItemService.class); |
| | | var batches = mock(MesWmBatchService.class); |
| | | var orders = mock(ErpSaleOrderApi.class); |
| | | var shipments = mock(MesWmProductSalesDetailMapper.class); |
| | | ReflectionTestUtils.setField(service, "returnSalesService", returns); |
| | | ReflectionTestUtils.setField(service, "mdmItemService", items); |
| | | ReflectionTestUtils.setField(service, "batchService", batches); |
| | | ReflectionTestUtils.setField(service, "saleOrderApi", orders); |
| | | ReflectionTestUtils.setField(service, "productSalesDetailMapper", shipments); |
| | | var order = new MesWmReturnSalesDO().setSaleOrderId(5L).setClientId(9L).setSalesOrderCode("SO"); |
| | | when(returns.validateReturnSalesExistsAndPrepare(1L)).thenReturn(order); |
| | | when(items.validateItemExistsAndEnable(2L)).thenReturn(new MesMdmItemDO()); |
| | | var batch = MesWmBatchDO.builder().id(3L).itemId(2L).code("B").reelNo("PHCS").build(); |
| | | when(batches.validateBatchExists(3L, 2L)).thenReturn(batch); |
| | | var item = new ErpSaleOrderItemRespDTO().setProductId(2L).setReelNo("PHCS"); |
| | | when(orders.getSaleOrderItemList(5L)).thenReturn(CommonResult.success(List.of(item))); |
| | | var req = new MesWmReturnSalesLineSaveReqVO().setReturnId(1L).setItemId(2L).setBatchId(3L); |
| | | assertThrows(RuntimeException.class, () -> ReflectionTestUtils.invokeMethod(service, "validateLineSaveData", req)); |
| | | when(shipments.countFinishedSaleBatch(eq(5L), eq(2L), eq(3L), anyInt())).thenReturn(1L); |
| | | assertDoesNotThrow(() -> ReflectionTestUtils.invokeMethod(service, "validateLineSaveData", req)); |
| | | assertEquals("B", req.getBatchCode()); |
| | | batch.setReelNo("OTHER"); |
| | | assertThrows(RuntimeException.class, () -> ReflectionTestUtils.invokeMethod(service, "validateLineSaveData", req)); |
| | | } |
| | | } |