From 1a1e3463023947db05d6c0e9b371e161253d4cbf Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 4 Mar 2010 10:44:58 +0100 Subject: [PATCH 01/47] [IMP] yaml test: init bzr revid: jth@openerp.com-20100304094458-oru0mdc523veqsbp --- bin/addons/__init__.py | 2 + bin/netsvc.py | 12 +- bin/tools/__init__.py | 1 + bin/tools/yaml_test.py | 406 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 bin/tools/yaml_test.py diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 2910b9fe7c1..ebf0c2fcd05 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -644,6 +644,8 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): new_query = ' '.join(query.split()) if new_query: cr.execute(new_query) + elif ext == '.yaml': + tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs) else: tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs) fp.close() diff --git a/bin/netsvc.py b/bin/netsvc.py index d8548db5d6a..eae53826a74 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -127,6 +127,7 @@ class ExportService(object): LOG_NOTSET = 'notset' LOG_DEBUG_RPC = 'debug_rpc' LOG_DEBUG = 'debug' +LOG_TEST = 'test' LOG_INFO = 'info' LOG_WARNING = 'warn' LOG_ERROR = 'error' @@ -135,6 +136,9 @@ LOG_CRITICAL = 'critical' logging.DEBUG_RPC = logging.DEBUG - 2 logging.addLevelName(logging.DEBUG_RPC, 'DEBUG_RPC') +logging.TEST = logging.INFO - 5 +logging.addLevelName(logging.TEST, 'TEST') + def init_logger(): import os from tools.translate import resetlocale @@ -195,6 +199,7 @@ def init_logger(): 'DEBUG_RPC': ('blue', 'white'), 'DEBUG': ('blue', 'default'), 'INFO': ('green', 'default'), + 'TEST': ('white', 'blue'), 'WARNING': ('yellow', 'default'), 'ERROR': ('red', 'default'), 'CRITICAL': ('white', 'red'), @@ -220,9 +225,10 @@ class Logger(object): log = logging.getLogger(tools.ustr(name)) - if level == LOG_DEBUG_RPC and not hasattr(log, level): - fct = lambda msg, *args, **kwargs: log.log(logging.DEBUG_RPC, msg, *args, **kwargs) - setattr(log, LOG_DEBUG_RPC, fct) + if level in [LOG_DEBUG_RPC, LOG_TEST] and not hasattr(log, level): + fct = lambda msg, *args, **kwargs: log.log(getattr(logging, level.upper()), msg, *args, **kwargs) + setattr(log, level, fct) + level_method = getattr(log, level) diff --git a/bin/tools/__init__.py b/bin/tools/__init__.py index 9b7bb84a57f..78c77edf394 100644 --- a/bin/tools/__init__.py +++ b/bin/tools/__init__.py @@ -24,6 +24,7 @@ import win32 from config import * from misc import * from convert import * +from yaml_test import * from translate import * from graph import graph from amount_to_text import * diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py new file mode 100644 index 00000000000..52ce059a5fd --- /dev/null +++ b/bin/tools/yaml_test.py @@ -0,0 +1,406 @@ +# -*- encoding: utf-8 -*- +import types +import yaml +import time # used to eval time.strftime expressions +import logging + +import pooler +import netsvc + +from config import config + +logger_channel = 'tests' + +class YamlImportException(Exception): + pass + +class YamlImportAbortion(Exception): + pass + +class YamlTag(object): + """Superclass for constructors of custom tags defined in yaml file.""" + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + def __getitem__(self, key): + return getattr(self, key) + def __getattr__(self, attr): + return None + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items())) + +class Assert(YamlTag): + def __init__(self, model, id, severity=netsvc.LOG_ERROR, string="NONAME", **kwargs): + self.model = model + self.id = id + self.severity = severity + self.string = string + super(Assert, self).__init__(**kwargs) + +class Record(YamlTag): + def __init__(self, model, id, **kwargs): + self.model = model + self.id = id + super(Record, self).__init__(**kwargs) + +class Python(YamlTag): + def __init__(self, model, severity=netsvc.LOG_ERROR, name="NONAME", **kwargs): + self.model= model + self.severity = severity + self.name = name + super(Python, self).__init__(**kwargs) + +class Workflow(YamlTag): + def __init__(self, model, action, **kwargs): + self.model = model + self.action = action + super(Workflow, self).__init__(**kwargs) + +class Context(YamlTag): + def __init__(self, **kwargs): + super(Context, self).__init__(**kwargs) + +class Eval(YamlTag): + def __init__(self, expression): + self.expression = expression + super(Eval, self).__init__() + +class Ref(YamlTag): + def __init__(self, xmlid): + self.xmlid = xmlid + super(Ref, self).__init__() + +def assert_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Assert(**kwargs) + +def record_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Record(**kwargs) + +def python_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Python(**kwargs) + +def workflow_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Workflow(**kwargs) + +def context_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Context(**kwargs) + +def eval_constructor(loader, node): + expression = loader.construct_scalar(node) + return Eval(expression) + +def ref_constructor(loader, node): + xmlid = loader.construct_scalar(node) + return Ref(xmlid) + +yaml.add_constructor(u"!assert", assert_constructor) +yaml.add_constructor(u"!record", record_constructor) +yaml.add_constructor(u"!python", python_constructor) +yaml.add_constructor(u"!workflow", workflow_constructor) +yaml.add_constructor(u"!context", context_constructor) +yaml.add_constructor(u"!eval", eval_constructor) +yaml.add_constructor(u"!ref", ref_constructor) + +def _is_yaml_mapping(node, tag_constructor): + value = isinstance(node, types.DictionaryType) \ + and len(node.keys()) == 1 \ + and isinstance(node.keys()[0], tag_constructor) + return value + +def is_comment(node): + return isinstance(node, types.StringTypes) + +def is_assert(node): + return _is_yaml_mapping(node, Assert) + +def is_record(node): + return _is_yaml_mapping(node, Record) + +def is_python(node): + return _is_yaml_mapping(node, Python) + +def is_workflow(node): + return isinstance(node, Workflow) \ + or _is_yaml_mapping(node, Workflow) + +def is_context(node): + return isinstance(node, Context) + +def is_eval(node): + return isinstance(node, Eval) + +def is_ref(node): + return isinstance(node, Ref) + + +class TestReport(object): + def __init__(self): + self._report = {} + + def record(self, success, severity): + """Records the result of an assertion for the failed/success count. + Returns success.""" + + if severity in self._report: + self._report[severity][success] += 1 + else: + self._report[severity] = {success: 1, not success: 0} + return success + + def __str__(self): + res = [] + res.append('\nAssertions report:\nLevel\tsuccess\tfailed') + success = failure = 0 + for severity in self._report: + res.append("%s\t%s\t%s" % (severity, self._report[severity][True], self._report[severity][False])) + success += self._report[severity][True] + failure += self._report[severity][False] + res.append("total\t%s\t%s" % (success, failure)) + res.append("end of report (%s assertion(s) checked)" % success + failure) + return "\n".join(res) + + +class YamlInterpreter(object): + def __init__(self, cr, module, id_map, mode, filename, noupdate=False): + self.cr = cr + self.module = module + self.id_map = id_map + self.mode = mode + self.filename = filename + self.assert_report = TestReport() + self.noupdate = noupdate + self.logger = netsvc.Logger() + self.pool = pooler.get_pool(cr.dbname) + self.uid = 1 + self.context = {} + + def _ref(self): + return lambda xml_id: self.get_id(xml_id) + + def get_model(self, model_name): + model = self.pool.get(model_name) + assert model, "The model %s does not exist." % (model_name,) + return model + + def validate_xml_id(self, xml_id): + id = xml_id + if '.' in xml_id: + module, id = xml_id.split('.', 1) + assert '.' not in id, "The ID reference '%s' must contains maximum one dot.\n" \ + "It is used to refer to other modules ID, in the form: module.record_id" \ + % (xml_id,) + if module != self.module: + module_count = self.pool.get('ir.module.module').search_count(self.cr, self.uid, \ + ['&', ('name', '=', module), ('state', 'in', ['installed'])]) + assert module_count == 1, """The ID "%s" refers to an uninstalled module""" % (xml_id,) + if len(id) > 64: # TODO where does 64 come from (DB is 128)? should be a constant or loaded form DB + self.logger.notifyChannel(logger_channel, netsvc.LOG_ERROR, 'id: %s is to long (max: 64)' % (id,)) + + def get_id(self, xml_id): + if isinstance(xml_id, types.IntType): + id = xml_id + elif xml_id in self.id_map: + id = self.id_map[xml_id] + else: + if '.' in xml_id: + module, xml_id = xml_id.split('.', 1) + else: + module = self.module + ir_id = self.pool.get('ir.model.data')._get_id(self.cr, self.uid, module, xml_id) + obj = self.pool.get('ir.model.data').read(self.cr, self.uid, ir_id, ['res_id']) + id = int(obj['res_id']) + self.id_map[xml_id] = id + return id + + def process_comment(self, node): + return node + + def _log_assert_failure(self, severity, msg, *args): + self.assert_report.record(False, severity) + self.logger.notifyChannel(logger_channel, severity, msg % (args)) + if getattr(logging, severity.upper()) >= config['assert_exit_level']: + raise YamlImportAbortion('Severe assertion failure (%s), aborting.' % (severity,)) + return + + def _get_assertion_id(self, assertion): + if assertion.id: + ids = [self.get_id(assertion.id)] + elif assertion.search: + q = eval(assertion.search, {'ref': self._ref}) + ids = self.pool.get(assertion.model).search(self.cr, self.uid, q, context=assertion.context) + if not ids: + raise YamlImportException('Nothing to assert: you must give either an id or a search criteria.') + return ids + + def process_assert(self, node): + assertion, expressions = node.items()[0] + + model = self.get_model(assertion.model) + ids = self._get_assertion_id(assertion) + if assertion.count and len(ids) != assertion.count: + msg = 'assertion "%s" failed!\n' \ + ' Incorrect search count:\n' \ + ' expected count: %d\n' \ + ' obtained count: %d\n' + args = (assertion.string, assertion.count, len(ids)) + self._log_assert_failure(assertion.severity, msg, *args) + else: + test_context = {'ref': self._ref, '_ref': self._ref} # added '_ref' so that record['ref'] is possible + for id in ids: + record = model.browse(self.cr, self.uid, id, assertion.context) + for test in expressions.get('test', ''): + success = eval(test, test_context, record) + if not success: + msg = 'Assertion "%s" FAILED\ntest: %s\n' + args = (assertion.string, test) + self._log_assert_failure(assertion.severity, msg, *args) + return + else: # all tests were successful for this assertion tag (no break) + self.assert_report.record(True, assertion.severity) + + def process_record(self, node): + record, fields = node.items()[0] + + self.validate_xml_id(record.id) + model = self.get_model(record.model) + record_dict = self._create_record(model, fields) + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \ + self.module, record_dict, record.id, mode=self.mode) + self.id_map[record.id] = int(id) + if config.get('import_partial', False): + self.cr.commit() + + def _create_record(self, model, fields): + record_dict = {} + for field_name, expression in fields.items(): + field_value = self._eval_field(model, field_name, expression) + record_dict[field_name] = field_value + return record_dict + + def _eval_field(self, model, field_name, expression): + column = model._columns[field_name] + if column._type == "many2one": + value = self.get_id(expression) + elif column._type == "one2many": + other_model = self.get_model(column._obj) + value = [(0, 0, self._create_record(other_model, fields)) for fields in expression] + elif column._type == "many2many": + ids = [self.get_id(xml_id) for xml_id in expression] + value= [(6, 0, ids)] + else: # scalar field + if isinstance(expression, Eval): + value = eval(expression.expression) + else: + value = expression + # raise YamlImportException('Unsupported column "%s" or value %s:%s' % (field_name, type(expression), expression)) + return value + + def process_context(self, node): + self.context = node.__dict__ + if 'uid' in node.__dict__: + self.uid = self.get_id(node.__dict__['uid']) + + def process_python(self, node): + def log(msg): + self.logger.notifyChannel(logger_channel, netsvc.LOG_TEST, msg) + python, statements = node.items()[0] + model = self.get_model(python.model) + statements = statements.replace("\r\n", "\n").replace("\n", ";") + code_context = {'self': model, 'cr': self.cr, 'uid': self.uid, 'log': log, 'context': self.context} + try: + code = compile(statements, self.filename, 'exec') + eval(code, code_context) + except Exception, e: + raise YamlImportException(e) + # TODO log success/failure + + def process_workflow(self, node): + workflow, values = node.items()[0] + model = self.get_model(workflow.model) + if workflow.ref: + id = self.get_id(workflow.ref) + else: + if not values: + raise YamlImportException('You must define a child node if you do not give a ref.') + if not len(values) == 1: + raise YamlImportException('Only one child node is accepted (%d given).' % len(values)) + value = values[0] + if not 'model' in value and not 'eval' in value: + raise YamlImportException('You must provide a model and an expression to evaluate for the workflow.') + value_model = self.get_model(value['model']) + local_context = {'ref': self._ref, '_ref': self._ref} + local_context['obj'] = lambda x: value_model.browse(self.cr, self.uid, x, context=self.context) + local_context.update(self.id_map) + id = eval(value['eval'], local_context) + + if workflow.uid is not None: + uid = workflow.uid + else: + uid = self.uid + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, model, id, workflow.action, self.cr) + + def process(self, yaml_string): + """Processes a Yaml string. Custom tags are interpreted by 'process_' instance methods.""" + + is_preceded_by_comment = False + for node in yaml.load(yaml_string): + is_preceded_by_comment = self._log(node, is_preceded_by_comment) + try: + self._process_node(node) + except YamlImportException, e: + self.logger.notifyChannel(logger_channel, netsvc.LOG_ERROR, e) + except YamlImportAbortion, e: + self.logger.notifyChannel(logger_channel, netsvc.LOG_ERROR, e) + return + + def _process_node(self, node): + if is_comment(node): + self.process_comment(node) + elif is_assert(node): + self.process_assert(node) + elif is_record(node): + self.process_record(node) + elif is_python(node): + self.process_python(node) + elif is_context(node): + self.process_context(node) + elif is_workflow(node): + if isinstance(node, types.DictionaryType): + self.process_workflow(node) + else: + self.process_workflow({node: []}) + else: + raise YamlImportException("Can not process YAML block: %s" % node) + + def _log(self, node, is_preceded_by_comment): + if is_comment(node): + is_preceded_by_comment = True + self.logger.notifyChannel(logger_channel, netsvc.LOG_TEST, node) + elif not is_preceded_by_comment: + if isinstance(node, types.DictionaryType): + k, v = node.items()[0] + msg = "Creating %s\n with %s" % (k, v) + self.logger.notifyChannel(logger_channel, netsvc.LOG_TEST, msg) + else: + self.logger.notifyChannel(logger_channel, netsvc.LOG_TEST, node) + else: + is_preceded_by_comment = False + return is_preceded_by_comment + +def yaml_import(cr, module, yamlfile, idref=None, mode='init', noupdate=False, report=None): + if idref is None: + idref = {} + yaml_string = yamlfile.read() + yaml_interpreter = YamlInterpreter(cr, module, idref, mode, filename=yamlfile.name, noupdate=noupdate) + yaml_interpreter.process(yaml_string) + +# keeps convention of convert.py +convert_yaml_import = yaml_import + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From b8b60d44363c0062e0588178dc02d641baacb5e3 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 4 Mar 2010 11:03:55 +0100 Subject: [PATCH 02/47] [FIX] YAML files have '.yml' extension, not '.yaml' bzr revid: jth@openerp.com-20100304100355-0je51f1c0261b25u --- bin/addons/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index ebf0c2fcd05..8137a7fecbb 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -644,7 +644,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): new_query = ' '.join(query.split()) if new_query: cr.execute(new_query) - elif ext == '.yaml': + elif ext == '.yml': tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs) else: tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs) From b8ebcf689bb31ca3cbefbd954c9d742c0a59c4e0 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 4 Mar 2010 16:41:59 +0100 Subject: [PATCH 03/47] [IMP] Record python block success in assertion report. bzr revid: jth@openerp.com-20100304154159-m1i6zuqsvg08s1vi --- bin/tools/yaml_test.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index 52ce059a5fd..b91e457791e 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -315,9 +315,15 @@ class YamlInterpreter(object): try: code = compile(statements, self.filename, 'exec') eval(code, code_context) + except AssertionError, e: + msg = 'Assertion "%s" FAILED in Python code.' + args = (python.name,) + self._log_assert_failure(python.severity, msg, *args) + return except Exception, e: - raise YamlImportException(e) - # TODO log success/failure + raise YamlImportAbortion(e) + else: + self.assert_report.record(True, python.severity) def process_workflow(self, node): workflow, values = node.items()[0] From af48a29843cabc84880e3fdbd35dd7360a0d8ff1 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 5 Mar 2010 10:12:18 +0100 Subject: [PATCH 04/47] [IMP] Added more syntax. bzr revid: jth@openerp.com-20100305091218-2t25717pfnw6iie8 --- bin/tools/yaml_test.py | 284 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 279 insertions(+), 5 deletions(-) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index b91e457791e..5cee9b92d5e 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -50,16 +50,45 @@ class Python(YamlTag): self.name = name super(Python, self).__init__(**kwargs) +class Menuitem(YamlTag): + def __init__(self, id, name, **kwargs): + self.id = id + self.name = name + super(Menuitem, self).__init__(**kwargs) + class Workflow(YamlTag): def __init__(self, model, action, **kwargs): self.model = model self.action = action super(Workflow, self).__init__(**kwargs) +class ActWindow(YamlTag): + def __init__(self, model, action, **kwargs): + self.model = model + self.action = action + super(Workflow, self).__init__(**kwargs) + +class Function(YamlTag): + def __init__(self, model, name, **kwargs): + self.model = model + self.name = name + super(Function, self).__init__(**kwargs) + +class Delete(YamlTag): + def __init__(self, model, id, search, **kwargs): + self.model = model + self.id = id + self.search = search + super(Delete, self).__init__(**kwargs) + class Context(YamlTag): def __init__(self, **kwargs): super(Context, self).__init__(**kwargs) +class Url(YamlTag): + def __init__(self, **kwargs): + super(Url, self).__init__(**kwargs) + class Eval(YamlTag): def __init__(self, expression): self.expression = expression @@ -82,14 +111,34 @@ def python_constructor(loader, node): kwargs = loader.construct_mapping(node) return Python(**kwargs) +def menuitem_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Menuitem(**kwargs) + def workflow_constructor(loader, node): kwargs = loader.construct_mapping(node) return Workflow(**kwargs) +def act_window_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return ActWindow(**kwargs) + +def function_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Function(**kwargs) + +def delete_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Delete(**kwargs) + def context_constructor(loader, node): kwargs = loader.construct_mapping(node) return Context(**kwargs) +def url_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Url(**kwargs) + def eval_constructor(loader, node): expression = loader.construct_scalar(node) return Eval(expression) @@ -101,8 +150,13 @@ def ref_constructor(loader, node): yaml.add_constructor(u"!assert", assert_constructor) yaml.add_constructor(u"!record", record_constructor) yaml.add_constructor(u"!python", python_constructor) +yaml.add_constructor(u"!menuitem", menuitem_constructor) yaml.add_constructor(u"!workflow", workflow_constructor) +yaml.add_constructor(u"!act_window", act_window_constructor) +yaml.add_constructor(u"!function", function_constructor) yaml.add_constructor(u"!context", context_constructor) +yaml.add_constructor(u"!delete", delete_constructor) +yaml.add_constructor(u"!url", url_constructor) yaml.add_constructor(u"!eval", eval_constructor) yaml.add_constructor(u"!ref", ref_constructor) @@ -124,13 +178,29 @@ def is_record(node): def is_python(node): return _is_yaml_mapping(node, Python) +def is_menuitem(node): + return isinstance(node, Menuitem) \ + or _is_yaml_mapping(node, Menuitem) + +def is_function(node): + return isinstance(node, Function) \ + or _is_yaml_mapping(node, Function) + def is_workflow(node): - return isinstance(node, Workflow) \ - or _is_yaml_mapping(node, Workflow) + return isinstance(node, Workflow) + +def is_act_window(node): + return isinstance(node, ActWindow) + +def is_delete(node): + return isinstance(node, Delete) def is_context(node): return isinstance(node, Context) +def is_url(node): + return isinstance(node, Url) + def is_eval(node): return isinstance(node, Eval) @@ -154,7 +224,7 @@ class TestReport(object): def __str__(self): res = [] - res.append('\nAssertions report:\nLevel\tsuccess\tfailed') + res.append('\nAssertions report:\nLevel\tsuccess\tfailure') success = failure = 0 for severity in self._report: res.append("%s\t%s\t%s" % (severity, self._report[severity][True], self._report[severity][False])) @@ -217,6 +287,12 @@ class YamlInterpreter(object): self.id_map[xml_id] = id return id + def get_context(self, node, locals_dict): + context = self.context.copy() + if node.context: + context.update(eval(node.context, locals_dict)) + return context + def process_comment(self, node): return node @@ -336,8 +412,8 @@ class YamlInterpreter(object): if not len(values) == 1: raise YamlImportException('Only one child node is accepted (%d given).' % len(values)) value = values[0] - if not 'model' in value and not 'eval' in value: - raise YamlImportException('You must provide a model and an expression to evaluate for the workflow.') + if not 'model' in value and (not 'eval' in value or not 'search' in value): + raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.') value_model = self.get_model(value['model']) local_context = {'ref': self._ref, '_ref': self._ref} local_context['obj'] = lambda x: value_model.browse(self.cr, self.uid, x, context=self.context) @@ -350,7 +426,192 @@ class YamlInterpreter(object): uid = self.uid wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, model, id, workflow.action, self.cr) + + def process_function(self, node): + if self.mode != 'init': + return + function, values = node.items()[0] + local_context = {'ref': self._ref, '_ref': self._ref} + context = self.get_context(node, local_context) + args = [] + if function.eval: + args = eval(function.eval, local_context) + for value in values: + if not 'model' in value and (not 'eval' in value or not 'search' in value): + raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.') + value_model = self.get_model(value['model']) + local_context = {'ref': self._ref, '_ref': self._ref} + local_context['obj'] = lambda x: value_model.browse(self.cr, self.uid, x, context=context) + local_context.update(self.id_map) + id = eval(value['eval'], local_context) + if id != None: + args.append(id) + model = self.get_model(function.model) + method = function.name + getattr(model, method)(self.cr, self.uid, *args) + def _set_group_values(self, node, values): + if node.groups: + group_names = node.groups.split(',') + groups_value = [] + for group in group_names: + if group.startswith('-'): + group_id = self.get_id(group[1:]) + groups_value.append((3, group_id)) + else: + group_id = self.get_id(group) + groups_value.append((4, group_id)) + values['groups_id'] = groups_value + + def process_menuitem(self, node): + self.validate_xml_id(node.id) + + if not node.parent: + parent_id = False + self.cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (node.name,)) + res = self.cr.fetchone() + values = {'parent_id': parent_id, 'name': node.name} + else: + parent_id = self.get_id(node.parent) + values = {'parent_id': parent_id} + if node.name: + values['name'] = node.name + try: + res = [ self.get_id(node.id) ] + except: # which exception ? + res = None + + if node.action: + action_type = node.type or 'act_window' + icons = { + "act_window": 'STOCK_NEW', + "report.xml": 'STOCK_PASTE', + "wizard": 'STOCK_EXECUTE', + "url": 'STOCK_JUMP_TO', + } + values['icon'] = icons.get(action_type, 'STOCK_NEW') + if action_type == 'act_window': + action_id = self.get_id(node.action) + self.cr.execute('select view_type,view_mode,name,view_id,target from ir_act_window where id=%s', (action_id,)) + ir_act_window_result = self.cr.fetchone() + assert ir_act_window_result, "No window action defined for this id %s !\n" \ + "Verify that this is a window action or add a type argument." % (node.action,) + action_type, action_mode, action_name, view_id, target = ir_act_window_result + if view_id: + self.cr.execute('SELECT type FROM ir_ui_view WHERE id=%s', (view_id,)) + # TODO guess why action_mode is ir_act_window.view_mode above and ir_ui_view.type here + action_mode = self.cr.fetchone() + self.cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%s ORDER BY sequence LIMIT 1', (action_id,)) + if self.cr.rowcount: + action_mode = self.cr.fetchone() + if action_type == 'tree': + values['icon'] = 'STOCK_INDENT' + elif action_mode and action_mode.startswith('tree'): + values['icon'] = 'STOCK_JUSTIFY_FILL' + elif action_mode and action_mode.startswith('graph'): + values['icon'] = 'terp-graph' + elif action_mode and action_mode.startswith('calendar'): + values['icon'] = 'terp-calendar' + if target == 'new': + values['icon'] = 'STOCK_EXECUTE' + if not values.get('name', False): + values['name'] = action_name + elif action_type == 'wizard': + action_id = self.get_id(node.action) + self.cr.execute('select name from ir_act_wizard where id=%s', (action_id,)) + ir_act_wizard_result = self.cr.fetchone() + if (not values.get('name', False)) and ir_act_wizard_result: + values['name'] = ir_act_wizard_result[0] + else: + raise YamlImportException("Unsupported type '%s' in menuitem tag." % action_type) + if node.sequence: + values['sequence'] = node.sequence + if node.icon: + values['icon'] = node.icon + + self._set_group_values(node, values) + + pid = self.pool.get('ir.model.data')._update(self.cr, self.uid, \ + 'ir.ui.menu', self.module, values, node.id, mode=self.mode, \ + res_id=res and res[0] or False) + + if node.id and parent_id: + self.id_map[node.id] = int(parent_id) + + if node.action and pid: + action_type = node.type or 'act_window' + action_id = self.get_id(node.action) + action = "ir.actions.%s,%d" % (action_type, action_id) + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', \ + 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(parent_id))], action, True, True, xml_id=node.id) + + def process_act_window(self, node): + self.validate_xml_id(node.id) + view_id = False + if node.view: + view_id = self.get_id(node.view) + context = eval(node.context, {'ref': self._ref, '_ref': self._ref}) + + values = { + 'name': node.name, + 'type': type or 'ir.actions.act_window', + 'view_id': view_id, + 'domain': node.domain, + 'context': context, + 'res_model': node.res_model, + 'src_model': node.src_model, + 'view_type': node.view_type or 'form', + 'view_mode': node.view_mode or 'tree,form', + 'usage': node.usage, + 'limit': node.limit, + 'auto_refresh': node.auto_refresh, + } + + self._set_group_values(node, values) + + if node.target: + values['target'] = node.target + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, \ + 'ir.actions.act_window', self.module, values, node.id, mode=self.mode) + self.id_map[node.id] = int(id) + + if node.src_model: + keyword = 'client_action_relate' + value = 'ir.actions.act_window,%s' % id + replace = node.replace or True + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', \ + keyword, node.id, [node.src_model], value, replace=replace, isobject=True, xml_id=node.id) + # TODO add remove ir.model.data + + def process_delete(self, node): + ids = [] + if len(node.search): + ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search)) + if len(node.id): + try: + ids.append(self.get_id(node.id)) + except: + pass + if len(ids): + self.pool.get(node.model).unlink(self.cr, self.uid, ids) + self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids, direct=True) + + def process_url(self, node): + self.validate_xml_id(node.id) + + res = {'name': node.name, 'url': node.url, 'target': node.target} + + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, \ + "ir.actions.url", self.module, res, node.id, mode=self.mode) + self.id_map[node.id] = int(id) + # ir_set + if (not node.menu or eval(node.menu)) and id: + keyword = node.keyword or 'client_action_multi' + value = 'ir.actions.url,%s' % id + replace = node.replace or True + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, \ + 'action', keyword, node.url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=node.id) + def process(self, yaml_string): """Processes a Yaml string. Custom tags are interpreted by 'process_' instance methods.""" @@ -374,13 +635,26 @@ class YamlInterpreter(object): self.process_record(node) elif is_python(node): self.process_python(node) + elif is_menuitem(node): + self.process_menuitem(node) + elif is_delete(node): + self.process_delete(node) + elif is_url(node): + self.process_url(node) elif is_context(node): self.process_context(node) + elif is_act_window(node): + self.process_act_window(node) elif is_workflow(node): if isinstance(node, types.DictionaryType): self.process_workflow(node) else: self.process_workflow({node: []}) + elif is_function(node): + if isinstance(node, types.DictionaryType): + self.process_function(node) + else: + self.process_function({node: []}) else: raise YamlImportException("Can not process YAML block: %s" % node) From 2b3611cb376cd49c57243e74387b0facedd4f537 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 5 Mar 2010 10:37:22 +0100 Subject: [PATCH 05/47] [IMP] Added ir_set. [FIX] ActWindow __init__ bzr revid: jth@openerp.com-20100305093722-t1ndcr0v8preofkw --- bin/tools/yaml_test.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index 5cee9b92d5e..442370ab5dc 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -66,7 +66,7 @@ class ActWindow(YamlTag): def __init__(self, model, action, **kwargs): self.model = model self.action = action - super(Workflow, self).__init__(**kwargs) + super(ActWindow, self).__init__(**kwargs) class Function(YamlTag): def __init__(self, model, name, **kwargs): @@ -94,10 +94,9 @@ class Eval(YamlTag): self.expression = expression super(Eval, self).__init__() -class Ref(YamlTag): - def __init__(self, xmlid): - self.xmlid = xmlid - super(Ref, self).__init__() +class IrSet(YamlTag): + def __init__(self): + super(IrSet, self).__init__() def assert_constructor(loader, node): kwargs = loader.construct_mapping(node) @@ -143,9 +142,9 @@ def eval_constructor(loader, node): expression = loader.construct_scalar(node) return Eval(expression) -def ref_constructor(loader, node): - xmlid = loader.construct_scalar(node) - return Ref(xmlid) +def ir_set_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return IrSet(**kwargs) yaml.add_constructor(u"!assert", assert_constructor) yaml.add_constructor(u"!record", record_constructor) @@ -158,7 +157,7 @@ yaml.add_constructor(u"!context", context_constructor) yaml.add_constructor(u"!delete", delete_constructor) yaml.add_constructor(u"!url", url_constructor) yaml.add_constructor(u"!eval", eval_constructor) -yaml.add_constructor(u"!ref", ref_constructor) +yaml.add_constructor(u"!ir_set", ir_set_constructor) def _is_yaml_mapping(node, tag_constructor): value = isinstance(node, types.DictionaryType) \ @@ -204,8 +203,8 @@ def is_url(node): def is_eval(node): return isinstance(node, Eval) -def is_ref(node): - return isinstance(node, Ref) +def is_ir_set(node): + return _is_yaml_mapping(node, IrSet) class TestReport(object): @@ -611,6 +610,21 @@ class YamlInterpreter(object): replace = node.replace or True self.pool.get('ir.model.data').ir_set(self.cr, self.uid, \ 'action', keyword, node.url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=node.id) + + def process_ir_set(self, node): + if not self.mode == 'init': + return False + _, fields = node.items()[0] + res = {} + for fieldname, expression in fields.items(): + if isinstance(expression, Eval): + value = eval(expression.expression, {'ref': self._ref, '_ref': self._ref}) + else: + value = expression + res[fieldname] = value + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, res['key'], res['key2'], \ + res['name'], res['models'], res['value'], replace=res.get('replace',True), \ + isobject=res.get('isobject', False), meta=res.get('meta',None)) def process(self, yaml_string): """Processes a Yaml string. Custom tags are interpreted by 'process_' instance methods.""" @@ -643,6 +657,8 @@ class YamlInterpreter(object): self.process_url(node) elif is_context(node): self.process_context(node) + elif is_ir_set(node): + self.process_ir_set(node) elif is_act_window(node): self.process_act_window(node) elif is_workflow(node): From 88635654ce8aa65af2e0d311178c356dd8e2cd42 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 5 Mar 2010 11:05:37 +0100 Subject: [PATCH 06/47] [FIX] fixed missing isnoupdate and get_context bzr revid: jth@openerp.com-20100305100537-fnf2dkkylpylrwhq --- bin/tools/yaml_test.py | 46 +++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index 442370ab5dc..d284824e1c1 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -291,6 +291,9 @@ class YamlInterpreter(object): if node.context: context.update(eval(node.context, locals_dict)) return context + + def isnoupdate(self, node): + return self.noupdate or node.noupdate or False def process_comment(self, node): return node @@ -315,6 +318,8 @@ class YamlInterpreter(object): def process_assert(self, node): assertion, expressions = node.items()[0] + if self.isnoupdate(assertion) and self.mode != 'init': + return model = self.get_model(assertion.model) ids = self._get_assertion_id(assertion) if assertion.count and len(ids) != assertion.count: @@ -325,11 +330,12 @@ class YamlInterpreter(object): args = (assertion.string, assertion.count, len(ids)) self._log_assert_failure(assertion.severity, msg, *args) else: - test_context = {'ref': self._ref, '_ref': self._ref} # added '_ref' so that record['ref'] is possible + local_context = {'ref': self._ref, '_ref': self._ref} # added '_ref' so that record['ref'] is possible + context = self.get_context(assertion, local_context) for id in ids: - record = model.browse(self.cr, self.uid, id, assertion.context) + record = model.browse(self.cr, self.uid, id, context) for test in expressions.get('test', ''): - success = eval(test, test_context, record) + success = eval(test, local_context, record) if not success: msg = 'Assertion "%s" FAILED\ntest: %s\n' args = (assertion.string, test) @@ -342,13 +348,14 @@ class YamlInterpreter(object): record, fields = node.items()[0] self.validate_xml_id(record.id) - model = self.get_model(record.model) - record_dict = self._create_record(model, fields) - id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \ - self.module, record_dict, record.id, mode=self.mode) - self.id_map[record.id] = int(id) - if config.get('import_partial', False): - self.cr.commit() + if self.isnoupdate(record) and self.mode != 'init': + model = self.get_model(record.model) + record_dict = self._create_record(model, fields) + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \ + self.module, record_dict, record.id, noupdate=self.isnoupdate(node), mode=self.mode) + self.id_map[record.id] = int(id) + if config.get('import_partial', False): + self.cr.commit() def _create_record(self, model, fields): record_dict = {} @@ -402,6 +409,8 @@ class YamlInterpreter(object): def process_workflow(self, node): workflow, values = node.items()[0] + if self.isnoupdate(workflow) and self.mode != 'init': + return model = self.get_model(workflow.model) if workflow.ref: id = self.get_id(workflow.ref) @@ -427,11 +436,11 @@ class YamlInterpreter(object): wf_service.trg_validate(uid, model, id, workflow.action, self.cr) def process_function(self, node): - if self.mode != 'init': - return function, values = node.items()[0] + if self.isnoupdate(function) and self.mode != 'init': + return local_context = {'ref': self._ref, '_ref': self._ref} - context = self.get_context(node, local_context) + context = self.get_context(function, local_context) args = [] if function.eval: args = eval(function.eval, local_context) @@ -532,7 +541,7 @@ class YamlInterpreter(object): pid = self.pool.get('ir.model.data')._update(self.cr, self.uid, \ 'ir.ui.menu', self.module, values, node.id, mode=self.mode, \ - res_id=res and res[0] or False) + noupdate=self.isnoupdate(node), res_id=res and res[0] or False) if node.id and parent_id: self.id_map[node.id] = int(parent_id) @@ -578,8 +587,8 @@ class YamlInterpreter(object): keyword = 'client_action_relate' value = 'ir.actions.act_window,%s' % id replace = node.replace or True - self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', \ - keyword, node.id, [node.src_model], value, replace=replace, isobject=True, xml_id=node.id) + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', keyword, \ + node.id, [node.src_model], value, replace=replace, noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id) # TODO add remove ir.model.data def process_delete(self, node): @@ -608,8 +617,9 @@ class YamlInterpreter(object): keyword = node.keyword or 'client_action_multi' value = 'ir.actions.url,%s' % id replace = node.replace or True - self.pool.get('ir.model.data').ir_set(self.cr, self.uid, \ - 'action', keyword, node.url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=node.id) + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', \ + keyword, node.url, ["ir.actions.url"], value, replace=replace, \ + noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id) def process_ir_set(self, node): if not self.mode == 'init': From c51be2604d770f2feaf9bbfbe7834c3168551dc7 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 5 Mar 2010 11:42:04 +0100 Subject: [PATCH 07/47] [IMP] Added report tag. bzr revid: jth@openerp.com-20100305104204-yg9ees4miw0hunjs --- bin/tools/yaml_test.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index d284824e1c1..65bf16475c3 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -6,6 +6,7 @@ import logging import pooler import netsvc +import misc from config import config @@ -74,6 +75,13 @@ class Function(YamlTag): self.name = name super(Function, self).__init__(**kwargs) +class Report(YamlTag): + def __init__(self, model, name, string, **kwargs): + self.model = model + self.name = name + self.string = string + super(Function, self).__init__(**kwargs) + class Delete(YamlTag): def __init__(self, model, id, search, **kwargs): self.model = model @@ -126,6 +134,10 @@ def function_constructor(loader, node): kwargs = loader.construct_mapping(node) return Function(**kwargs) +def report_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Report(**kwargs) + def delete_constructor(loader, node): kwargs = loader.construct_mapping(node) return Delete(**kwargs) @@ -153,6 +165,7 @@ yaml.add_constructor(u"!menuitem", menuitem_constructor) yaml.add_constructor(u"!workflow", workflow_constructor) yaml.add_constructor(u"!act_window", act_window_constructor) yaml.add_constructor(u"!function", function_constructor) +yaml.add_constructor(u"!report", report_constructor) yaml.add_constructor(u"!context", context_constructor) yaml.add_constructor(u"!delete", delete_constructor) yaml.add_constructor(u"!url", url_constructor) @@ -185,6 +198,9 @@ def is_function(node): return isinstance(node, Function) \ or _is_yaml_mapping(node, Function) +def is_report(node): + return isinstance(node, Report) + def is_workflow(node): return isinstance(node, Workflow) @@ -636,6 +652,38 @@ class YamlInterpreter(object): res['name'], res['models'], res['value'], replace=res.get('replace',True), \ isobject=res.get('isobject', False), meta=res.get('meta',None)) + def process_report(self, node): + values = {} + for dest, f in (('name','string'), ('model','model'), ('report_name','name')): + values[dest] = getattr(node, f) + assert values[dest], "Attribute %s of report is empty !" % (f,) + for field,dest in (('rml','report_rml'),('xml','report_xml'),('xsl','report_xsl'),('attachment','attachment'),('attachment_use','attachment_use')): + if getattr(node, field): + values[dest] = getattr(node, field) + if node.auto: + values['auto'] = eval(node.auto) + if node.sxw: + sxw_content = misc.file_open(node.sxw).read() + values['report_sxw_content'] = sxw_content + if node.header: + values['header'] = eval(node.header) + values['multi'] = node.multi and eval(node.multi) + xml_id = node.id + self.validate_xml_id(xml_id) + + self._set_group_values(node, values) + + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, "ir.actions.report.xml", \ + self.module, values, xml_id, noupdate=self.isnoupdate(node), mode=self.mode) + self.id_map[xml_id] = int(id) + + if not node.menu or eval(node.menu): + keyword = node.keyword or 'client_print_multi' + value = 'ir.actions.report.xml,%s' % id + replace = node.replace or True + self.pool.get('ir.model.data').ir_set(self.cr, self.uid, 'action', \ + keyword, values['name'], [values['model']], value, replace=replace, isobject=True, xml_id=xml_id) + def process(self, yaml_string): """Processes a Yaml string. Custom tags are interpreted by 'process_' instance methods.""" @@ -671,6 +719,8 @@ class YamlInterpreter(object): self.process_ir_set(node) elif is_act_window(node): self.process_act_window(node) + elif is_report(node): + self.process_report(node) elif is_workflow(node): if isinstance(node, types.DictionaryType): self.process_workflow(node) From 83d7ae2d21b8255ec8d4844b06ba1e56ae2fbda3 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 5 Mar 2010 12:01:28 +0100 Subject: [PATCH 08/47] [FIX] fixde Report __init__ bzr revid: jth@openerp.com-20100305110128-689067jl31nxy547 --- bin/tools/yaml_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/yaml_test.py b/bin/tools/yaml_test.py index 65bf16475c3..b495989991a 100644 --- a/bin/tools/yaml_test.py +++ b/bin/tools/yaml_test.py @@ -80,7 +80,7 @@ class Report(YamlTag): self.model = model self.name = name self.string = string - super(Function, self).__init__(**kwargs) + super(Report, self).__init__(**kwargs) class Delete(YamlTag): def __init__(self, model, id, search, **kwargs): From 425b2fef610cc865c1d30041da25df72cdd7efa4 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Tue, 30 Mar 2010 17:20:31 +0200 Subject: [PATCH 09/47] [REF] Splitted YAML custom tags definition in itw own file (needed by module recorder). bzr revid: jth@openerp.com-20100330152031-xvq4ve15ju51u7cy --- bin/tools/yaml_import.py | 188 ++++----------------------------------- bin/tools/yaml_tag.py | 157 ++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 171 deletions(-) create mode 100644 bin/tools/yaml_tag.py diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index fed3e81299e..8808a92820d 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -7,6 +7,7 @@ import pooler import netsvc import misc from config import config +import yaml_tag import yaml @@ -18,161 +19,6 @@ class YamlImportException(Exception): class YamlImportAbortion(Exception): pass -class YamlTag(object): - """ - Superclass for constructors of custom tags defined in yaml file. - """ - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - def __getitem__(self, key): - return getattr(self, key) - def __getattr__(self, attr): - return None - def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items())) - -class Assert(YamlTag): - def __init__(self, model, id, severity=logging.ERROR, string="NONAME", **kwargs): - self.model = model - self.id = id - self.severity = severity - self.string = string - super(Assert, self).__init__(**kwargs) - -class Record(YamlTag): - def __init__(self, model, id, **kwargs): - self.model = model - self.id = id - super(Record, self).__init__(**kwargs) - -class Python(YamlTag): - def __init__(self, model, severity=logging.ERROR, name="", **kwargs): - self.model= model - self.severity = severity - self.name = name - super(Python, self).__init__(**kwargs) - -class Menuitem(YamlTag): - def __init__(self, id, name, **kwargs): - self.id = id - self.name = name - super(Menuitem, self).__init__(**kwargs) - -class Workflow(YamlTag): - def __init__(self, model, action, **kwargs): - self.model = model - self.action = action - super(Workflow, self).__init__(**kwargs) - -class ActWindow(YamlTag): - def __init__(self, model, action, **kwargs): - self.model = model - self.action = action - super(ActWindow, self).__init__(**kwargs) - -class Function(YamlTag): - def __init__(self, model, name, **kwargs): - self.model = model - self.name = name - super(Function, self).__init__(**kwargs) - -class Report(YamlTag): - def __init__(self, model, name, string, **kwargs): - self.model = model - self.name = name - self.string = string - super(Report, self).__init__(**kwargs) - -class Delete(YamlTag): - def __init__(self, model, id, search, **kwargs): - self.model = model - self.id = id - self.search = search - super(Delete, self).__init__(**kwargs) - -class Context(YamlTag): - def __init__(self, **kwargs): - super(Context, self).__init__(**kwargs) - -class Url(YamlTag): - def __init__(self, **kwargs): - super(Url, self).__init__(**kwargs) - -class Eval(YamlTag): - def __init__(self, expression): - self.expression = expression - super(Eval, self).__init__() - -class IrSet(YamlTag): - def __init__(self): - super(IrSet, self).__init__() - -def assert_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Assert(**kwargs) - -def record_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Record(**kwargs) - -def python_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Python(**kwargs) - -def menuitem_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Menuitem(**kwargs) - -def workflow_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Workflow(**kwargs) - -def act_window_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return ActWindow(**kwargs) - -def function_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Function(**kwargs) - -def report_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Report(**kwargs) - -def delete_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Delete(**kwargs) - -def context_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Context(**kwargs) - -def url_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return Url(**kwargs) - -def eval_constructor(loader, node): - expression = loader.construct_scalar(node) - return Eval(expression) - -def ir_set_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return IrSet(**kwargs) - -yaml.add_constructor(u"!assert", assert_constructor) -yaml.add_constructor(u"!record", record_constructor) -yaml.add_constructor(u"!python", python_constructor) -yaml.add_constructor(u"!menuitem", menuitem_constructor) -yaml.add_constructor(u"!workflow", workflow_constructor) -yaml.add_constructor(u"!act_window", act_window_constructor) -yaml.add_constructor(u"!function", function_constructor) -yaml.add_constructor(u"!report", report_constructor) -yaml.add_constructor(u"!context", context_constructor) -yaml.add_constructor(u"!delete", delete_constructor) -yaml.add_constructor(u"!url", url_constructor) -yaml.add_constructor(u"!eval", eval_constructor) -yaml.add_constructor(u"!ir_set", ir_set_constructor) - def _is_yaml_mapping(node, tag_constructor): value = isinstance(node, types.DictionaryType) \ and len(node.keys()) == 1 \ @@ -183,45 +29,45 @@ def is_comment(node): return isinstance(node, types.StringTypes) def is_assert(node): - return _is_yaml_mapping(node, Assert) + return _is_yaml_mapping(node, yaml_tag.Assert) def is_record(node): - return _is_yaml_mapping(node, Record) + return _is_yaml_mapping(node, yaml_tag.Record) def is_python(node): - return _is_yaml_mapping(node, Python) + return _is_yaml_mapping(node, yaml_tag.Python) def is_menuitem(node): - return isinstance(node, Menuitem) \ - or _is_yaml_mapping(node, Menuitem) + return isinstance(node, yaml_tag.Menuitem) \ + or _is_yaml_mapping(node, yaml_tag.Menuitem) def is_function(node): - return isinstance(node, Function) \ - or _is_yaml_mapping(node, Function) + return isinstance(node, yaml_tag.Function) \ + or _is_yaml_mapping(node, yaml_tag.Function) def is_report(node): - return isinstance(node, Report) + return isinstance(node, yaml_tag.Report) def is_workflow(node): - return isinstance(node, Workflow) + return isinstance(node, yaml_tag.Workflow) def is_act_window(node): - return isinstance(node, ActWindow) + return isinstance(node, yaml_tag.ActWindow) def is_delete(node): - return isinstance(node, Delete) + return isinstance(node, yaml_tag.Delete) def is_context(node): - return isinstance(node, Context) + return isinstance(node, yaml_tag.Context) def is_url(node): - return isinstance(node, Url) + return isinstance(node, yaml_tag.Url) def is_eval(node): - return isinstance(node, Eval) + return isinstance(node, yaml_tag.Eval) def is_ir_set(node): - return _is_yaml_mapping(node, IrSet) + return _is_yaml_mapping(node, yaml_tag.IrSet) class TestReport(object): @@ -410,7 +256,7 @@ class YamlInterpreter(object): ids = [self.get_id(xml_id) for xml_id in expression] value= [(6, 0, ids)] else: # scalar field - if isinstance(expression, Eval): + if isinstance(expression, yaml_tag.Eval): value = eval(expression.expression) else: value = expression diff --git a/bin/tools/yaml_tag.py b/bin/tools/yaml_tag.py new file mode 100644 index 00000000000..0a5286882ed --- /dev/null +++ b/bin/tools/yaml_tag.py @@ -0,0 +1,157 @@ +import yaml +import logging + +class YamlTag(object): + """ + Superclass for constructors of custom tags defined in yaml file. + """ + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + def __getitem__(self, key): + return getattr(self, key) + def __getattr__(self, attr): + return None + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items())) + +class Assert(YamlTag): + def __init__(self, model, id, severity=logging.ERROR, string="NONAME", **kwargs): + self.model = model + self.id = id + self.severity = severity + self.string = string + super(Assert, self).__init__(**kwargs) + +class Record(YamlTag): + def __init__(self, model, id, **kwargs): + self.model = model + self.id = id + super(Record, self).__init__(**kwargs) + +class Python(YamlTag): + def __init__(self, model, severity=logging.ERROR, name="", **kwargs): + self.model= model + self.severity = severity + self.name = name + super(Python, self).__init__(**kwargs) + +class Menuitem(YamlTag): + def __init__(self, id, name, **kwargs): + self.id = id + self.name = name + super(Menuitem, self).__init__(**kwargs) + +class Workflow(YamlTag): + def __init__(self, model, action, **kwargs): + self.model = model + self.action = action + super(Workflow, self).__init__(**kwargs) + +class ActWindow(YamlTag): + def __init__(self, model, action, **kwargs): + self.model = model + self.action = action + super(ActWindow, self).__init__(**kwargs) + +class Function(YamlTag): + def __init__(self, model, name, **kwargs): + self.model = model + self.name = name + super(Function, self).__init__(**kwargs) + +class Report(YamlTag): + def __init__(self, model, name, string, **kwargs): + self.model = model + self.name = name + self.string = string + super(Report, self).__init__(**kwargs) + +class Delete(YamlTag): + def __init__(self, model, id, search, **kwargs): + self.model = model + self.id = id + self.search = search + super(Delete, self).__init__(**kwargs) + +class Context(YamlTag): + def __init__(self, **kwargs): + super(Context, self).__init__(**kwargs) + +class Url(YamlTag): + def __init__(self, **kwargs): + super(Url, self).__init__(**kwargs) + +class Eval(YamlTag): + def __init__(self, expression): + self.expression = expression + super(Eval, self).__init__() + +class IrSet(YamlTag): + def __init__(self): + super(IrSet, self).__init__() + +def assert_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Assert(**kwargs) + +def record_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Record(**kwargs) + +def python_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Python(**kwargs) + +def menuitem_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Menuitem(**kwargs) + +def workflow_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Workflow(**kwargs) + +def act_window_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return ActWindow(**kwargs) + +def function_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Function(**kwargs) + +def report_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Report(**kwargs) + +def delete_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Delete(**kwargs) + +def context_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Context(**kwargs) + +def url_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Url(**kwargs) + +def eval_constructor(loader, node): + expression = loader.construct_scalar(node) + return Eval(expression) + +def ir_set_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return IrSet(**kwargs) + +yaml.add_constructor(u"!assert", assert_constructor) +yaml.add_constructor(u"!record", record_constructor) +yaml.add_constructor(u"!python", python_constructor) +yaml.add_constructor(u"!menuitem", menuitem_constructor) +yaml.add_constructor(u"!workflow", workflow_constructor) +yaml.add_constructor(u"!act_window", act_window_constructor) +yaml.add_constructor(u"!function", function_constructor) +yaml.add_constructor(u"!report", report_constructor) +yaml.add_constructor(u"!context", context_constructor) +yaml.add_constructor(u"!delete", delete_constructor) +yaml.add_constructor(u"!url", url_constructor) +yaml.add_constructor(u"!eval", eval_constructor) +yaml.add_constructor(u"!ir_set", ir_set_constructor) From a6a0a06867a3fe1ece9be829f36ea05a8e9b4e8e Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 30 Mar 2010 19:26:03 +0200 Subject: [PATCH 10/47] [ADD] utility methods to split large lists of ids for use in IN clauses bzr revid: odo@openerp.com-20100330172603-gbv1zjcqmqeabfbt --- bin/sql_db.py | 8 +++++++- bin/tools/misc.py | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bin/sql_db.py b/bin/sql_db.py index 17bfa340653..94336cde69a 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -63,7 +63,7 @@ re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$'); sql_counter = 0 class Cursor(object): - IN_MAX = 1000 + IN_MAX = 1000 # decent limit on size of IN queries - guideline = Oracle limit __logger = logging.getLogger('db.cursor') def check(f): @@ -142,6 +142,12 @@ class Cursor(object): self.sql_into_log[res_into.group(1)][1] += delay return res + + def split_for_in_conditions(self, ids): + """Split a list of identifiers into one or more smaller tuples + safe for IN conditions, after uniquifying them.""" + return tools.misc.split_every(self.IN_MAX, set(ids)) + def print_log(self): global sql_counter sql_counter += self.sql_log_count diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 284324873de..ff20966857e 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -32,6 +32,7 @@ import zipfile import release import socket import re +from itertools import islice if sys.version_info[:2] < (2, 4): from threadinglocal import local @@ -1267,6 +1268,18 @@ def detect_server_timezone(): return 'UTC' +def split_every(n, iterable, piece_maker=tuple): + """Splits an iterable into length-n pieces. The last piece will be shorter + if ``n`` does not evenly divide the iterable length. + @param ``piece_maker``: function to build the pieces + from the slices (tuple,list,...) + """ + iterator = iter(iterable) + piece = piece_maker(islice(iterator, n)) + while piece: + yield piece + piece = piece_maker(islice(iterator, n)) + if __name__ == '__main__': import doctest doctest.testmod() From 760492db3648aa68b315873382d0aa377ba14940 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 30 Mar 2010 19:28:06 +0200 Subject: [PATCH 11/47] [IMP] refactoring of check_access_rule to avoid SQL injection and simplify code bzr revid: odo@openerp.com-20100330172806-837iforda2zrekmd --- bin/osv/orm.py | 70 +++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 697eb01f4e2..32efe32558b 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -2572,17 +2572,16 @@ class orm(orm_template): return '"%s"' % (f,) fields_pre2 = map(convert_field, fields_pre) order_by = self._parent_order or self._order - for i in range(0, len(ids), cr.IN_MAX): - sub_ids = ids[i:i+cr.IN_MAX] + for sub_ids in cr.split_for_in_conditions(ids): if d1: - cr.execute('SELECT %s FROM %s WHERE %s.id = ANY (%%s) AND %s ORDER BY %s' % \ + cr.execute('SELECT %s FROM %s WHERE %s.id IN %%s AND %s ORDER BY %s' % \ (','.join(fields_pre2 + [self._table + '.id']), ','.join(tables), self._table, ' and '.join(d1), order_by),[sub_ids,]+d2) - if not cr.rowcount == len({}.fromkeys(sub_ids)): + if cr.rowcount != len(sub_ids): raise except_orm(_('AccessError'), _('You try to bypass an access rule while reading (Document type: %s).') % self._description) else: - cr.execute('SELECT %s FROM \"%s\" WHERE id = ANY (%%s) ORDER BY %s' % + cr.execute('SELECT %s FROM \"%s\" WHERE id IN %%s ORDER BY %s' % (','.join(fields_pre2 + ['id']), self._table, order_by), (sub_ids,)) res.extend(cr.dictfetchall()) @@ -2734,29 +2733,24 @@ class orm(orm_template): if res and res[0]: raise except_orm('ConcurrencyException', _('Records were modified in the meanwhile')) - def check_access_rule(self, cr, uid, ids, mode, context=None): - d1, d2, tables = self.pool.get('ir.rule').domain_get(cr, uid, self._name, mode, context=context) - if d1: - d1 = ' and '+' and '.join(d1) - - for i in range(0, len(ids), cr.IN_MAX): - sub_ids = ids[i:i+cr.IN_MAX] - if d1: - cr.execute('SELECT '+self._table+'.id FROM '+','.join(tables)+' ' \ - 'WHERE '+self._table+'.id IN %s'+d1, (tuple(sub_ids),d2)) - if not cr.rowcount == len(sub_ids): + def check_access_rule(self, cr, uid, ids, operation, context=None): + """Verifies that the operation given by ``operation`` is allowed for the user + according to ir.rules. + @param ``operation``: one of ``'read'``, ``'write'``, ``'unlink'`` + @raise ``except_orm``: if current ir.rules do not permit this operation. + @return: ``None`` if the operation is allowed + """ + where_clause, where_params, tables = self.pool.get('ir.rule').domain_get(cr, uid, self._name, operation, context=context) + if where_clause: + where_clause = ' and ' + ' and '.join(where_clause) + for sub_ids in cr.split_for_in_conditions(ids): + cr.execute('SELECT ' + self._table + '.id FROM ' + ','.join(tables) + + ' WHERE ' + self._table + '.id IN %s' + where_clause, + [sub_ids] + where_params) + if cr.rowcount != len(sub_ids): raise except_orm(_('AccessError'), - _('You try to bypass an access rule to '+mode+ - ' (Document type: %s).') % self._name) - else: - cr.execute('SELECT id FROM "'+self._table+'" WHERE id IN %s', - (tuple(sub_ids),)) - if not cr.rowcount == len(sub_ids): - raise except_orm(_('AccessError'), - _('You try to ' +mode+ ' a record that doesn\'t exist (Document type: %s).') - % self._name) - #TODO: this is a SQL injection pattern again, need to refactor it - return ','.join(map(str,ids)) + _('Operation prohibited by access rules (Operation: %s, Document type: %s).') + % (operation, self._name)) def unlink(self, cr, uid, ids, context=None): if not ids: @@ -2787,12 +2781,13 @@ class orm(orm_template): # ids2 = [x[self._inherits[key]] for x in res] # self.pool.get(key).unlink(cr, uid, ids2) - ids_str = self.check_access_rule(cr, uid, ids, 'unlink', context=context) - cr.execute('delete from '+self._table+' ' \ - 'where id in ('+ids_str+')', ids) + self.check_access_rule(cr, uid, ids, 'unlink', context=context) + for sub_ids in cr.split_for_in_conditions(ids): + cr.execute('delete from ' + self._table + ' ' \ + 'where id in %s', sub_ids) for order, object, store_ids, fields in result_store: - if object<>self._name: + if object != self._name: obj = self.pool.get(object) cr.execute('select id from '+obj._table+' where id in ('+','.join(map(str, store_ids))+')') rids = map(lambda x: x[0], cr.fetchall()) @@ -2888,9 +2883,10 @@ class orm(orm_template): upd1.append(user) if len(upd0): - ids_str = self.check_access_rule(cr, user, ids, 'write', context=context) - cr.execute('update '+self._table+' set '+string.join(upd0, ',')+' ' \ - 'where id in ('+ids_str+')', upd1) + self.check_access_rule(cr, user, ids, 'write', context=context) + for sub_ids in cr.split_for_in_conditions(ids): + cr.execute('update ' + self._table + ' set ' + ','.join(upd0) + ' ' \ + 'where id in %s', upd1 + [sub_ids]) if totranslate: # TODO: optimize @@ -2921,11 +2917,9 @@ class orm(orm_template): for table in self._inherits: col = self._inherits[table] nids = [] - for i in range(0, len(ids), cr.IN_MAX): - sub_ids = ids[i:i+cr.IN_MAX] - ids_str = string.join(map(str, sub_ids), ',') + for sub_ids in cr.split_for_in_conditions(ids): cr.execute('select distinct "'+col+'" from "'+self._table+'" ' \ - 'where id in ('+ids_str+')', upd1) + 'where id in %s', (sub_ids,)) nids.extend([x[0] for x in cr.fetchall()]) v = {} From 3d2a727aacb79304aeaf80535b027185dbeb4340 Mon Sep 17 00:00:00 2001 From: Launchpad Code Hosting Date: Wed, 31 Mar 2010 04:54:43 +0100 Subject: [PATCH 12/47] Launchpad automatic translations update. bzr revid: codehost@crowberry-20100331035443-g3goa3jjj1hen5ag --- bin/addons/base/i18n/bg.po | 4 ++-- bin/addons/base/i18n/hr.po | 4 ++-- bin/addons/base/i18n/it.po | 14 +++++++------- bin/addons/base/i18n/ja.po | 4 ++-- bin/addons/base/i18n/sv.po | 4 ++-- bin/addons/base/i18n/uk.po | 4 ++-- bin/addons/base/i18n/zh_CN.po | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bin/addons/base/i18n/bg.po b/bin/addons/base/i18n/bg.po index 04d5ab798d1..5570b263bec 100644 --- a/bin/addons/base/i18n/bg.po +++ b/bin/addons/base/i18n/bg.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 10:51+0000\n" +"PO-Revision-Date: 2010-03-30 04:19+0000\n" "Last-Translator: Boris \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:50+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index 9290624ea43..f3739c66bf3 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 04:13+0000\n" +"PO-Revision-Date: 2010-03-30 04:36+0000\n" "Last-Translator: goranc \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:50+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" "Language: hr\n" diff --git a/bin/addons/base/i18n/it.po b/bin/addons/base/i18n/it.po index a1cfce3afdf..3d99b3829d9 100644 --- a/bin/addons/base/i18n/it.po +++ b/bin/addons/base/i18n/it.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 15:30+0000\n" +"PO-Revision-Date: 2010-03-30 09:53+0000\n" "Last-Translator: Carlo Vettore \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:50+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base @@ -3641,7 +3641,7 @@ msgstr "Crea azione" #. module: base #: selection:ir.actions.report.xml,report_type:0 msgid "HTML from HTML" -msgstr "" +msgstr "HTML da HTML" #. module: base #: selection:ir.actions.report.xml,report_type:0 @@ -3733,12 +3733,12 @@ msgstr "STOCK_ADD" #. module: base #: field:ir.cron,doall:0 msgid "Repeat Missed" -msgstr "" +msgstr "Ripeti mancato" #. module: base #: help:ir.actions.server,state:0 msgid "Type of the Action that is to be executed" -msgstr "" +msgstr "Tipo dell'azione che deve essere eseguita" #. module: base #: field:ir.server.object.lines,server_id:0 @@ -3783,7 +3783,7 @@ msgstr "Botswana" #: model:ir.ui.menu,name:base.menu_partner_title_partner #: view:res.partner.title:0 msgid "Partner Titles" -msgstr "" +msgstr "Qualifiche Partner" #. module: base #: selection:ir.actions.todo,type:0 @@ -6722,7 +6722,7 @@ msgstr "" #. module: base #: field:res.partner.bank,acc_number:0 msgid "Account Number" -msgstr "" +msgstr "Numero conto" #. module: base #: view:res.lang:0 diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index dd3caace65e..9430360cb87 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 04:11+0000\n" +"PO-Revision-Date: 2010-03-30 04:24+0000\n" "Last-Translator: Harry (Open ERP) \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:50+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index 73c67ea25ef..92102068d0d 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 04:09+0000\n" +"PO-Revision-Date: 2010-03-30 04:18+0000\n" "Last-Translator: Anders Wallenquist \n" "Language-Team: <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:51+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index 0c8b97a9a71..be9ac9ddeb1 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 04:11+0000\n" +"PO-Revision-Date: 2010-03-30 04:37+0000\n" "Last-Translator: Fabien (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:51+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index fd637aa00f7..795f0a2c33f 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-03-29 04:11+0000\n" +"PO-Revision-Date: 2010-03-30 04:19+0000\n" "Last-Translator: OpenERP Administrators \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-03-30 03:51+0000\n" +"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base From 197f89966ba51d68a406fb4bd5525173913d354e Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 31 Mar 2010 11:02:41 +0530 Subject: [PATCH 13/47] [FIX] convert: set uid variable which are used in view domain bzr revid: hmo@tinyerp.com-20100331053241-o5mb3tfpx7upuwx1 --- bin/tools/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 75b438cc6ea..1d4b1fd9d0b 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -376,7 +376,7 @@ form: module.record_id""" % (xml_id,) usage = rec.get('usage','').encode('utf-8') limit = rec.get('limit','').encode('utf-8') auto_refresh = rec.get('auto_refresh','').encode('utf-8') - + uid = self.uid # def ref() added because , if context has ref('id') eval wil use this ref active_id=str("active_id") # for further reference in client/bin/tools/__init__.py From 5e969614cac600338e9f0bef6a52ebed5ee719d3 Mon Sep 17 00:00:00 2001 From: "DSH (Open ERP)" Date: Wed, 31 Mar 2010 15:58:36 +0530 Subject: [PATCH 15/47] [FIX] res_lang : if value of thousands_sep is not present in language,method will give error- 'moentary' name is not defined bzr revid: dsh@tinyerp.com-20100331102836-b9sj12crrt7dv3x5 --- bin/addons/base/res/res_lang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/addons/base/res/res_lang.py b/bin/addons/base/res/res_lang.py index 8a3af7dd175..8427b366703 100644 --- a/bin/addons/base/res/res_lang.py +++ b/bin/addons/base/res/res_lang.py @@ -62,7 +62,7 @@ class lang(osv.osv): ] @tools.cache(skiparg=3) - def _lang_data_get(self, cr, uid, lang_id): + def _lang_data_get(self, cr, uid, lang_id, monetary=False): conv = localeconv() lang_obj=self.browse(cr,uid,lang_id) thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep'] @@ -120,7 +120,7 @@ class lang(osv.osv): if percent[0] != '%': raise ValueError("format() must be given exactly one %char format specifier") - lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0]) + lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary) formatted = percent % value # floats and decimal ints need special action! From f66af28b305539e31e007e0df2c57f131bc595b6 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Wed, 31 Mar 2010 18:55:26 +0200 Subject: [PATCH 17/47] [IMP] Added search for record relations. [FIX] Record creation. [FIX] Ref constructor. [FIX] Safer Eval expression. bzr revid: jth@openerp.com-20100331165526-5exmbhtx3jt161pm --- bin/tools/yaml_import.py | 73 +++++++++++++++++++++++++++++++--------- bin/tools/yaml_tag.py | 18 ++++++++-- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 8808a92820d..36eeadd0cf7 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -66,6 +66,10 @@ def is_url(node): def is_eval(node): return isinstance(node, yaml_tag.Eval) +def is_ref(node): + return isinstance(node, yaml_tag.Ref) \ + or _is_yaml_mapping(node, yaml_tag.Ref) + def is_ir_set(node): return _is_yaml_mapping(node, yaml_tag.IrSet) @@ -122,7 +126,7 @@ class YamlInterpreter(object): self.pool = pooler.get_pool(cr.dbname) self.uid = 1 self.context = {} # opererp context - self.eval_context = {'ref': self._ref, '_ref': self._ref} # added '_ref' so that record['ref'] is possible + self.eval_context = {'ref': self._ref, '_ref': self._ref, 'time': time} # added '_ref' so that record['ref'] is possible def _ref(self): return lambda xml_id: self.get_id(xml_id) @@ -155,10 +159,11 @@ class YamlInterpreter(object): id = self.id_map[xml_id] else: if '.' in xml_id: - module, xml_id = xml_id.split('.', 1) + module, checked_xml_id = xml_id.split('.', 1) else: module = self.module - ir_id = self.pool.get('ir.model.data')._get_id(self.cr, self.uid, module, xml_id) + checked_xml_id = xml_id + ir_id = self.pool.get('ir.model.data')._get_id(self.cr, self.uid, module, checked_xml_id) obj = self.pool.get('ir.model.data').read(self.cr, self.uid, ir_id, ['res_id']) id = int(obj['res_id']) self.id_map[xml_id] = id @@ -224,19 +229,39 @@ class YamlInterpreter(object): else: # all tests were successful for this assertion tag (no break) self.assert_report.record(True, assertion.severity) + def _coerce_bool(self, value, default=False): + if isinstance(value, types.BooleanType): + b = value + if isinstance(value, types.StringTypes): + b = value.strip().lower() not in ('0', 'false', 'off', 'no') + elif isinstance(value, types.IntType): + b = bool(value) + else: + b = default + return b + def process_record(self, node): record, fields = node.items()[0] self.validate_xml_id(record.id) if self.isnoupdate(record) and self.mode != 'init': - model = self.get_model(record.model) - record_dict = self._create_record(model, fields) - self.logger.debug("RECORD_DICT %s" % record_dict) - id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \ - self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode) - self.id_map[record.id] = int(id) - if config.get('import_partial', False): - self.cr.commit() + id = self.pool.get('ir.model.data')._update_dummy(self.cr, self.uid, record.model, self.module, record.id) + # check if the resource already existed at the last update + if id: + self.id_map[record] = int(id) + return None + else: + if not self._coerce_bool(record.forcecreate): + return None + + model = self.get_model(record.model) + record_dict = self._create_record(model, fields) + self.logger.debug("RECORD_DICT %s" % record_dict) + id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \ + self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode) + self.id_map[record.id] = int(id) + if config.get('import_partial', False): + self.cr.commit() def _create_record(self, model, fields): record_dict = {} @@ -247,17 +272,35 @@ class YamlInterpreter(object): def _eval_field(self, model, field_name, expression): column = model._columns[field_name] - if column._type == "many2one": + if is_ref(expression): + if expression.model: + other_model_name = expression.model + else: + other_model_name = column._obj + other_model = self.get_model(other_model_name) + if expression.search: + q = eval(expression.search, self.eval_context) + ids = other_model.search(self.cr, self.uid, q) + if expression.use: + instances = other_model.browse(self.cr, self.uid, ids) + elements = [inst[expression.use] for inst in instances] + else: + elements = ids + if column._type in ("many2many", "one2many"): + value = [(6, 0, elements)] + else: # many2one + value = elements[0] + elif column._type == "many2one": value = self.get_id(expression) elif column._type == "one2many": other_model = self.get_model(column._obj) value = [(0, 0, self._create_record(other_model, fields)) for fields in expression] elif column._type == "many2many": ids = [self.get_id(xml_id) for xml_id in expression] - value= [(6, 0, ids)] + value = [(6, 0, ids)] else: # scalar field - if isinstance(expression, yaml_tag.Eval): - value = eval(expression.expression) + if is_eval(expression): + value = eval(expression.expression, self.eval_context) else: value = expression # raise YamlImportException('Unsupported column "%s" or value %s:%s' % (field_name, type(expression), expression)) diff --git a/bin/tools/yaml_tag.py b/bin/tools/yaml_tag.py index 0a5286882ed..83f6dde9c8d 100644 --- a/bin/tools/yaml_tag.py +++ b/bin/tools/yaml_tag.py @@ -23,7 +23,7 @@ class Assert(YamlTag): super(Assert, self).__init__(**kwargs) class Record(YamlTag): - def __init__(self, model, id, **kwargs): + def __init__(self, model, id, use='id', **kwargs): self.model = model self.id = id super(Record, self).__init__(**kwargs) @@ -86,6 +86,12 @@ class Eval(YamlTag): self.expression = expression super(Eval, self).__init__() +class Ref(YamlTag): + # 'model' parameter is optional since it defaults to the column type + def __init__(self, search): + self.search = search + super(Ref, self).__init__() + class IrSet(YamlTag): def __init__(self): super(IrSet, self).__init__() @@ -138,10 +144,17 @@ def eval_constructor(loader, node): expression = loader.construct_scalar(node) return Eval(expression) +def ref_constructor(loader, node): + kwargs = loader.construct_mapping(node) + return Ref(**kwargs) + def ir_set_constructor(loader, node): kwargs = loader.construct_mapping(node) return IrSet(**kwargs) - + +# Registers constructors for custom tags. +# Constructors are actually defined globally: do not redefined them in another +# class/file/package. This means that module recorder need import this file. yaml.add_constructor(u"!assert", assert_constructor) yaml.add_constructor(u"!record", record_constructor) yaml.add_constructor(u"!python", python_constructor) @@ -154,4 +167,5 @@ yaml.add_constructor(u"!context", context_constructor) yaml.add_constructor(u"!delete", delete_constructor) yaml.add_constructor(u"!url", url_constructor) yaml.add_constructor(u"!eval", eval_constructor) +yaml.add_constructor(u"!ref", ref_constructor) yaml.add_constructor(u"!ir_set", ir_set_constructor) From 3ebd4313d94faa3dfb77a7b6b9e6d81889b9d114 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 12:10:13 +0200 Subject: [PATCH 18/47] [IMP] Warn if an assertion has not been evaluated. bzr revid: jth@openerp.com-20100401101013-gi2zpo47iu7pbpn4 --- bin/tools/yaml_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 36eeadd0cf7..6b098289611 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -202,6 +202,7 @@ class YamlInterpreter(object): assertion, expressions = node.items()[0] if self.isnoupdate(assertion) and self.mode != 'init': + self.logger.warn('This assertion was not evaluated ("%s").' % assertion.string) return model = self.get_model(assertion.model) ids = self._get_assertion_id(assertion) From 8d62e97ff5030095ea3ab415a09fe5d8062d5cf0 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 15:26:03 +0200 Subject: [PATCH 19/47] [FIX] Assertion expressions list is a direct child of !assert block. bzr revid: jth@openerp.com-20100401132603-2ar1hsmi62c0vs3p --- bin/tools/yaml_import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 6b098289611..df273103130 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -217,7 +217,7 @@ class YamlInterpreter(object): context = self.get_context(assertion, self.eval_context) for id in ids: record = model.browse(self.cr, self.uid, id, context) - for test in expressions.get('test', ''): + for test in expressions: try: success = eval(test, self.eval_context, RecordDictWrapper(record)) except Exception, e: From 44f6ef941a26abbdc5bc9528390c2d03a9e7e1dc Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 15:26:51 +0200 Subject: [PATCH 20/47] [FIX] Logs the stack trace. bzr revid: jth@openerp.com-20100401132651-dgcz26yhw152f4sh --- bin/tools/yaml_import.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index df273103130..0136bcf69e0 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -607,9 +607,9 @@ class YamlInterpreter(object): try: self._process_node(node) except YamlImportException, e: - self.logger.log(logging.ERROR, e) + self.logger.exception(e) except Exception, e: - self.logger.log(logging.ERROR, e) + self.logger.exception(e) raise e def _process_node(self, node): From 51f8a94d874c0eebd9e404078a02e787e2a14198 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 15:27:09 +0200 Subject: [PATCH 21/47] [FIX] Workflow transition takes the model name, not the model object. bzr revid: jth@openerp.com-20100401132709-1tyxfoh9550za6y1 --- bin/tools/yaml_import.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 0136bcf69e0..06dfb151cc9 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -336,7 +336,6 @@ class YamlInterpreter(object): workflow, values = node.items()[0] if self.isnoupdate(workflow) and self.mode != 'init': return - model = self.get_model(workflow.model) if workflow.ref: id = self.get_id(workflow.ref) else: @@ -357,7 +356,7 @@ class YamlInterpreter(object): else: uid = self.uid wf_service = netsvc.LocalService("workflow") - wf_service.trg_validate(uid, model, id, workflow.action, self.cr) + wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr) def process_function(self, node): function, values = node.items()[0] From 41fc8c369af3cb3562b6ce44e333befda15837c8 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 19:22:27 +0200 Subject: [PATCH 22/47] [FIX] Added support for string and constant (int) logging level. bzr revid: jth@openerp.com-20100401172227-q5geonsglidfsuqa --- bin/tools/yaml_import.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 06dfb151cc9..2f48ca51618 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -182,10 +182,16 @@ class YamlInterpreter(object): return node def _log_assert_failure(self, severity, msg, *args): - self.assert_report.record(False, severity) - self.logger.log(severity, msg, *args) - if severity >= config['assert_exit_level']: - raise YamlImportAbortion('Severe assertion failure (%s), aborting.' % logging.getLevelName(severity)) + if isinstance(severity, types.StringTypes): + levelname = severity.strip().upper() + level = logging.getLevelName(levelname) + else: + level = severity + levelname = logging.getLevelName(level) + self.assert_report.record(False, levelname) + self.logger.log(level, msg, *args) + if level >= config['assert_exit_level']: + raise YamlImportAbortion('Severe assertion failure (%s), aborting.' % levelname) return def _get_assertion_id(self, assertion): From 0eb45de95c08a189b997b3af307bedb4407769b5 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 21:17:49 +0200 Subject: [PATCH 23/47] [FIX] Removed ANSI output in logging level. ANSI output changed the builtin log level name. This actually broke tests as we rely on the log level name for assertion report. See comments for indications to a more appropriate implementation. bzr revid: jth@openerp.com-20100401191749-j562qu28o0a066m1 --- bin/netsvc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/netsvc.py b/bin/netsvc.py index 475bbc33ba7..6aaff59ead3 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -205,7 +205,10 @@ def init_logger(): for level, (fg, bg) in mapping.items(): msg = "\x1b[%dm\x1b[%dm%s\x1b[0m" % (foreground(fg), background(bg), level) - logging.addLevelName(getattr(logging, level), msg) +# jth: we should not override default level name +# jth: use this instead http://stackoverflow.com/questions/384076/how-can-i-make-the-python-logging-output-to-be-colored +# jth: also, do not output ANSI if terminal doesn't support it (test it in Eclipse console and on windows) + #logging.addLevelName(getattr(logging, level), msg) class Logger(object): From f1b72c67438c626e33fd124307e4d540c40967cd Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 21:24:14 +0200 Subject: [PATCH 24/47] [FIX] Fixed eval context. bzr revid: jth@openerp.com-20100401192414-s6mfpwtkph3rxsn8 --- bin/tools/yaml_import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 2f48ca51618..4e974720c6c 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -126,7 +126,7 @@ class YamlInterpreter(object): self.pool = pooler.get_pool(cr.dbname) self.uid = 1 self.context = {} # opererp context - self.eval_context = {'ref': self._ref, '_ref': self._ref, 'time': time} # added '_ref' so that record['ref'] is possible + self.eval_context = {'ref': self._ref(), '_ref': self._ref(), 'time': time} # added '_ref' so that record['ref'] is possible def _ref(self): return lambda xml_id: self.get_id(xml_id) From 7043023dd859943a2cf5fa3e3e86652ad427f6e5 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 21:25:02 +0200 Subject: [PATCH 25/47] [FIX] Safer assignment to many2one. bzr revid: jth@openerp.com-20100401192502-zojg3dxhup49oz1m --- bin/tools/yaml_import.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 4e974720c6c..b4278abd5c8 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -178,6 +178,15 @@ class YamlInterpreter(object): def isnoupdate(self, node): return self.noupdate or node.noupdate or False + def _get_first_result(self, results, default=False): + if len(results): + value = results[0] + if isinstance(value, types.TupleType): + value = value[0] + else: + value = default + return value + def process_comment(self, node): return node @@ -296,7 +305,7 @@ class YamlInterpreter(object): if column._type in ("many2many", "one2many"): value = [(6, 0, elements)] else: # many2one - value = elements[0] + value = self._get_first_result(elements) elif column._type == "many2one": value = self.get_id(expression) elif column._type == "one2many": From 60cd823fa36df6749813124441c9c36d3eb493a7 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Thu, 1 Apr 2010 21:26:47 +0200 Subject: [PATCH 26/47] [FIX] Fixed function evaluation. bzr revid: jth@openerp.com-20100401192647-4ew1sci1l34q8ft3 --- bin/tools/yaml_import.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index b4278abd5c8..8fe1d634764 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -374,23 +374,30 @@ class YamlInterpreter(object): wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr) def process_function(self, node): - function, values = node.items()[0] + function, params = node.items()[0] if self.isnoupdate(function) and self.mode != 'init': return + model = self.get_model(function.model) context = self.get_context(function, self.eval_context) args = [] if function.eval: args = eval(function.eval, self.eval_context) - for value in values: - if not 'model' in value and (not 'eval' in value or not 'search' in value): - raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.') - value_model = self.get_model(value['model']) - local_context = {'obj': lambda x: value_model.browse(self.cr, self.uid, x, context=context)} - local_context.update(self.id_map) - id = eval(value['eval'], self.eval_context, local_context) - if id != None: - args.append(id) - model = self.get_model(function.model) + for i, param in enumerate(params): + if 'model' in param: + param_model = self.get_model(param['model']) + else: + param_model = model + if 'search' in param: + q = eval(param['search'], self.eval_context) + ids = param_model.search(cr, uid, q) + value = self._get_first_result(ids) + elif 'eval' in param: + local_context = {'obj': lambda x: value_model.browse(self.cr, self.uid, x, context)} + local_context.update(self.id_map) + value = eval(param['eval'], self.eval_context, local_context) + else: + raise YamlImportException('You must provide at least a "eval" or a "search" to function parameter #%d.' % i) + args.append(value) method = function.name getattr(model, method)(self.cr, self.uid, *args) From 336f0e40a43a5a7f7dc6511417b839ce8a06ec2a Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 2 Apr 2010 10:08:55 +0200 Subject: [PATCH 27/47] [REF] Cleanup of delete tag. bzr revid: jth@openerp.com-20100402080855-8pvhqcspi9mhojpa --- bin/import_xml.rng | 6 ++++-- bin/tools/yaml_import.py | 8 ++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bin/import_xml.rng b/bin/import_xml.rng index e637d42f123..c852d421e17 100644 --- a/bin/import_xml.rng +++ b/bin/import_xml.rng @@ -148,8 +148,10 @@ - - + + + + diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 8fe1d634764..0a5d8d7e09b 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -535,14 +535,10 @@ class YamlInterpreter(object): # TODO add remove ir.model.data def process_delete(self, node): - ids = [] if len(node.search): ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search, self.eval_context)) - if len(node.id): - try: - ids.append(self.get_id(node.id)) - except: - pass + else: + ids = [self.get_id(node.id)] if len(ids): self.pool.get(node.model).unlink(self.cr, self.uid, ids) self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids, direct=True) From 3f8b66799f6cf768320045aca6131b7d8eb6dc5c Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 2 Apr 2010 10:15:46 +0200 Subject: [PATCH 28/47] [REF] Cleanup ir_model_data._unlink bzr revid: jth@openerp.com-20100402081546-deiqbx40q2hkucck --- bin/addons/base/ir/ir_model.py | 8 ++++---- bin/tools/convert.py | 2 +- bin/tools/yaml_import.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index db03cef116f..a4afff1973d 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -548,10 +548,10 @@ class ir_model_data(osv.osv): table.replace('.', '_'))] = (table, inherit_id) return res_id - def _unlink(self, cr, uid, model, ids, direct=False): - for id in ids: - self.unlink_mark[(model, id)]=False - cr.execute('delete from ir_model_data where res_id=%s and model=%s', (id, model)) + def _unlink(self, cr, uid, model, res_ids): + for res_id in res_ids: + self.unlink_mark[(model, res_id)] = False + cr.execute('delete from ir_model_data where res_id=%s and model=%s', (res_id, model)) return True def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 1d4b1fd9d0b..36f2740dbc9 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -251,7 +251,7 @@ form: module.record_id""" % (xml_id,) pass if ids: self.pool.get(d_model).unlink(cr, self.uid, ids) - self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True) + self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids) def _tag_report(self, cr, rec, data_node=None): res = {} diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index 0a5d8d7e09b..cd1a1a34fd6 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -541,7 +541,7 @@ class YamlInterpreter(object): ids = [self.get_id(node.id)] if len(ids): self.pool.get(node.model).unlink(self.cr, self.uid, ids) - self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids, direct=True) + self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids) def process_url(self, node): self.validate_xml_id(node.id) From 790f32d9d0327945f9f1741b58bfb6979923539e Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Fri, 2 Apr 2010 16:03:23 +0200 Subject: [PATCH 29/47] [REF] function, ref, eval nodes. [IMP] YAML multi constructor for ref tag. bzr revid: jth@openerp.com-20100402140323-qmki5mvns0vxwmdm --- bin/tools/yaml_import.py | 96 +++++++++++++++++++++++++--------------- bin/tools/yaml_tag.py | 16 ++++--- 2 files changed, 69 insertions(+), 43 deletions(-) diff --git a/bin/tools/yaml_import.py b/bin/tools/yaml_import.py index cd1a1a34fd6..e77999a49f1 100644 --- a/bin/tools/yaml_import.py +++ b/bin/tools/yaml_import.py @@ -286,26 +286,39 @@ class YamlInterpreter(object): record_dict[field_name] = field_value return record_dict + def process_ref(self, node, column=None): + if node.search: + if node.model: + model_name = node.model + elif column: + model_name = column._obj + else: + raise YamlImportException('You need to give a model for the search, or a column to infer it.') + model = self.get_model(model_name) + q = eval(node.search, self.eval_context) + ids = model.search(self.cr, self.uid, q) + if node.use: + instances = model.browse(self.cr, self.uid, ids) + value = [inst[node.use] for inst in instances] + else: + value = ids + elif node.id: + value = self.get_id(node.id) + else: + value = None + return value + + def process_eval(self, node): + return eval(node.expression, self.eval_context) + def _eval_field(self, model, field_name, expression): column = model._columns[field_name] if is_ref(expression): - if expression.model: - other_model_name = expression.model - else: - other_model_name = column._obj - other_model = self.get_model(other_model_name) - if expression.search: - q = eval(expression.search, self.eval_context) - ids = other_model.search(self.cr, self.uid, q) - if expression.use: - instances = other_model.browse(self.cr, self.uid, ids) - elements = [inst[expression.use] for inst in instances] - else: - elements = ids - if column._type in ("many2many", "one2many"): - value = [(6, 0, elements)] - else: # many2one - value = self._get_first_result(elements) + elements = self.process_ref(expression) + if column._type in ("many2many", "one2many"): + value = [(6, 0, elements)] + else: # many2one + value = self._get_first_result(elements) elif column._type == "many2one": value = self.get_id(expression) elif column._type == "one2many": @@ -316,7 +329,7 @@ class YamlInterpreter(object): value = [(6, 0, ids)] else: # scalar field if is_eval(expression): - value = eval(expression.expression, self.eval_context) + value = self.process_eval(expression) else: value = expression # raise YamlImportException('Unsupported column "%s" or value %s:%s' % (field_name, type(expression), expression)) @@ -372,6 +385,32 @@ class YamlInterpreter(object): uid = self.uid wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr) + + def _eval_params(self, model, params): + args = [] + for i, param in enumerate(params): + if isinstance(param, types.ListType): + value = self._eval_params(model, param) + elif is_ref(param): + value = self.process_ref(param) + elif is_eval(param): + value = self.process_eval(param) + elif isinstance(param, types.DictionaryType): # supports XML syntax + param_model = self.get_model(param.get('model', model)) + if 'search' in param: + q = eval(param['search'], self.eval_context) + ids = param_model.search(cr, uid, q) + value = self._get_first_result(ids) + elif 'eval' in param: + local_context = {'obj': lambda x: param_model.browse(self.cr, self.uid, x, context)} + local_context.update(self.id_map) + value = eval(param['eval'], self.eval_context, local_context) + else: + raise YamlImportException('You must provide either a !ref or at least a "eval" or a "search" to function parameter #%d.' % i) + else: + value = param # scalar value + args.append(value) + return args def process_function(self, node): function, params = node.items()[0] @@ -379,25 +418,10 @@ class YamlInterpreter(object): return model = self.get_model(function.model) context = self.get_context(function, self.eval_context) - args = [] if function.eval: - args = eval(function.eval, self.eval_context) - for i, param in enumerate(params): - if 'model' in param: - param_model = self.get_model(param['model']) - else: - param_model = model - if 'search' in param: - q = eval(param['search'], self.eval_context) - ids = param_model.search(cr, uid, q) - value = self._get_first_result(ids) - elif 'eval' in param: - local_context = {'obj': lambda x: value_model.browse(self.cr, self.uid, x, context)} - local_context.update(self.id_map) - value = eval(param['eval'], self.eval_context, local_context) - else: - raise YamlImportException('You must provide at least a "eval" or a "search" to function parameter #%d.' % i) - args.append(value) + args = self.process_eval(function.eval) + else: + args = self._eval_params(function.model, params) method = function.name getattr(model, method)(self.cr, self.uid, *args) diff --git a/bin/tools/yaml_tag.py b/bin/tools/yaml_tag.py index 83f6dde9c8d..1d36dc17a5b 100644 --- a/bin/tools/yaml_tag.py +++ b/bin/tools/yaml_tag.py @@ -87,10 +87,9 @@ class Eval(YamlTag): super(Eval, self).__init__() class Ref(YamlTag): - # 'model' parameter is optional since it defaults to the column type - def __init__(self, search): - self.search = search - super(Ref, self).__init__() + def __init__(self, *args, **kwargs): + print "kwargs %s" % kwargs + super(Ref, self).__init__(*args, **kwargs) class IrSet(YamlTag): def __init__(self): @@ -144,8 +143,11 @@ def eval_constructor(loader, node): expression = loader.construct_scalar(node) return Eval(expression) -def ref_constructor(loader, node): - kwargs = loader.construct_mapping(node) +def ref_constructor(loader, tag_suffix, node): + if tag_suffix == "id": + kwargs = {"id": loader.construct_scalar(node)} + else: + kwargs = loader.construct_mapping(node) return Ref(**kwargs) def ir_set_constructor(loader, node): @@ -167,5 +169,5 @@ yaml.add_constructor(u"!context", context_constructor) yaml.add_constructor(u"!delete", delete_constructor) yaml.add_constructor(u"!url", url_constructor) yaml.add_constructor(u"!eval", eval_constructor) -yaml.add_constructor(u"!ref", ref_constructor) +yaml.add_multi_constructor(u"!ref", ref_constructor) yaml.add_constructor(u"!ir_set", ir_set_constructor) From ed2c762bc7b209679fd1c9a3691965127df194b8 Mon Sep 17 00:00:00 2001 From: Launchpad Code Hosting Date: Mon, 5 Apr 2010 04:53:17 +0100 Subject: [PATCH 30/47] Launchpad automatic translations update. bzr revid: codehost@crowberry-20100403035418-kws0c2b4zehstcsw bzr revid: codehost@crowberry-20100404035222-xo32id7uhd75od1g bzr revid: codehost@crowberry-20100405035317-jonllw2dd4inplg8 --- bin/addons/base/i18n/he.po | 8 ++++---- bin/addons/base/i18n/hr.po | 4 ++-- bin/addons/base/i18n/ja.po | 4 ++-- bin/addons/base/i18n/sv.po | 4 ++-- bin/addons/base/i18n/uk.po | 4 ++-- bin/addons/base/i18n/zh_CN.po | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bin/addons/base/i18n/he.po b/bin/addons/base/i18n/he.po index 1f8196732f8..b068412415d 100644 --- a/bin/addons/base/i18n/he.po +++ b/bin/addons/base/i18n/he.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2009-12-18 17:51+0000\n" +"PO-Revision-Date: 2010-04-04 19:08+0000\n" "Last-Translator: Ddorda \n" "Language-Team: Hebrew \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-01-14 04:46+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base @@ -3006,7 +3006,7 @@ msgstr "מפריד עשרות" #: view:res.request:0 #: field:res.request,history:0 msgid "History" -msgstr "הסטוריה" +msgstr "היסטוריה" #. module: base #: field:ir.attachment,create_uid:0 @@ -4776,7 +4776,7 @@ msgstr "8. %I:%M:%S %p ==> 06:25:20 PM" #: view:ir.translation:0 #: model:ir.ui.menu,name:base.menu_translation msgid "Translations" -msgstr "תרגום" +msgstr "תרגומים" #. module: base #: field:ir.sequence,padding:0 diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index 55f4faa1f59..7d42d7b1df1 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-01 04:15+0000\n" +"PO-Revision-Date: 2010-04-04 04:38+0000\n" "Last-Translator: goranc \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" "X-Generator: Launchpad (build Unknown)\n" "Language: hr\n" diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index b3b586b82a7..554dd6419e7 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-01 04:13+0000\n" +"PO-Revision-Date: 2010-04-04 04:23+0000\n" "Last-Translator: Harry (Open ERP) \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index 4021ba05f39..40d0f5d2420 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-01 04:09+0000\n" +"PO-Revision-Date: 2010-04-04 04:19+0000\n" "Last-Translator: Anders Wallenquist \n" "Language-Team: <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index bb304a6d3a1..95eb2534544 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-01 04:14+0000\n" +"PO-Revision-Date: 2010-04-04 04:27+0000\n" "Last-Translator: Fabien (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 18feb650de8..67b91d630c9 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-01 04:12+0000\n" +"PO-Revision-Date: 2010-04-04 04:43+0000\n" "Last-Translator: OpenERP Administrators \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" +"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base From 06560539e9d7719aa07ff074de72cf3db96e52cc Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Mon, 5 Apr 2010 10:17:47 +0200 Subject: [PATCH 31/47] [IMP] Removed print. bzr revid: jth@openerp.com-20100405081747-spggk7u9xe7t8bur --- bin/tools/yaml_tag.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/tools/yaml_tag.py b/bin/tools/yaml_tag.py index 1d36dc17a5b..97b29db1ac0 100644 --- a/bin/tools/yaml_tag.py +++ b/bin/tools/yaml_tag.py @@ -88,7 +88,6 @@ class Eval(YamlTag): class Ref(YamlTag): def __init__(self, *args, **kwargs): - print "kwargs %s" % kwargs super(Ref, self).__init__(*args, **kwargs) class IrSet(YamlTag): From 877fde1280102e1154402b2e00c8347276fba33f Mon Sep 17 00:00:00 2001 From: "Jay (Open ERP)" Date: Mon, 5 Apr 2010 15:44:13 +0530 Subject: [PATCH 32/47] [FIX] Unlink : Corrected code for proper query lp bug: https://launchpad.net/bugs/553258 fixed bzr revid: jvo@tinyerp.com-20100405101413-bvcus7jamjcmseex --- bin/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 92fb7f9400b..4f7e5fefdae 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -2785,7 +2785,7 @@ class orm(orm_template): self.check_access_rule(cr, uid, ids, 'unlink', context=context) for sub_ids in cr.split_for_in_conditions(ids): cr.execute('delete from ' + self._table + ' ' \ - 'where id in %s', sub_ids) + 'where id in %s', (sub_ids,)) for order, object, store_ids, fields in result_store: if object != self._name: From 1b3c687e4bd1d823c389b0302ecbd1bd8dba81de Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Mon, 5 Apr 2010 23:14:19 +0200 Subject: [PATCH 33/47] [REF] Extract some functions before adding new things. bzr revid: jth@openerp.com-20100405211419-yokve9t42fna43n3 --- bin/addons/__init__.py | 70 +++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index e07fdd07bbc..e3550cd7018 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -591,6 +591,43 @@ class MigrationManager(object): def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): + + def process_sql_file(cr, file): + queries = fp.read().split(';') + for query in queries: + new_query = ' '.join(query.split()) + if new_query: + cr.execute(new_query) + + def load_init_update_xml(cr, m, idref, mode, kind): + for filename in package.data.get('%s_xml' % kind, []): + logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename)) + _, ext = os.path.splitext(filename) + fp = tools.file_open(opj(m, filename)) + if ext == '.csv': + noupdate = (kind == 'init') + tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate) + elif ext == '.sql': + process_sql_file(cr, fp) + elif ext == '.yml': + tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs) + else: + tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs) + fp.close() + + def load_demo_xml(cr, m, idref, mode): + for xml in package.data.get('demo_xml', []): + name, ext = os.path.splitext(xml) + logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml)) + fp = tools.file_open(opj(m, xml)) + if ext == '.csv': + tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True) + elif ext == '.yml': + tools.convert_yaml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs) + else: + tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs) + fp.close() + # **kwargs is passed directly to convert_xml_import if not status: status = {} @@ -647,39 +684,10 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): 'license': package.data.get('license', 'GPL-2'), 'certificate': package.data.get('certificate') or None, }) - for filename in package.data.get('%s_xml' % kind, []): - logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename)) - name, ext = os.path.splitext(filename) - fp = tools.file_open(opj(m, filename)) - if ext == '.csv': - noupdate=False - if kind == 'init': - noupdate=True - tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate) - elif ext == '.sql': - queries = fp.read().split(';') - for query in queries: - new_query = ' '.join(query.split()) - if new_query: - cr.execute(new_query) - elif ext == '.yml': - tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs) - else: - tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs) - fp.close() + load_init_update_xml(cr, m, idref, mode, kind) if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'): status['progress'] = (float(statusi)+0.75) / len(graph) - for xml in package.data.get('demo_xml', []): - name, ext = os.path.splitext(xml) - logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml)) - fp = tools.file_open(opj(m, xml)) - if ext == '.csv': - tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True) - elif ext == '.yml': - tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs) - else: - tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs) - fp.close() + load_demo_xml(cr, m, idref, mode) cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid)) package_todo.append(package.name) From 7fcd252f16c391fefdba22e6ee526eac0d8030da Mon Sep 17 00:00:00 2001 From: Launchpad Code Hosting Date: Tue, 6 Apr 2010 05:01:20 +0100 Subject: [PATCH 34/47] Launchpad automatic translations update. bzr revid: codehost@crowberry-20100406040120-ce71kl30h2qvczxq --- bin/addons/base/i18n/he.po | 4 ++-- bin/addons/base/i18n/hr.po | 4 ++-- bin/addons/base/i18n/ja.po | 4 ++-- bin/addons/base/i18n/sv.po | 4 ++-- bin/addons/base/i18n/uk.po | 4 ++-- bin/addons/base/i18n/zh_CN.po | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bin/addons/base/i18n/he.po b/bin/addons/base/i18n/he.po index b068412415d..1e3765b48e3 100644 --- a/bin/addons/base/i18n/he.po +++ b/bin/addons/base/i18n/he.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 19:08+0000\n" +"PO-Revision-Date: 2010-04-05 04:29+0000\n" "Last-Translator: Ddorda \n" "Language-Team: Hebrew \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index 7d42d7b1df1..51a7f1d772a 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 04:38+0000\n" +"PO-Revision-Date: 2010-04-05 04:33+0000\n" "Last-Translator: goranc \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" "X-Generator: Launchpad (build Unknown)\n" "Language: hr\n" diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index 554dd6419e7..f55114223a5 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 04:23+0000\n" +"PO-Revision-Date: 2010-04-05 04:34+0000\n" "Last-Translator: Harry (Open ERP) \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:52+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index 40d0f5d2420..04fc6b3d022 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 04:19+0000\n" +"PO-Revision-Date: 2010-04-05 04:37+0000\n" "Last-Translator: Anders Wallenquist \n" "Language-Team: <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index 95eb2534544..2557ca954df 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 04:27+0000\n" +"PO-Revision-Date: 2010-04-05 04:31+0000\n" "Last-Translator: Fabien (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 67b91d630c9..3010205f573 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-04 04:43+0000\n" +"PO-Revision-Date: 2010-04-05 04:30+0000\n" "Last-Translator: OpenERP Administrators \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-05 03:53+0000\n" +"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base From e92975499ffbda6e9baed7f7cf08538611e6e239 Mon Sep 17 00:00:00 2001 From: "nel@tinyerp.com" <> Date: Tue, 6 Apr 2010 09:17:43 +0200 Subject: [PATCH 35/47] [FIX] context in read_group bzr revid: nel@tinyerp.com-20100406071743-qe507a4o2iwhgpd7 --- bin/osv/orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 4f7e5fefdae..37432a9ff90 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1936,7 +1936,8 @@ class orm(orm_template): for d in data: d['__domain'] = [(groupby,'=',alldata[d['id']][groupby] or False)] + domain - d['__context'] = {'group_by':groupby_list[1:]} + if not isinstance(groupby_list,(str, unicode)): + d['__context'] = {'group_by':groupby_list[1:]} if fget.has_key(groupby): if d[groupby] and fget[groupby]['type'] in ('date','datetime'): dt = datetime.datetime.strptime(alldata[d['id']][groupby][:7],'%Y-%m') From f29491458bee47fa1c2e1770f6ac0d291936c3d8 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Tue, 6 Apr 2010 12:24:45 +0200 Subject: [PATCH 36/47] [ADD] Tests declared in 'test' section of __terp__ are rolled back at the end of the module processing. [FIX] Removed an unnecessary commit in ir_sequence.get_id (replaced by SELECT ... FOR UPDATE NOWAIT): commit was actually breaking the test rollback behaviour. bzr revid: jth@openerp.com-20100406102445-le227exvrphahbx5 --- bin/addons/__init__.py | 35 +++++++++++++++++++++++++++++++ bin/addons/base/ir/ir_sequence.py | 21 ++++++++----------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index e3550cd7018..2b0f90bc5cf 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -589,6 +589,7 @@ class MigrationManager(object): if mod: del mod +log = logging.getLogger('init') def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): @@ -628,6 +629,35 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs) fp.close() + def load_data(cr, module_name, id_map, mode): + _load_data(cr, module_name, id_map, mode, 'data') + + def load_demo(cr, module_name, id_map, mode): + _load_data(cr, module_name, id_map, mode, 'demo') + + def load_test(cr, module_name, id_map, mode): + cr.commit() + try: + _load_data(cr, module_name, id_map, mode, 'test') + finally: + cr.rollback() + + def _load_data(cr, module_name, id_map, mode, kind): + noupdate = (kind == 'demo') + for filename in package.data.get(kind, []): + _, ext = os.path.splitext(filename) + log.info("module %s: loading %s", module_name, filename) + pathname = os.path.join(module_name, filename) + file = tools.file_open(pathname) + # TODO manage .csv file with noupdate == (kind == 'init') + if ext == '.sql': + process_sql_file(cr, fp) + elif ext == '.yml': + tools.convert_yaml_import(cr, module_name, file, id_map, mode, noupdate) + else: + tools.convert_xml_import(cr, module_name, file, id_map, mode, noupdate) + file.close() + # **kwargs is passed directly to convert_xml_import if not status: status = {} @@ -685,10 +715,15 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs): 'certificate': package.data.get('certificate') or None, }) load_init_update_xml(cr, m, idref, mode, kind) + load_data(cr, m, idref, mode) if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'): status['progress'] = (float(statusi)+0.75) / len(graph) load_demo_xml(cr, m, idref, mode) + load_demo(cr, m, idref, mode) cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid)) + + load_test(cr, m, idref, mode) + package_todo.append(package.name) migrations.migrate_module(package, 'post') diff --git a/bin/addons/base/ir/ir_sequence.py b/bin/addons/base/ir/ir_sequence.py index 8b0e7795a7c..fcc197116a1 100644 --- a/bin/addons/base/ir/ir_sequence.py +++ b/bin/addons/base/ir/ir_sequence.py @@ -73,18 +73,15 @@ class ir_sequence(osv.osv): } def get_id(self, cr, uid, sequence_id, test='id', context=None): - try: - assert test in ('code','id') - cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+'=%s AND active=%s FOR UPDATE', (sequence_id, True)) - res = cr.dictfetchone() - if res: - cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=%s', (res['id'], True)) - if res['number_next']: - return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) - else: - return self._process(res['prefix']) + self._process(res['suffix']) - finally: - cr.commit() + assert test in ('code','id') + cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+'=%s AND active=%s FOR UPDATE NOWAIT', (sequence_id, True)) + res = cr.dictfetchone() + if res: + cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=%s', (res['id'], True)) + if res['number_next']: + return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) + else: + return self._process(res['prefix']) + self._process(res['suffix']) return False def get(self, cr, uid, code): From 8326caf5de58ff62c0fd18239e0a7ec7ccceb9b3 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Tue, 6 Apr 2010 16:39:53 +0530 Subject: [PATCH 37/47] [IMP] service: pass db parameter in checkRequest for http bzr revid: hmo@tinyerp.com-20100406110953-5x0h9b3jlytnkty6 --- bin/service/http_server.py | 14 +++++++------- bin/service/websrv_lib.py | 3 +++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bin/service/http_server.py b/bin/service/http_server.py index fe3d98a0004..47ae6c35ae8 100644 --- a/bin/service/http_server.py +++ b/bin/service/http_server.py @@ -251,12 +251,11 @@ class OerpAuthProxy(AuthProxy): self.auth_tries = 0 self.last_auth = None - def checkRequest(self,handler,path = '/'): - if self.auth_creds: - return True + def checkRequest(self,handler,path, db=False): auth_str = handler.headers.get('Authorization',False) try: - db = handler.get_db_from_path(path) + if not db: + db = handler.get_db_from_path(path) print "Got db:",db except: if path.startswith('/'): @@ -267,8 +266,9 @@ class OerpAuthProxy(AuthProxy): else: #FIXME! self.provider.log("Wrong path: %s, failing auth" %path) - raise AuthRejectedExc("Authorization failed. Wrong sub-path.") - + raise AuthRejectedExc("Authorization failed. Wrong sub-path.") + if self.auth_creds.get(db): + return True if auth_str and auth_str.startswith('Basic '): auth_str=auth_str[len('Basic '):] (user,passwd) = base64.decodestring(auth_str).split(':') @@ -276,7 +276,7 @@ class OerpAuthProxy(AuthProxy): acd = self.provider.authenticate(db,user,passwd,handler.client_address) if acd != False: self.auth_creds[db] = acd - self.last_auth=db + self.last_auth = db return True if self.auth_tries > 5: self.provider.log("Failing authorization after 5 requests w/o password") diff --git a/bin/service/websrv_lib.py b/bin/service/websrv_lib.py index 354311eaa64..464c41ca356 100644 --- a/bin/service/websrv_lib.py +++ b/bin/service/websrv_lib.py @@ -234,6 +234,9 @@ class MultiHTTPHandler(FixSendError,BaseHTTPRequestHandler): if fore.close_connection: # print "Closing connection because of handler" self.close_connection = fore.close_connection + if hasattr(fore, '_flush'): + fore._flush() + def parse_rawline(self): """Parse a request (internal). From 24d873fdbecf7444b861d59e8a7a4bcea1fc0f92 Mon Sep 17 00:00:00 2001 From: Julien Thewys Date: Tue, 6 Apr 2010 14:33:25 +0200 Subject: [PATCH 38/47] [MERGE] Fixed previous merges. bzr revid: jth@openerp.com-20100406123325-219p7klnjaen82h2 --- bin/addons/base/i18n/bg.po | 16 ---------------- bin/addons/base/i18n/hr.po | 32 -------------------------------- bin/addons/base/i18n/it.po | 9 --------- bin/addons/base/i18n/ja.po | 32 -------------------------------- bin/addons/base/i18n/sv.po | 32 -------------------------------- bin/addons/base/i18n/uk.po | 32 -------------------------------- bin/addons/base/i18n/zh_CN.po | 32 -------------------------------- 7 files changed, 185 deletions(-) diff --git a/bin/addons/base/i18n/bg.po b/bin/addons/base/i18n/bg.po index 7061cf9d069..297b2d31301 100644 --- a/bin/addons/base/i18n/bg.po +++ b/bin/addons/base/i18n/bg.po @@ -7,29 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:19+0000\n" -======= -"PO-Revision-Date: 2010-03-31 08:05+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-01 04:11+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: Boris \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index 1f286953955..51a7f1d772a 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -7,45 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:36+0000\n" -======= -"PO-Revision-Date: 2010-03-31 06:01+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-01 04:15+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-03 04:32+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-05 04:33+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: goranc \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-04 03:52+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" "Language: hr\n" diff --git a/bin/addons/base/i18n/it.po b/bin/addons/base/i18n/it.po index 8a9a054c1dd..f98e352340b 100644 --- a/bin/addons/base/i18n/it.po +++ b/bin/addons/base/i18n/it.po @@ -7,22 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 09:53+0000\n" -"Last-Translator: Carlo Vettore \n" -======= "PO-Revision-Date: 2010-03-31 05:14+0000\n" "Last-Translator: OpenERP Administrators \n" ->>>>>>> MERGE-SOURCE "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= "X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index ad273b86073..f55114223a5 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -8,45 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:24+0000\n" -======= -"PO-Revision-Date: 2010-03-31 05:47+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-01 04:13+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-03 04:34+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-05 04:34+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: Harry (Open ERP) \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-04 03:51+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index 58aab09492b..04fc6b3d022 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -7,45 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:18+0000\n" -======= -"PO-Revision-Date: 2010-03-31 04:49+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-01 04:09+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-03 04:28+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-05 04:37+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: Anders Wallenquist \n" "Language-Team: <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-04 03:52+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index a1612c6d22d..2557ca954df 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -7,45 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:37+0000\n" -======= -"PO-Revision-Date: 2010-03-31 05:27+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-01 04:14+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-03 04:31+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-05 04:31+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: Fabien (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-04 03:52+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 9f124f629d9..3010205f573 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -7,45 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"PO-Revision-Date: 2010-03-30 04:19+0000\n" -======= -"PO-Revision-Date: 2010-03-31 05:03+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-01 04:12+0000\n" ->>>>>>> MERGE-SOURCE -======= -"PO-Revision-Date: 2010-04-03 04:30+0000\n" ->>>>>>> MERGE-SOURCE -======= "PO-Revision-Date: 2010-04-05 04:30+0000\n" ->>>>>>> MERGE-SOURCE "Last-Translator: OpenERP Administrators \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -<<<<<<< TREE -"X-Launchpad-Export-Date: 2010-03-31 03:54+0000\n" -======= -"X-Launchpad-Export-Date: 2010-04-01 03:40+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-02 03:41+0000\n" ->>>>>>> MERGE-SOURCE -======= -"X-Launchpad-Export-Date: 2010-04-04 03:52+0000\n" ->>>>>>> MERGE-SOURCE -======= "X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" ->>>>>>> MERGE-SOURCE "X-Generator: Launchpad (build Unknown)\n" #. module: base From d6f25f5155707638fd63f715ed12c51a681005d3 Mon Sep 17 00:00:00 2001 From: Launchpad Code Hosting Date: Wed, 7 Apr 2010 04:46:30 +0100 Subject: [PATCH 39/47] Launchpad automatic translations update. bzr revid: codehost@crowberry-20100407034630-qmsnzcle2lwkqxey --- bin/addons/base/i18n/hr.po | 4 ++-- bin/addons/base/i18n/ja.po | 4 ++-- bin/addons/base/i18n/sv.po | 4 ++-- bin/addons/base/i18n/uk.po | 4 ++-- bin/addons/base/i18n/zh_CN.po | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/addons/base/i18n/hr.po b/bin/addons/base/i18n/hr.po index 51a7f1d772a..0069d26fd4f 100644 --- a/bin/addons/base/i18n/hr.po +++ b/bin/addons/base/i18n/hr.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-05 04:33+0000\n" +"PO-Revision-Date: 2010-04-06 04:41+0000\n" "Last-Translator: goranc \n" "Language-Team: openerp-translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" +"X-Launchpad-Export-Date: 2010-04-07 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" "Language: hr\n" diff --git a/bin/addons/base/i18n/ja.po b/bin/addons/base/i18n/ja.po index f55114223a5..98ee2ba6b7b 100644 --- a/bin/addons/base/i18n/ja.po +++ b/bin/addons/base/i18n/ja.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-05 04:34+0000\n" +"PO-Revision-Date: 2010-04-06 04:39+0000\n" "Last-Translator: Harry (Open ERP) \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-06 04:00+0000\n" +"X-Launchpad-Export-Date: 2010-04-07 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/sv.po b/bin/addons/base/i18n/sv.po index 04fc6b3d022..26ba50df07c 100644 --- a/bin/addons/base/i18n/sv.po +++ b/bin/addons/base/i18n/sv.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-05 04:37+0000\n" +"PO-Revision-Date: 2010-04-06 04:37+0000\n" "Last-Translator: Anders Wallenquist \n" "Language-Team: <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" +"X-Launchpad-Export-Date: 2010-04-07 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/uk.po b/bin/addons/base/i18n/uk.po index 2557ca954df..15eb8509852 100644 --- a/bin/addons/base/i18n/uk.po +++ b/bin/addons/base/i18n/uk.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-05 04:31+0000\n" +"PO-Revision-Date: 2010-04-06 04:43+0000\n" "Last-Translator: Fabien (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" +"X-Launchpad-Export-Date: 2010-04-07 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base diff --git a/bin/addons/base/i18n/zh_CN.po b/bin/addons/base/i18n/zh_CN.po index 3010205f573..fa885c2f0df 100644 --- a/bin/addons/base/i18n/zh_CN.po +++ b/bin/addons/base/i18n/zh_CN.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-12-18 08:39+0000\n" -"PO-Revision-Date: 2010-04-05 04:30+0000\n" +"PO-Revision-Date: 2010-04-06 04:37+0000\n" "Last-Translator: OpenERP Administrators \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-04-06 04:01+0000\n" +"X-Launchpad-Export-Date: 2010-04-07 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base From 90f0071acb93e05f743f05e5e54c1d2541d570fc Mon Sep 17 00:00:00 2001 From: "nel@tinyerp.com" <> Date: Wed, 7 Apr 2010 08:55:02 +0200 Subject: [PATCH 40/47] Merge and FIX VAT declaration basing on stable sources bzr revid: nel@tinyerp.com-20100407065502-62cik4iamvtzm4te --- addons/board_crm_configuration/__terp__.py | 2 +- addons/event/wizard/event_registration.py | 11 +++- addons/l10n_be/company.py | 6 ++- .../wizard/l10n_be_account_vat_declaration.py | 52 ++++++++++--------- .../l10n_be_account_vat_declaration_view.xml | 17 +++--- 5 files changed, 52 insertions(+), 36 deletions(-) diff --git a/addons/board_crm_configuration/__terp__.py b/addons/board_crm_configuration/__terp__.py index 3c303ee2d1c..09bd6e25bc1 100644 --- a/addons/board_crm_configuration/__terp__.py +++ b/addons/board_crm_configuration/__terp__.py @@ -34,7 +34,7 @@ This module implements a dashboard for CRM that includes: * Jobs Tracking (graph) """, 'author': 'Tiny', - 'depends': ['board', 'crm', 'report_crm'], + 'depends': ['board', 'crm'], 'update_xml': ['board_crm_statistical_view.xml', 'board_crm_view.xml'], 'demo_xml': ['board_crm_demo.xml'], 'installable': True, diff --git a/addons/event/wizard/event_registration.py b/addons/event/wizard/event_registration.py index e7252a1a63d..d8087b7a569 100644 --- a/addons/event/wizard/event_registration.py +++ b/addons/event/wizard/event_registration.py @@ -27,6 +27,15 @@ class event_registration_list(osv.osv_memory): _description = "List Event Registrations" def open_registration(self, cr, uid, ids, context={}): + if not context.get('active_id', None): + return { + 'name': 'Event Registrations', + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'event.registration', + 'type': 'ir.actions.act_window' + } + cr.execute('SELECT section_id FROM event_event WHERE id = %s', (context['active_id'],)) res = cr.fetchone() return { @@ -40,4 +49,4 @@ class event_registration_list(osv.osv_memory): event_registration_list() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/l10n_be/company.py b/addons/l10n_be/company.py index 4395f13380e..30435f0fc49 100644 --- a/addons/l10n_be/company.py +++ b/addons/l10n_be/company.py @@ -25,7 +25,7 @@ class res_company(osv.osv): _description = 'res.company' def _get_default_ad(self, addresses): - city = post_code = address = "" + city = post_code = address = country_code = "" for ads in addresses: if ads.type == 'default': city = ads.city or "" @@ -34,7 +34,9 @@ class res_company(osv.osv): address = ads.street or "" if ads.street2: address += " " + ads.street2 - return city, post_code, address + if ads.country_id: + country_code = ads.country_id and ads.country_id.code or "" + return city, post_code, address, country_code res_company() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py b/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py index 9dd5ea5b269..4b531438171 100644 --- a/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py +++ b/addons/l10n_be/wizard/l10n_be_account_vat_declaration.py @@ -18,25 +18,31 @@ # along with this program. If not, see . # ############################################################################## -import base64 +import time +import datetime +import base64 from osv import osv, fields from tools.translate import _ class l10n_be_vat_declaration(osv.osv_memory): - """ Periodical VAT Declaration """ + """ Vat Declaration """ _name = "l1on_be.vat.declaration" _description = "Vat Declaration" _columns = { 'period_id': fields.many2one('account.period','Period', required=True), 'msg': fields.text('File created', size=64, readonly=True), - 'file_save': fields.binary('Save File'), - } + 'file_save' : fields.binary('Save File'), + 'ask_resitution': fields.boolean('Ask Restitution'), + 'ask_payment': fields.boolean('Ask Payment'), + 'client_nihil': fields.boolean('Last Declaration of Entreprise', help = 'Thick this case only if it concerns only the last statement on the civil or cessation of activity') + + } _defaults = { 'msg': lambda *a:'''Save the File with '".xml"' extension.''', - } + } def create_xml(self, cr, uid, ids, context={}): obj_fyear = self.pool.get('account.fiscalyear') @@ -46,12 +52,12 @@ class l10n_be_vat_declaration(osv.osv_memory): obj_comp = self.pool.get('res.company') obj_data = self.pool.get('ir.model.data') - list_of_tags=['00','01','02','03','45','46','47','48','49','54','55','56','57','59','61','62','63','64','71','81','82','83','84','85','86','87','91'] + list_of_tags=['00','01','02','03','44','45','46','47','48','49','54','55','56','57','59','61','62','63','64','71','81','82','83','84','85','86','87','88','91'] obj_company = obj_user.browse(cr, uid, uid, context=context).company_id user_cmpny = obj_company.name vat_no=obj_company.partner_id.vat if not vat_no: - raise osv.except_osv(_('Data Insufficient'),_('No VAT Number Associated with Main Company!')) + raise wizard.except_wizard(_('Data Insufficient'),_('No VAT Number Associated with Main Company!')) tax_code_ids = obj_tax_code.search(cr, uid, [], context=context) ctx = context.copy() @@ -59,50 +65,46 @@ class l10n_be_vat_declaration(osv.osv_memory): ctx['period_id'] = data['period_id'] #added context here tax_info = obj_tax_code.read(cr, uid, tax_code_ids, ['code','sum_period'], context=ctx) - address = post_code = city = '' - if not obj_company.partner_id.address: - address = post_code = city = '' + address = post_code = city = country_code = '' + city, post_code, address, country_code = pooler.get_pool(cr.dbname).get('res.company')._get_default_ad(obj_company.partner_id.address) + - city, post_code, address = obj_comp._get_default_ad(obj_company.partner_id.address) year_id = obj_fyear.find(cr, uid) account_period = obj_acc_period.browse(cr, uid, data['period_id'], context=context) - current_year = account_period.fiscalyear_id.name period_code = account_period.code - send_ref = user_cmpny - if period_code: - send_ref = send_ref + period_code - + send_ref = str(obj_company.partner_id.id) + str(account_period.date_start[5:7]) + str(account_period.date_stop[:4]) data_of_file='\n' data_of_file +='\n\t\n\t\t'+str(vat_no)+'\n\t\t'+str(obj_company.name)+'\n\t\t
'+address+'
' - data_of_file +='\n\t\t'+post_code+'\n\t\t'+city+'\n\t\t'+send_ref+'\n\t
' - data_of_file +='\n\t\n\t\t1\n\t\t'+str(vat_no)+'\n\t\t\n\t\t\t' - + data_of_file +='\n\t\t'+post_code+'\n\t\t'+city+'\n\t\t'+country_code+'\n\t\t'+send_ref+'\n\t' + data_of_file +='\n\t\n\t\t1\n\t\t'+str(vat_no[2:])+'\n\t\t\n\t\t\t' + starting_month = account_period.date_start[5:7] ending_month = account_period.date_stop[5:7] if starting_month != ending_month: #starting month and ending month of selected period are not the same #it means that the accounting isn't based on periods of 1 month but on quarters quarter = str(((int(starting_month) - 1) / 3) + 1) - data_of_file += '' + quarter + '\n\t\t\t' + data_of_file += ''+quarter+'\n\t\t\t' else: - data_of_file += '' + starting_month + '\n\t\t\t' + data_of_file += ''+starting_month+'\n\t\t\t' data_of_file += '' + str(account_period.date_stop[:4]) + '\n\t\t\n\t\t' + data_of_file += '\n\t\t'+ (data['form']['client_nihil'] and 'YES' or 'NO') +'' data_of_file +='\n\t\t\n\t\t\t' for item in tax_info: if item['code']: if item['code'] == '71-72': - item['code'] = '71' + item['code']='71' if item['code'] in list_of_tags: - data_of_file +='\n\t\t\t\t' + str(int(item['sum_period']*100)) + '' + data_of_file +='\n\t\t\t\t' + str(abs(int(item['sum_period']*100))) + '' data_of_file +='\n\t\t\t\n\t\t\n\t\n
' data['file_save'] = base64.encodestring(data_of_file) self.write(cr, uid, ids, {'file_save':data['file_save']}, context=context) - return True + l10n_be_vat_declaration() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/l10n_be/wizard/l10n_be_account_vat_declaration_view.xml b/addons/l10n_be/wizard/l10n_be_account_vat_declaration_view.xml index 56f8b6477f9..62399ae1cba 100644 --- a/addons/l10n_be/wizard/l10n_be_account_vat_declaration_view.xml +++ b/addons/l10n_be/wizard/l10n_be_account_vat_declaration_view.xml @@ -3,9 +3,9 @@ + id="menu_finance_belgian_statement" + name="Belgium Statements" + parent="account.menu_finance_legal_statement"/> Select Period @@ -13,9 +13,12 @@ form
- - -