diff --git a/app/apps/export_app/resources/transactions.py b/app/apps/export_app/resources/transactions.py index daa02b9..dbcb0f1 100644 --- a/app/apps/export_app/resources/transactions.py +++ b/app/apps/export_app/resources/transactions.py @@ -1,8 +1,10 @@ from import_export import fields, resources -from import_export.widgets import ForeignKeyWidget from apps.accounts.models import Account -from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget +from apps.export_app.widgets.foreign_key import ( + AllObjectsForeignKeyWidget, + AutoCreateForeignKeyWidget, +) from apps.export_app.widgets.many_to_many import AutoCreateManyToManyWidget from apps.export_app.widgets.string import EmptyStringToNoneField from apps.transactions.models import ( @@ -20,7 +22,7 @@ class TransactionResource(resources.ModelResource): account = fields.Field( attribute="account", column_name="account", - widget=ForeignKeyWidget(Account, "name"), + widget=AllObjectsForeignKeyWidget(Account, "name"), ) category = fields.Field( @@ -86,7 +88,7 @@ class RecurringTransactionResource(resources.ModelResource): account = fields.Field( attribute="account", column_name="account", - widget=ForeignKeyWidget(Account, "name"), + widget=AllObjectsForeignKeyWidget(Account, "name"), ) category = fields.Field( @@ -119,12 +121,16 @@ class RecurringTransactionResource(resources.ModelResource): def get_queryset(self): return RecurringTransaction.all_objects.all() + def dehydrate_account_owner(self, obj): + """Export the account's owner ID for proper import matching.""" + return obj.account.owner_id if obj.account else None + class InstallmentPlanResource(resources.ModelResource): account = fields.Field( attribute="account", column_name="account", - widget=ForeignKeyWidget(Account, "name"), + widget=AllObjectsForeignKeyWidget(Account, "name"), ) category = fields.Field( @@ -156,3 +162,7 @@ class InstallmentPlanResource(resources.ModelResource): def get_queryset(self): return InstallmentPlan.all_objects.all() + + def dehydrate_account_owner(self, obj): + """Export the account's owner ID for proper import matching.""" + return obj.account.owner_id if obj.account else None diff --git a/app/apps/export_app/widgets/foreign_key.py b/app/apps/export_app/widgets/foreign_key.py index fd582ac..92463ca 100644 --- a/app/apps/export_app/widgets/foreign_key.py +++ b/app/apps/export_app/widgets/foreign_key.py @@ -1,6 +1,60 @@ from import_export.widgets import ForeignKeyWidget +class AllObjectsForeignKeyWidget(ForeignKeyWidget): + """ + ForeignKeyWidget that uses 'all_objects' manager for lookups, + bypassing user-filtered managers like SharedObjectManager. + Also filters by owner if available in the row data. + """ + + def get_queryset(self, value, row, *args, **kwargs): + # Use all_objects manager if available, otherwise fall back to default + if hasattr(self.model, "all_objects"): + qs = self.model.all_objects.all() + # Filter by owner if the row has an owner field and the model has owner + if row: + # Check for direct owner field first + owner_id = row.get("owner") if "owner" in row else None + # Fall back to account_owner for models like InstallmentPlan + if not owner_id and "account_owner" in row: + owner_id = row.get("account_owner") + # If still no owner, try to get it from the existing record's account + # This handles backward compatibility with older exports + if not owner_id and "id" in row and row.get("id"): + try: + # Try to find the existing record and get owner from its account + from apps.transactions.models import ( + InstallmentPlan, + RecurringTransaction, + ) + + record_id = row.get("id") + # Try to find the existing InstallmentPlan or RecurringTransaction + for model_class in [InstallmentPlan, RecurringTransaction]: + try: + existing = model_class.all_objects.get(id=record_id) + if existing.account: + owner_id = existing.account.owner_id + break + except model_class.DoesNotExist: + continue + except Exception: + pass + # Final fallback: use the current logged-in user + # This handles restoring to a fresh database with older exports + if not owner_id: + from apps.common.middleware.thread_local import get_current_user + + user = get_current_user() + if user and user.is_authenticated: + owner_id = user.id + if owner_id: + qs = qs.filter(owner_id=owner_id) + return qs + return super().get_queryset(value, row, *args, **kwargs) + + class AutoCreateForeignKeyWidget(ForeignKeyWidget): def clean(self, value, row=None, *args, **kwargs): if value: