Currencies
ISO 4217 currencies: names, symbols, minor units and the countries using them, prices formatted, and amounts turned into the cents payment APIs take.
Version 1.0.0 · 6 functions · 1 crate
Functions
What use currencies.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use currency_info, currency_of_country from currencies (Quillo 0.6).
currency_info(code: str) → anyor an errorA currency by its code ("EUR") or number ("978"): { code, numeric, name, symbol, subunit_symbol, minor_units, countries }. minor_units is how many decimals its amounts have; countries are alpha-2 codes.
currency_of_country(alpha2: str) → listor an errorThe currencies of a country by its alpha-2 code, funds left out: "CH" is ["CHF"], "PA" is ["PAB", "USD"].
currency_to_minor(amount: float, code: str) → intor an erroramount in the currency's smallest unit, as payment APIs such as Stripe take it: 12.34 EUR is 1234, 1250 JPY is 1250, 1.5 KWD is 1500. Rounded half away from zero.
currency_from_minor(minor: int, code: str) → floator an errorAn amount in the smallest unit back as a number: 1234 EUR cents is 12.34.
currency_format(amount: float, code: str) → stror an erroramount written with the currency's symbol and decimals, digits grouped by commas: "€1,234.50", "¥1,235" (rounded half away from zero), "-$5.00". Shops in other countries write money other ways (1.234,50 €): this is the English way.
currency_list() → listEvery current currency's code and name, [{ code, name }], by code: for a currency select. Funds and special codes (XAU gold, XDR) are left out.
Get it
$ quillo install currencies # currencies.qwer into this folder$ quillo install currencies --example # and its example, currencies.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/currencies.qwer$ curl -O https://quillolang.org/plugins/files/currencies.qweThen, in your program, all of it or only what you call:
use currencies.qweruse currency_info, currency_of_country from currencies // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
iso_currency = { version = "0.7", features = ["iterator"] }Example
// Prices shown in the buyer's currency, and sent to a payment API in its smallest unit.//// quillo run currencies.qwe then open http://localhost:8080/price?amount=1234.5¤cy=EURuse "currencies.qwer"route GET /price ? { amount: float, currency: str = "USD" } = { shown: currency_format(amount, currency)?, charge: { amount: currency_to_minor(amount, currency)?, currency: lower(currency) }, info: currency_info(currency)?,}route GET /examples = { yen: currency_format(1234.5, "JPY")?, dinar: currency_to_minor(1.5, "KWD")?, back: currency_from_minor(1234, "EUR")?, swiss: currency_of_country("CH")?, count: len(currency_list()),}$ quillo run currencies.qwe$ curl 'localhost:8080/price?amount=1234.5¤cy=EUR'$ curl 'localhost:8080/examples'Source
//! ISO 4217 currencies for prices and payments: names, symbols, minor units (2 for euros, 0 for yen, 3 for dinars), the countries using them, and amounts turned into the cents payment APIs take.//! version: 1.0.0//!//! [dependencies]//! iso_currency = { version = "0.7", features = ["iterator"] }use iso_currency::{Country, Currency, IntoEnumIterator};use serde_json::{json, Value};fn find(code: &str) -> Result<Currency, String> { let c = code.trim().to_uppercase(); if let Ok(n) = c.parse::<u16>() { return Currency::from_numeric(n).ok_or_else(|| format!("no currency {:?}", code)); } Currency::from_code(&c).ok_or_else(|| format!("no currency {:?}", code))}fn digits(c: Currency) -> u32 { c.exponent().unwrap_or(0) as u32}/// A currency by its code ("EUR") or number ("978"): `{ code, numeric, name, symbol, subunit_symbol, minor_units, countries }`. `minor_units` is how many decimals its amounts have; `countries` are alpha-2 codes.pub fn currency_info(code: &str) -> Result<Value, String> { let c = find(code)?; let s = c.symbol(); Ok(json!({ "code": c.code(), "numeric": c.numeric(), "name": c.name(), "symbol": s.symbol, "subunit_symbol": s.subunit_symbol, "minor_units": c.exponent(), "countries": c.used_by().iter().map(|k| k.to_string()).collect::<Vec<_>>(), }))}/// The currencies of a country by its alpha-2 code, funds left out: "CH" is ["CHF"], "PA" is ["PAB", "USD"].pub fn currency_of_country(alpha2: &str) -> Result<Vec<String>, String> { let k: Country = alpha2.trim().to_uppercase().parse().map_err(|_| format!("no country {:?}", alpha2))?; Ok(Currency::from_country(k).iter().filter(|c| !c.is_fund()).map(|c| c.code().to_string()).collect())}/// `amount` in the currency's smallest unit, as payment APIs such as Stripe take it: 12.34 EUR is 1234, 1250 JPY is 1250, 1.5 KWD is 1500. Rounded half away from zero.pub fn currency_to_minor(amount: f64, code: &str) -> Result<i64, String> { let c = find(code)?; let v = (amount * 10f64.powi(digits(c) as i32)).round(); if !v.is_finite() || v.abs() > 9e15 { return Err("amount out of range".into()); } Ok(v as i64)}/// An amount in the smallest unit back as a number: 1234 EUR cents is 12.34.pub fn currency_from_minor(minor: i64, code: &str) -> Result<f64, String> { Ok(minor as f64 / 10f64.powi(digits(find(code)?) as i32))}/// `amount` written with the currency's symbol and decimals, digits grouped by commas: "€1,234.50", "¥1,235" (rounded half away from zero), "-$5.00". Shops in other countries write money other ways (1.234,50 €): this is the English way.pub fn currency_format(amount: f64, code: &str) -> Result<String, String> { let c = find(code)?; let d = digits(c) as usize; let p = 10f64.powi(d as i32); let s = format!("{:.*}", d, (amount.abs() * p).round() / p); let (whole, frac) = s.split_once('.').map_or((s.as_str(), ""), |(w, f)| (w, f)); let mut g = String::new(); for (i, ch) in whole.chars().enumerate() { if i > 0 && (whole.len() - i) % 3 == 0 { g.push(','); } g.push(ch); } let sym = c.symbol().symbol; let sym = if sym.is_empty() { format!("{} ", c.code()) } else { sym }; Ok(format!("{}{}{}{}{}", if amount < 0.0 { "-" } else { "" }, sym, g, if d > 0 { "." } else { "" }, frac))}/// Every current currency's code and name, `[{ code, name }]`, by code: for a currency select. Funds and special codes (XAU gold, XDR) are left out.pub fn currency_list() -> Vec<Value> { let mut v: Vec<Currency> = Currency::iter().filter(|c| !c.is_fund() && !c.is_special() && c.is_superseded().is_none()).collect(); v.sort_by_key(|c| c.code()); v.iter().map(|c| json!({ "code": c.code(), "name": c.name() })).collect()}Related
cards.qwer · 1.0.0Payment card numbers checked before they reach a payment provider: Luhn check digit, brand and length, expiry, and the number formatted or masked for receipts.7 views · 8 downloadsCountries countries.qwer · 1.0.0ISO 3166 countries for forms and addresses: alpha-2, alpha-3 and numeric codes, names in several languages, calling codes, flags, continents, currencies and EU membership.9 views · 8 downloadsIBAN and BIC iban.qwer · 1.0.0IBANs checked (country, length, check digits) and printed as banks print them, and BICs checked.9 views · 9 downloadsLanguages languages.qwer · 1.0.0ISO 639 language codes and names in English and in the language itself, two- and three-letter codes read, and the best of your translations picked from Accept-Language.7 views · 10 downloadsPhone numbers phone.qwer · 1.0.0Phone numbers checked against Google's libphonenumber data, stored in E.164, shown in international or national form.7 views · 12 downloadsEmail addresses email_address.qwer · 1.0.0Email addresses checked against RFC 5322 and split into local part, domain and display name.7 views · 7 downloadsThread 0 posts
On Currencies: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.