commit a553585aca98e1ba0a3ce4fbc62ded353d7d6ea3
parent c3bc4fb27054eb6a7aaa7e75ab6285f47d44a6c5
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 12:56:35 +0000
core: add price and currency types
Diffstat:
2 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/src/hyf_core/domain/price.mojo b/src/hyf_core/domain/price.mojo
@@ -0,0 +1,67 @@
+from std.collections import Optional
+
+
+@fieldwise_init
+struct Price(Copyable, Movable):
+ var state: String
+ var amount: Int
+ var scale: Int
+ var currency: String
+ var basis: String
+
+
+def known_price(
+ amount: Int, scale: Int, currency: String, basis: String
+) raises -> Price:
+ if scale < 0 or scale > 9:
+ raise Error("price scale must be between 0 and 9")
+ if currency.strip() == "":
+ raise Error("known price requires a currency")
+ if (
+ basis != "per_unit"
+ and basis != "per_pack"
+ and basis != "per_order"
+ ):
+ raise Error("price basis must be per_unit, per_pack or per_order")
+ if amount < 0:
+ raise Error("price amount must be non-negative")
+ return Price(
+ state="known",
+ amount=amount,
+ scale=scale,
+ currency=String(currency),
+ basis=String(basis),
+ )
+
+
+def unknown_price() -> Price:
+ return Price(
+ state="unknown", amount=0, scale=0, currency="", basis="unknown"
+ )
+
+
+def price_is_known(price: Price) -> Bool:
+ return price.state == "known"
+
+
+def price_compare(left: Price, right: Price) raises -> Int:
+ if not price_is_known(left) or not price_is_known(right):
+ raise Error("cannot compare unknown prices")
+ if left.currency != right.currency:
+ raise Error(
+ "cannot compare prices in different currencies without conversion"
+ )
+ if left.basis != right.basis:
+ raise Error("cannot compare prices with different bases")
+ var scale = left.scale if left.scale > right.scale else right.scale
+ var left_value = left.amount
+ var right_value = right.amount
+ for _ in range(scale - left.scale):
+ left_value *= 10
+ for _ in range(scale - right.scale):
+ right_value *= 10
+ if left_value < right_value:
+ return -1
+ if left_value > right_value:
+ return 1
+ return 0
diff --git a/tests/test_domain.mojo b/tests/test_domain.mojo
@@ -197,3 +197,30 @@ def test_normalization_preserves_approximation() raises:
assert_equal(normalized.unit, "kg")
var exact = new_quantity(80, 0, "lb", "mass", "exact")
assert_equal(normalize_quantity_with_rule(exact, rule).qualifier, "exact")
+
+
+from hyf_core.domain.price import (
+ known_price,
+ price_compare,
+ price_is_known,
+ unknown_price,
+)
+
+
+def test_price_unknown_distinct_from_zero_and_no_fx() raises:
+ var unknown = unknown_price()
+ assert_true(not price_is_known(unknown))
+ assert_equal(unknown.amount, 0)
+ var zero = known_price(0, 2, "CAD", "per_unit")
+ assert_true(price_is_known(zero))
+ var five = known_price(500, 2, "CAD", "per_unit")
+ assert_equal(price_compare(five, zero), 1)
+ with assert_raises():
+ _ = price_compare(five, unknown)
+ var usd = known_price(500, 2, "USD", "per_unit")
+ with assert_raises():
+ _ = price_compare(five, usd)
+ with assert_raises():
+ _ = known_price(1, 2, "", "per_unit")
+ with assert_raises():
+ _ = known_price(1, 2, "CAD", "per_kg_approx")