Files
TimeTracker/migrations/fix_invoice_currency.py
Dries Peeters 0dd7ca1006 fix: Invoice currency displays EUR instead of selected currency from Settings
Fixed issue where invoices were always displaying EUR as the currency
regardless of what was configured in Settings. The Invoice model had a
hard-coded default of 'EUR' and the invoice creation route wasn't
explicitly setting the currency from Settings.

Changes:
- Updated invoice creation route to fetch and use currency from Settings
- Updated invoice duplication to preserve original invoice's currency
- Added currency code display to all monetary values in invoice templates
- Added currency code display to invoice list totals
- Created migration script to update existing invoices
- Added comprehensive unit tests and smoke tests
- Added detailed documentation for the fix

Backend changes:
- app/routes/invoices.py: Retrieve currency from Settings when creating
  invoices, pass currency_code explicitly to Invoice constructor
- app/routes/invoices.py: Preserve currency_code when duplicating invoices

Frontend changes:
- app/templates/invoices/view.html: Display currency code next to all
  monetary values (items, extra goods, subtotals, tax, totals)
- app/templates/invoices/list.html: Display currency code next to
  invoice totals in list view

Testing:
- tests/test_invoice_currency_fix.py: 10 unit tests covering various
  currency scenarios and edge cases
- tests/test_invoice_currency_smoke.py: 2 end-to-end smoke tests

Migration:
- migrations/fix_invoice_currency.py: Script to update existing invoices
  to use the currency from Settings

This fix is fully backward compatible. Existing invoices will continue
to work with their current currency values. Run the migration script to
update existing invoices to match the Settings currency.

Resolves: #153 (invoices-display-currency-as-eur-and-not-usd)
2025-10-25 07:40:35 +02:00

68 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""
Migration script to fix invoice currency codes.
Updates all invoices to use the currency from Settings instead of hard-coded EUR.
"""
import sys
import os
# Add parent directory to path to import app
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app import create_app, db
from app.models import Invoice, Settings
def fix_invoice_currencies():
"""Update all invoices to use currency from Settings"""
app = create_app()
with app.app_context():
# Get the currency from settings
settings = Settings.get_settings()
target_currency = settings.currency if settings else 'USD'
print(f"Target currency from settings: {target_currency}")
# Get all invoices
invoices = Invoice.query.all()
if not invoices:
print("No invoices found in database.")
return
print(f"Found {len(invoices)} invoices to process.")
# Update each invoice that doesn't match the target currency
updated_count = 0
for invoice in invoices:
if invoice.currency_code != target_currency:
print(f"Updating invoice {invoice.invoice_number}: {invoice.currency_code} -> {target_currency}")
invoice.currency_code = target_currency
updated_count += 1
if updated_count > 0:
try:
db.session.commit()
print(f"\nSuccessfully updated {updated_count} invoice(s) to use {target_currency}.")
except Exception as e:
db.session.rollback()
print(f"Error updating invoices: {e}")
sys.exit(1)
else:
print(f"\nAll invoices already using {target_currency}. No updates needed.")
if __name__ == '__main__':
print("=" * 60)
print("Invoice Currency Migration")
print("=" * 60)
print("\nThis script will update all invoices to use the currency")
print("configured in Settings instead of the hard-coded default.\n")
response = input("Do you want to proceed? (yes/no): ").strip().lower()
if response in ['yes', 'y']:
fix_invoice_currencies()
else:
print("Migration cancelled.")