Added pdf rendering support
This commit is contained in:
parent
ef7f3219a5
commit
b4113ef770
|
@ -28,9 +28,6 @@ class Command(BaseCommand):
|
|||
email = options.get('email')
|
||||
username = options.get('username')
|
||||
password = options.get('password')
|
||||
user = User.objects.create_superuser(username, email, password, account=account,
|
||||
is_main=True)
|
||||
account = Account.objects.create(user=user)
|
||||
user.account = account
|
||||
user.save()
|
||||
|
||||
account = Account.objects.create()
|
||||
user = User.objects.create_superuser(username, email, password,
|
||||
account=account, is_main=True)
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
from django.http import HttpResponse
|
||||
|
||||
from orchestra.utils.system import run
|
||||
|
||||
|
||||
def generate_bill(modeladmin, request, queryset):
|
||||
bill = queryset.get()
|
||||
bill.close()
|
||||
return HttpResponse(bill.html)
|
||||
pdf = run('xvfb-run -a -s "-screen 0 640x4800x16" wkhtmltopdf - -',
|
||||
stdin=bill.html.encode('utf-8'), display=False)
|
||||
return HttpResponse(pdf, content_type='application/pdf')
|
||||
|
|
|
@ -16,7 +16,7 @@ class BillManager(models.Manager):
|
|||
def get_queryset(self):
|
||||
queryset = super(BillManager, self).get_queryset()
|
||||
if self.model != Bill:
|
||||
bill_type = self.model.get_type()
|
||||
bill_type = self.model.get_class_type()
|
||||
queryset = queryset.filter(type=bill_type)
|
||||
return queryset
|
||||
|
||||
|
@ -127,7 +127,8 @@ class Bill(models.Model):
|
|||
},
|
||||
'currency': settings.BILLS_CURRENCY,
|
||||
})
|
||||
template = getattr(settings, 'BILLS_%s_TEMPLATE' % self.get_type())
|
||||
template = getattr(settings, 'BILLS_%s_TEMPLATE' % self.get_type(),
|
||||
settings.BILLS_DEFAULT_TEMPLATE)
|
||||
bill_template = loader.get_template(template)
|
||||
html = bill_template.render(context)
|
||||
html = html.replace('-pageskip-', '<pdf:nextpage />')
|
||||
|
|
|
@ -14,7 +14,11 @@ BILLS_AMENDMENT_FEE_NUMBER_PREFIX = getattr(settings, 'BILLS_AMENDMENT_FEE_NUMBE
|
|||
BILLS_BUDGET_NUMBER_PREFIX = getattr(settings, 'BILLS_BUDGET_NUMBER_PREFIX', 'Q')
|
||||
|
||||
|
||||
BILLS_INVOICE_TEMPLATE = getattr(settings, 'BILLS_INVOICE_TEMPLATE', 'bills/microspective.html')
|
||||
BILLS_DEFAULT_TEMPLATE = getattr(settings, 'BILLS_DEFAULT_TEMPLATE', 'bills/microspective.html')
|
||||
|
||||
BILLS_FEE_TEMPLATE = getattr(settings, 'BILLS_FEE_TEMPLATE', 'bills/microspective-fee.html')
|
||||
|
||||
|
||||
|
||||
|
||||
BILLS_CURRENCY = getattr(settings, 'BILLS_CURRENCY', 'euro')
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
float: right;
|
||||
padding: 15px;
|
||||
margin: 10px;
|
||||
margin-top: 0px;
|
||||
width: 44%;
|
||||
font-size: large;
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ hr {
|
|||
{% endblock %}
|
||||
|
||||
{% block summary %}
|
||||
<div style="position: relative; margin-top: 150px;">
|
||||
<div style="position: relative; margin-top: 140px;">
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
|
@ -121,5 +122,8 @@ from Apr 1, 2010 to Apr 1, 2011
|
|||
Con vuestras cuotas, ademas de obtener <br>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block pagination %}<hr>{% endblock %}
|
||||
{% block footer %}
|
||||
<hr>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
body {
|
||||
max-width: 650px;
|
||||
/* max-width: 650px;*/
|
||||
max-width: 800px;
|
||||
margin: 40 auto !important;
|
||||
float: none !important;
|
||||
font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif;
|
||||
|
@ -48,14 +49,20 @@ a:hover {
|
|||
}
|
||||
|
||||
/* SUMMARY */
|
||||
#bill-summary {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
#bill-summary > * {
|
||||
float: right;
|
||||
border: 1px solid grey;
|
||||
padding: 7px;
|
||||
padding: 7px 12px 7px 12px;
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
width: 100px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
#bill-summary hr {
|
||||
|
@ -161,12 +168,12 @@ a:hover {
|
|||
}
|
||||
|
||||
#lines .column-description {
|
||||
width: 55%;
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#lines .column-quantity {
|
||||
width: 20%;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#lines .column-rate {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
{% block header %}
|
||||
<div id="logo">
|
||||
{% block logo %}
|
||||
<div style="border-bottom:5px solid grey; color:grey; font-size:30;">
|
||||
<div style="border-bottom:5px solid grey; color:grey; font-size:30; margin-right: 20px;">
|
||||
YOUR<br>
|
||||
LOGO<br>
|
||||
HERE<br>
|
||||
|
@ -76,8 +76,8 @@
|
|||
{% for line in bill.lines.all %}
|
||||
<span class="value column-id">{{ line.id }}</span>
|
||||
<span class="value column-description">{{ line.description }}</span>
|
||||
<span class="value column-quantity">{{ line.amount }}</span>
|
||||
<span class="value column-rate">{{ line.rate }}</span>
|
||||
<span class="value column-quantity">{{ line.amount|default:" " }}</span>
|
||||
<span class="value column-rate">{% if line.rate %}{{ line.rate }} &{{ currency.lower }};{% else %} {% endif %}</span>
|
||||
<span class="value column-subtotal">{{ line.price }} &{{ currency.lower }};</span>
|
||||
<br>
|
||||
{% endfor %}
|
||||
|
|
|
@ -70,7 +70,8 @@ class MailboxAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
add_url += '?account=%d&mailboxes=%s' % (account.pk, mailbox.pk)
|
||||
img = '<img src="/static/admin/img/icon_addlink.gif" width="10" height="10" alt="Add Another">'
|
||||
onclick = 'onclick="return showAddAnotherPopup(this);"'
|
||||
add_link = '<a href="%s" %s>%s Add address</a>' % (add_url, onclick, img)
|
||||
add_link = '<a href="{add_url}" {onclick}>{img} Add address</a>'.format(
|
||||
add_url=add_url, onclick=onclick, img=img)
|
||||
value = '%s<br><br>' % add_link
|
||||
for pk, name, domain in mailbox.addresses.values_list('pk', 'name', 'domain__name'):
|
||||
url = reverse('admin:mails_address_change', args=(pk,))
|
||||
|
|
|
@ -282,6 +282,9 @@ class Order(models.Model):
|
|||
if service.handler.matches(instance):
|
||||
if not orders:
|
||||
account_id = getattr(instance, 'account_id', instance.pk)
|
||||
if account_id is None:
|
||||
# New account workaround -> user.account_id == None
|
||||
continue
|
||||
order = cls.objects.create(content_object=instance,
|
||||
service=service, account_id=account_id)
|
||||
else:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from .methods import BankTransfer
|
||||
|
||||
def process_transactions(modeladmin, request, queryset):
|
||||
BankTransfer().process(queryset)
|
||||
from .methods import SEPADirectDebit
|
||||
SEPADirectDebit().process(queryset)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from orchestra.admin.utils import admin_colored, admin_link
|
|||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
|
||||
from .actions import process_transactions
|
||||
from .methods import BankTransfer
|
||||
from .methods import SEPADirectDebit
|
||||
from .models import PaymentSource, Transaction, PaymentProcess
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ class TransactionAdmin(admin.ModelAdmin):
|
|||
class PaymentSourceAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('label', 'method', 'number', 'account_link', 'is_active')
|
||||
list_filter = ('method', 'is_active')
|
||||
form = BankTransfer().get_form()
|
||||
form = SEPADirectDebit().get_form()
|
||||
# TODO select payment source method
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
from .creditcard import CreditCard
|
||||
from .banktransfer import BankTransfer
|
||||
from .sepadirectdebit import SEPADirectDebit
|
||||
from .options import PaymentMethod, PaymentSourceDataForm
|
||||
|
|
|
@ -15,26 +15,26 @@ from .. import settings
|
|||
from .options import PaymentSourceDataForm, PaymentMethod
|
||||
|
||||
|
||||
class BankTransferForm(PaymentSourceDataForm):
|
||||
class SEPADirectDebitForm(PaymentSourceDataForm):
|
||||
iban = IBANFormField(label='IBAN',
|
||||
widget=forms.TextInput(attrs={'size': '50'}))
|
||||
name = forms.CharField(max_length=128, label=_("Name"),
|
||||
widget=forms.TextInput(attrs={'size': '50'}))
|
||||
|
||||
|
||||
class BankTransferSerializer(serializers.Serializer):
|
||||
class SEPADirectDebitSerializer(serializers.Serializer):
|
||||
iban = serializers.CharField(label='IBAN', validators=[IBANValidator()],
|
||||
min_length=min(IBAN_COUNTRY_CODE_LENGTH.values()), max_length=34)
|
||||
name = serializers.CharField(label=_("Name"), max_length=128)
|
||||
|
||||
|
||||
class BankTransfer(PaymentMethod):
|
||||
verbose_name = _("Bank transfer")
|
||||
class SEPADirectDebit(PaymentMethod):
|
||||
verbose_name = _("Direct Debit")
|
||||
label_field = 'name'
|
||||
number_field = 'iban'
|
||||
process_credit = True
|
||||
form = BankTransferForm
|
||||
serializer = BankTransferSerializer
|
||||
form = SEPADirectDebitForm
|
||||
serializer = SEPADirectDebitSerializer
|
||||
|
||||
def process(self, transactions):
|
||||
debts = []
|
|
@ -72,7 +72,7 @@ class Transaction(models.Model):
|
|||
return "Transaction {}".format(self.id)
|
||||
|
||||
|
||||
# TODO rename to TransactionProcess
|
||||
# TODO rename to TransactionProcess or PaymentRequest TransactionRequest
|
||||
class PaymentProcess(models.Model):
|
||||
"""
|
||||
Stores arbitrary data generated by payment methods while processing transactions
|
||||
|
|
|
@ -127,7 +127,9 @@ function install_requirements () {
|
|||
bind9utils \
|
||||
python-cracklib \
|
||||
libxml2-dev \
|
||||
libxslt1-dev"
|
||||
libxslt1-dev \
|
||||
wkhtmltopdf \
|
||||
xvfb"
|
||||
|
||||
PIP="django==1.6.1 \
|
||||
django-celery-email==1.0.4 \
|
||||
|
@ -151,8 +153,7 @@ function install_requirements () {
|
|||
|
||||
if $testing; then
|
||||
APT="${APT} \
|
||||
iceweasel \
|
||||
xvfb"
|
||||
iceweasel"
|
||||
PIP="${PIP} \
|
||||
selenium \
|
||||
xvfbwrapper"
|
||||
|
|
|
@ -46,21 +46,20 @@ def read_async(fd):
|
|||
return ''
|
||||
|
||||
|
||||
def run(command, display=True, error_codes=[0], silent=True):
|
||||
def run(command, display=True, error_codes=[0], silent=True, stdin=''):
|
||||
""" Subprocess wrapper for running commands """
|
||||
if display:
|
||||
sys.stderr.write("\n\033[1m $ %s\033[0m\n" % command)
|
||||
out_stream = subprocess.PIPE
|
||||
err_stream = subprocess.PIPE
|
||||
|
||||
p = subprocess.Popen(command, shell=True, executable='/bin/bash',
|
||||
stdout=out_stream, stderr=err_stream)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
make_async(p.stdout)
|
||||
make_async(p.stderr)
|
||||
|
||||
stdout = str()
|
||||
stderr = str()
|
||||
|
||||
p.stdin.write(stdin)
|
||||
p.stdin.close()
|
||||
# Async reading of stdout and sterr
|
||||
while True:
|
||||
# Wait for data to become available
|
||||
|
|
Loading…
Reference in New Issue