mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-27 15:12:25 +00:00
Module de paiement par note
This commit is contained in:
parent
1e72a6b6eb
commit
6b1597c0c6
9 changed files with 365 additions and 2 deletions
31
cotisations/migrations/0035_notepayment.py
Normal file
31
cotisations/migrations/0035_notepayment.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.7 on 2018-09-01 11:27
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import cotisations.payment_methods.mixins
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cotisations', '0034_auto_20180831_1532'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NotePayment',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('server', models.CharField(max_length=255, verbose_name='server')),
|
||||||
|
('port', models.PositiveIntegerField(blank=True, null=True)),
|
||||||
|
('id_note', models.PositiveIntegerField(blank=True, null=True)),
|
||||||
|
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'NoteKfet',
|
||||||
|
},
|
||||||
|
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||||
|
),
|
||||||
|
]
|
|
@ -127,10 +127,11 @@ method to your model, where `form` is an instance of
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from . import comnpay, cheque, balance, urls
|
from . import comnpay, cheque, balance, note, urls
|
||||||
|
|
||||||
PAYMENT_METHODS = [
|
PAYMENT_METHODS = [
|
||||||
comnpay,
|
comnpay,
|
||||||
cheque,
|
cheque,
|
||||||
balance,
|
balance,
|
||||||
|
note
|
||||||
]
|
]
|
||||||
|
|
26
cotisations/payment_methods/note/__init__.py
Normal file
26
cotisations/payment_methods/note/__init__.py
Normal file
|
@ -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 Gabriel Detraz, Pierre-Antoine Comby
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
NAME = "NOTE"
|
||||||
|
PaymentMethod = models.NotePayment
|
38
cotisations/payment_methods/note/forms.py
Normal file
38
cotisations/payment_methods/note/forms.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- 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 Pierre-Antoine Comby
|
||||||
|
# Copyright © 2018 Gabriel Detraz
|
||||||
|
#
|
||||||
|
# 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_lazy as _
|
||||||
|
|
||||||
|
from cotisations.utils import find_payment_method
|
||||||
|
|
||||||
|
class NoteCredentialForm(forms.Form):
|
||||||
|
"""A special form to get credential to connect to a NoteKfet2015 server throught his API
|
||||||
|
object.
|
||||||
|
"""
|
||||||
|
login = forms.CharField(
|
||||||
|
label=_("pseudo note")
|
||||||
|
)
|
||||||
|
password = forms.CharField(
|
||||||
|
label=_("Password"),
|
||||||
|
widget=forms.PasswordInput
|
||||||
|
)
|
||||||
|
|
65
cotisations/payment_methods/note/models.py
Normal file
65
cotisations/payment_methods/note/models.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# -*- 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 Pierre-Antoine Comby
|
||||||
|
# Copyright © 2018 Gabriel Detraz
|
||||||
|
#
|
||||||
|
# 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_lazy as _
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
|
from cotisations.models import Paiement
|
||||||
|
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||||
|
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
|
||||||
|
|
||||||
|
class NotePayment(PaymentMethodMixin, models.Model):
|
||||||
|
"""
|
||||||
|
The model allowing you to pay with NoteKfet2015.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("NoteKfet")
|
||||||
|
|
||||||
|
payment = models.OneToOneField(
|
||||||
|
Paiement,
|
||||||
|
on_delete = models.CASCADE,
|
||||||
|
related_name = 'payment_method',
|
||||||
|
editable = False
|
||||||
|
)
|
||||||
|
server = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("server")
|
||||||
|
)
|
||||||
|
port = models.PositiveIntegerField(
|
||||||
|
blank = True,
|
||||||
|
null = True
|
||||||
|
)
|
||||||
|
id_note = models.PositiveIntegerField(
|
||||||
|
blank = True,
|
||||||
|
null = True
|
||||||
|
)
|
||||||
|
|
||||||
|
def end_payment(self, invoice, request):
|
||||||
|
return redirect(reverse(
|
||||||
|
'cotisations:note:note_payment',
|
||||||
|
kwargs={'factureid': invoice.id}
|
||||||
|
))
|
74
cotisations/payment_methods/note/note.py
Executable file
74
cotisations/payment_methods/note/note.py
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
# Codé par PAC , forké de 20-100
|
||||||
|
|
||||||
|
""" Module pour dialoguer avec la NoteKfet2015 """
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import json
|
||||||
|
import ssl
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
|
def get_response(socket):
|
||||||
|
length_str = b''
|
||||||
|
char = socket.recv(1)
|
||||||
|
while char != b'\n':
|
||||||
|
length_str += char
|
||||||
|
char = socket.recv(1)
|
||||||
|
total = int(length_str)
|
||||||
|
return json.loads(socket.recv(total).decode('utf-8'))
|
||||||
|
|
||||||
|
def connect(server, port):
|
||||||
|
sock = socket.socket()
|
||||||
|
try:
|
||||||
|
# On établit la connexion sur port 4242
|
||||||
|
sock.connect((server, port))
|
||||||
|
# On passe en SSL
|
||||||
|
sock = ssl.wrap_socket(sock)
|
||||||
|
# On fait un hello
|
||||||
|
sock.send(b'["hello", "manual"]')
|
||||||
|
retcode = get_response(sock)
|
||||||
|
except:
|
||||||
|
# Si on a foiré quelque part, c'est que le serveur est down
|
||||||
|
return (False, sock, "Serveur indisponible")
|
||||||
|
return (True, sock, "")
|
||||||
|
|
||||||
|
def login(server, port, username, password, masque = [[], [], True]):
|
||||||
|
result, sock, err = connect(server, port)
|
||||||
|
if not result:
|
||||||
|
return (False, None, err)
|
||||||
|
try:
|
||||||
|
commande = ["login", [username, password, "bdd", masque]]
|
||||||
|
sock.send(json.dumps(commande).encode("utf-8"))
|
||||||
|
response = get_response(sock)
|
||||||
|
retcode = response['retcode']
|
||||||
|
if retcode == 0:
|
||||||
|
return (True, sock, "")
|
||||||
|
elif retcode == 5:
|
||||||
|
return (False, sock, "Login incorrect")
|
||||||
|
else:
|
||||||
|
return (False, sock, "Erreur inconnue " + str(retcode))
|
||||||
|
except:
|
||||||
|
# Si on a foiré quelque part, c'est que le serveur est down
|
||||||
|
return (False, sock, "Erreur de communication avec le serveur")
|
||||||
|
|
||||||
|
|
||||||
|
def don(sock, montant, id_note, facture):
|
||||||
|
"""
|
||||||
|
Faire faire un don à l'id_note
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
sock.send(json.dumps(["dons", [[id_note], round(montant*100), "Facture : id=%s, designation=%s" % (facture.id, facture.name())]]).encode("utf-8"))
|
||||||
|
response = get_response(sock)
|
||||||
|
retcode = response['retcode']
|
||||||
|
transaction_retcode = response["msg"][0][0]
|
||||||
|
if 0 < retcode < 100 or 200 <= retcode or 0 < transaction_retcode < 100 or 200 <= transaction_retcode:
|
||||||
|
return (False, "Transaction échouée. (Solde trop négatif ?)")
|
||||||
|
elif retcode == 0:
|
||||||
|
return (True, "")
|
||||||
|
else:
|
||||||
|
return (False, "Erreur inconnue " + str(retcode))
|
||||||
|
except:
|
||||||
|
return (False, "Erreur de communication avec le serveur")
|
30
cotisations/payment_methods/note/urls.py
Normal file
30
cotisations/payment_methods/note/urls.py
Normal file
|
@ -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 Gabriel Detraz
|
||||||
|
#
|
||||||
|
# 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'^note_payment/(?P<factureid>[0-9]+)$',
|
||||||
|
views.note_payment,
|
||||||
|
name='note_payment'
|
||||||
|
),
|
||||||
|
]
|
97
cotisations/payment_methods/note/views.py
Normal file
97
cotisations/payment_methods/note/views.py
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# -*- 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 Gabriel Detraz
|
||||||
|
# Copyright © 2018 Pierre-Antoine Comby
|
||||||
|
#
|
||||||
|
# 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 the views needed by comnpay
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.shortcuts import redirect, get_object_or_404
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
from django.utils.datastructures import MultiValueDictKeyError
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.http import HttpResponse, HttpResponseBadRequest
|
||||||
|
|
||||||
|
from cotisations.models import Facture
|
||||||
|
from cotisations.utils import find_payment_method
|
||||||
|
from .models import NotePayment
|
||||||
|
from re2o.views import form
|
||||||
|
from re2o.acl import (
|
||||||
|
can_create,
|
||||||
|
can_edit
|
||||||
|
)
|
||||||
|
from .note import login, don
|
||||||
|
from .forms import NoteCredentialForm
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@can_edit(Facture)
|
||||||
|
def note_payment(request, facture, factureid):
|
||||||
|
"""
|
||||||
|
Build a request to start the negociation with NoteKfet by using
|
||||||
|
a facture id, the price and the login/password data stored in
|
||||||
|
the preferences.
|
||||||
|
"""
|
||||||
|
user = facture.user
|
||||||
|
payment_method = find_payment_method(facture.paiement)
|
||||||
|
if not payment_method or not isinstance(payment_method, NotePayment):
|
||||||
|
messages.error(request, "Erreur inconnue")
|
||||||
|
return redirect(reverse(
|
||||||
|
'users:profil',
|
||||||
|
kwargs={'userid': user.id}
|
||||||
|
))
|
||||||
|
noteform = NoteCredentialForm(request.POST or None)
|
||||||
|
if noteform.is_valid():
|
||||||
|
pseudo = noteform.cleaned_data['login']
|
||||||
|
password = noteform.cleaned_data['password']
|
||||||
|
result, sock, err = login(payment_method.server, payment_method.port, pseudo, password)
|
||||||
|
if not result:
|
||||||
|
messages.error(request, err)
|
||||||
|
return form(
|
||||||
|
{'form': noteform, 'amount': facture.prix_total()},
|
||||||
|
"cotisations/payment.html",
|
||||||
|
request
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
result, err = don(sock, facture.prix_total(), payment_method.id_note, facture)
|
||||||
|
if not result:
|
||||||
|
messages.error(request, err)
|
||||||
|
return form(
|
||||||
|
{'form': noteform, 'amount': facture.prix_total()},
|
||||||
|
"cotisations/payment.html",
|
||||||
|
request
|
||||||
|
)
|
||||||
|
facture.valid = True
|
||||||
|
facture.save()
|
||||||
|
messages.success(request, "Le paiement par note a bien été effectué")
|
||||||
|
return redirect(reverse(
|
||||||
|
'users:profil',
|
||||||
|
kwargs={'userid': user.id}
|
||||||
|
))
|
||||||
|
return form(
|
||||||
|
{'form': noteform, 'amount': facture.prix_total()},
|
||||||
|
"cotisations/payment.html",
|
||||||
|
request
|
||||||
|
)
|
|
@ -19,9 +19,10 @@
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from . import comnpay, cheque
|
from . import comnpay, cheque, note
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')),
|
url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')),
|
||||||
url(r'^cheque/', include(cheque.urls, namespace='cheque')),
|
url(r'^cheque/', include(cheque.urls, namespace='cheque')),
|
||||||
|
url(r'^note/', include(note.urls, namespace='note')),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue