validateRaastQr function
Checks whether a Raast QR code can be paid, e.g. before showing a payment screen or to warn about a tampered sticker.
Errors: not a Pakistani payment QR, checksum mismatch (damaged or edited), no IBAN or an IBAN that fails its checksum, expired, or a fixed-amount QR without the expiry that banking apps require.
Warnings: an amount in a static QR (apps ignore it, so the payer must
type it), or a QR that expires within expiresSoonMs milliseconds (an
hour by default) of now (defaults to DateTime.now).
Implementation
RaastQrValidation validateRaastQr(
String payload, {
DateTime? now,
int expiresSoonMs = 3600000,
}) {
final qr = parseRaastQr(payload);
if (qr == null) {
return const RaastQrValidation(
valid: false,
errors: [RaastQrError.notARaastQr],
warnings: [],
qr: null,
);
}
final errors = <RaastQrError>[];
final warnings = <RaastQrWarning>[];
final time = now ?? DateTime.now();
if (!qr.crcValid) errors.add(RaastQrError.badChecksum);
if (qr.iban == null) {
errors.add(RaastQrError.noIban);
} else if (!qr.ibanValid) {
errors.add(RaastQrError.invalidIban);
}
if (qr.kind == RaastQrKind.p2p) {
if (qr.isDynamic && qr.expiresAt == null) {
errors.add(RaastQrError.missingExpiry);
}
if (!qr.isDynamic && qr.amount != null) {
warnings.add(RaastQrWarning.amountIgnored);
}
if (qr.expiresAt != null) {
final remaining = _localDateTime(qr.expiresAt!).millisecondsSinceEpoch -
time.millisecondsSinceEpoch;
if (remaining <= 0) {
errors.add(RaastQrError.expired);
} else if (remaining <= expiresSoonMs) {
warnings.add(RaastQrWarning.expiresSoon);
}
}
}
return RaastQrValidation(
valid: errors.isEmpty,
errors: List.unmodifiable(errors),
warnings: List.unmodifiable(warnings),
qr: qr,
);
}