Fix amount parsing to handle both @ and @@ SATS notation
Pending expense entries use per-unit price notation (@ SATS) while migrated entries use total price notation (@@ SATS). Formats handled: - "50.00 EUR @@ 50000 SATS" - total price (multiply = amount) - "50.00 EUR @ 1000.5 SATS" - per-unit price (multiply for total) - "50.00 EUR" with metadata - legacy format - "50000 SATS" - old SATS-first format 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7173e051fe
commit
913e4705b1
2 changed files with 144 additions and 51 deletions
118
fava_client.py
118
fava_client.py
|
|
@ -224,27 +224,61 @@ class FavaClient:
|
|||
continue
|
||||
|
||||
import re
|
||||
# Try to extract EUR/USD amount first (new format)
|
||||
fiat_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str)
|
||||
if fiat_match and fiat_match.group(2) in ('EUR', 'USD', 'GBP'):
|
||||
# Direct EUR/USD amount (new approach)
|
||||
fiat_amount = Decimal(fiat_match.group(1))
|
||||
fiat_currency = fiat_match.group(2)
|
||||
|
||||
# Try total price notation: "50.00 EUR @@ 50000 SATS"
|
||||
total_price_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})\s+@@\s+(-?\d+)\s+SATS$', amount_str)
|
||||
# Try per-unit price notation: "50.00 EUR @ 1000.5 SATS"
|
||||
unit_price_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})\s+@\s+([\d.]+)\s+SATS$', amount_str)
|
||||
|
||||
if total_price_match:
|
||||
fiat_amount = Decimal(total_price_match.group(1))
|
||||
fiat_currency = total_price_match.group(2)
|
||||
sats_amount = int(total_price_match.group(3))
|
||||
|
||||
if fiat_currency not in fiat_balances:
|
||||
fiat_balances[fiat_currency] = Decimal(0)
|
||||
|
||||
fiat_balances[fiat_currency] += fiat_amount
|
||||
|
||||
# Also track SATS equivalent from metadata if available
|
||||
posting_meta = posting.get("meta", {})
|
||||
sats_equiv = posting_meta.get("sats-equivalent")
|
||||
if sats_equiv:
|
||||
sats_amount = int(sats_equiv) if fiat_amount > 0 else -int(sats_equiv)
|
||||
total_sats += sats_amount
|
||||
if account_name not in accounts_dict:
|
||||
accounts_dict[account_name] = {"account": account_name, "sats": 0}
|
||||
accounts_dict[account_name]["sats"] += sats_amount
|
||||
total_sats += sats_amount
|
||||
if account_name not in accounts_dict:
|
||||
accounts_dict[account_name] = {"account": account_name, "sats": 0}
|
||||
accounts_dict[account_name]["sats"] += sats_amount
|
||||
|
||||
elif unit_price_match:
|
||||
fiat_amount = Decimal(unit_price_match.group(1))
|
||||
fiat_currency = unit_price_match.group(2)
|
||||
sats_per_unit = Decimal(unit_price_match.group(3))
|
||||
sats_amount = int(fiat_amount * sats_per_unit)
|
||||
|
||||
if fiat_currency not in fiat_balances:
|
||||
fiat_balances[fiat_currency] = Decimal(0)
|
||||
fiat_balances[fiat_currency] += fiat_amount
|
||||
|
||||
total_sats += sats_amount
|
||||
if account_name not in accounts_dict:
|
||||
accounts_dict[account_name] = {"account": account_name, "sats": 0}
|
||||
accounts_dict[account_name]["sats"] += sats_amount
|
||||
|
||||
# Try simple fiat format: "50.00 EUR" (check metadata for sats)
|
||||
elif re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str):
|
||||
fiat_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str)
|
||||
if fiat_match and fiat_match.group(2) in ('EUR', 'USD', 'GBP'):
|
||||
fiat_amount = Decimal(fiat_match.group(1))
|
||||
fiat_currency = fiat_match.group(2)
|
||||
|
||||
if fiat_currency not in fiat_balances:
|
||||
fiat_balances[fiat_currency] = Decimal(0)
|
||||
fiat_balances[fiat_currency] += fiat_amount
|
||||
|
||||
# Also track SATS equivalent from metadata if available (legacy)
|
||||
posting_meta = posting.get("meta", {})
|
||||
sats_equiv = posting_meta.get("sats-equivalent")
|
||||
if sats_equiv:
|
||||
sats_amount = int(sats_equiv) if fiat_amount > 0 else -int(sats_equiv)
|
||||
total_sats += sats_amount
|
||||
if account_name not in accounts_dict:
|
||||
accounts_dict[account_name] = {"account": account_name, "sats": 0}
|
||||
accounts_dict[account_name]["sats"] += sats_amount
|
||||
|
||||
else:
|
||||
# Old format: SATS with cost/price notation - extract SATS amount
|
||||
|
|
@ -347,24 +381,50 @@ class FavaClient:
|
|||
continue
|
||||
|
||||
import re
|
||||
# Try to extract EUR/USD amount first (new format)
|
||||
fiat_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str)
|
||||
if fiat_match and fiat_match.group(2) in ('EUR', 'USD', 'GBP'):
|
||||
# Direct EUR/USD amount (new approach)
|
||||
fiat_amount = Decimal(fiat_match.group(1))
|
||||
fiat_currency = fiat_match.group(2)
|
||||
|
||||
# Try total price notation: "50.00 EUR @@ 50000 SATS"
|
||||
total_price_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})\s+@@\s+(-?\d+)\s+SATS$', amount_str)
|
||||
# Try per-unit price notation: "50.00 EUR @ 1000.5 SATS"
|
||||
unit_price_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})\s+@\s+([\d.]+)\s+SATS$', amount_str)
|
||||
|
||||
if total_price_match:
|
||||
fiat_amount = Decimal(total_price_match.group(1))
|
||||
fiat_currency = total_price_match.group(2)
|
||||
sats_amount = int(total_price_match.group(3))
|
||||
|
||||
if fiat_currency not in user_data[user_id]["fiat_balances"]:
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] = Decimal(0)
|
||||
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] += fiat_amount
|
||||
user_data[user_id]["balance"] += sats_amount
|
||||
|
||||
# Also track SATS equivalent from metadata if available
|
||||
posting_meta = posting.get("meta", {})
|
||||
sats_equiv = posting_meta.get("sats-equivalent")
|
||||
if sats_equiv:
|
||||
sats_amount = int(sats_equiv) if fiat_amount > 0 else -int(sats_equiv)
|
||||
user_data[user_id]["balance"] += sats_amount
|
||||
elif unit_price_match:
|
||||
fiat_amount = Decimal(unit_price_match.group(1))
|
||||
fiat_currency = unit_price_match.group(2)
|
||||
sats_per_unit = Decimal(unit_price_match.group(3))
|
||||
sats_amount = int(fiat_amount * sats_per_unit)
|
||||
|
||||
if fiat_currency not in user_data[user_id]["fiat_balances"]:
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] = Decimal(0)
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] += fiat_amount
|
||||
user_data[user_id]["balance"] += sats_amount
|
||||
|
||||
# Try simple fiat format: "50.00 EUR" (check metadata for sats)
|
||||
elif re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str):
|
||||
fiat_match = re.match(r'^(-?[\d.]+)\s+([A-Z]{3})$', amount_str)
|
||||
if fiat_match and fiat_match.group(2) in ('EUR', 'USD', 'GBP'):
|
||||
fiat_amount = Decimal(fiat_match.group(1))
|
||||
fiat_currency = fiat_match.group(2)
|
||||
|
||||
if fiat_currency not in user_data[user_id]["fiat_balances"]:
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] = Decimal(0)
|
||||
user_data[user_id]["fiat_balances"][fiat_currency] += fiat_amount
|
||||
|
||||
# Also track SATS equivalent from metadata if available (legacy)
|
||||
posting_meta = posting.get("meta", {})
|
||||
sats_equiv = posting_meta.get("sats-equivalent")
|
||||
if sats_equiv:
|
||||
sats_amount = int(sats_equiv) if fiat_amount > 0 else -int(sats_equiv)
|
||||
user_data[user_id]["balance"] += sats_amount
|
||||
|
||||
else:
|
||||
# Old format: SATS with cost/price notation
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue