123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- # -*- 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 django.template import RequestContext
- from django.shortcuts import render
- 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
- from functools import update_wrapper
- from .forms import WizardImportPaymentCSV
- from .import_payments_from_csv import process
- 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 = ('number', 'date', 'status', 'amount', 'member',
- 'validated')
- list_display_links = ('number', 'date')
- 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)]
- def get_urls(self):
- def wrap(view):
- def wrapper(*args, **kwargs):
- return self.admin_site.admin_view(view)(*args, **kwargs)
- wrapper.model_admin = self
- return update_wrapper(wrapper, view)
- urls = super(PaymentAdmin, self).get_urls()
- info = self.model._meta.app_label, self.model._meta.model_name
- my_urls = [
- url(r'wizard_import_payment_csv/$', wrap(self.wizard_import_payment_csv), name='wizard_import_payment_csv'),
- ]
- return my_urls + urls
- def wizard_import_payment_csv(self, request):
- template = "admin/billing/payment/wizard_import_payment_csv.html"
- if request.method == 'POST':
- form = WizardImportPaymentCSV(request.POST, request.FILES)
- if form.is_valid():
- # Analyze
- new_payments = process(request.FILES["csv_file"])
- # If the user didn't ask for commit yet
- # display the result of the analyze (i.e. the matching)
- if "commit" not in request.POST:
- return render(request, template, {
- 'adminform': form,
- 'opts': self.model._meta,
- 'new_payments': new_payments
- })
- else:
- import pdb; pdb.set_trace()
- # To be implemented
- else:
- form = WizardImportPaymentCSV()
- return render(request, template, {
- 'adminform': form,
- 'opts': self.model._meta
- })
- class MembershipFeeAdmin(admin.ModelAdmin):
- list_display = ('member', 'end_date', '_amount')
- form = autocomplete_light.modelform_factory(MembershipFee, fields='__all__')
- class DonationAdmin(admin.ModelAdmin):
- list_display = ('member', 'date', '_amount')
- form = autocomplete_light.modelform_factory(MembershipFee, fields='__all__')
- class MembershipFeeInline(admin.TabularInline):
- model = MembershipFee
- extra = 0
- fields = ('start_date', 'end_date', '_amount')
- MemberAdmin.list_filter += ('status', MembershipFeeFilter)
- MemberAdmin.inlines += [MembershipFeeInline]
- admin.site.register(Invoice, InvoiceAdmin)
- admin.site.register(Payment, PaymentAdmin)
|