[ADD] portal: added portal.payment.acquirer model

portal.payment.acquirer stores payment processor
options (formally called payment acquirers). Each
acquirer is just a name and an HTML form template,
used to render an HTML snippet that can be included
in views where a payment option should be displayed.
The aquirer model has a generic method for rendering
a complete block of HTML to be included in form views
directly (with matching CSS): render_payment_block().

This method takes a few parameters to figure out
the name/reference, amount, currency, etc. to pay.

bzr revid: odo@openerp.com-20121024131554-j01ucniecjmoz3jq
This commit is contained in:
Olivier Dony 2012-10-24 15:15:54 +02:00
parent 21b56902b7
commit 20c81b5e2f
7 changed files with 252 additions and 1 deletions

View File

@ -22,6 +22,6 @@
import portal
import mail_mail
import wizard
import acquirer
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -49,8 +49,10 @@ 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',
],
'demo': ['portal_demo.xml'],
'css': ['static/src/css/portal.css'],
'installable': True,
}

96
addons/portal/acquirer.py Normal file
View File

@ -0,0 +1,96 @@
# -*- 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 import ustr
from openerp.tools.translate import _
_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),
'visible': fields.boolean('Visible', help="Whether this payment acquirer is currently displayed in portal forms"),
}
_default = {
'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
template = ustr(this.form_template)
result = MakoTemplate(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)
result = result.strip()
if result == u'False':
result = u''
return result
except Exception:
_logger.exception("failed to render mako template value for payment.acquirer %s: %r", this.name, template)
return
def _wrap_payment_block(self, cr, uid, html_block, context=None):
payment_header = _('Pay safely online:')
result = """<div class="payment_acquirers">
<span class="payment_header">%s</span>
%%s
</div>""" % 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):
html_forms.append(this.render(object, reference, currency, amount, context=context, **kwargs))
html_block = '\n'.join(html_forms)
return self._wrap_payment_block(cr, uid, html_block, context=context)

View File

@ -0,0 +1,67 @@
<?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 through mako, so it may use normal 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 sale 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>
<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>
<menuitem id="menu_acquirers" parent="portal_menu" action="action_acquirer_list"/>
<menuitem id="menu_acquirers2" parent="menu_acquirers" action="action_acquirer_list"/>
<menuitem id="menu_acquirers3" parent="menu_acquirers2" action="action_acquirer_list"/>
</data>
</openerp>

View File

@ -27,6 +27,30 @@
<field name="res_id" ref="company_jobs"/>
<field name="view_mode">form</field>
</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:
<%
kind = quote(kind.title())
comp_name = quote(object.company_id.name)
ref = quote(reference)
paypal_account = quote(object.company_id.paypal_account)
amount = quote(str(object.amount_total))
cur_code = quote(currency.name)
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=%s&amp;item_name=%s%%20%s%%20%s" \
"&amp;invoice=%s&amp;amount=%s&amp;currency_code=%s&amp;button_subtype=services&amp;no_note=1" \
"&amp;bn=OpenERP_Portal_PayNow_%s" % \
(paypal_account,comp_name,kind,ref,ref,amount,cur_code,cur_code)
%>
<a style="margin-left: 120px;" href="${paypal_url}">
<img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
</a>
% endif
]]></field>
</record>
</data>
</openerp>

View File

@ -4,3 +4,5 @@ access_res_partner,res.partner,base.model_res_partner,portal.group_portal,1,0,0,
access_res_partner_address,res.partner_address,base.model_res_partner_address,portal.group_portal,1,0,0,0
access_res_partner_category,res.partner_category,base.model_res_partner_category,portal.group_portal,1,0,0,0
access_res_partner_title,res.partner_title,base.model_res_partner_title,portal.group_portal,1,0,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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
4 access_res_partner_address res.partner_address base.model_res_partner_address portal.group_portal 1 0 0 0
5 access_res_partner_category res.partner_category base.model_res_partner_category portal.group_portal 1 0 0 0
6 access_res_partner_title res.partner_title base.model_res_partner_title portal.group_portal 1 0 0 0
7 access_acquirer portal.payment.acquirer portal.model_portal_payment_acquirer 1 0 0 0
8 access_acquirer_all portal.payment.acquirer portal.model_portal_payment_acquirer base.group_system 1 1 1 1

View File

@ -0,0 +1,60 @@
.openerp .oe_application .oe_form_sheetbg {
/* Establish a stacking context on top of which the
payment_acquirers::before element can be positioned */
position: relative;
z-index: 0;
}
.openerp .payment_acquirers {
margin: -40px 0 -32px -24px;
position: relative;
padding: 10px 15px;
right: -153px;
background: #729FCF;
background-image: -webkit-gradient(linear, left top, left bottom, from(#729FCF), to(#3465A4));
background-image: -webkit-linear-gradient(top, #729FCF, #3465A4);
background-image: -moz-linear-gradient(top, #729FCF, #3465A4);
background-image: -ms-linear-gradient(top, #729FCF, #3465A4);
background-image: -o-linear-gradient(top, #729FCF, #3465A4);
background-image: linear-gradient(to bottom, #729FCF, #3465A4);
border-bottom: 1px solid #043574;
-webkit-box-shadow: 0 4px 20px rgba(0, 0, 0, 0.45);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.45);
}
.openerp .payment_acquirers::after {
content: " ";
display: block;
width: 10px;
height: 20px;
position: absolute;
bottom: 0;
right: 1px;
margin-bottom: -6px;
background: #043574;
-webkit-transform: skewY(-45deg);
-moz-transform: skewY(-45deg);
-ms-transform: skewY(-45deg);
-o-transform: skewY(-45deg);
transform: skewY(-45deg);
-webkit-box-shadow: inset 1px -1px 2px black, -1px 1px 3px black;
box-shadow: inset 1px -1px 2px black, -1px 1px 3px black;
/* push it under all its siblings, just on top of its root
in the z-index stack: div.oe_form_sheetbg */
z-index: -1;
}
.openerp .payment_acquirers .payment_header {
font-weight: bold;
font-size: 110%;
padding-right: 15px;
color: white;
text-shadow: 0 1px 1px #729FCF, 0 -1px 1px #3465A4;
}