Added payments report
This commit is contained in:
parent
a17e8d9b8c
commit
3fe01a834b
|
@ -5,7 +5,7 @@ from functools import wraps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
import importlib
|
import importlib
|
||||||
|
@ -107,12 +107,16 @@ def admin_link(*args, **kwargs):
|
||||||
return '---'
|
return '---'
|
||||||
if not getattr(obj, 'pk', None):
|
if not getattr(obj, 'pk', None):
|
||||||
return '---'
|
return '---'
|
||||||
url = change_url(obj)
|
|
||||||
display = kwargs.get('display')
|
display = kwargs.get('display')
|
||||||
if display:
|
if display:
|
||||||
display = getattr(obj, display, 'merda')
|
display = getattr(obj, display, 'merda')
|
||||||
else:
|
else:
|
||||||
display = obj
|
display = obj
|
||||||
|
try:
|
||||||
|
url = change_url(obj)
|
||||||
|
except NoReverseMatch:
|
||||||
|
# Does not has admin
|
||||||
|
return str(display)
|
||||||
extra = ''
|
extra = ''
|
||||||
if kwargs['popup']:
|
if kwargs['popup']:
|
||||||
extra = 'onclick="return showAddAnotherPopup(this);"'
|
extra = 'onclick="return showAddAnotherPopup(this);"'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import io
|
||||||
import zipfile
|
import zipfile
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.admin import helpers
|
from django.contrib.admin import helpers
|
||||||
|
@ -22,17 +22,17 @@ from .helpers import validate_contact
|
||||||
|
|
||||||
def download_bills(modeladmin, request, queryset):
|
def download_bills(modeladmin, request, queryset):
|
||||||
if queryset.count() > 1:
|
if queryset.count() > 1:
|
||||||
stringio = StringIO()
|
bytesio = io.BytesIO()
|
||||||
archive = zipfile.ZipFile(stringio, 'w')
|
archive = zipfile.ZipFile(bytesio, 'w')
|
||||||
for bill in queryset:
|
for bill in queryset:
|
||||||
pdf = html_to_pdf(bill.html or bill.render())
|
pdf = bill.as_pdf()
|
||||||
archive.writestr('%s.pdf' % bill.number, pdf)
|
archive.writestr('%s.pdf' % bill.number, pdf)
|
||||||
archive.close()
|
archive.close()
|
||||||
response = HttpResponse(stringio.getvalue(), content_type='application/pdf')
|
response = HttpResponse(bytesio.getvalue(), content_type='application/pdf')
|
||||||
response['Content-Disposition'] = 'attachment; filename="orchestra-bills.zip"'
|
response['Content-Disposition'] = 'attachment; filename="orchestra-bills.zip"'
|
||||||
return response
|
return response
|
||||||
bill = queryset.get()
|
bill = queryset.get()
|
||||||
pdf = html_to_pdf(bill.html or bill.render(), pagination=bill.has_multiple_pages)
|
pdf = bill.as_pdf()
|
||||||
return HttpResponse(pdf, content_type='application/pdf')
|
return HttpResponse(pdf, content_type='application/pdf')
|
||||||
download_bills.verbose_name = _("Download")
|
download_bills.verbose_name = _("Download")
|
||||||
download_bills.url_name = 'download'
|
download_bills.url_name = 'download'
|
||||||
|
|
|
@ -136,7 +136,7 @@ class Bill(models.Model):
|
||||||
if not self.is_open:
|
if not self.is_open:
|
||||||
return self.total
|
return self.total
|
||||||
try:
|
try:
|
||||||
return self.computed_total
|
return round(self.computed_total, 2)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.computed_total = self.compute_total()
|
self.computed_total = self.compute_total()
|
||||||
return self.computed_total
|
return self.computed_total
|
||||||
|
@ -199,8 +199,7 @@ class Bill(models.Model):
|
||||||
return transaction
|
return transaction
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
html = self.html or self.render()
|
pdf = self.as_pdf()
|
||||||
pdf = html_to_pdf(html, pagination=self.has_multiple_pages)
|
|
||||||
self.account.send_email(
|
self.account.send_email(
|
||||||
template=settings.BILLS_EMAIL_NOTIFICATION_TEMPLATE,
|
template=settings.BILLS_EMAIL_NOTIFICATION_TEMPLATE,
|
||||||
context={
|
context={
|
||||||
|
@ -243,6 +242,10 @@ class Bill(models.Model):
|
||||||
html = html.replace('-pageskip-', '<pdf:nextpage />')
|
html = html.replace('-pageskip-', '<pdf:nextpage />')
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
def as_pdf(self):
|
||||||
|
html = self.html or self.render()
|
||||||
|
return html_to_pdf(html, pagination=self.has_multiple_pages)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.type:
|
if not self.type:
|
||||||
self.type = self.get_type()
|
self.type = self.get_type()
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Message(models.Model):
|
||||||
|
|
||||||
def sent(self):
|
def sent(self):
|
||||||
self.state = self.SENT
|
self.state = self.SENT
|
||||||
self.save(update_fiields=('state',))
|
self.save(update_fields=('state',))
|
||||||
|
|
||||||
def log(self, error):
|
def log(self, error):
|
||||||
result = SMTPLog.SUCCESS
|
result = SMTPLog.SUCCESS
|
||||||
|
|
|
@ -109,7 +109,7 @@ class BackendOperationInline(admin.TabularInline):
|
||||||
|
|
||||||
def instance_link(self, operation):
|
def instance_link(self, operation):
|
||||||
link = admin_link('instance')(self, operation)
|
link = admin_link('instance')(self, operation)
|
||||||
if not link.startswith('<a'):
|
if link == '---':
|
||||||
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
||||||
(escape(operation.content_type), escape(operation.object_id))))
|
(escape(operation.content_type), escape(operation.object_id))))
|
||||||
return link
|
return link
|
||||||
|
|
|
@ -182,3 +182,15 @@ def delete_selected(modeladmin, request, queryset):
|
||||||
helpers.post_delete_processes(modelamdin, request, related_transactions)
|
helpers.post_delete_processes(modelamdin, request, related_transactions)
|
||||||
return response
|
return response
|
||||||
delete_selected.short_description = actions.delete_selected.short_description
|
delete_selected.short_description = actions.delete_selected.short_description
|
||||||
|
|
||||||
|
|
||||||
|
def report(modeladmin, request, queryset):
|
||||||
|
if queryset.model == Transaction:
|
||||||
|
transactions = queryset
|
||||||
|
else:
|
||||||
|
transactions = queryset.values_list('transactions__id', flat=True).distinct()
|
||||||
|
transactions = Transaction.objects.filter(id__in=transactions)
|
||||||
|
context = {
|
||||||
|
'transactions': transactions
|
||||||
|
}
|
||||||
|
return render(request, 'admin/payments/transaction/report.html', context)
|
||||||
|
|
|
@ -87,11 +87,11 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
actions = (
|
change_view_actions = (
|
||||||
actions.process_transactions, actions.mark_as_executed,
|
actions.process_transactions, actions.mark_as_executed, actions.mark_as_secured,
|
||||||
actions.mark_as_secured, actions.mark_as_rejected
|
actions.mark_as_rejected,
|
||||||
)
|
)
|
||||||
change_view_actions = actions
|
actions = change_view_actions + (actions.report,)
|
||||||
filter_by_account_fields = ('bill', 'source')
|
filter_by_account_fields = ('bill', 'source')
|
||||||
change_readonly_fields = ('amount', 'currency')
|
change_readonly_fields = ('amount', 'currency')
|
||||||
readonly_fields = ('bill_link', 'display_state', 'process_link', 'account_link', 'source_link')
|
readonly_fields = ('bill_link', 'display_state', 'process_link', 'account_link', 'source_link')
|
||||||
|
@ -123,7 +123,9 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
fields = ('data', 'file_url', 'created_at')
|
fields = ('data', 'file_url', 'created_at')
|
||||||
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
|
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
|
||||||
inlines = [TransactionInline]
|
inlines = [TransactionInline]
|
||||||
change_view_actions = (actions.mark_process_as_executed, actions.abort, actions.commit)
|
change_view_actions = (
|
||||||
|
actions.mark_process_as_executed, actions.abort, actions.commit, actions.report
|
||||||
|
)
|
||||||
actions = change_view_actions + (actions.delete_selected,)
|
actions = change_view_actions + (actions.delete_selected,)
|
||||||
|
|
||||||
def file_url(self, process):
|
def file_url(self, process):
|
||||||
|
|
|
@ -131,22 +131,22 @@ class Transaction(models.Model):
|
||||||
def mark_as_processed(self):
|
def mark_as_processed(self):
|
||||||
self.check_state(self.WAITTING_PROCESSING)
|
self.check_state(self.WAITTING_PROCESSING)
|
||||||
self.state = self.WAITTING_EXECUTION
|
self.state = self.WAITTING_EXECUTION
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=['state', 'modified_at'])
|
||||||
|
|
||||||
def mark_as_executed(self):
|
def mark_as_executed(self):
|
||||||
self.check_state(self.WAITTING_EXECUTION)
|
self.check_state(self.WAITTING_EXECUTION)
|
||||||
self.state = self.EXECUTED
|
self.state = self.EXECUTED
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=['state', 'modified_at'])
|
||||||
|
|
||||||
def mark_as_secured(self):
|
def mark_as_secured(self):
|
||||||
self.check_state(self.EXECUTED)
|
self.check_state(self.EXECUTED)
|
||||||
self.state = self.SECURED
|
self.state = self.SECURED
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=['state', 'modified_at'])
|
||||||
|
|
||||||
def mark_as_rejected(self):
|
def mark_as_rejected(self):
|
||||||
self.check_state(self.EXECUTED)
|
self.check_state(self.EXECUTED)
|
||||||
self.state = self.REJECTED
|
self.state = self.REJECTED
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=['state', 'modified_at'])
|
||||||
|
|
||||||
|
|
||||||
class TransactionProcess(models.Model):
|
class TransactionProcess(models.Model):
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Transaction Report</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
|
<style type="text/css">
|
||||||
|
@page {
|
||||||
|
size: 11.69in 8.27in;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
font-family: sans;
|
||||||
|
font-size: 10px;
|
||||||
|
max-width: 10in;
|
||||||
|
}
|
||||||
|
table tr:nth-child(even) {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
table tr:nth-child(odd) {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
table th {
|
||||||
|
color: white;
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr id="transaction">
|
||||||
|
<th class="title column-id">ID</th>
|
||||||
|
<th class="title column-bill">{% trans "Bill" %}</th>
|
||||||
|
<th class="title column-billcontant">{% trans "Contact" %}</th>
|
||||||
|
<th class="title column-iban">IBAN</th>
|
||||||
|
<th class="title column-amount">{% trans "Amount" %}</th>
|
||||||
|
<th class="title column-state">{% trans "State" %}</th>
|
||||||
|
<th class="title column-created">{% trans "Created" %}</th>
|
||||||
|
<th class="title column-updated">{% trans "Updated" %}</th>
|
||||||
|
</tr>
|
||||||
|
{% for transaction in transactions %}
|
||||||
|
<tr>
|
||||||
|
<td class="item column-id">{{ transaction.id }}</td>
|
||||||
|
<td class="item column-bill">{{ transaction.bill.number }}</td>
|
||||||
|
<td class="item column-billcontant">{{ transaction.bill.buyer.get_name }}</td>
|
||||||
|
<td class="item column-iban">{{ transaction.source.data.iban }}</td>
|
||||||
|
<td class="item column-amount">{{ transaction.amount }}</td>
|
||||||
|
<td class="item column-state">{{ transaction.get_state_display }}</td>
|
||||||
|
<td class="item column-state">{{ transaction.created_at|date }}</td>
|
||||||
|
<td class="item column-state">{{ transaction.modified_at|date }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue