diff --git a/TODO.md b/TODO.md
index 7034a32c..bd8b5f31 100644
--- a/TODO.md
+++ b/TODO.md
@@ -89,6 +89,4 @@ at + clock time, midnight, noon- At 3:30 p.m., At 4:01, At noon
* help_text on readonly_fields specialy Bill.state. (eg. A bill is in OPEN state when bla bla )
-* Account link and "show all" button on the filters secction instead of object-tools
-
* Create ProForma from orders orders.bill(proforma=True)
diff --git a/orchestra/admin/forms.py b/orchestra/admin/forms.py
index b73e499e..ed675457 100644
--- a/orchestra/admin/forms.py
+++ b/orchestra/admin/forms.py
@@ -37,8 +37,8 @@ class AdminFormSet(BaseModelFormSet):
return template.render(Context({'inline_admin_formset': inline_admin_formset}))
-def adminmodelformset_factory(modeladmin, form):
- formset = modelformset_factory(modeladmin.model, extra=0,
- form=form, formset=AdminFormSet)
+def adminmodelformset_factory(modeladmin, form, formset=AdminFormSet, **kwargs):
+ formset = modelformset_factory(modeladmin.model, form=form, formset=formset,
+ **kwargs)
formset.modeladmin = modeladmin
return formset
diff --git a/orchestra/apps/accounts/admin.py b/orchestra/apps/accounts/admin.py
index 771f0795..dfd50ee5 100644
--- a/orchestra/apps/accounts/admin.py
+++ b/orchestra/apps/accounts/admin.py
@@ -198,19 +198,25 @@ class AccountAdminMixin(object):
def changelist_view(self, request, extra_context=None):
account_id = request.GET.get('account')
- context = {
- 'from_account': False
- }
+ context = {}
if account_id:
opts = self.model._meta
account = Account.objects.get(pk=account_id)
context = {
- 'from_account': True,
- 'title': _("Select %s to change for %s") % (
- opts.verbose_name, account.name),
'account': not account_id or Account.objects.get(pk=account_id),
'account_opts': Account._meta,
+ 'all_selected': True,
}
+ if not request.GET.get('all'):
+ context.update({
+ 'all_selected': False,
+ 'title': _("Select %s to change for %s") % (
+ opts.verbose_name, account.name),
+ })
+ else:
+ request_copy = request.GET.copy()
+ request_copy.pop('account')
+ request.GET = request_copy
context.update(extra_context or {})
return super(AccountAdminMixin, self).changelist_view(request,
extra_context=context)
diff --git a/orchestra/apps/accounts/filters.py b/orchestra/apps/accounts/filters.py
index 84a27831..078d44aa 100644
--- a/orchestra/apps/accounts/filters.py
+++ b/orchestra/apps/accounts/filters.py
@@ -1,4 +1,5 @@
from django.contrib.admin import SimpleListFilter
+from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
diff --git a/orchestra/apps/accounts/templates/admin/accounts/account/change_list.html b/orchestra/apps/accounts/templates/admin/accounts/account/change_list.html
index ea9d101b..08a7b563 100644
--- a/orchestra/apps/accounts/templates/admin/accounts/account/change_list.html
+++ b/orchestra/apps/accounts/templates/admin/accounts/account/change_list.html
@@ -1,11 +1,11 @@
{% extends "admin/change_list.html" %}
-{% load i18n admin_urls %}
+{% load i18n admin_urls admin_list %}
{% block breadcrumbs %}
{% trans 'Home' %}
-{% if from_account %}
+{% if account %}
›
{{ account_opts.app_config.verbose_name }}
›
{{ account_opts.verbose_name_plural|capfirst }}
›
{{ account|truncatewords:"18" }}
@@ -18,18 +18,32 @@
{% block object-tools-items %}
-{% if from_account %}
-
- {{ account|truncatewords:"18" }}
-
-
- {% trans 'Show all' %}
-
-{% endif %}
{% url cl.opts|admin_urlname:'add' as add_url %}
+ {% if all_selected %}
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
+ {% else %}
+ {% blocktrans with cl.opts.verbose_name as name and account|truncatewords:"18" as account %}Add {{ account }} {{ name }}{% endblocktrans %}
+ {% endif %}
{% endblock %}
+
+
+{% block filters %}
+ {% if cl.has_filters %}
+
+
{% trans 'Filter' %}
+ {% if account %}
+
{% trans 'By account' %}
+
+ {% endif %}
+ {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
+
+ {% endif %}
+{% endblock %}
+
diff --git a/orchestra/apps/bills/actions.py b/orchestra/apps/bills/actions.py
index 63ec1bde..ded70292 100644
--- a/orchestra/apps/bills/actions.py
+++ b/orchestra/apps/bills/actions.py
@@ -45,7 +45,8 @@ def close_bills(modeladmin, request, queryset):
if not queryset:
messages.warning(request, _("Selected bills should be in open state"))
return
- SelectSourceFormSet = adminmodelformset_factory(modeladmin, SelectSourceForm)
+ SelectSourceFormSet = adminmodelformset_factory(modeladmin, SelectSourceForm,
+ extra=0)
formset = SelectSourceFormSet(queryset=queryset)
if request.POST.get('post') == 'yes':
formset = SelectSourceFormSet(request.POST, request.FILES, queryset=queryset)
@@ -66,6 +67,7 @@ def close_bills(modeladmin, request, queryset):
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
'formset': formset,
}
+ # TODO use generic confirmation template
return render(request, 'admin/bills/close_confirmation.html', context)
close_bills.verbose_name = _("Close")
close_bills.url_name = 'close'
diff --git a/orchestra/apps/bills/templates/bills/microspective.html b/orchestra/apps/bills/templates/bills/microspective.html
index 00dcc9d0..70be3191 100644
--- a/orchestra/apps/bills/templates/bills/microspective.html
+++ b/orchestra/apps/bills/templates/bills/microspective.html
@@ -39,7 +39,7 @@
{% block summary %}
- {{ bill.get_type_display }}
+ {{ bill.get_type_display.capitalize }}
{{ bill.number }}
@@ -125,14 +125,14 @@
{% if payment.message %}
{{ payment.message | safe }}
{% else %}
- You can pay our invoice by bank transfer.
- Please make sure to state your name and the invoice number.
+ You can pay our {{ bill.get_type_display.lower }} by bank transfer.
+ Please make sure to state your name and the {{ bill.get_type_display.lower}} number.
Our bank account number is
{{ seller_info.bank_account }}
{% endif %}
- QUESTIONS If you have any question about your bill, please
+ QUESTIONS If you have any question about your {{ bill.get_type_display.lower}}, please
feel free to contact us at your convinience. We will reply as soon as we get
your message.
diff --git a/orchestra/apps/orders/backends.py b/orchestra/apps/orders/billing.py
similarity index 100%
rename from orchestra/apps/orders/backends.py
rename to orchestra/apps/orders/billing.py
diff --git a/orchestra/apps/orders/models.py b/orchestra/apps/orders/models.py
index d6d9d4b4..73f61b7b 100644
--- a/orchestra/apps/orders/models.py
+++ b/orchestra/apps/orders/models.py
@@ -13,6 +13,7 @@ from django.utils.translation import ugettext_lazy as _
from orchestra.core import caches, services, accounts
from orchestra.models import queryset
from orchestra.utils.apps import autodiscover
+from orchestra.utils.python import import_class
from . import settings, helpers
from .handlers import ServiceHandler
@@ -315,9 +316,7 @@ class Order(models.Model):
@classmethod
def get_bill_backend(cls):
- # TODO
- from .backends import BillsBackend
- return BillsBackend()
+ return import_class(settings.ORDERS_BILLING_BACKEND)()
def cancel(self):
self.cancelled_on = timezone.now()
diff --git a/orchestra/apps/orders/settings.py b/orchestra/apps/orders/settings.py
index 83c438e7..e6b49d1a 100644
--- a/orchestra/apps/orders/settings.py
+++ b/orchestra/apps/orders/settings.py
@@ -12,3 +12,7 @@ ORDERS_SERVICE_DEFAUL_TAX = getattr(settings, 'ORDERS_SERVICE_DFAULT_TAX', 0)
ORDERS_SERVICE_ANUAL_BILLING_MONTH = getattr(settings, 'ORDERS_SERVICE_ANUAL_BILLING_MONTH', 4)
+
+
+ORDERS_BILLING_BACKEND = getattr(settings, 'ORDERS_BILLING_BACKEND',
+ 'orchestra.apps.orders.billing.BillsBackend')
diff --git a/orchestra/apps/payments/actions.py b/orchestra/apps/payments/actions.py
index 2accd6cc..4e57bbcf 100644
--- a/orchestra/apps/payments/actions.py
+++ b/orchestra/apps/payments/actions.py
@@ -1,4 +1,5 @@
+from .methods import PaymentMethod
def process_transactions(modeladmin, request, queryset):
- for source, transactions in queryset.group_by('source'):
- if source:
- source.method_class().process(transactions)
+ for method, transactions in queryset.group_by('source__method'):
+ if method is not None:
+ PaymentMethod.get_plugin(method)().process(transactions)
diff --git a/orchestra/models/queryset.py b/orchestra/models/queryset.py
index 7a318393..812b7dd5 100644
--- a/orchestra/models/queryset.py
+++ b/orchestra/models/queryset.py
@@ -1,3 +1,6 @@
+from .utils import get_field_value
+
+
def group_by(qset, *fields, **kwargs):
""" group_by iterator with support for multiple nested fields """
ix = kwargs.get('ix', 0)
@@ -6,7 +9,11 @@ def group_by(qset, *fields, **kwargs):
group = []
first = True
for obj in qset:
- current = getattr(obj, fields[ix])
+ try:
+ current = get_field_value(obj, fields[ix])
+ except AttributeError:
+ # Intermediary relation does not exists
+ current = None
if first or current == previous:
group.append(obj)
else: