Preliminar implementation of amended invoices
This commit is contained in:
parent
3520b3968b
commit
75c72ce8a5
|
@ -17,6 +17,7 @@ from orchestra.admin.forms import adminmodelformset_factory
|
||||||
from orchestra.admin.utils import get_object_from_url, change_url
|
from orchestra.admin.utils import get_object_from_url, change_url
|
||||||
from orchestra.utils.html import html_to_pdf
|
from orchestra.utils.html import html_to_pdf
|
||||||
|
|
||||||
|
from . import settings
|
||||||
from .forms import SelectSourceForm
|
from .forms import SelectSourceForm
|
||||||
from .helpers import validate_contact
|
from .helpers import validate_contact
|
||||||
from .models import Bill, BillLine
|
from .models import Bill, BillLine
|
||||||
|
@ -217,7 +218,7 @@ def amend_bills(modeladmin, request, queryset):
|
||||||
if queryset.filter(is_open=True).exists():
|
if queryset.filter(is_open=True).exists():
|
||||||
messages.warning(request, _("Selected bills should be in closed state"))
|
messages.warning(request, _("Selected bills should be in closed state"))
|
||||||
return
|
return
|
||||||
ids = []
|
amend_ids = []
|
||||||
for bill in queryset:
|
for bill in queryset:
|
||||||
with translation.override(bill.account.language):
|
with translation.override(bill.account.language):
|
||||||
amend_type = bill.get_amend_type()
|
amend_type = bill.get_amend_type()
|
||||||
|
@ -239,17 +240,33 @@ def amend_bills(modeladmin, request, queryset):
|
||||||
line = BillLine.objects.create(
|
line = BillLine.objects.create(
|
||||||
bill=amend,
|
bill=amend,
|
||||||
start_on=bill.created_on,
|
start_on=bill.created_on,
|
||||||
description=_("Amend of %(related_type)s %(number)s, tax %(tax)s%%") % context,
|
description=_("%(related_type)s %(number)s subtotal for tax %(tax)s%%") % context,
|
||||||
subtotal=subtotals[0],
|
subtotal=subtotals[0],
|
||||||
tax=tax
|
tax=tax
|
||||||
)
|
)
|
||||||
ids.append(bill.pk)
|
amend_ids.append(amend.pk)
|
||||||
amend_url = reverse('admin:bills_bill_changelist')
|
num = len(amend_ids)
|
||||||
amend_url += '?id=%s' % ','.join(map(str, ids))
|
if num == 1:
|
||||||
|
amend_url = reverse('admin:bills_bill_change', args=amend_ids)
|
||||||
|
else:
|
||||||
|
amend_url = reverse('admin:bills_bill_changelist')
|
||||||
|
amend_url += '?id=%s' % ','.join(map(str, amend_ids))
|
||||||
|
context = {
|
||||||
|
'url': amend_url,
|
||||||
|
'num': num,
|
||||||
|
}
|
||||||
messages.success(request, mark_safe(ungettext(
|
messages.success(request, mark_safe(ungettext(
|
||||||
_('<a href="%s">One amendment bill</a> have been generated.') % amend_url,
|
_('<a href="%(url)s">One amendment bill</a> have been generated.') % context,
|
||||||
_('<a href="%s">%i amendment bills</a> have been generated.') % (amend_url, len(ids)),
|
_('<a href="%(url)s">%(num)i amendment bills</a> have been generated.') % context,
|
||||||
len(ids)
|
num
|
||||||
)))
|
)))
|
||||||
amend_bills.verbose_name = _("Amend")
|
amend_bills.verbose_name = _("Amend")
|
||||||
amend_bills.url_name = 'amend'
|
amend_bills.url_name = 'amend'
|
||||||
|
|
||||||
|
|
||||||
|
def report(modeladmin, request, queryset):
|
||||||
|
context = {
|
||||||
|
'bills': queryset,
|
||||||
|
'currency': settings.BILLS_CURRENCY,
|
||||||
|
}
|
||||||
|
return render(request, 'admin/bills/report.html', context)
|
||||||
|
|
|
@ -186,10 +186,10 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
'num_lines', 'display_total', 'display_payment_state', 'is_open', 'is_sent'
|
'num_lines', 'display_total', 'display_payment_state', 'is_open', 'is_sent'
|
||||||
)
|
)
|
||||||
list_filter = (BillTypeListFilter, 'is_open', 'is_sent', TotalListFilter, PaymentStateListFilter)
|
list_filter = (BillTypeListFilter, 'is_open', 'is_sent', TotalListFilter, PaymentStateListFilter)
|
||||||
add_fields = ('account', 'type', 'is_open', 'due_on', 'comments')
|
add_fields = ('account', 'type', 'amend_of', 'is_open', 'due_on', 'comments')
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'fields': ('number', 'type', 'account_link', 'display_total',
|
'fields': ('number', 'type', 'amend_of_link', 'account_link', 'display_total',
|
||||||
'display_payment_state', 'is_sent', 'due_on', 'comments'),
|
'display_payment_state', 'is_sent', 'due_on', 'comments'),
|
||||||
}),
|
}),
|
||||||
(_("Raw"), {
|
(_("Raw"), {
|
||||||
|
@ -205,13 +205,14 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
]
|
]
|
||||||
actions = [
|
actions = [
|
||||||
actions.manage_lines, actions.download_bills, actions.close_bills, actions.send_bills,
|
actions.manage_lines, actions.download_bills, actions.close_bills, actions.send_bills,
|
||||||
actions.amend_bills,
|
actions.amend_bills, actions.report
|
||||||
]
|
]
|
||||||
change_readonly_fields = ('account_link', 'type', 'is_open')
|
change_readonly_fields = ('account_link', 'type', 'is_open', 'amend_of_link')
|
||||||
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]
|
||||||
|
|
||||||
created_on_display = admin_date('created_on', short_description=_("Created"))
|
created_on_display = admin_date('created_on', short_description=_("Created"))
|
||||||
|
amend_of_link = admin_link('amend_of')
|
||||||
|
|
||||||
def num_lines(self, bill):
|
def num_lines(self, bill):
|
||||||
return bill.lines__count
|
return bill.lines__count
|
||||||
|
@ -267,8 +268,12 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def get_fieldsets(self, request, obj=None):
|
||||||
fieldsets = super(BillAdmin, self).get_fieldsets(request, obj)
|
fieldsets = super(BillAdmin, self).get_fieldsets(request, obj)
|
||||||
if obj and obj.is_open:
|
if obj:
|
||||||
fieldsets = (fieldsets[0],)
|
# if obj.amend_of_id:
|
||||||
|
# fieldsets = list(fieldsets)
|
||||||
|
# fieldsets[0][1]['fields'] = fieldsets[0][1]['fields'] + ('amend_of_link',)
|
||||||
|
if obj.is_open:
|
||||||
|
fieldsets = (fieldsets[0],)
|
||||||
return fieldsets
|
return fieldsets
|
||||||
|
|
||||||
def get_change_view_actions(self, obj=None):
|
def get_change_view_actions(self, obj=None):
|
||||||
|
@ -289,9 +294,12 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
if db_field.name == 'comments':
|
if db_field.name == 'comments':
|
||||||
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4})
|
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4})
|
||||||
if db_field.name == 'html':
|
elif db_field.name == 'html':
|
||||||
kwargs['widget'] = forms.Textarea(attrs={'cols': 150, 'rows': 20})
|
kwargs['widget'] = forms.Textarea(attrs={'cols': 150, 'rows': 20})
|
||||||
return super(BillAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
formfield = super(BillAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
if db_field.name == 'amend_of':
|
||||||
|
formfield.queryset = formfield.queryset.filter(is_open=False)
|
||||||
|
return formfield
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(BillAdmin, self).get_queryset(request)
|
qs = super(BillAdmin, self).get_queryset(request)
|
||||||
|
|
|
@ -4,6 +4,8 @@ from django.db.models import Q
|
||||||
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 . models import Bill
|
||||||
|
|
||||||
|
|
||||||
class BillTypeListFilter(SimpleListFilter):
|
class BillTypeListFilter(SimpleListFilter):
|
||||||
""" Filter tickets by created_by according to request.user """
|
""" Filter tickets by created_by according to request.user """
|
||||||
|
@ -89,6 +91,7 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
('PAID', _("Paid")),
|
('PAID', _("Paid")),
|
||||||
('PENDING', _("Pending")),
|
('PENDING', _("Pending")),
|
||||||
('BAD_DEBT', _("Bad debt")),
|
('BAD_DEBT', _("Bad debt")),
|
||||||
|
('AMENDED', _("Amended")),
|
||||||
)
|
)
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
def queryset(self, request, queryset):
|
||||||
|
@ -96,10 +99,12 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
if self.value() == 'OPEN':
|
if self.value() == 'OPEN':
|
||||||
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
||||||
elif self.value() == 'PAID':
|
elif self.value() == 'PAID':
|
||||||
zeros = queryset.filter(computed_total=0, computed_total__isnull=True).values_list('id', flat=True)
|
zeros = queryset.filter(computed_total=0, computed_total__isnull=True)
|
||||||
|
zeros = zeros.values_list('id', flat=True)
|
||||||
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
||||||
paid = []
|
paid = []
|
||||||
for bill_id, total in queryset.exclude(computed_total=0, computed_total__isnull=True, is_open=True).values_list('id', 'computed_total'):
|
relevant = queryset.exclude(computed_total=0, computed_total__isnull=True, is_open=True)
|
||||||
|
for bill_id, total in relevant.values_list('id', 'computed_total'):
|
||||||
try:
|
try:
|
||||||
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -107,7 +112,11 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
else:
|
else:
|
||||||
if abs(total) <= abs(ammount):
|
if abs(total) <= abs(ammount):
|
||||||
paid.append(bill_id)
|
paid.append(bill_id)
|
||||||
return queryset.filter(Q(computed_total=0)|Q(computed_total__isnull=True)|Q(id__in=paid)).exclude(is_open=True)
|
return queryset.filter(
|
||||||
|
Q(computed_total=0) |
|
||||||
|
Q(computed_total__isnull=True) |
|
||||||
|
Q(id__in=paid)
|
||||||
|
).exclude(is_open=True)
|
||||||
elif self.value() == 'PENDING':
|
elif self.value() == 'PENDING':
|
||||||
has_transaction = queryset.exclude(transactions__isnull=True)
|
has_transaction = queryset.exclude(transactions__isnull=True)
|
||||||
non_rejected = has_transaction.exclude(transactions__state=Transaction.REJECTED)
|
non_rejected = has_transaction.exclude(transactions__state=Transaction.REJECTED)
|
||||||
|
@ -115,4 +124,11 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
return queryset.filter(pk__in=non_rejected)
|
return queryset.filter(pk__in=non_rejected)
|
||||||
elif self.value() == 'BAD_DEBT':
|
elif self.value() == 'BAD_DEBT':
|
||||||
closed = queryset.filter(is_open=False).exclude(computed_total=0)
|
closed = queryset.filter(is_open=False).exclude(computed_total=0)
|
||||||
return closed.filter(Q(transactions__state=Transaction.REJECTED)|Q(transactions__isnull=True))
|
return closed.filter(
|
||||||
|
Q(transactions__state=Transaction.REJECTED) |
|
||||||
|
Q(transactions__isnull=True)
|
||||||
|
)
|
||||||
|
elif self.value() == 'AMENDED':
|
||||||
|
amendeds = queryset.filter(type__in=Bill.AMEND_MAP.values(), is_open=False)
|
||||||
|
amendeds_ids = amendeds.values_list('amend_of', flat=True)
|
||||||
|
return queryset.filter(id__in=amendeds)
|
||||||
|
|
Binary file not shown.
|
@ -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-29 09:39+0000\n"
|
"POT-Creation-Date: 2015-07-07 10:18+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"
|
||||||
|
@ -18,37 +18,37 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: actions.py:37
|
#: actions.py:40
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Descarrega"
|
msgstr "Descarrega"
|
||||||
|
|
||||||
#: actions.py:47
|
#: actions.py:50
|
||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Vista"
|
msgstr "Vista"
|
||||||
|
|
||||||
#: actions.py:55
|
#: actions.py:58
|
||||||
msgid "Selected bills should be in open state"
|
msgid "Selected bills should be in open state"
|
||||||
msgstr "Les factures seleccionades han d'estar en estat obert"
|
msgstr "Les factures seleccionades han d'estar en estat obert"
|
||||||
|
|
||||||
#: actions.py:73
|
#: actions.py:76
|
||||||
msgid "Selected bills have been closed"
|
msgid "Selected bills have been closed"
|
||||||
msgstr "Les factures seleccionades han estat tancades"
|
msgstr "Les factures seleccionades han estat tancades"
|
||||||
|
|
||||||
#: actions.py:86
|
#: actions.py:89
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
||||||
msgstr "S'ha creat una <a href=\"%(url)s\">transacció</a>"
|
msgstr "S'ha creat una <a href=\"%(url)s\">transacció</a>"
|
||||||
|
|
||||||
#: actions.py:87
|
#: actions.py:90
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
||||||
msgstr "S'han creat les <a href=\"%(url)s\">%(num)i següents transaccions</a>"
|
msgstr "S'han creat les <a href=\"%(url)s\">%(num)i següents transaccions</a>"
|
||||||
|
|
||||||
#: actions.py:93
|
#: actions.py:96
|
||||||
msgid "Are you sure about closing the following bills?"
|
msgid "Are you sure about closing the following bills?"
|
||||||
msgstr "Estàs a punt de tancar les següents factures, estàs segur?"
|
msgstr "Estàs a punt de tancar les següents factures, estàs segur?"
|
||||||
|
|
||||||
#: actions.py:94
|
#: actions.py:97
|
||||||
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"
|
||||||
|
@ -56,138 +56,183 @@ msgstr ""
|
||||||
"Una vegada la factura estigui tancada no podrà ser modificada.</p><p>Si us "
|
"Una vegada la factura estigui tancada no podrà ser modificada.</p><p>Si us "
|
||||||
"plau selecciona un mètode de pagament per les factures seleccionades"
|
"plau selecciona un mètode de pagament per les factures seleccionades"
|
||||||
|
|
||||||
#: actions.py:107
|
#: actions.py:110
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tanca"
|
msgstr "Tanca"
|
||||||
|
|
||||||
#: actions.py:125
|
#: actions.py:124
|
||||||
msgid "One bill has been sent."
|
msgid "One bill has been sent."
|
||||||
msgstr "S'ha creat una factura"
|
msgstr "S'ha creat una factura"
|
||||||
|
|
||||||
#: actions.py:126
|
#: actions.py:125
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%i bills have been sent."
|
msgid "%i bills have been sent."
|
||||||
msgstr "S'han enviat %i factures."
|
msgstr "S'han enviat %i factures."
|
||||||
|
|
||||||
#: actions.py:128
|
#: actions.py:127
|
||||||
msgid "Resend"
|
msgid "Resend"
|
||||||
msgstr "Reenviat"
|
msgstr "Reenviat"
|
||||||
|
|
||||||
#: actions.py:189
|
#: actions.py:188
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(norders)s orders and %(nlines)s lines undoed."
|
msgid "%(norders)s orders and %(nlines)s lines undoed."
|
||||||
msgstr "%(norders)s ordres i %(nlines)s línies desfetes."
|
msgstr "%(norders)s ordres i %(nlines)s línies desfetes."
|
||||||
|
|
||||||
#: actions.py:208
|
#: actions.py:207
|
||||||
msgid "Lines moved"
|
msgid "Lines moved"
|
||||||
msgstr "Línies mogudes"
|
msgstr "Línies mogudes"
|
||||||
|
|
||||||
#: admin.py:49 admin.py:93 admin.py:128 forms.py:11
|
#: actions.py:219
|
||||||
|
msgid "Selected bills should be in closed state"
|
||||||
|
msgstr "Les factures seleccionades han d'estar en estat obert"
|
||||||
|
|
||||||
|
#: actions.py:236
|
||||||
|
#, python-format
|
||||||
|
msgid "%(type)s of %(related_type)s %(number)s and creation date %(date)s"
|
||||||
|
msgstr "%(type)s de %(related_type)s %(number)s amb data de creació %(date)s"
|
||||||
|
|
||||||
|
#: actions.py:243
|
||||||
|
#, python-format
|
||||||
|
msgid "%(related_type)s %(number)s subtotal for tax %(tax)s%%"
|
||||||
|
msgstr "%(related_type)s %(number)s subtotal %(tax)s%%"
|
||||||
|
|
||||||
|
#: actions.py:259
|
||||||
|
#, python-format
|
||||||
|
msgid "<a href=\"%(url)s\">One amendment bill</a> have been generated."
|
||||||
|
msgstr "S'ha creat una <a href=\"%(url)s\">transacció</a>"
|
||||||
|
|
||||||
|
#: actions.py:260
|
||||||
|
#, python-format
|
||||||
|
msgid "<a href=\"%(url)s\">%(num)i amendment bills</a> have been generated."
|
||||||
|
msgstr "S'han creat les <a href=\"%(url)s\">%(num)i següents transaccions</a>"
|
||||||
|
|
||||||
|
#: actions.py:263
|
||||||
|
msgid "Amend"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:54 admin.py:98 admin.py:133 forms.py:11
|
||||||
|
#: templates/admin/bills/report.html:43
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
|
||||||
#: admin.py:80
|
#: admin.py:85
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
#: admin.py:88
|
#: admin.py:93
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Subtotal"
|
msgstr "Subtotal"
|
||||||
|
|
||||||
#: admin.py:118
|
#: admin.py:123
|
||||||
msgid "Is open"
|
msgid "Is open"
|
||||||
msgstr "És oberta"
|
msgstr "És oberta"
|
||||||
|
|
||||||
#: admin.py:123
|
#: admin.py:128
|
||||||
msgid "Subline"
|
msgid "Subline"
|
||||||
msgstr "Sublínia"
|
msgstr "Sublínia"
|
||||||
|
|
||||||
#: admin.py:157
|
#: admin.py:162
|
||||||
msgid "No bills selected."
|
msgid "No bills selected."
|
||||||
msgstr "No hi ha factures seleccionades"
|
msgstr "No hi ha factures seleccionades"
|
||||||
|
|
||||||
#: admin.py:164
|
#: admin.py:169
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Manage %s bill lines."
|
msgid "Manage %s bill lines."
|
||||||
msgstr "Gestiona %s línies de factura."
|
msgstr "Gestiona %s línies de factura."
|
||||||
|
|
||||||
#: admin.py:166
|
#: admin.py:171
|
||||||
msgid "Bill not in open state."
|
msgid "Bill not in open state."
|
||||||
msgstr "La factura no està en estat obert"
|
msgstr "La factura no està en estat obert"
|
||||||
|
|
||||||
#: admin.py:169
|
#: admin.py:174
|
||||||
msgid "Not all bills are in open state."
|
msgid "Not all bills are in open state."
|
||||||
msgstr "No totes les factures estan en estat obert"
|
msgstr "No totes les factures estan en estat obert"
|
||||||
|
|
||||||
#: admin.py:170
|
#: admin.py:175
|
||||||
msgid "Manage bill lines of multiple bills."
|
msgid "Manage bill lines of multiple bills."
|
||||||
msgstr "Gestiona línies de factura de multiples factures."
|
msgstr "Gestiona línies de factura de multiples factures."
|
||||||
|
|
||||||
#: admin.py:190
|
#: admin.py:195
|
||||||
msgid "Raw"
|
msgid "Raw"
|
||||||
msgstr "Raw"
|
msgstr "Raw"
|
||||||
|
|
||||||
#: admin.py:208
|
#: admin.py:214 models.py:72
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "Creada"
|
msgstr "Creada"
|
||||||
|
|
||||||
#: admin.py:213
|
#: admin.py:220
|
||||||
msgid "lines"
|
msgid "lines"
|
||||||
msgstr "línies"
|
msgstr "línies"
|
||||||
|
|
||||||
#: admin.py:218 templates/bills/microspective.html:118
|
#: admin.py:225 filters.py:44 templates/bills/microspective.html:118
|
||||||
msgid "total"
|
msgid "total"
|
||||||
msgstr "total"
|
msgstr "total"
|
||||||
|
|
||||||
#: admin.py:226 models.py:88 models.py:352
|
#: admin.py:233 models.py:103 models.py:446
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr "tipus"
|
msgstr "tipus"
|
||||||
|
|
||||||
#: admin.py:243
|
#: admin.py:250
|
||||||
msgid "Payment"
|
msgid "Payment"
|
||||||
msgstr "Pagament"
|
msgstr "Pagament"
|
||||||
|
|
||||||
#: filters.py:17
|
#: filters.py:19
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tot"
|
msgstr "Tot"
|
||||||
|
|
||||||
#: filters.py:18 models.py:78
|
#: filters.py:20 models.py:87
|
||||||
msgid "Invoice"
|
msgid "Invoice"
|
||||||
msgstr "Factura"
|
msgstr "Factura"
|
||||||
|
|
||||||
#: filters.py:19 models.py:79
|
#: filters.py:21 models.py:88
|
||||||
msgid "Amendment invoice"
|
msgid "Amendment invoice"
|
||||||
msgstr "Factura rectificativa"
|
msgstr "Factura rectificativa"
|
||||||
|
|
||||||
#: filters.py:20 models.py:80
|
#: filters.py:22 models.py:89
|
||||||
msgid "Fee"
|
msgid "Fee"
|
||||||
msgstr "Quota de soci"
|
msgstr "Quota de soci"
|
||||||
|
|
||||||
#: filters.py:21
|
#: filters.py:23
|
||||||
msgid "Amendment fee"
|
msgid "Amendment fee"
|
||||||
msgstr "Rectificació de quota de soci"
|
msgstr "Rectificació de quota de soci"
|
||||||
|
|
||||||
#: filters.py:22
|
#: filters.py:24
|
||||||
msgid "Pro-forma"
|
msgid "Pro-forma"
|
||||||
msgstr "Pro-forma"
|
msgstr "Pro-forma"
|
||||||
|
|
||||||
#: filters.py:41
|
#: filters.py:66
|
||||||
msgid "positive price"
|
|
||||||
msgstr "preu positiu"
|
|
||||||
|
|
||||||
#: filters.py:46 filters.py:64
|
|
||||||
msgid "Yes"
|
|
||||||
msgstr "Si"
|
|
||||||
|
|
||||||
#: filters.py:47 filters.py:65
|
|
||||||
msgid "No"
|
|
||||||
msgstr "No"
|
|
||||||
|
|
||||||
#: filters.py:59
|
|
||||||
msgid "has bill contact"
|
msgid "has bill contact"
|
||||||
msgstr "té contacte de facturació"
|
msgstr "té contacte de facturació"
|
||||||
|
|
||||||
#: forms.py:9
|
#: filters.py:71
|
||||||
|
msgid "Yes"
|
||||||
|
msgstr "Si"
|
||||||
|
|
||||||
|
#: filters.py:72
|
||||||
|
msgid "No"
|
||||||
|
msgstr "No"
|
||||||
|
|
||||||
|
#: filters.py:83
|
||||||
|
msgid "payment state"
|
||||||
|
msgstr "Pagament"
|
||||||
|
|
||||||
|
#: filters.py:88 models.py:71
|
||||||
|
msgid "Open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:89 models.py:75
|
||||||
|
msgid "Paid"
|
||||||
|
msgstr "Pagat"
|
||||||
|
|
||||||
|
#: filters.py:90
|
||||||
|
msgid "Pending"
|
||||||
|
msgstr "Pendent"
|
||||||
|
|
||||||
|
#: filters.py:91 models.py:78
|
||||||
|
msgid "Bad debt"
|
||||||
|
msgstr "Incobrable"
|
||||||
|
|
||||||
|
#: forms.py:9 templates/admin/bills/report.html:37
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
|
@ -219,7 +264,7 @@ msgstr "Relacionat"
|
||||||
msgid "Main"
|
msgid "Main"
|
||||||
msgstr "Principal"
|
msgstr "Principal"
|
||||||
|
|
||||||
#: models.py:23 models.py:86
|
#: models.py:23 models.py:99
|
||||||
msgid "account"
|
msgid "account"
|
||||||
msgstr "compte"
|
msgstr "compte"
|
||||||
|
|
||||||
|
@ -251,141 +296,186 @@ msgstr "Introdueix un codi postal vàlid."
|
||||||
msgid "country"
|
msgid "country"
|
||||||
msgstr "país"
|
msgstr "país"
|
||||||
|
|
||||||
#: models.py:35
|
#: models.py:35 templates/admin/bills/report.html:38
|
||||||
msgid "VAT number"
|
msgid "VAT number"
|
||||||
msgstr "NIF"
|
msgstr "NIF"
|
||||||
|
|
||||||
#: models.py:67
|
#: models.py:73
|
||||||
msgid "Paid"
|
msgid "Processed"
|
||||||
msgstr "Pagat"
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:68
|
#: models.py:74
|
||||||
msgid "Pending"
|
#, fuzzy
|
||||||
msgstr "Pendent"
|
#| msgid "amended line"
|
||||||
|
msgid "Amended"
|
||||||
|
msgstr "línia rectificada"
|
||||||
|
|
||||||
#: models.py:69
|
#: models.py:76
|
||||||
msgid "Bad debt"
|
msgid "Incomplete"
|
||||||
msgstr "Incobrable"
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:81
|
#: models.py:77
|
||||||
|
msgid "Executed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:90
|
||||||
msgid "Amendment Fee"
|
msgid "Amendment Fee"
|
||||||
msgstr "Rectificació de quota de soci"
|
msgstr "Rectificació de quota de soci"
|
||||||
|
|
||||||
#: models.py:82
|
#: models.py:91
|
||||||
msgid "Pro forma"
|
msgid "Pro forma"
|
||||||
msgstr "Pro forma"
|
msgstr "Pro forma"
|
||||||
|
|
||||||
#: models.py:85
|
#: models.py:98
|
||||||
msgid "number"
|
msgid "number"
|
||||||
msgstr "número"
|
msgstr "número"
|
||||||
|
|
||||||
#: models.py:89
|
#: models.py:101
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "amended line"
|
||||||
|
msgid "amend of"
|
||||||
|
msgstr "línia rectificada"
|
||||||
|
|
||||||
|
#: models.py:104
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "creat el"
|
msgstr "creat el"
|
||||||
|
|
||||||
#: models.py:90
|
#: models.py:105
|
||||||
msgid "closed on"
|
msgid "closed on"
|
||||||
msgstr "tancat el"
|
msgstr "tancat el"
|
||||||
|
|
||||||
#: models.py:91
|
#: models.py:106
|
||||||
msgid "open"
|
msgid "open"
|
||||||
msgstr "obert"
|
msgstr "obert"
|
||||||
|
|
||||||
#: models.py:92
|
#: models.py:107
|
||||||
msgid "sent"
|
msgid "sent"
|
||||||
msgstr "enviat"
|
msgstr "enviat"
|
||||||
|
|
||||||
#: models.py:93
|
#: models.py:108
|
||||||
msgid "due on"
|
msgid "due on"
|
||||||
msgstr "es deu"
|
msgstr "es deu"
|
||||||
|
|
||||||
#: models.py:94
|
#: models.py:109
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "actualitzada el"
|
msgstr "actualitzada el"
|
||||||
|
|
||||||
#: models.py:97
|
#: models.py:112
|
||||||
msgid "comments"
|
msgid "comments"
|
||||||
msgstr "comentaris"
|
msgstr "comentaris"
|
||||||
|
|
||||||
#: models.py:98
|
#: models.py:113
|
||||||
msgid "HTML"
|
msgid "HTML"
|
||||||
msgstr "HTML"
|
msgstr "HTML"
|
||||||
|
|
||||||
#: models.py:285
|
#: models.py:192
|
||||||
|
#, python-format
|
||||||
|
msgid "Type %s is not an amendment."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:194
|
||||||
|
msgid "Amend of related account doesn't match bill account."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:199
|
||||||
|
#, python-format
|
||||||
|
msgid "Type %s requires an amend of link."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:378
|
||||||
msgid "bill"
|
msgid "bill"
|
||||||
msgstr "factura"
|
msgstr "factura"
|
||||||
|
|
||||||
#: models.py:286 models.py:350 templates/bills/microspective.html:73
|
#: models.py:379 models.py:444 templates/bills/microspective.html:73
|
||||||
msgid "description"
|
msgid "description"
|
||||||
msgstr "descripció"
|
msgstr "descripció"
|
||||||
|
|
||||||
#: models.py:287
|
#: models.py:380
|
||||||
msgid "rate"
|
msgid "rate"
|
||||||
msgstr "tarifa"
|
msgstr "tarifa"
|
||||||
|
|
||||||
#: models.py:288
|
#: models.py:381
|
||||||
msgid "quantity"
|
msgid "quantity"
|
||||||
msgstr "quantitat"
|
msgstr "quantitat"
|
||||||
|
|
||||||
#: models.py:289
|
#: models.py:383
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "quantity"
|
#| msgid "quantity"
|
||||||
msgid "Verbose quantity"
|
msgid "Verbose quantity"
|
||||||
msgstr "quantitat"
|
msgstr "quantitat"
|
||||||
|
|
||||||
#: models.py:290 templates/bills/microspective.html:77
|
#: models.py:384 templates/bills/microspective.html:77
|
||||||
#: templates/bills/microspective.html:111
|
#: templates/bills/microspective.html:111
|
||||||
msgid "subtotal"
|
msgid "subtotal"
|
||||||
msgstr "subtotal"
|
msgstr "subtotal"
|
||||||
|
|
||||||
#: models.py:291
|
#: models.py:385
|
||||||
msgid "tax"
|
msgid "tax"
|
||||||
msgstr "impostos"
|
msgstr "impostos"
|
||||||
|
|
||||||
#: models.py:292
|
#: models.py:386
|
||||||
msgid "start"
|
msgid "start"
|
||||||
msgstr "iniciar"
|
msgstr "iniciar"
|
||||||
|
|
||||||
#: models.py:293
|
#: models.py:387
|
||||||
msgid "end"
|
msgid "end"
|
||||||
msgstr "finalitzar"
|
msgstr "finalitzar"
|
||||||
|
|
||||||
#: models.py:295
|
#: models.py:389
|
||||||
msgid "Informative link back to the order"
|
msgid "Informative link back to the order"
|
||||||
msgstr "Enllaç informatiu de l'ordre"
|
msgstr "Enllaç informatiu de l'ordre"
|
||||||
|
|
||||||
#: models.py:296
|
#: models.py:390
|
||||||
msgid "order billed"
|
msgid "order billed"
|
||||||
msgstr "ordre facturada"
|
msgstr "ordre facturada"
|
||||||
|
|
||||||
#: models.py:297
|
#: models.py:391
|
||||||
msgid "order billed until"
|
msgid "order billed until"
|
||||||
msgstr "ordre facturada fins a"
|
msgstr "ordre facturada fins a"
|
||||||
|
|
||||||
#: models.py:298
|
#: models.py:392
|
||||||
msgid "created"
|
msgid "created"
|
||||||
msgstr "creada"
|
msgstr "creada"
|
||||||
|
|
||||||
#: models.py:300
|
#: models.py:394
|
||||||
msgid "amended line"
|
msgid "amended line"
|
||||||
msgstr "línia rectificada"
|
msgstr "línia rectificada"
|
||||||
|
|
||||||
#: models.py:343
|
#: models.py:437
|
||||||
msgid "Volume"
|
msgid "Volume"
|
||||||
msgstr "Volum"
|
msgstr "Volum"
|
||||||
|
|
||||||
#: models.py:344
|
#: models.py:438
|
||||||
msgid "Compensation"
|
msgid "Compensation"
|
||||||
msgstr "Compensació"
|
msgstr "Compensació"
|
||||||
|
|
||||||
#: models.py:345
|
#: models.py:439
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr "Altre"
|
msgstr "Altre"
|
||||||
|
|
||||||
#: models.py:349
|
#: models.py:443
|
||||||
msgid "bill line"
|
msgid "bill line"
|
||||||
msgstr "línia de factura"
|
msgstr "línia de factura"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:39
|
||||||
|
msgid "Contact"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:40
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Due date"
|
||||||
|
msgid "Close date"
|
||||||
|
msgstr "Data de pagament"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:41
|
||||||
|
msgid "Base"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:42 templates/bills/microspective.html:111
|
||||||
|
#: templates/bills/microspective.html:114
|
||||||
|
msgid "VAT"
|
||||||
|
msgstr "IVA"
|
||||||
|
|
||||||
#: templates/bills/microspective-fee.html:107
|
#: templates/bills/microspective-fee.html:107
|
||||||
msgid "Due date"
|
msgid "Due date"
|
||||||
msgstr "Data de pagament"
|
msgstr "Data de pagament"
|
||||||
|
@ -433,11 +523,6 @@ msgstr "hrs/qnt"
|
||||||
msgid "rate/price"
|
msgid "rate/price"
|
||||||
msgstr "tarifa/preu"
|
msgstr "tarifa/preu"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:111
|
|
||||||
#: templates/bills/microspective.html:114
|
|
||||||
msgid "VAT"
|
|
||||||
msgstr "IVA"
|
|
||||||
|
|
||||||
#: templates/bills/microspective.html:114
|
#: templates/bills/microspective.html:114
|
||||||
msgid "taxes"
|
msgid "taxes"
|
||||||
msgstr "impostos"
|
msgstr "impostos"
|
||||||
|
@ -451,6 +536,7 @@ msgid "PAYMENT"
|
||||||
msgstr "PAGAMENT"
|
msgstr "PAGAMENT"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:140
|
#: templates/bills/microspective.html:140
|
||||||
|
#, python-format
|
||||||
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"
|
||||||
|
@ -483,3 +569,6 @@ msgstr ""
|
||||||
" contacta amb nosaltres a %(email)s. Et respondrem el més "
|
" contacta amb nosaltres a %(email)s. Et respondrem el més "
|
||||||
"ràpidament possible.\n"
|
"ràpidament possible.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
|
#~ msgid "positive price"
|
||||||
|
#~ msgstr "preu positiu"
|
||||||
|
|
Binary file not shown.
|
@ -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-28 12:31+0000\n"
|
"POT-Creation-Date: 2015-07-07 10:10+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"
|
||||||
|
@ -18,37 +18,37 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: actions.py:37
|
#: actions.py:40
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Descarga"
|
msgstr "Descarga"
|
||||||
|
|
||||||
#: actions.py:47
|
#: actions.py:50
|
||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Vista"
|
msgstr "Vista"
|
||||||
|
|
||||||
#: actions.py:55
|
#: actions.py:58
|
||||||
msgid "Selected bills should be in open state"
|
msgid "Selected bills should be in open state"
|
||||||
msgstr "Las facturas seleccionadas están en estado abierto"
|
msgstr "Las facturas seleccionadas están en estado abierto"
|
||||||
|
|
||||||
#: actions.py:73
|
#: actions.py:76
|
||||||
msgid "Selected bills have been closed"
|
msgid "Selected bills have been closed"
|
||||||
msgstr "Las facturas seleccionadas han sido cerradas"
|
msgstr "Las facturas seleccionadas han sido cerradas"
|
||||||
|
|
||||||
#: actions.py:86
|
#: actions.py:89
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
msgid "<a href=\"%(url)s\">One related transaction</a> has been created"
|
||||||
msgstr "Se ha creado una <a href=\"%(url)s\">transacción</a>"
|
msgstr "Se ha creado una <a href=\"%(url)s\">transacción</a>"
|
||||||
|
|
||||||
#: actions.py:87
|
#: actions.py:90
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
msgid "<a href=\"%(url)s\">%(num)i related transactions</a> have been created"
|
||||||
msgstr "Se han creado <a href=\"%(url)s\">%(num)i transacciones</a>"
|
msgstr "Se han creado <a href=\"%(url)s\">%(num)i transacciones</a>"
|
||||||
|
|
||||||
#: actions.py:93
|
#: actions.py:96
|
||||||
msgid "Are you sure about closing the following bills?"
|
msgid "Are you sure about closing the following bills?"
|
||||||
msgstr "Estás a punto de cerrar las sigüientes facturas. ¿Estás seguro?"
|
msgstr "Estás a punto de cerrar las sigüientes facturas. ¿Estás seguro?"
|
||||||
|
|
||||||
#: actions.py:94
|
#: actions.py:97
|
||||||
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"
|
||||||
|
@ -56,138 +56,180 @@ msgstr ""
|
||||||
"Una vez cerrada la factura ya no se podrá modificar.</p><p>Por favor "
|
"Una vez cerrada la factura ya no se podrá modificar.</p><p>Por favor "
|
||||||
"seleciona un metodo de pago para las facturas seleccionadas"
|
"seleciona un metodo de pago para las facturas seleccionadas"
|
||||||
|
|
||||||
#: actions.py:107
|
#: actions.py:110
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Cerrar"
|
msgstr "Cerrar"
|
||||||
|
|
||||||
#: actions.py:125
|
#: actions.py:124
|
||||||
msgid "One bill has been sent."
|
msgid "One bill has been sent."
|
||||||
msgstr "Se ha enviado una factura"
|
msgstr "Se ha enviado una factura"
|
||||||
|
|
||||||
#: actions.py:126
|
#: actions.py:125
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%i bills have been sent."
|
msgid "%i bills have been sent."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:128
|
#: actions.py:127
|
||||||
msgid "Resend"
|
msgid "Resend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: actions.py:189
|
#: actions.py:188
|
||||||
#, 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:208
|
#: actions.py:207
|
||||||
msgid "Lines moved"
|
msgid "Lines moved"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:49 admin.py:93 admin.py:128 forms.py:11
|
#: actions.py:219
|
||||||
|
msgid "Selected bills should be in closed state"
|
||||||
|
msgstr "Las facturas seleccionadas están en estado abierto"
|
||||||
|
|
||||||
|
#: actions.py:236
|
||||||
|
#, python-format
|
||||||
|
msgid "%(type)s of %(related_type)s %(number)s and creation date %(date)s"
|
||||||
|
msgstr "%(type)s de %(related_type)s %(number)s con fecha de creación %(date)s"
|
||||||
|
|
||||||
|
#: actions.py:243
|
||||||
|
msgid "%(related_type)s %(number)s subtotal for tax %(tax)s%%"
|
||||||
|
msgstr "%(related_type)s %(number)s subtotal %(tax)s%%"
|
||||||
|
|
||||||
|
#: actions.py:255
|
||||||
|
msgid "<a href=\"%(url)s\">One amendment bill</a> have been generated."
|
||||||
|
msgstr "Se ha creado una <a href=\"%(url)s\">transacción</a>"
|
||||||
|
|
||||||
|
#: actions.py:256
|
||||||
|
msgid "<a href=\"%(url)s\">%(num)i amendment bills</a> have been generated."
|
||||||
|
msgstr "Se han creado <a href=\"%(url)s\">%(num)i transacciones</a>"
|
||||||
|
|
||||||
|
#: actions.py:259
|
||||||
|
msgid "Amend"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: admin.py:54 admin.py:98 admin.py:133 forms.py:11
|
||||||
|
#: templates/admin/bills/report.html:43
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:80
|
#: admin.py:85
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:88
|
#: admin.py:93
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:118
|
#: admin.py:123
|
||||||
msgid "Is open"
|
msgid "Is open"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:123
|
#: admin.py:128
|
||||||
msgid "Subline"
|
msgid "Subline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:157
|
#: admin.py:162
|
||||||
msgid "No bills selected."
|
msgid "No bills selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:164
|
#: admin.py:169
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Manage %s bill lines."
|
msgid "Manage %s bill lines."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:166
|
#: admin.py:171
|
||||||
msgid "Bill not in open state."
|
msgid "Bill not in open state."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:169
|
#: admin.py:174
|
||||||
msgid "Not all bills are in open state."
|
msgid "Not all bills are in open state."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:170
|
#: admin.py:175
|
||||||
msgid "Manage bill lines of multiple bills."
|
msgid "Manage bill lines of multiple bills."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:190
|
#: admin.py:195
|
||||||
msgid "Raw"
|
msgid "Raw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:208
|
#: admin.py:214 models.py:72
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:213
|
#: admin.py:220
|
||||||
msgid "lines"
|
msgid "lines"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:218 templates/bills/microspective.html:118
|
#: admin.py:225 filters.py:44 templates/bills/microspective.html:118
|
||||||
msgid "total"
|
msgid "total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:226 models.py:88 models.py:352
|
#: admin.py:233 models.py:103 models.py:446
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:243
|
#: admin.py:250
|
||||||
msgid "Payment"
|
msgid "Payment"
|
||||||
msgstr "Pago"
|
msgstr "Pago"
|
||||||
|
|
||||||
#: filters.py:17
|
#: filters.py:19
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: filters.py:18 models.py:78
|
#: filters.py:20 models.py:87
|
||||||
msgid "Invoice"
|
msgid "Invoice"
|
||||||
msgstr "Factura"
|
msgstr "Factura"
|
||||||
|
|
||||||
#: filters.py:19 models.py:79
|
#: filters.py:21 models.py:88
|
||||||
msgid "Amendment invoice"
|
msgid "Amendment invoice"
|
||||||
msgstr "Factura rectificative"
|
msgstr "Factura rectificative"
|
||||||
|
|
||||||
#: filters.py:20 models.py:80
|
#: filters.py:22 models.py:89
|
||||||
msgid "Fee"
|
msgid "Fee"
|
||||||
msgstr "Quota de socio"
|
msgstr "Quota de socio"
|
||||||
|
|
||||||
#: filters.py:21
|
#: filters.py:23
|
||||||
msgid "Amendment fee"
|
msgid "Amendment fee"
|
||||||
msgstr "Quota rectificativa"
|
msgstr "Quota rectificativa"
|
||||||
|
|
||||||
#: filters.py:22
|
#: filters.py:24
|
||||||
msgid "Pro-forma"
|
msgid "Pro-forma"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: filters.py:41
|
#: filters.py:66
|
||||||
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"
|
msgid "has bill contact"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:9
|
#: filters.py:71
|
||||||
|
msgid "Yes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:72
|
||||||
|
msgid "No"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:83
|
||||||
|
msgid "payment state"
|
||||||
|
msgstr "Pago"
|
||||||
|
|
||||||
|
#: filters.py:88 models.py:71
|
||||||
|
msgid "Open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:89 models.py:75
|
||||||
|
msgid "Paid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:90
|
||||||
|
msgid "Pending"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: filters.py:91 models.py:78
|
||||||
|
msgid "Bad debt"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:9 templates/admin/bills/report.html:37
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -217,7 +259,7 @@ msgstr ""
|
||||||
msgid "Main"
|
msgid "Main"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:23 models.py:86
|
#: models.py:23 models.py:99
|
||||||
msgid "account"
|
msgid "account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -249,138 +291,179 @@ msgstr ""
|
||||||
msgid "country"
|
msgid "country"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:35
|
#: models.py:35 templates/admin/bills/report.html:38
|
||||||
msgid "VAT number"
|
msgid "VAT number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:67
|
#: models.py:73
|
||||||
msgid "Paid"
|
msgid "Processed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:68
|
#: models.py:74
|
||||||
msgid "Pending"
|
msgid "Amended"
|
||||||
|
msgstr "Quota rectificativa"
|
||||||
|
|
||||||
|
#: models.py:76
|
||||||
|
msgid "Incomplete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:69
|
#: models.py:77
|
||||||
msgid "Bad debt"
|
msgid "Executed"
|
||||||
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 ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:90
|
#: models.py:90
|
||||||
msgid "closed on"
|
msgid "Amendment Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:91
|
#: models.py:91
|
||||||
msgid "open"
|
msgid "Pro forma"
|
||||||
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 ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:98
|
#: models.py:98
|
||||||
|
msgid "number"
|
||||||
|
msgstr "número"
|
||||||
|
|
||||||
|
#: models.py:101
|
||||||
|
msgid "amend of"
|
||||||
|
msgstr "rectificación de"
|
||||||
|
|
||||||
|
#: models.py:104
|
||||||
|
msgid "created on"
|
||||||
|
msgstr "creado en"
|
||||||
|
|
||||||
|
#: models.py:105
|
||||||
|
msgid "closed on"
|
||||||
|
msgstr "cerrada en"
|
||||||
|
|
||||||
|
#: models.py:106
|
||||||
|
msgid "open"
|
||||||
|
msgstr "abierta"
|
||||||
|
|
||||||
|
#: models.py:107
|
||||||
|
msgid "sent"
|
||||||
|
msgstr "enviada"
|
||||||
|
|
||||||
|
#: models.py:108
|
||||||
|
msgid "due on"
|
||||||
|
msgstr "vencimiento"
|
||||||
|
|
||||||
|
#: models.py:109
|
||||||
|
msgid "updated on"
|
||||||
|
msgstr "actualizada en"
|
||||||
|
|
||||||
|
#: models.py:112
|
||||||
|
msgid "comments"
|
||||||
|
msgstr "comentarios"
|
||||||
|
|
||||||
|
#: models.py:113
|
||||||
msgid "HTML"
|
msgid "HTML"
|
||||||
|
msgstr "HTML"
|
||||||
|
|
||||||
|
#: models.py:192
|
||||||
|
#, python-format
|
||||||
|
msgid "Type %s is not an amendment."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:285
|
#: models.py:194
|
||||||
|
msgid "Amend of related account doesn't match bill account."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:199
|
||||||
|
#, python-format
|
||||||
|
msgid "Type %s requires an amend of link."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: models.py:378
|
||||||
msgid "bill"
|
msgid "bill"
|
||||||
msgstr ""
|
msgstr "factura"
|
||||||
|
|
||||||
#: models.py:286 models.py:350 templates/bills/microspective.html:73
|
#: models.py:379 models.py:444 templates/bills/microspective.html:73
|
||||||
msgid "description"
|
msgid "description"
|
||||||
msgstr ""
|
msgstr "descripción"
|
||||||
|
|
||||||
#: models.py:287
|
#: models.py:380
|
||||||
msgid "rate"
|
msgid "rate"
|
||||||
msgstr ""
|
msgstr "tarifa"
|
||||||
|
|
||||||
#: models.py:288
|
#: models.py:381
|
||||||
msgid "quantity"
|
msgid "quantity"
|
||||||
msgstr ""
|
msgstr "cantidad"
|
||||||
|
|
||||||
#: models.py:289
|
#: models.py:383
|
||||||
msgid "Verbose quantity"
|
msgid "Verbose quantity"
|
||||||
msgstr ""
|
msgstr "Cantidad"
|
||||||
|
|
||||||
#: models.py:290 templates/bills/microspective.html:77
|
#: models.py:384 templates/bills/microspective.html:77
|
||||||
#: templates/bills/microspective.html:111
|
#: templates/bills/microspective.html:111
|
||||||
msgid "subtotal"
|
msgid "subtotal"
|
||||||
msgstr ""
|
msgstr "subtotal"
|
||||||
|
|
||||||
#: models.py:291
|
#: models.py:385
|
||||||
msgid "tax"
|
msgid "tax"
|
||||||
msgstr ""
|
msgstr "impuesto"
|
||||||
|
|
||||||
#: models.py:292
|
#: models.py:386
|
||||||
msgid "start"
|
msgid "start"
|
||||||
msgstr ""
|
msgstr "inicio"
|
||||||
|
|
||||||
#: models.py:293
|
#: models.py:387
|
||||||
msgid "end"
|
msgid "end"
|
||||||
msgstr ""
|
msgstr "fín"
|
||||||
|
|
||||||
#: models.py:295
|
#: models.py:389
|
||||||
msgid "Informative link back to the order"
|
msgid "Informative link back to the order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:296
|
#: models.py:390
|
||||||
msgid "order billed"
|
msgid "order billed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:297
|
#: models.py:391
|
||||||
msgid "order billed until"
|
msgid "order billed until"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:298
|
#: models.py:392
|
||||||
msgid "created"
|
msgid "created"
|
||||||
msgstr ""
|
msgstr "creado"
|
||||||
|
|
||||||
#: models.py:300
|
#: models.py:394
|
||||||
msgid "amended line"
|
msgid "amended line"
|
||||||
msgstr ""
|
msgstr "linea rectificativa"
|
||||||
|
|
||||||
#: models.py:343
|
#: models.py:437
|
||||||
msgid "Volume"
|
msgid "Volume"
|
||||||
msgstr ""
|
msgstr "Volumen"
|
||||||
|
|
||||||
#: models.py:344
|
#: models.py:438
|
||||||
msgid "Compensation"
|
msgid "Compensation"
|
||||||
msgstr ""
|
msgstr "Compensación"
|
||||||
|
|
||||||
#: models.py:345
|
#: models.py:439
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr ""
|
msgstr "Otro"
|
||||||
|
|
||||||
#: models.py:349
|
#: models.py:443
|
||||||
msgid "bill line"
|
msgid "bill line"
|
||||||
msgstr ""
|
msgstr "linea de factura"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:39
|
||||||
|
msgid "Contact"
|
||||||
|
msgstr "Contacto"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:40
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Due date"
|
||||||
|
msgid "Close date"
|
||||||
|
msgstr "Fecha de pago"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:41
|
||||||
|
msgid "Base"
|
||||||
|
msgstr "Base"
|
||||||
|
|
||||||
|
#: templates/admin/bills/report.html:42 templates/bills/microspective.html:111
|
||||||
|
#: templates/bills/microspective.html:114
|
||||||
|
msgid "VAT"
|
||||||
|
msgstr "IVA"
|
||||||
|
|
||||||
#: templates/bills/microspective-fee.html:107
|
#: templates/bills/microspective-fee.html:107
|
||||||
msgid "Due date"
|
msgid "Due date"
|
||||||
|
@ -427,11 +510,6 @@ msgstr "hrs/cant"
|
||||||
msgid "rate/price"
|
msgid "rate/price"
|
||||||
msgstr "tarifa/precio"
|
msgstr "tarifa/precio"
|
||||||
|
|
||||||
#: templates/bills/microspective.html:111
|
|
||||||
#: templates/bills/microspective.html:114
|
|
||||||
msgid "VAT"
|
|
||||||
msgstr "IVA"
|
|
||||||
|
|
||||||
#: templates/bills/microspective.html:114
|
#: templates/bills/microspective.html:114
|
||||||
msgid "taxes"
|
msgid "taxes"
|
||||||
msgstr "impuestos"
|
msgstr "impuestos"
|
||||||
|
|
|
@ -90,6 +90,10 @@ class Bill(models.Model):
|
||||||
(AMENDMENTFEE, _("Amendment Fee")),
|
(AMENDMENTFEE, _("Amendment Fee")),
|
||||||
(PROFORMA, _("Pro forma")),
|
(PROFORMA, _("Pro forma")),
|
||||||
)
|
)
|
||||||
|
AMEND_MAP = {
|
||||||
|
INVOICE: AMENDMENTINVOICE,
|
||||||
|
FEE: AMENDMENTFEE,
|
||||||
|
}
|
||||||
|
|
||||||
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
|
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||||
|
@ -181,6 +185,24 @@ class Bill(models.Model):
|
||||||
return self.EXECUTED
|
return self.EXECUTED
|
||||||
return self.BAD_DEBT
|
return self.BAD_DEBT
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if self.amend_of_id:
|
||||||
|
errors = {}
|
||||||
|
if self.type not in self.AMEND_MAP.values():
|
||||||
|
errors['amend_of'] = _("Type %s is not an amendment.") % self.get_type_display()
|
||||||
|
if self.amend_of.account_id != self.account_id:
|
||||||
|
errors['account'] = _("Amend of related account doesn't match bill account.")
|
||||||
|
if self.amend_of.is_open:
|
||||||
|
errors['amend_of'] = _("Related invoice is in open state.")
|
||||||
|
if self.amend_of.type in self.AMEND_MAP.values():
|
||||||
|
errors['amend_of'] = _("Related invoice is an amendment.")
|
||||||
|
if errors:
|
||||||
|
raise ValidationError(errors)
|
||||||
|
elif self.type in self.AMEND_MAP.values():
|
||||||
|
raise ValidationError({
|
||||||
|
'amend_of': _("Type %s requires an amend of link.") % self.get_type_display()
|
||||||
|
})
|
||||||
|
|
||||||
def get_total(self):
|
def get_total(self):
|
||||||
if not self.is_open:
|
if not self.is_open:
|
||||||
return self.total
|
return self.total
|
||||||
|
@ -201,11 +223,7 @@ class Bill(models.Model):
|
||||||
return self.type or self.get_class_type()
|
return self.type or self.get_class_type()
|
||||||
|
|
||||||
def get_amend_type(self):
|
def get_amend_type(self):
|
||||||
amend_map = {
|
amend_type = self.AMEND_MAP.get(self.type)
|
||||||
self.INVOICE: self.AMENDMENTINVOICE,
|
|
||||||
self.FEE: self.AMENDMENTFEE,
|
|
||||||
}
|
|
||||||
amend_type = amend_map.get(self.type)
|
|
||||||
if amend_type is None:
|
if amend_type is None:
|
||||||
raise TypeError("%s has no associated amend type." % self.type)
|
raise TypeError("%s has no associated amend type." % self.type)
|
||||||
return amend_type
|
return amend_type
|
||||||
|
@ -321,10 +339,17 @@ class Bill(models.Model):
|
||||||
subtotals[tax] = (subtotal, round(tax/100*subtotal, 2))
|
subtotals[tax] = (subtotal, round(tax/100*subtotal, 2))
|
||||||
return subtotals
|
return subtotals
|
||||||
|
|
||||||
|
def compute_base(self):
|
||||||
|
bases = self.lines.annotate(
|
||||||
|
bases=F('subtotal') + Coalesce(F('sublines__total'), 0)
|
||||||
|
)
|
||||||
|
return round(bases.aggregate(Sum('bases'))['bases__sum'] or 0, 2)
|
||||||
|
|
||||||
def compute_total(self):
|
def compute_total(self):
|
||||||
totals = self.lines.annotate(
|
totals = self.lines.annotate(
|
||||||
totals=(F('subtotal') + Coalesce(F('sublines__total'), 0)) * (1+F('tax')/100))
|
totals=(F('subtotal') + Coalesce(F('sublines__total'), 0)) * (1+F('tax')/100)
|
||||||
return round(totals.aggregate(Sum('totals'))['totals__sum'], 2)
|
)
|
||||||
|
return round(totals.aggregate(Sum('totals'))['totals__sum'] or 0, 2)
|
||||||
|
|
||||||
|
|
||||||
class Invoice(Bill):
|
class Invoice(Bill):
|
||||||
|
@ -363,7 +388,7 @@ class BillLine(models.Model):
|
||||||
subtotal = models.DecimalField(_("subtotal"), max_digits=12, decimal_places=2)
|
subtotal = models.DecimalField(_("subtotal"), max_digits=12, decimal_places=2)
|
||||||
tax = models.DecimalField(_("tax"), max_digits=4, decimal_places=2)
|
tax = models.DecimalField(_("tax"), max_digits=4, decimal_places=2)
|
||||||
start_on = models.DateField(_("start"))
|
start_on = models.DateField(_("start"))
|
||||||
end_on = models.DateField(_("end"), null=True)
|
end_on = models.DateField(_("end"), null=True, blank=True)
|
||||||
order = models.ForeignKey(settings.BILLS_ORDER_MODEL, null=True, blank=True,
|
order = models.ForeignKey(settings.BILLS_ORDER_MODEL, null=True, blank=True,
|
||||||
help_text=_("Informative link back to the order"), on_delete=models.SET_NULL)
|
help_text=_("Informative link back to the order"), on_delete=models.SET_NULL)
|
||||||
order_billed_on = models.DateField(_("order billed"), null=True, blank=True)
|
order_billed_on = models.DateField(_("order billed"), null=True, blank=True)
|
||||||
|
|
60
orchestra/contrib/bills/templates/admin/bills/report.html
Normal file
60
orchestra/contrib/bills/templates/admin/bills/report.html
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
{% load i18n utils %}
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Bill 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;
|
||||||
|
}
|
||||||
|
.item.column-base, .item.column-vat, .item.column-total, .item.column-number {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.column-vat-number {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr id="transaction">
|
||||||
|
<th class="title column-number">{% trans "Number" %}</th>
|
||||||
|
<th class="title column-vat-number">{% trans "VAT number" %}</th>
|
||||||
|
<th class="title column-billcontant">{% trans "Contact" %}</th>
|
||||||
|
<th class="title column-date">{% trans "Close date" %}</th>
|
||||||
|
<th class="title column-base">{% trans "Base" %}</th>
|
||||||
|
<th class="title column-vat">{% trans "VAT" %}</th>
|
||||||
|
<th class="title column-total">{% trans "Total" %}</th>
|
||||||
|
</tr>
|
||||||
|
{% for bill in bills %}
|
||||||
|
<tr>
|
||||||
|
<td class="item column-number">{{ bill.number }}</td>
|
||||||
|
<td class="item column-vat-number">{{ bill.buyer.vat }}</td>
|
||||||
|
<td class="item column-billcontant">{{ bill.buyer.get_name }}</td>
|
||||||
|
<td class="item column-date">{{ bill.closed_on|date }}</td>
|
||||||
|
{% with base=bill.compute_base total=bill.compute_total %}
|
||||||
|
<td class="item column-base">{{ base }} &{{ currency }};</td>
|
||||||
|
<td class="item column-vat">{{ total|sub:base }} &{{ currency }};</td>
|
||||||
|
<td class="item column-total">{{ total }} &{{ currency }};</td>
|
||||||
|
{% endwith %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,7 +4,7 @@ from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from .utils import normurlpath
|
from .utils import normurlpath
|
||||||
from .validators import validate_domain_protocol
|
from .validators import validate_domain_protocol, validate_server_name
|
||||||
|
|
||||||
|
|
||||||
class WebsiteAdminForm(forms.ModelForm):
|
class WebsiteAdminForm(forms.ModelForm):
|
||||||
|
@ -15,12 +15,16 @@ class WebsiteAdminForm(forms.ModelForm):
|
||||||
if not domains:
|
if not domains:
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
protocol = self.cleaned_data.get('protocol')
|
protocol = self.cleaned_data.get('protocol')
|
||||||
for domain in domains.all():
|
domains = domains.all()
|
||||||
|
for domain in domains:
|
||||||
try:
|
try:
|
||||||
validate_domain_protocol(self.instance, domain, protocol)
|
validate_domain_protocol(self.instance, domain, protocol)
|
||||||
except ValidationError as e:
|
except ValidationError as err:
|
||||||
# TODO not sure about this one
|
self.add_error(None, err)
|
||||||
self.add_error(None, e)
|
try:
|
||||||
|
validate_server_name(domains)
|
||||||
|
except ValidationError as err:
|
||||||
|
self.add_error('domains', err)
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,3 +28,11 @@ def validate_domain_protocol(website, domain, protocol):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'domains': 'A website is already defined for "%s" on protocol %s' % (domain, protocol),
|
'domains': 'A website is already defined for "%s" on protocol %s' % (domain, protocol),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def validate_server_name(domains):
|
||||||
|
if domains:
|
||||||
|
for domain in domains:
|
||||||
|
if not domain.name.startswith('*'):
|
||||||
|
return
|
||||||
|
raise ValidationError(_("At least one non-wildcard domain should be provided."))
|
||||||
|
|
|
@ -96,3 +96,7 @@ def admin_url(obj):
|
||||||
def isactive(obj):
|
def isactive(obj):
|
||||||
return getattr(obj, 'is_active', True)
|
return getattr(obj, 'is_active', True)
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def sub(value, arg):
|
||||||
|
return value - arg
|
||||||
|
|
Loading…
Reference in a new issue