Fixes on bills and implemented domains serializer create() and update()
This commit is contained in:
parent
fd8d805b5e
commit
1223ed85e6
3
TODO.md
3
TODO.md
|
@ -412,5 +412,4 @@ touch /tmp/somefile
|
||||||
# batch zone edditing
|
# batch zone edditing
|
||||||
# inherit registers from parent?
|
# inherit registers from parent?
|
||||||
|
|
||||||
# Bill metric disk 5 GB: unialber: include not include 5, unialbert recheck period
|
# Disable pagination on membership fees (allways one page)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ def download_bills(modeladmin, request, queryset):
|
||||||
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())
|
pdf = html_to_pdf(bill.html or bill.render(), pagination=bill.has_multiple_pages)
|
||||||
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'
|
||||||
|
@ -78,9 +78,13 @@ def close_bills(modeladmin, request, queryset):
|
||||||
else:
|
else:
|
||||||
url = reverse('admin:transactions_transaction_changelist')
|
url = reverse('admin:transactions_transaction_changelist')
|
||||||
url += 'id__in=%s' % ','.join(map(str, transactions))
|
url += 'id__in=%s' % ','.join(map(str, transactions))
|
||||||
|
context = {
|
||||||
|
'url': url,
|
||||||
|
'num': num,
|
||||||
|
}
|
||||||
message = ungettext(
|
message = ungettext(
|
||||||
_('<a href="%s">One related transaction</a> has been created') % url,
|
_('<a href="%(url)s">One related transaction</a> has been created') % context,
|
||||||
_('<a href="%s">%i related transactions</a> have been created') % (url, num),
|
_('<a href="%(url)s">%(num)i related transactions</a> have been created') % context,
|
||||||
num)
|
num)
|
||||||
messages.success(request, mark_safe(message))
|
messages.success(request, mark_safe(message))
|
||||||
return
|
return
|
||||||
|
@ -105,12 +109,22 @@ close_bills.url_name = 'close'
|
||||||
|
|
||||||
|
|
||||||
def send_bills(modeladmin, request, queryset):
|
def send_bills(modeladmin, request, queryset):
|
||||||
|
num = 0
|
||||||
for bill in queryset:
|
for bill in queryset:
|
||||||
if not validate_contact(request, bill):
|
if not validate_contact(request, bill):
|
||||||
return
|
return
|
||||||
for bill in queryset:
|
num += 1
|
||||||
|
if num == 1:
|
||||||
bill.send()
|
bill.send()
|
||||||
|
else:
|
||||||
|
# Batch email
|
||||||
|
queryset.send()
|
||||||
|
for bill in queryset:
|
||||||
modeladmin.log_change(request, bill, 'Sent')
|
modeladmin.log_change(request, bill, 'Sent')
|
||||||
|
messages.success(request, ungetetx(
|
||||||
|
_("One bill has been sent."),
|
||||||
|
_("%i bills have been sent.") % num,
|
||||||
|
num))
|
||||||
send_bills.verbose_name = lambda bill: _("Resend" if getattr(bill, 'is_sent', False) else "Send")
|
send_bills.verbose_name = lambda bill: _("Resend" if getattr(bill, 'is_sent', False) else "Send")
|
||||||
send_bills.url_name = 'send'
|
send_bills.url_name = 'send'
|
||||||
|
|
||||||
|
@ -153,7 +167,7 @@ def undo_billing(modeladmin, request, queryset):
|
||||||
else:
|
else:
|
||||||
# First iteration
|
# First iteration
|
||||||
if order.billed_on < line.start_on:
|
if order.billed_on < line.start_on:
|
||||||
messages.error(request, "billed on is smaller than first line start_on.")
|
messages.error(request, "Billed on is smaller than first line start_on.")
|
||||||
return
|
return
|
||||||
prev = line.end_on
|
prev = line.end_on
|
||||||
nlines += 1
|
nlines += 1
|
||||||
|
@ -168,6 +182,7 @@ def undo_billing(modeladmin, request, queryset):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
nlines += 1
|
nlines += 1
|
||||||
line.delete()
|
line.delete()
|
||||||
|
# TODO update order history undo billing
|
||||||
order.save(update_fields=('billed_until', 'billed_on'))
|
order.save(update_fields=('billed_until', 'billed_on'))
|
||||||
norders += 1
|
norders += 1
|
||||||
|
|
||||||
|
@ -177,29 +192,14 @@ def undo_billing(modeladmin, request, queryset):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# TODO son't check for account equality
|
def move_lines(modeladmin, request, queryset, action=None):
|
||||||
def move_lines(modeladmin, request, queryset):
|
|
||||||
# Validate
|
# Validate
|
||||||
account = None
|
|
||||||
for line in queryset.select_related('bill'):
|
|
||||||
bill = line.bill
|
|
||||||
if not bill.is_open:
|
|
||||||
messages.error(request, _("Can not move lines from a closed bill."))
|
|
||||||
return
|
|
||||||
elif not account:
|
|
||||||
account = bill.account
|
|
||||||
elif bill.account != account:
|
|
||||||
messages.error(request, _("Can not move lines from different accounts"))
|
|
||||||
return
|
|
||||||
target = request.GET.get('target')
|
target = request.GET.get('target')
|
||||||
if not target:
|
if not target:
|
||||||
# select target
|
# select target
|
||||||
context = {}
|
context = {}
|
||||||
return render(request, 'admin/orchestra/generic_confirmation.html', context)
|
return render(request, 'admin/orchestra/generic_confirmation.html', context)
|
||||||
target = Bill.objects.get(pk=int(pk))
|
target = Bill.objects.get(pk=int(pk))
|
||||||
if target.account != account:
|
|
||||||
messages.error(request, _("Target account different than lines account."))
|
|
||||||
return
|
|
||||||
if request.POST.get('post') == 'generic_confirmation':
|
if request.POST.get('post') == 'generic_confirmation':
|
||||||
for line in queryset:
|
for line in queryset:
|
||||||
line.bill = target
|
line.bill = target
|
||||||
|
@ -212,9 +212,4 @@ def move_lines(modeladmin, request, queryset):
|
||||||
|
|
||||||
def copy_lines(modeladmin, request, queryset):
|
def copy_lines(modeladmin, request, queryset):
|
||||||
# same as move, but changing action behaviour
|
# same as move, but changing action behaviour
|
||||||
pass
|
return move_lines(modeladmin, request, queryset)
|
||||||
|
|
||||||
|
|
||||||
def delete_lines(modeladmin, request, queryset):
|
|
||||||
# Call contrib.admin delete action if all lines in open bill
|
|
||||||
pass
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import admin
|
from django.contrib import admin, messages
|
||||||
from django.contrib.admin.utils import unquote
|
from django.contrib.admin.utils import unquote
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -9,6 +9,7 @@ from django.db.models.functions import Coalesce
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import admin_date, insertattr, admin_link
|
from orchestra.admin.utils import admin_date, insertattr, admin_link
|
||||||
|
@ -101,16 +102,22 @@ class ClosedBillLineInline(BillLineInline):
|
||||||
|
|
||||||
class BillLineAdmin(admin.ModelAdmin):
|
class BillLineAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'description', 'bill_link', 'rate', 'quantity', 'tax', 'subtotal', 'display_sublinetotal',
|
'description', 'bill_link', 'display_is_open', 'account_link', 'rate', 'quantity', 'tax',
|
||||||
'display_total'
|
'subtotal', 'display_sublinetotal', 'display_total'
|
||||||
)
|
)
|
||||||
actions = (actions.undo_billing, actions.move_lines, actions.copy_lines,)
|
actions = (actions.undo_billing, actions.move_lines, actions.copy_lines,)
|
||||||
list_filter = ('tax', ('bill', admin.RelatedOnlyFieldListFilter))
|
list_filter = ('tax', ('bill', admin.RelatedOnlyFieldListFilter), 'bill__is_open')
|
||||||
list_select_related = ('bill',)
|
list_select_related = ('bill',)
|
||||||
search_fields = ('description', 'bill__number')
|
search_fields = ('description', 'bill__number')
|
||||||
|
|
||||||
|
account_link = admin_link('bill__account')
|
||||||
bill_link = admin_link('bill')
|
bill_link = admin_link('bill')
|
||||||
|
|
||||||
|
def display_is_open(self, instance):
|
||||||
|
return instance.bill.is_open
|
||||||
|
display_is_open.short_description = _("Is open")
|
||||||
|
display_is_open.boolean = True
|
||||||
|
|
||||||
def display_sublinetotal(self, instance):
|
def display_sublinetotal(self, instance):
|
||||||
return instance.subline_total or ''
|
return instance.subline_total or ''
|
||||||
display_sublinetotal.short_description = _("Subline")
|
display_sublinetotal.short_description = _("Subline")
|
||||||
|
@ -140,18 +147,26 @@ class BillLineManagerAdmin(BillLineAdmin):
|
||||||
return qset
|
return qset
|
||||||
|
|
||||||
def changelist_view(self, request, extra_context=None):
|
def changelist_view(self, request, extra_context=None):
|
||||||
GET = request.GET.copy()
|
GET_copy = request.GET.copy()
|
||||||
bill_ids = GET.pop('ids', None)
|
bill_ids = GET_copy.pop('ids', None)
|
||||||
if bill_ids:
|
if bill_ids:
|
||||||
request.GET = GET
|
bill_ids = bill_ids[0]
|
||||||
bill_ids = list(map(int, bill_ids))
|
request.GET = GET_copy
|
||||||
|
bill_ids = list(map(int, bill_ids.split(',')))
|
||||||
|
else:
|
||||||
|
messages.error(request, _("No bills selected."))
|
||||||
|
return redirect('..')
|
||||||
self.bill_ids = bill_ids
|
self.bill_ids = bill_ids
|
||||||
if bill_ids and len(bill_ids) == 1:
|
if len(bill_ids) == 1:
|
||||||
bill_url = reverse('admin:bills_bill_change', args=(bill_ids[0],))
|
bill_url = reverse('admin:bills_bill_change', args=(bill_ids[0],))
|
||||||
bill = Bill.objects.get(pk=bill_ids[0])
|
bill = Bill.objects.get(pk=bill_ids[0])
|
||||||
bill_link = '<a href="%s">%s</a>' % (bill_url, bill.number)
|
bill_link = '<a href="%s">%s</a>' % (bill_url, bill.number)
|
||||||
title = mark_safe(_("Manage %s bill lines.") % bill_link)
|
title = mark_safe(_("Manage %s bill lines.") % bill_link)
|
||||||
|
if not bill.is_open:
|
||||||
|
messages.warning(request, _("Bill not in open state."))
|
||||||
else:
|
else:
|
||||||
|
if Bill.objects.filter(id__in=bill_ids, is_open=False).exists():
|
||||||
|
messages.warning(request, _("Not all bills are in open state."))
|
||||||
title = _("Manage bill lines of multiple bills.")
|
title = _("Manage bill lines of multiple bills.")
|
||||||
context = {
|
context = {
|
||||||
'title': title,
|
'title': title,
|
||||||
|
@ -177,13 +192,15 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
'fields': ('html',),
|
'fields': ('html',),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
list_prefetch_related = ('transactions',)
|
||||||
|
search_fields = ('number', 'account__username', 'comments')
|
||||||
change_view_actions = [
|
change_view_actions = [
|
||||||
actions.manage_lines, actions.view_bill, actions.download_bills, actions.send_bills,
|
actions.manage_lines, actions.view_bill, actions.download_bills, actions.send_bills,
|
||||||
actions.close_bills
|
actions.close_bills
|
||||||
]
|
]
|
||||||
list_prefetch_related = ('transactions',)
|
actions = [
|
||||||
search_fields = ('number', 'account__username', 'comments')
|
actions.manage_lines, actions.download_bills, actions.close_bills, actions.send_bills
|
||||||
actions = [actions.download_bills, actions.close_bills, actions.send_bills]
|
]
|
||||||
change_readonly_fields = ('account_link', 'type', 'is_open')
|
change_readonly_fields = ('account_link', 'type', 'is_open')
|
||||||
readonly_fields = ('number', 'display_total', 'is_sent', 'display_payment_state')
|
readonly_fields = ('number', 'display_total', 'is_sent', 'display_payment_state')
|
||||||
inlines = [BillLineInline, ClosedBillLineInline]
|
inlines = [BillLineInline, ClosedBillLineInline]
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2015-05-27 13:28+0000\n"
|
"POT-Creation-Date: 2015-05-28 09:23+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -34,97 +34,114 @@ msgstr ""
|
||||||
msgid "Selected bills have been closed"
|
msgid "Selected bills have been closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:82
|
#: actions.py:86
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%s\">One related transaction</a> has been created"
|
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:83
|
#: actions.py:87
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%s\">%i related transactions</a> have been created"
|
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:89
|
#: actions.py:93
|
||||||
msgid "Are you sure about closing the following bills?"
|
msgid "Are you sure about closing the following bills?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:90
|
#: actions.py:94
|
||||||
msgid ""
|
msgid ""
|
||||||
"Once a bill is closed it can not be further modified.</p><p>Please select a "
|
"Once a bill is closed it can not be further modified.</p><p>Please select a "
|
||||||
"payment source for the selected bills"
|
"payment source for the selected bills"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:103
|
#: actions.py:107
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:114
|
#: actions.py:125
|
||||||
|
msgid "One bill has been sent."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:126
|
||||||
|
#, python-format
|
||||||
|
msgid "%i bills have been sent."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:128
|
||||||
msgid "Resend"
|
msgid "Resend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:174
|
#: actions.py:189
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(norders)s orders and %(nlines)s lines undoed."
|
msgid "%(norders)s orders and %(nlines)s lines undoed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:187
|
|
||||||
msgid "Can not move lines from a closed bill."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: actions.py:192
|
|
||||||
msgid "Can not move lines from different accounts"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: actions.py:201
|
|
||||||
msgid "Target account different than lines account."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: actions.py:208
|
#: actions.py:208
|
||||||
msgid "Lines moved"
|
msgid "Lines moved"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:48 admin.py:92 admin.py:121 forms.py:11
|
#: admin.py:49 admin.py:93 admin.py:128 forms.py:11
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:79
|
#: admin.py:80
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
#: admin.py:87
|
#: admin.py:88
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:116
|
#: admin.py:118
|
||||||
|
msgid "Is open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:123
|
||||||
msgid "Subline"
|
msgid "Subline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:153
|
#: admin.py:157
|
||||||
|
msgid "No bills selected."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:164
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Manage %s bill lines."
|
msgid "Manage %s bill lines."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:155
|
#: admin.py:166
|
||||||
|
msgid "Bill not in open state."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:169
|
||||||
|
msgid "Not all bills are in open state."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:170
|
||||||
msgid "Manage bill lines of multiple bills."
|
msgid "Manage bill lines of multiple bills."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:175
|
#: admin.py:190
|
||||||
msgid "Raw"
|
msgid "Raw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:196
|
#: admin.py:208
|
||||||
|
msgid "Created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:213
|
||||||
msgid "lines"
|
msgid "lines"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:201 templates/bills/microspective.html:118
|
#: admin.py:218 templates/bills/microspective.html:118
|
||||||
msgid "total"
|
msgid "total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:209 models.py:88 models.py:340
|
#: admin.py:226 models.py:88 models.py:352
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr "tipus"
|
msgstr "tipus"
|
||||||
|
|
||||||
#: admin.py:226
|
#: admin.py:243
|
||||||
msgid "Payment"
|
msgid "Payment"
|
||||||
msgstr "Pagament"
|
msgstr "Pagament"
|
||||||
|
|
||||||
|
@ -290,82 +307,78 @@ msgstr "comentaris"
|
||||||
msgid "HTML"
|
msgid "HTML"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:280
|
#: models.py:285
|
||||||
msgid "bill"
|
msgid "bill"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:281 models.py:338 templates/bills/microspective.html:73
|
#: models.py:286 models.py:350 templates/bills/microspective.html:73
|
||||||
msgid "description"
|
msgid "description"
|
||||||
msgstr "descripció"
|
msgstr "descripció"
|
||||||
|
|
||||||
#: models.py:282
|
#: models.py:287
|
||||||
msgid "rate"
|
msgid "rate"
|
||||||
msgstr "tarifa"
|
msgstr "tarifa"
|
||||||
|
|
||||||
#: models.py:283
|
#: models.py:288
|
||||||
msgid "quantity"
|
msgid "quantity"
|
||||||
msgstr "quantitat"
|
msgstr "quantitat"
|
||||||
|
|
||||||
#: models.py:284
|
#: models.py:289
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "quantity"
|
#| msgid "quantity"
|
||||||
msgid "Verbose quantity"
|
msgid "Verbose quantity"
|
||||||
msgstr "quantitat"
|
msgstr "quantitat"
|
||||||
|
|
||||||
#: models.py:285 templates/bills/microspective.html:77
|
#: models.py:290 templates/bills/microspective.html:77
|
||||||
#: templates/bills/microspective.html:111
|
#: templates/bills/microspective.html:111
|
||||||
msgid "subtotal"
|
msgid "subtotal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:286
|
#: models.py:291
|
||||||
msgid "tax"
|
msgid "tax"
|
||||||
msgstr "impostos"
|
msgstr "impostos"
|
||||||
|
|
||||||
#: models.py:287
|
#: models.py:292
|
||||||
msgid "start"
|
msgid "start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:288
|
#: models.py:293
|
||||||
msgid "end"
|
msgid "end"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:290
|
#: models.py:295
|
||||||
msgid "Informative link back to the order"
|
msgid "Informative link back to the order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:291
|
#: models.py:296
|
||||||
msgid "order billed"
|
msgid "order billed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:292
|
#: models.py:297
|
||||||
msgid "order billed until"
|
msgid "order billed until"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:293
|
#: models.py:298
|
||||||
msgid "created"
|
msgid "created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:295
|
#: models.py:300
|
||||||
msgid "amended line"
|
msgid "amended line"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:316
|
#: models.py:343
|
||||||
msgid "{ini} to {end}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: models.py:331
|
|
||||||
msgid "Volume"
|
msgid "Volume"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:332
|
#: models.py:344
|
||||||
msgid "Compensation"
|
msgid "Compensation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:333
|
#: models.py:345
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:337
|
#: models.py:349
|
||||||
msgid "bill line"
|
msgid "bill line"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -378,20 +391,15 @@ msgstr ""
|
||||||
msgid "On %(bank_account)s"
|
msgid "On %(bank_account)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/bills/microspective-fee.html:113
|
#: templates/bills/microspective-fee.html:114
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "From %(period)s"
|
msgid "From %(ini)s to %(end)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/bills/microspective-fee.html:118
|
#: templates/bills/microspective-fee.html:121
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"<strong>Con vuestras cuotas</strong>, ademas de obtener conexion y multitud "
|
"<strong>With your membership</strong> you are supporting ...\n"
|
||||||
"de servicios, estais<br>\n"
|
|
||||||
" Con vuestras cuotas, ademas de obtener conexion y multitud de servicios,"
|
|
||||||
"<br>\n"
|
|
||||||
" Con vuestras cuotas, ademas de obtener conexion <br>\n"
|
|
||||||
" Con vuestras cuotas, ademas de obtener <br>\n"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/bills/microspective.html:49
|
#: templates/bills/microspective.html:49
|
||||||
|
@ -403,8 +411,9 @@ msgid "TOTAL"
|
||||||
msgstr "TOTAL"
|
msgstr "TOTAL"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:57
|
#: templates/bills/microspective.html:57
|
||||||
#, python-format
|
#, fuzzy, python-format
|
||||||
msgid "%(bill_type|upper)s DATE "
|
#| msgid "%(bill_type|upper)s DATE "
|
||||||
|
msgid "%(bill_type)s DATE"
|
||||||
msgstr "DATA %(bill_type|upper)s"
|
msgstr "DATA %(bill_type|upper)s"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:74
|
#: templates/bills/microspective.html:74
|
||||||
|
@ -437,10 +446,18 @@ msgid "PAYMENT"
|
||||||
msgstr "PAGAMENT"
|
msgstr "PAGAMENT"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:140
|
#: templates/bills/microspective.html:140
|
||||||
#, python-format
|
#, fuzzy, python-format
|
||||||
|
#| msgid ""
|
||||||
|
#| "\n"
|
||||||
|
#| " You can pay our <i>%(type)s</i> by bank transfer. "
|
||||||
|
#| "<br>\n"
|
||||||
|
#| " Please make sure to state your name and the <i>"
|
||||||
|
#| "%(type)s</i> number.\n"
|
||||||
|
#| " Our bank account number is <br>\n"
|
||||||
|
#| " "
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" You can pay our <i>%(type)s</i> by bank transfer. <br>\n"
|
" You can pay our <i>%(type)s</i> by bank transfer.<br>\n"
|
||||||
" Please make sure to state your name and the <i>%(type)s</"
|
" Please make sure to state your name and the <i>%(type)s</"
|
||||||
"i> number.\n"
|
"i> number.\n"
|
||||||
" Our bank account number is <br>\n"
|
" Our bank account number is <br>\n"
|
||||||
|
@ -459,8 +476,8 @@ msgstr "PREGUNTES"
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" If you have any question about your <i>%(type)s</i>, please\n"
|
" If you have any question about your <i>%(type)s</i>, please\n"
|
||||||
" feel free to contact us at your convinience. We will reply as "
|
" feel free to write us at %(email)s. We will reply as soon as we "
|
||||||
"soon as we get\n"
|
"get\n"
|
||||||
" your message.\n"
|
" your message.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -0,0 +1,469 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2015-05-28 09:23+0000\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: actions.py:37
|
||||||
|
msgid "Download"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:47
|
||||||
|
msgid "View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:55
|
||||||
|
msgid "Selected bills should be in open state"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:73
|
||||||
|
msgid "Selected bills have been closed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:86
|
||||||
|
#, python-format
|
||||||
|
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:87
|
||||||
|
#, python-format
|
||||||
|
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:93
|
||||||
|
msgid "Are you sure about closing the following bills?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:94
|
||||||
|
msgid ""
|
||||||
|
"Once a bill is closed it can not be further modified.</p><p>Please select a "
|
||||||
|
"payment source for the selected bills"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:107
|
||||||
|
msgid "Close"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:125
|
||||||
|
msgid "One bill has been sent."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:126
|
||||||
|
#, python-format
|
||||||
|
msgid "%i bills have been sent."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:128
|
||||||
|
msgid "Resend"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:189
|
||||||
|
#, python-format
|
||||||
|
msgid "%(norders)s orders and %(nlines)s lines undoed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: actions.py:208
|
||||||
|
msgid "Lines moved"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:49 admin.py:93 admin.py:128 forms.py:11
|
||||||
|
msgid "Total"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:80
|
||||||
|
msgid "Description"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:88
|
||||||
|
msgid "Subtotal"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:118
|
||||||
|
msgid "Is open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:123
|
||||||
|
msgid "Subline"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:157
|
||||||
|
msgid "No bills selected."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:164
|
||||||
|
#, python-format
|
||||||
|
msgid "Manage %s bill lines."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:166
|
||||||
|
msgid "Bill not in open state."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:169
|
||||||
|
msgid "Not all bills are in open state."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:170
|
||||||
|
msgid "Manage bill lines of multiple bills."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:190
|
||||||
|
msgid "Raw"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:208
|
||||||
|
msgid "Created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:213
|
||||||
|
msgid "lines"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:218 templates/bills/microspective.html:118
|
||||||
|
msgid "total"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:226 models.py:88 models.py:352
|
||||||
|
msgid "type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:243
|
||||||
|
msgid "Payment"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:17
|
||||||
|
msgid "All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:18 models.py:78
|
||||||
|
msgid "Invoice"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:19 models.py:79
|
||||||
|
msgid "Amendment invoice"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:20 models.py:80
|
||||||
|
msgid "Fee"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:21
|
||||||
|
msgid "Amendment fee"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:22
|
||||||
|
msgid "Pro-forma"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:41
|
||||||
|
msgid "positive price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:46 filters.py:64
|
||||||
|
msgid "Yes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:47 filters.py:65
|
||||||
|
msgid "No"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:59
|
||||||
|
msgid "has bill contact"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:9
|
||||||
|
msgid "Number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:10
|
||||||
|
msgid "Account"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:12
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:13
|
||||||
|
msgid "Source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: helpers.py:10
|
||||||
|
msgid ""
|
||||||
|
"{relation} account \"{account}\" does not have a declared invoice contact. "
|
||||||
|
"You should <a href=\"{url}#invoicecontact-group\">provide one</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: helpers.py:17
|
||||||
|
msgid "Related"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: helpers.py:24
|
||||||
|
msgid "Main"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:23 models.py:86
|
||||||
|
msgid "account"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:25
|
||||||
|
msgid "name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:26
|
||||||
|
msgid "Account full name will be used when left blank."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:27
|
||||||
|
msgid "address"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:28
|
||||||
|
msgid "city"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:30
|
||||||
|
msgid "zip code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:31
|
||||||
|
msgid "Enter a valid zipcode."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:32
|
||||||
|
msgid "country"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:35
|
||||||
|
msgid "VAT number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:67
|
||||||
|
msgid "Paid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:68
|
||||||
|
msgid "Pending"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:69
|
||||||
|
msgid "Bad debt"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:81
|
||||||
|
msgid "Amendment Fee"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:82
|
||||||
|
msgid "Pro forma"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:85
|
||||||
|
msgid "number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:89
|
||||||
|
msgid "created on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:90
|
||||||
|
msgid "closed on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:91
|
||||||
|
msgid "open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:92
|
||||||
|
msgid "sent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:93
|
||||||
|
msgid "due on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:94
|
||||||
|
msgid "updated on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:97
|
||||||
|
msgid "comments"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:98
|
||||||
|
msgid "HTML"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:285
|
||||||
|
msgid "bill"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:286 models.py:350 templates/bills/microspective.html:73
|
||||||
|
msgid "description"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:287
|
||||||
|
msgid "rate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:288
|
||||||
|
msgid "quantity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:289
|
||||||
|
msgid "Verbose quantity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:290 templates/bills/microspective.html:77
|
||||||
|
#: templates/bills/microspective.html:111
|
||||||
|
msgid "subtotal"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:291
|
||||||
|
msgid "tax"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:292
|
||||||
|
msgid "start"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:293
|
||||||
|
msgid "end"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:295
|
||||||
|
msgid "Informative link back to the order"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:296
|
||||||
|
msgid "order billed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:297
|
||||||
|
msgid "order billed until"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:298
|
||||||
|
msgid "created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:300
|
||||||
|
msgid "amended line"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:343
|
||||||
|
msgid "Volume"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:344
|
||||||
|
msgid "Compensation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:345
|
||||||
|
msgid "Other"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:349
|
||||||
|
msgid "bill line"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective-fee.html:107
|
||||||
|
msgid "Due date"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective-fee.html:108
|
||||||
|
#, python-format
|
||||||
|
msgid "On %(bank_account)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective-fee.html:114
|
||||||
|
#, python-format
|
||||||
|
msgid "From %(ini)s to %(end)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective-fee.html:121
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
"<strong>With your membership</strong> you are supporting ...\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:49
|
||||||
|
msgid "DUE DATE"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:53
|
||||||
|
msgid "TOTAL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:57
|
||||||
|
#, python-format
|
||||||
|
msgid "%(bill_type)s DATE"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:74
|
||||||
|
msgid "period"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:75
|
||||||
|
msgid "hrs/qty"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:76
|
||||||
|
msgid "rate/price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:111
|
||||||
|
#: templates/bills/microspective.html:114
|
||||||
|
msgid "VAT"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:114
|
||||||
|
msgid "taxes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:130
|
||||||
|
msgid "COMMENTS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:136
|
||||||
|
msgid "PAYMENT"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:140
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" You can pay our <i>%(type)s</i> by bank transfer.<br>\n"
|
||||||
|
" Please make sure to state your name and the <i>%(type)s</"
|
||||||
|
"i> number.\n"
|
||||||
|
" Our bank account number is <br>\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:149
|
||||||
|
msgid "QUESTIONS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/bills/microspective.html:150
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" If you have any question about your <i>%(type)s</i>, please\n"
|
||||||
|
" feel free to write us at %(email)s. We will reply as soon as we "
|
||||||
|
"get\n"
|
||||||
|
" your message.\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
|
@ -124,6 +124,10 @@ class Bill(models.Model):
|
||||||
return self.PENDING
|
return self.PENDING
|
||||||
return self.BAD_DEBT
|
return self.BAD_DEBT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_multiple_pages(self):
|
||||||
|
return self.type != self.FEE
|
||||||
|
|
||||||
def get_payment_state_display(self):
|
def get_payment_state_display(self):
|
||||||
value = self.payment_state
|
value = self.payment_state
|
||||||
return force_text(dict(self.PAYMENT_STATES).get(value, value))
|
return force_text(dict(self.PAYMENT_STATES).get(value, value))
|
||||||
|
@ -186,6 +190,7 @@ class Bill(models.Model):
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
html = self.html or self.render()
|
html = self.html or self.render()
|
||||||
|
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={
|
||||||
|
@ -195,7 +200,7 @@ class Bill(models.Model):
|
||||||
email_from=settings.BILLS_SELLER_EMAIL,
|
email_from=settings.BILLS_SELLER_EMAIL,
|
||||||
contacts=(Contact.BILLING,),
|
contacts=(Contact.BILLING,),
|
||||||
attachments=[
|
attachments=[
|
||||||
('%s.pdf' % self.number, html_to_pdf(html), 'application/pdf')
|
('%s.pdf' % self.number, pdf, 'application/pdf')
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
self.is_sent = True
|
self.is_sent = True
|
||||||
|
@ -312,12 +317,10 @@ class BillLine(models.Model):
|
||||||
if self.start_on.day != 1 or self.end_on.day != 1:
|
if self.start_on.day != 1 or self.end_on.day != 1:
|
||||||
date_format = "N j, 'y"
|
date_format = "N j, 'y"
|
||||||
end = date(self.end_on, date_format)
|
end = date(self.end_on, date_format)
|
||||||
# .strftime(date_format)
|
|
||||||
else:
|
else:
|
||||||
end = date((self.end_on - datetime.timedelta(days=1)), date_format)
|
end = date((self.end_on - datetime.timedelta(days=1)), date_format)
|
||||||
# ).strftime(date_format)
|
ini = date(self.start_on, date_format).capitalize()
|
||||||
ini = date(self.start_on, date_format)
|
end = end.capitalize()
|
||||||
#.strftime(date_format)
|
|
||||||
if not self.end_on:
|
if not self.end_on:
|
||||||
return ini
|
return ini
|
||||||
if ini == end:
|
if ini == end:
|
||||||
|
|
|
@ -99,30 +99,31 @@ hr {
|
||||||
<div id="number" class="column-1">
|
<div id="number" class="column-1">
|
||||||
<span id="number-title">{% filter title %}{% trans bill.get_type_display %}{% endfilter %}</span><br>
|
<span id="number-title">{% filter title %}{% trans bill.get_type_display %}{% endfilter %}</span><br>
|
||||||
<span id="number-value">{{ bill.number }}</span><br>
|
<span id="number-value">{{ bill.number }}</span><br>
|
||||||
<span id="number-date">{{ bill.closed_on | default:now | date | capfirst }}</span><br>
|
<span id="number-date">{{ bill.closed_on | default:now | date:"F j, Y" | capfirst }}</span><br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="amount" class="column-2">
|
<div id="amount" class="column-2">
|
||||||
<span id="amount-value">{{ bill.get_total }} &{{ currency.lower }};</span><br>
|
<span id="amount-value">{{ bill.get_total }} &{{ currency.lower }};</span><br>
|
||||||
<span id="amount-note">{% trans "Due date" %} {{ payment.due_date| default:default_due_date | date }}<br>
|
<span id="amount-note">{% trans "Due date" %} {{ payment.due_date| default:default_due_date | date:"F j, Y" }}<br>
|
||||||
{% if not payment.message %}{% blocktrans with bank_account=seller_info.bank_account %}On {{ bank_account }}{% endblocktrans %}{% endif %}<br>
|
{% if not payment.message %}{% blocktrans with bank_account=seller_info.bank_account %}On {{ bank_account }}{% endblocktrans %}{% endif %}<br>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="date" class="column-2">
|
<div id="date" class="column-2">
|
||||||
{% blocktrans with period=bill.lines.get.get_verbose_period %}From {{ period }}{% endblocktrans %}
|
{% with line=bill.lines.get %}
|
||||||
|
{% blocktrans with ini=line.start_on|date:"F j, Y" end=line.end_on|date:"F j, Y" %}From {{ ini }} to {{ end }}{% endblocktrans %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="text">
|
<div id="text">
|
||||||
{% blocktrans %}
|
{% blocktrans %}
|
||||||
<strong>Con vuestras cuotas</strong>, ademas de obtener conexion y multitud de servicios, estais<br>
|
<strong>With your membership</strong> you are supporting ...
|
||||||
Con vuestras cuotas, ademas de obtener conexion y multitud de servicios,<br>
|
|
||||||
Con vuestras cuotas, ademas de obtener conexion <br>
|
|
||||||
Con vuestras cuotas, ademas de obtener <br>
|
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<hr>
|
<hr>
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
|
@ -175,12 +175,12 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
#lines .column-description {
|
#lines .column-description {
|
||||||
width: 42%;
|
width: 40%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lines .column-period {
|
#lines .column-period {
|
||||||
width: 20%;
|
width: 22%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lines .column-quantity {
|
#lines .column-quantity {
|
||||||
|
|
|
@ -47,15 +47,15 @@
|
||||||
<hr>
|
<hr>
|
||||||
<div id="due-date">
|
<div id="due-date">
|
||||||
<span class="title">{% trans "DUE DATE" %}</span><br>
|
<span class="title">{% trans "DUE DATE" %}</span><br>
|
||||||
<psan class="value">{{ bill.due_on | default:default_due_date | date }}</span>
|
<psan class="value">{{ bill.due_on | default:default_due_date | date | capfirst }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="total">
|
<div id="total">
|
||||||
<span class="title">{% trans "TOTAL" %}</span><br>
|
<span class="title">{% trans "TOTAL" %}</span><br>
|
||||||
<psan class="value">{{ bill.get_total }} &{{ currency.lower }};</span>
|
<psan class="value">{{ bill.get_total }} &{{ currency.lower }};</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="bill-date">
|
<div id="bill-date">
|
||||||
<span class="title">{% blocktrans with bill_type=bill.get_type_display.upper %}{{ bill_type }} DATE {% endblocktrans %}</span><br>
|
<span class="title">{% blocktrans with bill_type=bill.get_type_display.upper %}{{ bill_type }} DATE{% endblocktrans %}</span><br>
|
||||||
<psan class="value">{{ bill.closed_on | default:now | date }}</span>
|
<psan class="value">{{ bill.closed_on | default:now | date | capfirst }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="buyer-details">
|
<div id="buyer-details">
|
||||||
|
@ -77,9 +77,9 @@
|
||||||
<span class="title column-subtotal">{% trans "subtotal" %}</span>
|
<span class="title column-subtotal">{% trans "subtotal" %}</span>
|
||||||
<br>
|
<br>
|
||||||
{% for line in lines %}
|
{% for line in lines %}
|
||||||
{% with sublines=line.sublines.all description=line.description|slice:"40:" %}
|
{% with sublines=line.sublines.all description=line.description|slice:"38:" %}
|
||||||
<span class="{% if not sublines and not description %}last {% endif %}column-id">{% if not line.order_id %}L{% endif %}{{ line.order_id }}</span>
|
<span class="{% if not sublines and not description %}last {% endif %}column-id">{% if not line.order_id %}L{% endif %}{{ line.order_id }}</span>
|
||||||
<span class="{% if not sublines and not description %}last {% endif %}column-description">{{ line.description|slice:":40" }}</span>
|
<span class="{% if not sublines and not description %}last {% endif %}column-description">{{ line.description|slice:":38" }}</span>
|
||||||
<span class="{% if not sublines and not description %}last {% endif %}column-period">{{ line.get_verbose_period }}</span>
|
<span class="{% if not sublines and not description %}last {% endif %}column-period">{{ line.get_verbose_period }}</span>
|
||||||
<span class="{% if not sublines and not description %}last {% endif %}column-quantity">{{ line.get_verbose_quantity|default:" "|safe }}</span>
|
<span class="{% if not sublines and not description %}last {% endif %}column-quantity">{{ line.get_verbose_quantity|default:" "|safe }}</span>
|
||||||
<span class="{% if not sublines and not description %}last {% endif %}column-rate">{% if line.rate %}{{ line.rate }} &{{ currency.lower }};{% else %} {% endif %}</span>
|
<span class="{% if not sublines and not description %}last {% endif %}column-rate">{% if line.rate %}{{ line.rate }} &{{ currency.lower }};{% else %} {% endif %}</span>
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
<br>
|
<br>
|
||||||
{% if description %}
|
{% if description %}
|
||||||
<span class="{% if not sublines %}last {% endif %}subline column-id"> </span>
|
<span class="{% if not sublines %}last {% endif %}subline column-id"> </span>
|
||||||
<span class="{% if not sublines %}last {% endif %}subline column-description">{{ description|truncatechars:41 }}</span>
|
<span class="{% if not sublines %}last {% endif %}subline column-description">{{ description|truncatechars:39 }}</span>
|
||||||
<span class="{% if not sublines %}last {% endif %}subline column-period"> </span>
|
<span class="{% if not sublines %}last {% endif %}subline column-period"> </span>
|
||||||
<span class="{% if not sublines %}last {% endif %}subline column-quantity"> </span>
|
<span class="{% if not sublines %}last {% endif %}subline column-quantity"> </span>
|
||||||
<span class="{% if not sublines %}last {% endif %}subline column-rate"> </span>
|
<span class="{% if not sublines %}last {% endif %}subline column-rate"> </span>
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for subline in sublines %}
|
{% for subline in sublines %}
|
||||||
<span class="{% if forloop.last %}last {% endif %}subline column-id"> </span>
|
<span class="{% if forloop.last %}last {% endif %}subline column-id"> </span>
|
||||||
<span class="{% if forloop.last %}last {% endif %}subline column-description">{{ subline.description|truncatechars:41 }}</span>
|
<span class="{% if forloop.last %}last {% endif %}subline column-description">{{ subline.description|truncatechars:39 }}</span>
|
||||||
<span class="{% if forloop.last %}last {% endif %}subline column-period"> </span>
|
<span class="{% if forloop.last %}last {% endif %}subline column-period"> </span>
|
||||||
<span class="{% if forloop.last %}last {% endif %}subline column-quantity"> </span>
|
<span class="{% if forloop.last %}last {% endif %}subline column-quantity"> </span>
|
||||||
<span class="{% if forloop.last %}last {% endif %}subline column-rate"> </span>
|
<span class="{% if forloop.last %}last {% endif %}subline column-rate"> </span>
|
||||||
|
@ -138,7 +138,7 @@
|
||||||
{{ payment.message | safe }}
|
{{ payment.message | safe }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% blocktrans with type=bill.get_type_display.lower %}
|
{% blocktrans with type=bill.get_type_display.lower %}
|
||||||
You can pay our <i>{{ type }}</i> by bank transfer. <br>
|
You can pay our <i>{{ type }}</i> by bank transfer.<br>
|
||||||
Please make sure to state your name and the <i>{{ type }}</i> number.
|
Please make sure to state your name and the <i>{{ type }}</i> number.
|
||||||
Our bank account number is <br>
|
Our bank account number is <br>
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
@ -147,9 +147,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="questions">
|
<div id="questions">
|
||||||
<span class="title">{% trans "QUESTIONS" %}</span>
|
<span class="title">{% trans "QUESTIONS" %}</span>
|
||||||
{% blocktrans with type=bill.get_type_display.lower %}
|
{% blocktrans with type=bill.get_type_display.lower email=seller_info.email %}
|
||||||
If you have any question about your <i>{{ type }}</i>, please
|
If you have any question about your <i>{{ type }}</i>, please
|
||||||
feel free to contact us at your convinience. We will reply as soon as we get
|
feel free to write us at {{ email }}. We will reply as soon as we get
|
||||||
your message.
|
your message.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@ class RecordSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
""" Validates if this zone generates a correct zone file """
|
""" Validates if this zone generates a correct zone file """
|
||||||
records = RecordSerializer(required=False, many=True) #allow_add_remove=True)
|
records = RecordSerializer(required=False, many=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Domain
|
model = Domain
|
||||||
|
@ -44,3 +44,35 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
domain = domain_for_validation(self.instance, records)
|
domain = domain_for_validation(self.instance, records)
|
||||||
validators.validate_zone(domain.render_zone())
|
validators.validate_zone(domain.render_zone())
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
records = validated_data.pop('records')
|
||||||
|
domain = super(DomainSerializer, self).create(validated_data)
|
||||||
|
for record in records:
|
||||||
|
domain.records.create(type=record['type'], value=record['value'])
|
||||||
|
return domain
|
||||||
|
|
||||||
|
def update(self, validated_data):
|
||||||
|
precords = validated_data.pop('records')
|
||||||
|
domain = super(DomainSerializer, self).update(validated_data)
|
||||||
|
to_delete = []
|
||||||
|
for erecord in domain.records.all():
|
||||||
|
match = False
|
||||||
|
for ix, precord in enumerate(precords):
|
||||||
|
if erecord.type == precord['type'] and erecord.value == precord['value']:
|
||||||
|
match = True
|
||||||
|
break
|
||||||
|
if match:
|
||||||
|
precords.remove(ix)
|
||||||
|
else:
|
||||||
|
to_delete.append(erecord)
|
||||||
|
for precord in precords:
|
||||||
|
try:
|
||||||
|
recycled = to_delete.pop()
|
||||||
|
except IndexError:
|
||||||
|
domain.records.create(type=precord['type'], value=precord['value'])
|
||||||
|
else:
|
||||||
|
recycled.type = precord['type']
|
||||||
|
recycled.value = precord['value']
|
||||||
|
recycled.save()
|
||||||
|
return domain
|
||||||
|
|
|
@ -92,7 +92,7 @@ class BillSelectedOrders(object):
|
||||||
url = change_url(bills[0])
|
url = change_url(bills[0])
|
||||||
else:
|
else:
|
||||||
url = reverse('admin:bills_bill_changelist')
|
url = reverse('admin:bills_bill_changelist')
|
||||||
ids = ','.join(map(str, bills))
|
ids = ','.join([str(b.id) for b in bills])
|
||||||
url += '?id__in=%s' % ids
|
url += '?id__in=%s' % ids
|
||||||
msg = ungettext(
|
msg = ungettext(
|
||||||
'<a href="{url}">One bill</a> has been created.',
|
'<a href="{url}">One bill</a> has been created.',
|
||||||
|
|
|
@ -245,6 +245,10 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
|
||||||
}))
|
}))
|
||||||
|
|
||||||
def generate_line(self, order, price, *dates, metric=1, discounts=None, computed=False):
|
def generate_line(self, order, price, *dates, metric=1, discounts=None, computed=False):
|
||||||
|
"""
|
||||||
|
discounts: already applied discounts on price
|
||||||
|
computed: price = price*size already performed
|
||||||
|
"""
|
||||||
if len(dates) == 2:
|
if len(dates) == 2:
|
||||||
ini, end = dates
|
ini, end = dates
|
||||||
elif len(dates) == 1:
|
elif len(dates) == 1:
|
||||||
|
@ -377,7 +381,8 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
|
||||||
size = self.get_price_size(order.new_billed_until, new_end)
|
size = self.get_price_size(order.new_billed_until, new_end)
|
||||||
price += price*size
|
price += price*size
|
||||||
order.new_billed_until = new_end
|
order.new_billed_until = new_end
|
||||||
line = self.generate_line(order, price, ini, new_end or end, discounts=discounts, computed=True)
|
line = self.generate_line(
|
||||||
|
order, price, ini, new_end or end, discounts=discounts, computed=True)
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,24 @@ import textwrap
|
||||||
from orchestra.utils.sys import run
|
from orchestra.utils.sys import run
|
||||||
|
|
||||||
|
|
||||||
def html_to_pdf(html):
|
def html_to_pdf(html, pagination=False):
|
||||||
""" converts HTL to PDF using wkhtmltopdf """
|
""" converts HTL to PDF using wkhtmltopdf """
|
||||||
return run(textwrap.dedent("""\
|
print(pagination)
|
||||||
PATH=$PATH:/usr/local/bin/
|
context = {
|
||||||
xvfb-run -a -s "-screen 0 2480x3508x16" wkhtmltopdf -q \\
|
'pagination': textwrap.dedent("""\
|
||||||
--use-xserver \\
|
--footer-center "Page [page] of [topage]"\\
|
||||||
--footer-center "Page [page] of [topage]" \\
|
--footer-center "Page [page] of [topage]" \\
|
||||||
--footer-font-name sans \\
|
--footer-font-name sans \\
|
||||||
--footer-font-size 7 \\
|
--footer-font-size 7 \\
|
||||||
--footer-spacing 7 \\
|
--footer-spacing 7"""
|
||||||
|
) if pagination else '',
|
||||||
|
}
|
||||||
|
cmd = textwrap.dedent("""\
|
||||||
|
PATH=$PATH:/usr/local/bin/
|
||||||
|
xvfb-run -a -s "-screen 0 2480x3508x16" wkhtmltopdf -q \\
|
||||||
|
--use-xserver \\
|
||||||
|
%(pagination)s \\
|
||||||
--margin-bottom 22 \\
|
--margin-bottom 22 \\
|
||||||
--margin-top 20 - - """),
|
--margin-top 20 - -\
|
||||||
stdin=html.encode('utf-8')
|
""") % context
|
||||||
).stdout
|
return run(cmd, stdin=html.encode('utf-8')).stdout
|
||||||
|
|
Loading…
Reference in New Issue