Parcourir la source

Remove non-sens invoice billign period (period_from, period_to). But add theses fields to invoicedetail as optional. They are used to check if an invoice for a subscription has already been generated.

Fabs il y a 11 ans
Parent
commit
3ed8e2980d

+ 2 - 2
coin/billing/admin.py

@@ -7,7 +7,7 @@ import autocomplete_light
 class InvoiceDetailInline(admin.StackedInline):
 class InvoiceDetailInline(admin.StackedInline):
     model = InvoiceDetail
     model = InvoiceDetail
     extra = 0
     extra = 0
-    fields = (('label', 'amount', 'quantity', 'tax', 'offer'),)
+    fields = (('label', 'amount', 'quantity', 'tax'), ('offer','period_from', 'period_to'))
 
 
 
 
 class PaymentInline(admin.StackedInline):
 class PaymentInline(admin.StackedInline):
@@ -21,7 +21,7 @@ class InvoiceAdmin(admin.ModelAdmin):
 	list_display_links = ('number', 'date')
 	list_display_links = ('number', 'date')
 	inlines = [InvoiceDetailInline, PaymentInline]
 	inlines = [InvoiceDetailInline, PaymentInline]
 	fields = (('number', 'date', 'status'),
 	fields = (('number', 'date', 'status'),
-			  ('period_from', 'period_to', 'date_due'),
+			  ('date_due'),
 			  'member')
 			  'member')
 	form = autocomplete_light.modelform_factory(Invoice)
 	form = autocomplete_light.modelform_factory(Invoice)
 
 

+ 31 - 19
coin/billing/generate_invoices.py

@@ -21,7 +21,7 @@ def generate_missing_invoices(request):
 	sortie = ""
 	sortie = ""
 	for member in members:
 	for member in members:
 		sortie += '<br /> %s - %s' % (member, 
 		sortie += '<br /> %s - %s' % (member, 
-			generate_invoice_for_a_period(member, datetime.date(2013,12,5)))
+			generate_invoice_for_a_period(member, datetime.date(2014,5,17)))
 
 
 	return HttpResponse(sortie)
 	return HttpResponse(sortie)
 
 
@@ -30,43 +30,55 @@ def generate_invoice_for_a_period(member, date):
 	"""
 	"""
 	Génère si necessaire une facture pour un membre en prenant la date passée 
 	Génère si necessaire une facture pour un membre en prenant la date passée 
 	en paramètre comme premier mois de période. Renvoi la facture générée
 	en paramètre comme premier mois de période. Renvoi la facture générée
-	ou Non si aucune facture n'était necessaire.
+	ou None si aucune facture n'était necessaire.
 	"""
 	"""
 	invoice = None
 	invoice = None
 
 
+	# Récupère les abonnements en cours du membre
+	offer_subscriptions = (
+		OfferSubscription.get_member_offer_subscriptions(member,date))
 
 
-	offer_subscriptions = OfferSubscription.objects.filter(
-		Q(resign_date__isnull=True) | Q(resign_date__gte=datetime.date.today()),
-		member__exact=member.pk)
-
+	#Pour chaque abonnement
 	for offer_subscription in offer_subscriptions:
 	for offer_subscription in offer_subscriptions:
+		#Récupère l'offre de l'abonnement
 		offer = offer_subscription.offer
 		offer = offer_subscription.offer
 
 
+		# Recherche les factures déjà existantes de ce membre ayant cette offre
+		# comme item pour lesquels la période de facturation englobe la date
 		invoice_test = Invoice.objects.filter(
 		invoice_test = Invoice.objects.filter(
-			period_from__lte=date,
-			period_to__gte=date,
+			# period_from__lte=date,
+			# period_to__gte=date,
 			details__offer__exact=offer.pk,
 			details__offer__exact=offer.pk,
+			details__period_from__lte=date,
+			details__period_to__gte=date,
 			member__exact=member.pk)
 			member__exact=member.pk)
 
 
-		if not invoice_test.exists():			
+		#Si une telle facture n'existe pas
+		if not invoice_test.exists():
+			#Si l'object facture n'a pas encore été créé, le créé
 			if invoice == None:
 			if invoice == None:
 				invoice = Invoice.objects.create(
 				invoice = Invoice.objects.create(
-					period_from=datetime.date(date.year,date.month,1),
-					period_to=datetime.date(date.year,date.month,1),
+					# period_from=datetime.date(date.year,date.month,1),
+					# period_to=datetime.date(date.year,date.month,1),
 					date_due=datetime.date.today(),
 					date_due=datetime.date.today(),
 					member=member
 					member=member
 				)
 				)
 
 
-			new_period_to = (datetime.date(date.year,date.month,1) +
-							relativedelta(months = +offer.billing_period) -
-							relativedelta(days = +1))
-			if new_period_to > invoice.period_to:
-				invoice.period_to=new_period_to
-			
+			# new_period_to = (datetime.date(date.year,date.month,1) +
+			# 				relativedelta(months = +offer.billing_period) -
+			# 				relativedelta(days = +1))
+			# if new_period_to > invoice.period_to:
+			# 	invoice.period_to=new_period_to
+
+			#Ajout l'item de l'offre correspondant à l'abonnement à la facture			
 			invoice.details.create(label=offer.name,
 			invoice.details.create(label=offer.name,
 				amount=offer.period_fees,
 				amount=offer.period_fees,
-				offer=offer)
-			print invoice.period_to
+				offer=offer,
+				period_from=datetime.date(date.year,date.month,1),
+				period_to=(datetime.date(date.year,date.month,1) +
+							relativedelta(months = +offer.billing_period) -
+							relativedelta(days = +1)))
+
 			invoice.save();
 			invoice.save();
 
 
 	return invoice
 	return invoice

+ 117 - 0
coin/billing/migrations/0009_auto__add_field_invoicedetail_period_from__add_field_invoicedetail_per.py

@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'InvoiceDetail.period_from'
+        db.add_column(u'billing_invoicedetail', 'period_from',
+                      self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2014, 2, 1, 0, 0), null=True, blank=True),
+                      keep_default=False)
+
+        # Adding field 'InvoiceDetail.period_to'
+        db.add_column(u'billing_invoicedetail', 'period_to',
+                      self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2014, 2, 28, 0, 0), null=True, blank=True),
+                      keep_default=False)
+
+        # Deleting field 'Invoice.period_from'
+        db.delete_column(u'billing_invoice', 'period_from')
+
+        # Deleting field 'Invoice.period_to'
+        db.delete_column(u'billing_invoice', 'period_to')
+
+        # Adding unique constraint on 'Invoice', fields ['number']
+        db.create_unique(u'billing_invoice', ['number'])
+
+
+    def backwards(self, orm):
+        # Removing unique constraint on 'Invoice', fields ['number']
+        db.delete_unique(u'billing_invoice', ['number'])
+
+        # Deleting field 'InvoiceDetail.period_from'
+        db.delete_column(u'billing_invoicedetail', 'period_from')
+
+        # Deleting field 'InvoiceDetail.period_to'
+        db.delete_column(u'billing_invoicedetail', 'period_to')
+
+        # Adding field 'Invoice.period_from'
+        db.add_column(u'billing_invoice', 'period_from',
+                      self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2014, 2, 1, 0, 0), null=True),
+                      keep_default=False)
+
+        # Adding field 'Invoice.period_to'
+        db.add_column(u'billing_invoice', 'period_to',
+                      self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2014, 2, 28, 0, 0), null=True),
+                      keep_default=False)
+
+
+    models = {
+        u'billing.invoice': {
+            'Meta': {'object_name': 'Invoice'},
+            'date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today', 'null': 'True'}),
+            'date_due': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2014, 2, 28, 0, 0)', 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'member': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['members.Member']", 'null': 'True', 'blank': 'True'}),
+            'number': ('django.db.models.fields.CharField', [], {'default': "u'201402-545-398'", 'unique': 'True', 'max_length': '25'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'open'", 'max_length': '50'})
+        },
+        u'billing.invoicedetail': {
+            'Meta': {'object_name': 'InvoiceDetail'},
+            'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '5', 'decimal_places': '2'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invoice': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'details'", 'to': u"orm['billing.Invoice']"}),
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'offer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['offers.Offer']", 'null': 'True', 'blank': 'True'}),
+            'period_from': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2014, 2, 1, 0, 0)', 'null': 'True', 'blank': 'True'}),
+            'period_to': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2014, 2, 28, 0, 0)', 'null': 'True', 'blank': 'True'}),
+            'quantity': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True'}),
+            'tax': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'null': 'True', 'max_digits': '4', 'decimal_places': '2'})
+        },
+        u'billing.payment': {
+            'Meta': {'object_name': 'Payment'},
+            'amount': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2'}),
+            'date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invoce': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['billing.Invoice']"}),
+            'payment_mean': ('django.db.models.fields.CharField', [], {'default': "'transfer'", 'max_length': '100', 'null': 'True'})
+        },
+        u'members.member': {
+            'Meta': {'object_name': 'Member'},
+            'address': ('django.db.models.fields.TextField', [], {}),
+            'city': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'country': ('django.db.models.fields.CharField', [], {'default': "'France'", 'max_length': '200'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '254'}),
+            'entry_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'home_phone_number': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'ldap_cn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'mobile_phone_number': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
+            'organization_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '15'}),
+            'resign_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'non_adherent'", 'max_length': '50'}),
+            'type': ('django.db.models.fields.CharField', [], {'default': "'personne_physique'", 'max_length': '20'})
+        },
+        u'offers.offer': {
+            'Meta': {'object_name': 'Offer'},
+            'billing_period': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'initial_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '5', 'decimal_places': '2'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'period_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '5', 'decimal_places': '2'}),
+            'service': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['offers.Service']"})
+        },
+        u'offers.service': {
+            'Meta': {'object_name': 'Service'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        }
+    }
+
+    complete_apps = ['billing']

+ 16 - 12
coin/billing/models.py

@@ -24,17 +24,6 @@ class Invoice(models.Model):
                               default='open',
                               default='open',
                               verbose_name='Statut')
                               verbose_name='Statut')
     date = models.DateField(default=datetime.date.today, null=True)
     date = models.DateField(default=datetime.date.today, null=True)
-    period_from = models.DateField(
-        default=datetime.date(datetime.date.today().year,
-                              datetime.date.today().month, 1),
-        null=True,
-        verbose_name=u'Début de période de facturation')
-    period_to = models.DateField(
-        default=(datetime.date(datetime.date.today().year,
-                               datetime.date.today().month + 1, 1) -
-                 datetime.timedelta(days=1)),
-        null=True,
-        verbose_name=u'Fin de période de facturation')
     date_due = models.DateField(
     date_due = models.DateField(
         default=(datetime.date(datetime.date.today().year,
         default=(datetime.date(datetime.date.today().year,
                                datetime.date.today().month + 1, 1) -
                                datetime.date.today().month + 1, 1) -
@@ -49,7 +38,7 @@ class Invoice(models.Model):
       total = Decimal('0.0')
       total = Decimal('0.0')
       for detail in self.details.all():
       for detail in self.details.all():
         total += detail.amount * (detail.tax / Decimal('100.0') +
         total += detail.amount * (detail.tax / Decimal('100.0') +
-                                  Decimal('1.0'))
+                                  Decimal('1.0')) * detail.quantity
       return total.quantize(Decimal('0.01'))
       return total.quantize(Decimal('0.01'))
 
 
     @staticmethod
     @staticmethod
@@ -81,6 +70,21 @@ class InvoiceDetail(models.Model):
                                 related_name='details')
                                 related_name='details')
     offer = models.ForeignKey(Offer, null=True, blank=True, default=None,
     offer = models.ForeignKey(Offer, null=True, blank=True, default=None,
                               verbose_name='Offre')
                               verbose_name='Offre')
+    period_from = models.DateField(
+        default=datetime.date(datetime.date.today().year,
+                              datetime.date.today().month, 1),
+        null=True,
+        blank=True,
+        verbose_name=u'Début de période',
+        help_text=u'Date de début de période sur laquelle est facturé cet item')
+    period_to = models.DateField(
+        default=(datetime.date(datetime.date.today().year,
+                               datetime.date.today().month + 1, 1) -
+                 datetime.timedelta(days=1)),
+        null=True,
+        blank=True,
+        verbose_name=u'Fin de période',
+        help_text=u'Date de fin de période sur laquelle est facturé cet item')
 
 
     def __unicode__(self):
     def __unicode__(self):
         return self.label
         return self.label

+ 2 - 27
coin/billing/templates/billing/facture.tex

@@ -1,31 +1,6 @@
+{% autoescape off %}
 \documentclass{facture}
 \documentclass{facture}
 \usepackage{lipsum}
 \usepackage{lipsum}
-\setmainfont[Mapping=tex-text]{Palatino}
-\datelimite{30}
-\dest{{{member.first_name}} {{member.last_name}}\\
-{{member.address}}\\
-{{member.postal_code}} {member.city}} 
-}
-\fact{{{member.first_name}} {{member.last_name}}}
-{{member.address}}\\
-{{member.postal_code}} {{member.city}} 
-}
-\nomemet{Illyse - chez Jean-François Mourgues}
-\adresseemet{225 route de Genas\\
-69100 Villeurbanne\\
-contact@illyse.org \\
-}
-
-\numero{invoice.number}
-\type{Facture}
-\pied{Payable à l’ordre de Illyse}
-\begin{document}
-\entete
-
-\begin{facture}
-{% for detail in InvoiceDetail }
-\ligne{detail.label}[detail.quantity]{detail.amount}[][detail.tax]
-{% endfor %}
-\end{facture}
 
 
 \end{document}
 \end{document}
+{% endautoescape %}

+ 4 - 3
coin/billing/views.py

@@ -17,10 +17,11 @@ def pdf_test(request):
 
 
 def invoice_pdf(request, pk):
 def invoice_pdf(request, pk):
 
 
-    invoice = get_object_or_404(Invoice, pk=1)
-    context = {"invoice": invoice}
+    invoice = get_object_or_404(Invoice, pk=pk)
+    member = invoice.member
+    context = {"invoice": invoice, 'member':member}
 
 
     response = HttpResponse(content_type='application/pdf')
     response = HttpResponse(content_type='application/pdf')
     response['Content-Disposition'] = 'attachment; filename="facture.pdf"'
     response['Content-Disposition'] = 'attachment; filename="facture.pdf"'
-    response.write(process_latex('billing/invoice.tex', context))
+    response.write(process_latex('billing/facture.tex', context))
     return response
     return response

+ 8 - 0
coin/offers/models.py

@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 import datetime
 import datetime
 from django.db import models
 from django.db import models
+from django.db.models import Q
 
 
 
 
 class Service(models.Model):
 class Service(models.Model):
@@ -57,5 +58,12 @@ class OfferSubscription(models.Model):
         return u'%s - %s - %s' % (self.member, self.offer.name,
         return u'%s - %s - %s' % (self.member, self.offer.name,
                                    self.subscription_date)
                                    self.subscription_date)
 
 
+    @staticmethod
+    def get_member_offer_subscriptions(member, date=datetime.date.today()):
+      return OfferSubscription.objects.filter(
+        Q(member__exact=member.pk),
+        Q(subscription_date__lte=date),
+        Q(resign_date__isnull=True) | Q(resign_date__gte=date))
+
     class Meta:
     class Meta:
         verbose_name = 'abonnement'
         verbose_name = 'abonnement'