Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADD] Nuevo modulo para pagos con tarjeta de credito (sermepa-redsys) #72

Merged
merged 7 commits into from
Dec 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions payment_redsys/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Pasarela de pago Redsys
=======================


Este modulo añade la opcion de pago a traves de la pasarela de Redsys



PARAMETROS:

Nombre del comercio: Indicaremos el nombre del comercio.

Número de comercio (FUC): Indicaremos el número de comercio que
nuestra entidad nos ha comunicado.

Clave secreta de encriptación: Indicaremos la clave de encriptación
que tiene el comercio.

Número de terminal: Indicaremos el terminal del TPV.

Tipo de firma: Seleccionaremos el tipo de firma del comercio.

Tipo de moneda: Seleccionaremos la moneda de nuestro terminal TPV
(Normalmente Euros).

Tipo de transacción: Indicaremos el tipo de transacción, 0.

Idiomas TPV: Indicaremos el idiomas en el TPV.

URL_OK/URL_KO: durante el proceso del pago, y una vez que
se muestra al cliente la pantalla con el resultado del mismo, es
posible redirigir su navegador a una URL para las transacciones
autorizadas y a otra si la transacción ha sido denegada. A estas
se las denomina URL_OK y URL_KO, respectivamente. Se trata
de dos URL que pueden ser proporcionadas por el comercio.



Requirements
------------

Odoo v8.0


Note
----

Se tiene que verificar la configuración del comercio en el
módulo de administración de Redsys, donde la opción “Parámetros en las
URLs” debe tener el valor “SI”.
23 changes: 23 additions & 0 deletions payment_redsys/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
#
# 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 . import models
from . import controllers
16 changes: 16 additions & 0 deletions payment_redsys/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-

{
'name': 'Redsys Payment Acquirer',
'category': 'Hidden',
'summary': 'Payment Acquirer: Redsys Implementation',
'version': '1.0',
'author': 'Incaser Informatica S.L.',
'depends': ['payment'],
'data': [
'views/redsys.xml',
'views/payment_acquirer.xml',
'data/redsys.xml',
],
'installable': True,
}
3 changes: 3 additions & 0 deletions payment_redsys/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

from . import main
35 changes: 35 additions & 0 deletions payment_redsys/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
import logging
import pprint
import werkzeug

from openerp import http, SUPERUSER_ID
from openerp.http import request

_logger = logging.getLogger(__name__)


class RedsysController(http.Controller):
_return_url = '/payment/redsys/return'
_cancel_url = '/payment/redsys/cancel'
_exception_url = '/payment/redsys/error'
_reject_url = '/payment/redsys/reject'

@http.route([
'/payment/redsys/return',
'/payment/redsys/cancel',
'/payment/redsys/error',
'/payment/redsys/reject',
], type='http', auth='none')
def redsys_return(self, **post):
""" Redsys."""
_logger.info('Redsys: entering form_feedback with post data %s',
pprint.pformat(post))
if post:
request.registry['payment.transaction'].form_feedback(
request.cr, SUPERUSER_ID, post, 'redsys',
context=request.context)
return_url = post.pop('return_url', '')
if not return_url:
return_url = '/shop'
return werkzeug.utils.redirect(return_url)
17 changes: 17 additions & 0 deletions payment_redsys/data/redsys.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">

<record id="payment_acquirer_redsys" model="payment.acquirer">
<field name="name">Credit Card Redsys</field>
<field name="provider">redsys</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="redsys_acquirer_button"/>
<field name="environment">test</field>
<field name="pre_msg"><![CDATA[
<p>You will be redirected to the redsys website after cliking on the payment button.</p>]]>
</field>
</record>

</data>
</openerp>
3 changes: 3 additions & 0 deletions payment_redsys/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

from . import redsys
243 changes: 243 additions & 0 deletions payment_redsys/models/redsys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# -*- coding: utf-8 -*-
from hashlib import sha1
import logging
import urlparse

from openerp import models, fields, api, _
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.tools.float_utils import float_compare
from datetime import datetime
_logger = logging.getLogger(__name__)


class AcquirerRedsys(models.Model):
_inherit = 'payment.acquirer'

def _get_redsys_urls(self, environment):
""" Redsys URLs
"""
if environment == 'prod':
return {
'redsys_form_url':
'https://sis.redsys.es/sis/realizarPago/',
}
else:
return {
'redsys_form_url':
'https://sis-t.redsys.es:25443/sis/realizarPago/',
}

@api.model
def _get_providers(self):
providers = super(AcquirerRedsys, self)._get_providers()
providers.append(['redsys', 'Redsys'])
return providers

redsys_merchant_url = fields.Char('Merchant URL',
required_if_provider='redsys')
redsys_merchant_name = fields.Char('Merchant Name',
required_if_provider='redsys')
redsys_merchant_titular = fields.Char('Merchant Titular',
required_if_provider='redsys')
redsys_merchant_code = fields.Char('Merchant code',
required_if_provider='redsys')
redsys_merchant_description = fields.Char('Product Description',
required_if_provider='redsys')
redsys_secret_key = fields.Char('Secret Key',
required_if_provider='redsys')
redsys_terminal = fields.Char('Terminal', default='1',
required_if_provider='redsys')
redsys_currency = fields.Char('Currency', default='978',
required_if_provider='redsys')
redsys_transaction_type = fields.Char('Transtaction Type', default='0',
required_if_provider='redsys')
redsys_merchant_data = fields.Char('Merchant Data')
redsys_merchant_lang = fields.Selection([('001', 'Castellano'),
('004', 'Frances'),
], 'Merchant Consumer Language')
redsys_pay_method = fields.Selection([('T', 'Pago con Tarjeta'),
('R', 'Pago por Transferencia'),
('D', 'Domiciliacion'),
], 'Payment Method',
default='T')
redsys_url_ok = fields.Char('URL OK')
redsys_url_ko = fields.Char('URL KO')

def _redsys_generate_digital_sign(self, acquirer, inout, values):
""" Generate the shasign for incoming or outgoing communications.
:param browse acquirer: the payment.acquirer browse record. It should
have a shakey in shaky out
:param string inout: 'in' (encoding) or 'out' (decoding).
:param dict values: transaction values

:return string: shasign
"""
assert acquirer.provider == 'redsys'

def get_value(key):
if values.get(key):
return values[key]
return ''

if inout == 'out':
keys = ['Ds_Amount',
'Ds_Order',
'Ds_MerchantCode',
'Ds_Currency',
'Ds_Response']
else:
keys = ['Ds_Merchant_Amount',
'Ds_Merchant_Order',
'Ds_Merchant_MerchantCode',
'Ds_Merchant_Currency',
'Ds_Merchant_TransactionType',
'Ds_Merchant_MerchantURL']
sign = ''.join('%s' % (get_value(k)) for k in keys)
# Add the pre-shared secret key at the end of the signature
sign = sign + acquirer.redsys_secret_key
if isinstance(sign, str):
sign = urlparse.parse_qsl(sign)
shasign = sha1(sign).hexdigest().upper()
return shasign

@api.model
def redsys_form_generate_values(self, id, partner_values, tx_values):
acquirer = self.browse(id)
tx_values['reference'] += datetime.now().strftime('%M%S')
redsys_tx_values = dict(tx_values)
redsys_tx_values.update({
'Ds_Sermepa_Url':
(self._get_redsys_urls(acquirer.environment)
['redsys_form_url']),
'Ds_Merchant_Amount': int(tx_values['amount'] * 100),
'Ds_Merchant_Currency': acquirer.redsys_currency or '978',
'Ds_Merchant_Order': tx_values['reference'][:12],
'Ds_Merchant_MerchantCode': acquirer.redsys_merchant_code and
acquirer.redsys_merchant_code[:9],
'Ds_Merchant_Terminal': acquirer.redsys_terminal or '1',
'Ds_Merchant_TransactionType': (
acquirer.redsys_transaction_type or '0'),
'Ds_Merchant_Titular': acquirer.redsys_merchant_titular[:60] and
acquirer.redsys_merchant_titular[:60],
'Ds_Merchant_MerchantName': acquirer.redsys_merchant_name and
acquirer.redsys_merchant_name[:25],
'Ds_Merchant_MerchantURL':
(acquirer.redsys_merchant_url
and acquirer.redsys_merchant_url[:250] or ''),
'Ds_Merchant_MerchantData': acquirer.redsys_merchant_data or '',
'Ds_Merchant_ProductDescription': (
acquirer.redsys_merchant_description and
acquirer.redsys_merchant_description[:125]),
'Ds_Merchant_ConsumerLanguage': (
acquirer.redsys_merchant_lang or '001'),
'Ds_Merchant_UrlOK': acquirer.redsys_url_ok or '',
'Ds_Merchant_UrlKO': acquirer.redsys_url_ko or '',
'Ds_Merchant_PayMethods': acquirer.redsys_pay_method or 'T',
})

redsys_tx_values['Ds_Merchant_MerchantSignature'] = (
self._redsys_generate_digital_sign(
acquirer, 'in', redsys_tx_values))
return partner_values, redsys_tx_values

@api.multi
def redsys_get_form_action_url(self):
return self._get_redsys_urls(self.environment)['redsys_form_url']


class TxRedsys(models.Model):
_inherit = 'payment.transaction'

redsys_txnid = fields.Char('Transaction ID')

# --------------------------------------------------
# FORM RELATED METHODS
# --------------------------------------------------

@api.model
def _redsys_form_get_tx_from_data(self, data):
""" Given a data dict coming from redsys, verify it and
find the related transaction record. """
reference = data.get('Ds_Order', '')[:-4]
pay_id = data.get('Ds_AuthorisationCode')
shasign = data.get('Ds_Signature')
if not reference or not pay_id or not shasign:
error_msg = 'Redsys: received data with missing reference' \
' (%s) or pay_id (%s) or shashign (%s)' % (reference,
pay_id, shasign)
_logger.error(error_msg)
raise ValidationError(error_msg)

tx = self.search([('reference', '=', reference)])
if not tx or len(tx) > 1:
error_msg = 'Redsys: received data for reference %s' % (reference)
if not tx:
error_msg += '; no order found'
else:
error_msg += '; multiple order found'
_logger.error(error_msg)
raise ValidationError(error_msg)

# verify shasign
acquirer = self.env['payment.acquirer']
shasign_check = acquirer._redsys_generate_digital_sign(
tx.acquirer_id, 'out', data)
if shasign_check.upper() != shasign.upper():
error_msg = 'Redsys: invalid shasign, received %s, computed %s,' \
' for data %s' % (shasign, shasign_check, data)
_logger.error(error_msg)
raise ValidationError(error_msg)
return tx

@api.model
def _redsys_form_get_invalid_parameters(self, tx, data):
invalid_parameters = []

if (tx.acquirer_reference
and data.get('Ds_Order')) != tx.acquirer_reference:
invalid_parameters.append(
('Transaction Id', data.get('Ds_Order'),
tx.acquirer_reference))
# check what is buyed
if (float_compare(float(data.get('Ds_Amount', '0.0'))/100,
tx.amount, 2) != 0):
invalid_parameters.append(('Amount', data.get('Ds_Amount'),
'%.2f' % tx.amount))
return invalid_parameters

@api.model
def _redsys_form_validate(self, tx, data):
status_code = int(data.get('Ds_Response', '29999'))
if (status_code >= 0) and (status_code <= 99):
tx.write({
'state': 'done',
'redsys_txnid': data.get('Ds_AuthorisationCode'),
'state_message': _('Ok: %s') % data.get('Ds_Response'),
})
return True
if (status_code >= 101) and (status_code <= 202):
# 'Payment error: code: %s.'
tx.write({
'state': 'pending',
'redsys_txnid': data.get('Ds_AuthorisationCode'),
'state_message': _('Error: %s') % data.get('Ds_Response'),
})
return True
if (status_code == 912) and (status_code == 9912):
# 'Payment error: bank unavailable.'
tx.write({
'state': 'cancel',
'redsys_txnid': data.get('Ds_AuthorisationCode'),
'state_message': (_('Bank Error: %s')
% data.get('Ds_Response')),
})
return True
else:
error = 'Redsys: feedback error'
_logger.info(error)
tx.write({
'state': 'error',
'redsys_txnid': data.get('Ds_AuthorisationCode'),
'state_message': error,
})
return False
Binary file added payment_redsys/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added payment_redsys/static/src/img/redsys_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading