云
12 小时以前 401bdd0cfb4d7ce7344e34b3897ff14e303188fb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package cn.iocoder.yudao.module.crm.service.contract;
 
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.*;
import static org.junit.jupiter.api.Assertions.*;
 
class CrmContractDocumentRendererTest {
    private CrmContractRespVO contract() {
        var contract = new CrmContractRespVO();
        contract.setNo("HT20261015001"); contract.setCustomerName("中国科学院西北高原生物研究所");
        contract.setOrderDate(LocalDateTime.of(2026,10,15,0,0));
        var product = new CrmContractRespVO.Product();
        product.setItemName("冻干冬虫夏草"); product.setItemSpecification("2500级一等"); product.setItemUnitName("g");
        product.setCount(new BigDecimal("200")); product.setContractPrice(new BigDecimal("50")); product.setTotalPrice(new BigDecimal("10000"));
        contract.setProducts(List.of(product)); contract.setTotalPrice(new BigDecimal("10000"));
        return contract;
    }
    private Map<String,byte[]> unzip(byte[] bytes) throws IOException {
        Map<String,byte[]> parts = new HashMap<>();
        try (var input = new ZipInputStream(new ByteArrayInputStream(bytes))) {
            ZipEntry entry; while ((entry=input.getNextEntry())!=null) parts.put(entry.getName(),input.readAllBytes());
        }
        return parts;
    }
    @Test void fillsContractAndPreservesTemplateParts() throws Exception {
        byte[] bytes = CrmContractDocumentRenderer.render(contract());
        var parts = unzip(bytes);
        String xml = new String(parts.get("word/document.xml"), StandardCharsets.UTF_8);
        assertTrue(xml.contains("HT20261015001")); assertTrue(xml.contains("2026年10月15日"));
        assertTrue(xml.contains("10000.00")); assertTrue(xml.contains("壹万元整"));
        assertTrue(xml.contains("冻干冬虫夏草(2500级一等)")); assertTrue(xml.contains("诚信合规"));
        assertFalse(xml.contains("${"));
        try(var template = new ClassPathResource("templates/contract/sale-contract.docx").getInputStream()) {
            var original = unzip(template.readAllBytes()); assertEquals(original.keySet(),parts.keySet());
            for (var name : original.keySet()) if (!name.equals("word/document.xml")) assertArrayEquals(original.get(name), parts.get(name), name);
        }
        String output = System.getProperty("contract.document.sample");
        if (output != null) Files.write(Path.of(output),bytes);
    }
    @Test void supportsManyProductsDiscountAndXmlCharacters() throws Exception {
        var contract = contract(); contract.setCustomerName("客户<&>公司");
        contract.setProducts(Collections.nCopies(25,contract.getProducts().getFirst()));
        contract.setTotalPrice(new BigDecimal("249000"));
        String xml = new String(unzip(CrmContractDocumentRenderer.render(contract)).get("word/document.xml"),StandardCharsets.UTF_8);
        assertTrue(xml.contains("客户&lt;&amp;&gt;公司")); assertTrue(xml.contains("整单优惠 1000.00 元"));
        assertEquals(25,xml.split("冻干冬虫夏草(2500级一等)",-1).length-1);
        assertEquals(25,xml.split("<w:cantSplit",-1).length-1);
        assertTrue(xml.contains("249000.00")); assertFalse(xml.contains("${"));
        assertFalse(xml.contains("乙方(需方):中国科学院西北高原生物研究所"));
        String output = System.getProperty("contract.document.sample");
        if (output != null) Files.write(Path.of(output).resolveSibling("generated-contract-many.docx"), CrmContractDocumentRenderer.render(contract));
    }
    @Test void missingDateAndOptionalFieldsStayBlankWithoutInventingData() throws Exception {
        var contract = contract(); contract.setOrderDate(null);
        contract.getProducts().getFirst().setItemSpecification(null); contract.getProducts().getFirst().setItemUnitName(null);
        contract.getProducts().getFirst().setTotalPrice(null);
        String xml = new String(unzip(CrmContractDocumentRenderer.render(contract)).get("word/document.xml"),StandardCharsets.UTF_8);
        assertTrue(xml.contains("____________")); assertTrue(xml.contains("10000.00")); assertFalse(xml.contains("null"));
    }
    @Test void emptyContractCannotProduceUnrelatedTemplateProducts() {
        var contract = contract(); contract.setProducts(List.of());
        assertThrows(IllegalArgumentException.class,()->CrmContractDocumentRenderer.render(contract));
    }
}