///|
fn set_tolerance(
values : Array[(String, @decimal.Decimal)],
currency : String,
value : @decimal.Decimal,
add : Bool,
) -> Unit {
for i in 0.. Array[(String, @decimal.Decimal)] {
let options = ctx.options
let values : Array[(String, @decimal.Decimal)] = []
if options.inferred_tolerance_default.length() > 0 {
for (name, raw) in options.raw {
if name == "inferred_tolerance_default" {
let parts = raw.split(":").to_array()
if parts.length() == 2 {
let currency = String::from_iter(parts[0].iter())
if currency != "*" &&
options.inferred_tolerance_default.get(currency) is Some(n) {
set_tolerance(values, currency, n, false)
}
}
}
}
for (currency, n) in options.inferred_tolerance_default {
if currency != "*" {
set_tolerance(values, currency, n, false)
}
}
}
let costs : Array[(String, @decimal.Decimal)]? = if options.infer_tolerance_from_cost {
Some([])
} else {
None
}
for p in postings {
if p.units is Some(units) && units.number.has_fractional_digits() {
let scale = units.number.scale()
let tolerance = match ctx.tolerance_cache.get(scale) {
Some(n) => n
None => {
let n = units.number
.last_digit_place()
.mul(options.tolerance_multiplier)
ctx.tolerance_cache.set(scale, n)
n
}
}
set_tolerance(values, units.currency, tolerance, false)
if costs is Some(costs) {
if p.cost is Some(cost) &&
cost.number_per is Some(n) &&
cost.currency is Some(currency) {
set_tolerance(costs, currency, cost_tolerance(tolerance.mul(n)), true)
}
let price = match p.price {
Some(PerUnit(a)) => Some(a)
Some(Total(a)) =>
match a.number.div(units.number.abs()) {
Some(n) => Some(@ast.Amount::new(n, a.currency))
None => None
}
None => None
}
if price is Some(a) {
set_tolerance(
costs,
a.currency,
cost_tolerance(tolerance.mul(a.number.abs())),
true,
)
}
}
}
}
if costs is Some(costs) {
for (currency, n) in costs {
set_tolerance(values, currency, n, false)
}
}
values
}
///|
fn cost_tolerance(value : @decimal.Decimal) -> @decimal.Decimal {
let cap = @decimal.Decimal::parse("0.5").unwrap()
if value.less_than(cap) {
value
} else if value.equal(cap) {
value
} else {
cap
}
}