mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 06:21:23 +00:00
API v1: add amount_cents + signed_amount_cents to transactions (#899)
* feat(api): add amount_cents + signed_amount_cents to transactions * fix: use currency.minor_unit_conversion for amount_cents - Replace hardcoded *100 with currency.minor_unit_conversion - Handles JPY (0 decimals), KWD/BHD (3 decimals), etc. correctly - Add assert_amount_cents_fields helper to validate sign/scale invariants
This commit is contained in:
@@ -3,6 +3,17 @@
|
||||
json.id transaction.id
|
||||
json.date transaction.entry.date
|
||||
json.amount transaction.entry.amount_money.format
|
||||
|
||||
# Agent/automation-friendly numeric fields (avoid localized parsing and clarify sign)
|
||||
# `amount` in v1 is a localized string and may follow an accounting sign convention.
|
||||
# Expose minor units (cents) as integers to make the API agent-friendly.
|
||||
# Uses currency.minor_unit_conversion (e.g. 100 for USD/EUR, 1 for JPY, 1000 for KWD).
|
||||
amount_money = transaction.entry.amount_money
|
||||
conversion_factor = amount_money.currency.minor_unit_conversion
|
||||
amount_cents = (amount_money.amount * conversion_factor).round(0).to_i.abs
|
||||
json.amount_cents amount_cents
|
||||
json.signed_amount_cents(transaction.entry.classification == "income" ? amount_cents : -amount_cents)
|
||||
|
||||
json.currency transaction.entry.currency
|
||||
json.name transaction.entry.name
|
||||
json.notes transaction.entry.notes
|
||||
|
||||
@@ -41,6 +41,10 @@ class Api::V1::TransactionsControllerTest < ActionDispatch::IntegrationTest
|
||||
response_data = JSON.parse(response.body)
|
||||
assert response_data.key?("transactions")
|
||||
assert response_data.key?("pagination")
|
||||
|
||||
# Agent-friendly numeric fields (validate type + sign invariants)
|
||||
first = response_data["transactions"].first
|
||||
assert_amount_cents_fields(first)
|
||||
assert response_data["pagination"].key?("page")
|
||||
assert response_data["pagination"].key?("per_page")
|
||||
assert response_data["pagination"].key?("total_count")
|
||||
@@ -130,6 +134,7 @@ class Api::V1::TransactionsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal @transaction.id, response_data["id"]
|
||||
assert response_data.key?("name")
|
||||
assert response_data.key?("amount")
|
||||
assert_amount_cents_fields(response_data)
|
||||
assert response_data.key?("date")
|
||||
assert response_data.key?("account")
|
||||
end
|
||||
@@ -358,4 +363,22 @@ end
|
||||
def api_headers(api_key)
|
||||
{ "X-Api-Key" => api_key.display_key }
|
||||
end
|
||||
|
||||
# Validates agent-friendly numeric fields: type, sign invariants
|
||||
def assert_amount_cents_fields(txn_json)
|
||||
assert txn_json.key?("amount_cents"), "Expected amount_cents field"
|
||||
assert txn_json.key?("signed_amount_cents"), "Expected signed_amount_cents field"
|
||||
assert_kind_of Integer, txn_json["amount_cents"]
|
||||
assert_kind_of Integer, txn_json["signed_amount_cents"]
|
||||
assert_operator txn_json["amount_cents"], :>=, 0, "amount_cents must be non-negative"
|
||||
assert_equal txn_json["amount_cents"].abs, txn_json["signed_amount_cents"].abs,
|
||||
"Absolute values of amount_cents and signed_amount_cents must match"
|
||||
if txn_json["classification"] == "income"
|
||||
assert_operator txn_json["signed_amount_cents"], :>=, 0,
|
||||
"income transactions should have non-negative signed_amount_cents"
|
||||
else
|
||||
assert_operator txn_json["signed_amount_cents"], :<=, 0,
|
||||
"non-income transactions should have non-positive signed_amount_cents"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user