刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package jnpf.fileStorage.dms;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import jnpf.dmsEntity.storage.form.DmsFileUploadRegisterForm;
import jnpf.exception.DataException;
import jnpf.model.filecontent.FileContentImportForm;
import jnpf.service.DmsApprovalPageTagService;
import org.docx4j.XmlUtils;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.*;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
 
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
 
/** Exercises the real DOCX writer and page merger through physical-content import. */
public class DmsApprovalTagImportTest {
    private static final ObjectFactory WML = new ObjectFactory();
    private final DmsCommonFileReader reader = mock(DmsCommonFileReader.class);
    private final DmsFileStorageService storage = mock(DmsFileStorageService.class);
    private final DmsApprovalPageTagService pageTags = new DmsApprovalPageTagService();
    private final FileContentImportService service = new FileContentImportService(reader, storage,
            new DmsApprovalPageMergeService(pageTags), new DmsQianpiyeDocxWriter(),
            new DmsDocxCommentCleaner(), new ObjectMapper());
 
    @Test public void fillsOriginalWorkflowFormAndRowsTagsWithoutInsertingAPage() throws Exception {
        FileContentImportForm form = form();
        MultipartFile original = docx("main.docx", "原文件正文",
                "dms.qianpiye.form.wenjian_bianhao", "{{文件编号}}",
                "dms.qianpiye.flow.approve-1.approver", "{{审核人}}",
                "dms.qianpiye.rows.common.distribution", "{{department}}({{copies}})");
        read("main.docx", form.getFileJson(), form.getFileName(), original);
 
        MultipartFile result = imported(form);
        String xml = xml(result);
 
        assertTrue(xml.contains("原文件正文"));
        assertTrue(xml.contains("DOC-001"));
        assertTrue(xml.contains("张三"));
        assertTrue(xml.contains("质量部(10)"));
        assertFalse(xml.contains("{{"));
        assertFalse(pageTags.hasApprovalPage(result));
        verify(reader, times(1)).withFile(any(), any(), any(), any());
    }
 
    @Test public void fillsBothConfiguredPageAndOriginalDocumentBeforeStoring() throws Exception {
        FileContentImportForm form = form();
        form.setSignaturePageFiles("[{\"url\":\"page.docx\"}]");
        read("main.docx", form.getFileJson(), form.getFileName(), docx("main.docx", "原文件正文",
                "dms.qianpiye.form.wenjian_bianhao", "{{文件编号}}"));
        read("page.docx", form.getSignaturePageFiles(), "签批页", docx("page.docx", "配置的签批页",
                "dms.qianpiye.flow.approve-1.approver", "{{审核人}}"));
 
        MultipartFile result = imported(form);
        String xml = xml(result);
 
        assertTrue(xml.contains("原文件正文"));
        assertTrue(xml.contains("配置的签批页"));
        assertTrue(xml.contains("DOC-001"));
        assertTrue(xml.contains("张三"));
        assertFalse(xml.contains("{{"));
        assertTrue(pageTags.hasApprovalPage(result));
        verify(reader, times(2)).withFile(any(), any(), any(), any());
    }
 
    @Test public void untaggedOriginalKeepsItsContentWithoutAnApprovalPage() throws Exception {
        FileContentImportForm form = form();
        read("main.docx", form.getFileJson(), form.getFileName(), docx("main.docx", "无标注正文"));
 
        MultipartFile result = imported(form);
 
        assertTrue(xml(result).contains("无标注正文"));
        assertFalse(pageTags.hasApprovalPage(result));
    }
 
    @Test public void clearsRemovedFieldsInBothBodyAndApprovalPageBeforeStoring() throws Exception {
        FileContentImportForm form = form();
        form.setSignaturePageFiles("[{\"url\":\"page.docx\"}]");
        read("main.docx", form.getFileJson(), form.getFileName(), docx("main.docx", "正文",
                "dms.qianpiye.form.deleted_field", "旧正文值",
                "dms.qianpiye.form.wenjian_bianhao", "{{文件编号}}"));
        read("page.docx", form.getSignaturePageFiles(), "签批页", docx("page.docx", "签批页",
                "dms.qianpiye.form.deleted_table.column", "旧子表值",
                "dms.qianpiye.rows.common.deleted_table", "旧子表整行",
                "dms.qianpiye.flow.approve-1.approver", "{{审核人}}"));
 
        MultipartFile result = imported(form);
        String xml = xml(result);
 
        assertTrue(xml.contains("DOC-001"));
        assertTrue(xml.contains("张三"));
        assertTrue(pageTags.hasApprovalPage(result));
        assertFalse(xml.contains("旧正文值"));
        assertFalse(xml.contains("旧子表值"));
        assertFalse(xml.contains("旧子表整行"));
        assertFalse(xml.contains("{{"));
    }
 
    @Test public void replacesAnOldFilledApprovalPageBeforeRenderingTheOriginalBody() throws Exception {
        FileContentImportForm form = form();
        form.setSignaturePageFiles("[{\"url\":\"page.docx\"}]");
        MultipartFile body = docx("main.docx", "修订正文",
                "dms.qianpiye.form.wenjian_bianhao", "{{文件编号}}");
        // Historical generated rows have no remaining placeholders or saved pattern.
        MultipartFile oldPage = docx("old.docx", "旧签批页",
                "dms.qianpiye.rows.common.distribution", "历史部门(旧份数)");
        MultipartFile original = new DmsApprovalPageMergeService(pageTags).replaceOrPrepend(body, oldPage);
        read("main.docx", form.getFileJson(), form.getFileName(), original);
        read("page.docx", form.getSignaturePageFiles(), "签批页", docx("page.docx", "新签批页",
                "dms.qianpiye.flow.approve-1.approver", "{{审核人}}"));
 
        String xml = xml(imported(form));
 
        assertTrue(xml.contains("修订正文"));
        assertTrue(xml.contains("新签批页"));
        assertTrue(xml.contains("DOC-001"));
        assertTrue(xml.contains("张三"));
        assertFalse(xml.contains("旧签批页"));
        assertFalse(xml.contains("历史部门"));
    }
 
    @Test public void originalTagRenderingFailureStopsPhysicalStorage() {
        FileContentImportForm form = form();
        read("main.docx", form.getFileJson(), form.getFileName(),
                new MockMultipartFile("file", "main.docx", "application/octet-stream", new byte[]{1, 2, 3}));
 
        assertThrows(DataException.class, () -> service.importContent(form));
 
        verifyNoInteractions(storage);
    }
 
    private FileContentImportForm form() {
        FileContentImportForm form = new FileContentImportForm();
        form.setDocumentId(UUID.randomUUID());
        form.setFileVersionId(UUID.randomUUID());
        form.setFileName("归档名称");
        form.setFileJson("[{\"url\":\"main.docx\"}]");
        form.setApprovalFlowVersionId("flow-version");
        form.setSignaturePageValues(Map.of(
                "dms.qianpiye.form.wenjian_bianhao", "DOC-001",
                "dms.qianpiye.flow.approve-1.approver", "张三",
                "dms.qianpiye.rows.common.distribution", "[{\"department\":\"质量部\",\"copies\":\"10\"}]"));
        return form;
    }
 
    private void read(String url, String fileJson, String name, MultipartFile file) {
        when(reader.withFile(eq(url), eq(fileJson), eq(name), any())).thenAnswer(invocation ->
                invocation.<Function<MultipartFile, DmsFileUploadRegisterForm>>getArgument(3).apply(file));
    }
 
    private MultipartFile imported(FileContentImportForm form) {
        when(storage.storeWorkflowContent(eq(form.getDocumentId()), eq(form.getFileVersionId()), any()))
                .thenReturn(new DmsFileUploadRegisterForm());
        service.importContent(form);
        ArgumentCaptor<MultipartFile> content = ArgumentCaptor.forClass(MultipartFile.class);
        verify(storage).storeWorkflowContent(eq(form.getDocumentId()), eq(form.getFileVersionId()), content.capture());
        assertEquals("归档名称.docx", content.getValue().getOriginalFilename());
        return content.getValue();
    }
 
    private MultipartFile docx(String name, String body, String... tagsAndText) throws Exception {
        WordprocessingMLPackage word = WordprocessingMLPackage.createPackage();
        word.getMainDocumentPart().addParagraphOfText(body);
        for (int index = 0; index < tagsAndText.length; index += 2) {
            Tag tag = WML.createTag();
            tag.setVal(tagsAndText[index]);
            SdtPr properties = WML.createSdtPr();
            properties.setTag(tag);
            Text text = WML.createText();
            text.setValue(tagsAndText[index + 1]);
            R run = WML.createR();
            run.getContent().add(WML.createRT(text));
            CTSdtContentRun content = WML.createCTSdtContentRun();
            content.getContent().add(run);
            SdtRun control = WML.createSdtRun();
            control.setSdtPr(properties);
            control.setSdtContent(content);
            P paragraph = WML.createP();
            paragraph.getContent().add(WML.createPSdt(control));
            word.getMainDocumentPart().getContent().add(paragraph);
        }
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        word.save(bytes);
        return new MockMultipartFile("file", name,
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document", bytes.toByteArray());
    }
 
    private String xml(MultipartFile file) throws Exception {
        WordprocessingMLPackage word = WordprocessingMLPackage.load(file.getInputStream());
        return XmlUtils.marshaltoString(word.getMainDocumentPart().getJaxbElement(), true, true);
    }
}