@@ -23,6 +23,38 @@ class TransactionAdmin(admin.ModelAdmin):
2323 date_hierarchy = "posted_at"
2424 autocomplete_fields = ("account" ,)
2525 readonly_fields = ("reference" ,)
26+ # Stock Django admin actions (`@admin.action`). They surface on the
27+ # changelist (multi-pk runs) AND the SPA's detail page header
28+ # (single-pk runs) — no `django-object-actions` mixin, no
29+ # `change_actions = [...]` redeclaration. One source of truth for
30+ # everything the consumer wants to expose as an action.
31+ actions = ("mark_reconciled" , "recompute_reference" )
32+
33+ @admin .action (description = "Mark as reconciled" )
34+ def mark_reconciled (self , request , queryset ):
35+ """Tag every row in the queryset as reconciled.
36+
37+ Demo no-op: the model has no `reconciled` flag yet — this
38+ exists so the SPA's detail page has a stock-Django-admin
39+ action to render. A real ModelAdmin would update the row
40+ and message the user.
41+ """
42+ count = queryset .count ()
43+ self .message_user (request , f"Marked { count } transaction(s) as reconciled." )
44+
45+ @admin .action (description = "Recompute reference" )
46+ def recompute_reference (self , request , queryset ):
47+ """Roll the ``reference`` field on each row in the queryset.
48+
49+ Demo: bumps ``reference`` to ``TXN-RECOMP-<stamp>-<i>`` so the
50+ operator can see the action ran end-to-end on the SPA.
51+ """
52+ from datetime import datetime , timezone as tz
53+ stamp = datetime .now (tz .utc ).strftime ("%Y%m%d%H%M%S" )
54+ for i , row in enumerate (queryset ):
55+ row .reference = f"TXN-RECOMP-{ stamp } -{ i :02d} "
56+ row .save (update_fields = ["reference" ])
57+ self .message_user (request , f"Recomputed reference on { queryset .count ()} row(s)." )
2658
2759
2860@admin .register (Statement )
0 commit comments