Added support for reissue rejected transactions

This commit is contained in:
Marc Aymerich 2016-05-09 12:02:10 +00:00
parent fdd84b7e74
commit e804a1d102
6 changed files with 62 additions and 15 deletions

View File

@ -122,7 +122,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
return views return views
def get_actions(self, request): def get_actions(self, request):
actions = super(AccountAdmin, self).get_actions(request) actions = super().get_actions(request)
if 'delete_selected' in actions: if 'delete_selected' in actions:
del actions['delete_selected'] del actions['delete_selected']
return actions return actions

View File

@ -0,0 +1,9 @@
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
def last(modeladmin, request, queryset):
last_id = queryset.order_by('id').values_list('id', flat=True).first()
url = reverse('admin:mailer_message_change', args=(last_id,))
print(url)
return redirect(url)

View File

@ -8,9 +8,11 @@ from django.db.models import Count
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.admin import ExtendedModelAdmin
from orchestra.admin.utils import admin_link, admin_colored, admin_date, wrap_admin_view from orchestra.admin.utils import admin_link, admin_colored, admin_date, wrap_admin_view
from orchestra.contrib.tasks import task from orchestra.contrib.tasks import task
from .actions import last
from .engine import send_pending from .engine import send_pending
from .models import Message, SMTPLog from .models import Message, SMTPLog
@ -25,13 +27,13 @@ COLORS = {
} }
class MessageAdmin(admin.ModelAdmin): class MessageAdmin(ExtendedModelAdmin):
list_display = ( list_display = (
'display_subject', 'colored_state', 'priority', 'to_address', 'from_address', 'display_subject', 'colored_state', 'priority', 'to_address', 'from_address',
'created_at_delta', 'display_retries', 'last_try_delta', 'created_at_delta', 'display_retries', 'last_try_delta',
) )
list_filter = ('state', 'priority', 'retries') list_filter = ('state', 'priority', 'retries')
list_prefetch_related = ('logs__id') list_prefetch_related = ('logs',)
search_fields = ('to_address', 'from_address', 'subject',) search_fields = ('to_address', 'from_address', 'subject',)
fieldsets = ( fieldsets = (
(None, { (None, {
@ -49,6 +51,7 @@ class MessageAdmin(admin.ModelAdmin):
'display_to', 'display_from', 'display_content', 'display_to', 'display_from', 'display_content',
) )
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
change_view_actions = (last,)
colored_state = admin_colored('state', colors=COLORS) colored_state = admin_colored('state', colors=COLORS)
created_at_delta = admin_date('created_at') created_at_delta = admin_date('created_at')
@ -114,7 +117,7 @@ class MessageAdmin(admin.ModelAdmin):
def get_urls(self): def get_urls(self):
from django.conf.urls import url from django.conf.urls import url
urls = super(MessageAdmin, self).get_urls() urls = super().get_urls()
info = self.model._meta.app_label, self.model._meta.model_name info = self.model._meta.app_label, self.model._meta.model_name
urls.insert(0, urls.insert(0,
url(r'^send-pending/$', url(r'^send-pending/$',
@ -124,8 +127,8 @@ class MessageAdmin(admin.ModelAdmin):
return urls return urls
def get_queryset(self, request): def get_queryset(self, request):
qs = super(MessageAdmin, self).get_queryset(request) qs = super().get_queryset(request)
return qs.annotate(Count('logs')).prefetch_related('logs').defer('content') return qs.annotate(Count('logs')).defer('content')
def send_pending_view(self, request): def send_pending_view(self, request):
task(send_pending).apply_async() task(send_pending).apply_async()
@ -135,7 +138,7 @@ class MessageAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'subject': if db_field.name == 'subject':
kwargs['widget'] = forms.TextInput(attrs={'size':'100'}) kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
return super(MessageAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super().formfield_for_dbfield(db_field, **kwargs)
class SMTPLogAdmin(admin.ModelAdmin): class SMTPLogAdmin(admin.ModelAdmin):

View File

@ -2,8 +2,9 @@ from functools import partial
from django.contrib import messages from django.contrib import messages
from django.contrib.admin import actions from django.contrib.admin import actions
from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import render from django.shortcuts import render, redirect
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _
@ -205,3 +206,19 @@ def report(modeladmin, request, queryset):
'transactions': transactions, 'transactions': transactions,
} }
return render(request, 'admin/payments/transaction/report.html', context) return render(request, 'admin/payments/transaction/report.html', context)
def reissue(modeladmin, request, queryset):
if len(queryset) != 1:
messages.error(request, _("One transaction should be selected."))
return
trans = queryset[0]
url = reverse('admin:payments_transaction_add')
url += '?account=%i&bill=%i&source=%s&amount=%s&currency=%s' % (
trans.bill.account_id,
trans.bill_id,
trans.source_id or '',
trans.amount,
trans.currency,
)
return redirect(url)

View File

@ -105,9 +105,10 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
) )
change_view_actions = ( change_view_actions = (
actions.process_transactions, actions.mark_as_executed, actions.mark_as_secured, actions.process_transactions, actions.mark_as_executed, actions.mark_as_secured,
actions.mark_as_rejected, actions.mark_as_rejected, actions.reissue
) )
actions = change_view_actions + (actions.report, list_accounts) search_fields = ('bill__number', 'bill__account__username', 'id')
actions = change_view_actions + (actions.report, list_accounts,)
filter_by_account_fields = ('bill', 'source') filter_by_account_fields = ('bill', 'source')
change_readonly_fields = ('amount', 'currency') change_readonly_fields = ('amount', 'currency')
readonly_fields = ( readonly_fields = (
@ -124,17 +125,28 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
display_created_at = admin_date('created_at', short_description=_("Created")) display_created_at = admin_date('created_at', short_description=_("Created"))
display_modified_at = admin_date('modified_at', short_description=_("Modified")) display_modified_at = admin_date('modified_at', short_description=_("Modified"))
def has_delete_permission(self, *args, **kwargs):
return False
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def get_change_view_actions(self, obj=None): def get_change_view_actions(self, obj=None):
actions = super(TransactionAdmin, self).get_change_view_actions() actions = super(TransactionAdmin, self).get_change_view_actions()
exclude = [] exclude = []
if obj: if obj:
if obj.state == Transaction.WAITTING_PROCESSING: if obj.state == Transaction.WAITTING_PROCESSING:
exclude = ['mark_as_executed', 'mark_as_secured'] exclude = ['mark_as_executed', 'mark_as_secured', 'reissue']
elif obj.state == Transaction.WAITTING_EXECUTION: elif obj.state == Transaction.WAITTING_EXECUTION:
exclude = ['process_transactions', 'mark_as_secured'] exclude = ['process_transactions', 'mark_as_secured', 'reissue']
if obj.state == Transaction.EXECUTED: if obj.state == Transaction.EXECUTED:
exclude = ['process_transactions', 'mark_as_executed'] exclude = ['process_transactions', 'mark_as_executed', 'reissue']
elif obj.state in [Transaction.REJECTED, Transaction.SECURED]: elif obj.state == Transaction.REJECTED:
exclude = ['process_transactions', 'mark_as_executed', 'mark_as_secured', 'mark_as_rejected']
elif obj.state == Transaction.SECURED:
return [] return []
return [action for action in actions if action.__name__ not in exclude] return [action for action in actions if action.__name__ not in exclude]
@ -154,6 +166,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
) )
list_filter = ('state',) list_filter = ('state',)
fields = ('data', 'file_url', 'created_at') fields = ('data', 'file_url', 'created_at')
search_fields = ('transactions__bill__number', 'transactions__bill__account__username', 'id')
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at') readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
list_prefetch_related = ('transactions',) list_prefetch_related = ('transactions',)
inlines = [TransactionInline] inlines = [TransactionInline]

View File

@ -135,7 +135,12 @@ class Transaction(models.Model):
if not self.pk: if not self.pk:
amount = self.bill.transactions.exclude(state=self.REJECTED).amount() amount = self.bill.transactions.exclude(state=self.REJECTED).amount()
if amount >= self.bill.total: if amount >= self.bill.total:
raise ValidationError(_("New transactions can not be allocated for this bill.")) raise ValidationError(
_("Bill %(number)s already has valid transactions that cover bill total amount (%(amount)s).") % {
'number': self.bill.number,
'amount': amount,
}
)
def get_state_help(self): def get_state_help(self):
if self.source: if self.source: