Legal Entity Identifiers
Legal Entity Identifiers (ISO 17442) checked by their check digits, taken apart, made from an 18-character base, found in text, and looked up in GLEIF's public register for the company's name and status.
Version 1.0.0 · 5 functions · 1 crate
Functions
What use lei.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use lei_check, lei_valid from lei (Quillo 0.6).
lei_check(lei: str) → anyAn LEI read: { valid, lei, lou, reserved, entity, check_digits, error }. lou is the issuing organization's prefix (first four characters), entity the twelve that name the company. Spaces and case are ignored.
lei_valid(lei: str) → boolWhether lei is a well-formed LEI with the right check digits.
lei_make(base: str) → stror an errorAn LEI from its first 18 characters, with the two check digits added (for test data and for LOUs issuing codes).
lei_find(text: str) → listEvery valid LEI in a text (a contract, a trade confirmation, a CSV), each once in the order found.
lei_lookup(lei: str, base_url: str) → anyor an errorThe company behind an LEI from GLEIF's public register (no key needed): { lei, legal_name, country, city, jurisdiction, legal_form, entity_status, registration_status, next_renewal, managing_lou }. registration_status "ISSUED" is current; "LAPSED" means it was not renewed. base_url "" is GLEIF's API (GLEIF_API_URL changes it).
Get it
$ quillo install lei # lei.qwer into this folder$ quillo install lei --example # and its example, lei.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/lei.qwer$ curl -O https://quillolang.org/plugins/files/lei.qweThen, in your program, all of it or only what you call:
use lei.qweruse lei_check, lei_valid from lei // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
ureq = "2"Example
// Counterparties on a trade confirmation checked by their LEIs before the report goes to the// regulator; a typo is caught offline, and a lookup shows who the LEI belongs to.//// quillo run lei.qwe then open http://localhost:8080/check and http://localhost:8080/who/HWUPKR0MPOU8FGXBT394 (network)use "lei.qwer"let CONFIRMATION = "Trade 77812. Buyer LEI: HWUPKR0MPOU8FGXBT394. Seller LEI: 5493001KJTIIGC8Y1R12. Broker: 5493001KJTIIGC8Y1R17 (as typed)."route GET /check = { found: lei_find(CONFIRMATION), buyer: lei_check("HWUP KR0M POU8 FGXB T394"), typo: lei_check("5493001KJTIIGC8Y1R17").error, made: lei_make("5493001KJTIIGC8Y1R")?, short: lei_check("5493001KJ").error,}route GET /who/:lei = lei_lookup(lei, "")?$ quillo run lei.qwe$ curl 'localhost:8080/check'Source
//! Legal Entity Identifiers (ISO 17442), the 20-character codes banks and regulators use for companies: checked by their ISO 7064 check digits, taken apart, made from an 18-character base, found in text, and looked up in GLEIF's public register for the company's name, country and whether the LEI is current.//! version: 1.0.0//!//! [dependencies]//! ureq = "2"use serde_json::{json, Value};fn clean(s: &str) -> String { s.chars().filter(|c| c.is_ascii_alphanumeric()).map(|c| c.to_ascii_uppercase()).collect()}/// The number mod 97, letters as 10 to 35 (ISO 7064 MOD 97-10), worked out piece by piece.fn mod97(s: &str) -> Option<u32> { let mut r: u64 = 0; for c in s.chars() { let v = c.to_digit(36)? as u64; r = if v < 10 { (r * 10 + v) % 97 } else { (r * 100 + v) % 97 }; } Some(r as u32)}/// An LEI read: `{ valid, lei, lou, reserved, entity, check_digits, error }`. `lou` is the issuing organization's prefix (first/// four characters), `entity` the twelve that name the company. Spaces and case are ignored.pub fn lei_check(lei: &str) -> Value { let l = clean(lei); let fail = |e: &str| json!({ "valid": false, "lei": l, "error": e }); if l.len() != 20 { return fail(&format!("an LEI has 20 characters, not {}", l.len())); } if !l[18..].chars().all(|c| c.is_ascii_digit()) { return fail("the last two characters are check digits"); } if mod97(&l) != Some(1) { return fail("the check digits do not match: a typo"); } json!({ "valid": true, "lei": l, "lou": &l[..4], "reserved": &l[4..6], "entity": &l[6..18], "check_digits": &l[18..], "error": null })}/// Whether `lei` is a well-formed LEI with the right check digits.pub fn lei_valid(lei: &str) -> bool { lei_check(lei)["valid"] == json!(true)}/// An LEI from its first 18 characters, with the two check digits added (for test data and for LOUs issuing codes).pub fn lei_make(base: &str) -> Result<String, String> { let b = clean(base); if b.len() != 18 { return Err(format!("the base is 18 characters, not {}", b.len())); } let r = mod97(&format!("{}00", b)).ok_or("the base has letters and digits only")?; Ok(format!("{}{:02}", b, 98 - r))}/// Every valid LEI in a text (a contract, a trade confirmation, a CSV), each once in the order found.pub fn lei_find(text: &str) -> Vec<String> { let mut out: Vec<String> = vec![]; for w in text.split(|c: char| !c.is_ascii_alphanumeric()) { if w.len() == 20 && lei_valid(w) { let u = w.to_ascii_uppercase(); if !out.contains(&u) { out.push(u); } } } out}/// The company behind an LEI from GLEIF's public register (no key needed): `{ lei, legal_name, country, city, jurisdiction,/// legal_form, entity_status, registration_status, next_renewal, managing_lou }`. `registration_status` "ISSUED" is current;/// "LAPSED" means it was not renewed. `base_url` "" is GLEIF's API (GLEIF_API_URL changes it).pub fn lei_lookup(lei: &str, base_url: &str) -> Result<Value, String> { let c = lei_check(lei); if c["valid"] != json!(true) { return Err(c["error"].as_str().unwrap_or("not an LEI").to_string()); } let l = c["lei"].as_str().unwrap_or_default(); let base = if base_url.is_empty() { std::env::var("GLEIF_API_URL").unwrap_or_else(|_| "https://api.gleif.org/api/v1".into()) } else { base_url.to_string() }; let url = format!("{}/lei-records/{}", base.trim_end_matches('/'), l); let res = ureq::get(&url).timeout(std::time::Duration::from_secs(15)).set("Accept", "application/vnd.api+json").call(); let text = match res { Ok(r) => r.into_string().unwrap_or_default(), Err(ureq::Error::Status(404, _)) => return Err(format!("{} is not in GLEIF's register", l)), Err(e) => return Err(format!("GLEIF: {}", e)), }; let v: Value = serde_json::from_str(&text).map_err(|_| "GLEIF did not answer JSON".to_string())?; let a = &v["data"]["attributes"]; let e = &a["entity"]; Ok(json!({ "lei": l, "legal_name": e["legalName"]["name"], "country": e["legalAddress"]["country"], "city": e["legalAddress"]["city"], "jurisdiction": e["jurisdiction"], "legal_form": e["legalForm"]["id"], "entity_status": e["status"], "registration_status": a["registration"]["status"], "next_renewal": a["registration"]["nextRenewalDate"], "managing_lou": a["registration"]["managingLou"], }))}Related
iban.qwer · 1.0.0IBANs checked (country, length, check digits) and printed as banks print them, and BICs checked.9 views · 8 downloadsSecurity identifiers securities_ids.qwer · 1.0.0ISIN, CUSIP and CINS, SEDOL and FIGI checked by their check digits and told apart, ISINs made from a CUSIP, SEDOL or other national number, and ISINs found in text.7 views · 6 downloadsUS routing numbers aba_routing.qwer · 1.0.0US bank routing numbers checked by their check digit and read for the Federal Reserve district and kind of institution, a check's MICR line read into routing, account and check number, and Canadian transit numbers.7 views · 6 downloadsOFX statements ofx.qwer · 1.0.0Bank and credit card statements in OFX and QFX, old SGML or XML: accounts, balances and each transaction with its bank id, ready to import without doubles.6 views · 8 downloadsISBN isbn.qwer · 1.0.0ISBNs checked, converted between 10 and 13 digits, hyphenated by the ISBN Agency's ranges into group, publisher and title parts with the group's language or country named, and every ISBN in a text found.6 views · 6 downloadsNational ID numbers national_ids.qwer · 1.0.0National identity numbers of 29 countries checked by their own rules (US SSN, UK NINO, CPF, Aadhaar, PH TIN, DNI and NIE, codice fiscale, PESEL...), with the birth date and sex read out where the number holds them.7 views · 7 downloadsThread 0 posts
On Legal Entity Identifiers: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.