[MERGE] Merge parents
bzr revid: rim@openerp.com-20131206091907-r9zo0z32zgewj0mx
|
@ -1,21 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="res_partner_grade_bronze" model="res.partner.grade">
|
||||
<field name="name">Bronze</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_silver" model="res.partner.grade">
|
||||
<field name="name">Silver</field>
|
||||
<field name="sequence">2</field>
|
||||
<record id="res_partner_grade_platinium" model="res.partner.grade">
|
||||
<field name="name">Platinum</field>
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_gold" model="res.partner.grade">
|
||||
<field name="name">Gold</field>
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_platinium" model="res.partner.grade">
|
||||
<field name="name">Platinum</field>
|
||||
<field name="sequence">4</field>
|
||||
<record id="res_partner_grade_silver" model="res.partner.grade">
|
||||
<field name="name">Silver</field>
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_bronze" model="res.partner.grade">
|
||||
<field name="name">Bronze</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
|
||||
<record id="base.res_partner_15" model="res.partner">
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
import logging
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools import float_round
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _partner_format_address(address1=False, address2=False):
|
||||
return ' '.join((address1 or '', address2 or ''))
|
||||
return ' '.join((address1 or '', address2 or '')).strip()
|
||||
|
||||
|
||||
def _partner_split_name(partner_name):
|
||||
|
@ -22,8 +23,9 @@ class ValidationError(ValueError):
|
|||
|
||||
class PaymentAcquirer(osv.Model):
|
||||
""" Acquirer Model. Each specific acquirer can extend the model by adding
|
||||
its own fields. Using the required_if_provider='<name>' attribute on fields
|
||||
it is possible to have required fields that depend on a specific acquirer.
|
||||
its own fields, using the acquirer_name as a prefix for the new fields.
|
||||
Using the required_if_provider='<name>' attribute on fields it is possible
|
||||
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``
|
||||
|
@ -36,7 +38,10 @@ class PaymentAcquirer(osv.Model):
|
|||
method that generates the values used to render the form button template.
|
||||
- ``<name>_get_form_action_url(self, cr, uid, id, context=None):``: method
|
||||
that returns the url of the button form. It is used for example in
|
||||
ecommerce application, if you want to repost some data to the acquirer.
|
||||
ecommerce application, if you want to post some data to the acquirer.
|
||||
- ``<name>_compute_fees(self, cr, uid, id, amount, currency_id, country_id,
|
||||
context=None)``: computed the fees of the acquirer, using generic fields
|
||||
defined on the acquirer model (see fields definition).
|
||||
|
||||
Each acquirer should also define controllers to handle communication between
|
||||
OpenERP and the acquirer. It generally consists in return urls given to the
|
||||
|
@ -54,8 +59,9 @@ class PaymentAcquirer(osv.Model):
|
|||
'env': fields.selection(
|
||||
[('test', 'Test'), ('prod', 'Production')],
|
||||
string='Environment'),
|
||||
'portal_published': fields.boolean('Visible in Portal',
|
||||
help="Make this payment acquirer available (Customer invoices, etc.)"),
|
||||
'portal_published': fields.boolean(
|
||||
'Visible in Portal',
|
||||
help="Make this payment acquirer available (Customer invoices, etc.)"),
|
||||
# Fees
|
||||
'fees_active': fields.boolean('Compute fees'),
|
||||
'fees_dom_fixed': fields.float('Fixed domestic fees'),
|
||||
|
@ -89,27 +95,91 @@ class PaymentAcquirer(osv.Model):
|
|||
return getattr(self, '%s_get_form_action_url' % acquirer.name)(cr, uid, id, context=context)
|
||||
return False
|
||||
|
||||
def form_preprocess_values(self, cr, uid, id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_custom_values, context=None):
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
tx_values = tx_custom_values
|
||||
def form_preprocess_values(self, cr, uid, id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_values, context=None):
|
||||
""" Pre process values before giving them to the acquirer-specific render
|
||||
methods. Those methods will receive:
|
||||
|
||||
# compute country
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
tx_values['country_id'] = partner.country_id.id
|
||||
elif partner_values and partner_values.get('country_name'):
|
||||
country_ids = self.pool['res.country'].search(cr, uid, [('name', '=', partner_values.get('country_name'))], context=context)
|
||||
tx_values['country_id'] = country_ids and country_ids[0] or None
|
||||
- partner_values: will contain name, lang, email, zip, address, city,
|
||||
country_id (int or False), country (browse or False), phone, reference
|
||||
- tx_values: will contain refernece, amount, currency_id (int or False),
|
||||
currency (browse or False), partner (browse or False)
|
||||
"""
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
|
||||
if tx_id:
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
tx_data = {
|
||||
'reference': tx.reference,
|
||||
'amount': tx.amount,
|
||||
'currency_id': tx.currency_id.id,
|
||||
'currency': tx.currency_id,
|
||||
'partner': tx.partner_id,
|
||||
}
|
||||
partner_data = {
|
||||
'name': tx.partner_name,
|
||||
'lang': tx.partner_lang,
|
||||
'email': tx.partner_email,
|
||||
'zip': tx.partner_zip,
|
||||
'address': tx.partner_address,
|
||||
'city': tx.partner_city,
|
||||
'country_id': tx.partner_country_id.id,
|
||||
'country': tx.partner_country_id,
|
||||
'phone': tx.partner_phone,
|
||||
'reference': tx.partner_reference,
|
||||
}
|
||||
else:
|
||||
tx_values['country_id'] = False
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
partner_data = {
|
||||
'name': partner.name,
|
||||
'lang': partner.lang,
|
||||
'email': partner.email,
|
||||
'zip': partner.zip,
|
||||
'city': partner.city,
|
||||
'address': _partner_format_address(partner.street, partner.street2),
|
||||
'country_id': partner.country_id.id,
|
||||
'country': partner.country_id,
|
||||
'phone': partner.phone,
|
||||
}
|
||||
else:
|
||||
partner, partner_data = False, {}
|
||||
partner_data.update(partner_values)
|
||||
|
||||
if currency_id:
|
||||
currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context)
|
||||
else:
|
||||
currency = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
|
||||
tx_data = {
|
||||
'reference': reference,
|
||||
'amount': amount,
|
||||
'currency_id': currency.id,
|
||||
'currency': currency,
|
||||
'partner': partner,
|
||||
}
|
||||
|
||||
# update tx values
|
||||
tx_data.update(tx_values)
|
||||
|
||||
# update partner values
|
||||
if not partner_data.get('address'):
|
||||
partner_data['address'] = _partner_format_address(partner_data.get('street', ''), partner_data.get('street2', ''))
|
||||
if not partner_data.get('country') and partner_data.get('country_id'):
|
||||
partner_data['country'] = self.pool['res.country'].browse(cr, uid, partner_data.get('country_id'), context=context)
|
||||
partner_data.update({
|
||||
'first_name': _partner_split_name(partner_data['name'])[0],
|
||||
'last_name': _partner_split_name(partner_data['name'])[1],
|
||||
})
|
||||
|
||||
# compute fees
|
||||
if hasattr(self, '%s_compute_fees' % acquirer.name):
|
||||
tx_values['fees'] = getattr(self, '%s_compute_fees' % acquirer.name)(cr, uid, id, amount, currency_id, tx_values.get('country_id'), context=None)
|
||||
fees_method_name = '%s_compute_fees' % acquirer.name
|
||||
if hasattr(self, fees_method_name):
|
||||
fees = getattr(self, fees_method_name)(
|
||||
cr, uid, id, tx_data['amount'], tx_data['currency_id'], partner_data['country_id'], context=None)
|
||||
tx_data['fees'] = float_round(fees, 2)
|
||||
|
||||
return tx_values
|
||||
return (partner_data, tx_data)
|
||||
|
||||
def render(self, cr, uid, id, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
|
||||
def render(self, cr, uid, id, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_values=None, context=None):
|
||||
""" Renders the form template of the given acquirer as a qWeb template.
|
||||
All templates will receive:
|
||||
|
||||
|
@ -120,9 +190,9 @@ class PaymentAcquirer(osv.Model):
|
|||
- reference: reference of the transaction
|
||||
- partner: the current partner browse record, if any (not necessarily set)
|
||||
- partner_values: a dictionary of partner-related values
|
||||
- tx_custom_values: a dictionary of transaction related values that depends
|
||||
on the acquirer. Some specific keys should be managed
|
||||
in each provider, depending on the features it offers:
|
||||
- tx_values: a dictionary of transaction related values that depends on
|
||||
the acquirer. Some specific keys should be managed in each
|
||||
provider, depending on the features it offers:
|
||||
|
||||
- 'feedback_url': feedback URL, controler that manage answer of the acquirer
|
||||
(without base url) -> FIXME
|
||||
|
@ -147,38 +217,40 @@ class PaymentAcquirer(osv.Model):
|
|||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if tx_custom_values is None:
|
||||
tx_custom_values = {}
|
||||
partner = None
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
if tx_values is None:
|
||||
tx_values = {}
|
||||
if partner_values is None:
|
||||
partner_values = {}
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context)
|
||||
|
||||
# pre-process values
|
||||
tx_values = self.form_preprocess_values(cr, uid, id, reference, amount, currency, tx_id, partner_id, partner_values, tx_custom_values, context=context)
|
||||
amount = float_round(amount, 2)
|
||||
partner_values, tx_values = self.form_preprocess_values(
|
||||
cr, uid, id, reference, amount, currency_id, tx_id, partner_id,
|
||||
partner_values, tx_values, context=context)
|
||||
|
||||
# call <name>_form_generate_values to update the tx dict with acqurier specific values
|
||||
cust_method_name = '%s_form_generate_values' % (acquirer.name)
|
||||
if tx_id and hasattr(self.pool['payment.transaction'], cust_method_name):
|
||||
method = getattr(self.pool['payment.transaction'], cust_method_name)
|
||||
tx_values = method(cr, uid, tx_id, tx_values, context=context)
|
||||
elif hasattr(self, cust_method_name):
|
||||
if hasattr(self, cust_method_name):
|
||||
method = getattr(self, cust_method_name)
|
||||
tx_values = method(cr, uid, id, reference, amount, currency, partner_id, partner_values, tx_values, context=context)
|
||||
partner_values, tx_values = method(cr, uid, id, partner_values, tx_values, context=context)
|
||||
|
||||
qweb_context = {
|
||||
'tx_url': context.get('tx_url', self.get_form_action_url(cr, uid, id, context=context)),
|
||||
'submit_class': context.get('submit_class', 'btn btn-link'),
|
||||
'submit_txt': context.get('submit_txt'),
|
||||
'acquirer': acquirer,
|
||||
'user': self.pool.get("res.users").browse(cr, uid, uid, context=context),
|
||||
'reference': reference,
|
||||
'amount': amount,
|
||||
'currency': currency,
|
||||
'partner': partner,
|
||||
'reference': tx_values['reference'],
|
||||
'amount': tx_values['amount'],
|
||||
'currency': tx_values['currency'],
|
||||
'partner': tx_values.get('partner'),
|
||||
'partner_values': partner_values,
|
||||
'tx_values': tx_values,
|
||||
'context': context,
|
||||
}
|
||||
# because render accepts view ids but not qweb -> need to find the xml_id
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
@ -186,12 +258,6 @@ class PaymentTransaction(osv.Model):
|
|||
""" Transaction Model. Each specific acquirer can extend the model by adding
|
||||
its own fields.
|
||||
|
||||
Methods that should be added in an acquirer-specific implementation:
|
||||
|
||||
- ``<name>_form_generate_values(self, cr, uid, id, tx_custom_values=None,
|
||||
context=None)``: method that generates the values used to render the
|
||||
form button template.
|
||||
|
||||
Methods that can be added in an acquirer-specific implementation:
|
||||
|
||||
- ``<name>_create``: method receiving values used when creating a new
|
||||
|
@ -230,22 +296,29 @@ class PaymentTransaction(osv.Model):
|
|||
help='Field used to store error and/or validation messages for information'),
|
||||
# payment
|
||||
'amount': fields.float('Amount', required=True,
|
||||
help='Amount in cents',
|
||||
track_visibility='always'),
|
||||
'fees': fields.float('Fees', help='Fees amount; set by the system because depends on the acquirer'),
|
||||
digits=(16, 2),
|
||||
track_visibility='always',
|
||||
help='Amount in cents'),
|
||||
'fees': fields.float('Fees',
|
||||
digits=(16, 2),
|
||||
track_visibility='always',
|
||||
help='Fees amount; set by the system because depends on the acquirer'),
|
||||
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
|
||||
'reference': fields.char('Order Reference', required=True),
|
||||
'acquirer_reference': fields.char('Acquirer Order Reference',
|
||||
help='Reference of the TX as stored in the acquirer database'),
|
||||
# duplicate partner / transaction data to store the values at transaction time
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner', track_visibility='onchange',),
|
||||
'partner_name': fields.char('Partner Name'),
|
||||
'partner_lang': fields.char('Lang'),
|
||||
'partner_email': fields.char('Email'),
|
||||
'partner_zip': fields.char('Zip'),
|
||||
'partner_address': fields.char('Address'),
|
||||
'partner_city': fields.char('City'),
|
||||
'partner_country_id': fields.many2one('res.country', 'Country'),
|
||||
'partner_country_id': fields.many2one('res.country', 'Country', required=True),
|
||||
'partner_phone': fields.char('Phone'),
|
||||
'partner_reference': fields.char('Buyer Reference'),
|
||||
'partner_reference': fields.char('Partner Reference',
|
||||
help='Reference of the customer in the acquirer database'),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
|
@ -272,8 +345,9 @@ class PaymentTransaction(osv.Model):
|
|||
# compute fees
|
||||
custom_method_name = '%s_compute_fees' % acquirer.name
|
||||
if hasattr(Acquirer, custom_method_name):
|
||||
values['fees'] = getattr(Acquirer, custom_method_name)(
|
||||
fees = getattr(Acquirer, custom_method_name)(
|
||||
cr, uid, acquirer.id, values.get('amount', 0.0), values.get('currency_id'), values.get('country_id'), context=None)
|
||||
values['fees'] = float_round(fees, 2)
|
||||
|
||||
# custom create
|
||||
custom_method_name = '%s_create' % acquirer.name
|
||||
|
@ -283,30 +357,19 @@ class PaymentTransaction(osv.Model):
|
|||
return super(PaymentTransaction, self).create(cr, uid, values, context=context)
|
||||
|
||||
def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
|
||||
partner = None
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
values = {
|
||||
'partner_name': partner.name,
|
||||
'partner_lang': partner.lang,
|
||||
'partner_email': partner.email,
|
||||
'partner_zip': partner.zip,
|
||||
'partner_address': _partner_format_address(partner.street, partner.street2),
|
||||
'partner_city': partner.city,
|
||||
'partner_country_id': partner.country_id.id,
|
||||
'partner_phone': partner.phone,
|
||||
}
|
||||
else:
|
||||
values = {
|
||||
'partner_name': False,
|
||||
'partner_lang': 'en_US',
|
||||
'partner_email': False,
|
||||
'partner_zip': False,
|
||||
'partner_address': False,
|
||||
'partner_city': False,
|
||||
'partner_country_id': False,
|
||||
'partner_phone': False,
|
||||
}
|
||||
return {'values': values}
|
||||
return {'values': {
|
||||
'partner_name': partner and partner.name or False,
|
||||
'partner_lang': partner and partner.lang or 'en_US',
|
||||
'partner_email': partner and partner.email or False,
|
||||
'partner_zip': partner and partner.zip or False,
|
||||
'partner_address': _partner_format_address(partner and partner.street or '', partner and partner.street2 or ''),
|
||||
'partner_city': partner and partner.city or False,
|
||||
'partner_country_id': partner and partner.country_id.id or False,
|
||||
'partner_phone': partner and partner.phone or False,
|
||||
}}
|
||||
|
||||
# --------------------------------------------------
|
||||
# FORM RELATED METHODS
|
||||
|
|
|
@ -14,8 +14,10 @@ class PaymentAcquirerCommon(common.TransactionCase):
|
|||
self.cr, self.uid, [('name', '=', 'EUR')], limit=1)[0]
|
||||
self.currency_euro = self.registry('res.currency').browse(
|
||||
self.cr, self.uid, self.currency_euro_id)
|
||||
country_belgium_id = self.registry('res.country').search(
|
||||
self.country_belgium_id = self.registry('res.country').search(
|
||||
self.cr, self.uid, [('code', 'like', 'BE')], limit=1)[0]
|
||||
self.country_france_id = self.registry('res.country').search(
|
||||
self.cr, self.uid, [('code', 'like', 'FR')], limit=1)[0]
|
||||
|
||||
# dict partner values
|
||||
self.buyer_values = {
|
||||
|
@ -27,7 +29,7 @@ class PaymentAcquirerCommon(common.TransactionCase):
|
|||
'phone': '0032 12 34 56 78',
|
||||
'city': 'Sin City',
|
||||
'zip': '1000',
|
||||
'country_id': country_belgium_id,
|
||||
'country_id': self.country_belgium_id,
|
||||
'country_name': 'Belgium',
|
||||
}
|
||||
|
||||
|
@ -42,6 +44,6 @@ class PaymentAcquirerCommon(common.TransactionCase):
|
|||
'phone': '0032 12 34 56 78',
|
||||
'city': 'Sin City',
|
||||
'zip': '1000',
|
||||
'country_id': country_belgium_id,
|
||||
'country_id': self.country_belgium_id,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -38,10 +38,10 @@
|
|||
<div>
|
||||
<field name="view_template_id" nolabel="1"/>
|
||||
<div>
|
||||
This is an HTML form template to submit a payment through this acquirer.
|
||||
The template will be rendered with qWeb, so it may use qWeb expressions.
|
||||
The qWeb evaluation context provides:
|
||||
This template renders the acquirer button with all necessary values.
|
||||
It is be rendered with qWeb with the following evaluation context:
|
||||
<ul>
|
||||
<li>tx_url: transaction URL to post the form</li>
|
||||
<li>acquirer: payment.acquirer browse record</li>
|
||||
<li>user: current user browse record</li>
|
||||
<li>reference: the transaction reference number</li>
|
||||
|
@ -49,7 +49,7 @@
|
|||
<li>amount: the transaction amount, a float</li>
|
||||
<li>partner: the buyer partner browse record, not necessarily set</li>
|
||||
<li>partner_values: specific values about the buyer, for example coming from a shipping form</li>
|
||||
<li>tx_values: specific transaction values</li>
|
||||
<li>tx_values: transaction values</li>
|
||||
<li>context: the current context dictionary</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -98,23 +98,32 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Payment Transactions" version="7.0">
|
||||
<sheet>
|
||||
<group>
|
||||
<group col="6">
|
||||
<group>
|
||||
<field name="reference"/>
|
||||
<field name="amount"/>
|
||||
<field name="date_create"/>
|
||||
<field name="fees"/>
|
||||
<field name="currency_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="partner_name"/>
|
||||
<field name="partner_email"/>
|
||||
<field name="partner_reference"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_create"/>
|
||||
<field name="date_validate"/>
|
||||
<field name="acquirer_id"/>
|
||||
<field name="acquirer_reference"/>
|
||||
<field name="date_validate"/>
|
||||
<field name="state"/>
|
||||
<field name="state_message"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="partner_name"/>
|
||||
<field name="partner_address"/>
|
||||
<field name="partner_email"/>
|
||||
<field name="partner_lang"/>
|
||||
<field name="partner_zip"/>
|
||||
<field name="partner_city"/>
|
||||
<field name="partner_country_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
</notebook>
|
||||
|
|
|
@ -19,7 +19,7 @@ class AdyenController(http.Controller):
|
|||
|
||||
@website.route([
|
||||
'/payment/adyen/return/',
|
||||
], type='http', auth='public', methods=['POST'])
|
||||
], type='http', auth='public')
|
||||
def adyen_return(self, **post):
|
||||
""" Paypal IPN. """
|
||||
_logger.info('Beginning Adyen form_feedback with post data %s', pprint.pformat(post)) # debug
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_acquirer_adyen" model="payment.acquirer">
|
||||
<field name="name">adyen</field>
|
||||
<field name="view_template_id" ref="adyen_acquirer_button"/>
|
||||
<field name="env">test</field>
|
||||
<field name="adyen_merchant_account">OpenERPCOM</field>
|
||||
<field name="adyen_skin_code">cbqYWvVL</field>
|
||||
<field name="adyen_skin_hmac_key">cbqYWvVL</field>
|
||||
<field name="adyen_merchant_account">dummy</field>
|
||||
<field name="adyen_skin_code">dummy</field>
|
||||
<field name="adyen_skin_hmac_key">dummy</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -21,26 +21,24 @@ _logger = logging.getLogger(__name__)
|
|||
class AcquirerAdyen(osv.Model):
|
||||
_inherit = 'payment.acquirer'
|
||||
|
||||
def _get_adyen_urls(self, cr, uid, ids, name, args, context=None):
|
||||
def _get_adyen_urls(self, cr, uid, env, context=None):
|
||||
""" Adyen URLs
|
||||
|
||||
- yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple
|
||||
"""
|
||||
res = {}
|
||||
for acquirer in self.browse(cr, uid, ids, context=context):
|
||||
qualif = acquirer.env
|
||||
res[acquirer.id] = {
|
||||
'adyen_form_url': 'https://%s.adyen.com/hpp/pay.shtml' % qualif,
|
||||
if env == 'prod':
|
||||
return {
|
||||
'adyen_form_url': 'https://prod.adyen.com/hpp/pay.shtml',
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'adyen_form_url': 'https://test.adyen.com/hpp/pay.shtml',
|
||||
}
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'adyen_merchant_account': fields.char('Merchant Account', required_if_provider='adyen'),
|
||||
'adyen_skin_code': fields.char('Skin Code', required_if_provider='adyen'),
|
||||
'adyen_skin_hmac_key': fields.char('Skin HMAC Key', required_if_provider='adyen'),
|
||||
'adyen_form_url': fields.function(
|
||||
_get_adyen_urls, multi='_get_adyen_urls',
|
||||
type='char', string='Transaction URL', required_if_provider='adyen'),
|
||||
}
|
||||
|
||||
def _adyen_generate_merchant_sig(self, acquirer, inout, values):
|
||||
|
@ -72,9 +70,7 @@ class AcquirerAdyen(osv.Model):
|
|||
key = acquirer.adyen_skin_hmac_key.encode('ascii')
|
||||
return base64.b64encode(hmac.new(key, sign, sha1).digest())
|
||||
|
||||
def adyen_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
|
||||
if partner_values is None:
|
||||
partner_values = {}
|
||||
def adyen_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
|
||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
# tmp
|
||||
|
@ -82,31 +78,26 @@ class AcquirerAdyen(osv.Model):
|
|||
from dateutil import relativedelta
|
||||
tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1)
|
||||
|
||||
partner = None
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
tx_values = {
|
||||
'merchantReference': reference,
|
||||
'paymentAmount': '%d' % int(float_round(amount, 2) * 100),
|
||||
'currencyCode': currency and currency.name or 'EUR',
|
||||
adyen_tx_values = dict(tx_values)
|
||||
adyen_tx_values.update({
|
||||
'merchantReference': tx_values['reference'],
|
||||
'paymentAmount': '%d' % int(float_round(tx_values['amount'], 2) * 100),
|
||||
'currencyCode': tx_values['currency'] and tx_values['currency'].name or '',
|
||||
'shipBeforeDate': tmp_date,
|
||||
'skinCode': acquirer.adyen_skin_code,
|
||||
'merchantAccount': acquirer.adyen_merchant_account,
|
||||
'shopperLocale': partner and partner.lang or partner_values.get('lang', 'en_US'),
|
||||
'shopperLocale': partner_values['lang'],
|
||||
'sessionValidity': tmp_date,
|
||||
'merchantSig': 'oij',
|
||||
'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url),
|
||||
}
|
||||
if tx_custom_values and tx_custom_values.get('return_url'):
|
||||
tx_values['merchantReturnData'] = json.dumps({'return_url': '%s' % tx_custom_values.pop('return_url')})
|
||||
if tx_custom_values:
|
||||
tx_values.update(tx_custom_values)
|
||||
tx_values['merchantSig'] = self._adyen_generate_merchant_sig(acquirer, 'in', tx_values)
|
||||
return tx_values
|
||||
})
|
||||
if adyen_tx_values.get('return_url'):
|
||||
adyen_tx_values['merchantReturnData'] = json.dumps({'return_url': '%s' % adyen_tx_values.pop('return_url')})
|
||||
adyen_tx_values['merchantSig'] = self._adyen_generate_merchant_sig(acquirer, 'in', adyen_tx_values)
|
||||
return partner_values, adyen_tx_values
|
||||
|
||||
def adyen_get_form_action_url(self, cr, uid, id, context=None):
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
return acquirer.adyen_form_url
|
||||
return self._get_adyen_urls(cr, uid, acquirer.env, context=context)['adyen_form_url']
|
||||
|
||||
|
||||
class TxAdyen(osv.Model):
|
||||
|
@ -120,21 +111,6 @@ class TxAdyen(osv.Model):
|
|||
# FORM RELATED METHODS
|
||||
# --------------------------------------------------
|
||||
|
||||
def adyen_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
|
||||
tx_data = {
|
||||
'shopperLocale': tx.partner_lang,
|
||||
}
|
||||
if tx_custom_values:
|
||||
tx_data.update(tx_custom_values)
|
||||
return self.pool['payment.acquirer'].paypal_form_generate_values(
|
||||
cr, uid, tx.acquirer_id.id,
|
||||
tx.reference, tx.amount, tx.currency_id,
|
||||
tx_custom_values=tx_data,
|
||||
context=context
|
||||
)
|
||||
|
||||
def _adyen_form_get_tx_from_data(self, cr, uid, data, context=None):
|
||||
reference, pspReference = data.get('merchantReference'), data.get('pspReference')
|
||||
if not reference or not pspReference:
|
||||
|
@ -164,12 +140,18 @@ class TxAdyen(osv.Model):
|
|||
return tx
|
||||
|
||||
def _adyen_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
|
||||
# TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details
|
||||
invalid_parameters = []
|
||||
|
||||
# reference at acquirer: pspReference
|
||||
if tx.acquirer_reference and data.get('pspReference') != tx.acquirer_reference:
|
||||
invalid_parameters.append(('pspReference', data.get('pspReference'), tx.acquirer_reference))
|
||||
# seller
|
||||
if data.get('skinCode') != tx.acquirer_id.adyen_skin_code:
|
||||
invalid_parameters.append(('skinCode', data.get('skinCode'), tx.acquirer_id.adyen_skin_code))
|
||||
# result
|
||||
if not data.get('authResult'):
|
||||
invalid_parameters.append(('authResult', data.get('authResult'), 'something'))
|
||||
|
||||
return invalid_parameters
|
||||
|
||||
def _adyen_form_validate(self, cr, uid, tx, data, context=None):
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_adyen
|
||||
# from . import test_adyen
|
||||
|
||||
checks = [
|
||||
test_adyen,
|
||||
# test_adyen,
|
||||
]
|
||||
|
|
|
@ -1,34 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
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.osv.orm import except_orm
|
||||
from openerp.tools import mute_logger
|
||||
|
||||
from lxml import objectify
|
||||
import urlparse
|
||||
|
||||
|
||||
class AdyenCommon(PaymentAcquirerCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(AdyenCommon, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
model, self.paypal_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_adyen', 'adyen_acquirer_button')
|
||||
|
||||
# create a new ogone account
|
||||
self.adyen_id = self.payment_acquirer.create(
|
||||
cr, uid, {
|
||||
'name': 'adyen',
|
||||
'env': 'test',
|
||||
'view_template_id': self.paypal_view_id,
|
||||
'adyen_merchant_account': 'OpenERPCOM',
|
||||
'adyen_skin_code': 'cbqYWvVL',
|
||||
'adyen_skin_hmac_key': 'cbqYWvVL',
|
||||
})
|
||||
# get the adyen account
|
||||
model, self.adyen_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_adyen', 'payment_acquirer_adyen')
|
||||
|
||||
# some CC (always use expiration date 06 / 2016, cvc 737, cid 7373 (amex))
|
||||
self.amex = (('370000000000002', '7373'))
|
||||
|
@ -57,6 +47,9 @@ class AdyenForm(AdyenCommon):
|
|||
|
||||
def test_10_adyen_form_render(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')
|
||||
|
||||
# ----------------------------------------
|
||||
# Test: button direct rendering
|
||||
|
@ -74,7 +67,7 @@ class AdyenForm(AdyenCommon):
|
|||
# render the button
|
||||
res = self.payment_acquirer.render(
|
||||
cr, uid, self.adyen_id,
|
||||
'test_ref0', 0.01, self.currency_euro,
|
||||
'test_ref0', 0.01, self.currency_euro_id,
|
||||
partner_id=None,
|
||||
partner_values=self.buyer_values,
|
||||
context=context)
|
||||
|
@ -88,12 +81,15 @@ class AdyenForm(AdyenCommon):
|
|||
self.assertEqual(
|
||||
form_input.get('value'),
|
||||
form_values[form_input.get('name')],
|
||||
'adyen: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')])
|
||||
'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')
|
||||
|
||||
# {'authResult': u'AUTHORISED',
|
||||
# 'merchantReference': u'SO014',
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<data noupdate="0">
|
||||
|
||||
<template id="adyen_acquirer_button">
|
||||
<form t-if="acquirer.adyen_merchant_account" t-att-action="acquirer.adyen_form_url" method="post" target="_self">
|
||||
<form t-if="acquirer.adyen_merchant_account" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="merchantReference" t-att-value="tx_values['merchantReference']"/>
|
||||
<input type="hidden" name="paymentAmount" t-att-value="tx_values['paymentAmount']"/>
|
||||
<input type="hidden" name="currencyCode" t-att-value="tx_values['currencyCode']"/>
|
||||
|
@ -19,10 +19,12 @@
|
|||
<!-- custom -->
|
||||
<input t-if="tx_values.get('merchantReturnData')" type='hidden' name='merchantReturnData'
|
||||
t-att-value="tx_values.get('merchantReturnData')"/>
|
||||
<!-- button -->
|
||||
<input type="image" name="submit" id="payment_submit"
|
||||
width="100px"
|
||||
src="/payment_acquirer_adyen/static/src/img/logo.jpg"/>
|
||||
<!-- 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"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
<field name="model">payment.acquirer</field>
|
||||
<field name="inherit_id" ref="payment_acquirer.acquirer_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//group[@name="acquirer_base"]' position='after'>
|
||||
<group string="Adyen Details"
|
||||
attrs="{'invisible': [('name', '!=', 'adyen')]}">
|
||||
<xpath expr='//group[@name="acquirer_display"]' position='after'>
|
||||
<group attrs="{'invisible': [('name', '!=', 'adyen')]}">
|
||||
<field name="adyen_merchant_account"/>
|
||||
<field name="adyen_skin_code"/>
|
||||
<field name="adyen_skin_hmac_key"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
|
|
|
@ -22,7 +22,8 @@ class OgoneController(http.Controller):
|
|||
'/payment/ogone/cancel', '/payment/ogone/test/cancel',
|
||||
], 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'].ogone_form_feedback(cr, uid, post, context)
|
||||
request.registry['payment.transaction'].form_feedback(cr, uid, post, 'ogone', context=context)
|
||||
return request.redirect(post.pop('return_url', '/'))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_acquirer_ogone" model="payment.acquirer">
|
||||
<field name="name">ogone</field>
|
||||
|
@ -9,8 +9,8 @@
|
|||
<field name='ogone_pspid'>dummy</field>
|
||||
<field name='ogone_userid'>dummy</field>
|
||||
<field name='ogone_password'>dummy</field>
|
||||
<field name="ogone_shakey_in">tINY4Yv14789gUix1130</field>
|
||||
<field name="ogone_shakey_out">tINYj885Tfvd4P471464</field>
|
||||
<field name="ogone_shakey_in">dummy</field>
|
||||
<field name="ogone_shakey_out">dummy</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -14,6 +14,7 @@ from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneControll
|
|||
from openerp.addons.payment_acquirer_ogone.data import ogone
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools import float_round
|
||||
from openerp.tools.float_utils import float_compare
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -21,48 +22,26 @@ _logger = logging.getLogger(__name__)
|
|||
class PaymentAcquirerOgone(osv.Model):
|
||||
_inherit = 'payment.acquirer'
|
||||
|
||||
def _get_ogone_urls(self, cr, uid, ids, name, args, context=None):
|
||||
def _get_ogone_urls(self, cr, uid, env, context=None):
|
||||
""" Ogone URLS:
|
||||
|
||||
- standard order: POST address for form-based
|
||||
|
||||
@TDETODO: complete me
|
||||
"""
|
||||
res = {}
|
||||
for acquirer in self.browse(cr, uid, ids, context=context):
|
||||
qualif = acquirer.env
|
||||
res[acquirer.id] = {
|
||||
'ogone_standard_order_url': 'https://secure.ogone.com/ncol/%s/orderstandard.asp' % qualif,
|
||||
'ogone_direct_order_url': 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % qualif,
|
||||
'ogone_direct_query_url': 'https://secure.ogone.com/ncol/%s/querydirect.asp' % qualif,
|
||||
'ogone_afu_agree_url': 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % qualif,
|
||||
}
|
||||
return res
|
||||
return {
|
||||
'ogone_standard_order_url': 'https://secure.ogone.com/ncol/%s/orderstandard.asp' % env,
|
||||
'ogone_direct_order_url': 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % env,
|
||||
'ogone_direct_query_url': 'https://secure.ogone.com/ncol/%s/querydirect.asp' % env,
|
||||
'ogone_afu_agree_url': 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % env,
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'ogone_pspid': fields.char(
|
||||
'PSPID', required_if_provider='ogone'),
|
||||
'ogone_userid': fields.char(
|
||||
'API User id', required_if_provider='ogone'),
|
||||
'ogone_password': fields.char(
|
||||
'Password', required_if_provider='ogone'),
|
||||
'ogone_shakey_in': fields.char(
|
||||
'SHA Key IN', size=32, required_if_provider='ogone'),
|
||||
'ogone_shakey_out': fields.char(
|
||||
'SHA Key OUT', size=32, required_if_provider='ogone'),
|
||||
# store ogone contact URLs -> not necessary IMHO
|
||||
'ogone_standard_order_url': fields.function(
|
||||
_get_ogone_urls, type='char', multi='_get_ogone_urls',
|
||||
string='Stanrd Order URL (form)'),
|
||||
'ogone_direct_order_url': fields.function(
|
||||
_get_ogone_urls, type='char', multi='_get_ogone_urls',
|
||||
string='Direct Order URL (2)'),
|
||||
'ogone_direct_query_url': fields.function(
|
||||
_get_ogone_urls, type='char', multi='_get_ogone_urls',
|
||||
string='Direct Query URL'),
|
||||
'ogone_afu_agree_url': fields.function(
|
||||
_get_ogone_urls, type='char', multi='_get_ogone_urls',
|
||||
string='AFU Agree URL'),
|
||||
'ogone_pspid': fields.char('PSPID', required_if_provider='ogone'),
|
||||
'ogone_userid': fields.char('API User ID', required_if_provider='ogone'),
|
||||
'ogone_password': fields.char('API User Password', required_if_provider='ogone'),
|
||||
'ogone_shakey_in': fields.char('SHA Key IN', size=32, required_if_provider='ogone'),
|
||||
'ogone_shakey_out': fields.char('SHA Key OUT', size=32, required_if_provider='ogone'),
|
||||
}
|
||||
|
||||
def _ogone_generate_shasign(self, acquirer, inout, values):
|
||||
|
@ -93,43 +72,39 @@ class PaymentAcquirerOgone(osv.Model):
|
|||
shasign = sha1(sign).hexdigest()
|
||||
return shasign
|
||||
|
||||
def ogone_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
|
||||
if partner_values is None:
|
||||
partner_values = {}
|
||||
def ogone_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
|
||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
partner = None
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
tx_values = {
|
||||
|
||||
ogone_tx_values = dict(tx_values)
|
||||
temp_ogone_tx_values = {
|
||||
'PSPID': acquirer.ogone_pspid,
|
||||
'ORDERID': reference,
|
||||
'AMOUNT': '%d' % int(float_round(amount, 2) * 100),
|
||||
'CURRENCY': currency and currency.name or 'EUR',
|
||||
'LANGUAGE': partner and partner.lang or partner_values.get('lang', ''),
|
||||
'CN': partner and partner.name or partner_values.get('name', ''),
|
||||
'EMAIL': partner and partner.email or partner_values.get('email', ''),
|
||||
'OWNERZIP': partner and partner.zip or partner_values.get('zip', ''),
|
||||
'OWNERADDRESS': partner and ' '.join((partner.street or '', partner.street2 or '')).strip() or ' '.join((partner_values.get('street', ''), partner_values.get('street2', ''))).strip(),
|
||||
'OWNERTOWN': partner and partner.city or partner_values.get('city', ''),
|
||||
'OWNERCTY': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
|
||||
'OWNERTELNO': partner and partner.phone or partner_values.get('phone', ''),
|
||||
'ORDERID': tx_values['reference'],
|
||||
'AMOUNT': '%d' % int(float_round(tx_values['amount'], 2) * 100),
|
||||
'CURRENCY': tx_values['currency'] and tx_values['currency'].name or '',
|
||||
'LANGUAGE': partner_values['lang'],
|
||||
'CN': partner_values['name'],
|
||||
'EMAIL': partner_values['email'],
|
||||
'OWNERZIP': partner_values['zip'],
|
||||
'OWNERADDRESS': partner_values['address'],
|
||||
'OWNERTOWN': partner_values['city'],
|
||||
'OWNERCTY': partner_values['country'] and partner_values['country'].name or '',
|
||||
'OWNERTELNO': partner_values['phone'],
|
||||
'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneController._accept_url),
|
||||
'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneController._decline_url),
|
||||
'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url),
|
||||
'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url),
|
||||
}
|
||||
if tx_custom_values and tx_custom_values.get('return_url'):
|
||||
tx_values['PARAMPLUS'] = 'return_url=%s' % tx_custom_values.pop('return_url')
|
||||
if tx_custom_values:
|
||||
tx_values.update(tx_custom_values)
|
||||
shasign = self._ogone_generate_shasign(acquirer, 'in', tx_values)
|
||||
tx_values['SHASIGN'] = shasign
|
||||
return tx_values
|
||||
if ogone_tx_values.get('return_url'):
|
||||
temp_ogone_tx_values['PARAMPLUS'] = 'return_url=%s' % ogone_tx_values.pop('return_url')
|
||||
shasign = self._ogone_generate_shasign(acquirer, 'in', temp_ogone_tx_values)
|
||||
temp_ogone_tx_values['SHASIGN'] = shasign
|
||||
ogone_tx_values.update(temp_ogone_tx_values)
|
||||
return partner_values, ogone_tx_values
|
||||
|
||||
def ogone_get_form_action_url(self, cr, uid, id, context=None):
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
return acquirer.ogone_standard_order_url
|
||||
return self._get_ogone_urls(cr, uid, acquirer.env, context=context)['ogone_standard_order_url']
|
||||
|
||||
|
||||
class PaymentTxOgone(osv.Model):
|
||||
|
@ -141,10 +116,8 @@ class PaymentTxOgone(osv.Model):
|
|||
_ogone_cancel_tx_status = [1]
|
||||
|
||||
_columns = {
|
||||
'ogone_3ds': fields.dummy('3ds Activated'),
|
||||
'ogone_3ds': fields.boolean('3DS Activated'),
|
||||
'ogone_3ds_html': fields.html('3DS HTML'),
|
||||
'ogone_feedback_model': fields.char(),
|
||||
'ogone_feedback_eval': fields.char(),
|
||||
'ogone_complus': fields.char('Complus'),
|
||||
'ogone_payid': fields.char('PayID', help='Payment ID, generated by Ogone')
|
||||
}
|
||||
|
@ -153,30 +126,6 @@ class PaymentTxOgone(osv.Model):
|
|||
# FORM RELATED METHODS
|
||||
# --------------------------------------------------
|
||||
|
||||
def ogone_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
|
||||
""" Ogone-specific value generation for rendering a transaction-based
|
||||
form button. """
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
|
||||
tx_data = {
|
||||
'LANGUAGE': tx.partner_lang,
|
||||
'CN': tx.partner_name,
|
||||
'EMAIL': tx.partner_email,
|
||||
'OWNERZIP': tx.partner_zip,
|
||||
'OWNERADDRESS': tx.partner_address,
|
||||
'OWNERTOWN': tx.partner_city,
|
||||
'OWNERCTY': tx.partner_country_id and tx.partner_country_id.name or '',
|
||||
'OWNERTELNO': tx.partner_phone,
|
||||
}
|
||||
if tx_custom_values:
|
||||
tx_data.update(tx_custom_values)
|
||||
return self.pool['payment.acquirer'].ogone_form_generate_values(
|
||||
cr, uid, tx.acquirer_id.id,
|
||||
tx.reference, tx.amount, tx.currency_id,
|
||||
tx_custom_values=tx_data,
|
||||
context=context
|
||||
)
|
||||
|
||||
def _ogone_form_get_tx_from_data(self, cr, uid, data, context=None):
|
||||
""" Given a data dict coming from ogone, verify it and find the related
|
||||
transaction record. """
|
||||
|
@ -207,29 +156,42 @@ class PaymentTxOgone(osv.Model):
|
|||
|
||||
return tx
|
||||
|
||||
def ogone_form_feedback(self, cr, uid, data, context=None):
|
||||
tx = self._ogone_form_get_tx_from_data(cr, uid, data, context)
|
||||
if not tx:
|
||||
raise ValidationError('Ogone: feedback: tx not found')
|
||||
def _ogone_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
|
||||
invalid_parameters = []
|
||||
|
||||
# TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details
|
||||
if tx.acquirer_reference and data.get('PAYID') != tx.acquirer_reference:
|
||||
invalid_parameters.append(('PAYID', data.get('PAYID'), tx.acquirer_reference))
|
||||
# check what is buyed
|
||||
if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0:
|
||||
invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount))
|
||||
if data.get('currency') != tx.currency_id.name:
|
||||
invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name))
|
||||
|
||||
return invalid_parameters
|
||||
|
||||
def _ogone_form_validate(self, cr, uid, tx, data, context=None):
|
||||
if tx.state == 'done':
|
||||
_logger.warning('Ogone: trying to validate an already validated tx (ref %s' % tx.reference)
|
||||
return False
|
||||
_logger.warning('Ogone: trying to validate an already validated tx (ref %s)' % tx.reference)
|
||||
return True
|
||||
|
||||
status = int(data.get('STATUS', '0'))
|
||||
if status in self._ogone_valid_tx_status:
|
||||
tx.write({
|
||||
'state': 'done',
|
||||
'date_validate': data['TRXDATE'],
|
||||
'ogone_payid': data['PAYID'],
|
||||
'acquirer_reference': data['PAYID'],
|
||||
})
|
||||
return True
|
||||
elif status in self._ogone_cancel_tx_status:
|
||||
tx.write({
|
||||
'state': 'cancel',
|
||||
'acquirer_reference': data.get('PAYID'),
|
||||
})
|
||||
elif status in self._ogone_pending_tx_status:
|
||||
tx.write({
|
||||
'state': 'pending',
|
||||
'acquirer_reference': data.get('PAYID'),
|
||||
})
|
||||
else:
|
||||
error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
|
||||
|
@ -238,7 +200,11 @@ class PaymentTxOgone(osv.Model):
|
|||
'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERRORPLUS')),
|
||||
}
|
||||
_logger.info(error)
|
||||
tx.write({'state': 'error', 'state_message': error})
|
||||
tx.write({
|
||||
'state': 'error',
|
||||
'state_message': error,
|
||||
'acquirer_reference': data.get('PAYID'),
|
||||
})
|
||||
return False
|
||||
|
||||
# --------------------------------------------------
|
||||
|
@ -268,6 +234,7 @@ class PaymentTxOgone(osv.Model):
|
|||
'PROCESS_MODE': 'CHECKANDPROCESS',
|
||||
}
|
||||
|
||||
# TODO: fix URL computation
|
||||
request = urllib2.Request(tx.acquirer_id.ogone_afu_agree_url, urlencode(tx_data))
|
||||
result = urllib2.urlopen(request).read()
|
||||
|
||||
|
|
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 3.1 KiB |
|
@ -1,45 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
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.tools import mute_logger
|
||||
|
||||
from lxml import objectify
|
||||
# import requests
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
|
||||
class OgonePayment(PaymentAcquirerCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(OgonePayment, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
model, self.ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button')
|
||||
|
||||
# create a new ogone account
|
||||
self.ogone_id = self.payment_acquirer.create(
|
||||
cr, uid, {
|
||||
'name': 'ogone',
|
||||
'env': 'test',
|
||||
'view_template_id': self.ogone_view_id,
|
||||
'ogone_pspid': 'dummy',
|
||||
'ogone_userid': 'dummy',
|
||||
'ogone_password': 'dummy',
|
||||
'ogone_shakey_in': 'tINY4Yv14789gUix1130',
|
||||
'ogone_shakey_out': 'tINYj885Tfvd4P471464',
|
||||
})
|
||||
self.ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [self.ogone_id], None, None)[self.ogone_id]['ogone_standard_order_url']
|
||||
|
||||
def test_00_ogone_acquirer(self):
|
||||
ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None)
|
||||
self.assertEqual(ogone.env, 'test', 'test without test env')
|
||||
# get the adyen account
|
||||
model, self.ogone_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'payment_acquirer_ogone')
|
||||
|
||||
def test_10_ogone_form_render(self):
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
# be sure not to do stupid thing
|
||||
ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None)
|
||||
self.assertEqual(ogone.env, 'test', 'test without test env')
|
||||
|
||||
# ----------------------------------------
|
||||
# Test: button direct rendering + shasign
|
||||
|
@ -68,7 +53,7 @@ class OgonePayment(PaymentAcquirerCommon):
|
|||
# render the button
|
||||
res = self.payment_acquirer.render(
|
||||
cr, uid, self.ogone_id,
|
||||
'test_ref0', 0.01, self.currency_euro,
|
||||
'test_ref0', 0.01, self.currency_euro_id,
|
||||
partner_id=None,
|
||||
partner_values=self.buyer_values,
|
||||
context=context)
|
||||
|
@ -82,7 +67,7 @@ class OgonePayment(PaymentAcquirerCommon):
|
|||
self.assertEqual(
|
||||
form_input.get('value'),
|
||||
form_values[form_input.get('name')],
|
||||
'ogone: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')])
|
||||
'ogone: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
|
||||
)
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -123,6 +108,9 @@ class OgonePayment(PaymentAcquirerCommon):
|
|||
@mute_logger('openerp.addons.payment_acquirer_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
|
||||
ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None)
|
||||
self.assertEqual(ogone.env, 'test', 'test without test env')
|
||||
|
||||
# typical data posted by ogone after client has successfully paid
|
||||
ogone_post_data = {
|
||||
|
@ -155,6 +143,7 @@ class OgonePayment(PaymentAcquirerCommon):
|
|||
'currency_id': self.currency_euro_id,
|
||||
'reference': 'test_ref_2',
|
||||
'partner_name': 'Norbert Buyer',
|
||||
'partner_country_id': self.country_france_id,
|
||||
}, context=context
|
||||
)
|
||||
# validate it
|
||||
|
@ -183,6 +172,9 @@ class OgonePayment(PaymentAcquirerCommon):
|
|||
def test_30_ogone_s2s(self):
|
||||
test_ref = 'test_ref_%.15f' % time.time()
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
# be sure not to do stupid thing
|
||||
ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None)
|
||||
self.assertEqual(ogone.env, 'test', 'test without test env')
|
||||
|
||||
# create a new draft tx
|
||||
tx_id = self.payment_transaction.create(
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<data noupdate="0">
|
||||
|
||||
<template id="ogone_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="acquirer.ogone_standard_order_url" method="post" target="_self">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<!-- seller -->
|
||||
<input type='hidden' name='PSPID' t-att-value='tx_values["PSPID"]'/>
|
||||
<input type='hidden' name='ORDERID' t-att-value='tx_values["ORDERID"]'/>
|
||||
|
@ -40,8 +40,12 @@
|
|||
<input type='hidden' name='DECLINEURL' t-att-value='tx_values["DECLINEURL"]'/>
|
||||
<input type='hidden' name='EXCEPTIONURL' t-att-value='tx_values["EXCEPTIONURL"]'/>
|
||||
<input type='hidden' name='CANCELURL' t-att-value='tx_values["CANCELURL"]'/>
|
||||
<input type="image" name="submit" id="payment_submit"
|
||||
src="/payment_acquirer_ogone/static/src/img/ogone_logo_plain.gif"/>
|
||||
<!-- 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"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
<field name="model">payment.acquirer</field>
|
||||
<field name="inherit_id" ref="payment_acquirer.acquirer_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//group[@name="acquirer_base"]' position='after'>
|
||||
<group string="Ogone Details"
|
||||
attrs="{'invisible': [('name', '!=', 'ogone')]}">
|
||||
<xpath expr='//group[@name="acquirer_display"]' position='after'>
|
||||
<group attrs="{'invisible': [('name', '!=', 'ogone')]}">
|
||||
<field name="ogone_pspid"/>
|
||||
<field name="ogone_userid"/>
|
||||
<field name="ogone_password"/>
|
||||
|
@ -29,8 +28,10 @@
|
|||
<page string="Ogone TX Details">
|
||||
<group>
|
||||
<field name="ogone_payid"/>
|
||||
<!-- <field name="ogone_3ds"/>
|
||||
<field name="ogone_3ds_html"/> -->
|
||||
<field name="ogone_3ds"/>
|
||||
<field name="ogone_3ds_html"/>
|
||||
<field name="ogone_complus"/>
|
||||
<field name="ogone_payid"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
import logging
|
||||
import pprint
|
||||
import requests
|
||||
from urllib import urlencode
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -21,6 +21,14 @@ class PaypalController(http.Controller):
|
|||
_return_url = '/payment/paypal/dpn/'
|
||||
_cancel_url = '/payment/paypal/cancel/'
|
||||
|
||||
def _get_return_url(self, **post):
|
||||
""" Extract the return URL from the data coming from paypal. """
|
||||
return_url = post.pop('return_url', '')
|
||||
if not return_url:
|
||||
custom = json.loads(post.pop('custom', '{}'))
|
||||
return_url = custom.get('return_url', '/')
|
||||
return return_url
|
||||
|
||||
def paypal_validate_data(self, **post):
|
||||
""" Paypal IPN: three steps validation to ensure data correctness
|
||||
|
||||
|
@ -32,14 +40,15 @@ class PaypalController(http.Controller):
|
|||
|
||||
Once data is validated, process it. """
|
||||
res = False
|
||||
paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
|
||||
post_url = '%s?cmd=_notify-validate&%s' % (paypal_url, urlencode(post))
|
||||
resp = requests.post(post_url)
|
||||
if resp.text == 'VERIFIED':
|
||||
new_post = dict(post, cmd='_notify-validate')
|
||||
urequest = urllib2.Request("https://www.sandbox.paypal.com/cgi-bin/webscr", urllib.urlencode(new_post))
|
||||
uopen = urllib2.urlopen(urequest)
|
||||
resp = uopen.read()
|
||||
if resp == 'VERIFIED':
|
||||
_logger.info('Paypal: validated data')
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
res = request.registry['payment.transaction'].form_feedback(cr, uid, post, 'paypal', context=context)
|
||||
elif resp.text == 'INVALID':
|
||||
elif resp == 'INVALID':
|
||||
_logger.warning('Paypal: answered INVALID on data verification')
|
||||
else:
|
||||
_logger.warning('Paypal: unrecognized paypal answer, received %s instead of VERIFIED or INVALID' % resp.text)
|
||||
|
@ -47,7 +56,7 @@ class PaypalController(http.Controller):
|
|||
|
||||
@website.route([
|
||||
'/payment/paypal/ipn/',
|
||||
], type='http', auth='public')
|
||||
], type='http', auth='public', methods=['POST'])
|
||||
def paypal_ipn(self, **post):
|
||||
""" Paypal IPN. """
|
||||
_logger.info('Beginning Paypal IPN form_feedback with post data %s', pprint.pformat(post)) # debug
|
||||
|
@ -56,14 +65,11 @@ class PaypalController(http.Controller):
|
|||
|
||||
@website.route([
|
||||
'/payment/paypal/dpn',
|
||||
], type='http', auth="public")
|
||||
], type='http', auth="public", 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 = post.pop('return_url', '')
|
||||
if not return_url:
|
||||
custom = json.loads(post.pop('custom', '{}'))
|
||||
return_url = custom.pop('return_url', '/')
|
||||
return_url = self._get_return_url(**post)
|
||||
self.paypal_validate_data(**post)
|
||||
return request.redirect(return_url)
|
||||
|
||||
|
@ -71,11 +77,8 @@ class PaypalController(http.Controller):
|
|||
'/payment/paypal/cancel',
|
||||
], type='http', auth="public")
|
||||
def paypal_cancel(self, **post):
|
||||
""" TODO
|
||||
"""
|
||||
""" When the user cancels its Paypal payment: GET on this route """
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
print 'Entering paypal_cancel with post', post
|
||||
|
||||
return_url = post.pop('return_url', '/')
|
||||
print 'return_url', return_url
|
||||
_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)
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
<field name="name">paypal</field>
|
||||
<field name="view_template_id" ref="paypal_acquirer_button"/>
|
||||
<field name="env">test</field>
|
||||
<field name="message"><![CDATA[
|
||||
<p>You will be redirected to the Paypal website after cliking on the payment button.</p>]]></field>
|
||||
<field name="paypal_tx_url">https://www.sandbox.paypal.com/cgi-bin/webscr</field>
|
||||
<field name="paypal_email_id">dummy</field>
|
||||
<field name="paypal_username">dummy</field>
|
||||
<field name="paypal_seller_id">dummy</field>
|
||||
<field name="paypal_api_username">dummy</field>
|
||||
<field name="paypal_api_password">dummy</field>
|
||||
</record>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
from openerp.addons.payment_acquirer.models import payment_acquirer
|
||||
from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
|
||||
from openerp.addons.payment_acquirer_paypal.controllers.main import PaypalController
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools.float_utils import float_compare
|
||||
|
||||
import base64
|
||||
try:
|
||||
import simplejson as json
|
||||
|
@ -16,16 +10,33 @@ 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.osv import osv, fields
|
||||
from openerp.tools.float_utils import float_compare
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AcquirerPaypal(osv.Model):
|
||||
_inherit = 'payment.acquirer'
|
||||
|
||||
def _get_paypal_urls(self, cr, uid, env, context=None):
|
||||
""" 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',
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'paypal_form_url': 'https://www.sandbox.paypal.com/cgi-bin/webscr',
|
||||
'paypal_rest_url': 'https://api.sandbox.paypal.com/v1/oauth2/token',
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'paypal_email_id': fields.char('Email ID', required_if_provider='paypal'),
|
||||
'paypal_username': fields.char('Username', required_if_provider='paypal'),
|
||||
'paypal_tx_url': fields.char('Transaction URL', required_if_provider='paypal'),
|
||||
'paypal_seller_id': fields.char('Seller ID', required_if_provider='paypal'),
|
||||
'paypal_use_ipn': fields.boolean('Use IPN'),
|
||||
# Server 2 server
|
||||
'paypal_api_enabled': fields.boolean('Use Rest API'),
|
||||
|
@ -36,7 +47,6 @@ class AcquirerPaypal(osv.Model):
|
|||
}
|
||||
|
||||
_defaults = {
|
||||
'paypal_tx_url': 'https://www.sandbox.paypal.com/cgi-bin/webscr',
|
||||
'paypal_use_ipn': True,
|
||||
'fees_active': False,
|
||||
'fees_dom_fixed': 0.35,
|
||||
|
@ -65,44 +75,38 @@ class AcquirerPaypal(osv.Model):
|
|||
fees = amount * (1 + acquirer.fees_int_var / 100.0) + acquirer.fees_int_fixed - amount
|
||||
return fees
|
||||
|
||||
def paypal_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
|
||||
if partner_values is None:
|
||||
partner_values = {}
|
||||
def paypal_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
|
||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
partner = None
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
|
||||
|
||||
tx_values = {
|
||||
paypal_tx_values = dict(tx_values)
|
||||
paypal_tx_values.update({
|
||||
'cmd': '_xclick',
|
||||
'business': acquirer.paypal_email_id,
|
||||
'item_name': reference,
|
||||
'item_number': reference,
|
||||
'amount': amount,
|
||||
'currency_code': currency and currency.name or 'EUR',
|
||||
'address1': payment_acquirer._partner_format_address(partner and partner.street or partner_values.get('street', ''), partner and partner.street2 or partner_values.get('street2', '')),
|
||||
'city': partner and partner.city or partner_values.get('city', ''),
|
||||
'country': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
|
||||
'email': partner and partner.email or partner_values.get('email', ''),
|
||||
'zip': partner and partner.zip or partner_values.get('zip', ''),
|
||||
'first_name': payment_acquirer._partner_split_name(partner and partner.name or partner_values.get('name', ''))[0],
|
||||
'last_name': payment_acquirer._partner_split_name(partner and partner.name or partner_values.get('name', ''))[1],
|
||||
'item_name': tx_values['reference'],
|
||||
'item_number': tx_values['reference'],
|
||||
'amount': tx_values['amount'],
|
||||
'currency_code': tx_values['currency'] and tx_values['currency'].name or '',
|
||||
'address1': partner_values['address'],
|
||||
'city': partner_values['city'],
|
||||
'country': partner_values['country'] and partner_values['country'].name or '',
|
||||
'email': partner_values['email'],
|
||||
'zip': partner_values['zip'],
|
||||
'first_name': partner_values['first_name'],
|
||||
'last_name': partner_values['last_name'],
|
||||
'return': '%s' % urlparse.urljoin(base_url, PaypalController._return_url),
|
||||
'notify_url': '%s' % urlparse.urljoin(base_url, PaypalController._notify_url),
|
||||
'cancel_return': '%s' % urlparse.urljoin(base_url, PaypalController._cancel_url),
|
||||
}
|
||||
})
|
||||
if acquirer.fees_active:
|
||||
tx_values['handling'] = '%.2f' % tx_custom_values.pop('fees', 0.0)
|
||||
if tx_custom_values and tx_custom_values.get('return_url'):
|
||||
tx_values['custom'] = json.dumps({'return_url': '%s' % tx_custom_values.pop('return_url')})
|
||||
if tx_custom_values:
|
||||
tx_values.update(tx_custom_values)
|
||||
return tx_values
|
||||
paypal_tx_values['handling'] = '%.2f' % paypal_tx_values.pop('fees', 0.0)
|
||||
if paypal_tx_values.get('return_url'):
|
||||
paypal_tx_values['custom'] = json.dumps({'return_url': '%s' % paypal_tx_values.pop('return_url')})
|
||||
return partner_values, paypal_tx_values
|
||||
|
||||
def paypal_get_form_action_url(self, cr, uid, id, context=None):
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
return acquirer.paypal_tx_url
|
||||
return self._get_paypal_urls(cr, uid, acquirer.env, context=context)['paypal_form_url']
|
||||
|
||||
def _paypal_s2s_get_access_token(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
|
@ -144,28 +148,6 @@ class TxPaypal(osv.Model):
|
|||
# FORM RELATED METHODS
|
||||
# --------------------------------------------------
|
||||
|
||||
def paypal_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
|
||||
tx_data = {
|
||||
'item_name': tx.name,
|
||||
'first_name': payment_acquirer._partner_split_name(tx.partner_name)[0],
|
||||
'last_name': payment_acquirer._partner_split_name(tx.partner_name)[0],
|
||||
'email': tx.partner_email,
|
||||
'zip': tx.partner_zip,
|
||||
'address1': tx.partner_address,
|
||||
'city': tx.partner_city,
|
||||
'country': tx.partner_country_id and tx.partner_country_id.name or '',
|
||||
}
|
||||
if tx_custom_values:
|
||||
tx_data.update(tx_custom_values)
|
||||
return self.pool['payment.acquirer'].paypal_form_generate_values(
|
||||
cr, uid, tx.acquirer_id.id,
|
||||
tx.reference, tx.amount, tx.currency_id,
|
||||
tx_custom_values=tx_data,
|
||||
context=context
|
||||
)
|
||||
|
||||
def _paypal_form_get_tx_from_data(self, cr, uid, data, context=None):
|
||||
reference, txn_id = data.get('item_number'), data.get('txn_id')
|
||||
if not reference or not txn_id:
|
||||
|
@ -186,9 +168,8 @@ class TxPaypal(osv.Model):
|
|||
return self.browse(cr, uid, tx_ids[0], context=context)
|
||||
|
||||
def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
|
||||
# TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details
|
||||
invalid_parameters = []
|
||||
if data.get('notify_version')[0] != '2.6':
|
||||
if data.get('notify_version')[0] != '3.4':
|
||||
_logger.warning(
|
||||
'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' %
|
||||
data.get('notify_version')
|
||||
|
@ -197,60 +178,48 @@ class TxPaypal(osv.Model):
|
|||
_logger.warning(
|
||||
'Received a notification from Paypal using sandbox'
|
||||
),
|
||||
|
||||
# TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details
|
||||
if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference:
|
||||
invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference))
|
||||
# check what is buyed
|
||||
if float_compare(float(data.get('mc_gross', '0.0')), tx.amount, 2) != 0:
|
||||
invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount))
|
||||
if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0:
|
||||
invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees
|
||||
if data.get('mc_currency') != tx.currency_id.name:
|
||||
invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name))
|
||||
# if parameters.get('payment_fee') != tx.payment_fee:
|
||||
# invalid_parameters.append(('payment_fee', tx.payment_fee))
|
||||
# if parameters.get('quantity') != tx.quantity:
|
||||
# invalid_parameters.append(('mc_currency', tx.quantity))
|
||||
# if parameters.get('shipping') != tx.shipping:
|
||||
# invalid_parameters.append(('shipping', tx.shipping))
|
||||
invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name))
|
||||
if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0:
|
||||
invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees))
|
||||
# check buyer
|
||||
# if parameters.get('payer_id') != tx.payer_id:
|
||||
# invalid_parameters.append(('mc_gross', tx.payer_id))
|
||||
# if parameters.get('payer_email') != tx.payer_email:
|
||||
# invalid_parameters.append(('payer_email', tx.payer_email))
|
||||
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 parameters.get('receiver_email') != tx.receiver_email:
|
||||
# invalid_parameters.append(('receiver_email', tx.receiver_email))
|
||||
# if parameters.get('receiver_id') != tx.receiver_id:
|
||||
# invalid_parameters.append(('receiver_id', tx.receiver_id))
|
||||
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))
|
||||
|
||||
return invalid_parameters
|
||||
|
||||
def _paypal_form_validate(self, cr, uid, tx, data, context=None):
|
||||
status = data.get('payment_status')
|
||||
data = {
|
||||
'acquirer_reference': data.get('txn_id'),
|
||||
'paypal_txn_type': data.get('payment_type'),
|
||||
'partner_reference': data.get('payer_id')
|
||||
}
|
||||
if status in ['Completed', 'Processed']:
|
||||
_logger.info('Validated Paypal payment for tx %s: set as done' % (tx.reference))
|
||||
tx.write({
|
||||
'state': 'done',
|
||||
'date_validate': data.get('payment_date', fields.datetime.now()),
|
||||
'paypal_txn_id': data['txn_id'],
|
||||
'paypal_txn_type': data.get('express_checkout'),
|
||||
})
|
||||
return True
|
||||
data.update(state='done', date_validate=data.get('payment_date', fields.datetime.now()))
|
||||
return tx.write(data)
|
||||
elif status in ['Pending', 'Expired']:
|
||||
_logger.info('Received notification for Paypal payment %s: set as pending' % (tx.reference))
|
||||
tx.write({
|
||||
'state': 'pending',
|
||||
'state_message': data.get('pending_reason', ''),
|
||||
'paypal_txn_id': data['txn_id'],
|
||||
'paypal_txn_type': data.get('express_checkout'),
|
||||
})
|
||||
return True
|
||||
data.udpate(state='pending', state_message=data.get('pending_reason', ''))
|
||||
return tx.write(data)
|
||||
else:
|
||||
error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (tx.reference, status)
|
||||
_logger.info(error)
|
||||
tx.write({
|
||||
'state': 'error',
|
||||
'state_message': error,
|
||||
'paypal_txn_id': data['txn_id'],
|
||||
'paypal_txn_type': data.get('express_checkout'),
|
||||
})
|
||||
return False
|
||||
data.update(state='error', state_message=error)
|
||||
return tx.write(data)
|
||||
|
||||
# --------------------------------------------------
|
||||
# SERVER2SERVER RELATED METHODS
|
||||
|
|
After Width: | Height: | Size: 7.1 KiB |
|
@ -15,22 +15,10 @@ class PaypalCommon(PaymentAcquirerCommon):
|
|||
def setUp(self):
|
||||
super(PaypalCommon, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
model, self.paypal_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_paypal', 'paypal_acquirer_button')
|
||||
|
||||
# create a new ogone account
|
||||
self.paypal_id = self.payment_acquirer.create(
|
||||
cr, uid, {
|
||||
'name': 'paypal',
|
||||
'env': 'test',
|
||||
'view_template_id': self.paypal_view_id,
|
||||
'paypal_email_id': 'dummy',
|
||||
'paypal_username': 'dummy',
|
||||
'paypal_api_enabled': True,
|
||||
'paypal_api_username': 'dummy',
|
||||
'paypal_api_password': 'dummy',
|
||||
})
|
||||
# get the paypal account
|
||||
model, self.paypal_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_paypal', 'payment_acquirer_paypal')
|
||||
# tde+seller@openerp.com - tde+buyer@openerp.com - tde+buyer-it@openerp.com
|
||||
|
||||
# some CC
|
||||
|
@ -50,6 +38,9 @@ class PaypalServer2Server(PaypalCommon):
|
|||
|
||||
def test_00_tx_management(self):
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
# be sure not to do stupid things
|
||||
paypal = self.payment_acquirer.browse(self.cr, self.uid, self.paypal_id, None)
|
||||
self.assertEqual(paypal.env, 'test', 'test without test env')
|
||||
|
||||
res = self.payment_acquirer._paypal_s2s_get_access_token(cr, uid, [self.paypal_id], context=context)
|
||||
self.assertTrue(res[self.paypal_id] is not False, 'paypal: did not generate access token')
|
||||
|
@ -78,24 +69,10 @@ class PaypalServer2Server(PaypalCommon):
|
|||
|
||||
class PaypalForm(PaypalCommon):
|
||||
|
||||
def test_00_paypal_acquirer(self):
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
# forgot some mandatory fields: should crash
|
||||
with self.assertRaises(except_orm):
|
||||
self.payment_acquirer.create(
|
||||
cr, uid, {
|
||||
'name': 'paypal',
|
||||
'env': 'test',
|
||||
'view_template_id': self.paypal_view_id,
|
||||
'paypal_email_id': 'tde+paypal-facilitator@openerp.com',
|
||||
}, context=context)
|
||||
|
||||
paypal = self.payment_acquirer.browse(self.cr, self.uid, self.paypal_id, None)
|
||||
self.assertEqual(paypal.env, 'test', 'test without test env')
|
||||
|
||||
def test_10_paypal_form_render(self):
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
# be sure not to do stupid things
|
||||
self.payment_acquirer.write(cr, uid, self.paypal_id, {'fees_active': False}, context)
|
||||
paypal = self.payment_acquirer.browse(cr, uid, self.paypal_id, context)
|
||||
self.assertEqual(paypal.env, 'test', 'test without test env')
|
||||
|
||||
|
@ -103,6 +80,14 @@ class PaypalForm(PaypalCommon):
|
|||
# Test: button direct rendering
|
||||
# ----------------------------------------
|
||||
|
||||
# render the button
|
||||
res = self.payment_acquirer.render(
|
||||
cr, uid, self.paypal_id,
|
||||
'test_ref0', 0.01, self.currency_euro_id,
|
||||
partner_id=None,
|
||||
partner_values=self.buyer_values,
|
||||
context=context)
|
||||
|
||||
form_values = {
|
||||
'cmd': '_xclick',
|
||||
'business': 'tde+paypal-facilitator@openerp.com',
|
||||
|
@ -122,14 +107,6 @@ class PaypalForm(PaypalCommon):
|
|||
'cancel_return': '%s' % urlparse.urljoin(self.base_url, PaypalController._cancel_url),
|
||||
}
|
||||
|
||||
# render the button
|
||||
res = self.payment_acquirer.render(
|
||||
cr, uid, self.paypal_id,
|
||||
'test_ref0', 0.01, self.currency_euro,
|
||||
partner_id=None,
|
||||
partner_values=self.buyer_values,
|
||||
context=context)
|
||||
|
||||
# check form result
|
||||
tree = objectify.fromstring(res)
|
||||
self.assertEqual(tree.get('action'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url')
|
||||
|
@ -139,19 +116,24 @@ class PaypalForm(PaypalCommon):
|
|||
self.assertEqual(
|
||||
form_input.get('value'),
|
||||
form_values[form_input.get('name')],
|
||||
'paypal: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')])
|
||||
'paypal: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
|
||||
)
|
||||
|
||||
def test_11_paypal_form_with_fees(self):
|
||||
cr, uid, context = self.cr, self.uid, {}
|
||||
self.payment_acquirer.write(cr, uid, self.paypal_id, {
|
||||
'fees_active': True,
|
||||
}, context)
|
||||
|
||||
# be sure not to do stupid things
|
||||
paypal = self.payment_acquirer.browse(self.cr, self.uid, self.paypal_id, None)
|
||||
self.assertEqual(paypal.env, 'test', 'test without test env')
|
||||
|
||||
# update acquirer: compute fees
|
||||
self.payment_acquirer.write(cr, uid, self.paypal_id, {
|
||||
'fees_active': True,
|
||||
'fees_dom_fixed': 1.0,
|
||||
'fees_dom_var': 0.35,
|
||||
'fees_int_fixed': 1.5,
|
||||
'fees_int_var': 0.50,
|
||||
}, context)
|
||||
|
||||
# render the button
|
||||
res = self.payment_acquirer.render(
|
||||
cr, uid, self.paypal_id,
|
||||
|
@ -167,7 +149,7 @@ class PaypalForm(PaypalCommon):
|
|||
for form_input in tree.input:
|
||||
if form_input.get('name') in ['handling']:
|
||||
handling_found = True
|
||||
self.assertEqual(form_input.get('value'), '0.84', 'paypal: wrong computed fees')
|
||||
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')
|
||||
|
@ -233,6 +215,7 @@ class PaypalForm(PaypalCommon):
|
|||
'currency_id': self.currency_euro_id,
|
||||
'reference': 'test_ref_2',
|
||||
'partner_name': 'Norbert Buyer',
|
||||
'partner_country_id': self.country_france_id,
|
||||
}, context=context
|
||||
)
|
||||
# validate it
|
||||
|
|
|
@ -10,14 +10,16 @@
|
|||
<xpath expr='//group[@name="acquirer_display"]' position='after'>
|
||||
<group attrs="{'invisible': [('name', '!=', 'paypal')]}">
|
||||
<group>
|
||||
<field name="paypal_email_id"/>
|
||||
<field name="paypal_username"/>
|
||||
<field name="paypal_use_ipn"/>
|
||||
<field name="paypal_api_enabled"/>
|
||||
<field name="paypal_api_username"
|
||||
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
|
||||
<field name="paypal_api_password"
|
||||
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
|
||||
<group>
|
||||
<field name="paypal_email_id"/>
|
||||
<field name="paypal_seller_id"/>
|
||||
<field name="paypal_use_ipn"/>
|
||||
<field name="paypal_api_enabled"/>
|
||||
<field name="paypal_api_username"
|
||||
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
|
||||
<field name="paypal_api_password"
|
||||
attrs="{'invisible': [('paypal_api_enabled', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
|
|
|
@ -3,16 +3,14 @@
|
|||
<data noupdate="0">
|
||||
|
||||
<template id="paypal_acquirer_button">
|
||||
<form t-if="acquirer.paypal_email_id" t-att-action="acquirer.paypal_tx_url" method="post" target="_self">
|
||||
<form t-if="acquirer.paypal_email_id" 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']"/>
|
||||
<input type="hidden" name="item_number" t-att-value="tx_values['item_number']"/>
|
||||
<input type="hidden" name="amount" t-att-value="tx_values['amount']"/>
|
||||
<t t-if="'handling' in tx_values">
|
||||
<input type="hidden" name="handling" t-att-value="tx_values['handling']"/>
|
||||
</t>
|
||||
<input type="hidden" name="amount" t-att-value="tx_values['amount']"/>
|
||||
<input t-if="'handling' in tx_values" type="hidden" name="handling"
|
||||
t-att-value="tx_values.get('handling')"/>
|
||||
<input type="hidden" name="currency_code" t-att-value="tx_values['currency_code']"/>
|
||||
<!-- partner / address data -->
|
||||
<input type="hidden" name="address1" t-att-value="tx_values['address1']"/>
|
||||
|
@ -23,20 +21,21 @@
|
|||
<input type="hidden" name="last_name" t-att-value="tx_values['last_name']"/>
|
||||
<input type="hidden" name="zip" t-att-value="tx_values['zip']"/>
|
||||
<!-- after payment parameters -->
|
||||
<t t-if='tx_values.get("custom")'>
|
||||
<input type='hidden' name="custom" t-att-value='tx_values["custom"]'/>
|
||||
</t>
|
||||
<input t-if='tx_values.get("custom")' type='hidden' name="custom"
|
||||
t-att-value='tx_values.get("custom")'/>
|
||||
<!-- URLs -->
|
||||
<input t-if="tx_values.get('return')" type='hidden' name='return'
|
||||
t-att-value="tx_values['return']"/>
|
||||
t-att-value="tx_values.get('return')"/>
|
||||
<input t-if="acquirer.paypal_use_ipn" type='hidden' name='notify_url'
|
||||
t-att-value="tx_values['notify_url']"/>
|
||||
t-att-value="tx_values.get('notify_url')"/>
|
||||
<input t-if="tx_values.get('cancel_return')" type="hidden" name="cancel_return"
|
||||
t-att-value="tx_values['cancel_return']"/>
|
||||
<!-- button -->
|
||||
<input type="image" name="submit" id="payment_submit"
|
||||
width="100px"
|
||||
src="/payment_acquirer_paypal/static/src/img/paypal_logo.png"/>
|
||||
t-att-value="tx_values.get('cancel_return')"/>
|
||||
<!-- 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"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_acquirer_transfer" model="payment.acquirer">
|
||||
<field name="name">transfer</field>
|
||||
|
|
After Width: | Height: | Size: 14 KiB |
|
@ -3,16 +3,19 @@
|
|||
<data noupdate="0">
|
||||
|
||||
<template id="transfer_acquirer_button">
|
||||
<div t-field="acquirer.message"/>
|
||||
<form t-if="acquirer" action="/payment/transfer/feedback" method="post" target="_self">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<t t-if="tx_values.get('return_url')">
|
||||
<input type='hidden' name='return_url' t-att-value='tx_values["return_url"]'/>
|
||||
</t>
|
||||
<input type='hidden' name='reference' t-att-value='reference'/>
|
||||
<input type='hidden' name='amount' t-att-value='amount'/>
|
||||
<input type='hidden' name='currency' t-att-value='currency.name'/>
|
||||
<input type="submit" name="submit" id="payment_submit"
|
||||
class="btn btn-primary" value="Confirmer"/>
|
||||
<!-- 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"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
if request.context['editable']:
|
||||
page = 'website.page_404'
|
||||
else:
|
||||
return request.registry['ir.http']._handle_404(e)
|
||||
return request.registry['ir.http']._handle_exception(e, 404)
|
||||
return request.website.render(page, values)
|
||||
|
||||
@website.route('/website/customize_template_toggle', type='json', auth='user')
|
||||
|
|
|
@ -61,7 +61,7 @@ class ir_http(orm.AbstractModel):
|
|||
request.lang = request.context['lang'] = path.pop(1)
|
||||
path = '/'.join(path) or '/'
|
||||
return self.reroute(path)
|
||||
return self._handle_404()
|
||||
return self._handle_exception(code=404)
|
||||
return super(ir_http, self)._dispatch()
|
||||
|
||||
def reroute(self, path):
|
||||
|
@ -79,37 +79,44 @@ class ir_http(orm.AbstractModel):
|
|||
|
||||
return self._dispatch()
|
||||
|
||||
def _handle_403(self, exception):
|
||||
def _handle_exception(self, exception=None, code=500):
|
||||
if isinstance(exception, werkzeug.exceptions.HTTPException) and exception.response:
|
||||
return exception.response
|
||||
if getattr(request, 'cms', False) and request.website:
|
||||
logger.warn("403 Forbidden:\n\n%s", traceback.format_exc(exception))
|
||||
self._auth_method_public()
|
||||
return self._render_error(403, {
|
||||
'error': exception.message
|
||||
})
|
||||
raise exception
|
||||
values = dict(
|
||||
exception=exception,
|
||||
traceback=traceback.format_exc(exception),
|
||||
)
|
||||
if exception:
|
||||
if isinstance(exception, openerp.exceptions.AccessError):
|
||||
code = 403
|
||||
else:
|
||||
code = getattr(exception, 'code', code)
|
||||
values.update(
|
||||
qweb_template=getattr(exception, 'qweb_template', None),
|
||||
qweb_node=getattr(exception, 'qweb_node', None),
|
||||
qweb_eval=getattr(exception, 'qweb_eval', None),
|
||||
)
|
||||
if code == 500:
|
||||
logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
|
||||
elif code == 403:
|
||||
logger.warn("403 Forbidden:\n\n%s", values['traceback'])
|
||||
|
||||
def _handle_404(self, exception=None):
|
||||
if getattr(request, 'cms', False) and request.website:
|
||||
return self._render_error(404)
|
||||
raise request.not_found()
|
||||
values.update(
|
||||
status_message=werkzeug.http.HTTP_STATUS_CODES[code],
|
||||
status_code=code,
|
||||
)
|
||||
|
||||
def _handle_500(self, exception):
|
||||
if getattr(request, 'cms', False) and request.website:
|
||||
logger.error("500 Internal Server Error:\n\n%s", traceback.format_exc(exception))
|
||||
return self._render_error(500, {
|
||||
'exception': exception,
|
||||
'traceback': traceback.format_exc(),
|
||||
'qweb_template': getattr(exception, 'qweb_template', None),
|
||||
'qweb_node': getattr(exception, 'qweb_node', None),
|
||||
'qweb_eval': getattr(exception, 'qweb_eval', None),
|
||||
})
|
||||
raise exception
|
||||
if not request.uid:
|
||||
self._auth_method_public()
|
||||
|
||||
def _render_error(self, code, values=None):
|
||||
return werkzeug.wrappers.Response(
|
||||
request.website._render('website.%s' % code, values),
|
||||
status=code,
|
||||
content_type='text/html;charset=utf-8')
|
||||
try:
|
||||
html = request.website._render('website.%s' % code, values)
|
||||
except:
|
||||
html = request.website._render('website.http_error', values)
|
||||
return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
|
||||
|
||||
return super(ir_http, self)._handle_exception(exception)
|
||||
|
||||
class ModelConverter(ir.ir_http.ModelConverter):
|
||||
def __init__(self, url_map, model=False):
|
||||
|
|
|
@ -121,33 +121,49 @@ class Date(orm.AbstractModel):
|
|||
_name = 'website.qweb.field.date'
|
||||
_inherit = ['website.qweb.field', 'ir.qweb.field.date']
|
||||
|
||||
def attributes(self, cr, uid, field_name, record, options,
|
||||
source_element, g_att, t_att, qweb_context,
|
||||
context=None):
|
||||
attrs = super(Date, self).attributes(
|
||||
cr, uid, field_name, record, options, source_element, g_att, t_att,
|
||||
qweb_context, context=None)
|
||||
return itertools.chain(attrs, [('data-oe-original', record[field_name])])
|
||||
|
||||
def from_html(self, cr, uid, model, column, element, context=None):
|
||||
lang = self.user_lang(cr, uid, context=context)
|
||||
in_format = lang.date_format.encode('utf-8')
|
||||
|
||||
value = element.text_content().strip()
|
||||
try:
|
||||
dt = datetime.datetime.strptime(in_format, value)
|
||||
except ValueError:
|
||||
dt = parse_fuzzy(in_format, value)
|
||||
if not value: return False
|
||||
|
||||
return dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
datetime.datetime.strptime(value, DEFAULT_SERVER_DATE_FORMAT)
|
||||
return value
|
||||
|
||||
class DateTime(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.datetime'
|
||||
_inherit = ['website.qweb.field', 'ir.qweb.field.datetime']
|
||||
|
||||
def attributes(self, cr, uid, field_name, record, options,
|
||||
source_element, g_att, t_att, qweb_context,
|
||||
context=None):
|
||||
column = record._model._all_columns[field_name].column
|
||||
value = record[field_name]
|
||||
if isinstance(value, basestring):
|
||||
value = datetime.datetime.strptime(
|
||||
value, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
value = column.context_timestamp(
|
||||
cr, uid, timestamp=value, context=context)
|
||||
|
||||
attrs = super(DateTime, self).attributes(
|
||||
cr, uid, field_name, record, options, source_element, g_att, t_att,
|
||||
qweb_context, context=None)
|
||||
return itertools.chain(attrs, [
|
||||
('data-oe-original', value.strftime(openerp.tools.DEFAULT_SERVER_DATETIME_FORMAT))
|
||||
])
|
||||
|
||||
def from_html(self, cr, uid, model, column, element, context=None):
|
||||
lang = self.user_lang(cr, uid, context=context)
|
||||
in_format = (u"%s %s" % (lang.date_format, lang.time_format)).encode('utf-8')
|
||||
|
||||
value = element.text_content().strip()
|
||||
try:
|
||||
dt = datetime.datetime.strptime(in_format, value)
|
||||
except ValueError:
|
||||
dt = parse_fuzzy(in_format, value)
|
||||
if not value: return False
|
||||
|
||||
return dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
datetime.datetime.strptime(value, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
return value
|
||||
|
||||
class Text(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.text'
|
||||
|
@ -302,3 +318,34 @@ class Monetary(orm.AbstractModel):
|
|||
|
||||
return float(value.replace(lang.thousands_sep, '')
|
||||
.replace(lang.decimal_point, '.'))
|
||||
|
||||
class Duration(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.duration'
|
||||
_inherit = [
|
||||
'ir.qweb.field.duration',
|
||||
'website.qweb.field.float',
|
||||
]
|
||||
|
||||
def attributes(self, cr, uid, field_name, record, options,
|
||||
source_element, g_att, t_att, qweb_context,
|
||||
context=None):
|
||||
attrs = super(Duration, self).attributes(
|
||||
cr, uid, field_name, record, options, source_element, g_att, t_att,
|
||||
qweb_context, context=None)
|
||||
return itertools.chain(attrs, [('data-oe-original', record[field_name])])
|
||||
|
||||
def from_html(self, cr, uid, model, column, element, context=None):
|
||||
value = element.text_content().strip()
|
||||
|
||||
# non-localized value
|
||||
return float(value)
|
||||
|
||||
|
||||
class RelativeDatetime(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.relative'
|
||||
_inherit = [
|
||||
'ir.qweb.field.relative',
|
||||
'website.qweb.field.datetime',
|
||||
]
|
||||
|
||||
# get formatting from ir.qweb.field.relative but edition/save from datetime
|
||||
|
|
|
@ -80,6 +80,23 @@ def urlplus(url, params):
|
|||
def quote_plus(value):
|
||||
return urllib.quote_plus(value.encode('utf-8') if isinstance(value, unicode) else str(value))
|
||||
|
||||
def preload_records(*args, **kwargs):
|
||||
""" This helper allows to check the existence and prefetch one or many browse_records at once.
|
||||
If the browse record(s) does not exists in the db it will raise a LazyResponse
|
||||
"""
|
||||
field = kwargs.pop('field', 'name')
|
||||
on_error = kwargs.pop('on_error', 'website.404')
|
||||
error_code = kwargs.pop('error_code', 404)
|
||||
try:
|
||||
for arg in args:
|
||||
if isinstance(arg, orm.browse_record):
|
||||
arg[field]
|
||||
elif isinstance(arg, orm.browse_record_list):
|
||||
[record[field] for record in arg]
|
||||
except:
|
||||
lazy_error = request.website.render(on_error, status_code=error_code)
|
||||
raise werkzeug.exceptions.HTTPException(response=lazy_error)
|
||||
|
||||
class website(osv.osv):
|
||||
def _get_menu_website(self, cr, uid, ids, context=None):
|
||||
# IF a menu is changed, update all websites
|
||||
|
|
|
@ -206,10 +206,6 @@ ul.oe_menu_editor .disclose {
|
|||
position: static !important;
|
||||
}
|
||||
|
||||
.cke_widget_drag_handler_container {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cke_widget_editable:empty:after {
|
||||
content: " ";
|
||||
white-space: pre-wrap;
|
||||
|
|
|
@ -168,9 +168,6 @@ ul.oe_menu_editor
|
|||
// Breaks completely horribly crazy products listing page, so take it out.
|
||||
.cke_widget_wrapper
|
||||
position: static !important
|
||||
// "remove" drag & drop of CKE widgets
|
||||
.cke_widget_drag_handler_container
|
||||
display: none !important
|
||||
// prevent inline widgets from entirely disappearing when their (textual)
|
||||
// content is removed
|
||||
.cke_widget_editable:empty:after
|
||||
|
|
|
@ -323,14 +323,26 @@
|
|||
init: function (editor) {
|
||||
editor.widgets.add('oeref', {
|
||||
editables: { text: '*' },
|
||||
draggable: false,
|
||||
|
||||
upcast: function (el) {
|
||||
return el.attributes['data-oe-type']
|
||||
&& el.attributes['data-oe-type'] !== 'monetary';
|
||||
var matches = el.attributes['data-oe-type'] && el.attributes['data-oe-type'] !== 'monetary';
|
||||
if (!matches) { return false; }
|
||||
|
||||
if (el.attributes['data-oe-original']) {
|
||||
while (el.children.length) {
|
||||
el.children[0].remove();
|
||||
}
|
||||
el.add(new CKEDITOR.htmlParser.text(
|
||||
el.attributes['data-oe-original']
|
||||
));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
editor.widgets.add('monetary', {
|
||||
editables: { text: 'span.oe_currency_value' },
|
||||
draggable: false,
|
||||
|
||||
upcast: function (el) {
|
||||
return el.attributes['data-oe-type'] === 'monetary';
|
||||
|
|
|
@ -404,6 +404,74 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<template id="http_error">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="oe_structure">
|
||||
<h1 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h1>
|
||||
</div>
|
||||
|
||||
<t t-if="editable or request.debug">
|
||||
<t t-call="website.http_error_debug"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="http_error_debug">
|
||||
<div class="container panel-group mb32 mt32" id="debug_infos">
|
||||
<div class="panel panel-default" t-if="exception">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#debug_infos" href="#error_main">
|
||||
Error
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_main" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<p t-if="website_controller">The following error was raised in the website controller <code t-esc="website_controller"/></p>
|
||||
<p><strong>Error message:</strong> <pre t-esc="exception.message"/></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default" t-if="qweb_template">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#adebug_infos" href="#error_qweb">
|
||||
QWeb
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_qweb" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
The error occured while rendering the template <code t-esc="qweb_template"/>
|
||||
<t t-if="qweb_eval">and evaluating the following expression: <code t-esc="qweb_eval"/></t>
|
||||
</p>
|
||||
<t t-if="qweb_node">
|
||||
<pre id="exception_node" t-esc="qweb_node.toxml()"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default" t-if="traceback">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#adebug_infos" href="#error_traceback">
|
||||
Traceback
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_traceback" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<pre id="exception_traceback" t-esc="traceback"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="404">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
|
@ -423,70 +491,16 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-if="request.debug">
|
||||
<t t-call="website.http_error_debug"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="500">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="oe_structure">
|
||||
<h1 class="container mt32">500: Internal Server Error!</h1>
|
||||
</div>
|
||||
|
||||
<div class="container panel-group" id="debug_infos" t-if="editable">
|
||||
<div class="panel panel-default" t-if="exception">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#debug_infos" href="#error_main">
|
||||
Error
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_main" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<p t-if="website_controller">The following error was raised in the website controller <code t-esc="website_controller"/></p>
|
||||
<p><strong>Error message:</strong> <t t-esc="exception.message"/></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default" t-if="qweb_template">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#adebug_infos" href="#error_qweb">
|
||||
QWeb
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_qweb" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
The error occured while rendering the template <code t-esc="qweb_template"/>
|
||||
<t t-if="qweb_eval">and evaluating the following expression: <code t-esc="qweb_eval"/></t>
|
||||
</p>
|
||||
<t t-if="qweb_node">
|
||||
<pre id="exception_node" t-esc="qweb_node.toxml()"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default" t-if="traceback">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#adebug_infos" href="#error_traceback">
|
||||
Traceback
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="error_traceback" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<pre id="exception_traceback" t-esc="traceback"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-call="website.http_error"/>
|
||||
</template>
|
||||
|
||||
<template id="403">
|
||||
|
@ -498,9 +512,6 @@
|
|||
The page you were looking for could not be
|
||||
authorized.
|
||||
</p>
|
||||
<t t-if="error and editable">
|
||||
<pre t-esc="error"/>
|
||||
</t>
|
||||
<p>
|
||||
Maybe you were looking for one of these
|
||||
popular pages ?
|
||||
|
@ -510,6 +521,9 @@
|
|||
<li><a href="/page/website.contactus/">Contact Us</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<t t-if="editable or request.debug">
|
||||
<t t-call="website.http_error_debug"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
|
|
@ -97,6 +97,7 @@ class WebsiteBlog(http.Controller):
|
|||
"""
|
||||
BYPAGE = 10
|
||||
|
||||
website.preload_records(category, tag)
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
blog_post_obj = request.registry['blog.post']
|
||||
|
||||
|
@ -178,6 +179,8 @@ class WebsiteBlog(http.Controller):
|
|||
- 'nav_list': a dict [year][month] for archives navigation
|
||||
"""
|
||||
|
||||
website.preload_records(blog_post)
|
||||
|
||||
pager_url = "/blogpost/%s" % blog_post.id
|
||||
|
||||
pager = request.website.pager(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="website.secure_layout">
|
||||
<template id="secure_layout" inherit_id="website.secure_layout">
|
||||
<xpath expr="//t[@id='editable_scripts_hook']" position="inside">
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.editor.js" t-ignore="true"></script>
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website.tour.blog.js" t-ignore="true"></script>
|
||||
|
|
|
@ -14,5 +14,5 @@ OpenERP Contact Form
|
|||
'data/website_crm_data.xml',
|
||||
'views/website_crm.xml',
|
||||
],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
|
|
@ -7,14 +7,17 @@ from openerp.addons.web import http
|
|||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
|
||||
|
||||
class WebsiteCrmPartnerAssign(http.Controller):
|
||||
_references_per_page = 20
|
||||
|
||||
@website.route([
|
||||
'/partners/', '/partners/page/<int:page>/',
|
||||
'/partners/country/<int:country_id>', '/partners/country/page/<int:country_id>/',
|
||||
'/partners/',
|
||||
'/partners/page/<int:page>/',
|
||||
'/partners/country/<int:country_id>',
|
||||
'/partners/country/page/<int:country_id>/',
|
||||
], type='http', auth="public", multilang=True)
|
||||
def partners(self, country_id=0, page=0, **post):
|
||||
country_obj = request.registry['res.country']
|
||||
|
@ -24,7 +27,7 @@ class WebsiteCrmPartnerAssign(http.Controller):
|
|||
country = None
|
||||
|
||||
# format displayed membership lines domain
|
||||
base_partner_domain = [('is_company', '=', True)]
|
||||
base_partner_domain = [('is_company', '=', True), ('grade_id', '!=', False), ('website_published', '=', True)]
|
||||
partner_domain = list(base_partner_domain)
|
||||
if grade_id and grade_id != "all":
|
||||
partner_domain += [('grade_id', '=', int(grade_id))] # try/catch int
|
||||
|
@ -36,26 +39,26 @@ class WebsiteCrmPartnerAssign(http.Controller):
|
|||
|
||||
# format pager
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, request.uid, partner_domain,
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context)
|
||||
pager = request.website.pager(url="/partners/", total=len(partner_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
|
||||
|
||||
# search for partners to display
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, request.uid, partner_domain,
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context,
|
||||
limit=self._references_per_page, offset=pager['offset'],
|
||||
order="grade_id ASC,partner_weight DESC")
|
||||
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
|
||||
partners = partner_obj.browse(
|
||||
request.cr, request.uid, partner_ids, request.context)
|
||||
partners_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_ids, website_partner.white_list, context=request.context)
|
||||
|
||||
# group by country
|
||||
countries = partner_obj.read_group(
|
||||
request.cr, request.uid, base_partner_domain, ["id", "country_id"],
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
countries_partners = partner_obj.search(
|
||||
request.cr, request.uid, base_partner_domain,
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain,
|
||||
context=request.context, count=True)
|
||||
countries.insert(0, {
|
||||
'country_id_count': countries_partners,
|
||||
|
@ -64,10 +67,10 @@ class WebsiteCrmPartnerAssign(http.Controller):
|
|||
|
||||
# group by grade
|
||||
grades = partner_obj.read_group(
|
||||
request.cr, request.uid, base_partner_domain, ["id", "grade_id"],
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain, ["id", "grade_id"],
|
||||
groupby="grade_id", orderby="grade_id", context=request.context)
|
||||
grades_partners = partner_obj.search(
|
||||
request.cr, request.uid, base_partner_domain,
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain,
|
||||
context=request.context, count=True)
|
||||
grades.insert(0, {
|
||||
'grade_id_count': grades_partners,
|
||||
|
@ -80,7 +83,7 @@ class WebsiteCrmPartnerAssign(http.Controller):
|
|||
'current_country': country,
|
||||
'grades': grades,
|
||||
'grade_id': grade_id,
|
||||
'partners': partners,
|
||||
'partners_data': partners_data,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'searches': post,
|
||||
|
@ -88,16 +91,9 @@ class WebsiteCrmPartnerAssign(http.Controller):
|
|||
}
|
||||
return request.website.render("website_crm_partner_assign.index", values)
|
||||
|
||||
@website.route(['/partners/<int:partner_id>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, partner_id=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_ids = partner_obj.search(request.cr, request.uid, [('id', '=', partner_id)], context=request.context)
|
||||
if not partner_ids:
|
||||
return self.members(post)
|
||||
|
||||
values = {
|
||||
'partner_id': partner_obj.browse(
|
||||
request.cr, request.uid, partner_ids[0],
|
||||
context=dict(request.context, show_address=True)),
|
||||
}
|
||||
@website.route(['/partners/<model("res.partner"):partner>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, partner, **post):
|
||||
values = website_partner.get_partner_template_value(partner)
|
||||
if not values:
|
||||
return self.partners(**post)
|
||||
return request.website.render("website_crm_partner_assign.partner", values)
|
||||
|
|
|
@ -75,22 +75,20 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<t t-foreach="partners" t-as="partner_id">
|
||||
<t t-if="internal_gid != partner_id.grade_id.id">
|
||||
<t t-set="internal_gid" t-value="partner_id.grade_id.id"/>
|
||||
<t t-foreach="partners_data" t-as="partner_data">
|
||||
<t t-if="internal_gid != partner_data['grade_id'][1]">
|
||||
<h3 class="text-center">
|
||||
<span t-field="partner_id.grade_id"/> Partners
|
||||
<span t-esc="partner_data['grade_id'][1]"/> Partners
|
||||
<t t-if="current_country"> in <t t-esc="current_country.name"/></t>
|
||||
</h3>
|
||||
</t>
|
||||
<div class="media thumbnail">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
|
||||
<a class="pull-left" t-href="/partners/#{ partner_id.id }/">
|
||||
<img class="media-object" t-att-src="partner_id.img('image_small')"/>
|
||||
<a class="pull-left" t-href="/partners/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data['image_small']}"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-href="/partners/#{ partner_id.id }/"><span t-field="partner_id.parent_id"/> <span t-field="partner_id.name"/></a> - <span t-field="partner_id.grade_id"/>
|
||||
<div t-field="partner_id.website_short_description"/>
|
||||
<a class="media-heading" t-href="/partners/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/"><t t-if="partner_data['parent_id']"><span t-esc="partner_data['parent_id'][1]"/></t> <span t-esc="partner_data['name']"/></a> - <span t-esc="partner_data['grade_id'][1]"/>
|
||||
<div t-esc="partner_data['website_short_description']"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
|
|
@ -40,5 +40,5 @@ OpenERP Customer References
|
|||
'views/website_customer.xml',
|
||||
],
|
||||
'qweb': [],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ from openerp.addons.web import http
|
|||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
import urllib
|
||||
|
||||
|
||||
|
@ -12,10 +13,12 @@ class WebsiteCustomer(http.Controller):
|
|||
_references_per_page = 20
|
||||
|
||||
@website.route([
|
||||
'/customers/', '/customers/page/<int:page>/',
|
||||
'/customers/country/<int:country_id>', '/customers/country/<int:country_id>/page/<int:page>/'
|
||||
'/customers/',
|
||||
'/customers/page/<int:page>/',
|
||||
'/customers/country/<model("res.country"):country>',
|
||||
'/customers/country/<model("res.country"):country>/page/<int:page>/'
|
||||
], type='http', auth="public", multilang=True)
|
||||
def customers(self, country_id=None, page=0, **post):
|
||||
def customers(self, country=None, page=0, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_name = post.get('search', '')
|
||||
|
@ -28,22 +31,24 @@ class WebsiteCustomer(http.Controller):
|
|||
('name', 'ilike', "%%%s%%" % post.get("search")),
|
||||
('website_description', 'ilike', "%%%s%%" % post.get("search"))
|
||||
]
|
||||
if country_id:
|
||||
domain += [('country_id', '=', country_id)]
|
||||
country_id = None
|
||||
if country:
|
||||
domain += [('country_id', '=', country.id)]
|
||||
country_id = country.id
|
||||
|
||||
# group by country, based on all customers (base domain)
|
||||
countries = partner_obj.read_group(
|
||||
cr, uid, base_domain, ["id", "country_id"],
|
||||
cr, openerp.SUPERUSER_ID, base_domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
country_count = partner_obj.search(
|
||||
cr, uid, base_domain, count=True, context=request.context)
|
||||
cr, openerp.SUPERUSER_ID, base_domain, count=True, context=request.context)
|
||||
countries.insert(0, {
|
||||
'country_id_count': country_count,
|
||||
'country_id': (0, _("All Countries"))
|
||||
})
|
||||
|
||||
# search customers to display
|
||||
partner_ids = partner_obj.search(cr, uid, domain, context=request.context)
|
||||
partner_ids = partner_obj.search(cr, openerp.SUPERUSER_ID, domain, context=request.context)
|
||||
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
|
||||
|
||||
# pager
|
||||
|
@ -54,15 +59,14 @@ class WebsiteCustomer(http.Controller):
|
|||
|
||||
# browse page of customers to display
|
||||
partner_ids = partner_obj.search(
|
||||
cr, uid, domain,
|
||||
cr, openerp.SUPERUSER_ID, domain,
|
||||
limit=self._references_per_page, offset=pager['offset'], context=context)
|
||||
partners = partner_obj.browse(request.cr, request.uid,
|
||||
partner_ids, request.context)
|
||||
|
||||
partners_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_ids, website_partner.white_list, context=request.context)
|
||||
values = {
|
||||
'countries': countries,
|
||||
'current_country_id': country_id or 0,
|
||||
'partner_ids': partners,
|
||||
'partners_data': partners_data,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'post': post,
|
||||
|
@ -71,9 +75,23 @@ class WebsiteCustomer(http.Controller):
|
|||
return request.website.render("website_customer.index", values)
|
||||
|
||||
@website.route(['/customers/<model("res.partner"):partner>/'], type='http', auth="public", multilang=True)
|
||||
def customer(self, partner=None, **post):
|
||||
""" Route for displaying a single partner / customer. """
|
||||
values = {
|
||||
'partner': partner
|
||||
}
|
||||
def customer(self, partner, **post):
|
||||
values = website_partner.get_partner_template_value(partner, ["commercial_partner_id", "assigned_partner_id", "implemented_partner_ids"])
|
||||
if not values:
|
||||
return self.customers(**post)
|
||||
|
||||
partner_obj = request.registry['res.partner']
|
||||
if values['partner_data']['assigned_partner_id']:
|
||||
values['assigned_partner_data'] = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, [values['partner_data']['assigned_partner_id'][0]],
|
||||
website_partner.white_list, context=request.context)[0]
|
||||
if values['partner_data']['implemented_partner_ids']:
|
||||
implemented_partners_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, values['partner_data']['implemented_partner_ids'],
|
||||
website_partner.white_list, context=request.context)
|
||||
values['implemented_partners_data'] = []
|
||||
for data in implemented_partners_data:
|
||||
if data.get('website_published'):
|
||||
values['implemented_partners_data'].append(data)
|
||||
|
||||
return request.website.render("website_customer.details", values)
|
||||
|
|
|
@ -39,16 +39,16 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<t t-foreach="partner_ids" t-as="partner" class="media">
|
||||
<t t-foreach="partners_data" t-as="partner_data" class="media">
|
||||
<div class="col-md-2">
|
||||
<a t-href="/customers/#{ slug(partner) }/">
|
||||
<img class="img img-thumbnail" t-att-src="partner.img('image_medium')"/>
|
||||
<a t-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/">
|
||||
<img class="img img-thumbnail" t-attf-src="data:image/png;base64,#{partner_data.get('image')}"/>
|
||||
</a>
|
||||
</div><div class="col-md-10">
|
||||
<h4>
|
||||
<a t-href="/customers/#{ slug(partner) }/" t-field="partner.name"/>
|
||||
<a t-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/" t-esc="partner_data.get('name')"/>
|
||||
</h4>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
<div t-raw="partner_data.get('website_short_description')"/>
|
||||
</div>
|
||||
<div class="clearfix mb8"/>
|
||||
</t>
|
||||
|
@ -66,7 +66,7 @@
|
|||
<template id="opt_country" inherit_option_id="website_customer.index" name="Show Map">
|
||||
<xpath expr="//div[@id='ref_left_column']" position="inside">
|
||||
|
||||
<iframe t-attf-src="/google_map/?partner_ids=#{ google_map_partner_ids }&partner_url=/customers/&output=embed"
|
||||
<iframe t-attf-src="/google_map/?partner_ids=#{ google_map_partner_ids }&partner_url=/customers/&output=embed/"
|
||||
style="width:100%; border:0; padding:0; margin:0;"></iframe>
|
||||
</xpath>
|
||||
</template>
|
||||
|
@ -78,7 +78,7 @@
|
|||
<t t-foreach="countries" t-as="country_dict">
|
||||
<t t-if="country_dict['country_id']">
|
||||
<li t-att-class="country_dict['country_id'][0] == current_country_id and 'active' or ''">
|
||||
<a t-href="/customers/country/#{ country_dict['country_id'][0] }">
|
||||
<a t-href="/customers/country/#{ slug(country_dict['country_id']) }/">
|
||||
<span class="badge pull-right" t-esc="country_dict['country_id_count']"/>
|
||||
<t t-esc="country_dict['country_id'][1]"/>
|
||||
</a>
|
||||
|
@ -99,20 +99,17 @@
|
|||
<div class="col-md-5">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="/customers">Our References</a></li>
|
||||
<li class="active"><span t-field="partner.name"/></li>
|
||||
<li class="active"><span t-esc="partner_data.get('name')"/></li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<h1 class="text-center" t-field="partner.name"/>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div t-field="partner.website_description"/>
|
||||
</div>
|
||||
<div class="col-md-3" id="ref_right_column">
|
||||
</div>
|
||||
<t t-call="website_partner.partner_detail">
|
||||
<t t-set="left_column">
|
||||
<div id="left_column"></div>
|
||||
</t>
|
||||
<t t-set="right_column">
|
||||
<div id="right_column"></div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
|
@ -121,25 +118,27 @@
|
|||
</template>
|
||||
|
||||
<template id="customer_contact" inherit_id="website_customer.details" inherit_option_id="website_customer.details" name="Customer Contacts">
|
||||
<xpath expr="//div[@id='ref_right_column']" position="inside">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>Customer Reference</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
<img t-att-src="partner.img('image')" class="img img-shadow"/>
|
||||
<img class="img img-shadow" t-attf-src="data:image/png;base64,#{partner_data.get('image_medium')}"/>
|
||||
</div>
|
||||
<address class="mt16 mb8">
|
||||
<strong t-field="partner.name"/>
|
||||
<p t-field="partner.commercial_partner_id"/>
|
||||
<div t-if="partner.phone">
|
||||
<span class="fa fa-phone"/> <span t-field="partner.phone"/>
|
||||
<strong t-esc="partner_data.get('name')"/>
|
||||
<t t-if="partner_data.get('commercial_partner_id')">
|
||||
<p t-raw="'<br/>'.join(partner_data.get('commercial_partner_id')[1].split('\n')[1:])"/>
|
||||
</t>
|
||||
<div t-if="partner_data.get('phone')">
|
||||
<span class="fa fa-phone"/> <span t-esc="partner_data.get('phone')"/>
|
||||
</div>
|
||||
<div t-if="partner.email">
|
||||
<div t-if="partner_data.get('email')">
|
||||
<span class="fa fa-envelope"/>
|
||||
<a t-att-href="'mailto:'+partner.email">
|
||||
<span t-field="partner.email"/>
|
||||
<a t-att-href="'mailto:'+partner_data.get('email')">
|
||||
<span t-esc="partner_data.get('email')"/>
|
||||
</a>
|
||||
</div>
|
||||
</address>
|
||||
|
@ -148,5 +147,58 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="partner_assign" inherit_option_id="website_customer.details" inherit_id="website_customer.details" name="Implemented By">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<t t-if="assigned_partner_data">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>Implemented By</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
<img class="img img-shadow" t-attf-src="data:image/png;base64,#{assigned_partner_data.get('image_medium')}"/>
|
||||
</div>
|
||||
<address class="mt16 mb8">
|
||||
<strong t-esc="assigned_partner_data.get('name')"/>
|
||||
<div t-if="assigned_partner_data.get('phone')">
|
||||
<span class="fa fa-phone"/> <span t-esc="assigned_partner_data.get('phone')"/>
|
||||
</div>
|
||||
<div t-if="assigned_partner_data.get('email')">
|
||||
<span class="fa fa-envelope"/>
|
||||
<a t-att-href="'mailto:'+assigned_partner_data.get('email')">
|
||||
<span t-esc="assigned_partner_data.get('email')"/>
|
||||
</a>
|
||||
</div>
|
||||
</address>
|
||||
<div>
|
||||
<a t-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/#references/" t-if="implemented_partner_ids">
|
||||
<t t-esc="len(implemented_partner_ids)"/> references
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="references" inherit_id="website_customer.details" name="Partner References">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<t t-if="implemented_partners_data">
|
||||
<h3 id="references">References</h3>
|
||||
<div t-foreach="implemented_partners_data" t-as="partner_data" class="media thumbnail">
|
||||
<a class="pull-left" t-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data.get('image_small')}"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/">
|
||||
<t t-if="partner_data.get('parent_id')"><span t-esc="partner_data.get('parent_id')[1]"/></t> <span t-esc="partner_data.get('name')"/>
|
||||
</a>
|
||||
<div t-if="partner_data.get('website_short_description')" t-raw="partner_data.get('website_short_description')"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP S.A. (<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/>.
|
||||
#
|
||||
##############################################################################
|
|
@ -1,42 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013-Today OpenERP S.A. (<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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Public Customer References + Partner Assign',
|
||||
'category': 'Website',
|
||||
'summary': 'Add Partner Assignment Info to your Customer References',
|
||||
'version': '1.0',
|
||||
'description': """
|
||||
OpenERP Customer References + Partner Assign
|
||||
============================================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': [
|
||||
'crm_partner_assign',
|
||||
'website_customer'
|
||||
],
|
||||
'data': [
|
||||
'views/website_customer.xml',
|
||||
],
|
||||
'qweb': [],
|
||||
'installable': False,
|
||||
'auto_install': False,
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="partner_assign" inherit_option_id="website_customer.details" inherit_id="website_customer.details" name="Implemented By">
|
||||
<xpath expr="//div[@id='ref_right_column']" position="inside">
|
||||
<t t-if="partner.assigned_partner_id">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>Implemented By</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
<img t-att-src="partner.assigned_partner_id.img('image')" class="img img-shadow"/>
|
||||
</div>
|
||||
<address class="mt16 mb8">
|
||||
<strong t-field="partner.assigned_partner_id.name"/>
|
||||
<p t-field="partner.assigned_partner_id"/>
|
||||
<div t-if="partner.assigned_partner_id.phone">
|
||||
<span class="fa fa-phone"/> <span t-field="partner.assigned_partner_id.phone"/>
|
||||
</div>
|
||||
<div t-if="partner.assigned_partner_id.email">
|
||||
<span class="fa fa-envelope"/>
|
||||
<a t-att-href="'mailto:'+partner.assigned_partner_id.email">
|
||||
<span t-field="partner.assigned_partner_id.email"/>
|
||||
</a>
|
||||
</div>
|
||||
</address>
|
||||
<div>
|
||||
<a t-href="/customers/#{ slug(partner) }#references" t-if="partner.implemented_partner_ids">
|
||||
<t t-esc="len(partner.implemented_partner_ids)"/> references
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="references" inherit_id="website_customer.details" name="Partner References">
|
||||
<xpath expr="//div[@t-field='partner.website_description']" position="after">
|
||||
<h3 id="references">References</h3>
|
||||
<div>
|
||||
<div t-foreach="partner.implemented_partner_ids" t-as="partner" class="media thumbnail">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
|
||||
<a class="pull-left" t-href="/customers/#{ slug(partner) }/">
|
||||
<img class="media-object" t-att-src="partner.img('image_small')"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-href="/customers/#{ slug(partner) }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -163,13 +163,15 @@ class website_event(http.Controller):
|
|||
|
||||
@website.route(['/event/<model("event.event"):event>/page/<page:page>'], type='http', auth="public", multilang=True)
|
||||
def event_page(self, event, page, **post):
|
||||
website.preload_records(event, on_error="website_event.404")
|
||||
values = {
|
||||
'event': event,
|
||||
}
|
||||
return request.website.render(page, values)
|
||||
|
||||
@website.route(['/event/<model("event.event"):event>'], type='http', auth="public", multilang=True)
|
||||
def event(self, event=None, **post):
|
||||
def event(self, event, **post):
|
||||
website.preload_records(event, on_error="website_event.404")
|
||||
if event.menu_id and event.menu_id.child_id:
|
||||
target_url = event.menu_id.child_id[0].url
|
||||
else:
|
||||
|
@ -179,7 +181,8 @@ class website_event(http.Controller):
|
|||
return request.redirect(target_url);
|
||||
|
||||
@website.route(['/event/<model("event.event"):event>/register'], type='http', auth="public", multilang=True)
|
||||
def event_register(self, event=None, **post):
|
||||
def event_register(self, event, **post):
|
||||
website.preload_records(event, on_error="website_event.404")
|
||||
values = {
|
||||
'event': event,
|
||||
'range': range,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="website.secure_layout">
|
||||
<template id="secure_layout" inherit_id="website.secure_layout">
|
||||
<xpath expr="//t[@id='editable_scripts_hook']" position="inside">
|
||||
<script type="text/javascript" src="/website_event/static/src/js/website_event.editor.js" t-ignore="true"></script>
|
||||
<script type="text/javascript" src="/website_event/static/src/js/website.tour.event.js" t-ignore="true"></script>
|
||||
|
@ -243,6 +243,20 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<template id="404">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="oe_structure oe_empty">
|
||||
<div class="container">
|
||||
<h1 class="mt32">Event not found!</h1>
|
||||
<p>Sorry, the requested event is not available anymore.</p>
|
||||
<p><a t-href="/event/">Return to the event list.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="event_description_full">
|
||||
<t t-call="website_event.event_details">
|
||||
<div class="col-md-8">
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<field name="description">Job Posts on your website</field>
|
||||
</record>
|
||||
|
||||
<template id="website.secure_layout">
|
||||
<template id="secure_layout" inherit_id="website.secure_layout">
|
||||
<xpath expr="//t[@id='editable_scripts_hook']" position="inside">
|
||||
<script type="text/javascript" src="/website_hr_recruitment/static/src/js/website_hr_recruitment.editor.js" t-ignore="true"></script>
|
||||
</xpath>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template id="website.secure_layout" name="Mail customization">
|
||||
<template id="secure_layout" inherit_id="website.secure_layout" name="Mail customization">
|
||||
<xpath expr="//head" position="inside">
|
||||
<script type="text/javascript" src="/website_mail/static/src/js/website_mail.js"></script>
|
||||
</xpath>
|
||||
|
|
|
@ -4,6 +4,7 @@ import openerp
|
|||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import urllib
|
||||
|
@ -39,7 +40,7 @@ class WebsiteMembership(http.Controller):
|
|||
# group by country, based on all customers (base domain)
|
||||
membership_line_ids = membership_line_obj.search(cr, uid, base_line_domain, context=context)
|
||||
countries = partner_obj.read_group(
|
||||
cr, uid, [('member_lines', 'in', membership_line_ids)], ["id", "country_id"],
|
||||
cr, uid, [('member_lines', 'in', membership_line_ids), ("website_published", "=", True)], ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
countries_total = sum(country_dict['country_id_count'] for country_dict in countries)
|
||||
countries.insert(0, {
|
||||
|
@ -57,6 +58,10 @@ class WebsiteMembership(http.Controller):
|
|||
partner_ids = [m.partner and m.partner.id for m in membership_lines]
|
||||
google_map_partner_ids = ",".join(map(str, partner_ids))
|
||||
|
||||
partners_data = {}
|
||||
for partner in partner_obj.read(cr, openerp.SUPERUSER_ID, partner_ids, website_partner.white_list, context=context):
|
||||
partners_data[partner.get("id")] = partner
|
||||
|
||||
# format domain for group_by and memberships
|
||||
membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], context=context)
|
||||
memberships = product_obj.browse(cr, uid, membership_ids, context=context)
|
||||
|
@ -65,6 +70,7 @@ class WebsiteMembership(http.Controller):
|
|||
pager = request.website.pager(url="/members/", total=len(membership_line_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
|
||||
|
||||
values = {
|
||||
'partners_data': partners_data,
|
||||
'membership_lines': membership_lines,
|
||||
'memberships': memberships,
|
||||
'membership': membership,
|
||||
|
@ -78,12 +84,7 @@ class WebsiteMembership(http.Controller):
|
|||
|
||||
@website.route(['/members/<model("res.partner"):partner>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, partner, **post):
|
||||
if not partner.exists():
|
||||
values = website_partner.get_partner_template_value(partner)
|
||||
if not values:
|
||||
return self.members(**post)
|
||||
|
||||
values = {
|
||||
'partner_id': request.registry['res.partner'].browse(
|
||||
request.cr, request.uid, partner.id,
|
||||
context=dict(request.context, show_address=True)),
|
||||
}
|
||||
return request.website.render("website_membership.partner", values)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<div class="col-md-4" id="left_column">
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<li class="nav-header"><h3>Associations</h3></li>
|
||||
<li t-att-class="membership and '' or 'active'"><a href="/members/">All</a></li>
|
||||
<li t-att-class="'' if membership else 'active'"><a href="/members/">All</a></li>
|
||||
<t t-foreach="memberships" t-as="membership_id">
|
||||
<li t-att-class="membership and membership_id.id == membership.id and 'active' or ''">
|
||||
<a t-href="/members/association/#{ membership_id.id }"><t t-esc="membership_id.name"/></a>
|
||||
|
@ -59,17 +59,14 @@
|
|||
<t t-set="current_membership_id" t-value="membership_line_id.membership_id.id"/>
|
||||
<h3 class="text-center"><span t-field="membership_line_id.membership_id"/></h3>
|
||||
</t>
|
||||
<t t-set="partner" t-value="membership_line_id.partner"/>
|
||||
<t t-set="partner_data" t-value="partners_data[membership_line_id.partner.id]"/>
|
||||
<div class="media">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="partner"/>
|
||||
</t>
|
||||
<a class="pull-left" t-href="/members/#{ slug(partner) }/">
|
||||
<img class="media-object" t-att-src="partner.img('image_small')"/>
|
||||
<a class="pull-left" t-href="/members/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data.get('image_small')}"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-href="/members/#{ slug(partner) }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
<a class="media-heading" t-href="/members/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/"><t t-if="partner_data.get('parent_id')"><span t-esc="partner_data.get('parent_id')[1]"/></t> <span t-esc="partner_data.get('name')"/></a>
|
||||
<div t-raw="partner_data.get('website_short_description')"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
'data': [
|
||||
'views/res_partner_view.xml',
|
||||
'views/website_partner_view.xml',
|
||||
'security/website_partner_security.xml',
|
||||
'data/website_data.xml',
|
||||
],
|
||||
'demo': ['website_partner_demo.xml'],
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import openerp
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
import werkzeug
|
||||
|
||||
white_list = ["grade_id", "name", "parent_id", 'website_short_description', "website_published",
|
||||
"website_description", "tel", "fax", "image", "image_small", "image_medium"]
|
||||
|
||||
def get_partner_template_value(partner, add_white_list=None):
|
||||
ctx = dict(request.context, show_address=True)
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_id = partner.id
|
||||
partner_ids = partner_obj.search(request.cr, request.uid, [('id', '=', partner_id)], context=request.context)
|
||||
if not partner.exists() or not partner_ids:
|
||||
partner = None
|
||||
|
||||
partner_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, [partner_id], white_list + (add_white_list or []), context=ctx)[0]
|
||||
|
||||
if not partner_data["website_published"]:
|
||||
return None
|
||||
|
||||
partner_data['name_get'] = partner_obj.name_get(request.cr, openerp.SUPERUSER_ID, [partner_id],context=request.context)[0]
|
||||
|
||||
partner_data['address'] = '<br/>'.join(partner_obj.name_get(
|
||||
request.cr, openerp.SUPERUSER_ID, [partner_id],context=ctx)[0][1].split('\n')[1:])
|
||||
|
||||
values = {
|
||||
'partner': partner,
|
||||
'partner_data': partner_data,
|
||||
}
|
||||
return values
|
||||
|
||||
class WebsitePartner(http.Controller):
|
||||
@website.route(['/partners/<model("res.partner"):partner>/'], type='http', auth="public", multilang=True)
|
||||
def partner(self, partner, **post):
|
||||
""" Route for displaying a single partner / customer. """
|
||||
values = get_partner_template_value(partner)
|
||||
if not values:
|
||||
raise werkzeug.exceptions.NotFound
|
||||
return request.website.render("website_partner.partner_detail", values)
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<!-- <data noupdate="1"> -->
|
||||
<data>
|
||||
|
||||
<!-- res_partner related security rules -->
|
||||
<record id="res_partner_public_website_rule" model="ir.rule">
|
||||
<field name="name">res_partner: public: child of commercial_partner + website_published partners</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="domain_force">['|', ('id', 'child_of', user.commercial_partner_id.id), ('website_published', '=', True)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -2,12 +2,17 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="partner_detail" name="Partner">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
|
||||
<h1 class="col-md-12 text-center" t-field="partner_id.name"/>
|
||||
<template id="partner_detail" name="Partner Details (Complex Template for Access Right)">
|
||||
<t t-if="partner" t-call="website.publish_management">
|
||||
<t t-set="object" t-value="partner"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
</t>
|
||||
<t t-if="partner"><h1 class="col-md-12 text-center" t-field="partner.name"/></t>
|
||||
<t t-if="not partner"><h1 class="col-md-12 text-center" t-esc="partner_data.get('name_get')[1]"/></t>
|
||||
<div class="col-md-4">
|
||||
<div class="text-center">
|
||||
<img t-att-src="partner_id.img('image_medium')"/>
|
||||
<t t-if="partner"><img t-att-src="partner.img('image')"/></t>
|
||||
<t t-if="not partner"><img t-attf-src="data:image/png;base64,#{partner_data.get('image')}"/></t>
|
||||
</div>
|
||||
<address>
|
||||
<table style="margin: auto;" class="well">
|
||||
|
@ -16,24 +21,49 @@
|
|||
<col/>
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<t t-set="address" t-value="'<br/>'.join(partner_id.name_get()[0][1].split('\n')[1:])"/>
|
||||
<tr t-if="address or editable"><th class="texttop">Address</th><td class="span2" t-raw="address"/></tr>
|
||||
<tr t-if="partner_id.website or editable"><th>Website</th><td class="span2">
|
||||
<t t-if="partner_id.website"><span t-field="partner_id.website"/></t></td></tr>
|
||||
<tr t-if="partner_id.phone or editable"><th>Phone</th><td class="span2">
|
||||
<t t-if="partner_id.phone"><span t-field="partner_id.phone"/></t></td></tr>
|
||||
<tr t-if="partner_id.mobile or editable"><th>Tel</th><td class="span2">
|
||||
<t t-if="partner_id.mobile"><span t-field="partner_id.mobile"/></t></td></tr>
|
||||
<tr t-if="partner_id.fax or editable"><th>Fax</th><td class="span2">
|
||||
<t t-if="partner_id.fax"><span t-field="partner_id.fax"/></t></td></tr>
|
||||
<tr t-if="partner_id.email or editable"><th>Email</th><td class="span2">
|
||||
<t t-if="partner_id.email"><span t-field="partner_id.email"/></t></td></tr>
|
||||
<t t-if="partner">
|
||||
<t t-set="address" t-value="'<br/>'.join(partner.name_get()[0][1].split('\n')[1:])"/>
|
||||
<tr t-if="address or editable"><th class="texttop">Address</th><td class="span2" t-raw="address"/></tr>
|
||||
</t>
|
||||
<tr t-if="not partner and partner_data.get('address')"><th class="texttop">Address</th><td class="span2" t-raw="partner_data.get('address')"/></tr>
|
||||
|
||||
<tr t-if="partner and (partner.website or editable)"><th>Website</th><td class="span2">
|
||||
<t t-if="partner.website"><span t-field="partner.website"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('website')"><th>Website</th><td class="span2"><span t-esc="partner_data.get('website')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.phone or editable)"><th>Phone</th><td class="span2">
|
||||
<t t-if="partner.phone"><span t-field="partner.phone"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('phone')"><th>Phone</th><td class="span2"><span t-esc="partner_data.get('phone')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.mobile or editable)"><th>Tel</th><td class="span2">
|
||||
<t t-if="partner.mobile"><span t-field="partner.mobile"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('mobile')"><th>Tel</th><td class="span2"><span t-esc="partner_data.get('mobile')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.fax or editable)"><th>Fax</th><td class="span2">
|
||||
<t t-if="partner.fax"><span t-field="partner.fax"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('fax')"><th>Fax</th><td class="span2"><span t-esc="partner_data.get('fax')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.email or editable)"><th>Email</th><td class="span2">
|
||||
<t t-if="partner.email"><span t-field="partner.email"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('email')"><th>Email</th><td class="span2"><span t-esc="partner_data.get('email')"/></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</address>
|
||||
<t t-raw="left_column or ''"/>
|
||||
</div>
|
||||
<div class="col-md-8 mt32">
|
||||
<t t-if="partner">
|
||||
<div t-field="partner.website_description"/>
|
||||
<t t-if="editable">
|
||||
<h2 class="css_non_editable_mode_hidden">Short Description for List View</h2>
|
||||
<div class="css_non_editable_mode_hidden" t-field="partner.website_short_description"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="not partner">
|
||||
<div class="col-md-8 mt32" t-raw="partner_data.get('website_description')"/>
|
||||
</t>
|
||||
<t t-raw="right_column or ''"/>
|
||||
</div>
|
||||
<div class="col-md-8 mt32" t-field="partner_id.website_description"/>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -18,5 +18,3 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import controllers
|
||||
|
|
|
@ -1,42 +1,18 @@
|
|||
# -*- 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Payment: Website Integration (Test Module)',
|
||||
'name': 'Payment: Website Integration',
|
||||
'category': 'Website',
|
||||
'summary': 'Payment: Website Integration (Test Module)',
|
||||
'summary': 'Payment: Website Integration',
|
||||
'version': '1.0',
|
||||
'description': """Module installing all sub-payment modules and adding some
|
||||
controllers and menu entries in order to test them.""",
|
||||
'description': """Bridge module for acquirers and website.""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': [
|
||||
'website',
|
||||
'payment_acquirer',
|
||||
'payment_acquirer_ogone',
|
||||
'payment_acquirer_paypal',
|
||||
'payment_acquirer_transfer',
|
||||
],
|
||||
'data': [
|
||||
'views/website_payment_templates.xml',
|
||||
],
|
||||
'installable': False,
|
||||
'active': False,
|
||||
'auto_install': True,
|
||||
}
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
# -*- 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 openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
|
||||
|
||||
class WebsitePayment(http.Controller):
|
||||
|
||||
@website.route([
|
||||
'/payment/paypal/test',
|
||||
], type='http', auth="public")
|
||||
def paypal_test(self, **post):
|
||||
""" TODO
|
||||
"""
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
acquirer_obj = request.registry['payment.acquirer']
|
||||
payment_obj = request.registry['payment.transaction']
|
||||
currency_obj = request.registry['res.currency']
|
||||
|
||||
paypal_id = acquirer_obj.search(cr, uid, [('name', '=', 'paypal')], limit=1, context=context)[0]
|
||||
currency_id = currency_obj.search(cr, uid, [('name', '=', 'EUR')], limit=1, context=context)[0]
|
||||
|
||||
nbr_tx = payment_obj.search(cr, uid, [], count=True, context=context)
|
||||
tx_id = payment_obj.create(cr, uid, {
|
||||
'reference': 'test_ref_%s' % (nbr_tx),
|
||||
'amount': 1.95,
|
||||
'currency_id': currency_id,
|
||||
'acquirer_id': paypal_id,
|
||||
'partner_name': 'Norbert Buyer',
|
||||
'partner_email': 'norbert.buyer@example.com',
|
||||
'partner_lang': 'fr_FR',
|
||||
}, context=context)
|
||||
|
||||
paypal_form = acquirer_obj.render(cr, uid, paypal_id, None, None, None, tx_id=tx_id, context=context)
|
||||
paypal = acquirer_obj.browse(cr, uid, paypal_id, context=context)
|
||||
|
||||
values = {
|
||||
'acquirer': paypal,
|
||||
'acquirer_form': paypal_form,
|
||||
}
|
||||
return request.website.render("website_payment.index_paypal", values)
|
||||
|
||||
@website.route([
|
||||
'/payment/ogone/test',
|
||||
], type='http', auth="public")
|
||||
def ogone_test(self, **post):
|
||||
""" TODO
|
||||
"""
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
acquirer_obj = request.registry['payment.acquirer']
|
||||
payment_obj = request.registry['payment.transaction']
|
||||
currency_obj = request.registry['res.currency']
|
||||
|
||||
ogone_id = acquirer_obj.search(cr, uid, [('name', '=', 'ogone')], limit=1, context=context)[0]
|
||||
currency_id = currency_obj.search(cr, uid, [('name', '=', 'EUR')], limit=1, context=context)[0]
|
||||
|
||||
nbr_tx = payment_obj.search(cr, uid, [], count=True, context=context)
|
||||
tx_id = payment_obj.create(cr, uid, {
|
||||
'reference': 'test_ref_%s' % (nbr_tx),
|
||||
'amount': 1.95,
|
||||
'currency_id': currency_id,
|
||||
'acquirer_id': ogone_id,
|
||||
'partner_name': 'Norbert Buyer',
|
||||
'partner_email': 'norbert.buyer@example.com',
|
||||
'partner_lang': 'fr_FR',
|
||||
}, context=context)
|
||||
|
||||
ogone_form = acquirer_obj.render(cr, uid, ogone_id, None, None, None, tx_id=tx_id, context=context)
|
||||
ogone = acquirer_obj.browse(cr, uid, ogone_id, context=context)
|
||||
|
||||
values = {
|
||||
'acquirer': ogone,
|
||||
'acquirer_form': ogone_form,
|
||||
}
|
||||
return request.website.render("website_payment.index_ogone", values)
|
|
@ -1,100 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
|
||||
<!-- Add menus for testing -->
|
||||
<data noupdate="0">
|
||||
<record id="menu_paypal_test" model="website.menu">
|
||||
<field name="name">Paypal (Test)</field>
|
||||
<field name="url">/payment/paypal/test</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">90</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_paypal_ogone" model="website.menu">
|
||||
<field name="name">Ogone (Test)</field>
|
||||
<field name="url">/payment/ogone/test</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">91</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_transfer_test" model="website.menu">
|
||||
<field name="name">Transfer (Test)</field>
|
||||
<field name="url">/payment/transfer/test</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">92</field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<!-- Page -->
|
||||
<data>
|
||||
<template id="index_paypal" name="Paypal (Test)" page="True">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="head">
|
||||
<script type="text/javascript" src="/website_payment/static/src/js/payment_acquirer.js"></script>
|
||||
<script type="text/javascript" src="/website_payment/static/lib/jquery.payment/jquery.payment.js"></script>
|
||||
<link rel='stylesheet' href='/website_payment/static/src/css/website_payment.css'/>
|
||||
</t>
|
||||
<div id="wrap">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<!-- <div class="row">
|
||||
<h3>Paypal payment: server 2 server</h3>
|
||||
<form class="form-horizontal col-sm-4 oe_cc" role="form">
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="control-label" for="cc_number">Card number</label>
|
||||
<input type="tel" id="cc_number" class="form-control"/>
|
||||
<div class="card_placeholder"></div>
|
||||
<div class="visa"></div>
|
||||
</div>
|
||||
<div class="form-group col-sm-4">
|
||||
<label class="control-label" for="cc_cvc">Card code</label>
|
||||
<input type="text" id="cc_cvc" class="form-control" maxlength="4" palceholder="CVC"/>
|
||||
</div>
|
||||
<div class="form-group col-sm-7">
|
||||
<label class="control-label" for="cc_holder_name">Holder Name</label>
|
||||
<input type="text" id="cc_hoder_name" class="form-control"/>
|
||||
</div>
|
||||
<div class="form-group col-sm-5">
|
||||
<label class="control-label" for="cc_expires_mm">Expires</label>
|
||||
<input type="text" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div> -->
|
||||
<div>
|
||||
<h3>Paypal payment: form based</h3>
|
||||
<t t-raw="acquirer_form"/>
|
||||
</div>
|
||||
<template id="cc_form" name="Paypal (Test)" page="True">
|
||||
<div class="row">
|
||||
<h3>Paypal payment: server 2 server</h3>
|
||||
<form class="form-horizontal col-sm-4 oe_cc" role="form">
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="control-label" for="cc_number">Card number</label>
|
||||
<input type="tel" id="cc_number" class="form-control"/>
|
||||
<div class="card_placeholder"></div>
|
||||
<div class="visa"></div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="index_ogone" name="Ogone (Test)" page="True">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<div class="row">
|
||||
Ogone payment
|
||||
<t t-raw="acquirer_form"/>
|
||||
</div>
|
||||
<div class="form-group col-sm-4">
|
||||
<label class="control-label" for="cc_cvc">Card code</label>
|
||||
<input type="text" id="cc_cvc" class="form-control" maxlength="4" palceholder="CVC"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="index_transfer" name="Ogone (Test)" page="True">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<div class="row">
|
||||
Transfer payment
|
||||
<t t-raw="acquirer_form"/>
|
||||
</div>
|
||||
<div class="form-group col-sm-7">
|
||||
<label class="control-label" for="cc_holder_name">Holder Name</label>
|
||||
<input type="text" id="cc_hoder_name" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<div class="form-group col-sm-5">
|
||||
<label class="control-label" for="cc_expires_mm">Expires</label>
|
||||
<input type="text" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -121,19 +121,19 @@ class Ecommerce(http.Controller):
|
|||
return product_obj.browse(request.cr, request.uid, product_ids, context=request.context)
|
||||
|
||||
def has_search_filter(self, attribute_id, value_id=None):
|
||||
if request.httprequest.args.get('filter'):
|
||||
filter = simplejson.loads(request.httprequest.args['filter'])
|
||||
if request.httprequest.args.get('filters'):
|
||||
filters = simplejson.loads(request.httprequest.args['filters'])
|
||||
else:
|
||||
filter = []
|
||||
for key_val in filter:
|
||||
filters = []
|
||||
for key_val in filters:
|
||||
if key_val[0] == attribute_id and (not value_id or value_id in key_val[1:]):
|
||||
return key_val
|
||||
return False
|
||||
|
||||
@website.route(['/shop/filter/'], type='http', auth="public", multilang=True)
|
||||
def filter(self, **post):
|
||||
@website.route(['/shop/filters/'], type='http', auth="public", multilang=True)
|
||||
def filters(self, **post):
|
||||
index = []
|
||||
filter = []
|
||||
filters = []
|
||||
for key, val in post.items():
|
||||
cat = key.split("-")
|
||||
if len(cat) < 3 or cat[2] in ('max','minmem','maxmem'):
|
||||
|
@ -145,19 +145,19 @@ class Ecommerce(http.Controller):
|
|||
_max = int(post.pop("att-%s-max" % cat[1]))
|
||||
_min = int(val)
|
||||
if (minmem != _min or maxmem != _max) and cat_id not in index:
|
||||
filter.append([cat_id , [_min, _max] ])
|
||||
filters.append([cat_id , [_min, _max] ])
|
||||
index.append(cat_id)
|
||||
elif cat_id not in index:
|
||||
filter.append([ cat_id, int(cat[2]) ])
|
||||
filters.append([ cat_id, int(cat[2]) ])
|
||||
index.append(cat_id)
|
||||
else:
|
||||
cat[2] = int(cat[2])
|
||||
if cat[2] not in filter[index.index(cat_id)][1:]:
|
||||
filter[index.index(cat_id)].append( cat[2] )
|
||||
if cat[2] not in filters[index.index(cat_id)][1:]:
|
||||
filters[index.index(cat_id)].append( cat[2] )
|
||||
post.pop(key)
|
||||
|
||||
return request.redirect("/shop/?filter=%s%s%s" % (
|
||||
simplejson.dumps(filter),
|
||||
return request.redirect("/shop/?filters=%s%s%s" % (
|
||||
simplejson.dumps(filters),
|
||||
post.get("search") and ("&search=%s" % post.get("search")) or "",
|
||||
post.get("category") and ("&category=%s" % post.get("category")) or ""
|
||||
))
|
||||
|
@ -188,7 +188,7 @@ class Ecommerce(http.Controller):
|
|||
'/shop/category/<int:category>/',
|
||||
'/shop/category/<int:category>/page/<int:page>/'
|
||||
], type='http', auth="public", multilang=True)
|
||||
def shop(self, category=0, page=0, filter_domain='', search='', **post):
|
||||
def shop(self, category=0, page=0, filters='', search='', **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
product_obj = request.registry.get('product.template')
|
||||
domain = request.registry.get('website').get_website_sale_domain()
|
||||
|
@ -198,10 +198,10 @@ class Ecommerce(http.Controller):
|
|||
('description', 'ilike', "%%%s%%" % search)]
|
||||
if category:
|
||||
domain.append(('product_variant_ids.public_categ_id', 'child_of', category))
|
||||
if filter_domain:
|
||||
filter_domain = simplejson.loads(filter_domain)
|
||||
if filter_domain:
|
||||
ids = self.attributes_to_ids(filter_domain)
|
||||
if filters:
|
||||
filters = simplejson.loads(filters)
|
||||
if filters:
|
||||
ids = self.attributes_to_ids(filters)
|
||||
domain.append(('id', 'in', ids or [0]))
|
||||
|
||||
product_count = product_obj.search_count(cr, uid, domain, context=context)
|
||||
|
@ -228,10 +228,12 @@ class Ecommerce(http.Controller):
|
|||
values = {
|
||||
'products': products,
|
||||
'bins': table_compute().process(products),
|
||||
'rows': PPR,
|
||||
'range': range,
|
||||
'search': {
|
||||
'search': search,
|
||||
'category': category,
|
||||
'filter_domain': filter_domain,
|
||||
'filters': filters,
|
||||
},
|
||||
'pager': pager,
|
||||
'styles': styles,
|
||||
|
@ -242,7 +244,9 @@ class Ecommerce(http.Controller):
|
|||
return request.website.render("website_sale.products", values)
|
||||
|
||||
@website.route(['/shop/product/<model("product.template"):product>/'], type='http', auth="public", multilang=True)
|
||||
def product(self, product, search='', category='', filter_domain='', **kwargs):
|
||||
def product(self, product, search='', category='', filters='', **kwargs):
|
||||
website.preload_records(product, on_error="website_sale.404")
|
||||
|
||||
category_obj = request.registry.get('product.public.category')
|
||||
|
||||
category_ids = category_obj.search(request.cr, request.uid, [], context=request.context)
|
||||
|
@ -263,7 +267,7 @@ class Ecommerce(http.Controller):
|
|||
'search': {
|
||||
'search': search,
|
||||
'category': category and str(category.id),
|
||||
'filter': filter_domain,
|
||||
'filters': filters,
|
||||
}
|
||||
}
|
||||
return request.website.render("website_sale.product", values)
|
||||
|
@ -600,21 +604,23 @@ class Ecommerce(http.Controller):
|
|||
|
||||
# fetch all registered payment means
|
||||
if tx:
|
||||
payment_ids = [tx.acquirer_id.id]
|
||||
acquirer_ids = [tx.acquirer_id.id]
|
||||
else:
|
||||
payment_ids = payment_obj.search(cr, SUPERUSER_ID, [('portal_published', '=', True)], context=context)
|
||||
values['payments'] = payment_obj.browse(cr, uid, payment_ids, context=context)
|
||||
for pay in values['payments']:
|
||||
pay._content = payment_obj.render(
|
||||
cr, uid, pay.id,
|
||||
acquirer_ids = payment_obj.search(cr, SUPERUSER_ID, [('portal_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']:
|
||||
render_ctx['tx_url'] = '/shop/payment/transaction/%s' % acquirer.id
|
||||
acquirer.button = payment_obj.render(
|
||||
cr, uid, acquirer.id,
|
||||
order.name,
|
||||
order.amount_total,
|
||||
order.pricelist_id.currency_id,
|
||||
order.pricelist_id.currency_id.id,
|
||||
partner_id=shipping_partner_id,
|
||||
tx_custom_values={
|
||||
tx_values={
|
||||
'return_url': '/shop/payment/validate',
|
||||
},
|
||||
context=context)
|
||||
context=render_ctx)
|
||||
|
||||
return request.website.render("website_sale.payment", values)
|
||||
|
||||
|
|
|
@ -7,13 +7,6 @@ $(document).ready(function () {
|
|||
$(".oe_website_sale .js_shipping").toggle();
|
||||
});
|
||||
|
||||
var $payment = $(".oe_website_sale .js_payment");
|
||||
$payment.find("input[name='payment_type']").click(function (ev) {
|
||||
var payment_id = $(ev.currentTarget).val();
|
||||
$("div[data-id]", $payment).addClass("hidden");
|
||||
$("a.btn:last, div[data-id='"+payment_id+"']", $payment).removeClass("hidden");
|
||||
});
|
||||
|
||||
// change for css
|
||||
$(document).on('mouseup', '.js_publish', function (ev) {
|
||||
$(ev.currentTarget).parents(".thumbnail").toggleClass("disabled");
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
$(document).ready(function () {
|
||||
|
||||
/* Hitting the payment button: payment transaction process begins
|
||||
* We redirect the user to a custom shop page in oder to create the
|
||||
* transaction. The form POST data will be used to perform the post
|
||||
* query.
|
||||
*/
|
||||
$('input#payment_submit').on('click', function (ev) { // TDEFIXME: change input#ID to input inside payment form, less strict
|
||||
var acquirer_id = $(this).closest('form').closest('div.oe_payment_acquirer').data().id || 0;
|
||||
var form_action = $(this).closest("form").attr('action');
|
||||
console.log('cliking on submit for payment - redirecting from', form_action, 'to shop with acqurier_id', acquirer_id);
|
||||
$(this).closest("form").attr("action", '/shop/payment/transaction/' + acquirer_id);
|
||||
// When choosing an acquirer, display its Pay Now button
|
||||
var $payment = $("#payment_method");
|
||||
$payment.find("input[name='acquirer']").click(function (ev) {
|
||||
var payment_id = $(ev.currentTarget).val();
|
||||
$("div.oe_sale_acquirer_button[data-id]", $payment).addClass("hidden");
|
||||
$("div.oe_sale_acquirer_button[data-id='"+payment_id+"']", $payment).removeClass("hidden");
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<!-- Layout add nav and footer -->
|
||||
|
||||
<template id="website.secure_layout">
|
||||
<template id="secure_layout" inherit_id="website.secure_layout">
|
||||
<xpath expr="//t[@id='editable_scripts_hook']" position="inside">
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.editor.js" t-ignore="true"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website.tour.shop.js" t-ignore="true"></script>
|
||||
|
@ -40,7 +40,7 @@
|
|||
|
||||
<template id="search" name="Search hidden fields">
|
||||
<input type="hidden" name="category" t-att-value="search.get('category') or ''"/>
|
||||
<input type="hidden" name="filter_domain" t-att-value="search.get('filter_domain') or ''"/>
|
||||
<input type="hidden" name="filters" t-att-value="search.get('filters') or ''"/>
|
||||
<input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search.get('search') or ''"/>
|
||||
</template>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
<div class="ribbon">Promo</div>
|
||||
</div>
|
||||
<div class="oe_product_description">
|
||||
<a t-href="/shop/product/#{ slug(product) }/" t-keep-query="category,search,filter_domain">
|
||||
<a t-href="/shop/product/#{ slug(product) }/" t-keep-query="category,search,filters">
|
||||
<b t-field="product.name"/>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -69,7 +69,7 @@
|
|||
</b>
|
||||
</div>
|
||||
<div class="oe_product_image text-center">
|
||||
<a t-href="/shop/product/#{ product.id }/" t-keep-query="category,search,filter_domain">
|
||||
<a t-href="/shop/product/#{ product.id }/" t-keep-query="category,search,filters">
|
||||
<span t-field="product.image" t-field-options='{"widget": "image"}'/>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -105,12 +105,14 @@
|
|||
<div class="col-md-12" id="products_grid">
|
||||
<table width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td t-foreach="range(0,rows)" t-as="row" t-attf-width="#{100/rows}%"></td>
|
||||
</tr>
|
||||
<tr t-foreach="bins" t-as="tr_product">
|
||||
<t t-foreach="tr_product" t-as="td_product">
|
||||
<t t-if="td_product">
|
||||
<t t-set="product" t-value="td_product['product']"/>
|
||||
<td t-att-colspan="td_product['x']"
|
||||
t-attf-width="#{td_product['x']*25}%"
|
||||
t-att-rowspan="td_product['y']"
|
||||
t-attf-class="oe_product oe-height-#{td_product['y']*2} #{ td_product['class'] }">
|
||||
|
||||
|
@ -227,6 +229,19 @@
|
|||
|
||||
|
||||
<!-- product -->
|
||||
<template id="404">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="oe_structure oe_empty">
|
||||
<div class="container">
|
||||
<h1 class="mt32">Product not found!</h1>
|
||||
<p>Sorry, this product is not available anymore.</p>
|
||||
<p><a t-href="/shop/">Return to the product list.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="product" name="Product">
|
||||
<t t-call="website.layout">
|
||||
|
@ -241,7 +256,7 @@
|
|||
<div class="col-sm-5">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="/shop">Products</a></li>
|
||||
<li t-if="search.get('category')"><a t-href="/shop/" t-keep-query="category,search,filter_domain"><span t-field="category.name"/></a></li>
|
||||
<li t-if="search.get('category')"><a t-href="/shop/" t-keep-query="category,search,filters"><span t-field="category.name"/></a></li>
|
||||
<li class="active"><span t-field="product.name"/></li>
|
||||
</ol>
|
||||
</div><div class="col-sm-3">
|
||||
|
@ -512,7 +527,7 @@
|
|||
|
||||
<template id="products_attributes" inherit_option_id="website_sale.products" name="Product Filters and Attributes">
|
||||
<xpath expr="//div[@id='products_grid_before']" position="inside">
|
||||
<form t-action="/shop/filter/" method="post" t-keep-query="category,search">
|
||||
<form t-action="/shop/filters/" method="post" t-keep-query="category,search">
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<t t-set="attribute_ids" t-value="Ecommerce.get_attribute_ids()"/>
|
||||
<t t-foreach="attribute_ids" t-as="attribute_id">
|
||||
|
@ -545,7 +560,7 @@
|
|||
</t>
|
||||
</ul>
|
||||
<button class="btn btn-xs btn-primary mt16">Apply filter</button>
|
||||
<a t-href="/shop/" t-keep-query="category,search,add_filter" class="btn btn-xs btn-default mt16">Cancel filter</a>
|
||||
<a t-href="/shop/" t-keep-query="category,search" class="btn btn-xs btn-default mt16">Cancel filter</a>
|
||||
</form>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='products_grid_before']" position="attributes">
|
||||
|
@ -882,20 +897,22 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="js_payment mb64" t-if="not payment_acquirer_id and payments" id="payment_method">
|
||||
<div class="js_payment mb64" t-if="acquirers" id="payment_method">
|
||||
<h3>Choose your payment method</h3>
|
||||
<div class="col-lg-5 col-sm-6">
|
||||
<t t-foreach="payments or []" t-as="payment">
|
||||
<label t-if="payment._content">
|
||||
<input t-att-value="payment.id" type="radio" name="payment_type"/> <span t-field="payment.name"/>
|
||||
<t t-foreach="acquirers or []" t-as="acquirer">
|
||||
<label t-if="acquirer.button" class="oe_sale_acquirer_logo" style="display: block;">
|
||||
<input t-att-value="acquirer.id" type="radio" name="acquirer"/>
|
||||
<img class="media-object" style="width: 60px; display: inline-block;"
|
||||
t-att-title="acquirer.name"
|
||||
t-att-src="'/payment_acquirer_%s/static/src/img/%s_icon.png' % (acquirer.name, acquirer.name)"/>
|
||||
</label>
|
||||
</t>
|
||||
<t t-foreach="payments" t-as="payment">
|
||||
<div t-att-data-id="payment.id" t-raw="payment._content" class="oe_payment_acquirer hidden"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-3">
|
||||
<button class="btn btn-primary pull-right">Pay Now !!!</button>
|
||||
<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"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|