diff --git a/cotisations/migrations/0032_chequepayment_comnpaypayment.py b/cotisations/migrations/0032_chequepayment_comnpaypayment.py index d2c67308..e0717a05 100644 --- a/cotisations/migrations/0032_chequepayment_comnpaypayment.py +++ b/cotisations/migrations/0032_chequepayment_comnpaypayment.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import cotisations.payment_methods.comnpay.aes_field -import cotisations.payment_methods.models +import cotisations.payment_methods.mixins from django.db import migrations, models import django.db.models.deletion @@ -47,7 +47,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), ], - bases=(cotisations.payment_methods.models.PaymentMethodMixin, models.Model), + bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), ), migrations.CreateModel( name='ComnpayPayment', @@ -57,7 +57,7 @@ class Migration(migrations.Migration): ('payment_pass', cotisations.payment_methods.comnpay.aes_field.AESEncryptedField(blank=True, max_length=255, null=True)), ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), ], - bases=(cotisations.payment_methods.models.PaymentMethodMixin, models.Model), + bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), ), migrations.RunPython(add_comnpay), migrations.RunPython(add_cheque), diff --git a/cotisations/migrations/0033_balancepayment.py b/cotisations/migrations/0033_balancepayment.py new file mode 100644 index 00000000..9308a7b0 --- /dev/null +++ b/cotisations/migrations/0033_balancepayment.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-07-03 13:53 +from __future__ import unicode_literals + +import cotisations.payment_methods.mixins +from django.db import migrations, models +import django.db.models.deletion + + +def add_solde(apps, schema_editor): + OptionalUser = apps.get_model('preferences', 'OptionalUser') + options, _created = OptionalUser.objects.get_or_create() + + Payment = apps.get_model('cotisations', 'Paiement') + BalancePayment = apps.get_model('cotisations', 'BalancePayment') + + solde, _created = Payment.objects.get_or_create(moyen="solde") + balance = BalancePayment() + balance.payment = solde + balance.minimum_balance = options.solde_negatif + balance.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0032_chequepayment_comnpaypayment'), + ] + + operations = [ + migrations.CreateModel( + name='BalancePayment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('minimum_balance', models.DecimalField(decimal_places=2, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.', max_digits=5, verbose_name='Minimum balance')), + ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), + ], + bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), + ), + migrations.RunPython(add_solde) + ] diff --git a/cotisations/models.py b/cotisations/models.py index 66e045db..ba285c90 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -668,7 +668,7 @@ class Paiement(RevMixin, AclMixin, models.Model): ) return redirect(reverse( 'users:profil', - kwargs={'userid': request.user.pk} + kwargs={'userid': invoice.user.pk} )) diff --git a/cotisations/payment_methods/__init__.py b/cotisations/payment_methods/__init__.py index a85fa49c..422bd069 100644 --- a/cotisations/payment_methods/__init__.py +++ b/cotisations/payment_methods/__init__.py @@ -1,6 +1,7 @@ -from . import comnpay, cheque, urls +from . import comnpay, cheque, balance, urls PAYMENT_METHODS = [ comnpay, cheque, + balance, ] diff --git a/cotisations/payment_methods/balance/.views.py.swo b/cotisations/payment_methods/balance/.views.py.swo new file mode 100644 index 00000000..179420c2 Binary files /dev/null and b/cotisations/payment_methods/balance/.views.py.swo differ diff --git a/cotisations/payment_methods/balance/__init__.py b/cotisations/payment_methods/balance/__init__.py new file mode 100644 index 00000000..adfca187 --- /dev/null +++ b/cotisations/payment_methods/balance/__init__.py @@ -0,0 +1,7 @@ +""" +This module contains a method to pay online using user balance. +""" +from . import models +NAME = "BALANCE" + +PaymentMethod = models.BalancePayment diff --git a/cotisations/payment_methods/balance/models.py b/cotisations/payment_methods/balance/models.py new file mode 100644 index 00000000..b2ff96cc --- /dev/null +++ b/cotisations/payment_methods/balance/models.py @@ -0,0 +1,50 @@ +from django.db import models +from django.shortcuts import redirect +from django.urls import reverse +from django.utils.translation import ugettext as _ +from django.utils.translation import ugettext_lazy as _l +from django.contrib import messages + + +from cotisations.models import Paiement +from cotisations.payment_methods.mixins import PaymentMethodMixin + + +class BalancePayment(PaymentMethodMixin, models.Model): + """ + The model allowing you to pay with a cheque. + """ + payment = models.OneToOneField( + Paiement, + related_name='payment_method', + editable=False + ) + minimum_balance = models.DecimalField( + verbose_name=_l("Minimum balance"), + help_text=_l("The minimal amount of money allowed for the balance" + " at the end of a payment. You can specify negative " + "amount." + ), + max_digits=5, + decimal_places=2, + ) + + def end_payment(self, invoice, request): + user = invoice.user + total_price = invoice.prix_total() + if float(user.solde) - float(total_price) < self.minimum_balance: + invoice.valid = False + invoice.save() + messages.error( + request, + _("Your balance is too low for this operation.") + ) + return redirect(reverse( + 'users:profil', + kwargs={'userid': user.id} + )) + return invoice.paiement.end_payment( + invoice, + request, + use_payment_method=False + ) diff --git a/cotisations/views.py b/cotisations/views.py index 0acd6b78..fbf8d7ab 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -139,33 +139,6 @@ def new_facture(request, user, userid): articles = article_formset # Check if at leat one article has been selected if any(art.cleaned_data for art in articles): - user_balance = OptionalUser.get_cached_value('user_solde') - negative_balance = OptionalUser.get_cached_value('solde_negatif') - # If the paiement using balance has been activated, - # checking that the total price won't get the user under - # the authorized minimum (negative_balance) - if user_balance: - # TODO : change Paiement to Payment - if new_invoice_instance.paiement == ( - Paiement.objects.get_or_create(moyen='solde')[0] - ): - total_price = 0 - for art_item in articles: - if art_item.cleaned_data: - total_price += ( - art_item.cleaned_data['article'].prix * - art_item.cleaned_data['quantity'] - ) - if (float(user.solde) - float(total_price) - < negative_balance): - messages.error( - request, - _("Your balance is too low for this operation.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': userid} - )) new_invoice_instance.save() # Building a purchase for each article sold diff --git a/users/models.py b/users/models.py index 0284985c..66dd0011 100644 --- a/users/models.py +++ b/users/models.py @@ -426,36 +426,31 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def solde(self): - """ Renvoie le solde d'un user. Vérifie que l'option solde est - activé, retourne 0 sinon. + """ Renvoie le solde d'un user. Somme les crédits de solde et retire les débit payés par solde""" - user_solde = OptionalUser.get_cached_value('user_solde') - if user_solde: - solde_objects = Paiement.objects.filter(moyen='Solde') - somme_debit = Vente.objects.filter( - facture__in=Facture.objects.filter( - user=self, - paiement__in=solde_objects, - valid=True - ) - ).aggregate( - total=models.Sum( - models.F('prix')*models.F('number'), - output_field=models.FloatField() - ) - )['total'] or 0 - somme_credit = Vente.objects.filter( - facture__in=Facture.objects.filter(user=self, valid=True), - name="solde" - ).aggregate( - total=models.Sum( - models.F('prix')*models.F('number'), - output_field=models.FloatField() - ) - )['total'] or 0 - return somme_credit - somme_debit - else: - return 0 + solde_objects = Paiement.objects.filter(moyen='solde') + somme_debit = Vente.objects.filter( + facture__in=Facture.objects.filter( + user=self, + paiement__in=solde_objects, + valid=True + ) + ).aggregate( + total=models.Sum( + models.F('prix')*models.F('number'), + output_field=models.FloatField() + ) + )['total'] or 0 + somme_credit = Vente.objects.filter( + facture__in=Facture.objects.filter(user=self, valid=True), + name="solde" + ).aggregate( + total=models.Sum( + models.F('prix')*models.F('number'), + output_field=models.FloatField() + ) + )['total'] or 0 + return somme_credit - somme_debit def user_interfaces(self, active=True): """ Renvoie toutes les interfaces dont les machines appartiennent à