From 61fafecb780a877a69ecca27ea95a1494669b70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elisi=C3=A1rio=20Couto?= Date: Wed, 10 Sep 2025 21:11:26 +0100 Subject: [PATCH] feat(frontend): adapt to composite key transaction structure - Update Transaction interface to include stable transaction_id field - Modify TransactionsList to use stable transaction_id for React keys - Update API models to handle new transactionId field from database - Fix API routes to properly map transaction_id in responses - Update test mocks to include transactionId field - Ensure backward compatibility with internal_transaction_id This adapts the frontend to work with the new composite primary key (accountId, transactionId) structure that prevents duplicate transactions. --- frontend/src/components/TransactionsList.tsx | 7 ++----- frontend/src/types/api.ts | 3 ++- leggend/api/models/accounts.py | 4 +++- leggend/api/routes/accounts.py | 6 ++++-- leggend/api/routes/transactions.py | 6 ++++-- tests/unit/test_api_transactions.py | 13 +++++++++---- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/TransactionsList.tsx b/frontend/src/components/TransactionsList.tsx index a210116..3adb3a8 100644 --- a/frontend/src/components/TransactionsList.tsx +++ b/frontend/src/components/TransactionsList.tsx @@ -267,10 +267,7 @@ export default function TransactionsList() { return (
@@ -365,7 +362,7 @@ export default function TransactionsList() { isOpen={showRawModal} onClose={handleCloseModal} rawTransaction={selectedTransaction?.raw_transaction} - transactionId={selectedTransaction?.internal_transaction_id || "unknown"} + transactionId={selectedTransaction?.transaction_id || "unknown"} />
); diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts index de7db2c..4e9f230 100644 --- a/frontend/src/types/api.ts +++ b/frontend/src/types/api.ts @@ -56,7 +56,8 @@ export interface RawTransactionData { } export interface Transaction { - internal_transaction_id: string | null; + transaction_id: string; // NEW: stable bank-provided transaction ID + internal_transaction_id: string | null; // OLD: unstable GoCardless ID account_id: string; transaction_value: number; transaction_currency: string; diff --git a/leggend/api/models/accounts.py b/leggend/api/models/accounts.py index 9588956..39c5e2c 100644 --- a/leggend/api/models/accounts.py +++ b/leggend/api/models/accounts.py @@ -36,7 +36,8 @@ class AccountDetails(BaseModel): class Transaction(BaseModel): """Transaction model""" - internal_transaction_id: Optional[str] = None + transaction_id: str # NEW: stable bank-provided transaction ID + internal_transaction_id: Optional[str] = None # OLD: unstable GoCardless ID institution_id: str iban: Optional[str] = None account_id: str @@ -54,6 +55,7 @@ class Transaction(BaseModel): class TransactionSummary(BaseModel): """Transaction summary for lists""" + transaction_id: str # NEW: stable bank-provided transaction ID internal_transaction_id: Optional[str] = None date: datetime description: str diff --git a/leggend/api/routes/accounts.py b/leggend/api/routes/accounts.py index e6f4362..63e9af2 100644 --- a/leggend/api/routes/accounts.py +++ b/leggend/api/routes/accounts.py @@ -243,7 +243,8 @@ async def get_account_transactions( # Return simplified transaction summaries data = [ TransactionSummary( - internal_transaction_id=txn["internalTransactionId"], + transaction_id=txn["transactionId"], # NEW: stable bank-provided ID + internal_transaction_id=txn.get("internalTransactionId"), date=txn["transactionDate"], description=txn["description"], amount=txn["transactionValue"], @@ -257,7 +258,8 @@ async def get_account_transactions( # Return full transaction details data = [ Transaction( - internal_transaction_id=txn["internalTransactionId"], + transaction_id=txn["transactionId"], # NEW: stable bank-provided ID + internal_transaction_id=txn.get("internalTransactionId"), institution_id=txn["institutionId"], iban=txn["iban"], account_id=txn["accountId"], diff --git a/leggend/api/routes/transactions.py b/leggend/api/routes/transactions.py index 701bf3b..3f91d2e 100644 --- a/leggend/api/routes/transactions.py +++ b/leggend/api/routes/transactions.py @@ -75,7 +75,8 @@ async def get_all_transactions( # Return simplified transaction summaries data = [ TransactionSummary( - internal_transaction_id=txn["internalTransactionId"], + transaction_id=txn["transactionId"], # NEW: stable bank-provided ID + internal_transaction_id=txn.get("internalTransactionId"), date=txn["transactionDate"], description=txn["description"], amount=txn["transactionValue"], @@ -89,7 +90,8 @@ async def get_all_transactions( # Return full transaction details data = [ Transaction( - internal_transaction_id=txn["internalTransactionId"], + transaction_id=txn["transactionId"], # NEW: stable bank-provided ID + internal_transaction_id=txn.get("internalTransactionId"), institution_id=txn["institutionId"], iban=txn["iban"], account_id=txn["accountId"], diff --git a/tests/unit/test_api_transactions.py b/tests/unit/test_api_transactions.py index bb99740..dc3cf61 100644 --- a/tests/unit/test_api_transactions.py +++ b/tests/unit/test_api_transactions.py @@ -15,6 +15,7 @@ class TestTransactionsAPI: """Test successful retrieval of all transactions from database.""" mock_transactions = [ { + "transactionId": "bank-txn-001", # NEW: stable bank-provided ID "internalTransactionId": "txn-001", "institutionId": "REVOLUT_REVOLT21", "iban": "LT313250081177977789", @@ -24,9 +25,10 @@ class TestTransactionsAPI: "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": "test-account-123", - "rawTransaction": {"some": "data"}, + "rawTransaction": {"transactionId": "bank-txn-001", "some": "data"}, }, { + "transactionId": "bank-txn-002", # NEW: stable bank-provided ID "internalTransactionId": "txn-002", "institutionId": "REVOLUT_REVOLT21", "iban": "LT313250081177977789", @@ -36,7 +38,7 @@ class TestTransactionsAPI: "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": "test-account-123", - "rawTransaction": {"other": "data"}, + "rawTransaction": {"transactionId": "bank-txn-002", "other": "data"}, }, ] @@ -73,6 +75,7 @@ class TestTransactionsAPI: """Test retrieval of full transaction details from database.""" mock_transactions = [ { + "transactionId": "bank-txn-001", # NEW: stable bank-provided ID "internalTransactionId": "txn-001", "institutionId": "REVOLUT_REVOLT21", "iban": "LT313250081177977789", @@ -82,7 +85,7 @@ class TestTransactionsAPI: "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": "test-account-123", - "rawTransaction": {"some": "raw_data"}, + "rawTransaction": {"transactionId": "bank-txn-001", "some": "raw_data"}, } ] @@ -105,6 +108,7 @@ class TestTransactionsAPI: assert len(data["data"]) == 1 transaction = data["data"][0] + assert transaction["transaction_id"] == "bank-txn-001" # NEW: check stable ID assert transaction["internal_transaction_id"] == "txn-001" assert transaction["institution_id"] == "REVOLUT_REVOLT21" assert transaction["iban"] == "LT313250081177977789" @@ -116,6 +120,7 @@ class TestTransactionsAPI: """Test getting transactions with various filters.""" mock_transactions = [ { + "transactionId": "bank-txn-001", # NEW: stable bank-provided ID "internalTransactionId": "txn-001", "institutionId": "REVOLUT_REVOLT21", "iban": "LT313250081177977789", @@ -125,7 +130,7 @@ class TestTransactionsAPI: "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": "test-account-123", - "rawTransaction": {"some": "data"}, + "rawTransaction": {"transactionId": "bank-txn-001", "some": "data"}, } ]