validateMrzLineTd1 function

OcrMrzValidation validateMrzLineTd1({
  1. required String l1,
  2. required String l2,
  3. required String l3,
  4. required List<String> otherLines,
  5. required String firstName,
  6. required String lastName,
  7. required OcrMrzSetting setting,
  8. required String country,
  9. required String nationality,
  10. required String personalNumber,
  11. List<NameValidationData>? nameValidations,
})

Implementation

OcrMrzValidation validateMrzLineTd1({
  required String l1,
  required String l2,
  required String l3,
  required List<String> otherLines,
  required String firstName,
  required String lastName,
  required OcrMrzSetting setting,
  required String country,
  required String nationality,
  required String personalNumber,
  List<NameValidationData>? nameValidations,
}) {
  OcrMrzValidation validation = OcrMrzValidation();
  try {
    final documentType = l1.substring(0, 1); // first char
    final documentCode = l1.substring(0, 2); // first char
    final issuingState = fixAlphaOnlyField(l1.substring(2, 5));
    final docNo = l1.substring(5, 14);
    final docChk = l1[14];
    final opt1 = l1.substring(15, 30);

    // Line2 (30):
    // [0..6) birth, [6] birthChk, [7] sex, [8..14) expiry, [14] expiryChk,
    // [15..18) nationality, [18..29) opt2, [29] finalComposite
    final birth = l2.substring(0, 6);
    final birthChk = l2[6];
    final sex = l2[7];
    final expiry = l2.substring(8, 14);
    final expiryChk = l2[14];
    final nationality = fixAlphaOnlyField(l2.substring(15, 18));
    final opt2 = l2.substring(18, 29);
    final finalComposite = l2[29];

    log("Nationality ${nationality}");

    // Line3 (30): names "LAST<<FIRST<MIDDLE..."
    final nameField = l3;
    final nameParts = nameField.split('<<');
    String lastName = nameParts.isNotEmpty ? nameParts[0].replaceAll('<', ' ').trim() : '';
    String firstName = nameParts.length > 1 ? nameParts[1].replaceAll('<', ' ').trim() : '';
    lastName = _cleanName(lastName);
    firstName = _cleanName(firstName);

    // Validations
    final vDoc = _computeMrzCheckDigit(docNo) == docChk;
    final vBirth = RegExp(r'^\d{6}$').hasMatch(birth) && _computeMrzCheckDigit(birth) == birthChk;
    final vExpiry = RegExp(r'^\d{6}$').hasMatch(expiry) && _computeMrzCheckDigit(expiry) == expiryChk;

    validation.linesLengthValid = (l2.length == 44 && l1.length == 44);
    // validation.docCodeValid = DocumentCodeHelper.isValid(documentCode);
    validation.docCodeValid = DocumentCodeHelper.isValid(documentCode);

    bool isDocNumberValid = _computeMrzCheckDigit(docNo) == docChk;
    validation.docNumberValid = isDocNumberValid;

    bool isBirthDateValid = (RegExp(r'^\d{6}$').hasMatch(birth) && _computeMrzCheckDigit(birth) == birthChk);
    validation.birthDateValid = isBirthDateValid;

    bool isExpiryDateValid = (RegExp(r'^\d{6}$').hasMatch(expiry) && _computeMrzCheckDigit(expiry) == expiryChk);
    validation.expiryDateValid = isExpiryDateValid;

    validation.personalNumberValid = true;

    final compositeInput = docNo + docChk + birth + birthChk + expiry + expiryChk + opt2; // ICAO Doc 9303 specifies opt2 in composite
    final vFinal = _computeMrzCheckDigit(compositeInput) == finalComposite;
    validation.finalCheckValid = vFinal;

    bool validNames = validateNames(firstName, lastName, otherLines);
    bool isNamesValid = validNames;
    validation.nameValid = isNamesValid;
    if (!isNamesValid && nameValidations != null) {
      if (nameValidations.any((a) => a.firstName.toLowerCase() == firstName.toLowerCase() && a.lastName.toLowerCase() == lastName.toLowerCase())) {
        isNamesValid = true;
        validation.nameValid = true;
      }
    }

    bool validCountry = isValidMrzCountry(country);
    bool isValidCountry = validCountry;
    validation.countryValid = isValidCountry;

    bool validNationality = isValidMrzCountry(nationality);
    bool isValidNationality = validNationality;
    validation.nationalityValid = isValidNationality;

    return validation;
  } catch (e) {
    return validation;
  }
}