Pflicht-Präsenz von UNH und UNT pro Nachricht validieren
This commit is contained in:
@@ -24,6 +24,8 @@ import de.gecheckt.asv.validation.model.ValidationSeverity;
|
||||
* 6. Nachrichtenpositionen innerhalb einer Eingabedatei müssen eindeutig und positiv sein
|
||||
* 7. UNH- und UNT-Referenznummern müssen innerhalb einer Nachricht übereinstimmen
|
||||
* 8. Die im UNT angegebene Segmentanzahl muss der tatsächlichen Anzahl der Segmente entsprechen
|
||||
* 9. Eine Nachricht muss mindestens ein UNH-Segment enthalten
|
||||
* 10. Eine Nachricht muss mindestens ein UNT-Segment enthalten
|
||||
*/
|
||||
public class DefaultStructureValidator implements StructureValidator {
|
||||
|
||||
@@ -86,11 +88,79 @@ public class DefaultStructureValidator implements StructureValidator {
|
||||
// Validiere Segmente in dieser Nachricht
|
||||
validateSegments(message.segments(), messagePosition, errors);
|
||||
|
||||
// Prüfe zuerst, ob grundlegende Strukturfehler vorliegen (keine Segmente)
|
||||
// In diesem Fall können wir keine UNH/UNT-Prüfung durchführen
|
||||
if (message.segments().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Regel 9: Nachricht muss mindestens ein UNH-Segment enthalten
|
||||
validateUnhPresence(message, errors);
|
||||
|
||||
// Regel 10: Nachricht muss mindestens ein UNT-Segment enthalten
|
||||
validateUntPresence(message, errors);
|
||||
|
||||
// Regel 7: UNH- und UNT-Referenznummern müssen übereinstimmen
|
||||
validateUnhUntReferenceNumbers(message, errors);
|
||||
// Nur prüfen, wenn beide Segmente vorhanden sind
|
||||
if (message.getFirstSegment("UNH").isPresent() && message.getFirstSegment("UNT").isPresent()) {
|
||||
validateUnhUntReferenceNumbers(message, errors);
|
||||
}
|
||||
|
||||
// Regel 8: UNT-Segmentanzahl muss mit tatsächlicher Segmentanzahl übereinstimmen
|
||||
validateUntSegmentCount(message, errors);
|
||||
// Nur prüfen, wenn UNT-Segment vorhanden ist
|
||||
if (message.getFirstSegment("UNT").isPresent()) {
|
||||
validateUntSegmentCount(message, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validiert, dass mindestens ein UNH-Segment in der Nachricht vorhanden ist.
|
||||
*
|
||||
* @param message die zu validierende Nachricht
|
||||
* @param errors die Liste zum Hinzufügen von Validierungsfehlern
|
||||
*/
|
||||
private void validateUnhPresence(Message message, List<ValidationError> errors) {
|
||||
var unhSegment = message.getFirstSegment("UNH");
|
||||
|
||||
// Wenn kein UNH-Segment vorhanden ist, Fehler hinzufügen
|
||||
if (unhSegment.isEmpty()) {
|
||||
errors.add(createError(
|
||||
"STRUCTURE_009",
|
||||
"Nachricht muss mindestens ein UNH-Segment enthalten",
|
||||
ValidationSeverity.ERROR,
|
||||
"",
|
||||
message.messagePosition(),
|
||||
"",
|
||||
0,
|
||||
"",
|
||||
"UNH-Segment erforderlich"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validiert, dass mindestens ein UNT-Segment in der Nachricht vorhanden ist.
|
||||
*
|
||||
* @param message die zu validierende Nachricht
|
||||
* @param errors die Liste zum Hinzufügen von Validierungsfehlern
|
||||
*/
|
||||
private void validateUntPresence(Message message, List<ValidationError> errors) {
|
||||
var untSegment = message.getFirstSegment("UNT");
|
||||
|
||||
// Wenn kein UNT-Segment vorhanden ist, Fehler hinzufügen
|
||||
if (untSegment.isEmpty()) {
|
||||
errors.add(createError(
|
||||
"STRUCTURE_010",
|
||||
"Nachricht muss mindestens ein UNT-Segment enthalten",
|
||||
ValidationSeverity.ERROR,
|
||||
"",
|
||||
message.messagePosition(),
|
||||
"",
|
||||
0,
|
||||
"",
|
||||
"UNT-Segment erforderlich"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +313,9 @@ public class DefaultStructureValidator implements StructureValidator {
|
||||
}
|
||||
|
||||
// Validate fields in this segment
|
||||
validateFields(segment.fields(), segmentName, segmentPosition, errors);
|
||||
if (!segment.fields().isEmpty()) {
|
||||
validateFields(segment.fields(), segmentName, segmentPosition, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +328,10 @@ public class DefaultStructureValidator implements StructureValidator {
|
||||
* @param errors die Liste zum Hinzufügen von Validierungsfehlern
|
||||
*/
|
||||
private void validateFields(List<Field> fields, String segmentName, int segmentPosition, List<ValidationError> errors) {
|
||||
if (fields.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fieldPositions = new HashSet<Integer>();
|
||||
|
||||
for (var field : fields) {
|
||||
|
||||
@@ -73,41 +73,53 @@ class DefaultStructureValidatorTest {
|
||||
|
||||
@Test
|
||||
void validate_shouldReportErrorWhenSegmentHasDuplicatePositions() {
|
||||
Segment segment1 = new Segment("SEG1", 1);
|
||||
Segment segment2 = new Segment("SEG2", 1); // Duplicate position
|
||||
Message message = new Message(1, List.of(segment1, segment2));
|
||||
// Manually create segments with duplicate positions to bypass parser validation
|
||||
// Also include required UNH and UNT segments
|
||||
Segment unh = new Segment("UNH", 1, List.of(new Field(1, "12345"), new Field(2, "ORDERS:D:03B:UN:EAN008")));
|
||||
Segment segment1 = new Segment("SEG1", 2);
|
||||
Segment segment2 = new Segment("SEG2", 2); // Duplicate position
|
||||
Segment unt = new Segment("UNT", 4, List.of(new Field(1, "4"), new Field(2, "12345")));
|
||||
Message message = new Message(1, List.of(unh, segment1, segment2, unt));
|
||||
InputFile inputFile = new InputFile("test.txt", List.of(message));
|
||||
|
||||
|
||||
// When
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
|
||||
// Then
|
||||
assertTrue(result.hasErrors());
|
||||
assertEquals(1, result.getErrors().size());
|
||||
|
||||
|
||||
ValidationError error = result.getErrors().get(0);
|
||||
assertEquals("STRUCTURE_005", error.errorCode());
|
||||
assertEquals("Duplicate segment position: 1", error.description());
|
||||
assertEquals("Duplicate segment position: 2", error.description());
|
||||
assertEquals("SEG2", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals(2, error.segmentPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validate_shouldReportErrorWhenFieldHasDuplicatePositions() {
|
||||
// Create segments with duplicate field positions manually to bypass parser validation
|
||||
// Also include required UNH and UNT segments
|
||||
Segment unh = new Segment("UNH", 1, List.of(new Field(1, "12345"), new Field(2, "ORDERS:D:03B:UN:EAN008")));
|
||||
Field field1 = new Field(1, "value1");
|
||||
Field field2 = new Field(1, "value2"); // Duplicate position
|
||||
Segment segment = new Segment("SEG1", 1, List.of(field1, field2));
|
||||
Message message = new Message(1, List.of(segment));
|
||||
Segment segment = new Segment("SEG1", 2, List.of(field1, field2));
|
||||
Segment unt = new Segment("UNT", 3, List.of(new Field(1, "3"), new Field(2, "12345")));
|
||||
Message message = new Message(1, List.of(unh, segment, unt));
|
||||
InputFile inputFile = new InputFile("test.txt", List.of(message));
|
||||
|
||||
|
||||
// When
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
|
||||
// Then
|
||||
assertTrue(result.hasErrors());
|
||||
assertEquals(1, result.getErrors().size());
|
||||
|
||||
|
||||
ValidationError error = result.getErrors().get(0);
|
||||
assertEquals("STRUCTURE_004", error.errorCode());
|
||||
assertEquals("Duplicate field position: 1", error.description());
|
||||
assertEquals("SEG1", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals(2, error.segmentPosition());
|
||||
assertEquals(1, error.fieldPosition());
|
||||
}
|
||||
|
||||
@@ -115,8 +127,10 @@ class DefaultStructureValidatorTest {
|
||||
void validate_shouldReturnNoErrorsForValidStructure() {
|
||||
Field field1 = new Field(1, "value1");
|
||||
Field field2 = new Field(2, "value2");
|
||||
Segment segment = new Segment("SEG1", 1, List.of(field1, field2));
|
||||
Message message = new Message(1, List.of(segment));
|
||||
Segment segment = new Segment("UNH", 1, List.of(new Field(1, "12345")));
|
||||
Segment segment2 = new Segment("SEG1", 2, List.of(field1, field2));
|
||||
Segment segment3 = new Segment("UNT", 3, List.of(new Field(1, "3"), new Field(2, "12345")));
|
||||
Message message = new Message(1, List.of(segment, segment2, segment3));
|
||||
InputFile inputFile = new InputFile("test.txt", List.of(message));
|
||||
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
@@ -305,4 +319,123 @@ class DefaultStructureValidatorTest {
|
||||
assertEquals("10 != 9", error.actualValue());
|
||||
assertEquals("Segmentanzahl in UNT muss mit tatsächlicher Anzahl übereinstimmen", error.expectedRule());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validate_shouldReportErrorWhenUnhIsMissingInMessage() {
|
||||
// Manually create a message without UNH segment to ensure only the UNH missing error occurs
|
||||
Segment bgm = new Segment("BGM", 1, List.of(new Field(1, "220"), new Field(2, "100001")));
|
||||
Segment dtm = new Segment("DTM", 2, List.of(new Field(1, "137:20260325:102")));
|
||||
Segment nad = new Segment("NAD", 3, List.of(new Field(1, "BY"), new Field(2, "5000000000000:16"), new Field(3, ""), new Field(4, "Customer Name")));
|
||||
Segment lin = new Segment("LIN", 4, List.of(new Field(1, "1"), new Field(2, ""), new Field(3, "Product123:SA")));
|
||||
Segment qty = new Segment("QTY", 5, List.of(new Field(1, "21:10:PCE")));
|
||||
Segment uns = new Segment("UNS", 6, List.of(new Field(1, "S")));
|
||||
Segment cnt = new Segment("CNT", 7, List.of(new Field(1, "2:1")));
|
||||
Segment unt = new Segment("UNT", 8, List.of(new Field(1, "8"), new Field(2, "missing")));
|
||||
|
||||
// Create message without UNH
|
||||
Message message = new Message(1, List.of(bgm, dtm, nad, lin, qty, uns, cnt, unt));
|
||||
InputFile inputFile = new InputFile("test.txt", List.of(message));
|
||||
|
||||
// When
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
// Then
|
||||
assertTrue(result.hasErrors());
|
||||
// Expect exactly one error for missing UNH (STRUCTURE_009)
|
||||
assertEquals(1, result.getErrors().size());
|
||||
|
||||
ValidationError error = result.getErrors().get(0);
|
||||
assertEquals("STRUCTURE_009", error.errorCode());
|
||||
assertEquals("Nachricht muss mindestens ein UNH-Segment enthalten", error.description());
|
||||
assertEquals("", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals("UNH-Segment erforderlich", error.expectedRule());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validate_shouldReportErrorWhenUntIsMissingInMessage() throws IOException, InputFileParseException {
|
||||
// Given
|
||||
SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer();
|
||||
DefaultInputFileParser parser = new DefaultInputFileParser(tokenizer);
|
||||
String fileName = "no-unt.asv";
|
||||
Path filePath = Path.of("src/test/resources/no-unt.asv");
|
||||
String fileContent = Files.readString(filePath);
|
||||
|
||||
// When
|
||||
InputFile inputFile = parser.parse(fileName, fileContent);
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
// Then
|
||||
assertTrue(result.hasErrors());
|
||||
// Expect exactly one error for missing UNT (STRUCTURE_010)
|
||||
assertEquals(1, result.getErrors().size());
|
||||
|
||||
ValidationError error = result.getErrors().get(0);
|
||||
assertEquals("STRUCTURE_010", error.errorCode());
|
||||
assertEquals("Nachricht muss mindestens ein UNT-Segment enthalten", error.description());
|
||||
assertEquals("", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals("UNT-Segment erforderlich", error.expectedRule());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validate_shouldReportTwoErrorsWhenBothUnhAndUntAreMissing() throws IOException, InputFileParseException {
|
||||
// Given
|
||||
SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer();
|
||||
DefaultInputFileParser parser = new DefaultInputFileParser(tokenizer);
|
||||
String fileName = "no-unh-unt.asv";
|
||||
Path filePath = Path.of("src/test/resources/no-unh-unt.asv");
|
||||
String fileContent = Files.readString(filePath);
|
||||
|
||||
// When
|
||||
InputFile inputFile = parser.parse(fileName, fileContent);
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
// Then
|
||||
assertTrue(result.hasErrors());
|
||||
// Expect exactly two errors: one for missing UNH (STRUCTURE_009) and one for missing UNT (STRUCTURE_010)
|
||||
assertEquals(2, result.getErrors().size());
|
||||
|
||||
// Check that both errors are present
|
||||
boolean foundUnhError = false;
|
||||
boolean foundUntError = false;
|
||||
|
||||
for (ValidationError error : result.getErrors()) {
|
||||
if ("STRUCTURE_009".equals(error.errorCode())) {
|
||||
foundUnhError = true;
|
||||
assertEquals("Nachricht muss mindestens ein UNH-Segment enthalten", error.description());
|
||||
assertEquals("", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals("UNH-Segment erforderlich", error.expectedRule());
|
||||
} else if ("STRUCTURE_010".equals(error.errorCode())) {
|
||||
foundUntError = true;
|
||||
assertEquals("Nachricht muss mindestens ein UNT-Segment enthalten", error.description());
|
||||
assertEquals("", error.segmentName());
|
||||
assertEquals(1, error.segmentPosition());
|
||||
assertEquals("UNT-Segment erforderlich", error.expectedRule());
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(foundUnhError, "Expected STRUCTURE_009 error for missing UNH");
|
||||
assertTrue(foundUntError, "Expected STRUCTURE_010 error for missing UNT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validate_shouldNotReportAdditionalErrorsForUntSegmentCountWhenUntIsMissing() throws IOException, InputFileParseException {
|
||||
// Given
|
||||
SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer();
|
||||
DefaultInputFileParser parser = new DefaultInputFileParser(tokenizer);
|
||||
String fileName = "no-unt.asv";
|
||||
Path filePath = Path.of("src/test/resources/no-unt.asv");
|
||||
String fileContent = Files.readString(filePath);
|
||||
|
||||
// When
|
||||
InputFile inputFile = parser.parse(fileName, fileContent);
|
||||
ValidationResult result = validator.validate(inputFile);
|
||||
|
||||
// Then
|
||||
// Should not have STRUCTURE_008 error for segment count mismatch when UNT is missing
|
||||
assertFalse(result.getErrors().stream()
|
||||
.anyMatch(error -> "STRUCTURE_008".equals(error.errorCode())));
|
||||
}
|
||||
}
|
||||
3
src/test/resources/duplicate-fields.asv
Normal file
3
src/test/resources/duplicate-fields.asv
Normal file
@@ -0,0 +1,3 @@
|
||||
UNH+12345+ORDERS:D:03B:UN:EAN008'
|
||||
SEG1+value1+value1'
|
||||
UNT+3+12345'
|
||||
4
src/test/resources/duplicate-segments.asv
Normal file
4
src/test/resources/duplicate-segments.asv
Normal file
@@ -0,0 +1,4 @@
|
||||
UNH+12345+ORDERS:D:03B:UN:EAN008'
|
||||
SEG1+value1+value2'
|
||||
SEG2+value3+value4'
|
||||
UNT+3+12345'
|
||||
7
src/test/resources/no-unh-unt.asv
Normal file
7
src/test/resources/no-unh-unt.asv
Normal file
@@ -0,0 +1,7 @@
|
||||
BGM+220+100001'
|
||||
DTM+137:20260325:102'
|
||||
NAD+BY+5000000000000:16++Customer Name'
|
||||
LIN+1++Product123:SA'
|
||||
QTY+21:10:PCE'
|
||||
UNS+S'
|
||||
CNT+2:1'
|
||||
@@ -1,3 +1,4 @@
|
||||
UNH+12345+ORDERS:D:03B:UN:EAN008'
|
||||
BGM+220+100001'
|
||||
DTM+137:20260325:102'
|
||||
NAD+BY+5000000000000:16++Customer Name'
|
||||
@@ -5,4 +6,4 @@ LIN+1++Product123:SA'
|
||||
QTY+21:10:PCE'
|
||||
UNS+S'
|
||||
CNT+2:1'
|
||||
UNT+9+12345'
|
||||
UNT+9+12345'
|
||||
|
||||
@@ -5,4 +5,4 @@ NAD+BY+5000000000000:16++Customer Name'
|
||||
LIN+1++Product123:SA'
|
||||
QTY+21:10:PCE'
|
||||
UNS+S'
|
||||
CNT+2:1'
|
||||
CNT+2:1'
|
||||
|
||||
Reference in New Issue
Block a user