fix(parties): read every separator a TIN can be written with (P7)
A taxpayer identification number can be written 123,45,6789 or (123) 45-6789 as easily as 123-45-6789, and the scanner only knew the second: a comma-grouped number slipped through every party field, every refusal that quotes its input and the access log's masking, which is how a full TIN could reach a result the books promise never shows one (rules.md B-26, I-7). The scanner now reads a comma or a parenthesis between a TIN's 3-2-4 or 2-7 groups, and any run of spaces counts once however long it is, so 12 3456789 is an EIN. Commas and parentheses join only those groups: an amount's thousands separators (1,234,567.89 is 1-3-3-2) still read as an amount, and a nine-digit D-U-N-S number stays its own setting's kind (company.duns). The old run reading is unchanged for everything it found, which the property asserts; replay still reads a journaled line as P2 did (B-28). The truth table and the ASCII-equality property pinned the old separator set, so they were updated with it: the property is now has_full_tin_never_forgets_a_tin (what was found before is still found). No journal, entry or figure changes: this is a text scanner only.
This commit is contained in:
1 parent
40101f197e
commit
c6527280e7
3 files changed
+224
-71
No files matched your search
@@ -1141,3 +1141,60 @@ proptest! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#![proptest_config(ProptestConfig::with_cases(2000))]
|
||||
|
||||
/// rules.md B-26 (P7): a TIN is found and masked however its groups
|
||||
/// are separated — a hyphen, a dot, a comma, a parenthesis, a slash,
|
||||
/// an underscore, or any run of spaces — and what merely looks like
|
||||
/// one is not: an amount's thousands separators (1,234,567.89 is
|
||||
/// 1-3-3-2, no TIN's shape), a longer number holding a TIN's digits,
|
||||
/// and the company's own nine-digit D-U-N-S number, which is its own
|
||||
/// setting's kind (company.duns), never a party field. The ACH payment
|
||||
/// methods' lines get the same exemption in P4b S4's Kind; until then
|
||||
/// the filing scan's narrow shapes keep a bank export's routing
|
||||
/// numbers out of the rule (rules.md B-26).
|
||||
#[test]
|
||||
fn tin_shapes_with_any_separator_are_found(
|
||||
sep in prop::sample::select(vec![
|
||||
"-", " ", " ", " ", ".", ",", "/", "_", " - ", ", ", ") ", "(", ")", ",\u{a0}",
|
||||
]),
|
||||
which in 0usize..2,
|
||||
) {
|
||||
let shapes: [&[&str]; 2] = [&["187", "05", "1907"], &["12", "3456789"]];
|
||||
let tin = shapes[which].join(sep);
|
||||
prop_assert!(ledger_core::parties::has_full_tin(&tin), "{:?}", tin);
|
||||
let masked = ledger_core::parties::redact_full_tins(&tin);
|
||||
prop_assert_eq!(
|
||||
masked.chars().filter(|c| *c == '•').count(),
|
||||
9,
|
||||
"{:?}: {:?}",
|
||||
tin,
|
||||
masked
|
||||
);
|
||||
prop_assert!(
|
||||
!ledger_core::parties::has_full_tin(&masked),
|
||||
"{:?}: {:?}",
|
||||
tin,
|
||||
masked
|
||||
);
|
||||
|
||||
// No false positive on an amount.
|
||||
prop_assert!(!ledger_core::parties::has_full_tin("1,234,567.89"));
|
||||
let amount = ledger_core::parties::redact_full_tins("1,234,567.89");
|
||||
prop_assert_eq!(amount.as_ref(), "1,234,567.89");
|
||||
// Nor on the company's D-U-N-S number: the key's own kind takes a
|
||||
// nine-digit number, bare or printed 2-3-4.
|
||||
let duns = ledger_core::settings::KEYS
|
||||
.iter()
|
||||
.find(|k| k.name == "company.duns")
|
||||
.expect("the books know company.duns");
|
||||
prop_assert!(
|
||||
ledger_core::settings::check(duns, &serde_json::json!("149976972")).is_ok()
|
||||
);
|
||||
prop_assert!(
|
||||
ledger_core::settings::check(duns, &serde_json::json!("14-997-6972")).is_ok()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user