[MERGE] [REVIEW] payment and payment-related modules cleaning, fixing and improvement.

[RENAME] payment_acquirer_* -> payment_ *

[CLEAN] payment_paypal duplicate of portal.payment.acquirer
- [REM] portal.payment.acquirer model, now replaced by payment.acquirer
- paypal banner generation on sale orders and invoices is done using the new payment.acquirer model. It basically works like the old portal.payment.acquirer, using a render_payment_block method.

[CLEAN] payment_paypal and paypal_account field of res.company
- in account: paypal_account is a char field (nothing changes)
- when installing payment_paypal: the char field is replaced by a function field that looks in the payment.acquirer table for paypal instances and get the first one back
- when installing payment_paypal, the company.paypal_account value is used to replace the default paypal data
- this function field and 'migration mechanism' are company aware

[IMP] payment: added pre_msg, post_msg, that are messages to be displayed before payment (like redirection warning for Paypal) and after payment (like account and communication details for transfer). Added a default message for transfer taking the visible company bank accounts.

[IMP] payment: added manual / automatic distinction. eCommerce use this information to decide whether to poll the tx status or display an information message.

[FIX] payment_*: fixed return controlers, using werkzeug.redirect instead of request.redirect that does not work anymore

[IMP] configuration
- added checkboxes to install paypal, ogone and adyen directly from the invoicing configuration

bzr revid: tde@openerp.com-20140124152541-y6e6kset056jbpkv
This commit is contained in:
Thibault Delavallée 2014-01-24 16:25:41 +01:00
commit 86dcc20dcb
92 changed files with 442 additions and 341 deletions

View File

@ -230,14 +230,14 @@
<group name="bank_cash">
<label for="id" string="Configuration"/>
<div>
<div>
<div name='company_footer'>
<label for="company_footer"/>
<button name="open_company_form" type="object"
string="Configure your company bank accounts" icon="gtk-go-forward"
class="oe_inline oe_link"/>
<field name="company_footer"/>
</div>
<div>
<div name='payment_acquirer'>
<label for="paypal_account"/>
<field name="paypal_account" placeholder="e.g. sales@openerp.com" class="oe_inline"/>
</div>

View File

@ -7,9 +7,10 @@
'version': '1.0',
'description': """Payment Acquirer Base Module""",
'author': 'OpenERP SA',
'depends': ['mail'],
'depends': ['mail', 'account'],
'data': [
'views/payment_acquirer.xml',
'views/res_config_view.xml',
'security/ir.model.access.csv',
],
'installable': True,

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import payment_acquirer
import res_config

View File

@ -3,7 +3,8 @@
import logging
from openerp.osv import osv, fields
from openerp.tools import float_round
from openerp.tools import float_round, float_repr
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@ -28,8 +29,8 @@ class PaymentAcquirer(osv.Model):
to have required fields that depend on a specific acquirer.
Each acquirer has a link to an ir.ui.view record that is a template of
a button used to display the payment form. See examples in ``payment_acquirer_ogone``
and ``payment_acquirer_paypal`` modules.
a button used to display the payment form. See examples in ``payment_ogone``
and ``payment_paypal`` modules.
Methods that should be added in an acquirer-specific implementation:
@ -54,13 +55,18 @@ class PaymentAcquirer(osv.Model):
_columns = {
'name': fields.char('Name', required=True),
'company_id': fields.many2one('res.company', 'Company', required=True),
'message': fields.html('Message', help='Message displayed to help payment and validation'),
'pre_msg': fields.html('Message', help='Message displayed to explain and help the payment process.'),
'post_msg': fields.html('Thanks Message', help='Message displayed after having done the payment process.'),
'validation': fields.selection(
[('manual', 'Manual'), ('automatic', 'Automatic')],
string='Process Method',
help='Static payments are payments like transfer, that require manual steps.'),
'view_template_id': fields.many2one('ir.ui.view', 'Form Button Template', required=True),
'env': fields.selection(
[('test', 'Test'), ('prod', 'Production')],
string='Environment'),
'portal_published': fields.boolean(
'Visible in Portal',
'website_published': fields.boolean(
'Visible in Portal / Website',
help="Make this payment acquirer available (Customer invoices, etc.)"),
# Fees
'fees_active': fields.boolean('Compute fees'),
@ -73,7 +79,8 @@ class PaymentAcquirer(osv.Model):
_defaults = {
'company_id': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(cr, uid, uid).company_id.id,
'env': 'test',
'portal_published': True,
'validation': 'automatic',
'website_published': True,
}
def _check_required_if_provider(self, cr, uid, ids, context=None):
@ -185,7 +192,7 @@ class PaymentAcquirer(osv.Model):
- acquirer: the payment.acquirer browse record
- user: the current user browse record
- currency: currency browse record
- currency_id: id of the transaction currency
- amount: amount of the transaction
- reference: reference of the transaction
- partner: the current partner browse record, if any (not necessarily set)
@ -253,6 +260,36 @@ class PaymentAcquirer(osv.Model):
# because render accepts view ids but not qweb -> need to use the xml_id
return self.pool['ir.ui.view'].render(cr, uid, acquirer.view_template_id.xml_id, qweb_context, engine='ir.qweb', context=context)
def _wrap_payment_block(self, cr, uid, html_block, amount, currency_id, context=None):
payment_header = _('Pay safely online')
amount_str = float_repr(amount, self.pool.get('decimal.precision').precision_get(cr, uid, 'Account'))
currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context)
currency_str = currency.symbol or currency.name
amount = u"%s %s" % ((currency_str, amount_str) if currency.position == 'before' else (amount_str, currency_str))
result = """<div class="payment_acquirers">
<div class="payment_header">
<div class="payment_amount">%s</div>
%s
</div>
%%s
</div>""" % (amount, payment_header)
return result % html_block
def render_payment_block(self, cr, uid, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_values=None, context=None):
html_forms = []
acquirer_ids = self.search(cr, uid, [('website_published', '=', True), ('validation', '=', 'automatic')], context=context)
for acquirer_id in acquirer_ids:
button = self.render(
cr, uid, acquirer_id,
reference, amount, currency_id,
tx_id, partner_id, partner_values, tx_values,
context)
html_forms.append(button)
if not html_forms:
return ''
html_block = '\n'.join(filter(None, html_forms))
return self._wrap_payment_block(cr, uid, html_block, amount, currency_id, context=context)
class PaymentTransaction(osv.Model):
""" Transaction Model. Each specific acquirer can extend the model by adding

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
class AccountPaymentConfig(osv.TransientModel):
_inherit = 'account.config.settings'
_columns = {
'module_payment_paypal': fields.boolean(
'Manage Payments Using Paypal',
help='Blahblahblah\n'
'-It installs the module payment_paypal.'),
'module_payment_ogone': fields.boolean(
'Manage Payments Using Ogone',
help='Blahblahblah\n'
'-It installs the module payment_ogone.'),
'module_payment_adyen': fields.boolean(
'Manage Payments Using Adyen',
help='Blahblahblah\n'
'-It installs the module payment_adyen.'),
}

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -17,7 +17,7 @@
<group>
<field name="name"/>
<field name="company_id"/>
<field name="portal_published"/>
<field name="website_published"/>
<field name="env"/>
</group>
<group>
@ -33,7 +33,8 @@
</group>
</group>
<group name="acquirer_display">
<field name="message"/>
<field name="pre_msg"/>
<field name="post_msg"/>
<label for="view_template_id"/>
<div>
<field name="view_template_id" nolabel="1"/>
@ -65,7 +66,7 @@
<field name="arch" type="xml">
<tree string="Payment Acquirers">
<field name="name"/>
<field name="portal_published"/>
<field name="website_published"/>
<field name="env"/>
</tree>
</field>

View File

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Add payment options to sale.order and invoice forms -->
<record model="ir.ui.view" id="payment_acquirer_installation">
<field name="model">account.config.settings</field>
<field name="inherit_id" ref="account.view_account_config_settings"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='payment_acquirer']" version="7.0" position="inside">
<div>
<field name="module_payment_paypal" class="oe_inline"/>
<label for="module_payment_paypal"/>
</div>
<div>
<field name="module_payment_ogone" class="oe_inline"/>
<label for="module_payment_ogone"/>
</div>
<div>
<field name="module_payment_adyen" class="oe_inline"/>
<label for="module_payment_adyen"/>
</div>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -7,7 +7,7 @@
'version': '1.0',
'description': """Adyen Payment Acquirer""",
'author': 'OpenERP SA',
'depends': ['payment_acquirer'],
'depends': ['payment'],
'data': [
'views/adyen.xml',
'views/payment_acquirer.xml',

View File

@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
from openerp.addons.web import http
from openerp.addons.web.http import request
try:
import simplejson as json
except ImportError:
import json
import logging
import pprint
import werkzeug
from openerp.addons.web import http
from openerp.addons.web.http import request
_logger = logging.getLogger(__name__)
@ -18,7 +19,7 @@ class AdyenController(http.Controller):
@http.route([
'/payment/adyen/return/',
], type='http', auth='public', website=True)
], type='http', auth='admin')
def adyen_return(self, pspReference, **post):
""" Paypal IPN."""
post["pspReference"] = pspReference
@ -28,4 +29,4 @@ class AdyenController(http.Controller):
if not return_url:
custom = json.loads(post.pop('merchantReturnData', '{}'))
return_url = custom.pop('return_url', '/')
return request.redirect(return_url)
return werkzeug.utils.redirect(return_url)

View File

@ -4,8 +4,11 @@
<record id="payment_acquirer_adyen" model="payment.acquirer">
<field name="name">adyen</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="adyen_acquirer_button"/>
<field name="env">test</field>
<field name="pre_msg"><![CDATA[
<p>You will be redirected to the Adyen website after cliking on the payment button.</p>]]></field>
<field name="adyen_merchant_account">dummy</field>
<field name="adyen_skin_code">dummy</field>
<field name="adyen_skin_hmac_key">dummy</field>

View File

@ -10,8 +10,8 @@ import hmac
import logging
import urlparse
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer_adyen.controllers.main import AdyenController
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment_adyen.controllers.main import AdyenController
from openerp.osv import osv, fields
from openerp.tools import float_round

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -3,9 +3,9 @@
from lxml import objectify
import urlparse
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_acquirer_adyen.controllers.main import AdyenController
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_adyen.controllers.main import AdyenController
from openerp.osv.orm import except_orm
from openerp.tools import mute_logger
@ -18,7 +18,7 @@ class AdyenCommon(PaymentAcquirerCommon):
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
# get the adyen account
model, self.adyen_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_adyen', 'payment_acquirer_adyen')
model, self.adyen_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_adyen', 'payment_acquirer_adyen')
# some CC (always use expiration date 06 / 2016, cvc 737, cid 7373 (amex))
self.amex = (('370000000000002', '7373'))
@ -84,12 +84,12 @@ class AdyenForm(AdyenCommon):
'adyen: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
)
@mute_logger('openerp.addons.payment_acquirer_paypal.models.paypal', 'ValidationError')
def test_20_paypal_form_management(self):
cr, uid, context = self.cr, self.uid, {}
# be sure not to do stupid things
adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None)
self.assertEqual(adyen.env, 'test', 'test without test env')
# @mute_logger('openerp.addons.payment_adyen.models.adyen', 'ValidationError')
# def test_20_paypal_form_management(self):
# cr, uid, context = self.cr, self.uid, {}
# # be sure not to do stupid things
# adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None)
# self.assertEqual(adyen.env, 'test', 'test without test env')
# {'authResult': u'AUTHORISED',
# 'merchantReference': u'SO014',

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<data noupdate="1">
<template id="adyen_acquirer_button">
<form t-if="acquirer.adyen_merchant_account" t-att-action="tx_url" method="post" target="_self">
@ -22,7 +22,7 @@
<!-- submit -->
<button type="image" name="submit" width="100px"
t-att-class="submit_class">
<img t-if="not submit_txt" src="/payment_acquirer_adyen/static/src/img/adyen_icon.png"/>
<img t-if="not submit_txt" src="/payment_adyen/static/src/img/adyen_icon.png"/>
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
</button>
</form>

View File

@ -5,7 +5,7 @@
<record id="acquirer_form_adyen" model="ir.ui.view">
<field name="name">acquirer.form.adyen</field>
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment_acquirer.acquirer_form"/>
<field name="inherit_id" ref="payment.acquirer_form"/>
<field name="arch" type="xml">
<xpath expr='//group[@name="acquirer_display"]' position='after'>
<group attrs="{'invisible': [('name', '!=', 'adyen')]}">
@ -20,7 +20,7 @@
<record id="transaction_form_adyen" model="ir.ui.view">
<field name="name">acquirer.transaction.form.adyen</field>
<field name="model">payment.transaction</field>
<field name="inherit_id" ref="payment_acquirer.transaction_form"/>
<field name="inherit_id" ref="payment.transaction_form"/>
<field name="arch" type="xml">
<xpath expr='//notebook' position='inside'>
<page string="Adyen TX Details">

View File

@ -7,7 +7,7 @@
'version': '1.0',
'description': """Ogone Payment Acquirer""",
'author': 'OpenERP SA',
'depends': ['payment_acquirer'],
'depends': ['payment'],
'data': [
'views/ogone.xml',
'views/payment_acquirer.xml',

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import logging
import pprint
import werkzeug
from openerp.addons.web import http
from openerp.addons.web.http import request
@ -19,10 +20,10 @@ class OgoneController(http.Controller):
'/payment/ogone/decline', '/payment/ogone/test/decline',
'/payment/ogone/exception', '/payment/ogone/test/exception',
'/payment/ogone/cancel', '/payment/ogone/test/cancel',
], type='http', auth='admin', website=True)
], type='http', auth='admin')
def ogone_form_feedback(self, **post):
""" Ogone contacts using GET, at least for accept """
_logger.info('Ogone: entering form_feedback with post data %s', pprint.pformat(post)) # debug
cr, uid, context = request.cr, request.uid, request.context
request.registry['payment.transaction'].form_feedback(cr, uid, post, 'ogone', context=context)
return request.redirect(post.pop('return_url', '/'))
return werkzeug.utils.redirect(post.pop('return_url', '/'))

View File

@ -4,8 +4,11 @@
<record id="payment_acquirer_ogone" model="payment.acquirer">
<field name="name">ogone</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="ogone_acquirer_button"/>
<field name="env">test</field>
<field name="pre_msg"><![CDATA[
<p>You will be redirected to the Ogone website after cliking on the payment button.</p>]]></field>
<field name='ogone_pspid'>dummy</field>
<field name='ogone_userid'>dummy</field>
<field name='ogone_password'>dummy</field>

View File

@ -9,9 +9,9 @@ from urllib import urlencode
import urllib2
import urlparse
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneController
from openerp.addons.payment_acquirer_ogone.data import ogone
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment_ogone.controllers.main import OgoneController
from openerp.addons.payment_ogone.data import ogone
from openerp.osv import osv, fields
from openerp.tools import float_round
from openerp.tools.float_utils import float_compare
@ -212,7 +212,14 @@ class PaymentTxOgone(osv.Model):
# --------------------------------------------------
def ogone_s2s_create_alias(self, cr, uid, id, values, context=None):
""" Purpose: create an alias via batch """
""" Create an alias at Ogone via batch.
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
tx = self.browse(cr, uid, id, context=context)
assert tx.type == 'server2server', 'Calling s2s dedicated method for a %s acquirer' % tx.type
alias = 'OPENERP-%d-%d' % (tx.partner_id.id, tx.id)
@ -265,6 +272,14 @@ class PaymentTxOgone(osv.Model):
return True
def ogone_s2s_generate_values(self, cr, uid, id, custom_values, context=None):
""" Generate valid Ogone values for a s2s tx.
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
tx = self.browse(cr, uid, id, context=context)
tx_data = {
'PSPID': tx.acquirer_id.ogone_pspid,
@ -295,9 +310,23 @@ class PaymentTxOgone(osv.Model):
return tx_data
def ogone_s2s_feedback(self, cr, uid, data, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
pass
def ogone_s2s_execute(self, cr, uid, id, values, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
tx = self.browse(cr, uid, id, context=context)
tx_data = self.ogone_s2s_generate_values(cr, uid, id, values, context=context)

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -4,9 +4,9 @@ from lxml import objectify
import time
import urlparse
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneController
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_ogone.controllers.main import OgoneController
from openerp.tools import mute_logger
@ -18,7 +18,7 @@ class OgonePayment(PaymentAcquirerCommon):
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
# get the adyen account
model, self.ogone_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'payment_acquirer_ogone')
model, self.ogone_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_ogone', 'payment_acquirer_ogone')
def test_10_ogone_form_render(self):
cr, uid, context = self.cr, self.uid, {}
@ -105,7 +105,7 @@ class OgonePayment(PaymentAcquirerCommon):
'ogone: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
)
@mute_logger('openerp.addons.payment_acquirer_ogone.models.ogone', 'ValidationError')
@mute_logger('openerp.addons.payment_ogone.models.ogone', 'ValidationError')
def test_20_ogone_form_management(self):
cr, uid, context = self.cr, self.uid, {}
# be sure not to do stupid thing

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<data noupdate="1">
<template id="ogone_acquirer_button">
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
@ -43,7 +43,7 @@
<!-- submit -->
<button type="image" name="submit" width="100px"
t-att-class="submit_class">
<img t-if="not submit_txt" src="/payment_acquirer_ogone/static/src/img/ogone_icon.png"/>
<img t-if="not submit_txt" src="/payment_ogone/static/src/img/ogone_icon.png"/>
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
</button>
</form>

View File

@ -5,7 +5,7 @@
<record id="acquirer_form_ogone" model="ir.ui.view">
<field name="name">acquirer.form.ogone</field>
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment_acquirer.acquirer_form"/>
<field name="inherit_id" ref="payment.acquirer_form"/>
<field name="arch" type="xml">
<xpath expr='//group[@name="acquirer_display"]' position='after'>
<group attrs="{'invisible': [('name', '!=', 'ogone')]}">
@ -22,7 +22,7 @@
<record id="transaction_form_ogone" model="ir.ui.view">
<field name="name">acquirer.transaction.form.ogone</field>
<field name="model">payment.transaction</field>
<field name="inherit_id" ref="payment_acquirer.transaction_form"/>
<field name="inherit_id" ref="payment.transaction_form"/>
<field name="arch" type="xml">
<xpath expr='//notebook' position='inside'>
<page string="Ogone TX Details">

View File

@ -7,10 +7,11 @@
'version': '1.0',
'description': """Paypal Payment Acquirer""",
'author': 'OpenERP SA',
'depends': ['payment_acquirer'],
'depends': ['payment'],
'data': [
'views/paypal.xml',
'views/payment_acquirer.xml',
'views/res_config_view.xml',
'data/paypal.xml',
],
'installable': True,

View File

@ -8,6 +8,7 @@ import logging
import pprint
import urllib
import urllib2
import werkzeug
from openerp.addons.web import http
from openerp.addons.web.http import request
@ -53,31 +54,25 @@ class PaypalController(http.Controller):
_logger.warning('Paypal: unrecognized paypal answer, received %s instead of VERIFIED or INVALID' % resp.text)
return res
@http.route([
'/payment/paypal/ipn/',
], type='http', auth='public', methods=['POST'], website=True)
@http.route('/payment/paypal/ipn/', type='http', auth='admin', methods=['POST'])
def paypal_ipn(self, **post):
""" Paypal IPN. """
_logger.info('Beginning Paypal IPN form_feedback with post data %s', pprint.pformat(post)) # debug
self.paypal_validate_data(**post)
return ''
@http.route([
'/payment/paypal/dpn',
], type='http', auth="public", methods=['POST'], website=True)
@http.route('/payment/paypal/dpn', type='http', auth="admin", methods=['POST'])
def paypal_dpn(self, **post):
""" Paypal DPN """
_logger.info('Beginning Paypal DPN form_feedback with post data %s', pprint.pformat(post)) # debug
return_url = self._get_return_url(**post)
self.paypal_validate_data(**post)
return request.redirect(return_url)
return werkzeug.utils.redirect(return_url)
@http.route([
'/payment/paypal/cancel',
], type='http', auth="public", website=True)
@http.route('/payment/paypal/cancel', type='http', auth="admin")
def paypal_cancel(self, **post):
""" When the user cancels its Paypal payment: GET on this route """
cr, uid, context = request.cr, request.uid, request.context
_logger.info('Beginning Paypal cancel with post data %s', pprint.pformat(post)) # debug
return_url = self._get_return_url(**post)
return request.redirect(return_url)
return werkzeug.utils.redirect(return_url)

View File

@ -4,15 +4,17 @@
<record id="payment_acquirer_paypal" model="payment.acquirer">
<field name="name">paypal</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="paypal_acquirer_button"/>
<field name="env">test</field>
<field name="message"><![CDATA[
<field name="pre_msg"><![CDATA[
<p>You will be redirected to the Paypal website after cliking on the payment button.</p>]]></field>
<field name="paypal_email_id">dummy</field>
<field name="paypal_seller_id">dummy</field>
<field name="paypal_email_account">dummy</field>
<field name="paypal_seller_account">dummy</field>
<field name="paypal_api_username">dummy</field>
<field name="paypal_api_password">dummy</field>
</record>
<function model="payment.acquirer" name="_migrate_paypal_account"/>
</data>
</openerp>

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import paypal
import res_company

View File

@ -10,8 +10,8 @@ import urlparse
import urllib
import urllib2
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer_paypal.controllers.main import PaypalController
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment_paypal.controllers.main import PaypalController
from openerp.osv import osv, fields
from openerp.tools.float_utils import float_compare
@ -25,8 +25,8 @@ class AcquirerPaypal(osv.Model):
""" Paypal URLS """
if env == 'prod':
return {
'paypal_form_url': 'https://www.sandbox.paypal.com/cgi-bin/webscr',
'paypal_rest_url': 'https://api.sandbox.paypal.com/v1/oauth2/token',
'paypal_form_url': 'https://www.paypal.com/cgi-bin/webscr',
'paypal_rest_url': 'https://api.paypal.com/v1/oauth2/token',
}
else:
return {
@ -35,9 +35,11 @@ class AcquirerPaypal(osv.Model):
}
_columns = {
'paypal_email_id': fields.char('Email ID', required_if_provider='paypal'),
'paypal_seller_id': fields.char('Seller ID', required_if_provider='paypal'),
'paypal_use_ipn': fields.boolean('Use IPN'),
'paypal_email_account': fields.char('Paypal Email ID', required_if_provider='paypal'),
'paypal_seller_account': fields.char(
'Paypal Seller ID',
help='The Seller ID is used to ensure communications coming from Paypal are valid and secured.'),
'paypal_use_ipn': fields.boolean('Use IPN', help='Paypal Instant Payment Notification'),
# Server 2 server
'paypal_api_enabled': fields.boolean('Use Rest API'),
'paypal_api_username': fields.char('Rest API Username'),
@ -56,6 +58,23 @@ class AcquirerPaypal(osv.Model):
'paypal_api_enabled': False,
}
def _migrate_paypal_account(self, cr, uid, context=None):
""" COMPLETE ME """
cr.execute('SELECT id, paypal_account FROM res_company')
res = cr.fetchall()
for (company_id, company_paypal_account) in res:
if company_paypal_account:
company_paypal_ids = self.search(cr, uid, [('company_id', '=', company_id), ('name', '=', 'paypal')], limit=1, context=context)
if company_paypal_ids:
self.write(cr, uid, company_paypal_ids, {'paypal_email_account': company_paypal_account}, context=context)
else:
paypal_view = self.pool['ir.model.data'].get_object(cr, uid, 'payment_paypal', 'paypal_acquirer_button')
self.create(cr, uid, {
'paypal_email_account': company_paypal_account,
'view_template_id': paypal_view.id,
}, context=context)
return True
def paypal_compute_fees(self, cr, uid, id, amount, currency_id, country_id, context=None):
""" Compute paypal fees.
@ -82,7 +101,7 @@ class AcquirerPaypal(osv.Model):
paypal_tx_values = dict(tx_values)
paypal_tx_values.update({
'cmd': '_xclick',
'business': acquirer.paypal_email_id,
'business': acquirer.paypal_email_account,
'item_name': tx_values['reference'],
'item_number': tx_values['reference'],
'amount': tx_values['amount'],
@ -116,12 +135,15 @@ class AcquirerPaypal(osv.Model):
"""
res = dict.fromkeys(ids, False)
parameters = urllib.urlencode({'grant_type': 'client_credentials'})
request = urllib2.Request('https://api.sandbox.paypal.com/v1/oauth2/token', parameters)
# add other headers (https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/)
request.add_header('Accept', 'application/json')
request.add_header('Accept-Language', 'en_US')
for acquirer in self.browse(cr, uid, ids, context=context):
tx_url = self._get_paypal_urls(cr, uid, acquirer.env)['paypal_rest_url']
request = urllib2.Request(tx_url, parameters)
# add other headers (https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/)
request.add_header('Accept', 'application/json')
request.add_header('Accept-Language', 'en_US')
# add authorization header
base64string = base64.encodestring('%s:%s' % (
acquirer.paypal_api_username,
@ -193,10 +215,10 @@ class TxPaypal(osv.Model):
if tx.partner_reference and data.get('payer_id') != tx.partner_reference:
invalid_parameters.append(('payer_id', data.get('payer_id'), tx.partner_reference))
# check seller
if data.get('receiver_email') != tx.acquirer_id.paypal_email_id:
invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_id))
if data.get('receiver_id') != tx.acquirer_id.paypal_seller_id:
invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_id))
if data.get('receiver_email') != tx.acquirer_id.paypal_email_account:
invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account))
if tx.acquirer_id.paypal_seller_account and data.get('receiver_id') != tx.acquirer_id.paypal_seller_account:
invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account))
return invalid_parameters
@ -226,23 +248,42 @@ class TxPaypal(osv.Model):
# --------------------------------------------------
def _paypal_try_url(self, request, tries=3, context=None):
try:
res = urllib2.urlopen(request)
except urllib2.HTTPError as e:
res = e.read()
e.close()
if tries and res and json.loads(res)['name'] == 'INTERNAL_SERVICE_ERROR':
_logger.warning('Failed contacting Paypal, retrying (%s remaining)' % tries)
return self._paypal_try_url(request, tries=tries - 1, context=context)
raise
except:
raise
""" Try to contact Paypal. Due to some issues, internal service errors
seem to be quite frequent. Several tries are done before considering
the communication as failed.
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
done, res = False, None
while (not done and tries):
try:
res = urllib2.urlopen(request)
done = True
except urllib2.HTTPError as e:
res = e.read()
e.close()
if tries and res and json.loads(res)['name'] == 'INTERNAL_SERVICE_ERROR':
_logger.warning('Failed contacting Paypal, retrying (%s remaining)' % tries)
tries = tries - 1
if not res:
pass
# raise openerp.exceptions.
result = res.read()
res.close()
return result
def _paypal_s2s_send(self, cr, uid, values, cc_values, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
tx_id = self.create(cr, uid, values, context=context)
tx = self.browse(cr, uid, tx_id, context=context)
@ -282,9 +323,10 @@ class TxPaypal(osv.Model):
}]
}
else:
# TODO: complete redirect URLs
data['redirect_urls'] = {
'return_url': 'http://example.com/your_redirect_url/',
'cancel_url': 'http://example.com/your_cancel_url/',
# 'return_url': 'http://example.com/your_redirect_url/',
# 'cancel_url': 'http://example.com/your_cancel_url/',
},
data['payer'] = {
'payment_method': 'paypal',
@ -296,10 +338,24 @@ class TxPaypal(osv.Model):
return (tx_id, result)
def _paypal_s2s_get_invalid_parameters(self, cr, uid, tx, data, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
invalid_parameters = []
return invalid_parameters
def _paypal_s2s_validate(self, cr, uid, tx, data, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
values = json.loads(data)
status = values.get('state')
if status in ['approved']:
@ -329,6 +385,13 @@ class TxPaypal(osv.Model):
return False
def _paypal_s2s_get_tx_status(self, cr, uid, tx, context=None):
"""
.. versionadded:: pre-v8 saas-3
.. warning::
Experimental code. You should not use it before OpenERP v8 official
release.
"""
# TDETODO: check tx.paypal_txn_id is set
headers = {
'Content-Type': 'application/json',

View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
class ResCompany(osv.Model):
_inherit = "res.company"
def _get_paypal_account(self, cr, uid, ids, name, arg, context=None):
Acquirer = self.pool['payment.acquirer']
company_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.id
paypal_ids = Acquirer.search(cr, uid, [
('website_published', '=', True),
('name', 'ilike', 'paypal'),
('company_id', '=', company_id),
], limit=1, context=context)
if paypal_ids:
paypal = Acquirer.browse(cr, uid, paypal_ids[0], context=context)
return dict.fromkeys(ids, paypal.paypal_email_account)
return dict.fromkeys(ids, False)
def _set_paypal_account(self, cr, uid, id, name, value, arg, context=None):
Acquirer = self.pool['payment.acquirer']
company_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.id
paypal_account = self.browse(cr, uid, id, context=context).paypal_account
paypal_ids = Acquirer.search(cr, uid, [
('website_published', '=', True),
('paypal_email_account', '=', paypal_account),
('company_id', '=', company_id),
], context=context)
if paypal_ids:
Acquirer.write(cr, uid, paypal_ids, {'paypal_email_account': value}, context=context)
return True
_columns = {
'paypal_account': fields.function(
_get_paypal_account,
fnct_inv=_set_paypal_account,
nodrop=True,
type='char', string='Paypal Account',
help="Paypal username (usually email) for receiving online payments."
),
}

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_acquirer_paypal.controllers.main import PaypalController
from openerp.osv.orm import except_orm
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_paypal.controllers.main import PaypalController
from openerp.tools import mute_logger
from lxml import objectify
@ -18,7 +17,7 @@ class PaypalCommon(PaymentAcquirerCommon):
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
# get the paypal account
model, self.paypal_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_paypal', 'payment_acquirer_paypal')
model, self.paypal_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_paypal', 'payment_acquirer_paypal')
# tde+seller@openerp.com - tde+buyer@openerp.com - tde+buyer-it@openerp.com
# some CC
@ -152,7 +151,7 @@ class PaypalForm(PaypalCommon):
self.assertEqual(form_input.get('value'), '1.56', 'paypal: wrong computed fees')
self.assertTrue(handling_found, 'paypal: fees_active did not add handling input in rendered form')
@mute_logger('openerp.addons.payment_acquirer_paypal.models.paypal', 'ValidationError')
@mute_logger('openerp.addons.payment_paypal.models.paypal', 'ValidationError')
def test_20_paypal_form_management(self):
cr, uid, context = self.cr, self.uid, {}
# be sure not to do stupid things

View File

@ -5,20 +5,21 @@
<record id="acquirer_form_paypal" model="ir.ui.view">
<field name="name">acquirer.form.paypal</field>
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment_acquirer.acquirer_form"/>
<field name="inherit_id" ref="payment.acquirer_form"/>
<field name="arch" type="xml">
<xpath expr='//group[@name="acquirer_display"]' position='after'>
<group attrs="{'invisible': [('name', '!=', 'paypal')]}">
<group>
<group>
<field name="paypal_email_id"/>
<field name="paypal_seller_id"/>
<field name="paypal_email_account"/>
<field name="paypal_seller_account"/>
<field name="paypal_use_ipn"/>
<field name="paypal_api_enabled"/>
<field name="paypal_api_enabled"
invisible="1"/> <!-- WIP in saas-3 -->
<field name="paypal_api_username"
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
invisible="1"/> <!-- WIP in saas-3 -->
<field name="paypal_api_password"
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
invisible="1"/> <!-- WIP in saas-3 -->
</group>
</group>
</group>
@ -29,7 +30,7 @@
<record id="transaction_form_paypal" model="ir.ui.view">
<field name="name">acquirer.transaction.form.paypal</field>
<field name="model">payment.transaction</field>
<field name="inherit_id" ref="payment_acquirer.transaction_form"/>
<field name="inherit_id" ref="payment.transaction_form"/>
<field name="arch" type="xml">
<xpath expr='//notebook' position='inside'>
<page string="Paypal TX Details">

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<data noupdate="1">
<template id="paypal_acquirer_button">
<form t-if="acquirer.paypal_email_id" t-att-action="tx_url" method="post" target="_self">
<form t-if="acquirer.paypal_email_account" t-att-action="tx_url" method="post" target="_self">
<input type="hidden" name="cmd" t-att-value="tx_values['cmd']"/>
<input type="hidden" name="business" t-att-value="tx_values['business']"/>
<input type="hidden" name="item_name" t-att-value="tx_values['item_name']"/>
@ -33,7 +33,7 @@
<!-- submit -->
<button type="image" name="submit" width="100px"
t-att-class="submit_class">
<img t-if="not submit_txt" src="/payment_acquirer_paypal/static/src/img/paypal_icon.png"/>
<img t-if="not submit_txt" src="/payment_paypal/static/src/img/paypal_icon.png"/>
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
</button>
</form>

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Add payment options to sale.order and invoice forms -->
<record model="ir.ui.view" id="payment_paypal_option_config">
<field name="model">account.config.settings</field>
<field name="inherit_id" ref="account.view_account_config_settings"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='payment_acquirer']" version="7.0" position="inside">
<button name='%(payment.acquirer_list)d' type="action"
string="Configure payment acquiring methods" class="oe_link"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -7,7 +7,7 @@
'version': '1.0',
'description': """Transfer Payment Acquirer""",
'author': 'OpenERP SA',
'depends': ['payment_acquirer'],
'depends': ['payment'],
'data': [
'views/transfer.xml',
'data/transfer.xml',

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import logging
import pprint
import werkzeug
from openerp.addons.web import http
from openerp.addons.web.http import request
@ -13,9 +14,9 @@ class OgoneController(http.Controller):
@http.route([
'/payment/transfer/feedback',
], type='http', auth='admin', website=True)
], type='http', auth='admin')
def transfer_form_feedback(self, **post):
cr, uid, context = request.cr, request.uid, request.context
_logger.info('Beginning form_feedback with post data %s', pprint.pformat(post)) # debug
request.registry['payment.transaction'].form_feedback(cr, uid, post, 'transfer', context)
return request.redirect(post.pop('return_url', '/'))
return werkzeug.utils.redirect(post.pop('return_url', '/'))

View File

@ -4,11 +4,13 @@
<record id="payment_acquirer_transfer" model="payment.acquirer">
<field name="name">transfer</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="transfer_acquirer_button"/>
<field name="validation">manual</field>
<field name="env">test</field>
<field name="portal_published" eval="True"/>
<field name="message"><![CDATA[
<p>Please use the account 001-002-003 to make the payment.</p>]]>
<field name="website_published" eval="True"/>
<field name="pre_msg"><![CDATA[
<p>Transfer information will be provided after choosing the payment mode.</p>]]>
</field>
</record>

View File

@ -1,8 +1,9 @@
# -*- coding: utf-'8' "-*-"
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.osv import osv
from openerp.tools.float_utils import float_compare
from openerp.tools.translate import _
import logging
import pprint
@ -16,6 +17,33 @@ class TransferPaymentAcquirer(osv.Model):
def transfer_get_form_action_url(self, cr, uid, id, context=None):
return '/payment/transfer/feedback'
def _format_transfer_data(self, cr, uid, context=None):
bank_ids = [bank.id for bank in self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.bank_ids]
# filter only bank accounts marked as visible
bank_ids = self.pool['res.partner.bank'].search(cr, uid, [('id', 'in', bank_ids), ('footer', '=', True)], context=context)
accounts = self.pool['res.partner.bank'].name_get(cr, uid, bank_ids, context=context)
bank_title = _('Bank Accounts') if len(accounts) > 1 else _('Bank Account')
bank_accounts = ''.join(['<ul>'] + ['<li>%s</li>' % name for id, name in accounts] + ['</ul>'])
post_msg = '''<div>
<h3>Please use the following transfer details</h3>
<h4>%(bank_title)s</h4>
%(bank_accounts)s
<h4>Communication</h4>
<p>Please use the order name as communication reference.</p>
</div>''' % {
'bank_title': bank_title,
'bank_accounts': bank_accounts,
}
return post_msg
def create(self, cr, uid, values, context=None):
""" Hook in create to create a default post_msg. This is done in create
to have access to the name and other creation values. If no post_msg
or a void post_msg is given at creation, generate a default one. """
if values.get('name') == 'transfer' and not values.get('post_msg'):
values['post_msg'] = self._format_transfer_data(cr, uid, context=context)
return super(TransferPaymentAcquirer, self).create(cr, uid, values, context=context)
class TransferPaymentTransaction(osv.Model):
_inherit = 'payment.transaction'

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<data noupdate="1">
<template id="transfer_acquirer_button">
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
@ -13,7 +13,7 @@
<!-- submit -->
<button type="image" name="submit" width="100px"
t-att-class="submit_class">
<img t-if="not submit_txt" src="/payment_acquirer_transfer/static/src/img/transfer_icon.png"/>
<img t-if="not submit_txt" src="/payment_transfer/static/src/img/transfer_icon.png"/>
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
</button>
</form>

View File

@ -24,6 +24,5 @@ import mail_thread
import mail_mail
import mail_message
import wizard
import acquirer
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -47,7 +47,6 @@ very handy when used in combination with the module 'share'.
'portal_view.xml',
'wizard/portal_wizard_view.xml',
'wizard/share_wizard_view.xml',
'acquirer_view.xml',
'security/ir.model.access.csv',
],
'demo': ['portal_demo.xml'],

View File

@ -1,108 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://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/>.
#
##############################################################################
import logging
from urllib import quote as quote
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools import float_repr
_logger = logging.getLogger(__name__)
try:
from mako.template import Template as MakoTemplate
except ImportError:
_logger.warning("payment_acquirer: mako templates not available, payment acquirer will not work!")
class acquirer(osv.Model):
_name = 'portal.payment.acquirer'
_description = 'Online Payment Acquirer'
_columns = {
'name': fields.char('Name', required=True),
'form_template': fields.text('Payment form template (HTML)', translate=True, required=True),
'visible': fields.boolean('Visible', help="Make this payment acquirer available in portal forms (Customer invoices, etc.)"),
}
_defaults = {
'visible': True,
}
def render(self, cr, uid, id, object, reference, currency, amount, context=None, **kwargs):
""" Renders the form template of the given acquirer as a mako template """
if not isinstance(id, (int,long)):
id = id[0]
this = self.browse(cr, uid, id)
if context is None:
context = {}
try:
i18n_kind = _(object._description) # may fail to translate, but at least we try
result = MakoTemplate(this.form_template).render_unicode(object=object,
reference=reference,
currency=currency,
amount=amount,
kind=i18n_kind,
quote=quote,
# context kw would clash with mako internals
ctx=context,
format_exceptions=True)
return result.strip()
except Exception:
_logger.exception("failed to render mako template value for payment.acquirer %s: %r", this.name, this.form_template)
return
def _wrap_payment_block(self, cr, uid, html_block, amount, currency, context=None):
if not html_block:
link = '#action=account.action_account_config'
payment_header = _('You can finish the configuration in the <a href="%s">Bank&Cash settings</a>') % link
amount = _('No online payment acquirers configured')
group_ids = self.pool.get('res.users').browse(cr, uid, uid, context=context).groups_id
if any(group.is_portal for group in group_ids):
return ''
else:
payment_header = _('Pay safely online')
amount_str = float_repr(amount, self.pool.get('decimal.precision').precision_get(cr, uid, 'Account'))
currency_str = currency.symbol or currency.name
amount = u"%s %s" % ((currency_str, amount_str) if currency.position == 'before' else (amount_str, currency_str))
result = """<div class="payment_acquirers">
<div class="payment_header">
<div class="payment_amount">%s</div>
%s
</div>
%%s
</div>""" % (amount, payment_header)
return result % html_block
def render_payment_block(self, cr, uid, object, reference, currency, amount, context=None, **kwargs):
""" Renders all visible payment acquirer forms for the given rendering context, and
return them wrapped in an appropriate HTML block, ready for direct inclusion
in an OpenERP v7 form view """
acquirer_ids = self.search(cr, uid, [('visible', '=', True)])
if not acquirer_ids:
return
html_forms = []
for this in self.browse(cr, uid, acquirer_ids):
content = this.render(object, reference, currency, amount, context=context, **kwargs)
if content:
html_forms.append(content)
html_block = '\n'.join(filter(None,html_forms))
return self._wrap_payment_block(cr, uid, html_block, amount, currency, context=context)

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="acquirer_form" model="ir.ui.view">
<field name="model">portal.payment.acquirer</field>
<field name="arch" type="xml">
<form string="Payment Acquirer" version="7.0">
<group col="1">
<div class="oe_title">
<label for="name" class="oe_edit_only"/><h1><field name="name"/></h1>
<div class="oe_edit_only"><field name="visible"/><label for="visible"/></div>
</div>
<group string="Form Template">
<div>
<p>
This is an HTML form template to submit a payment through this acquirer.
The template will be rendered with <a href="http://www.makotemplates.org/" target="_blank">Mako</a>, so it may use Mako expressions.
The Mako evaluation context provides:
<ul>
<li>reference: the reference number of the document to pay</li>
<li>kind: the kind of document on which the payment form is rendered (translated to user language, e.g. "Invoice")</li>
<li>currency: the currency record in which the document is issued (e.g. currency.name could be EUR)</li>
<li>amount: the total amount to pay, as a float</li>
<li>object: the document on which the payment form is rendered (usually an invoice or sales order record)</li>
<li>quote(): a method to quote special string character to make them suitable for inclusion in a URL</li>
<li>cr: the current database cursor</li>
<li>uid: the current user id</li>
<li>ctx: the current context dictionary</li>
</ul>
If the template renders to an empty result in a certain context it will be ignored, as if it was inactive.
</p>
</div>
<field name="form_template" nolabel="1" colspan="2"/>
</group>
</group>
</form>
</field>
</record>
<record id="acquirer_list" model="ir.ui.view">
<field name="model">portal.payment.acquirer</field>
<field name="arch" type="xml">
<tree string="Payment Acquirers">
<field name="name"/>
<field name="visible"/>
</tree>
</field>
</record>
<record id="acquirer_search" model="ir.ui.view">
<field name="model">portal.payment.acquirer</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
</search>
</field>
</record>
<!-- Acquirers list action is visible in Invoicing Settings -->
<record model="ir.actions.act_window" id="action_acquirer_list">
<field name="name">Payment Acquirers</field>
<field name="res_model">portal.payment.acquirer</field>
</record>
</data>
</openerp>

View File

@ -10,21 +10,5 @@
<field name="share" eval="True"/>
</record>
<record id="paypal_acquirer" model="portal.payment.acquirer">
<field name="name">Paypal</field>
<field name="form_template"><![CDATA[
% if object.company_id.paypal_account:
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_xclick"/>
<input type="hidden" name="business" value="${object.company_id.paypal_account}"/>
<input type="hidden" name="item_name" value="${object.company_id.name} ${kind.title()} ${reference}"/>
<input type="hidden" name="amount" value="${amount}"/>
<input type="hidden" name="currency_code" value="${currency.name}"/>
<input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
</form>
% endif
]]></field>
</record>
</data>
</openerp>

View File

@ -3,6 +3,4 @@ access_mail_message_portal,mail.message.portal,mail.model_mail_message,base.grou
access_mail_mail_portal,mail.mail.portal,mail.model_mail_mail,base.group_portal,1,1,1,0
access_mail_notification_portal,mail.notification.portal,mail.model_mail_notification,base.group_portal,1,1,1,0
access_mail_followers_portal,mail.followers.portal,mail.model_mail_followers,base.group_portal,1,1,0,0
access_acquirer,portal.payment.acquirer,portal.model_portal_payment_acquirer,,1,0,0,0
access_acquirer_all,portal.payment.acquirer,portal.model_portal_payment_acquirer,base.group_system,1,1,1,1
access_ir_attachment_group_portal,ir.attachment group_portal,base.model_ir_attachment,base.group_portal,1,0,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_mail_mail_portal mail.mail.portal mail.model_mail_mail base.group_portal 1 1 1 0
4 access_mail_notification_portal mail.notification.portal mail.model_mail_notification base.group_portal 1 1 1 0
5 access_mail_followers_portal mail.followers.portal mail.model_mail_followers base.group_portal 1 1 0 0
access_acquirer portal.payment.acquirer portal.model_portal_payment_acquirer 1 0 0 0
access_acquirer_all portal.payment.acquirer portal.model_portal_payment_acquirer base.group_system 1 1 1 1
6 access_ir_attachment_group_portal ir.attachment group_portal base.model_ir_attachment base.group_portal 1 0 1 0

View File

@ -44,7 +44,7 @@ pay online on their Sale Orders and Invoices that are not paid yet. Paypal is in
by default, you simply need to configure a Paypal account in the Accounting/Invoicing settings.
""",
'author': 'OpenERP SA',
'depends': ['sale','portal'],
'depends': ['sale', 'portal', 'payment'],
'data': [
'security/portal_security.xml',
'portal_sale_view.xml',

View File

@ -34,11 +34,12 @@ class sale_order(osv.Model):
def _portal_payment_block(self, cr, uid, ids, fieldname, arg, context=None):
result = dict.fromkeys(ids, False)
payment_acquirer = self.pool.get('portal.payment.acquirer')
payment_acquirer = self.pool['payment.acquirer']
for this in self.browse(cr, uid, ids, context=context):
if this.state not in ('draft', 'cancel') and not this.invoiced:
result[this.id] = payment_acquirer.render_payment_block(cr, uid, this, this.name,
this.pricelist_id.currency_id, this.amount_total, context=context)
result[this.id] = payment_acquirer.render_payment_block(
cr, uid, this.name, this.amount_total, this.pricelist_id.currency_id.id,
partner_id=this.partner_id.id, context=context)
return result
def action_quotation_send(self, cr, uid, ids, context=None):
@ -84,11 +85,12 @@ class account_invoice(osv.Model):
def _portal_payment_block(self, cr, uid, ids, fieldname, arg, context=None):
result = dict.fromkeys(ids, False)
payment_acquirer = self.pool.get('portal.payment.acquirer')
payment_acquirer = self.pool.get('payment.acquirer')
for this in self.browse(cr, uid, ids, context=context):
if this.type == 'out_invoice' and this.state not in ('draft', 'done') and not this.reconciled:
result[this.id] = payment_acquirer.render_payment_block(cr, uid, this, this.number,
this.currency_id, this.residual, context=context)
result[this.id] = payment_acquirer.render_payment_block(
cr, uid, this.number, this.residual, this.currency_id.id,
partner_id=this.partner_id.id, context=context)
return result
def action_invoice_sent(self, cr, uid, ids, context=None):

View File

@ -11,7 +11,7 @@
<div>
<field name="group_payment_options" class="oe_inline"/>
<label for="group_payment_options"/>
<button name='%(portal.action_acquirer_list)d' type="action"
<button name='%(payment.acquirer_list)d' type="action"
string="Configure payment acquiring methods" class="oe_link"/>
</div>
</xpath>

View File

@ -9,7 +9,7 @@
'author': 'OpenERP SA',
'depends': [
'website',
'payment_acquirer',
'payment',
],
'data': [
'views/website_payment_templates.xml',

View File

@ -11,7 +11,7 @@
<separator string="E-Commerce"/>
<group name="shop">
<button type="action"
name="%(payment_acquirer.action_payment_acquirer)d"
name="%(payment.action_payment_acquirer)d"
string="Configure payment acquirers" class="oe_link"/>
</group>
</div>

View File

@ -9,7 +9,7 @@ OpenERP E-Commerce
""",
'author': 'OpenERP SA',
'depends': ['website', 'sale', 'payment_acquirer'],
'depends': ['website', 'sale', 'payment'],
'data': [
'data/website_sale_data.xml',
'views/website_sale.xml',

View File

@ -564,7 +564,7 @@ class Ecommerce(http.Controller):
if tx:
acquirer_ids = [tx.acquirer_id.id]
else:
acquirer_ids = payment_obj.search(cr, SUPERUSER_ID, [('portal_published', '=', True)], context=context)
acquirer_ids = payment_obj.search(cr, SUPERUSER_ID, [('website_published', '=', True)], context=context)
values['acquirers'] = payment_obj.browse(cr, uid, acquirer_ids, context=context)
render_ctx = dict(context, submit_class='btn btn-primary', submit_txt='Pay Now')
for acquirer in values['acquirers']:
@ -635,6 +635,7 @@ class Ecommerce(http.Controller):
if not order:
return {
'state': 'error',
'message': '<p>There seems to be an error with your request.</p>',
}
tx_ids = request.registry['payment.transaction'].search(
@ -643,11 +644,25 @@ class Ecommerce(http.Controller):
], context=context)
if not tx_ids:
return {
'state': 'error'
'state': 'error',
'message': '<p>There seems to be an error with your request.</p>',
}
tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
state = tx.state
if state == 'done':
message = '<p>Your payment has been received.</p>'
elif state == 'cancel':
message = '<p>The payment seems to have been canceled.</p>'
elif state == 'pending' and tx.acquirer_id.validation == 'manual':
message = '<p>Your transaction is waiting confirmation.</p>'
message += tx.acquirer_id.post_msg
else:
message = '<p>Your transaction is waiting confirmation.</p>'
return {
'state': tx.state,
'state': state,
'message': message,
'validation': tx.acquirer_id.validation
}
@http.route('/shop/payment/validate/', type='http', auth="public", website=True, multilang=True)

View File

@ -11,22 +11,15 @@ $(document).ready(function () {
return openerp.jsonRpc('/shop/payment/get_status/' + order_id, 'call', {
}).then(function (result) {
var tx_node = $('div.oe_website_sale_tx_status');
var txt = '<h3>Your transaction is waiting confirmation.</h3>';
_poll_nbr += 1;
if (result.state == 'pending' && _poll_nbr <= 5) {
txt = "<h3>Your transaction is waiting confirmation.</h3>";
if (result.state == 'pending' && result.validation == 'automatic' && _poll_nbr <= 5) {
var txt = result.mesage;
setTimeout(function () {
payment_transaction_poll_status();
}, 1000);
}
else if (result.state == 'done') {
txt = "<h3>Your payment has been received.</h3>";
}
else if (result.state == 'pending') {
txt = "<h3>Your transaction is waiting confirmation. You may try to refresh this page.</h3>";
}
else if (result.state == 'cancel') {
txt = "<h3>The payment seems to have been canceled.</h3>";
else {
var txt = result.message;
}
tx_node.html(txt);
});

View File

@ -960,7 +960,10 @@
</div>
<div class="col-lg-3 col-sm-3">
<t t-foreach="acquirers or []" t-as="acquirer">
<div t-att-data-id="acquirer.id" t-raw="acquirer.button" class="oe_sale_acquirer_button hidden pull-right"/>
<div t-att-data-id="acquirer.id" class="oe_sale_acquirer_button hidden pull-right">
<div t-raw="acquirer.button"/>
<div t-field="acquirer.pre_msg"/>
</div>
</t>
</div>
</div>
@ -989,7 +992,7 @@
<li class="text-muted">Payment<span class="chevron"></span></li>
<li class="text-primary">Confirmation<span class="chevron"></span></li>
</ul>
<h1 class="mb32">Order Confirmed</h1>
<h1 class="mb32">Order <em t-field="order.name"/> Confirmed</h1>
<div class="row">
<div class="col-md-8 oe_mycart">
<h2>Thank you for your order.</h2>