fix(importing): make document receivers/tags canonical-authoritative on re-import
The DocumentImporter accumulated receivers/tags via addAll without pruning, so a shrunk canonical row left stale links on a re-imported PLACEHOLDER document. Clear the collections before re-populating so the canonical row is authoritative: a removed receiver/tag is now pruned. Raw sender_text/receiver_text retention is unchanged. Refs #669 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -165,6 +165,10 @@ public class DocumentImporter {
|
|||||||
doc.setContentType(contentType);
|
doc.setContentType(contentType);
|
||||||
doc.setSender(sender);
|
doc.setSender(sender);
|
||||||
doc.setSenderText(blankToNull(senderName));
|
doc.setSenderText(blankToNull(senderName));
|
||||||
|
// The canonical row is authoritative for receivers/tags (ADR-025): clear then
|
||||||
|
// re-populate so a shrunk set on re-import prunes stale links rather than
|
||||||
|
// accumulating them. The raw sender_text/receiver_text retention is separate.
|
||||||
|
doc.getReceivers().clear();
|
||||||
doc.getReceivers().addAll(receivers);
|
doc.getReceivers().addAll(receivers);
|
||||||
doc.setReceiverText(blankToNull(receiverNames));
|
doc.setReceiverText(blankToNull(receiverNames));
|
||||||
doc.setDocumentDate(parseIsoDate(row.get("date_iso")));
|
doc.setDocumentDate(parseIsoDate(row.get("date_iso")));
|
||||||
@@ -203,7 +207,10 @@ public class DocumentImporter {
|
|||||||
.build()));
|
.build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authoritative: the canonical row defines the document's tags exactly. Clearing first
|
||||||
|
// means a tag removed from the row is pruned on re-import (ADR-025).
|
||||||
private void attachTag(Document doc, String tagPath) {
|
private void attachTag(Document doc, String tagPath) {
|
||||||
|
doc.getTags().clear();
|
||||||
if (tagPath.isBlank()) return;
|
if (tagPath.isBlank()) return;
|
||||||
tagService.findBySourceRef(tagPath).ifPresent(tag -> doc.getTags().add(tag));
|
tagService.findBySourceRef(tagPath).ifPresent(tag -> doc.getTags().add(tag));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,6 +382,28 @@ class DocumentImporterTest {
|
|||||||
verify(documentService).save(org.mockito.ArgumentMatchers.argThat(d -> d.getId().equals(existing.getId())));
|
verify(documentService).save(org.mockito.ArgumentMatchers.argThat(d -> d.getId().equals(existing.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── canonical collections are authoritative — re-import prunes removed links ──────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void load_prunesReceiversAndTags_whenCanonicalRowShrinks(@TempDir Path tempDir) throws Exception {
|
||||||
|
ReflectionTestUtils.setField(importer, "importDir", tempDir.toString());
|
||||||
|
Person staleReceiver = Person.builder().id(UUID.randomUUID()).sourceRef("stale-receiver").lastName("Stale").build();
|
||||||
|
Tag staleTag = Tag.builder().id(UUID.randomUUID()).name("Stale").sourceRef("Themen/Stale").build();
|
||||||
|
Document existing = Document.builder().id(UUID.randomUUID())
|
||||||
|
.originalFilename("W-0008").status(DocumentStatus.PLACEHOLDER).build();
|
||||||
|
existing.getReceivers().add(staleReceiver);
|
||||||
|
existing.getTags().add(staleTag);
|
||||||
|
when(documentService.findByOriginalFilename("W-0008")).thenReturn(Optional.of(existing));
|
||||||
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
// The canonical row now carries no receiver and no tag: both stale links must go.
|
||||||
|
Path xlsx = writeDocs(tempDir, docRow("W-0008", "", "", "", "", "", "", "", "", ""));
|
||||||
|
|
||||||
|
importer.load(xlsx.toFile());
|
||||||
|
|
||||||
|
verify(documentService).save(org.mockito.ArgumentMatchers.argThat(d ->
|
||||||
|
d.getReceivers().isEmpty() && d.getTags().isEmpty()));
|
||||||
|
}
|
||||||
|
|
||||||
// ─── helpers ─────────────────────────────────────────────────────────────────────
|
// ─── helpers ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private Map<String, String> docRow(String index, String file, String senderId, String senderName,
|
private Map<String, String> docRow(String index, String file, String senderId, String senderName,
|
||||||
|
|||||||
Reference in New Issue
Block a user