implement support for SAGA payment system (#17228)
This commit is contained in:
parent
89c213a491
commit
1b17c0b1c5
|
@ -0,0 +1,33 @@
|
|||
# combo-plugin-nanterre - Combo Nanterre plugin
|
||||
# Copyright (C) 2017 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import django.apps
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class Plugin(object):
|
||||
def get_apps(self):
|
||||
return [__name__]
|
||||
|
||||
class AppConfig(django.apps.AppConfig):
|
||||
name = __name__
|
||||
verbose_name = _('Nanterre extension')
|
||||
|
||||
def get_after_urls(self):
|
||||
from . import urls
|
||||
return urls.urlpatterns
|
||||
|
||||
default_app_config = __name__ + '.AppConfig'
|
|
@ -0,0 +1,28 @@
|
|||
# combo-plugin-nanterre - Combo Nanterre plugin
|
||||
# Copyright (C) 2017 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import saga_transaction, saga_retour_asynchrone, saga_retour_synchrone
|
||||
|
||||
urlpatterns = [
|
||||
url('^_plugin/nanterre/saga-transaction/*$', saga_transaction,
|
||||
name='nanterre-saga-transaction'),
|
||||
url('^_plugin/nanterre/saga-retour-asynchrone/*$', saga_retour_asynchrone,
|
||||
name='nanterre-saga-retour-asynchrone'),
|
||||
url('^_plugin/nanterre/saga-retour-synchrone/*$', saga_retour_synchrone,
|
||||
name='nanterre-saga-retour-synchrone'),
|
||||
]
|
|
@ -0,0 +1,163 @@
|
|||
# combo-plugin-nanterre - Combo Nanterre plugin
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from combo.utils import requests, get_templated_url
|
||||
|
||||
|
||||
ERROR_MESSAGE = ("Le système de paiement n'est pas disponible, "
|
||||
"veuillez essayer ultérieurement.")
|
||||
MESSAGE_BY_STATE = {
|
||||
'paye': (messages.SUCCESS, "Le paiement a bien été effectué."),
|
||||
'abandon': (messages.WARNING, "Le paiement a été annulé."),
|
||||
'refus': (messages.WARNING, "Le paiement a été refusé."),
|
||||
}
|
||||
|
||||
|
||||
def rsu_post(request, endpoint, payload):
|
||||
timeout = getattr(settings, 'NANTERRE_PAYMENT_TIMEOUT', 10)
|
||||
url = '[zoo_url]rsu/' + endpoint
|
||||
context = RequestContext(request, {'request': request})
|
||||
url = get_templated_url(url, context=context)
|
||||
return requests.post(url, json=payload, timeout=timeout).json()
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@login_required
|
||||
def saga_transaction(request):
|
||||
logger = logging.getLogger('combo_plugin_nanterre.saga_transaction')
|
||||
num_factures = request.POST.getlist('num_factures')
|
||||
email = request.POST.get('email') or request.user.email
|
||||
error_url = request.POST.get('error_url') or '/'
|
||||
|
||||
urlretour_asynchrone = request.build_absolute_uri(
|
||||
reverse('nanterre-saga-retour-asynchrone')).rstrip('/')
|
||||
urlretour_synchrone = request.build_absolute_uri(
|
||||
reverse('nanterre-saga-retour-synchrone')).rstrip('/')
|
||||
|
||||
payload = {
|
||||
'num_factures': num_factures,
|
||||
'email': email,
|
||||
'urlretour_asynchrone': urlretour_asynchrone,
|
||||
'urlretour_synchrone': urlretour_synchrone,
|
||||
}
|
||||
try:
|
||||
saga = rsu_post(request, 'saga/[user_nameid]/transaction/', payload)
|
||||
except:
|
||||
logger.error('[rsu/saga] failed to create transaction '
|
||||
'for num_factures=%s', num_factures)
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
return HttpResponseRedirect(error_url)
|
||||
if not isinstance(saga, dict) or not saga.get('data', {}).get('url'):
|
||||
logger.error('[rsu/saga] failed to create transaction '
|
||||
'for num_factures=%s, received bad response=%r',
|
||||
num_factures, saga)
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
return HttpResponseRedirect(error_url)
|
||||
if saga.get('errors'):
|
||||
logger.warning('[rsu/saga] failed to create transaction '
|
||||
'for num_factures=%s, errors=%r',
|
||||
num_factures, saga['errors'])
|
||||
for error in saga['errors']:
|
||||
messages.error(request, error)
|
||||
return HttpResponseRedirect(error_url)
|
||||
if saga.get('err') != 0:
|
||||
logger.warning('[rsu/saga] failed to create transaction '
|
||||
'for num_factures=%s, unknown error, code=%r',
|
||||
num_factures, saga['err'])
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
return HttpResponseRedirect(error_url)
|
||||
|
||||
# finally, response seems good! redirect to payment system URL
|
||||
logger.info('[rsu/saga] new transaction created '
|
||||
'for num_factures=%s, redirect to %s',
|
||||
num_factures, saga['data']['url'])
|
||||
return HttpResponseRedirect(saga['data']['url'])
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@login_required
|
||||
def saga_retour_synchrone(request):
|
||||
logger = logging.getLogger('combo_plugin_nanterre.saga_retour_synchrone')
|
||||
next_url = getattr(settings, 'NANTERRE_PAYMENT_RESULT_PAGE', '/')
|
||||
idop = request.GET.get('idop')
|
||||
payload = {'idop': idop}
|
||||
try:
|
||||
saga = rsu_post(request, 'saga/retour-synchrone/', payload)
|
||||
except:
|
||||
logger.error('[rsu/saga] retour-synchrone: cannot post idop=%s', idop)
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
return HttpResponseRedirect(next_url)
|
||||
|
||||
# add a result message and redirect
|
||||
if (isinstance(saga, dict) and saga.get('err') == 0
|
||||
and saga.get('data', {}).get('etat')):
|
||||
etat = saga['data']['etat']
|
||||
if etat in MESSAGE_BY_STATE:
|
||||
logger.info('[rsu/saga] retour-synchrone: idop=%s etat=%s',
|
||||
idop, etat)
|
||||
messages.add_message(request, *MESSAGE_BY_STATE[etat])
|
||||
else:
|
||||
logger.error('[rsu/saga] retour-synchrone: idop=%s '
|
||||
'receive unknown etat=%s', idop, etat)
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
else:
|
||||
logger.error('[rsu/saga] retour-synchrone: idop=%s '
|
||||
'receive bad response=%r', idop, saga)
|
||||
messages.error(request, ERROR_MESSAGE)
|
||||
return HttpResponseRedirect(next_url)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def saga_retour_asynchrone(request):
|
||||
logger = logging.getLogger('combo_plugin_nanterre.saga_retour_asynchrone')
|
||||
idop = request.GET.get('idop')
|
||||
payload = {'idop': idop}
|
||||
err = 0
|
||||
try:
|
||||
saga = rsu_post(request, 'saga/retour-asynchrone/', payload)
|
||||
except:
|
||||
err = 1
|
||||
logger.error('[rsu/saga] retour-asynchrone: cannot post idop=%s', idop)
|
||||
else:
|
||||
if (isinstance(saga, dict) and saga.get('err') == 0
|
||||
and saga.get('data', {}).get('etat')):
|
||||
etat = saga['data']['etat']
|
||||
if etat in MESSAGE_BY_STATE:
|
||||
logger.info('[rsu/saga] retour-asynchrone: idop=%s etat=%s',
|
||||
idop, etat)
|
||||
else:
|
||||
err = 1
|
||||
logger.error('[rsu/saga] retour-asynchrone: idop=%s '
|
||||
'receive unknown etat=%s', idop, etat)
|
||||
else:
|
||||
err = 1
|
||||
logger.error('[rsu/saga] retour-asynchrone: idop=%s '
|
||||
'receive bad response=%r', idop, saga)
|
||||
response = HttpResponse(content_type='application/json')
|
||||
response.write(json.dumps({'err': err}))
|
||||
return response
|
Loading…
Reference in New Issue