From 43aab58c9ecb1203770ba382efbdbae299ca87ec Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期一, 26 十月 2026 15:12:31 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business

---
 yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/item/MesBomImportAdapterTest.java |  174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/item/MesBomImportAdapterTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/item/MesBomImportAdapterTest.java
new file mode 100644
index 0000000..763628c
--- /dev/null
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/item/MesBomImportAdapterTest.java
@@ -0,0 +1,174 @@
+package cn.iocoder.yudao.module.mes.service.md.item;
+
+import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductBomMapper;
+import cn.iocoder.yudao.module.system.api.agent.imports.AgentImportCommitReqVO;
+import cn.iocoder.yudao.module.system.api.agent.imports.AgentImportPreflightReqVO;
+import cn.iocoder.yudao.module.system.api.agent.imports.AgentImportPreflightRespVO;
+import cn.iocoder.yudao.module.system.api.agent.imports.AgentImportRowReceipt;
+import cn.iocoder.yudao.module.system.framework.agent.AgentPrincipal;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.math.BigDecimal;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class MesBomImportAdapterTest {
+
+    private static final AgentPrincipal PRINCIPAL = new AgentPrincipal(1L, "live");
+
+    private MesBomImportAdapter adapter;
+    private MesMdItemService itemService;
+    private MesMdProductBomService productBomService;
+    private MesMdProductBomMapper productBomMapper;
+
+    @BeforeEach
+    void setUp() {
+        adapter = new MesBomImportAdapter();
+        itemService = mock(MesMdItemService.class);
+        productBomService = mock(MesMdProductBomService.class);
+        productBomMapper = mock(MesMdProductBomMapper.class);
+        ReflectionTestUtils.setField(adapter, "itemService", itemService);
+        ReflectionTestUtils.setField(adapter, "productBomService", productBomService);
+        ReflectionTestUtils.setField(adapter, "productBomMapper", productBomMapper);
+        when(itemService.getItemByCode("P")).thenReturn(item(1L, "P"));
+        when(itemService.getItemByCode("C")).thenReturn(item(2L, "C"));
+        when(itemService.getItemByCode("A")).thenReturn(item(3L, "A"));
+        when(itemService.getItemByCode("X")).thenReturn(null);
+        when(productBomMapper.selectAll()).thenReturn(List.of());
+    }
+
+    @Test
+    void preflightCreatesWhenItemsAreSynced() {
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "C", "2")));
+
+        assertEquals("CREATE", plan.getRows().get(0).getAction());
+        assertEquals(1, plan.getSummary().getCreate());
+        assertTrue(plan.getCanCommit());
+        assertNotNull(plan.getPreflightHash());
+    }
+
+    @Test
+    void existingCombinationIsSkippedWithWarning() {
+        when(productBomMapper.selectAll()).thenReturn(List.of(bom(50L, 1L, 2L)));
+
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "C", "2")));
+
+        assertEquals("SKIP", plan.getRows().get(0).getAction());
+        assertEquals(50L, plan.getRows().get(0).getTargetId());
+        assertEquals(1, plan.getSummary().getSkip());
+        assertTrue(plan.getRows().get(0).getWarnings().stream()
+                .anyMatch(item -> "BOM_EXISTS".equals(item.getCode())));
+    }
+
+    @Test
+    void unsyncedComponentBlocksRow() {
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "X", "1")));
+
+        assertEquals("BLOCKED", plan.getRows().get(0).getAction());
+        assertTrue(plan.getRows().get(0).getBlockers().stream()
+                .anyMatch(item -> "MES_ITEM_NOT_SYNCED".equals(item.getCode())));
+        assertFalse(plan.getCanCommit());
+    }
+
+    @Test
+    void selfReferenceBlocksRow() {
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "P", "1")));
+
+        assertEquals("BLOCKED", plan.getRows().get(0).getAction());
+        assertTrue(plan.getRows().get(0).getBlockers().stream()
+                .anyMatch(item -> "BOM_SELF_REFERENCE".equals(item.getCode())));
+    }
+
+    @Test
+    void duplicateCombinationInFileBlocksSecondRow() {
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(
+                row("r1", "P", "C", "1"),
+                row("r2", "P", "C", "2")));
+
+        assertEquals("CREATE", plan.getRows().get(0).getAction());
+        assertEquals("BLOCKED", plan.getRows().get(1).getAction());
+        assertTrue(plan.getRows().get(1).getBlockers().stream()
+                .anyMatch(item -> "DUPLICATE_IN_FILE".equals(item.getCode())));
+    }
+
+    @Test
+    void cycleAgainstExistingGraphBlocksRow() {
+        when(productBomMapper.selectAll()).thenReturn(List.of(bom(60L, 3L, 1L)));
+
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "A", "1")));
+
+        assertEquals("BLOCKED", plan.getRows().get(0).getAction());
+        assertTrue(plan.getRows().get(0).getBlockers().stream()
+                .anyMatch(item -> "BOM_CYCLE".equals(item.getCode())));
+    }
+
+    @Test
+    void invalidQuantityBlocksRow() {
+        AgentImportPreflightRespVO plan = adapter.preflight(PRINCIPAL, request(row("r1", "P", "C", "0")));
+
+        assertEquals("BLOCKED", plan.getRows().get(0).getAction());
+        assertTrue(plan.getRows().get(0).getBlockers().stream()
+                .anyMatch(item -> "INVALID_QUANTITY".equals(item.getCode())));
+    }
+
+    @Test
+    void commitCreatesBomWithResolvedItemIds() {
+        when(productBomService.createProductBom(any())).thenReturn(88L);
+
+        AgentImportRowReceipt receipt = adapter.commitRow(PRINCIPAL, new AgentImportCommitReqVO(),
+                AgentImportPreflightRespVO.Row.builder().candidateId("r1").action("CREATE").build(),
+                row("r1", "P", "C", "2"));
+
+        assertEquals(88L, receipt.targetId());
+        assertEquals("P", receipt.code());
+        verify(productBomService).createProductBom(any(MesMdProductBomSaveReqVO.class));
+    }
+
+    private static MesMdItemDO item(Long id, String code) {
+        MesMdItemDO item = new MesMdItemDO();
+        item.setId(id);
+        item.setCode(code);
+        return item;
+    }
+
+    private static MesMdProductBomDO bom(Long id, Long itemId, Long bomItemId) {
+        MesMdProductBomDO bom = new MesMdProductBomDO();
+        bom.setId(id);
+        bom.setItemId(itemId);
+        bom.setBomItemId(bomItemId);
+        bom.setQuantity(BigDecimal.ONE);
+        return bom;
+    }
+
+    private static AgentImportPreflightReqVO request(AgentImportPreflightReqVO.Row... rows) {
+        AgentImportPreflightReqVO request = new AgentImportPreflightReqVO();
+        request.setAttachmentId(1L);
+        request.setSourceSha256("a".repeat(64));
+        request.setProposalRevision("0");
+        request.setRows(List.of(rows));
+        return request;
+    }
+
+    private static AgentImportPreflightReqVO.Row row(String candidateId, String parent, String component,
+                                                      String quantity) {
+        Map<String, String> values = new LinkedHashMap<>();
+        values.put("parentCode", parent);
+        values.put("componentCode", component);
+        values.put("quantity", quantity);
+        AgentImportPreflightReqVO.Row row = new AgentImportPreflightReqVO.Row();
+        row.setCandidateId(candidateId);
+        row.setRowNo(1);
+        row.setValues(values);
+        return row;
+    }
+}

--
Gitblit v1.9.3