[REF] iap, various: reorganize IAP module organization

PURPOSE

Clean and improve IAP tools integration in Odoo. Introduce bridge modules
to extract common features, notably for CRM and Partner.

SPECIFICATIONS

In this commit we reorganize IAP module to better understand its content
and ease future cleaning

  * have models separated from tools;
  * rename some tools to find their grep. An iap_ prefix is added to ensure
    we don't clash with other global functions or methods;
  * perform some linting;

To provide backward compatibility support we keep some import in init file of
IAP addon. Standard code is about to be updated but we want to avoid too
much issues when migrating code to 13.5 . Compatibility layer will be removed
after v14 final freeze.

LINKS

Task ID-2248367
Community PR odoo/odoo#53214
Enterprise PR odoo/enterprise#11258
Upgrade PR odoo/upgrade#1363
IAP PR odoo/iap-apps#191
This commit is contained in:
Thibault Delavallée
2020-08-18 11:41:59 +00:00
parent 14a73fa1df
commit fcd10b3691
16 changed files with 331 additions and 307 deletions
@@ -4,8 +4,7 @@
import logging
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from odoo.addons.iap import jsonrpc, InsufficientCreditError
from odoo.addons.iap.tools import iap_tools
_logger = logging.getLogger(__name__)
@@ -180,9 +179,9 @@ class CRMLeadMiningRequest(models.Model):
'data': server_payload
}
try:
response = jsonrpc(endpoint, params=params, timeout=300)
response = iap_tools.iap_jsonrpc(endpoint, params=params, timeout=300)
return response['data']
except InsufficientCreditError as e:
except iap_tools.InsufficientCreditError as e:
self.error = 'Insufficient credits. Recharge your account and retry.'
self.state = 'error'
self._cr.commit()
@@ -5,7 +5,7 @@ import datetime
import logging
from odoo import _, api, fields, models, tools
from odoo.addons.iap import InsufficientCreditError
from odoo.addons.iap.tools import iap_tools
_logger = logging.getLogger(__name__)
@@ -58,7 +58,7 @@ class Lead(models.Model):
if lead_emails:
try:
iap_response = self.env['iap.enrich.api']._request_enrich(lead_emails)
except InsufficientCreditError:
except iap_tools.InsufficientCreditError:
_logger.info('Sent batch %s enrich requests: failed because of credit', len(lead_emails))
if not from_cron:
data = {
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, api
from odoo.addons import iap
from odoo.addons.iap.tools import iap_tools
class IapEnrichAPI(models.AbstractModel):
@@ -17,7 +17,7 @@ class IapEnrichAPI(models.AbstractModel):
params['account_token'] = account.account_token
params['dbuuid'] = dbuuid
base_url = self.env['ir.config_parameter'].sudo().get_param('enrich.endpoint', self._DEFAULT_ENDPOINT)
return iap.jsonrpc(base_url + local_endpoint, params=params, timeout=300)
return iap_tools.iap_jsonrpc(base_url + local_endpoint, params=params, timeout=300)
@api.model
def _request_enrich(self, lead_emails):
+2 -2
View File
@@ -5,7 +5,7 @@ from functools import partial
from unittest.mock import patch
from odoo import exceptions
from odoo.addons import iap
from odoo.addons.iap.tools import iap_tools
from odoo.addons.crm_iap_lead_enrich.models.iap_enrich_api import IapEnrichAPI
from odoo.tests import common, new_test_user
@@ -36,7 +36,7 @@ class MockIAPEnrich(common.BaseCase):
result = {}
for lead_id, email in params['domains'].items():
if sim_error and sim_error == 'credit':
raise iap.InsufficientCreditError('InsufficientCreditError')
raise iap_tools.InsufficientCreditError('InsufficientCreditError')
elif sim_error and sim_error == 'jsonrpc_exception':
raise exceptions.AccessError(
'The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was ' + local_endpoint
@@ -9,7 +9,7 @@ from dateutil.relativedelta import relativedelta
import odoo
from odoo import api, fields, models, tools, _
from odoo.addons.iap import jsonrpc
from odoo.addons.iap.tools import iap_tools
from odoo.addons.crm.models import crm_stage
from odoo.exceptions import ValidationError
@@ -323,7 +323,7 @@ class CRMRevealRule(models.Model):
'account_token': account_token.account_token,
'data': server_payload
}
result = jsonrpc(endpoint, params=params, timeout=300)
result = iap_tools.iap_jsonrpc(endpoint, params=params, timeout=300)
for res in result.get('reveal_data', []):
if not res.get('not_found'):
lead = self._create_lead_from_response(res)
+9 -1
View File
@@ -2,4 +2,12 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from .models.iap import jsonrpc, charge, authorize, capture, cancel, InsufficientCreditError
from . import tools
# compatibility imports
from odoo.addons.iap.tools.iap_tools import iap_jsonrpc as jsonrpc
from odoo.addons.iap.tools.iap_tools import iap_authorize as authorize
from odoo.addons.iap.tools.iap_tools import iap_cancel as cancel
from odoo.addons.iap.tools.iap_tools import iap_capture as capture
from odoo.addons.iap.tools.iap_tools import iap_charge as charge
from odoo.addons.iap.tools.iap_tools import InsufficientCreditError
+7 -7
View File
@@ -1,15 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'In-App Purchases',
'category': 'Hidden/Tools',
'version': '1.1',
'summary': 'Basic models and helpers to support In-App purchases.',
'description': """
This module provides standard tools (account model, context manager and helpers) to support In-App purchases inside Odoo.
""",
'depends': ['web', 'base_setup'],
This module provides standard tools (account model, context manager and helpers)
to support In-App purchases inside Odoo. """,
'depends': [
'web',
'base_setup'
],
'data': [
'security/ir.model.access.csv',
'security/ir_rule.xml',
@@ -17,9 +20,6 @@ This module provides standard tools (account model, context manager and helpers)
'views/iap_views.xml',
'views/res_config_settings.xml',
],
'images': [
'static/src/img/iap_logo.svg',
],
'qweb': [
'static/src/xml/iap_templates.xml',
],
+1 -2
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import iap
from . import iap_account
from . import res_config_settings
-256
View File
@@ -1,256 +0,0 @@
# -*- coding: utf-8 -*-
import contextlib
import logging
import json
import uuid
import werkzeug.urls
import requests
from odoo import api, fields, models, exceptions, _
from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap.odoo.com'
#----------------------------------------------------------
# Helpers for both clients and proxy
#----------------------------------------------------------
def get_endpoint(env):
url = env['ir.config_parameter'].sudo().get_param('iap.endpoint', DEFAULT_ENDPOINT)
return url
#----------------------------------------------------------
# Helpers for clients
#----------------------------------------------------------
class InsufficientCreditError(Exception):
pass
class AuthenticationError(Exception):
pass
def jsonrpc(url, method='call', params=None, timeout=15):
"""
Calls the provided JSON-RPC endpoint, unwraps the result and
returns JSON-RPC errors as exceptions.
"""
payload = {
'jsonrpc': '2.0',
'method': method,
'params': params,
'id': uuid.uuid4().hex,
}
_logger.info('iap jsonrpc %s', url)
try:
req = requests.post(url, json=payload, timeout=timeout)
req.raise_for_status()
response = req.json()
if 'error' in response:
name = response['error']['data'].get('name').rpartition('.')[-1]
message = response['error']['data'].get('message')
if name == 'InsufficientCreditError':
e_class = InsufficientCreditError
elif name == 'AccessError':
e_class = exceptions.AccessError
elif name == 'UserError':
e_class = exceptions.UserError
else:
raise requests.exceptions.ConnectionError()
e = e_class(message)
e.data = response['error']['data']
raise e
return response.get('result')
except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.MissingSchema, requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
raise exceptions.AccessError(
_('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s', url)
)
#----------------------------------------------------------
# Helpers for proxy
#----------------------------------------------------------
class IapTransaction(object):
def __init__(self):
self.credit = None
def authorize(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None):
endpoint = get_endpoint(env)
params = {
'account_token': account_token,
'credit': credit,
'key': key,
'description': description,
}
if dbuuid:
params.update({'dbuuid': dbuuid})
try:
transaction_token = jsonrpc(endpoint + '/iap/1/authorize', params=params)
except InsufficientCreditError as e:
if credit_template:
arguments = json.loads(e.args[0])
arguments['body'] = pycompat.to_text(env['ir.qweb']._render(credit_template))
e.args = (json.dumps(arguments),)
raise e
return transaction_token
def cancel(env, transaction_token, key):
endpoint = get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
}
r = jsonrpc(endpoint + '/iap/1/cancel', params=params)
return r
def capture(env, transaction_token, key, credit):
endpoint = get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
'credit_to_capture': credit,
}
r = jsonrpc(endpoint + '/iap/1/capture', params=params)
return r
@contextlib.contextmanager
def charge(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None):
"""
Account charge context manager: takes a hold for ``credit``
amount before executing the body, then captures it if there
is no error, or cancels it if the body generates an exception.
:param str key: service identifier
:param str account_token: user identifier
:param int credit: cost of the body's operation
:param description: a description of the purpose of the charge,
the user will be able to see it in their
dashboard
:type description: str
:param credit_template: a QWeb template to render and show to the
user if their account does not have enough
credits for the requested operation
:type credit_template: str
"""
transaction_token = authorize(env, key, account_token, credit, dbuuid, description, credit_template)
try:
transaction = IapTransaction()
transaction.credit = credit
yield transaction
except Exception as e:
r = cancel(env,transaction_token, key)
raise e
else:
r = capture(env,transaction_token, key, transaction.credit)
#----------------------------------------------------------
# Models for client
#----------------------------------------------------------
class IapAccount(models.Model):
_name = 'iap.account'
_rec_name = 'service_name'
_description = 'IAP Account'
service_name = fields.Char()
account_token = fields.Char(default=lambda s: uuid.uuid4().hex)
company_ids = fields.Many2many('res.company')
@api.model
def get(self, service_name, force_create=True):
domain = [
('service_name', '=', service_name),
'|',
('company_ids', 'in', self.env.companies.ids),
('company_ids', '=', False)
]
accounts = self.search(domain, order='id desc')
if not accounts:
with self.pool.cursor() as cr:
# Since the account did not exist yet, we will encounter a NoCreditError,
# which is going to rollback the database and undo the account creation,
# preventing the process to continue any further.
# Flush the pending operations to avoid a deadlock.
self.flush()
IapAccount = self.with_env(self.env(cr=cr))
account = IapAccount.search(domain, order='id desc', limit=1)
if not account:
if not force_create:
return account
account = IapAccount.create({'service_name': service_name})
# fetch 'account_token' into cache with this cursor,
# as self's cursor cannot see this account
account_token = account.account_token
account = self.browse(account.id)
self.env.cache.set(account, IapAccount._fields['account_token'], account_token)
return account
accounts_with_company = accounts.filtered(lambda acc: acc.company_ids)
if accounts_with_company:
return accounts_with_company[0]
return accounts[0]
@api.model
def get_credits_url(self, service_name, base_url='', credit=0, trial=False):
dbuuid = self.env['ir.config_parameter'].sudo().get_param('database.uuid')
if not base_url:
endpoint = get_endpoint(self.env)
route = '/iap/1/credit'
base_url = endpoint + route
account_token = self.get(service_name).account_token
d = {
'dbuuid': dbuuid,
'service_name': service_name,
'account_token': account_token,
'credit': credit,
}
if trial:
d.update({'trial': trial})
return '%s?%s' % (base_url, werkzeug.urls.url_encode(d))
@api.model
def get_account_url(self):
route = '/iap/services'
endpoint = get_endpoint(self.env)
d = {'dbuuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid')}
return '%s?%s' % (endpoint + route, werkzeug.urls.url_encode(d))
@api.model
def get_config_account_url(self):
account = self.env['iap.account'].get('partner_autocomplete')
action = self.env.ref('iap.iap_account_action')
menu = self.env.ref('iap.iap_account_menu')
no_one = self.user_has_groups('base.group_no_one')
if account:
url = "/web#id=%s&action=%s&model=iap.account&view_type=form&menu_id=%s" % (account.id, action.id, menu.id)
else:
url = "/web#action=%s&model=iap.account&view_type=form&menu_id=%s" % (action.id, menu.id)
return no_one and url
@api.model
def get_credits(self, service_name):
account = self.get(service_name, force_create=False)
credit = 0
if account:
route = '/iap/1/balance'
endpoint = get_endpoint(self.env)
url = endpoint + route
params = {
'dbuuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid'),
'account_token': account.account_token,
'service_name': service_name,
}
try:
credit = jsonrpc(url=url, params=params)
except Exception as e:
_logger.info('Get credit error : %s', str(e))
credit = -1
return credit
+120
View File
@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import uuid
import werkzeug.urls
from odoo import api, fields, models
from odoo.addons.iap.tools import iap_tools
_logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap.odoo.com'
class IapAccount(models.Model):
_name = 'iap.account'
_rec_name = 'service_name'
_description = 'IAP Account'
service_name = fields.Char()
account_token = fields.Char(default=lambda s: uuid.uuid4().hex)
company_ids = fields.Many2many('res.company')
@api.model
def get(self, service_name, force_create=True):
domain = [
('service_name', '=', service_name),
'|',
('company_ids', 'in', self.env.companies.ids),
('company_ids', '=', False)
]
accounts = self.search(domain, order='id desc')
if not accounts:
with self.pool.cursor() as cr:
# Since the account did not exist yet, we will encounter a NoCreditError,
# which is going to rollback the database and undo the account creation,
# preventing the process to continue any further.
# Flush the pending operations to avoid a deadlock.
self.flush()
IapAccount = self.with_env(self.env(cr=cr))
account = IapAccount.search(domain, order='id desc', limit=1)
if not account:
if not force_create:
return account
account = IapAccount.create({'service_name': service_name})
# fetch 'account_token' into cache with this cursor,
# as self's cursor cannot see this account
account_token = account.account_token
account = self.browse(account.id)
self.env.cache.set(account, IapAccount._fields['account_token'], account_token)
return account
accounts_with_company = accounts.filtered(lambda acc: acc.company_ids)
if accounts_with_company:
return accounts_with_company[0]
return accounts[0]
@api.model
def get_credits_url(self, service_name, base_url='', credit=0, trial=False):
""" Called notably by ajax crash manager, buy more widget, partner_autocomplete, sanilmail. """
dbuuid = self.env['ir.config_parameter'].sudo().get_param('database.uuid')
if not base_url:
endpoint = iap_tools.iap_get_endpoint(self.env)
route = '/iap/1/credit'
base_url = endpoint + route
account_token = self.get(service_name).account_token
d = {
'dbuuid': dbuuid,
'service_name': service_name,
'account_token': account_token,
'credit': credit,
}
if trial:
d.update({'trial': trial})
return '%s?%s' % (base_url, werkzeug.urls.url_encode(d))
@api.model
def get_account_url(self):
""" Called only by res settings """
route = '/iap/services'
endpoint = iap_tools.iap_get_endpoint(self.env)
d = {'dbuuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid')}
return '%s?%s' % (endpoint + route, werkzeug.urls.url_encode(d))
@api.model
def get_config_account_url(self):
""" Called notably by ajax partner_autocomplete. """
account = self.env['iap.account'].get('partner_autocomplete')
action = self.env.ref('iap.iap_account_action')
menu = self.env.ref('iap.iap_account_menu')
no_one = self.user_has_groups('base.group_no_one')
if account:
url = "/web#id=%s&action=%s&model=iap.account&view_type=form&menu_id=%s" % (account.id, action.id, menu.id)
else:
url = "/web#action=%s&model=iap.account&view_type=form&menu_id=%s" % (action.id, menu.id)
return no_one and url
@api.model
def get_credits(self, service_name):
account = self.get(service_name, force_create=False)
credit = 0
if account:
route = '/iap/1/balance'
endpoint = iap_tools.iap_get_endpoint(self.env)
url = endpoint + route
params = {
'dbuuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid'),
'account_token': account.account_token,
'service_name': service_name,
}
try:
credit = iap_tools.iap_jsonrpc(url=url, params=params)
except Exception as e:
_logger.info('Get credit error : %s', str(e))
credit = -1
return credit
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import iap_tools
+150
View File
@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import contextlib
import logging
import json
import requests
import uuid
from odoo import exceptions, _
from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap.odoo.com'
#----------------------------------------------------------
# Helpers for both clients and proxy
#----------------------------------------------------------
def iap_get_endpoint(env):
url = env['ir.config_parameter'].sudo().get_param('iap.endpoint', DEFAULT_ENDPOINT)
return url
#----------------------------------------------------------
# Helpers for clients
#----------------------------------------------------------
class InsufficientCreditError(Exception):
pass
def iap_jsonrpc(url, method='call', params=None, timeout=15):
"""
Calls the provided JSON-RPC endpoint, unwraps the result and
returns JSON-RPC errors as exceptions.
"""
payload = {
'jsonrpc': '2.0',
'method': method,
'params': params,
'id': uuid.uuid4().hex,
}
_logger.info('iap jsonrpc %s', url)
try:
req = requests.post(url, json=payload, timeout=timeout)
req.raise_for_status()
response = req.json()
if 'error' in response:
name = response['error']['data'].get('name').rpartition('.')[-1]
message = response['error']['data'].get('message')
if name == 'InsufficientCreditError':
e_class = InsufficientCreditError
elif name == 'AccessError':
e_class = exceptions.AccessError
elif name == 'UserError':
e_class = exceptions.UserError
else:
raise requests.exceptions.ConnectionError()
e = e_class(message)
e.data = response['error']['data']
raise e
return response.get('result')
except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.MissingSchema, requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
raise exceptions.AccessError(
_('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s', url)
)
#----------------------------------------------------------
# Helpers for proxy
#----------------------------------------------------------
class IapTransaction(object):
def __init__(self):
self.credit = None
def iap_authorize(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None):
endpoint = iap_get_endpoint(env)
params = {
'account_token': account_token,
'credit': credit,
'key': key,
'description': description,
}
if dbuuid:
params.update({'dbuuid': dbuuid})
try:
transaction_token = iap_jsonrpc(endpoint + '/iap/1/authorize', params=params)
except InsufficientCreditError as e:
if credit_template:
arguments = json.loads(e.args[0])
arguments['body'] = pycompat.to_text(env['ir.qweb']._render(credit_template))
e.args = (json.dumps(arguments),)
raise e
return transaction_token
def iap_cancel(env, transaction_token, key):
endpoint = iap_get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
}
r = iap_jsonrpc(endpoint + '/iap/1/cancel', params=params)
return r
def iap_capture(env, transaction_token, key, credit):
endpoint = iap_get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
'credit_to_capture': credit,
}
r = iap_jsonrpc(endpoint + '/iap/1/capture', params=params)
return r
@contextlib.contextmanager
def iap_charge(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None):
"""
Account charge context manager: takes a hold for ``credit``
amount before executing the body, then captures it if there
is no error, or cancels it if the body generates an exception.
:param str key: service identifier
:param str account_token: user identifier
:param int credit: cost of the body's operation
:param description: a description of the purpose of the charge,
the user will be able to see it in their
dashboard
:type description: str
:param credit_template: a QWeb template to render and show to the
user if their account does not have enough
credits for the requested operation
:type credit_template: str
"""
transaction_token = iap_authorize(env, key, account_token, credit, dbuuid, description, credit_template)
try:
transaction = IapTransaction()
transaction.credit = credit
yield transaction
except Exception as e:
r = iap_cancel(env,transaction_token, key)
raise e
else:
r = iap_capture(env,transaction_token, key, transaction.credit)
@@ -4,9 +4,9 @@
import logging
import json
from odoo import api, fields, models, exceptions, _
from odoo.addons.iap import jsonrpc
from odoo.addons.iap.tools import iap_tools
# TDE FIXME: check those errors at iap level ?
from requests.exceptions import ConnectionError, HTTPError
from odoo.addons.iap.models.iap import InsufficientCreditError
_logger = logging.getLogger(__name__)
@@ -96,11 +96,11 @@ class ResPartner(models.Model):
'zip': self.env.company.zip,
})
try:
return jsonrpc(url=url, params=params, timeout=timeout), False
return iap_tools.iap_jsonrpc(url=url, params=params, timeout=timeout), False
except (ConnectionError, HTTPError, exceptions.AccessError, exceptions.UserError) as exception:
_logger.error('Autocomplete API error: %s' % str(exception))
return False, str(exception)
except InsufficientCreditError as exception:
except iap_tools.InsufficientCreditError as exception:
_logger.warning('Insufficient Credits for Autocomplete Service: %s' % str(exception))
return False, 'Insufficient Credit'
+2 -2
View File
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
from odoo.addons.iap.models import iap
from odoo.addons.iap.tools import iap_tools
DEFAULT_ENDPOINT = 'https://iap-sms.odoo.com'
@@ -17,7 +17,7 @@ class SmsApi(models.AbstractModel):
params['account_token'] = account.account_token
endpoint = self.env['ir.config_parameter'].sudo().get_param('sms.endpoint', DEFAULT_ENDPOINT)
# TODO PRO, the default timeout is 15, do we have to increase it ?
return iap.jsonrpc(endpoint + local_endpoint, params=params)
return iap_tools.iap_jsonrpc(endpoint + local_endpoint, params=params)
@api.model
def _send_sms(self, numbers, message):
+2 -2
View File
@@ -4,7 +4,7 @@ import re
import base64
from odoo import fields, models, api, _
from odoo.addons.iap import jsonrpc
from odoo.addons.iap.tools import iap_tools
from odoo.tools.safe_eval import safe_eval
DEFAULT_ENDPOINT = 'https://iap-snailmail.odoo.com'
@@ -335,7 +335,7 @@ class SnailmailLetter(models.Model):
endpoint = self.env['ir.config_parameter'].sudo().get_param('snailmail.endpoint', DEFAULT_ENDPOINT)
timeout = int(self.env['ir.config_parameter'].sudo().get_param('snailmail.timeout', DEFAULT_TIMEOUT))
params = self._snailmail_create('print')
response = jsonrpc(endpoint + PRINT_ENDPOINT, params=params, timeout=timeout)
response = iap_tools.iap_jsonrpc(endpoint + PRINT_ENDPOINT, params=params, timeout=timeout)
for doc in response['request']['documents']:
if doc.get('sent') and response['request_code'] == 200:
note = _('The document was correctly sent by post.<br>The tracking id is %s', doc['send_id'])
+21 -21
View File
@@ -289,9 +289,9 @@ server*.
There are no requirements when it comes to the server or the communication
protocol between the app and our server, but ``iap`` provides a
:func:`~odoo.addons.iap.jsonrpc` helper to call a JSON-RPC2_ endpoint on an
:func:`~odoo.addons.iap.tools.iap_tools.iap_jsonrpc` helper to call a JSON-RPC2_ endpoint on an
other Odoo instance and transparently re-raise relevant Odoo exceptions
(:class:`~odoo.addons.iap.models.iap.InsufficientCreditError`,
(:class:`~odoo.addons.iap.tools.iap_tools.InsufficientCreditError`,
:class:`odoo.exceptions.AccessError` and :class:`odoo.exceptions.UserError`).
In that call, we will need to provide:
@@ -308,17 +308,17 @@ In that call, we will need to provide:
.. note::
``iap`` automatically handles
:class:`~odoo.addons.iap.models.iap.InsufficientCreditError` coming from the action
:class:`~odoo.addons.iap.tools.iap_tools.InsufficientCreditError` coming from the action
and prompts the user to add credits to their account.
:func:`~odoo.addons.iap.jsonrpc` takes care of re-raising
:func:`~odoo.addons.iap.tools.iap_tools.iap_jsonrpc` takes care of re-raising
:class:`~odoo.addons.iap.models.iap.InsufficientCreditError` for you.
.. danger::
If you are not using :func:`~odoo.addons.iap.jsonrpc` you *must* be
If you are not using :func:`~odoo.addons.iap.tools.iap_tools.iap_jsonrpc` you *must* be
careful to re-raise
:class:`~odoo.addons.iap.models.iap.InsufficientCreditError` in your handler
:class:`~odoo.addons.iap.tools.iap_tools.InsufficientCreditError` in your handler
otherwise the user will not be prompted to credit their account, and the
next call will fail the same way.
@@ -330,14 +330,14 @@ Service
.. queue:: iap_service/series
Though that is not *required*, since ``iap`` provides both a client helper
for JSON-RPC2_ calls (:func:`~odoo.addons.iap.jsonrpc`) and a service helper
for transactions (:class:`~odoo.addons.iap.models.iap.charge`) we will also be
for JSON-RPC2_ calls (:func:`~odoo.addons.iap.tools.iap_tools.iap_jsonrpc`) and a service helper
for transactions (:class:`~odoo.addons.iap.tools.iap_tools.iap_charge`) we will also be
implementing the service side as an Odoo module:
.. patch::
Since the query from the client comes as JSON-RPC2_ we will need the
corresponding controller which can call :class:`~odoo.addons.iap.models.iap.charge` and
corresponding controller which can call :class:`~odoo.addons.iap.tools.iap_tools.iap_charge` and
perform the service within:
.. patch::
@@ -347,7 +347,7 @@ perform the service within:
.. todo:: "My Account" > "Your InApp Services"?
The :class:`~odoo.addons.iap.models.iap.charge` helper will:
The :class:`~odoo.addons.iap.tools.iap_tools.iap_charge` helper will:
1. authorize (create) a transaction with the specified number of credits,
if the account does not have enough credits it will raise the relevant
@@ -361,7 +361,7 @@ The :class:`~odoo.addons.iap.models.iap.charge` helper will:
.. danger::
By default, :class:`~odoo.addons.iap.models.iap.charge` contacts the *production*
By default, :class:`~odoo.addons.iap.tools.iap_tools.iap_charge` contacts the *production*
IAP endpoint, https://iap.odoo.com. While developing and testing your
service you may want to point it towards the *development* IAP endpoint
https://iap-sandbox.odoo.com.
@@ -371,7 +371,7 @@ The :class:`~odoo.addons.iap.models.iap.charge` helper will:
Parameters --> System Parameters`, just define an entry for the key
``iap.endpoint`` if none already exists).
The :class:`~odoo.addons.iap.models.iap.charge` helper has two additional optional
The :class:`~odoo.addons.iap.tools.iap_tools.iap_charge` helper has two additional optional
parameters we can use to make things clearer to the end-user.
``description``
@@ -543,7 +543,7 @@ care how they are implemented.
Transaction identifier, returned by the authorization process and consumed
by either capturing or cancelling the transaction.
.. exception:: odoo.addons.iap.models.iap.InsufficientCreditError
.. exception:: odoo.addons.iap.tools.iap_tools.InsufficientCreditError
Raised during transaction authorization if the credits requested are not
currently available on the account (either not enough credits or too many
@@ -555,7 +555,7 @@ care how they are implemented.
Raised by:
* any operation to which a service token is required, if the service token is invalid; or
* any failure in an inter-server call. (typically, in :func:`~odoo.addons.iap.jsonrpc`).
* any failure in an inter-server call. (typically, in :func:`~odoo.addons.iap.tools.iap_tools.iap_jsonrpc`).
.. exception:: odoo.exceptions.UserError
:noindex:
@@ -576,9 +576,9 @@ In order to test the developped app, we propose a sandbox platform that allows y
The latter consists in specific tokens that will work on **IAP-Sandbox only**.
* Token ``000000``: Represents a non-existing account. Returns
an :class:`~odoo.addons.iap.models.iap.InsufficientCreditError` on authorize attempt.
an :class:`~odoo.addons.iap.tools.iap_tools.InsufficientCreditError` on authorize attempt.
* Token ``000111``: Represents an account without sufficient credits to perform any service.
Returns an :class:`~odoo.addons.iap.models.iap.InsufficientCreditError` on authorize attempt.
Returns an :class:`~odoo.addons.iap.tools.iap_tools.InsufficientCreditError` on authorize attempt.
* Token ``111111``: Represents an account with enough credits to perform any service.
An authorize attempt will return a dummy transacion token that is processed by the capture
and cancel routes.
@@ -600,7 +600,7 @@ module provides a few helpers to make IAP flow even simpler.
Charging
--------
.. class:: odoo.addons.iap.models.iap.charge(env, key, account_token, credit[, dbuuid, description, credit_template])
.. class:: odoo.addons.iap.tools.iap_tools.iap_charge(env, key, account_token, credit[, dbuuid, description, credit_template])
A *context manager* for authorizing and automatically capturing or
cancelling transactions for use in the backend/proxy.
@@ -633,7 +633,7 @@ Charging
"""
credits = int(MAXIMUM_POWER * factor)
description = "We will demonstrate the power of this station on your home planet of Alderaan."
with charge(request.env, SERVICE_KEY, user_account, credits, description) as transaction:
with iap_charge(request.env, SERVICE_KEY, user_account, credits, description) as transaction:
# TODO: allow other targets
transaction.credit = max(credits, 2)
# Sales ongoing one the energy price,
@@ -647,7 +647,7 @@ Charging
Authorize
---------
.. class:: odoo.addons.iap.models.iap.authorize(env, key, account_token, credit[, dbuuid, description, credit_template])
.. class:: odoo.addons.iap.tools.iap_tools.iap_authorize(env, key, account_token, credit[, dbuuid, description, credit_template])
Will authorize everything.
@@ -688,7 +688,7 @@ Authorize
Cancel
------
.. class:: odoo.addons.iap.models.iap.cancel(env, transaction_token, key)
.. class:: odoo.addons.iap.tools.iap_tools.iap_cancel(env, transaction_token, key)
Will cancel an authorized transaction.
@@ -726,7 +726,7 @@ Cancel
Capture
-------
.. class:: odoo.addons.iap.models.iap.capture(env, transaction_token, key, credit)
.. class:: odoo.addons.iap.tools.iap_tools.iap_capture(env, transaction_token, key, credit)
Will capture the amount ``credit`` on the given transaction.