[MERGE] forward port of branch saas-6 up to 2616def
This commit is contained in:
@@ -91,7 +91,7 @@ class TestTax(AccountTestUsers):
|
||||
def test_tax_currency(self):
|
||||
self.division_tax.amount = 15.0
|
||||
res = self.division_tax.compute_all(200.0, currency=self.env.ref('base.VEF'))
|
||||
self.assertEquals(res['total_included'], 235.2941)
|
||||
self.assertAlmostEqual(res['total_included'], 235.2941)
|
||||
|
||||
def test_tax_move_lines_creation(self):
|
||||
""" Test that creating a move.line with tax_ids generates the tax move lines and adjust line amount when a tax is price_include """
|
||||
|
||||
@@ -195,6 +195,7 @@ class EscposDriver(Thread):
|
||||
localips = ['0.0.0.0','127.0.0.1','127.0.1.1']
|
||||
hosting_ap = os.system('pgrep hostapd') == 0
|
||||
ssid = subprocess.check_output('iwconfig 2>&1 | grep \'ESSID:"\' | sed \'s/.*"\\(.*\\)"/\\1/\'', shell=True).rstrip()
|
||||
mac = subprocess.check_output('ifconfig | grep -B 1 \'inet addr\' | grep -o \'HWaddr .*\' | sed \'s/HWaddr //\'', shell=True).rstrip()
|
||||
ips = [ c.split(':')[1].split(' ')[0] for c in commands.getoutput("/sbin/ifconfig").split('\n') if 'inet addr' in c ]
|
||||
ips = [ ip for ip in ips if ip not in localips ]
|
||||
eprint.text('\n\n')
|
||||
@@ -218,6 +219,7 @@ class EscposDriver(Thread):
|
||||
eprint.text(ip+'\n')
|
||||
|
||||
if len(ips) >= 1:
|
||||
eprint.text('\nMAC Address:\n' + mac + '\n')
|
||||
eprint.text('\nHomepage:\nhttp://'+ips[0]+':8069\n')
|
||||
|
||||
eprint.text('\n\n')
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<p t-if="o.address_id == o.partner_invoice_id">Invoice and shipping address:</p>
|
||||
<p t-if="o.address_id != o.partner_invoice_id">Invoice address: </p>
|
||||
<div t-field="o.partner_invoice_id"
|
||||
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true, "phone_icons": true}'/>
|
||||
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
|
||||
<strong t-if="o.address_id == o.partner_invoice_id">Invoice and shipping address:</strong>
|
||||
<div t-if="o.partner_invoice_id">
|
||||
<strong t-if="o.address_id != o.partner_invoice_id">Invoice address: </strong>
|
||||
<div t-field="o.partner_invoice_id"
|
||||
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true, "phone_icons": true}'/>
|
||||
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
|
||||
</div>
|
||||
<div t-if="o.address_id != o.partner_invoice_id">
|
||||
<p>Shipping address :</p>
|
||||
<strong>Shipping address :</strong>
|
||||
<div t-field="o.address_id"
|
||||
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true, "phone_icons": true}'/>
|
||||
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
|
||||
|
||||
@@ -388,6 +388,7 @@ var DataExport = Dialog.extend({
|
||||
},
|
||||
add_field: function(field_id, string) {
|
||||
var field_list = this.$el.find('#fields_list');
|
||||
field_id = this.records[field_id] || field_id;
|
||||
if (this.$el.find("#fields_list option[value='" + field_id + "']")
|
||||
&& !this.$el.find("#fields_list option[value='" + field_id + "']").length) {
|
||||
field_list.append(new Option(string, field_id));
|
||||
|
||||
@@ -468,7 +468,7 @@ class website(osv.osv):
|
||||
:rtype: bool
|
||||
"""
|
||||
endpoint = rule.endpoint
|
||||
methods = endpoint.routing.get('method') or ['GET']
|
||||
methods = endpoint.routing.get('methods') or ['GET']
|
||||
|
||||
converters = rule._converters.values()
|
||||
if not ('GET' in methods
|
||||
|
||||
@@ -422,28 +422,46 @@ class TestNewFields(common.TransactionCase):
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model')
|
||||
def test_41_new_related(self):
|
||||
""" test the behavior of related fields on new records. """
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
|
||||
""" test the behavior of related fields starting on new records. """
|
||||
# make discussions unreadable for demo user
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
access.write({'perm_read': False})
|
||||
|
||||
# create an environment for demo user
|
||||
demo_env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(demo_env.user.login, "demo")
|
||||
env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(env.user.login, "demo")
|
||||
|
||||
# create a new message as demo user
|
||||
values = {'discussion': discussion.id}
|
||||
message = demo_env['test_new_api.message'].new(values)
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
message = env['test_new_api.message'].new({'discussion': discussion})
|
||||
self.assertEqual(message.discussion, discussion)
|
||||
|
||||
# read the related field discussion_name
|
||||
self.assertEqual(message.discussion.env, demo_env)
|
||||
self.assertEqual(message.discussion.env, env)
|
||||
self.assertEqual(message.discussion_name, discussion.name)
|
||||
with self.assertRaises(AccessError):
|
||||
message.discussion.name
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model')
|
||||
def test_42_new_related(self):
|
||||
""" test the behavior of related fields traversing new records. """
|
||||
# make discussions unreadable for demo user
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
access.write({'perm_read': False})
|
||||
|
||||
# create an environment for demo user
|
||||
env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(env.user.login, "demo")
|
||||
|
||||
# create a new discussion and a new message as demo user
|
||||
discussion = env['test_new_api.discussion'].new({'name': 'Stuff'})
|
||||
message = env['test_new_api.message'].new({'discussion': discussion})
|
||||
self.assertEqual(message.discussion, discussion)
|
||||
|
||||
# read the related field discussion_name
|
||||
self.assertNotEqual(message.sudo().env, message.env)
|
||||
self.assertEqual(message.discussion_name, discussion.name)
|
||||
|
||||
def test_50_defaults(self):
|
||||
""" test default values. """
|
||||
fields = ['discussion', 'body', 'author', 'size']
|
||||
|
||||
+16
-5
@@ -12,6 +12,7 @@ import logging
|
||||
import pytz
|
||||
import xmlrpclib
|
||||
|
||||
from openerp.sql_db import LazyCursor
|
||||
from openerp.tools import float_round, frozendict, html_sanitize, ustr, OrderedSet
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
|
||||
@@ -41,6 +42,15 @@ def _check_value(value):
|
||||
""" Return ``value``, or call its getter if ``value`` is a :class:`SpecialValue`. """
|
||||
return value.get() if isinstance(value, SpecialValue) else value
|
||||
|
||||
def copy_cache(records, env):
|
||||
""" Recursively copy the cache of ``records`` to the environment ``env``. """
|
||||
for record, target in zip(records, records.with_env(env)):
|
||||
if not target._cache:
|
||||
for name, value in record._cache.iteritems():
|
||||
target[name] = value
|
||||
if isinstance(value, BaseModel):
|
||||
copy_cache(value, env)
|
||||
|
||||
|
||||
def resolve_mro(model, name, predicate):
|
||||
""" Return the list of successively overridden values of attribute ``name``
|
||||
@@ -560,10 +570,9 @@ class Field(object):
|
||||
# when related_sudo, bypass access rights checks when reading values
|
||||
others = records.sudo() if self.related_sudo else records
|
||||
for record, other in zip(records, others):
|
||||
if not record.id:
|
||||
if not record.id and record.env != other.env:
|
||||
# draft records: copy record's cache to other's cache first
|
||||
for name, value in record._cache.iteritems():
|
||||
other[name] = value
|
||||
copy_cache(record, other.env)
|
||||
other, field = self.traverse_related(other)
|
||||
record[self.name] = other[field.name]
|
||||
|
||||
@@ -1074,7 +1083,7 @@ class Float(Field):
|
||||
@property
|
||||
def digits(self):
|
||||
if callable(self._digits):
|
||||
with fields._get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits(cr)
|
||||
else:
|
||||
return self._digits
|
||||
@@ -1091,6 +1100,8 @@ class Float(Field):
|
||||
def convert_to_cache(self, value, record, validate=True):
|
||||
# apply rounding here, otherwise value in cache may be wrong!
|
||||
value = float(value or 0.0)
|
||||
if not validate:
|
||||
return value
|
||||
digits = self.digits
|
||||
return float_round(value, precision_digits=digits[1]) if digits else value
|
||||
|
||||
@@ -1980,7 +1991,7 @@ class Id(Field):
|
||||
raise TypeError("field 'id' cannot be assigned")
|
||||
|
||||
# imported here to avoid dependency cycle issues
|
||||
from openerp import SUPERUSER_ID, registry
|
||||
from openerp import SUPERUSER_ID
|
||||
from .exceptions import Warning, AccessError, MissingError
|
||||
from .models import check_pg_name, BaseModel, MAGIC_COLUMNS
|
||||
from .osv import fields
|
||||
|
||||
@@ -46,7 +46,7 @@ class AddonsImportHook(object):
|
||||
thus `import openerp.addons.module`.
|
||||
"""
|
||||
|
||||
def find_module(self, module_name, package_path):
|
||||
def find_module(self, module_name, package_path=None):
|
||||
module_parts = module_name.split('.')
|
||||
if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
|
||||
return self # We act as a loader too.
|
||||
|
||||
@@ -25,21 +25,18 @@ import pytz
|
||||
import re
|
||||
import xmlrpclib
|
||||
from operator import itemgetter
|
||||
from contextlib import contextmanager
|
||||
from psycopg2 import Binary
|
||||
|
||||
import openerp
|
||||
import openerp.tools as tools
|
||||
from openerp.sql_db import LazyCursor
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools import float_repr, float_round, frozendict, html_sanitize
|
||||
import json
|
||||
from openerp import SUPERUSER_ID, registry
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
@contextmanager
|
||||
def _get_cursor():
|
||||
# yield a valid cursor from any environment or create a new one if none found
|
||||
with registry().cursor() as cr:
|
||||
yield cr
|
||||
# deprecated; kept for backward compatibility only
|
||||
_get_cursor = LazyCursor
|
||||
|
||||
EMPTY_DICT = frozendict()
|
||||
|
||||
@@ -378,7 +375,7 @@ class float(_column):
|
||||
@property
|
||||
def digits(self):
|
||||
if self._digits_compute:
|
||||
with _get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits_compute(cr)
|
||||
else:
|
||||
return self._digits
|
||||
@@ -1354,7 +1351,7 @@ class function(_column):
|
||||
@property
|
||||
def digits(self):
|
||||
if self._digits_compute:
|
||||
with _get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits_compute(cr)
|
||||
else:
|
||||
return self._digits
|
||||
|
||||
@@ -456,6 +456,40 @@ class TestCursor(Cursor):
|
||||
self.execute("ROLLBACK TO SAVEPOINT test_cursor")
|
||||
self.execute("SAVEPOINT test_cursor")
|
||||
|
||||
class LazyCursor(object):
|
||||
""" A proxy object to a cursor. The cursor itself is allocated only if it is
|
||||
needed. This class is useful for cached methods, that use the cursor
|
||||
only in the case of a cache miss.
|
||||
"""
|
||||
def __init__(self, dbname=None):
|
||||
self._dbname = dbname
|
||||
self._cursor = None
|
||||
self._depth = 0
|
||||
|
||||
@property
|
||||
def dbname(self):
|
||||
return self._dbname or threading.currentThread().dbname
|
||||
|
||||
def __getattr__(self, name):
|
||||
cr = self._cursor
|
||||
if cr is None:
|
||||
from openerp import registry
|
||||
cr = self._cursor = registry(self.dbname).cursor()
|
||||
for _ in xrange(self._depth):
|
||||
cr.__enter__()
|
||||
return getattr(cr, name)
|
||||
|
||||
def __enter__(self):
|
||||
self._depth += 1
|
||||
if self._cursor is not None:
|
||||
self._cursor.__enter__()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._depth -= 1
|
||||
if self._cursor is not None:
|
||||
self._cursor.__exit__(exc_type, exc_value, traceback)
|
||||
|
||||
class PsycoConnection(psycopg2.extensions.connection):
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user