diff --git a/views_api.py b/views_api.py index 25d49db..4611b60 100644 --- a/views_api.py +++ b/views_api.py @@ -315,38 +315,131 @@ async def api_get_user_entries( # Regular user can only see their own entries target_user_id = wallet.wallet.user - # Query Fava for transactions - if target_user_id: - # Build account pattern based on account_type filter - if filter_account_type: - # Filter by account type (asset = receivable, liability = payable) - if filter_account_type.lower() == "asset": - account_pattern = f"Receivable:User-{target_user_id[:8]}" - elif filter_account_type.lower() == "liability": - account_pattern = f"Payable:User-{target_user_id[:8]}" - else: - account_pattern = f"User-{target_user_id[:8]}" + # Get all journal entries from Fava (full transaction objects) + all_entries = await fava.get_journal_entries() + + # Filter and transform entries + filtered_entries = [] + for e in all_entries: + if e.get("t") != "Transaction": + continue + + # Skip voided transactions + if "voided" in e.get("tags", []): + continue + + # Extract user ID from metadata or account names + user_id_match = None + entry_meta = e.get("meta", {}) + if "user-id" in entry_meta: + user_id_match = entry_meta["user-id"] else: - # All user accounts - account_pattern = f"User-{target_user_id[:8]}" + # Try to extract from account names in postings + for posting in e.get("postings", []): + account = posting.get("account", "") + if "User-" in account: + # Extract user ID from account name (e.g., "Liabilities:Payable:User-abc123") + parts = account.split("User-") + if len(parts) > 1: + user_id_match = parts[1] # Just the short ID after User- + break - entries = await fava.query_transactions( - account_pattern=account_pattern, - limit=limit + offset # Fava doesn't support offset, so fetch more and slice - ) - # Apply offset - entries = entries[offset:offset + limit] - total = len(entries) # Note: This is approximate since we don't know the true total - else: - # Super user viewing all entries - entries = await fava.query_transactions(limit=limit + offset) - entries = entries[offset:offset + limit] - total = len(entries) + # Filter by target user if specified + if target_user_id and user_id_match: + if not user_id_match.startswith(target_user_id[:8]): + continue + + # Filter by account type if specified + if filter_account_type and user_id_match: + postings = e.get("postings", []) + has_matching_account = False + for posting in postings: + account = posting.get("account", "") + if filter_account_type.lower() == "asset" and "Receivable" in account: + has_matching_account = True + break + elif filter_account_type.lower() == "liability" and "Payable" in account: + has_matching_account = True + break + if not has_matching_account: + continue + + # Extract data for frontend + # Extract entry ID from links + entry_id = None + links = e.get("links", []) + if isinstance(links, (list, set)): + for link in links: + if isinstance(link, str): + link_clean = link.lstrip('^') + if "castle-" in link_clean: + parts = link_clean.split("castle-") + if len(parts) > 1: + entry_id = parts[-1] + break + + # Extract amount from postings + amount_sats = 0 + fiat_amount = None + fiat_currency = None + + postings = e.get("postings", []) + if postings: + first_posting = postings[0] + if isinstance(first_posting, dict): + amount_field = first_posting.get("amount") + if isinstance(amount_field, dict): + amount_sats = abs(int(float(amount_field.get("number", 0)))) + + cost = first_posting.get("cost") + if isinstance(cost, dict): + fiat_amount = float(cost.get("number", 0)) + fiat_currency = cost.get("currency") + + # Extract reference from links (first non-castle link) + reference = None + if isinstance(links, (list, set)): + for link in links: + if isinstance(link, str): + link_clean = link.lstrip('^') + if not link_clean.startswith("castle-") and not link_clean.startswith("ln-"): + reference = link_clean + break + + # Get username from user ID (first 8 chars for display) + username = f"User-{user_id_match[:8]}" if user_id_match else None + + entry_data = { + "id": entry_id or e.get("entry_hash", "unknown"), + "date": e.get("date", ""), + "entry_date": e.get("date", ""), + "flag": e.get("flag"), + "description": e.get("narration", ""), + "payee": e.get("payee"), + "tags": e.get("tags", []), + "links": links, + "amount": amount_sats, + "user_id": user_id_match, + "username": username, + "reference": reference, + "meta": entry_meta, # Include metadata for frontend + } + + if fiat_amount and fiat_currency: + entry_data["fiat_amount"] = fiat_amount + entry_data["fiat_currency"] = fiat_currency + + filtered_entries.append(entry_data) + + # Sort by date descending + filtered_entries.sort(key=lambda x: x.get("date", ""), reverse=True) + + # Apply pagination + total = len(filtered_entries) + paginated_entries = filtered_entries[offset:offset + limit] - # Fava transactions already contain the data we need - # Metadata includes user-id, account information, etc. return { - "entries": entries, + "entries": paginated_entries, "total": total, "limit": limit, "offset": offset,