parse static method

BankChequeInfo parse(
  1. String rawText
)

Parses raw text extracted from bank cheque OCR scan into BankChequeInfo.

Implementation

static BankChequeInfo parse(String rawText) {
  final cleanedText = rawText.replaceAll('\r', '').trim();
  final lines = cleanedText.split('\n');

  String rawMicrLine = '';
  for (final line in lines) {
    if (line.contains('c') || line.contains('a') || line.contains('⑈') || line.contains('⑆') || RegExp(r'[0-9]{6}.*[0-9]{9}').hasMatch(line)) {
      rawMicrLine = line;
      break;
    }
  }
  if (rawMicrLine.isEmpty && lines.isNotEmpty) {
    rawMicrLine = lines.last;
  }

  // 1. Extract Cheque Number (6 digits)
  String chequeNumber = '000000';
  final chequeMatch = _chequeNumRegex.firstMatch(cleanedText);
  if (chequeMatch != null) {
    chequeNumber = chequeMatch.group(1)!;
  }

  // 2. Extract MICR Routing Number (9 digits)
  String routingNumber = '000000000';
  final routingMatch = _routingRegex.firstMatch(cleanedText);
  if (routingMatch != null) {
    routingNumber = routingMatch.group(1)!;
  } else {
    final plain9 = RegExp(r'\b([0-9]{9})\b').firstMatch(cleanedText);
    if (plain9 != null) routingNumber = plain9.group(1)!;
  }

  // 6. Extract optional IFSC Code & Bank Name
  String? ifscCode;
  final ifscMatch = _ifscRegex.firstMatch(cleanedText);
  if (ifscMatch != null) {
    ifscCode = ifscMatch.group(1);
  }

  // 3. Extract Account Number
  String accountNumber = '000000';
  final accountMatches = _accountRegex.allMatches(cleanedText).toList();
  for (final match in accountMatches) {
    final val = match.group(1)!;
    if (val != chequeNumber && val != routingNumber && (ifscCode == null || !ifscCode.contains(val))) {
      accountNumber = val;
      break;
    }
  }

  // 4. Extract Transaction Code
  String transactionCode = '10';
  final transMatches = _transCodeRegex.allMatches(cleanedText).toList();
  for (final match in transMatches) {
    final val = match.group(1)!;
    if (val != chequeNumber && !routingNumber.contains(val) && val != accountNumber) {
      transactionCode = val;
      break;
    }
  }

  // 5. Check sum validation on ABA 9-digit Transit Routing Number (3-7-1 weighting)
  final isValidMicr = validateRoutingChecksum(routingNumber) || (chequeNumber != '000000' && routingNumber.length == 9);

  String? bankName = _inferBankName(cleanedText, routingNumber, ifscCode);

  // 7. Extract Date & Amount
  String? chequeDate;
  final dateMatch = _dateRegex.firstMatch(cleanedText);
  if (dateMatch != null) {
    chequeDate = dateMatch.group(1);
  }

  double? amount;
  final explicitAmt = RegExp(r'(?:AMOUNT|TOTAL|PAY)\s*[:\$₹]?\s*([0-9,]+(?:\.[0-9]{2})?)', caseSensitive: false).firstMatch(cleanedText);
  if (explicitAmt != null) {
    amount = double.tryParse(explicitAmt.group(1)!.replaceAll(',', ''));
  } else {
    final currencyMatch = RegExp(r'[\$₹]\s*([0-9,]+(?:\.[0-9]{2})?)').firstMatch(cleanedText);
    if (currencyMatch != null) {
      amount = double.tryParse(currencyMatch.group(1)!.replaceAll(',', ''));
    }
  }

  return BankChequeInfo(
    rawMicrLine: rawMicrLine,
    chequeNumber: chequeNumber,
    routingNumber: routingNumber,
    accountNumber: accountNumber,
    transactionCode: transactionCode,
    bankName: bankName,
    ifscCode: ifscCode,
    chequeDate: chequeDate,
    amount: amount,
    isValidMicr: isValidMicr,
    extraDetails: {
      'MICR Codeline': rawMicrLine,
      'Format Standard': 'ISO 1004 / E-13B MICR',
    },
  );
}