123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- # -*- coding: utf-8 -*-
- from __future__ import unicode_literals
- from django.contrib import admin
- from django.contrib import messages
- from django.http import HttpResponseRedirect
- from django.conf.urls import url
- from django.contrib.admin.utils import flatten_fieldsets
- from django import forms
- from coin.filtering_queryset import LimitedAdminInlineMixin
- from coin.billing.models import Invoice, InvoiceDetail, Payment, PaymentAllocation
- from coin.billing.utils import get_invoice_from_id_or_number
- from django.core.urlresolvers import reverse
- import autocomplete_light
- class InvoiceDetailInlineForm(forms.ModelForm):
- class Meta:
- model = InvoiceDetail
- fields = (
- 'label', 'amount', 'quantity', 'tax',
- 'offersubscription', 'period_from', 'period_to'
- )
- widgets = {'quantity': forms.NumberInput(attrs={'step': 1})}
- class InvoiceDetailInline(LimitedAdminInlineMixin, admin.StackedInline):
- model = InvoiceDetail
- extra = 0
- fields = (('label', 'amount', 'quantity', 'tax'),
- ('offersubscription', 'period_from', 'period_to'))
- form = InvoiceDetailInlineForm
- def get_filters(self, obj):
- """
- Le champ "Abonnement" est filtré afin de n'afficher que les abonnements
- du membre choisi dans la facture. Si pas de membre alors renvoi
- une liste vide
- """
- if obj and obj.member:
- return (('offersubscription', {'member': obj.member}),)
- else:
- return (('offersubscription', None),)
- def get_readonly_fields(self, request, obj=None):
- if not obj or not obj.member:
- return self.readonly_fields + ('offersubscription',)
- return self.readonly_fields
- class InvoiceDetailInlineReadOnly(admin.StackedInline):
- """
- Lorsque la facture est validée, il n'est plus possible de la modifier
- Ce inline est donc identique à InvoiceDetailInline, mais tous
- les champs sont en lecture seule
- """
- model = InvoiceDetail
- extra = 0
- fields = InvoiceDetailInline.fields
- can_delete = False
- def has_add_permission(self, request):
- return False
- def get_readonly_fields(self, request, obj=None):
- if self.declared_fieldsets:
- result = flatten_fieldsets(self.declared_fieldsets)
- else:
- result = list(set(
- [field.name for field in self.opts.local_fields] +
- [field.name for field in self.opts.local_many_to_many]
- ))
- result.remove('id')
- return result
- class PaymentAllocatedReadOnly(admin.TabularInline):
- model = PaymentAllocation
- extra = 0
- fields = ("payment", "amount")
- readonly_fields = ("payment", "amount")
- verbose_name = None
- verbose_name_plural = "Paiement alloués"
- def has_add_permission(self, request, obj=None):
- return False
- def has_delete_permission(self, request, obj=None):
- return False
- class PaymentInlineAdd(admin.StackedInline):
- model = Payment
- extra = 0
- fields = (('date', 'payment_mean', 'amount'),)
- can_delete = False
- verbose_name_plural = "Ajouter des paiements"
- def has_change_permission(self, request):
- return False
- class InvoiceAdmin(admin.ModelAdmin):
- list_display_links = ('number', 'date')
- list_filter = ('status', 'validated')
- search_fields = ['member__username', 'member__first_name', 'member__last_name', 'member__email', 'member__nickname', 'number', 'date']
- list_display = ('number', 'date', 'status', 'amount', 'member',
- 'validated')
- fields = (('number', 'date', 'status'),
- ('date_due'),
- ('member'),
- ('amount', 'amount_paid'),
- ('validated', 'pdf'))
- readonly_fields = ('amount', 'amount_paid', 'validated', 'pdf', 'number')
- form = autocomplete_light.modelform_factory(Invoice, fields='__all__')
- def get_readonly_fields(self, request, obj=None):
- """
- Si la facture est validée, passe tous les champs en readonly
- """
- if obj and obj.validated:
- if self.declared_fieldsets:
- return flatten_fieldsets(self.declared_fieldsets)
- else:
- return list(set(
- [field.name for field in self.opts.local_fields] +
- [field.name for field in self.opts.local_many_to_many]
- ))
- return self.readonly_fields
- def get_inline_instances(self, request, obj=None):
- """
- Renvoi les inlines selon le context :
- * Si création, alors ne renvoi aucun inline
- * Si modification, renvoi InvoiceDetail et PaymentInline
- * Si facture validée, renvoi InvoiceDetail en ReadOnly et PaymentInline
- """
- inlines = []
- inline_instances = []
- if obj is not None:
- if obj.validated:
- inlines = [InvoiceDetailInlineReadOnly]
- else:
- inlines = [InvoiceDetailInline]
- if obj.validated:
- inlines += [PaymentAllocatedReadOnly]
- if obj.status == "open":
- inlines += [PaymentInlineAdd]
- for inline_class in inlines:
- inline = inline_class(self.model, self.admin_site)
- if request:
- if not (inline.has_add_permission(request) or
- inline.has_change_permission(request) or
- inline.has_delete_permission(request)):
- continue
- if not inline.has_add_permission(request):
- inline.max_num = 0
- inline_instances.append(inline)
- return inline_instances
- def get_urls(self):
- """
- Custom admin urls
- """
- urls = super(InvoiceAdmin, self).get_urls()
- my_urls = [
- url(r'^validate/(?P<id>.+)$',
- self.admin_site.admin_view(self.validate_view),
- name='invoice_validate'),
- ]
- return my_urls + urls
- def validate_view(self, request, id):
- """
- Vue appelée lorsque l'admin souhaite valider une facture et
- générer son pdf
- """
- # TODO : Add better perm here
- if request.user.is_superuser:
- invoice = get_invoice_from_id_or_number(id)
- if invoice.amount() == 0:
- messages.error(request, 'Une facture validée ne peut pas avoir'
- ' un total de 0€.')
- else:
- invoice.validate()
- messages.success(request, 'La facture a été validée.')
- else:
- messages.error(
- request, 'Vous n\'avez pas l\'autorisation de valider '
- 'une facture.')
- return HttpResponseRedirect(reverse('admin:billing_invoice_change',
- args=(id,)))
- class PaymentAllocationInlineReadOnly(admin.TabularInline):
- model = PaymentAllocation
- extra = 0
- fields = ("invoice", "amount")
- readonly_fields = ("invoice", "amount")
- verbose_name = None
- verbose_name_plural = "Alloué à"
- def has_add_permission(self, request, obj=None):
- return False
- def has_delete_permission(self, request, obj=None):
- return False
- class PaymentAdmin(admin.ModelAdmin):
- list_display = ('__unicode__', 'member', 'payment_mean', 'amount', 'date',
- 'amount_already_allocated', 'label')
- list_display_links = ()
- fields = (('member'),
- ('amount', 'payment_mean', 'date', 'label'),
- ('amount_already_allocated'))
- readonly_fields = ('amount_already_allocated', 'label')
- form = autocomplete_light.modelform_factory(Payment, fields='__all__')
- def get_readonly_fields(self, request, obj=None):
- # If payment already started to be allocated or already have a member
- if obj and (obj.amount_already_allocated() != 0 or obj.member != None):
- # All fields are readonly
- return flatten_fieldsets(self.declared_fieldsets)
- else:
- return self.readonly_fields
- def get_inline_instances(self, request, obj=None):
- return [PaymentAllocationInlineReadOnly(self.model, self.admin_site)]
- admin.site.register(Invoice, InvoiceAdmin)
- admin.site.register(Payment, PaymentAdmin)
|