[MIG] payment_paypal: new API

No functional change.
This commit is contained in:
Shivam Dudhat
2016-07-06 15:10:47 +02:00
committed by Thibault Delavallée
parent 9e69cfd0b4
commit f1ac1b1271
7 changed files with 128 additions and 164 deletions
+5 -9
View File
@@ -6,8 +6,8 @@ import pprint
import urllib2
import werkzeug
from openerp import http, SUPERUSER_ID
from openerp.http import request
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
@@ -37,21 +37,18 @@ class PaypalController(http.Controller):
Once data is validated, process it. """
res = False
new_post = dict(post, cmd='_notify-validate')
cr, uid, context = request.cr, request.uid, request.context
reference = post.get('item_number')
tx = None
if reference:
tx_ids = request.registry['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
if tx_ids:
tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
paypal_urls = request.registry['payment.acquirer']._get_paypal_urls(cr, uid, tx and tx.acquirer_id and tx.acquirer_id.environment or 'prod', context=context)
tx = request.env['payment.transaction'].search([('reference', '=', reference)])
paypal_urls = tx.acquirer_id._get_paypal_urls(tx.acquirer_id.environment or 'prod')
validate_url = paypal_urls['paypal_form_url']
urequest = urllib2.Request(validate_url, werkzeug.url_encode(new_post))
uopen = urllib2.urlopen(urequest)
resp = uopen.read()
if resp == 'VERIFIED':
_logger.info('Paypal: validated data')
res = request.registry['payment.transaction'].form_feedback(cr, SUPERUSER_ID, post, 'paypal', context=context)
res = request.env['payment.transaction'].sudo().form_feedback(post, 'paypal')
elif resp == 'INVALID':
_logger.warning('Paypal: answered INVALID on data verification')
else:
@@ -76,7 +73,6 @@ class PaypalController(http.Controller):
@http.route('/payment/paypal/cancel', type='http', auth="none", csrf=False)
def paypal_cancel(self, **post):
""" When the user cancels its Paypal payment: GET on this route """
cr, uid, context = request.cr, SUPERUSER_ID, request.context
_logger.info('Beginning Paypal cancel with post data %s', pprint.pformat(post)) # debug
return_url = self._get_return_url(**post)
return werkzeug.utils.redirect(return_url)
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<data noupdate="1">
<record id="payment.payment_acquirer_paypal" model="payment.acquirer">
@@ -18,4 +18,4 @@
</record>
</data>
</openerp>
</odoo>
+77 -92
View File
@@ -1,26 +1,41 @@
# coding: utf-8
import base64
import json
import logging
import urlparse
import werkzeug.urls
import urllib2
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment_paypal.controllers.main import PaypalController
from openerp.osv import osv, fields
from openerp.tools.float_utils import float_compare
from openerp import SUPERUSER_ID
from openerp.tools.translate import _
from odoo import api, fields, models, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_paypal.controllers.main import PaypalController
from odoo.tools.float_utils import float_compare
_logger = logging.getLogger(__name__)
class AcquirerPaypal(osv.Model):
class AcquirerPaypal(models.Model):
_inherit = 'payment.acquirer'
def _get_paypal_urls(self, cr, uid, environment, context=None):
provider = fields.Selection(selection_add=[('paypal', 'Paypal')])
paypal_email_account = fields.Char('Paypal Email ID', required_if_provider='paypal')
paypal_seller_account = fields.Char(
'Paypal Merchant ID',
help='The Merchant ID is used to ensure communications coming from Paypal are valid and secured.')
paypal_use_ipn = fields.Boolean('Use IPN', default=True, help='Paypal Instant Payment Notification')
# Server 2 server
paypal_api_enabled = fields.Boolean('Use Rest API', default=False)
paypal_api_username = fields.Char('Rest API Username')
paypal_api_password = fields.Char('Rest API Password')
paypal_api_access_token = fields.Char('Access Token')
paypal_api_access_token_validity = fields.Datetime('Access Token Validity')
# Default paypal fees
fees_dom_fixed = fields.Float(default=0.35)
fees_dom_var = fields.Float(default=3.4)
fees_int_fixed = fields.Float(default=0.35)
fees_int_var = fields.Float(default=3.9)
@api.model
def _get_paypal_urls(self, environment):
""" Paypal URLS """
if environment == 'prod':
return {
@@ -33,36 +48,8 @@ class AcquirerPaypal(osv.Model):
'paypal_rest_url': 'https://api.sandbox.paypal.com/v1/oauth2/token',
}
def _get_providers(self, cr, uid, context=None):
providers = super(AcquirerPaypal, self)._get_providers(cr, uid, context=context)
providers.append(['paypal', 'Paypal'])
return providers
_columns = {
'paypal_email_account': fields.char('Paypal Email ID', required_if_provider='paypal'),
'paypal_seller_account': fields.char(
'Paypal Merchant ID',
help='The Merchant ID is used to ensure communications coming from Paypal are valid and secured.'),
'paypal_use_ipn': fields.boolean('Use IPN', help='Paypal Instant Payment Notification'),
# Server 2 server
'paypal_api_enabled': fields.boolean('Use Rest API'),
'paypal_api_username': fields.char('Rest API Username'),
'paypal_api_password': fields.char('Rest API Password'),
'paypal_api_access_token': fields.char('Access Token'),
'paypal_api_access_token_validity': fields.datetime('Access Token Validity'),
}
_defaults = {
'paypal_use_ipn': True,
'fees_active': False,
'fees_dom_fixed': 0.35,
'fees_dom_var': 3.4,
'fees_int_fixed': 0.35,
'fees_int_var': 3.9,
'paypal_api_enabled': False,
}
def paypal_compute_fees(self, cr, uid, ids, amount, currency_id, country_id, context=None):
@api.multi
def paypal_compute_fees(self, amount, currency_id, country_id):
""" Compute paypal fees.
:param float amount: the amount to pay
@@ -71,28 +58,27 @@ class AcquirerPaypal(osv.Model):
the acquirer company country.
:return float fees: computed fees
"""
acquirer = self.browse(cr, uid, ids, context=context)[0]
if not acquirer.fees_active:
if not self.fees_active:
return 0.0
country = self.pool['res.country'].browse(cr, uid, country_id, context=context)
if country and acquirer.company_id.country_id.id == country.id:
percentage = acquirer.fees_dom_var
fixed = acquirer.fees_dom_fixed
country = self.env['res.country'].browse(country_id)
if country and self.company_id.country_id.id == country.id:
percentage = self.fees_dom_var
fixed = self.fees_dom_fixed
else:
percentage = acquirer.fees_int_var
fixed = acquirer.fees_int_fixed
percentage = self.fees_int_var
fixed = self.fees_int_fixed
fees = (percentage / 100.0 * amount + fixed) / (1 - percentage / 100.0)
return fees
def paypal_form_generate_values(self, cr, uid, ids, values, context=None):
base_url = self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'web.base.url')
acquirer = self.browse(cr, uid, ids, context=context)[0]
@api.multi
def paypal_form_generate_values(self, values):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
paypal_tx_values = dict(values)
paypal_tx_values.update({
'cmd': '_xclick',
'business': acquirer.paypal_email_account,
'item_name': '%s: %s' % (acquirer.company_id.name, values['reference']),
'business': self.paypal_email_account,
'item_name': '%s: %s' % (self.company_id.name, values['reference']),
'item_number': values['reference'],
'amount': values['amount'],
'currency_code': values['currency'] and values['currency'].name or '',
@@ -107,28 +93,27 @@ class AcquirerPaypal(osv.Model):
'paypal_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),
'handling': '%.2f' % paypal_tx_values.pop('fees', 0.0) if acquirer.fees_active else False,
'handling': '%.2f' % paypal_tx_values.pop('fees', 0.0) if self.fees_active else False,
'custom': json.dumps({'return_url': '%s' % paypal_tx_values.pop('return_url')}) if paypal_tx_values.get('return_url') else False,
})
return paypal_tx_values
def paypal_get_form_action_url(self, cr, uid, ids, context=None):
acquirer = self.browse(cr, uid, ids, context=context)[0]
return self._get_paypal_urls(cr, uid, acquirer.environment, context=context)['paypal_form_url']
@api.multi
def paypal_get_form_action_url(self):
return self._get_paypal_urls(self.environment)['paypal_form_url']
class TxPaypal(osv.Model):
class TxPaypal(models.Model):
_inherit = 'payment.transaction'
_columns = {
'paypal_txn_type': fields.char('Transaction type'),
}
paypal_txn_type = fields.Char('Transaction type')
# --------------------------------------------------
# FORM RELATED METHODS
# --------------------------------------------------
def _paypal_form_get_tx_from_data(self, cr, uid, data, context=None):
@api.model
def _paypal_form_get_tx_from_data(self, data):
reference, txn_id = data.get('item_number'), data.get('txn_id')
if not reference or not txn_id:
error_msg = _('Paypal: received data with missing reference (%s) or txn_id (%s)') % (reference, txn_id)
@@ -136,19 +121,19 @@ class TxPaypal(osv.Model):
raise ValidationError(error_msg)
# find tx -> @TDENOTE use txn_id ?
tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
if not tx_ids or len(tx_ids) > 1:
txs = self.env['payment.transaction'].search([('reference', '=', reference)])
if not txs or len(txs) > 1:
error_msg = 'Paypal: received data for reference %s' % (reference)
if not tx_ids:
if not txs:
error_msg += '; no order found'
else:
error_msg += '; multiple order found'
_logger.info(error_msg)
raise ValidationError(error_msg)
return self.browse(cr, uid, tx_ids[0], context=context)
return txs[0]
def _paypal_form_get_invalid_parameters(self, cr, uid, ids, data, context=None):
tx = self.browse(cr, uid, ids, context=context)[0]
@api.multi
def _paypal_form_get_invalid_parameters(self, data):
invalid_parameters = []
_logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version'))
if data.get('test_ipn'):
@@ -157,50 +142,50 @@ class TxPaypal(osv.Model):
),
# 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))
if self.acquirer_reference and data.get('txn_id') != self.acquirer_reference:
invalid_parameters.append(('txn_id', data.get('txn_id'), self.acquirer_reference))
# check what is buyed
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 '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))
if float_compare(float(data.get('mc_gross', '0.0')), (self.amount + self.fees), 2) != 0:
invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % self.amount)) # mc_gross is amount + fees
if data.get('mc_currency') != self.currency_id.name:
invalid_parameters.append(('mc_currency', data.get('mc_currency'), self.currency_id.name))
if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), self.fees, 2) != 0:
invalid_parameters.append(('handling_amount', data.get('handling_amount'), self.fees))
# check buyer
if tx.payment_token_id and data.get('payer_id') != tx.payment_token_id.acquirer_ref:
invalid_parameters.append(('payer_id', data.get('payer_id'), tx.payment_token_id.acquirer_ref))
if self.payment_token_id and data.get('payer_id') != self.payment_token_id.acquirer_ref:
invalid_parameters.append(('payer_id', data.get('payer_id'), self.payment_token_id.acquirer_ref))
# check seller
if data.get('receiver_id') and tx.acquirer_id.paypal_seller_account and data['receiver_id'] != tx.acquirer_id.paypal_seller_account:
invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account))
if not data.get('receiver_id') or not tx.acquirer_id.paypal_seller_account:
if data.get('receiver_id') and self.acquirer_id.paypal_seller_account and data['receiver_id'] != self.acquirer_id.paypal_seller_account:
invalid_parameters.append(('receiver_id', data.get('receiver_id'), self.acquirer_id.paypal_seller_account))
if not data.get('receiver_id') or not self.acquirer_id.paypal_seller_account:
# Check receiver_email only if receiver_id was not checked.
# In Paypal, this is possible to configure as receiver_email a different email than the business email (the login email)
# In Odoo, there is only one field for the Paypal email: the business email. This isn't possible to set a receiver_email
# different than the business email. Therefore, if you want such a configuration in your Paypal, you are then obliged to fill
# the Merchant ID in the Paypal payment acquirer in Odoo, so the check is performed on this variable instead of the receiver_email.
# At least one of the two checks must be done, to avoid fraudsters.
if data.get('receiver_email') != tx.acquirer_id.paypal_email_account:
invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account))
if data.get('receiver_email') != self.acquirer_id.paypal_email_account:
invalid_parameters.append(('receiver_email', data.get('receiver_email'), self.acquirer_id.paypal_email_account))
return invalid_parameters
def _paypal_form_validate(self, cr, uid, ids, data, context=None):
tx = self.browse(cr, uid, ids, context=context)[0]
@api.multi
def _paypal_form_validate(self, data):
status = data.get('payment_status')
res = {
'acquirer_reference': data.get('txn_id'),
'paypal_txn_type': data.get('payment_type'),
}
if status in ['Completed', 'Processed']:
_logger.info('Validated Paypal payment for tx %s: set as done' % (tx.reference))
_logger.info('Validated Paypal payment for tx %s: set as done' % (self.reference))
res.update(state='done', date_validate=data.get('payment_date', fields.datetime.now()))
return tx.write(res)
return self.write(res)
elif status in ['Pending', 'Expired']:
_logger.info('Received notification for Paypal payment %s: set as pending' % (tx.reference))
_logger.info('Received notification for Paypal payment %s: set as pending' % (self.reference))
res.update(state='pending', state_message=data.get('pending_reason', ''))
return tx.write(res)
return self.write(res)
else:
error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (tx.reference, status)
error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (self.reference, status)
_logger.info(error)
res.update(state='error', state_message=error)
return tx.write(res)
return self.write(res)
+38 -55
View File
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from openerp.addons.payment.models.payment_acquirer import ValidationError
from openerp.addons.payment.tests.common import PaymentAcquirerCommon
from openerp.addons.payment_paypal.controllers.main import PaypalController
from openerp.tools import mute_logger
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment.tests.common import PaymentAcquirerCommon
from odoo.addons.payment_paypal.controllers.main import PaypalController
from odoo.tools import mute_logger
from lxml import objectify
import urlparse
@@ -13,12 +13,8 @@ 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')
# get the paypal account
model, self.paypal_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_paypal')
# tde+seller@openerp.com - tde+buyer@openerp.com - tde+buyer-it@openerp.com
self.paypal = self.env.ref('payment.payment_acquirer_paypal')
# some CC
self.amex = (('378282246310005', '123'), ('371449635398431', '123'))
@@ -36,26 +32,23 @@ class PaypalCommon(PaymentAcquirerCommon):
class PaypalForm(PaypalCommon):
def test_10_paypal_form_render(self):
cr, uid, context = self.cr, self.uid, {}
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
# be sure not to do stupid things
self.payment_acquirer.write(cr, uid, self.paypal_id, {'paypal_email_account': 'tde+paypal-facilitator@openerp.com', 'fees_active': False}, context)
paypal = self.payment_acquirer.browse(cr, uid, self.paypal_id, context)
self.assertEqual(paypal.environment, 'test', 'test without test environment')
self.paypal.write({'paypal_email_account': 'tde+paypal-facilitator@odoo.com', 'fees_active': False})
self.assertEqual(self.paypal.environment, 'test', 'test without test environment')
# ----------------------------------------
# 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,
values=self.buyer_values,
context=context)
res = self.paypal.render(
'test_ref0', 0.01, self.currency_euro.id,
values=self.buyer_values)
form_values = {
'cmd': '_xclick',
'business': 'tde+paypal-facilitator@openerp.com',
'business': 'tde+paypal-facilitator@odoo.com',
'item_name': 'YourCompany: test_ref0',
'item_number': 'test_ref0',
'first_name': 'Norbert',
@@ -67,9 +60,9 @@ class PaypalForm(PaypalCommon):
'zip': '1000',
'country': 'Belgium',
'email': 'norbert.buyer@example.com',
'return': '%s' % urlparse.urljoin(self.base_url, PaypalController._return_url),
'notify_url': '%s' % urlparse.urljoin(self.base_url, PaypalController._notify_url),
'cancel_return': '%s' % urlparse.urljoin(self.base_url, PaypalController._cancel_url),
'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),
}
# check form result
@@ -85,26 +78,22 @@ class PaypalForm(PaypalCommon):
)
def test_11_paypal_form_with_fees(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.environment, 'test', 'test without test environment')
self.assertEqual(self.paypal.environment, 'test', 'test without test environment')
# update acquirer: compute fees
self.payment_acquirer.write(cr, uid, self.paypal_id, {
self.paypal.write({
'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,
'test_ref0', 12.50, self.currency_euro_id,
values=self.buyer_values,
context=context)
res = self.paypal.render(
'test_ref0', 12.50, self.currency_euro.id,
values=self.buyer_values)
# check form result
handling_found = False
@@ -116,12 +105,10 @@ class PaypalForm(PaypalCommon):
self.assertEqual(form_input.get('value'), '1.57', 'paypal: wrong computed fees')
self.assertTrue(handling_found, 'paypal: fees_active did not add handling input in rendered form')
@mute_logger('openerp.addons.payment_paypal.models.paypal', 'ValidationError')
@mute_logger('openerp.addons.payment_paypal.models.payment', 'ValidationError')
def test_20_paypal_form_management(self):
cr, uid, context = self.cr, self.uid, {}
# be sure not to do stupid things
paypal = self.payment_acquirer.browse(cr, uid, self.paypal_id, context)
self.assertEqual(paypal.environment, 'test', 'test without test environment')
self.assertEqual(self.paypal.environment, 'test', 'test without test environment')
# typical data posted by paypal after client has successfully paid
paypal_post_data = {
@@ -160,7 +147,7 @@ class PaypalForm(PaypalCommon):
'address_status': u'unconfirmed',
'mc_currency': u'EUR',
'shipping': u'0.00',
'payer_email': u'tde+buyer@openerp.com',
'payer_email': u'tde+buyer@odoo.com',
'payment_type': u'instant',
'mc_gross': u'1.95',
'ipn_track_id': u'866df2ccd444b',
@@ -169,39 +156,35 @@ class PaypalForm(PaypalCommon):
# should raise error about unknown tx
with self.assertRaises(ValidationError):
self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context)
self.env['payment.transaction'].form_feedback(paypal_post_data, 'paypal')
# create tx
tx_id = self.payment_transaction.create(
cr, uid, {
'amount': 1.95,
'acquirer_id': self.paypal_id,
'currency_id': self.currency_euro_id,
'reference': 'test_ref_2',
'partner_name': 'Norbert Buyer',
'partner_country_id': self.country_france_id,
}, context=context
)
tx = self.env['payment.transaction'].create({
'amount': 1.95,
'acquirer_id': self.paypal.id,
'currency_id': self.currency_euro.id,
'reference': 'test_ref_2',
'partner_name': 'Norbert Buyer',
'partner_country_id': self.country_france.id})
# validate it
self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context)
tx.form_feedback(paypal_post_data, 'paypal')
# check
tx = self.payment_transaction.browse(cr, uid, tx_id, context=context)
self.assertEqual(tx.state, 'pending', 'paypal: wrong state after receiving a valid pending notification')
self.assertEqual(tx.state_message, 'multi_currency', 'paypal: wrong state message after receiving a valid pending notification')
self.assertEqual(tx.acquirer_reference, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification')
self.assertFalse(tx.date_validate, 'paypal: validation date should not be updated whenr receiving pending notification')
# update tx
self.payment_transaction.write(cr, uid, [tx_id], {
tx.write({
'state': 'draft',
'acquirer_reference': False,
}, context=context)
'acquirer_reference': False})
# update notification from paypal
paypal_post_data['payment_status'] = 'Completed'
# validate it
self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context)
tx.form_feedback(paypal_post_data, 'paypal')
# check
tx = self.payment_transaction.browse(cr, uid, tx_id, context=context)
self.assertEqual(tx.state, 'done', 'paypal: wrong state after receiving a valid pending notification')
self.assertEqual(tx.acquirer_reference, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification')
self.assertEqual(tx.date_validate, '2013-11-18 03:21:19', 'paypal: wrong validation date')
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<openerp>
<odoo>
<data>
<!-- Add payment options to sale.order and invoice forms -->
<record model="ir.ui.view" id="payment_paypal_option_config">
@@ -12,4 +12,4 @@
</field>
</record>
</data>
</openerp>
</odoo>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<data noupdate="1">
<template id="paypal_acquirer_button">
@@ -40,4 +40,4 @@
</template>
</data>
</openerp>
</odoo>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<data>
<record id="acquirer_form_paypal" model="ir.ui.view">
@@ -37,4 +37,4 @@
</record>
</data>
</openerp>
</odoo>