mirror of https://gitlab.federez.net/re2o/re2o
Browse Source
Module de paiement par note See merge request federez/re2o!285add_link_port_search_results
9 changed files with 365 additions and 2 deletions
@ -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), |
||||
|
), |
||||
|
] |
||||
@ -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 |
||||
@ -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 |
||||
|
) |
||||
|
|
||||
@ -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_kfet:note_payment', |
||||
|
kwargs={'factureid': invoice.id} |
||||
|
)) |
||||
@ -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") |
||||
@ -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' |
||||
|
), |
||||
|
] |
||||
@ -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 |
||||
|
) |
||||
Loading…
Reference in new issue