mirror of https://gitlab.federez.net/re2o/re2o
50 changed files with 1722 additions and 866 deletions
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-06-17 14:59 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0029_auto_20180414_2056'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='paiement', |
||||
|
name='allow_self_subscription', |
||||
|
field=models.BooleanField(default=False, verbose_name='Is available for self subscription'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-06-17 17:13 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0030_paiement_allow_self_subscription'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='article', |
||||
|
name='allow_self_subscription', |
||||
|
field=models.BooleanField(default=False, verbose_name='Is available for self subscription'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,65 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-02 18:56 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
import re2o.aes_field |
||||
|
import cotisations.payment_methods.mixins |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
def add_cheque(apps, schema_editor): |
||||
|
ChequePayment = apps.get_model('cotisations', 'ChequePayment') |
||||
|
Payment = apps.get_model('cotisations', 'Paiement') |
||||
|
for p in Payment.objects.filter(type_paiement=1): |
||||
|
cheque = ChequePayment() |
||||
|
cheque.payment = p |
||||
|
cheque.save() |
||||
|
|
||||
|
|
||||
|
def add_comnpay(apps, schema_editor): |
||||
|
ComnpayPayment = apps.get_model('cotisations', 'ComnpayPayment') |
||||
|
Payment = apps.get_model('cotisations', 'Paiement') |
||||
|
AssoOption = apps.get_model('preferences', 'AssoOption') |
||||
|
options, _created = AssoOption.objects.get_or_create() |
||||
|
payment, _created = Payment.objects.get_or_create( |
||||
|
moyen='Rechargement en ligne' |
||||
|
) |
||||
|
comnpay = ComnpayPayment() |
||||
|
comnpay.payment_user = options.payment_id |
||||
|
comnpay.payment_pass = options.payment_pass |
||||
|
comnpay.payment = payment |
||||
|
comnpay.save() |
||||
|
payment.moyen = "ComnPay" |
||||
|
payment.save() |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0031_article_allow_self_subscription'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RunSQL('update preferences_assooption set payment_pass="" where id=1;'), |
||||
|
migrations.CreateModel( |
||||
|
name='ChequePayment', |
||||
|
fields=[ |
||||
|
('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.mixins.PaymentMethodMixin, models.Model), |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name='ComnpayPayment', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('payment_credential', models.CharField(blank=True, default='', max_length=255)), |
||||
|
('payment_pass', re2o.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.mixins.PaymentMethodMixin, models.Model), |
||||
|
), |
||||
|
migrations.RunPython(add_comnpay), |
||||
|
migrations.RunPython(add_cheque), |
||||
|
] |
||||
@ -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) |
||||
|
] |
||||
@ -0,0 +1,26 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-03 14:29 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
import re2o.aes_field |
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0033_balancepayment'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='comnpaypayment', |
||||
|
name='payment_credential', |
||||
|
field=models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAD Number'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='comnpaypayment', |
||||
|
name='payment_pass', |
||||
|
field=re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay Secret Key'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,28 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-03 15:05 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0034_auto_20180703_0929'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='paiement', |
||||
|
options={'permissions': (('view_paiement', "Can see a payement's details"), ('use', 'Can use a payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='paiement', |
||||
|
name='allow_self_subscription', |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='paiement', |
||||
|
name='available_for_everyone', |
||||
|
field=models.BooleanField(default=False, verbose_name='Is available for every user'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,28 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-03 15:56 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0035_auto_20180703_1005'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='article', |
||||
|
options={'permissions': (('view_article', "Can see an article's details"), ('buy_every_article', 'Can buy every_article')), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'}, |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='article', |
||||
|
name='allow_self_subscription', |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='article', |
||||
|
name='available_for_everyone', |
||||
|
field=models.BooleanField(default=False, verbose_name='Is available for every user'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,35 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-03 17:02 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
def create_max_balance(apps, schema_editor): |
||||
|
OptionalUser = apps.get_model('preferences', 'OptionalUser') |
||||
|
Payment = apps.get_model('cotisations', 'Paiement') |
||||
|
|
||||
|
balance, _created = Payment.objects.get_or_create(moyen='solde') |
||||
|
options, _created = OptionalUser.objects.get_or_create() |
||||
|
|
||||
|
balance.maximum_balance = options.max_solde |
||||
|
balance.save() |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0036_auto_20180703_1056'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='paiement', |
||||
|
options={'permissions': (('view_paiement', "Can see a payement's details"), ('use_every_payment', 'Can use every payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='balancepayment', |
||||
|
name='maximum_balance', |
||||
|
field=models.DecimalField(decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, verbose_name='Maximum balance'), |
||||
|
), |
||||
|
migrations.RunPython(create_max_balance) |
||||
|
] |
||||
@ -0,0 +1,29 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-04 16:30 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
def update_balance(apps, _): |
||||
|
Payment = apps.get_model('cotisations', 'Paiement') |
||||
|
try: |
||||
|
balance = Payment.objects.get(moyen="solde") |
||||
|
balance.is_balance = True |
||||
|
balance.save() |
||||
|
except Payment.DoesNotExist: |
||||
|
pass |
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0037_auto_20180703_1202'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='paiement', |
||||
|
name='is_balance', |
||||
|
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', verbose_name='Is user balance'), |
||||
|
), |
||||
|
migrations.RunPython(update_balance) |
||||
|
] |
||||
@ -0,0 +1,21 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-04 16:47 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
import cotisations.models |
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0038_paiement_is_balance'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='paiement', |
||||
|
name='is_balance', |
||||
|
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', validators=[cotisations.models.check_no_balance], verbose_name='Is user balance'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-05 13:22 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('cotisations', '0039_auto_20180704_1147'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='balancepayment', |
||||
|
name='minimum_balance', |
||||
|
field=models.DecimalField(decimal_places=2, default=0, 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'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,136 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
""" |
||||
|
# Custom Payment methods |
||||
|
|
||||
|
When creating an invoice with a classic payment method, the creation view calls |
||||
|
the `end_payment` method of the `Payment` object of the invoice. This method |
||||
|
checks for a payment method associated to the `Payment` and if nothing is |
||||
|
found, adds a message for payment confirmation and redirects the user towards |
||||
|
their profil page. This is fine for most of the payment method, but you might |
||||
|
want to define custom payment methods. As an example for negociating with an |
||||
|
other server for online payment or updating some fields in your models. |
||||
|
|
||||
|
# Defining a custom payment method |
||||
|
To define a custom payment method, you can add a Python module to |
||||
|
`cotisations/payment_methods/`. This module should be organized like |
||||
|
a Django application. |
||||
|
As an example, if you want to add the payment method `foo`. |
||||
|
|
||||
|
## Basic |
||||
|
|
||||
|
The first thing to do is to create a `foo` Python module with a `models.py`. |
||||
|
|
||||
|
``` |
||||
|
payment_methods |
||||
|
├── foo |
||||
|
│ ├── __init__.py |
||||
|
│ └── models.py |
||||
|
├── forms.py |
||||
|
├── __init__.py |
||||
|
├── mixins.py |
||||
|
└── urls.py |
||||
|
``` |
||||
|
|
||||
|
Then, in `models.py` you could add a model like this : |
||||
|
```python |
||||
|
from django.db import models |
||||
|
|
||||
|
from cotisations.models import Paiement |
||||
|
from cotisations.payment_methods.mixins import PaymentMethodMixin |
||||
|
|
||||
|
|
||||
|
# The `PaymentMethodMixin` defines the default `end_payment` |
||||
|
class FooPayment(PaymentMethodMixin, models.Model): |
||||
|
|
||||
|
# This field is required, it is used by `Paiement` in order to |
||||
|
# determine if a payment method is associated to it. |
||||
|
payment = models.OneToOneField( |
||||
|
Paiement, |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name='payment_method', |
||||
|
editable=False |
||||
|
) |
||||
|
``` |
||||
|
|
||||
|
And in `__init__.py` : |
||||
|
```python |
||||
|
from . import models |
||||
|
NAME = "FOO" # Name displayed when you crate a payment type |
||||
|
PaymentMethod = models.FooPayment # You must define this alias |
||||
|
``` |
||||
|
|
||||
|
Then you just have to register your payment method in |
||||
|
`payment_methods/__init__.py` in the `PAYMENT_METHODS` list : |
||||
|
|
||||
|
``` |
||||
|
from . import ... # Some existing imports |
||||
|
from . import foo |
||||
|
|
||||
|
PAYMENT_METHODS = [ |
||||
|
# Some already registered payment methods... |
||||
|
foo |
||||
|
] |
||||
|
``` |
||||
|
|
||||
|
And... that's it, you can use your new payment method after running |
||||
|
`makemigrations` and `migrate`. |
||||
|
|
||||
|
But this payment method is not really usefull, since it does noting ! |
||||
|
|
||||
|
## A payment method which does something |
||||
|
|
||||
|
You have to redefine the `end_payment` method. Here is its prototype : |
||||
|
|
||||
|
```python |
||||
|
def end_payment(self, invoice, request): |
||||
|
pass |
||||
|
``` |
||||
|
|
||||
|
With `invoice` the invoice being created and `request` the request which |
||||
|
created it. This method has to return an HttpResponse-like object. |
||||
|
|
||||
|
## Additional views |
||||
|
|
||||
|
You can add specific urls for your payment method like in any django app. To |
||||
|
register these urls, modify `payment_methods/urls.py`. |
||||
|
|
||||
|
## Alter the `Paiement` object after creation |
||||
|
|
||||
|
You can do that by adding a `alter_payment(self, payment)` |
||||
|
method to your model. |
||||
|
|
||||
|
## Validate the creation field |
||||
|
|
||||
|
You may want to perform some additionals verifications on the form |
||||
|
creating the payment. You can do that by adding a `valid_form(self, form)` |
||||
|
method to your model, where `form` is an instance of |
||||
|
`cotisations.payment_methods.forms.PaymentMethodForm`. |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
from . import comnpay, cheque, balance, urls |
||||
|
|
||||
|
PAYMENT_METHODS = [ |
||||
|
comnpay, |
||||
|
cheque, |
||||
|
balance, |
||||
|
] |
||||
@ -0,0 +1,27 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
""" |
||||
|
This module contains a method to pay online using user balance. |
||||
|
""" |
||||
|
from . import models |
||||
|
NAME = "BALANCE" |
||||
|
|
||||
|
PaymentMethod = models.BalancePayment |
||||
@ -0,0 +1,95 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
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, |
||||
|
on_delete=models.CASCADE, |
||||
|
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, |
||||
|
default=0, |
||||
|
) |
||||
|
maximum_balance = models.DecimalField( |
||||
|
verbose_name=_l("Maximum balance"), |
||||
|
help_text=_l("The maximal amount of money allowed for the balance."), |
||||
|
max_digits=5, |
||||
|
decimal_places=2, |
||||
|
default=50 |
||||
|
) |
||||
|
|
||||
|
def end_payment(self, invoice, request): |
||||
|
"""Changes the user's balance to pay the invoice. If it is not |
||||
|
possible, shows an error and invalidates the invoice. |
||||
|
""" |
||||
|
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 |
||||
|
) |
||||
|
|
||||
|
def valid_form(self, form): |
||||
|
"""Checks that there is not already a balance payment method.""" |
||||
|
p = Paiement.objects.filter(is_balance=True) |
||||
|
if len(p) > 0: |
||||
|
form.add_error( |
||||
|
'payment_method', |
||||
|
_("There is already a payment type for user balance") |
||||
|
) |
||||
|
|
||||
|
def alter_payment(self, payment): |
||||
|
"""Register the payment as a balance payment.""" |
||||
|
self.payment.is_balance = True |
||||
@ -0,0 +1,27 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
""" |
||||
|
This module contains a method to pay online using cheque. |
||||
|
""" |
||||
|
from . import models, urls, views |
||||
|
NAME = "CHEQUE" |
||||
|
|
||||
|
PaymentMethod = models.ChequePayment |
||||
@ -0,0 +1,31 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django import forms |
||||
|
|
||||
|
from re2o.mixins import FormRevMixin |
||||
|
from cotisations.models import Facture as Invoice |
||||
|
|
||||
|
|
||||
|
class InvoiceForm(FormRevMixin, forms.ModelForm): |
||||
|
"""A simple form to get the bank a the cheque number.""" |
||||
|
class Meta: |
||||
|
model = Invoice |
||||
|
fields = ['banque', 'cheque'] |
||||
@ -0,0 +1,49 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django.db import models |
||||
|
from django.shortcuts import redirect |
||||
|
from django.urls import reverse |
||||
|
|
||||
|
from cotisations.models import Paiement |
||||
|
from cotisations.payment_methods.mixins import PaymentMethodMixin |
||||
|
|
||||
|
|
||||
|
class ChequePayment(PaymentMethodMixin, models.Model): |
||||
|
""" |
||||
|
The model allowing you to pay with a cheque. |
||||
|
""" |
||||
|
payment = models.OneToOneField( |
||||
|
Paiement, |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name='payment_method', |
||||
|
editable=False |
||||
|
) |
||||
|
|
||||
|
def end_payment(self, invoice, request): |
||||
|
"""Invalidates the invoice then redirect the user towards a view asking |
||||
|
for informations to add to the invoice before validating it. |
||||
|
""" |
||||
|
invoice.valid = False |
||||
|
invoice.save() |
||||
|
return redirect(reverse( |
||||
|
'cotisations:cheque:validate', |
||||
|
kwargs={'invoice_pk': invoice.pk} |
||||
|
)) |
||||
@ -0,0 +1,30 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django.conf.urls import url |
||||
|
from . import views |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url( |
||||
|
r'^validate/(?P<invoice_pk>[0-9]+)$', |
||||
|
views.cheque, |
||||
|
name='validate' |
||||
|
) |
||||
|
] |
||||
@ -0,0 +1,68 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
"""Payment |
||||
|
|
||||
|
Here are defined some views dedicated to cheque payement. |
||||
|
""" |
||||
|
|
||||
|
from django.urls import reverse |
||||
|
from django.shortcuts import redirect, render, get_object_or_404 |
||||
|
from django.contrib.auth.decorators import login_required |
||||
|
from django.contrib import messages |
||||
|
from django.utils.translation import ugettext as _ |
||||
|
|
||||
|
from cotisations.models import Facture as Invoice |
||||
|
|
||||
|
from .models import ChequePayment |
||||
|
from .forms import InvoiceForm |
||||
|
|
||||
|
|
||||
|
@login_required |
||||
|
def cheque(request, invoice_pk): |
||||
|
"""This view validate an invoice with the data from a cheque.""" |
||||
|
invoice = get_object_or_404(Invoice, pk=invoice_pk) |
||||
|
payment_method = getattr(invoice.paiement, 'payment_method', None) |
||||
|
if invoice.valid or not isinstance(payment_method, ChequePayment): |
||||
|
messages.error( |
||||
|
request, |
||||
|
_("You cannot pay this invoice with a cheque.") |
||||
|
) |
||||
|
return redirect(reverse( |
||||
|
'users:profil', |
||||
|
kwargs={'userid': request.user.pk} |
||||
|
)) |
||||
|
form = InvoiceForm(request.POST or None, instance=invoice) |
||||
|
if form.is_valid(): |
||||
|
form.instance.valid = True |
||||
|
form.save() |
||||
|
return form.instance.paiement.end_payment( |
||||
|
form.instance, |
||||
|
request, |
||||
|
use_payment_method=False |
||||
|
) |
||||
|
return render( |
||||
|
request, |
||||
|
'cotisations/payment.html', |
||||
|
{ |
||||
|
'form': form, |
||||
|
'amount': invoice.prix_total() |
||||
|
} |
||||
|
) |
||||
@ -0,0 +1,26 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
""" |
||||
|
This module contains a method to pay online using comnpay. |
||||
|
""" |
||||
|
from . import models, urls, views |
||||
|
NAME = "COMNPAY" |
||||
|
PaymentMethod = models.ComnpayPayment |
||||
@ -0,0 +1,88 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django.db import models |
||||
|
from django.shortcuts import render |
||||
|
from django.urls import reverse |
||||
|
from django.utils.translation import ugettext as _ |
||||
|
from django.utils.translation import ugettext_lazy as _l |
||||
|
|
||||
|
from cotisations.models import Paiement |
||||
|
from cotisations.payment_methods.mixins import PaymentMethodMixin |
||||
|
|
||||
|
from re2o.aes_field import AESEncryptedField |
||||
|
from .comnpay import Transaction |
||||
|
|
||||
|
|
||||
|
class ComnpayPayment(PaymentMethodMixin, models.Model): |
||||
|
""" |
||||
|
The model allowing you to pay with COMNPAY. |
||||
|
""" |
||||
|
payment = models.OneToOneField( |
||||
|
Paiement, |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name='payment_method', |
||||
|
editable=False |
||||
|
) |
||||
|
payment_credential = models.CharField( |
||||
|
max_length=255, |
||||
|
default='', |
||||
|
blank=True, |
||||
|
verbose_name=_l("ComNpay VAD Number"), |
||||
|
) |
||||
|
payment_pass = AESEncryptedField( |
||||
|
max_length=255, |
||||
|
null=True, |
||||
|
blank=True, |
||||
|
verbose_name=_l("ComNpay Secret Key"), |
||||
|
) |
||||
|
|
||||
|
def end_payment(self, invoice, request): |
||||
|
""" |
||||
|
Build a request to start the negociation with Comnpay by using |
||||
|
a facture id, the price and the secret transaction data stored in |
||||
|
the preferences. |
||||
|
""" |
||||
|
invoice.valid = False |
||||
|
invoice.save() |
||||
|
host = request.get_host() |
||||
|
p = Transaction( |
||||
|
str(self.payment_credential), |
||||
|
str(self.payment_pass), |
||||
|
'https://' + host + reverse( |
||||
|
'cotisations:comnpay:accept_payment', |
||||
|
kwargs={'factureid': invoice.id} |
||||
|
), |
||||
|
'https://' + host + reverse('cotisations:comnpay:refuse_payment'), |
||||
|
'https://' + host + reverse('cotisations:comnpay:ipn'), |
||||
|
"", |
||||
|
"D" |
||||
|
) |
||||
|
r = { |
||||
|
'action': 'https://secure.homologation.comnpay.com', |
||||
|
'method': 'POST', |
||||
|
'content': p.buildSecretHTML( |
||||
|
_("Pay invoice no : ")+str(invoice.id), |
||||
|
invoice.prix_total(), |
||||
|
idTransaction=str(invoice.id) |
||||
|
), |
||||
|
'amount': invoice.prix_total(), |
||||
|
} |
||||
|
return render(request, 'cotisations/payment.html', r) |
||||
@ -0,0 +1,20 @@ |
|||||
|
from django.conf.urls import url |
||||
|
from . import views |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url( |
||||
|
r'^accept/(?P<factureid>[0-9]+)$', |
||||
|
views.accept_payment, |
||||
|
name='accept_payment' |
||||
|
), |
||||
|
url( |
||||
|
r'^refuse/$', |
||||
|
views.refuse_payment, |
||||
|
name='refuse_payment' |
||||
|
), |
||||
|
url( |
||||
|
r'^ipn/$', |
||||
|
views.ipn, |
||||
|
name='ipn' |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,113 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django import forms |
||||
|
from django.utils.translation import ugettext as _ |
||||
|
from django.utils.translation import ugettext_lazy as _l |
||||
|
|
||||
|
from . import PAYMENT_METHODS |
||||
|
from cotisations.utils import find_payment_method |
||||
|
|
||||
|
def payment_method_factory(payment, *args, creation=True, **kwargs): |
||||
|
"""This function finds the right payment method form for a given payment. |
||||
|
|
||||
|
If the payment has a payment method, returns a ModelForm of it. Else if |
||||
|
it is the creation of the payment, a `PaymentMethodForm`. |
||||
|
Else an empty form. |
||||
|
|
||||
|
:param payment: The payment |
||||
|
:param *args: arguments passed to the form |
||||
|
:param creation: Should be True if you are creating the payment |
||||
|
:param **kwargs: passed to the form |
||||
|
|
||||
|
:returns: A form |
||||
|
""" |
||||
|
payment_method = kwargs.pop('instance', find_payment_method(payment)) |
||||
|
if payment_method is not None: |
||||
|
return forms.modelform_factory(type(payment_method), fields='__all__')( |
||||
|
*args, |
||||
|
instance=payment_method, |
||||
|
**kwargs |
||||
|
) |
||||
|
elif creation: |
||||
|
return PaymentMethodForm(*args, **kwargs) |
||||
|
else: |
||||
|
return forms.Form() |
||||
|
|
||||
|
|
||||
|
class PaymentMethodForm(forms.Form): |
||||
|
"""A special form which allows you to add a payment method to a `Payment` |
||||
|
object. |
||||
|
""" |
||||
|
|
||||
|
payment_method = forms.ChoiceField( |
||||
|
label=_l("Special payment method"), |
||||
|
help_text=_l("Warning : You will not be able to change the payment " |
||||
|
"method later. But you will be allowed to edit its " |
||||
|
"options." |
||||
|
), |
||||
|
required=False |
||||
|
) |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(PaymentMethodForm, self).__init__(*args, **kwargs) |
||||
|
prefix = kwargs.get('prefix', None) |
||||
|
self.fields['payment_method'].choices = [(i,p.NAME) for (i,p) in enumerate(PAYMENT_METHODS)] |
||||
|
self.fields['payment_method'].choices.insert(0, ('', _l('no'))) |
||||
|
self.fields['payment_method'].widget.attrs = { |
||||
|
'id': 'paymentMethodSelect' |
||||
|
} |
||||
|
self.templates = [ |
||||
|
forms.modelform_factory(p.PaymentMethod, fields='__all__')(prefix=prefix) |
||||
|
for p in PAYMENT_METHODS |
||||
|
] |
||||
|
|
||||
|
def clean(self): |
||||
|
"""A classic `clean` method, except that it replaces |
||||
|
`self.payment_method` by the payment method object if one has been |
||||
|
found. Tries to call `payment_method.valid_form` if it exists. |
||||
|
""" |
||||
|
super(PaymentMethodForm, self).clean() |
||||
|
choice = self.cleaned_data['payment_method'] |
||||
|
if choice=='': |
||||
|
return |
||||
|
choice = int(choice) |
||||
|
model = PAYMENT_METHODS[choice].PaymentMethod |
||||
|
form = forms.modelform_factory(model, fields='__all__')(self.data, prefix=self.prefix) |
||||
|
self.payment_method = form.save(commit=False) |
||||
|
if hasattr(self.payment_method, 'valid_form'): |
||||
|
self.payment_method.valid_form(self) |
||||
|
return self.cleaned_data |
||||
|
|
||||
|
|
||||
|
|
||||
|
def save(self, payment, *args, **kwargs): |
||||
|
"""Saves the payment method. |
||||
|
|
||||
|
Tries to call `payment_method.alter_payment` if it exists. |
||||
|
""" |
||||
|
commit = kwargs.pop('commit', True) |
||||
|
self.payment_method.payment = payment |
||||
|
if hasattr(self.payment_method, 'alter_payment'): |
||||
|
self.payment_method.alter_payment(payment) |
||||
|
if commit: |
||||
|
payment.save() |
||||
|
self.payment_method.save() |
||||
|
return self.payment_method |
||||
@ -0,0 +1,33 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
|
||||
|
|
||||
|
class PaymentMethodMixin: |
||||
|
"""A simple mixin to avoid redefining end_payment if you don't need to""" |
||||
|
|
||||
|
def end_payment(self, invoice, request): |
||||
|
"""Redefine this method in order to get a different ending to the |
||||
|
payment session if you whish. |
||||
|
|
||||
|
Must return a HttpResponse-like object. |
||||
|
""" |
||||
|
return self.payment.end_payment( |
||||
|
invoice, request, use_payment_method=False) |
||||
@ -0,0 +1,27 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
from django.conf.urls import include, url |
||||
|
from . import comnpay, cheque |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')), |
||||
|
url(r'^cheque/', include(cheque.urls, namespace='cheque')), |
||||
|
] |
||||
@ -1,158 +0,0 @@ |
|||||
{% extends "cotisations/sidebar.html" %} |
|
||||
{% comment %} |
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|
||||
se veut agnostique au réseau considéré, de manière à être installable en |
|
||||
quelques clics. |
|
||||
|
|
||||
Copyright © 2017 Gabriel Détraz |
|
||||
Copyright © 2017 Goulven Kermarec |
|
||||
Copyright © 2017 Augustin Lemesle |
|
||||
|
|
||||
This program is free software; you can redistribute it and/or modify |
|
||||
it under the terms of the GNU General Public License as published by |
|
||||
the Free Software Foundation; either version 2 of the License, or |
|
||||
(at your option) any later version. |
|
||||
|
|
||||
This program is distributed in the hope that it will be useful, |
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
GNU General Public License for more details. |
|
||||
|
|
||||
You should have received a copy of the GNU General Public License along |
|
||||
with this program; if not, write to the Free Software Foundation, Inc., |
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
||||
{% endcomment %} |
|
||||
|
|
||||
{% load bootstrap3 %} |
|
||||
{% load staticfiles%} |
|
||||
{% load i18n %} |
|
||||
|
|
||||
{% block title %}{% trans "Invoices creation and edition" %}{% endblock %} |
|
||||
|
|
||||
{% block content %} |
|
||||
{% bootstrap_form_errors venteform.management_form %} |
|
||||
|
|
||||
<form class="form" method="post"> |
|
||||
{% csrf_token %} |
|
||||
<h3>{% trans "New invoice" %}</h3> |
|
||||
{{ venteform.management_form }} |
|
||||
<!-- TODO: FIXME to include data-type="check" for right option in id_cheque select --> |
|
||||
<h3>{% trans "Invoice's articles" %}</h3> |
|
||||
<div id="form_set" class="form-group"> |
|
||||
{% for form in venteform.forms %} |
|
||||
<div class='product_to_sell form-inline'> |
|
||||
{% trans "Article" %} : |
|
||||
{% bootstrap_form form label_class='sr-only' %} |
|
||||
|
|
||||
<button class="btn btn-danger btn-sm" id="id_form-0-article-remove" type="button"> |
|
||||
<span class="fa fa-times"></span> |
|
||||
</button> |
|
||||
</div> |
|
||||
{% endfor %} |
|
||||
</div> |
|
||||
<input class="btn btn-primary btn-sm" role="button" value="{% trans "Add an article"%}" id="add_one"> |
|
||||
<p> |
|
||||
{% blocktrans %} |
|
||||
Total price : <span id="total_price">0,00</span> € |
|
||||
{% endblocktrans %} |
|
||||
</p> |
|
||||
{% trans "Confirm" as tr_confirm %} |
|
||||
{% bootstrap_button tr_confirm button_type='submit' icon='star' %} |
|
||||
</form> |
|
||||
|
|
||||
<script type="text/javascript"> |
|
||||
|
|
||||
var prices = {}; |
|
||||
{% for article in articlelist %} |
|
||||
prices[{{ article.id|escapejs }}] = {{ article.prix }}; |
|
||||
{% endfor %} |
|
||||
|
|
||||
var template = `Article : |
|
||||
{% bootstrap_form venteform.empty_form label_class='sr-only' %} |
|
||||
|
|
||||
<button class="btn btn-danger btn-sm" id="id_form-__prefix__-article-remove" type="button"> |
|
||||
<span class="fa fa-times"></span> |
|
||||
</button>` |
|
||||
|
|
||||
function add_article(){ |
|
||||
// Index start at 0 => new_index = number of items |
|
||||
var new_index = |
|
||||
document.getElementsByClassName('product_to_sell').length; |
|
||||
document.getElementById('id_form-TOTAL_FORMS').value ++; |
|
||||
var new_article = document.createElement('div'); |
|
||||
new_article.className = 'product_to_sell form-inline'; |
|
||||
new_article.innerHTML = template.replace(/__prefix__/g, new_index); |
|
||||
document.getElementById('form_set').appendChild(new_article); |
|
||||
add_listenner_for_id(new_index); |
|
||||
} |
|
||||
|
|
||||
function update_price(){ |
|
||||
var price = 0; |
|
||||
var product_count = |
|
||||
document.getElementsByClassName('product_to_sell').length; |
|
||||
var article, article_price, quantity; |
|
||||
for (i = 0; i < product_count; ++i){ |
|
||||
article = document.getElementById( |
|
||||
'id_form-' + i.toString() + '-article').value; |
|
||||
if (article == '') { |
|
||||
continue; |
|
||||
} |
|
||||
article_price = prices[article]; |
|
||||
quantity = document.getElementById( |
|
||||
'id_form-' + i.toString() + '-quantity').value; |
|
||||
price += article_price * quantity; |
|
||||
} |
|
||||
document.getElementById('total_price').innerHTML = |
|
||||
price.toFixed(2).toString().replace('.', ','); |
|
||||
} |
|
||||
|
|
||||
function add_listenner_for_id(i){ |
|
||||
document.getElementById('id_form-' + i.toString() + '-article') |
|
||||
.addEventListener("change", update_price, true); |
|
||||
document.getElementById('id_form-' + i.toString() + '-article') |
|
||||
.addEventListener("onkeypress", update_price, true); |
|
||||
document.getElementById('id_form-' + i.toString() + '-quantity') |
|
||||
.addEventListener("change", update_price, true); |
|
||||
document.getElementById('id_form-' + i.toString() + '-article-remove') |
|
||||
.addEventListener("click", function(event) { |
|
||||
var article = event.target.parentNode; |
|
||||
article.parentNode.removeChild(article); |
|
||||
document.getElementById('id_form-TOTAL_FORMS').value --; |
|
||||
update_price(); |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
|
|
||||
function set_cheque_info_visibility() { |
|
||||
var paiement = document.getElementById("id_Facture-paiement"); |
|
||||
var visible = paiement.value == paiement.getAttribute('data-cheque'); |
|
||||
p = document.getElementById("id_Facture-paiement"); |
|
||||
var display = 'none'; |
|
||||
if (visible) { |
|
||||
display = 'block'; |
|
||||
} |
|
||||
document.getElementById("id_Facture-cheque") |
|
||||
.parentNode.style.display = display; |
|
||||
document.getElementById("id_Facture-banque") |
|
||||
.parentNode.style.display = display; |
|
||||
} |
|
||||
|
|
||||
// Add events manager when DOM is fully loaded |
|
||||
document.addEventListener("DOMContentLoaded", function() { |
|
||||
document.getElementById("add_one") |
|
||||
.addEventListener("click", add_article, true); |
|
||||
var product_count = |
|
||||
document.getElementsByClassName('product_to_sell').length; |
|
||||
for (i = 0; i < product_count; ++i){ |
|
||||
add_listenner_for_id(i); |
|
||||
} |
|
||||
document.getElementById("id_Facture-paiement") |
|
||||
.addEventListener("change", set_cheque_info_visibility, true); |
|
||||
set_cheque_info_visibility(); |
|
||||
update_price(); |
|
||||
}); |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
{% endblock %} |
|
||||
|
|
||||
@ -1,45 +0,0 @@ |
|||||
{% extends "cotisations/sidebar.html" %} |
|
||||
{% comment %} |
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|
||||
se veut agnostique au réseau considéré, de manière à être installable en |
|
||||
quelques clics. |
|
||||
|
|
||||
Copyright © 2017 Gabriel Détraz |
|
||||
Copyright © 2017 Goulven Kermarec |
|
||||
Copyright © 2017 Augustin Lemesle |
|
||||
|
|
||||
This program is free software; you can redistribute it and/or modify |
|
||||
it under the terms of the GNU General Public License as published by |
|
||||
the Free Software Foundation; either version 2 of the License, or |
|
||||
(at your option) any later version. |
|
||||
|
|
||||
This program is distributed in the hope that it will be useful, |
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
GNU General Public License for more details. |
|
||||
|
|
||||
You should have received a copy of the GNU General Public License along |
|
||||
with this program; if not, write to the Free Software Foundation, Inc., |
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
||||
{% endcomment %} |
|
||||
|
|
||||
{% load bootstrap3 %} |
|
||||
{% load staticfiles%} |
|
||||
{% load i18n %} |
|
||||
|
|
||||
{% block title %}{% trans "Balance refill" %}{% endblock %} |
|
||||
|
|
||||
{% block content %} |
|
||||
<h2>{% trans "Balance refill" %}</h2> |
|
||||
<h3> |
|
||||
{% blocktrans %} |
|
||||
Balance : <span class="label label-default">{{ request.user.solde }} €</span> |
|
||||
{% endblocktrans %} |
|
||||
</h3> |
|
||||
<form class="form" method="post"> |
|
||||
{% csrf_token %} |
|
||||
{% bootstrap_form rechargeform %} |
|
||||
{% trans "Confirm" as tr_confirm %} |
|
||||
{% bootstrap_button tr_confirm button_type='submit' icon='piggy-bank' %} |
|
||||
</form> |
|
||||
{% endblock %} |
|
||||
@ -0,0 +1,32 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2018 Hugo Levy-Falk |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
|
||||
|
|
||||
|
def find_payment_method(payment): |
||||
|
"""Finds the payment method associated to the payment if it exists.""" |
||||
|
from cotisations.payment_methods import PAYMENT_METHODS |
||||
|
for method in PAYMENT_METHODS: |
||||
|
try: |
||||
|
o = method.PaymentMethod.objects.get(payment=payment) |
||||
|
return o |
||||
|
except method.PaymentMethod.DoesNotExist: |
||||
|
pass |
||||
|
return None |
||||
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-06-17 15:12 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('preferences', '0034_auto_20180416_1120'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='optionaluser', |
||||
|
name='allow_self_subscription', |
||||
|
field=models.BooleanField(default=False, help_text="Autoriser les utilisateurs à cotiser par eux mêmes via les moyens de paiement permettant l'auto-cotisation."), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,47 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2018-07-05 13:40 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('preferences', '0035_optionaluser_allow_self_subscription'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RemoveField( |
||||
|
model_name='assooption', |
||||
|
name='payment', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='assooption', |
||||
|
name='payment_id', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='assooption', |
||||
|
name='payment_pass', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='optionaluser', |
||||
|
name='allow_self_subscription', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='optionaluser', |
||||
|
name='max_solde', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='optionaluser', |
||||
|
name='min_online_payment', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='optionaluser', |
||||
|
name='solde_negatif', |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='optionaluser', |
||||
|
name='user_solde', |
||||
|
), |
||||
|
] |
||||
Loading…
Reference in new issue