From 5cb1835e26a3868df3a0a71b3329bea17f455327 Mon Sep 17 00:00:00 2001 From: Yannick Vaucher Date: Fri, 15 Mar 2013 15:24:03 +0100 Subject: [PATCH 01/65] [FIX] add missing context on compute call in pricelist price_get_multi context lp bug: https://launchpad.net/bugs/1155624 fixed bzr revid: yannick.vaucher@camptocamp.com-20130315142403-gz7fy7etwzls96rt --- addons/product/pricelist.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 73707e39807..3a466191795 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -236,7 +236,10 @@ class product_pricelist(osv.osv): qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id uom_price_already_computed = True - price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) + price = currency_obj.compute(cr, uid, + ptype_src, res['currency_id'], + price_tmp, round=False, + context=context) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: where = [] From 300d5be0e6af4d24d09419e0be6807b265da3cd8 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 28 Mar 2013 13:03:37 +0100 Subject: [PATCH 02/65] [FIX] web: int/float fields were not offering auto-completion in search views, making them un-searchable except via advanced search Added the missing complete() function and removed the incorrect value_from() override that seemed to be a leftover remnant of the 6.1 search field implementation of get_value(), wrongly renamed for 7.0. bzr revid: odo@openerp.com-20130328120337-lao4o9i0owsbpysi --- addons/web/static/src/js/search.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index c1ace6b57f3..50576687808 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1346,20 +1346,22 @@ instance.web.search.CharField = instance.web.search.Field.extend( /** @lends ins } }); instance.web.search.NumberField = instance.web.search.Field.extend(/** @lends instance.web.search.NumberField# */{ - value_from: function () { - if (!this.$el.val()) { - return null; - } - var val = this.parse(this.$el.val()), - check = Number(this.$el.val()); - if (isNaN(val) || val !== check) { - this.$el.addClass('error'); - throw new instance.web.search.Invalid( - this.attrs.name, this.$el.val(), this.error_message); - } - this.$el.removeClass('error'); - return val; - } + complete: function (value) { + var val = this.parse(value); + if (!val || isNaN(val)) { return $.when(); } + var label = _.str.sprintf(_.str.escapeHTML( + _t("Search %(field)s for: %(value)s")), { + field: '' + this.attrs.string + '', + value: '' + _.str.escapeHTML(value) + ''}); + return $.when([{ + label: label, + facet: { + category: this.attrs.string, + field: this, + values: [{label: value, value: val}] + } + }]); + }, }); /** * @class From 35d61bbd8bbfd034b3d9e01347f0f13ee0ef17ac Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 28 Mar 2013 16:35:02 +0100 Subject: [PATCH 03/65] [FIX] web search: correct previous fix to properly handle searching for 0 on number fields Also removed useless HTML escaping and added basic tests. bzr revid: odo@openerp.com-20130328153502-v71q2m60wh37ganq --- addons/web/static/src/js/search.js | 6 ++-- addons/web/static/test/search.js | 53 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 50576687808..37f8bd8b3f2 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1348,9 +1348,9 @@ instance.web.search.CharField = instance.web.search.Field.extend( /** @lends ins instance.web.search.NumberField = instance.web.search.Field.extend(/** @lends instance.web.search.NumberField# */{ complete: function (value) { var val = this.parse(value); - if (!val || isNaN(val)) { return $.when(); } - var label = _.str.sprintf(_.str.escapeHTML( - _t("Search %(field)s for: %(value)s")), { + if (isNaN(val)) { return $.when(); } + var label = _.str.sprintf( + _t("Search %(field)s for: %(value)s"), { field: '' + this.attrs.string + '', value: '' + _.str.escapeHTML(value) + ''}); return $.when([{ diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js index 6c4b6d61d3c..73d984506b2 100644 --- a/addons/web/static/test/search.js +++ b/addons/web/static/test/search.js @@ -614,6 +614,59 @@ openerp.testing.section('search.completions', { {relation: 'dummy.model'}, view); return f.complete("bob"); }); + test('Integer: invalid', {asserts: 1}, function (instance) { + var view = {inputs: []}; + var f = new instance.web.search.IntegerField( + {attrs: {string: "Dummy"}}, {}, view); + return f.complete("qux") + .done(function (completions) { + ok(!completions, "non-number => no completion"); + }); + }); + test('Integer: non-zero', {asserts: 5}, function (instance) { + var view = {inputs: []}; + var f = new instance.web.search.IntegerField( + {attrs: {string: "Dummy"}}, {}, view); + return f.complete("-2") + .done(function (completions) { + equal(completions.length, 1, "number fields provide 1 completion only"); + var facet = new instance.web.search.Facet(completions[0].facet); + equal(facet.get('category'), f.attrs.string); + equal(facet.get('field'), f); + var value = facet.values.at(0); + equal(value.get('label'), "-2"); + equal(value.get('value'), -2); + }); + }); + test('Integer: zero', {asserts: 3}, function (instance) { + var view = {inputs: []}; + var f = new instance.web.search.IntegerField( + {attrs: {string: "Dummy"}}, {}, view); + return f.complete("0") + .done(function (completions) { + equal(completions.length, 1, "number fields provide 1 completion only"); + var facet = new instance.web.search.Facet(completions[0].facet); + var value = facet.values.at(0); + equal(value.get('label'), "0"); + equal(value.get('value'), 0); + }); + }); + test('Float: non-zero', {asserts: 5}, function (instance) { + var view = {inputs: []}; + var f = new instance.web.search.FloatField( + {attrs: {string: "Dummy"}}, {}, view); + return f.complete("42.37") + .done(function (completions) { + equal(completions.length, 1, "float fields provide 1 completion only"); + var facet = new instance.web.search.Facet(completions[0].facet); + equal(facet.get('category'), f.attrs.string); + equal(facet.get('field'), f); + var value = facet.values.at(0); + equal(value.get('label'), "42.37"); + equal(value.get('value'), 42.37); + }); + }); + }); openerp.testing.section('search.serialization', { dependencies: ['web.search'], From 17eaf9e92a44db7238f9ca3a53041bc94314322e Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 29 Mar 2013 15:03:29 +0100 Subject: [PATCH 04/65] [TESTS] add dispatcher tests bzr revid: xmo@openerp.com-20130329140329-a78lqt87str80v99 --- addons/web/tests/__init__.py | 3 +- addons/web/tests/test_dispatch.py | 181 ++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 addons/web/tests/test_dispatch.py diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py index d7abb8e5a8c..2734bd45ddb 100644 --- a/addons/web/tests/__init__.py +++ b/addons/web/tests/__init__.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- -from . import test_dataset, test_menu, test_serving_base, test_js +from . import test_dataset, test_menu, test_serving_base, test_js, test_dispatch fast_suite = [] checks = [ test_dataset, test_menu, test_serving_base, + test_dispatch, ] diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py new file mode 100644 index 00000000000..df142043de5 --- /dev/null +++ b/addons/web/tests/test_dispatch.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +import json +import unittest2 + +from .. import http +import werkzeug.test + + +def setUpModule(): + """ + Force load_addons once to import all the crap we don't care for as this + thing is full of side-effects + """ + http.Root().load_addons() + +class DispatchCleanup(unittest2.TestCase): + """ + Cleans up controllers registries in the web client so it's possible to + test controllers registration and dispatching in isolation. + """ + def setUp(self): + self.classes = http.controllers_class + self.objects = http.controllers_object + self.paths = http.controllers_path + + http.controllers_class = [] + http.controllers_object = {} + http.controllers_path = {} + + def tearDown(self): + http.controllers_path = self.paths + http.controllers_object = self.objects + http.controllers_class = self.classes + + +def jsonrpc_body(params=None): + """ + Builds and dumps the body of a JSONRPC request with params ``params`` + """ + return json.dumps({ + 'jsonrpc': '2.0', + 'method': 'call', + 'id': None, + 'params': params or {}, + }) + + +def jsonrpc_response(result=None): + """ + Builds a JSONRPC response (as a Python dict) with result ``result`` + """ + return { + u'jsonrpc': u'2.0', + u'id': None, + u'result': result, + } + + +class TestDispatching(DispatchCleanup): + def setUp(self): + super(TestDispatching, self).setUp() + self.app = http.Root() + self.client = werkzeug.test.Client(self.app) + + def test_not_exposed(self): + class CatController(http.Controller): + _cp_path = '/cat' + + def index(self): + return 'Blessid iz da feline' + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('404 NOT FOUND', status) + + def test_basic_http(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.httprequest + def index(self, req): + return 'no walk in counsil of wickid,' + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('200 OK', status) + self.assertEqual('no walk in counsil of wickid,', ''.join(body)) + + def test_basic_jsonrpc(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.jsonrequest + def index(self, req): + return 'no place paws in path of da sinnerz,' + self.app.load_addons() + + body, status, headers = self.client.post('/cat', data=jsonrpc_body()) + + self.assertEqual('200 OK', status) + self.assertEqual( + jsonrpc_response('no place paws in path of da sinnerz,'), + json.loads(''.join(body))) + + def test_add_method(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.httprequest + def index(self, req): + return 'no sit and purr with da mockerz.' + + class CeilingController(CatController): + @http.httprequest + def lol(self, req): + return 'But der delightz in lawz of Ceiling Cat,' + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('200 OK', status) + self.assertEqual('no sit and purr with da mockerz.', ''.join(body)) + body, status, headers = self.client.get('/cat/lol') + self.assertEqual('200 OK', status) + self.assertEqual('But der delightz in lawz of Ceiling Cat,', + ''.join(body)) + + def test_override_method(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.httprequest + def index(self, req): + return 'an ponderz' + + class CeilingController(CatController): + @http.httprequest + def index(self, req): + return '%s much.' % super(CeilingController, self).index(req) + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('200 OK', status) + self.assertEqual('an ponderz much.', ''.join(body)) + + def test_make_invisible(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.httprequest + def index(self, req): + return 'Tehy liek treez bai teh waterz,' + + class CeilingController(CatController): + def index(self, req): + return super(CeilingController, self).index(req) + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('404 NOT FOUND', status) + + def test_make_json_invisible(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.jsonrequest + def index(self, req): + return 'Tehy liek treez bai teh waterz,' + + class CeilingController(CatController): + def index(self, req): + return super(CeilingController, self).index(req) + + self.app.load_addons() + + body, status, headers = self.client.post('/cat') + self.assertEqual('404 NOT FOUND', status) From 23904b523af532aa87341b681e298b7ae2fcec01 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 29 Mar 2013 15:16:45 +0100 Subject: [PATCH 05/65] [TEST] test normal inheritance of controllers bzr revid: xmo@openerp.com-20130329141645-m70aitx3kv74yo97 --- addons/web/tests/test_dispatch.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index df142043de5..54b987cf555 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -179,3 +179,30 @@ class TestDispatching(DispatchCleanup): body, status, headers = self.client.post('/cat') self.assertEqual('404 NOT FOUND', status) + + def test_extend(self): + class CatController(http.Controller): + _cp_path = '/cat' + + @http.httprequest + def index(self, req): + return '[%s]' % self.speak() + + def speak(self): + return 'Yu ordered cheezburgerz,' + + class DogController(CatController): + _cp_path = '/dog' + + def speak(self): + return 'Woof woof woof woof' + + self.app.load_addons() + + body, status, headers = self.client.get('/cat') + self.assertEqual('200 OK', status) + self.assertEqual('[Yu ordered cheezburgerz,]', ''.join(body)) + + body, status, headers = self.client.get('/dog') + self.assertEqual('200 OK', status) + self.assertEqual('[Woof woof woof woof]', ''.join(body)) From 1f421e7928f5295a21e87f43a94faded5a72bc13 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 2 Apr 2013 16:32:17 +0200 Subject: [PATCH 06/65] [FIX] redefinition and in-place extension scenarios for controllers bzr revid: xmo@openerp.com-20130402143217-pfe2288iodw9r81g --- addons/web/http.py | 54 ++++++++-- addons/web/tests/test_dispatch.py | 165 +++++++++++++++++++++++++++--- 2 files changed, 197 insertions(+), 22 deletions(-) diff --git a/addons/web/http.py b/addons/web/http.py index e05d74e0873..f08d7c64c4d 100644 --- a/addons/web/http.py +++ b/addons/web/http.py @@ -354,18 +354,58 @@ def httprequest(f): #---------------------------------------------------------- addons_module = {} addons_manifest = {} -controllers_class = [] -controllers_object = {} +controllers_class = {} controllers_path = {} class ControllerType(type): def __init__(cls, name, bases, attrs): super(ControllerType, cls).__init__(name, bases, attrs) - controllers_class.append(("%s.%s" % (cls.__module__, cls.__name__), cls)) + # Only for root "Controller" + if bases == (object,): + assert name == 'Controller' + return + + path = attrs.get('_cp_path') + if Controller in bases: + assert path, "Controller subclass %s missing a _cp_path" % cls + else: + parent_paths = set(base._cp_path for base in bases + if issubclass(base, Controller)) + assert len(parent_paths) == 1,\ + "%s inheriting from multiple controllers is not supported" % ( + name) + [parent_path] = parent_paths + [parent] = [ + controller for controller in controllers_class.itervalues() + if controller._cp_path == parent_path] + + # inherit from a Controller subclass + if path: + _logger.warn("Re-exposing %s at %s.\n" + "\tThis usage is unsupported.", + parent.__name__, + attrs['_cp_path']) + + if path: + assert path not in controllers_class,\ + "Trying to expose %s at the same URL as %s" % ( + cls, controllers_class[path]) + controllers_class[path] = cls + class Controller(object): __metaclass__ = ControllerType + def __new__(cls, *args, **kwargs): + subclasses = [c for c in cls.__subclasses__() + if c._cp_path is cls._cp_path] + if subclasses: + name = "%s (+%s)" % ( + cls.__name__, + '+'.join(sub.__name__ for sub in subclasses)) + cls = type(name, tuple(reversed(subclasses)), {}) + return object.__new__(cls) + #---------------------------------------------------------- # Session context manager #---------------------------------------------------------- @@ -558,12 +598,8 @@ class Root(object): addons_manifest[module] = manifest self.statics['/%s/static' % module] = path_static - for k, v in controllers_class: - if k not in controllers_object: - o = v() - controllers_object[k] = o - if hasattr(o, '_cp_path'): - controllers_path[o._cp_path] = o + for c in controllers_class.itervalues(): + controllers_path[c._cp_path] = c() app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, self.statics) self.dispatch = DisableCacheMiddleware(app) diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index 54b987cf555..516345bfa13 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -1,5 +1,9 @@ # -*- coding: utf-8 -*- +import contextlib import json +import logging +import logging.handlers +import types import unittest2 from .. import http @@ -20,16 +24,13 @@ class DispatchCleanup(unittest2.TestCase): """ def setUp(self): self.classes = http.controllers_class - self.objects = http.controllers_object self.paths = http.controllers_path - http.controllers_class = [] - http.controllers_object = {} + http.controllers_class = {} http.controllers_path = {} def tearDown(self): http.controllers_path = self.paths - http.controllers_object = self.objects http.controllers_class = self.classes @@ -56,6 +57,30 @@ def jsonrpc_response(result=None): } +class TestHandler(logging.handlers.BufferingHandler): + def __init__(self): + logging.handlers.BufferingHandler.__init__(self, 0) + + def shouldFlush(self, record): + return False + +@contextlib.contextmanager +def capture_logging(level=logging.DEBUG): + logger = logging.getLogger('openerp') + old_level = logger.level + old_handlers = logger.handlers + + test_handler = TestHandler() + logger.handlers = [test_handler] + logger.setLevel(level) + + try: + yield test_handler + finally: + logger.setLevel(old_level) + logger.handlers = old_handlers + + class TestDispatching(DispatchCleanup): def setUp(self): super(TestDispatching, self).setUp() @@ -104,6 +129,13 @@ class TestDispatching(DispatchCleanup): jsonrpc_response('no place paws in path of da sinnerz,'), json.loads(''.join(body))) + +class TestSubclassing(DispatchCleanup): + def setUp(self): + super(TestSubclassing, self).setUp() + self.app = http.Root() + self.client = werkzeug.test.Client(self.app) + def test_add_method(self): class CatController(http.Controller): _cp_path = '/cat' @@ -180,7 +212,38 @@ class TestDispatching(DispatchCleanup): body, status, headers = self.client.post('/cat') self.assertEqual('404 NOT FOUND', status) - def test_extend(self): + def test_extends(self): + """ + When subclassing an existing Controller new classes are "merged" into + the base one + """ + class A(http.Controller): + _cp_path = '/foo' + @http.httprequest + def index(self, req): + return '1' + + class B(A): + @http.httprequest + def index(self, req): + return "%s 2" % super(B, self).index(req) + + class C(A): + @http.httprequest + def index(self, req): + return "%s 3" % super(C, self).index(req) + + self.app.load_addons() + + body, status, headers = self.client.get('/foo') + self.assertEqual('200 OK', status) + self.assertEqual('1 2 3', ''.join(body)) + + def test_re_expose(self): + """ + An existing Controller should not be extended with a new cp_path + (re-exposing somewhere else) + """ class CatController(http.Controller): _cp_path = '/cat' @@ -191,18 +254,94 @@ class TestDispatching(DispatchCleanup): def speak(self): return 'Yu ordered cheezburgerz,' - class DogController(CatController): - _cp_path = '/dog' + with capture_logging() as handler: + class DogController(CatController): + _cp_path = '/dog' - def speak(self): - return 'Woof woof woof woof' + def speak(self): + return 'Woof woof woof woof' + + [record] = handler.buffer + self.assertEqual(logging.WARN, record.levelno) + self.assertEqual("Re-exposing CatController at /dog.\n" + "\tThis usage is unsupported.", + record.getMessage()) + + def test_fail_redefine(self): + """ + An existing Controller can't be overwritten by a new one on the same + path (? or should this generate a warning and still work as if it was + an extend?) + """ + class FooController(http.Controller): + _cp_path = '/foo' + + with self.assertRaises(AssertionError): + class BarController(http.Controller): + _cp_path = '/foo' + + def test_fail_no_path(self): + """ + A Controller must have a path (and thus be exposed) + """ + with self.assertRaises(AssertionError): + class FooController(http.Controller): + pass + + def test_mixin(self): + """ + Can mix "normal" python classes into a controller directly + """ + class Mixin(object): + @http.httprequest + def index(self, req): + return 'ok' + + class FooController(http.Controller, Mixin): + _cp_path = '/foo' + + class BarContoller(Mixin, http.Controller): + _cp_path = '/bar' self.app.load_addons() - body, status, headers = self.client.get('/cat') + body, status, headers = self.client.get('/foo') self.assertEqual('200 OK', status) - self.assertEqual('[Yu ordered cheezburgerz,]', ''.join(body)) + self.assertEqual('ok', ''.join(body)) - body, status, headers = self.client.get('/dog') + body, status, headers = self.client.get('/bar') self.assertEqual('200 OK', status) - self.assertEqual('[Woof woof woof woof]', ''.join(body)) + self.assertEqual('ok', ''.join(body)) + + def test_mixin_extend(self): + """ + Can mix "normal" python class into a controller by extension + """ + class FooController(http.Controller): + _cp_path = '/foo' + + class M1(object): + @http.httprequest + def m1(self, req): + return 'ok 1' + + class M2(object): + @http.httprequest + def m2(self, req): + return 'ok 2' + + class AddM1(FooController, M1): + pass + + class AddM2(M2, FooController): + pass + + self.app.load_addons() + + body, status, headers = self.client.get('/foo/m1') + self.assertEqual('200 OK', status) + self.assertEqual('ok 1', ''.join(body)) + + body, status, headers = self.client.get('/foo/m2') + self.assertEqual('200 OK', status) + self.assertEqual('ok 2', ''.join(body)) From 41784d0aec09c4fdda793fee7587c9fd8fedec52 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 10:26:35 +0200 Subject: [PATCH 07/65] [FIX] Export and Reports controllers have no need to extend View bzr revid: xmo@openerp.com-20130403082635-9dmdi4cco3kawiib --- addons/web/controllers/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index a199cba7854..890fa6fa466 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1428,7 +1428,7 @@ class Action(openerpweb.Controller): else: return False -class Export(View): +class Export(openerpweb.Controller): _cp_path = "/web/export" @openerpweb.jsonrequest @@ -1691,7 +1691,7 @@ class ExcelExport(Export): fp.close() return data -class Reports(View): +class Reports(openerpweb.Controller): _cp_path = "/web/report" POLLING_DELAY = 0.25 TYPES_MAPPING = { From bc07cab28cb1d21cbbada118423adf57cf011518 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 11:10:25 +0200 Subject: [PATCH 08/65] [IMP] export formats have no need to inherit from the export controller bzr revid: xmo@openerp.com-20130403091025-wjb23mzbmdyjnahm --- addons/web/controllers/main.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 890fa6fa466..4fdadc65c7a 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- - import ast import base64 import csv import glob import itertools -import logging import operator import datetime import hashlib @@ -30,7 +28,6 @@ except ImportError: xlwt = None import openerp -import openerp.modules.registry from openerp.tools.translate import _ from .. import http @@ -1428,6 +1425,7 @@ class Action(openerpweb.Controller): else: return False + class Export(openerpweb.Controller): _cp_path = "/web/export" @@ -1569,7 +1567,13 @@ class Export(openerpweb.Controller): (prefix + '/' + k, prefix_string + '/' + v) for k, v in self.fields_info(req, model, export_fields).iteritems()) - #noinspection PyPropertyDefinition + +class ExportFormat(object): + """ + Superclass for export formats, should probably be an abc and have a way to + generate _cp_path from fmt but it's a pain to deal with conflicts with + ControllerType + """ @property def content_type(self): """ Provides the format's content type """ @@ -1610,14 +1614,14 @@ class Export(openerpweb.Controller): else: columns_headers = [val['label'].strip() for val in fields] - return req.make_response(self.from_data(columns_headers, import_data), headers=[('Content-Disposition', content_disposition(self.filename(model), req)), ('Content-Type', self.content_type)], cookies={'fileToken': int(token)}) -class CSVExport(Export): + +class CSVExport(ExportFormat, http.Controller): _cp_path = '/web/export/csv' fmt = {'tag': 'csv', 'label': 'CSV'} @@ -1652,7 +1656,8 @@ class CSVExport(Export): fp.close() return data -class ExcelExport(Export): + +class ExcelExport(ExportFormat, http.Controller): _cp_path = '/web/export/xls' fmt = { 'tag': 'xls', @@ -1691,6 +1696,7 @@ class ExcelExport(Export): fp.close() return data + class Reports(openerpweb.Controller): _cp_path = "/web/report" POLLING_DELAY = 0.25 From cfcda2b032dc555d4a5e41caecfb83ae3c17e087 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 14:10:39 +0200 Subject: [PATCH 09/65] [IMP] reduce scope of captured logger bzr revid: xmo@openerp.com-20130403121039-qdq6tz012uc7lgdh --- addons/web/tests/test_dispatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index 516345bfa13..4ab3aa3f997 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -66,7 +66,7 @@ class TestHandler(logging.handlers.BufferingHandler): @contextlib.contextmanager def capture_logging(level=logging.DEBUG): - logger = logging.getLogger('openerp') + logger = logging.getLogger('openerp.addons.web') old_level = logger.level old_handlers = logger.handlers From 0ace6833b4f98a66f4f466fa74405cb43bb06d18 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 14:11:06 +0200 Subject: [PATCH 10/65] [IMP] don't make the diagram controller inherit from View, there's no point bzr revid: xmo@openerp.com-20130403121106-55vuku5w4r0mp25n --- addons/web_diagram/controllers/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/web_diagram/controllers/main.py b/addons/web_diagram/controllers/main.py index c598a7e4652..2efaab7183d 100644 --- a/addons/web_diagram/controllers/main.py +++ b/addons/web_diagram/controllers/main.py @@ -1,9 +1,10 @@ -import openerp +from openerp.addons.web.http import Controller, jsonrequest -class DiagramView(openerp.addons.web.controllers.main.View): + +class Diagram(Controller): _cp_path = "/web_diagram/diagram" - @openerp.addons.web.http.jsonrequest + @jsonrequest def get_diagram_info(self, req, id, model, node, connector, src_node, des_node, label, **kw): From ebc1cb227d36f2039d44d42ed539193029303f95 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 14:34:42 +0200 Subject: [PATCH 11/65] [IMP] make logger not propagate when captured bzr revid: xmo@openerp.com-20130403123442-p96cj73lwtxa2sek --- addons/web/tests/test_dispatch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index 4ab3aa3f997..ab2234e7d0d 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -69,14 +69,17 @@ def capture_logging(level=logging.DEBUG): logger = logging.getLogger('openerp.addons.web') old_level = logger.level old_handlers = logger.handlers + old_propagate = logger.propagate test_handler = TestHandler() logger.handlers = [test_handler] logger.setLevel(level) + logger.propagate = False try: yield test_handler finally: + logger.propagate = old_propagate logger.setLevel(old_level) logger.handlers = old_handlers From 3df2a146cdc87410ff271b663827aa2bacfe1f65 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Apr 2013 15:58:49 +0200 Subject: [PATCH 12/65] [FIX] logging capture when testing embedded in server, handler hooks are more complex than through oe bzr revid: xmo@openerp.com-20130403135849-ufnn2a1hdu938p7p --- addons/web/tests/test_dispatch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index ab2234e7d0d..b1304fca7f1 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -65,8 +65,8 @@ class TestHandler(logging.handlers.BufferingHandler): return False @contextlib.contextmanager -def capture_logging(level=logging.DEBUG): - logger = logging.getLogger('openerp.addons.web') +def capture_logging(logger, level=logging.DEBUG): + logger = logging.getLogger(logger) old_level = logger.level old_handlers = logger.handlers old_propagate = logger.propagate @@ -257,7 +257,7 @@ class TestSubclassing(DispatchCleanup): def speak(self): return 'Yu ordered cheezburgerz,' - with capture_logging() as handler: + with capture_logging('openerp.addons.web.http') as handler: class DogController(CatController): _cp_path = '/dog' From 77595a843e774a19d879a8f770444f1901c46d27 Mon Sep 17 00:00:00 2001 From: Vidhin Mehta Date: Fri, 5 Apr 2013 14:22:24 +0530 Subject: [PATCH 13/65] [IMP]Improvements in Manage View. bzr revid: vme@tinyerp.com-20130405085224-yecygjxi39nd60h0 --- .../static/src/js/view_editor.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/addons/web_view_editor/static/src/js/view_editor.js b/addons/web_view_editor/static/src/js/view_editor.js index 48b76e02904..524c415d34a 100644 --- a/addons/web_view_editor/static/src/js/view_editor.js +++ b/addons/web_view_editor/static/src/js/view_editor.js @@ -15,7 +15,7 @@ instance.web.ViewManagerAction.include({ } evt.currentTarget.selectedIndex = 0; }else{ - return this._super.apply(this,arguments); + return this._super.apply(this,arguments); } } }); @@ -232,10 +232,11 @@ instance.web_view_editor.ViewEditor = instance.web.Widget.extend({ return main_object; }, parse_xml: function(arch, view_id) { + //First element of att_list must be element tagname. main_object = { 'level': 0, 'id': this.xml_element_id +=1, - 'att_list': [], + 'att_list': ["view"], 'name': _.str.sprintf("", view_id), 'child_id': [] }; @@ -535,15 +536,22 @@ instance.web_view_editor.ViewEditor = instance.web.Widget.extend({ var field_dataset = new instance.web.DataSetSearch(this, this.model, null, null); parent_tr = self.get_object_by_id(parseInt($(parent_tr).attr('id').replace(/[^0-9]+/g, '')), this.one_object['main_object'], [])[0].att_list[0]; _.each([tr, parent_tr],function(element) { - var value = _.has(_CHILDREN, element) ? element : _.str.include(html_tag, element)?"html_tag":false; + var value = _.has(_CHILDREN, element) ? element : _.str.include(html_tag, element)?"html_tag":false; property_to_check.push(value); }); field_dataset.call( 'fields_get', []).done(function(result) { var fields = _.keys(result); fields.push(" "),fields.sort(); - self.on_add_node(property_to_check, fields); + self.on_add_node(property_to_check, fields, self.inject_position(parent_tr,tr)); }); }, + inject_position : function(parent_tag,current_tag){ + if(parent_tag == "view") + return ['Inside']; + if(current_tag == "field") + return ['After','Before']; + return ['After','Before','Inside']; + }, do_node_edit: function(side) { var self = this; var result = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], []); @@ -941,11 +949,11 @@ instance.web_view_editor.ViewEditor = instance.web.Widget.extend({ }); return def.promise(); }, - on_add_node: function(properties, fields){ + on_add_node: function(properties, fields, position){ var self = this; var render_list = [{'name': 'node_type','selection': _.keys(_CHILDREN).sort(), 'value': 'field', 'string': 'Node Type','type': 'selection'}, {'name': 'field_value','selection': fields, 'value': false, 'string': '','type': 'selection'}, - {'name': 'position','selection': ['After','Before','Inside'], 'value': false, 'string': 'Position','type': 'selection'}]; + {'name': 'position','selection': position, 'value': false, 'string': 'Position','type': 'selection'}]; this.add_widget = []; this.add_node_dialog = new instance.web.Dialog(this,{ title: _t("Properties"), @@ -1186,7 +1194,7 @@ var _CHILDREN = { //e.g.:xyz 'td' : ['field'] }; // Generic html_tag list and can be added html tag in future. It's support above _CHILDREN dict's *html_tag* by default. -// For specific child node one has to define tag above and specify children tag in list. Like above xyz example. +// For specific child node one has to define tag above and specify children tag in list. Like above xyz example. var html_tag = ['div','h1','h2','h3','h4','h5','h6','td','tr']; var _ICONS = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', From ad1650854eead5af703d535cb03d5bdf56088cde Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sun, 7 Apr 2013 23:23:33 +0200 Subject: [PATCH 14/65] [FIX] account: recursively find proper partner to link to journal items, as discussed in bugs 1160365 and 1151947 lp bug: https://launchpad.net/bugs/1160365 fixed lp bug: https://launchpad.net/bugs/1151947 fixed bzr revid: odo@openerp.com-20130407212333-34jahthhppcz2wju --- addons/account/account_invoice.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index eb362455cd9..4611e0ab240 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1260,9 +1260,7 @@ class account_invoice(osv.osv): ref = invoice.reference else: ref = self._convert_ref(cr, uid, invoice.number) - partner = invoice.partner_id - if partner.parent_id and not partner.is_company: - partner = partner.parent_id + partner = self.pool['res.partner']._find_accounting_partner(invoice.partner_id) # Pay attention to the sign for both debit/credit AND amount_currency l1 = { 'debit': direction * pay_amount>0 and direction * pay_amount, @@ -1733,15 +1731,17 @@ class res_partner(osv.osv): 'invoice_ids': fields.one2many('account.invoice.line', 'partner_id', 'Invoices', readonly=True), } - def _find_accounting_partner(self, part): + def _find_accounting_partner(self, partner): ''' Find the partner for which the accounting entries will be created ''' + # FIXME: after 7.0, to replace by function field partner.commercial_id + #if the chosen partner is not a company and has a parent company, use the parent for the journal entries #because you want to invoice 'Agrolait, accounting department' but the journal items are for 'Agrolait' - if part.parent_id and not part.is_company: - part = part.parent_id - return part + while not partner.is_company and partner.parent_id: + partner = partner.parent_id + return partner def copy(self, cr, uid, id, default=None, context=None): default = default or {} From 438e1c1daf5bc4eb212f78b87f277fff8e8a0ceb Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 01:50:13 +0200 Subject: [PATCH 15/65] [FIX] res.partner: Hide commercial-related fields on contacts form + autosync them from parent company Fixes handling of accounting/invoicing-related fields on partners that are not "commercial entities" (either marked as "is_company" or parentless). The corresponding fields are also hidden from form views on these partners and replaced by a short sentence and a link to edit the "master fields" on the commercial entity. This corresponds to part B of the solution described on bug 1160365. lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130407235013-j3tv4uxy46eej43i --- addons/account/partner.py | 5 +++++ addons/account/partner_view.xml | 7 ++++++- addons/base_vat/base_vat.py | 3 +++ addons/l10n_be_invoice_bba/partner.py | 5 +++++ addons/l10n_ro/res_partner.py | 4 ++++ addons/product/partner.py | 3 +++ addons/product/partner_view.xml | 5 ++++- addons/purchase/partner.py | 3 +++ addons/sale_journal/sale_journal.py | 4 ++++ addons/sale_journal/sale_journal_view.xml | 2 +- 10 files changed, 38 insertions(+), 3 deletions(-) diff --git a/addons/account/partner.py b/addons/account/partner.py index ae8d2fc1871..4914a17dd2b 100644 --- a/addons/account/partner.py +++ b/addons/account/partner.py @@ -236,6 +236,11 @@ class res_partner(osv.osv): 'last_reconciliation_date': fields.datetime('Latest Full Reconciliation Date', help='Date on which the partner accounting entries were fully reconciled last time. It differs from the last date where a reconciliation has been made for this partner, as here we depict the fact that nothing more was to be reconciled at this date. This can be achieved in 2 different ways: either the last unreconciled debit/credit entry of this partner was reconciled, either the user pressed the button "Nothing more to reconcile" during the manual reconciliation process.') } + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + \ + ['debit_limit', 'property_account_payable', 'property_account_receivable', 'property_account_position', + 'property_payment_term', 'property_supplier_payment_term', 'last_reconciliation_date'] + res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml index 1267e20165b..abded67f6ab 100644 --- a/addons/account/partner_view.xml +++ b/addons/account/partner_view.xml @@ -73,7 +73,7 @@ - + @@ -103,6 +103,11 @@ + +
+

Accounting-related settings are managed on

+
diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py index 616333e3b47..3366101c7c7 100644 --- a/addons/base_vat/base_vat.py +++ b/addons/base_vat/base_vat.py @@ -134,6 +134,9 @@ class res_partner(osv.osv): 'vat_subjected': fields.boolean('VAT Legal Statement', help="Check this box if the partner is subjected to the VAT. It will be used for the VAT legal statement.") } + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['vat_subjected'] + def _construct_constraint_msg(self, cr, uid, ids, context=None): def default_vat_check(cn, vn): # by default, a VAT number is valid if: diff --git a/addons/l10n_be_invoice_bba/partner.py b/addons/l10n_be_invoice_bba/partner.py index 9e0eec10713..df68268bf43 100644 --- a/addons/l10n_be_invoice_bba/partner.py +++ b/addons/l10n_be_invoice_bba/partner.py @@ -44,6 +44,11 @@ class res_partner(osv.osv): help='Select Algorithm to generate the Structured Communication on Outgoing Invoices.' ), } + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + \ + ['out_inv_comm_type', 'out_inv_comm_algorithm'] + + _default = { 'out_inv_comm_type': 'none', } diff --git a/addons/l10n_ro/res_partner.py b/addons/l10n_ro/res_partner.py index 1cfe7390a77..95867f8e883 100755 --- a/addons/l10n_ro/res_partner.py +++ b/addons/l10n_ro/res_partner.py @@ -32,6 +32,10 @@ class res_partner(osv.osv): ('vat_uniq', 'unique (vat)', 'The vat of the partner must be unique !'), ('nrc_uniq', 'unique (nrc)', 'The code of the partner must be unique !') ] + + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['nrc'] + res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/product/partner.py b/addons/product/partner.py index 1d11e909346..4a291a8ddd3 100644 --- a/addons/product/partner.py +++ b/addons/product/partner.py @@ -36,6 +36,9 @@ class res_partner(osv.osv): help="This pricelist will be used, instead of the default one, for sales to the current partner"), } + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_product_pricelist'] + res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/product/partner_view.xml b/addons/product/partner_view.xml index acb087533ac..5117da6044e 100644 --- a/addons/product/partner_view.xml +++ b/addons/product/partner_view.xml @@ -8,9 +8,12 @@ - + +
+

Pricelists are managed on

diff --git a/addons/purchase/partner.py b/addons/purchase/partner.py index 56eaf288fe6..e05f6b9c9c6 100644 --- a/addons/purchase/partner.py +++ b/addons/purchase/partner.py @@ -43,6 +43,9 @@ class res_partner(osv.osv): super(res_partner, self).copy(cr, uid, id, default=default, context=context) + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_product_pricelist_purchase'] + _columns = { 'property_product_pricelist_purchase': fields.property( 'product.pricelist', diff --git a/addons/sale_journal/sale_journal.py b/addons/sale_journal/sale_journal.py index 8463ab3f3bd..cb33d7e2334 100644 --- a/addons/sale_journal/sale_journal.py +++ b/addons/sale_journal/sale_journal.py @@ -52,6 +52,10 @@ class res_partner(osv.osv): group_name = "Accounting Properties", help = "This invoicing type will be used, by default, to invoice the current partner."), } + + def _commercial_fields(self, cr, uid, context=None): + return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_invoice_type'] + res_partner() class picking(osv.osv): diff --git a/addons/sale_journal/sale_journal_view.xml b/addons/sale_journal/sale_journal_view.xml index bcd83b5be84..9d41103252e 100644 --- a/addons/sale_journal/sale_journal_view.xml +++ b/addons/sale_journal/sale_journal_view.xml @@ -146,7 +146,7 @@ - + From dcac505a5b83888d847c65b3ec3443aa47271e4f Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 01:51:15 +0200 Subject: [PATCH 16/65] [FIX] sale: remove useless code to select commercial entity, now handled by res.partner.address_get directly lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130407235115-4kovy1jngblrdd5z --- addons/sale/sale.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index a6be2838171..a52efc12467 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -314,10 +314,6 @@ class sale_order(osv.osv): return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False, 'payment_term': False, 'fiscal_position': False}} part = self.pool.get('res.partner').browse(cr, uid, part, context=context) - #if the chosen partner is not a company and has a parent company, use the parent to choose the delivery, the - #invoicing addresses and all the fields related to the partner. - if part.parent_id and not part.is_company: - part = part.parent_id addr = self.pool.get('res.partner').address_get(cr, uid, [part.id], ['delivery', 'invoice', 'contact']) pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False payment_term = part.property_payment_term and part.property_payment_term.id or False From 347c784dabb42f907abc33a2b40de082b815d3f8 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 01:56:40 +0200 Subject: [PATCH 17/65] [FIX] account: include contacts matches when searching for company invoices This implements part E of the solution described on bug 1160365 lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130407235640-cg02qh4ittc743zw --- addons/account/account_invoice_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 8c7cec67ac5..1fbdbf26453 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -447,14 +447,14 @@ account.invoice - + - + From e4f04efdd6ffb3e599bde28bd87b6ebc8f963400 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 02:01:24 +0200 Subject: [PATCH 18/65] [FIX] account.invoice: only allow selecting partners that are `commercial entities` Following-up to the discussion on bug 1160365, this will help users make the right choice when manualling creating invoices. lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130408000124-wcmjco9561hc9fbl --- addons/account/account_invoice_view.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 1fbdbf26453..59c78c98e54 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -166,7 +166,7 @@ + domain="[('supplier', '=', True),'|',('parent_id','=',False),('is_company','=',True)]"/> @@ -320,7 +320,8 @@ + options='{"always_reload": True}' + domain="[('customer', '=', True),'|',('parent_id','=',False),('is_company','=',True)]"/> From ed62e366918ace0988c9edfc2594f9e31650b590 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 02:55:26 +0200 Subject: [PATCH 19/65] [FIX] account_voucher,sale,purchase: include contacts matches when searching for company documents This implements part E of the solution described on bug 1160365 lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130408005526-7124r7u39yhh9la3 --- addons/account_voucher/account_voucher_view.xml | 2 +- addons/purchase/purchase_view.xml | 6 +++--- addons/sale/sale_view.xml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index f429480f656..4674d62b6a0 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -129,7 +129,7 @@ - + diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index 63735b090dd..b497599f848 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -270,7 +270,7 @@ - + @@ -297,7 +297,7 @@ - + @@ -481,7 +481,7 @@ - + diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index a6cc7df1f12..8a0c6c9e6a4 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -308,7 +308,7 @@ - + @@ -472,7 +472,7 @@ - + @@ -498,7 +498,7 @@ - + From 2bf1034cd2fca0115bc38a6c75a6d213a833c6a3 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 03:37:42 +0200 Subject: [PATCH 20/65] [FIX] res.partner: autosync of commercial fields and address fields + correct views accordingly + basic tests * Commercial fields (bug 1160365) Fix autosync of accounting/invoicing-related fields on contacts, just as if they were actually modeled as fields.related to the parent commercial entity. This starts with the addition of the new functional field `commercial_id`, to locate the commercial entity for any partner. The commercial entity is defined as the first ancestor (starting at the partner itself) that is either marked `is_company` or has no parent. [This is Part A of the solution on bug 1160365]. Then, whenever a partner is created or modified: - if it is a commercial entity, the commercial fields are synced downstream to all its descendants, stopping at company boundaries. - if is is not a commercial entity, the commercial fields are synced from its parent commercial entity. The list of fields to sync is determined by calling the new res.partner method `_commercial_fields()` which can be easily extended by any module that adds commercial fields on res.partner. A utility method `open_commercial_entity()` was added to res.partner to make it easy to include a button for editing the parent commercial entity, to be displayed instead of now-hidden commercial fields. [This is part B of the solution on bug 1160365] The res.partner.address_get() method (used to find child partners of certain types, e.g. "invoice") was udpated to take the new "commercial entity" notion into account: it will now look for matches in children but also parents and siblings that are part of the same "commercial entity". The default partner `type` is now "contact" to reflect the new model ; "default" is inappropriate because it is a wildcard and would stop the type lookup early. [This composes parts C and D of the solution on bug 1160365] Note: This fix comes with a matching addons fix to implement module-specific extensions of part B, as well as part E of the solution. * Address fields (bug 1160425) Corrected autosync of address fields is also included in the same branch, because those two mechanisms are closely related and share some parts of the implementation. The `use_parent_address` field now defaults to False (except in the mini-kanban view of contacts on a partner form), and the autosync of address fields has been modified to only work downstream and never update a parent company if a child contact is modified. Instead, the address fields are now displayed readonly on contacts that use the parent address, with a button to edit the parent address (new method open_parent(), similar to open_commercial_entity() but opening the direct parent). To make the initial creation of a contact + company pair, a special case was added: when a new contact is created for a company that has no other contact and no address, the address of the contact is assumed to be that of the company so it is moved to the company, then the `use_parent_address` flag is enabled on the contact, and the `is_company` flag on the company. This covers a use case where contact and company are created on-the-fly when creating a new document. Many logical flaws in the autosync of address fields have been corrected and are now covered by unit tests. * Misc related fixes - checking `is_company` does not reset the parent_id field anymore, to allow for multi-level structures. The field is still hidden automatically because having an empty "Company" field on the form view of a company is quite suprising), but this UI behavior is easily customized; - the `email`, `phone`, `fax`, `mobile`, `lang`, etc. that were sometimes synced when changing parent company are now properly left alone; - the `use_parent_address` field is now always visible next to the parent_id field when a parent is set lp bug: https://launchpad.net/bugs/1160425 fixed lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130408013742-tm8w0w0nmunanokk --- openerp/addons/base/res/res_partner.py | 250 ++++++++++++++----- openerp/addons/base/res/res_partner_view.xml | 27 +- openerp/addons/base/tests/test_base.py | 206 +++++++++++++++ 3 files changed, 403 insertions(+), 80 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 72c221c5534..1193abcd862 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -30,6 +30,7 @@ from openerp import SUPERUSER_ID from openerp import pooler, tools from openerp.osv import osv, fields from openerp.tools.translate import _ +from openerp.tools.yaml_import import is_comment class format_address(object): def fields_view_get_address(self, cr, uid, arch, context={}): @@ -159,8 +160,9 @@ def _lang_get(self, cr, uid, context=None): res = lang_pool.read(cr, uid, ids, ['code', 'name'], context) return [(r['code'], r['name']) for r in res] -POSTAL_ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id') -ADDRESS_FIELDS = POSTAL_ADDRESS_FIELDS + ('email', 'phone', 'fax', 'mobile', 'website', 'ref', 'lang') +# fields copy if 'use_parent_address' is checked +ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id', 'type') +POSTAL_ADDRESS_FIELDS = ADDRESS_FIELDS # deprecated, to remove after 7.0 class res_partner(osv.osv, format_address): _description = 'Partner' @@ -193,6 +195,18 @@ class res_partner(osv.osv, format_address): result[obj.id] = obj.image != False return result + def _commercial_id_compute(self, cr, uid, ids, name, args, context=None): + """ Returns the partner that is considered the commercial + entity of this partner. The commercial entity holds the master data + for all commercial fields (see :py:meth:`~_commercial_fields`) """ + result = dict.fromkeys(ids, False) + for partner in self.browse(cr, uid, ids, context=context): + current_partner = partner + while not current_partner.is_company and current_partner.parent_id: + current_partner = current_partner.parent_id + result[partner.id] = current_partner.id + return result + _order = "name" _columns = { 'name': fields.char('Name', size=128, required=True, select=True), @@ -264,6 +278,9 @@ class res_partner(osv.osv, format_address): 'color': fields.integer('Color Index'), 'user_ids': fields.one2many('res.users', 'partner_id', 'Users'), 'contact_address': fields.function(_address_display, type='char', string='Complete Address'), + + # technical field used for managing commercial fields + 'commercial_id': fields.function(_commercial_id_compute, type='many2one', relation='res.partner', string='Commercial Entity') } def _default_category(self, cr, uid, context=None): @@ -302,8 +319,8 @@ class res_partner(osv.osv, format_address): 'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=ctx), 'color': 0, 'is_company': False, - 'type': 'default', - 'use_parent_address': True, + 'type': 'contact', # type 'default' is wildcard and thus inappropriate + 'use_parent_address': False, 'image': False, } @@ -318,7 +335,6 @@ class res_partner(osv.osv, format_address): value = {} value['title'] = False if is_company: - value['parent_id'] = False domain = {'title': [('domain', '=', 'partner')]} else: domain = {'title': [('domain', '=', 'contact')]} @@ -329,10 +345,11 @@ class res_partner(osv.osv, format_address): """ return val or val.id if val is a browse record """ return val if isinstance(val, (bool, int, long, float, basestring)) else val.id - if use_parent_address and parent_id: + if parent_id: parent = self.browse(cr, uid, parent_id, context=context) - return {'value': dict((key, value_or_id(parent[key])) for key in ADDRESS_FIELDS)} - return {} + address_fields = self._address_fields(cr, uid, context=context) + return {'value': dict((key, value_or_id(parent[key])) for key in address_fields)} + return {'value': {'use_parent_address': False}} def onchange_state(self, cr, uid, ids, state_id, context=None): if state_id: @@ -358,56 +375,134 @@ class res_partner(osv.osv, format_address): # _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])] - def write(self, cr, uid, ids, vals, context=None): - # Update parent and siblings or children records - if isinstance(ids, (int, long)): - ids = [ids] - if vals.get('is_company')==False: - vals.update({'child_ids' : [(5,)]}) - for partner in self.browse(cr, uid, ids, context=context): - update_ids = [] - if partner.is_company: - domain_children = [('parent_id', '=', partner.id), ('use_parent_address', '=', True)] - update_ids = self.search(cr, uid, domain_children, context=context) - elif partner.parent_id: - if vals.get('use_parent_address')==True: - domain_siblings = [('parent_id', '=', partner.parent_id.id), ('use_parent_address', '=', True)] - update_ids = [partner.parent_id.id] + self.search(cr, uid, domain_siblings, context=context) - if 'use_parent_address' not in vals and partner.use_parent_address: - domain_siblings = [('parent_id', '=', partner.parent_id.id), ('use_parent_address', '=', True)] - update_ids = [partner.parent_id.id] + self.search(cr, uid, domain_siblings, context=context) - self.update_address(cr, uid, update_ids, vals, context) - return super(res_partner,self).write(cr, uid, ids, vals, context=context) - - def create(self, cr, uid, vals, context=None): - if context is None: - context = {} - # Update parent and siblings records - if vals.get('parent_id'): - if 'use_parent_address' in vals: - use_parent_address = vals['use_parent_address'] + def _update_fields_values(self, cr, uid, partner, fields, context=None): + """ Returns dict of write() values for synchronizing ``fields`` """ + values = {} + for field in fields: + column = self._all_columns[field].column + if column._type == 'one2many': + raise AssertionError('One2Many fields cannot be synchronized as part of `commercial_fields` or `address fields`') + if column._type == 'many2one': + values[field] = partner[field].id if partner[field] else False + elif column._type == 'many2many': + values[field] = [(6,0,[r.id for r in partner[field] or []])] else: - use_parent_address = self.default_get(cr, uid, ['use_parent_address'], context=context)['use_parent_address'] + values[field] = partner[field] + return values - if use_parent_address: - domain_siblings = [('parent_id', '=', vals['parent_id']), ('use_parent_address', '=', True)] - update_ids = [vals['parent_id']] + self.search(cr, uid, domain_siblings, context=context) - self.update_address(cr, uid, update_ids, vals, context) - - # add missing address keys - onchange_values = self.onchange_address(cr, uid, [], use_parent_address, - vals['parent_id'], context=context).get('value') or {} - vals.update(dict((key, value) - for key, value in onchange_values.iteritems() - if key in ADDRESS_FIELDS and key not in vals)) - - return super(res_partner, self).create(cr, uid, vals, context=context) + def _address_fields(self, cr, uid, context=None): + """ Returns the list of address fields that are synced from the parent + when the `use_parent_address` flag is set. """ + return ADDRESS_FIELDS def update_address(self, cr, uid, ids, vals, context=None): - addr_vals = dict((key, vals[key]) for key in POSTAL_ADDRESS_FIELDS if key in vals) + address_fields = self._address_fields(cr, uid, context=context) + addr_vals = dict((key, vals[key]) for key in address_fields if key in vals) if addr_vals: return super(res_partner, self).write(cr, uid, ids, addr_vals, context) + def _commercial_fields(self, cr, uid, context=None): + """ Returns the list of fields that are managed by the commercial entity + to which a partner belongs. These fields are meant to be hidden on + partners that aren't `commercial entities` themselves, and will be + delegated to the parent `commercial entity`. The list is meant to be + extended by inheriting classes. """ + return ['vat'] + + def _commercial_sync_from_company(self, cr, uid, partner, context=None): + """ Handle sync of commercial fields when a new parent commercial entity is set, + as if they were related fields """ + if partner.commercial_id != partner: + commercial_fields = self._commercial_fields(cr, uid, context=context) + sync_vals = self._update_fields_values(cr, uid, partner.commercial_id, + commercial_fields, context=context) + return self.write(cr, uid, partner.id, sync_vals, context=context) + + def _commercial_sync_to_children(self, cr, uid, partner, context=None): + """ Handle sync of commercial fields to descendants """ + commercial_fields = self._commercial_fields(cr, uid, context=context) + sync_vals = self._update_fields_values(cr, uid, partner.commercial_id, + commercial_fields, context=context) + sync_children = [c for c in partner.child_ids if not c.is_company] + for child in sync_children: + self._commercial_sync_to_children(cr, uid, child, context=context) + return self.write(cr, uid, [c.id for c in sync_children], sync_vals, context=context) + + def _fields_sync(self, cr, uid, partner, update_values, context=None): + """ Sync commercial fields and address fields from company and to children after create/update, + just as if those were all modeled as fields.related to the parent """ + # 1. From UPSTREAM: sync from parent + if update_values.get('parent_id') or update_values.get('use_company_address'): + # 1a. Commercial fields: sync if parent changed + if update_values.get('parent_id'): + self._commercial_sync_from_company(cr, uid, partner, context=context) + # 1b. Address fields: sync if parent or use_parent changed *and* both are now set + if partner.parent_id and partner.use_parent_address: + onchange_vals = self.onchange_address(cr, uid, [partner.id], + use_parent_address=partner.use_parent_address, + parent_id=partner.parent_id.id, + context=context).get('value', {}) + self.update_address(cr, uid, partner.id, onchange_vals, context=context) + + # 2. To DOWNSTREAM: sync children + if partner.child_ids: + # 2a. Commercial Fields: sync if commercial entity + if partner.commercial_id == partner: + self._commercial_sync_to_children(cr, uid, partner, context=context) + # 2b. Address fields: sync if address changed + address_fields = self._address_fields(cr, uid, context=context) + if any(field in update_values for field in address_fields): + domain_children = [('parent_id', '=', partner.id), ('use_parent_address', '=', True)] + update_ids = self.search(cr, uid, domain_children, context=context) + self.update_address(cr, uid, update_ids, update_values, context=context) + + def _handle_first_contact_creation(self, cr, uid, partner, context=None): + """ On creation of first contact for a company (or root) that has no address, assume contact address + was meant to be company address """ + parent = partner.parent_id + address_data_fields = list(set(self._address_fields(cr, uid, context=context)).difference(['type'])) + if parent and (parent.is_company or not parent.parent_id) and len(parent.child_ids) == 1 and \ + any(partner[f] for f in address_data_fields) and not any(parent[f] for f in address_data_fields): + addr_vals = self._update_fields_values(cr, uid, partner, address_data_fields, context=context) + parent.update_address(addr_vals) + if not parent.is_company: + parent.write({'is_company': True}) + + def write(self, cr, uid, ids, vals, context=None): + if isinstance(ids, (int, long)): + ids = [ids] + result = super(res_partner,self).write(cr, uid, ids, vals, context=context) + for partner in self.browse(cr, uid, ids, context=context): + self._fields_sync(cr, uid, partner, vals, context) + return result + + def create(self, cr, uid, vals, context=None): + new_id = super(res_partner, self).create(cr, uid, vals, context=context) + partner = self.browse(cr, uid, new_id, context=context) + self._fields_sync(cr, uid, partner, vals, context) + self._handle_first_contact_creation(cr, uid, partner, context) + return new_id + + def open_commercial_entity(self, cr, uid, ids, context=None): + """ Utility method used to add an "Open Company" button in partner views """ + partner = self.browse(cr, uid, ids[0], context=context) + return {'type': 'ir.actions.act_window', + 'res_model': 'res.partner', + 'view_mode': 'form', + 'res_id': partner.commercial_id.id, + 'target': 'new', + 'flags': {'form': {'action_buttons': True}}} + + def open_parent(self, cr, uid, ids, context=None): + """ Utility method used to add an "Open Parent" button in partner views """ + partner = self.browse(cr, uid, ids[0], context=context) + return {'type': 'ir.actions.act_window', + 'res_model': 'res.partner', + 'view_mode': 'form', + 'res_id': partner.parent_id.id, + 'target': 'new', + 'flags': {'form': {'action_buttons': True}}} + def name_get(self, cr, uid, ids, context=None): if context is None: context = {} @@ -516,25 +611,42 @@ class res_partner(osv.osv, format_address): ids = ids[16:] return True - def address_get(self, cr, uid, ids, adr_pref=None): - if adr_pref is None: - adr_pref = ['default'] + def address_get(self, cr, uid, ids, adr_pref=None, context=None): + """ Find contacts/addresses of the right type(s) by doing a depth-first-search + through descendants within company boundaries (stop at entities flagged ``is_company``) + then continuing the search at the ancestors that are within the same company boundaries. + Defaults to partners of type ``'default'`` when the exact type is not found, or to the + commercial entity if no type ``'default'`` is found either. """ + adr_pref = set(adr_pref or []) + if 'default' not in adr_pref: + adr_pref.add('default') result = {} - # retrieve addresses from the partner itself and its children - res = [] - # need to fix the ids ,It get False value in list like ids[False] - if ids and ids[0]!=False: - for p in self.browse(cr, uid, ids): - res.append((p.type, p.id)) - res.extend((c.type, c.id) for c in p.child_ids) - address_dict = dict(reversed(res)) - # get the id of the (first) default address if there is one, - # otherwise get the id of the first address in the list - default_address = False - if res: - default_address = address_dict.get('default', res[0][1]) - for adr in adr_pref: - result[adr] = address_dict.get(adr, default_address) + visited = set() + for partner in self.browse(cr, uid, filter(None, ids), context=context): + current_partner = partner + while current_partner: + to_scan = [current_partner] + # Scan descendants, DFS + while to_scan: + record = to_scan.pop(0) + visited.add(record) + if record.type in adr_pref and not result.get(record.type): + result[record.type] = record.id + if len(result) == len(adr_pref): + return result + to_scan = [c for c in record.child_ids + if c not in visited + if not c.is_company] + to_scan + + # Continue scanning at ancestor if current_partner is not a commercial entity + if current_partner.is_company or not current_partner.parent_id: + break + current_partner = current_partner.parent_id + + # default to type 'default' or the commercial_entity of the main/last partner + default = result.get('default', partner.commercial_id.id) + for adr_type in adr_pref: + result[adr_type] = result.get(adr_type) or default return result def view_header_get(self, cr, uid, view_id, view_type, context): diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 71c789af1a7..3650b4d6d9d 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -140,7 +140,12 @@ placeholder="Company" domain="[('is_company', '=', True)]" context="{'default_is_company': True}" attrs="{'invisible': [('is_company','=', True)]}" - on_change="onchange_address(use_parent_address, parent_id)"/> + on_change="onchange_address(use_parent_address, parent_id)" class="oe_inline"/> + + @@ -183,7 +187,7 @@ - + @@ -252,6 +256,7 @@
+ diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 285af8fbf6e..1f6410f7231 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -39,5 +39,211 @@ class test_base(common.TransactionCase): self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again') + def test_20_res_partner_address_sync(self): + cr, uid = self.cr, self.uid + ghoststep = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'GhostStep', + 'is_company': True, + 'street': 'Main Street, 10', + 'phone': '123456789', + 'email': 'info@ghoststep.com', + 'vat': 'BE0477472701'})) + p1 = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Denis Bladesmith ')[0]) + p1phone = '123456789#34' + p1.write({'phone': p1phone, + 'parent_id': ghoststep.id, + 'use_parent_address': True}) + p1.refresh() + self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced') + self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync') + self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync') + ghoststreet = 'South Street, 25' + ghoststep.write({'street': ghoststreet}) + p1.refresh() + self.assertEqual(p1.street, ghoststreet, 'Address fields must be synced automatically') + self.assertEqual(p1.phone, p1phone, 'Phone should not be synced') + self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync') + + p1street = 'My Street, 11' + p1.write({'street': p1street}) + ghoststep.refresh() + self.assertEqual(ghoststep.street, ghoststreet, 'Touching contact should never alter parent') + + + def test_30_res_partner_first_contact_sync(self): + """ Test initial creation of company/contact pair where contact address gets copied to + company """ + cr, uid = self.cr, self.uid + ironshield = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'IronShield')[0]) + self.assertFalse(ironshield.is_company, 'Partners are not companies by default') + self.assertFalse(ironshield.use_parent_address, 'use_parent_address defaults to False') + self.assertEqual(ironshield.type, 'contact', 'Default type must be "contact"') + p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'Isen Hardearth', + 'street': 'Strongarm Avenue, 12', + 'parent_id': ironshield.id})) + self.assertEquals(p1.type, 'contact', 'Default type must be "contact"') + ironshield.refresh() + self.assertEqual(ironshield.street, p1.street, 'Address fields should be copied to company') + self.assertTrue(ironshield.is_company, 'Company flag should be turned on after first contact creation') + + def test_40_res_partner_address_getc(self): + """ Test address_get address resolution mechanism: it should first go down through descendants, + stopping when encountering another is_copmany entity, then go up, stopping again at the first + is_company entity or the root ancestor and if nothing matches, it should use the commercial entity + of the partner (which could be itself) """ + cr, uid = self.cr, self.uid + elmtree = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Elmtree')[0]) + branch1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 1', + 'parent_id': elmtree.id, + 'is_company': True})) + leaf10 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 10', + 'parent_id': branch1.id, + 'type': 'invoice'})) + branch11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 11', + 'parent_id': branch1.id, + 'type': 'other'})) + leaf111 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 111', + 'parent_id': branch11.id, + 'type': 'delivery'})) + branch11.write({'is_company': False}) # force is_company after creating 1rst child + branch2 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 2', + 'parent_id': elmtree.id, + 'is_company': True})) + leaf21 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 21', + 'parent_id': branch2.id, + 'type': 'delivery'})) + leaf22 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 22', + 'parent_id': branch2.id})) + leaf23 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 23', + 'parent_id': branch2.id, + 'type': 'default'})) + # go up, stop at branch1 + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf111.id, + 'invoice': leaf10.id, + 'contact': branch1.id, + 'other': branch11.id, + 'default': branch1.id}, 'Invalid address resolution') + self.assertEqual(self.res_partner.address_get(cr, uid, [branch11.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf111.id, + 'invoice': leaf10.id, + 'contact': branch1.id, + 'other': branch11.id, + 'default': branch1.id}, 'Invalid address resolution') + + # go down, stop at at all child companies + self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': elmtree.id, + 'invoice': elmtree.id, + 'contact': elmtree.id, + 'other': elmtree.id, + 'default': elmtree.id}, 'Invalid address resolution') + + # go down through children + self.assertEqual(self.res_partner.address_get(cr, uid, [branch1.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf111.id, + 'invoice': leaf10.id, + 'contact': branch1.id, + 'other': branch11.id, + 'default': branch1.id}, 'Invalid address resolution') + self.assertEqual(self.res_partner.address_get(cr, uid, [branch2.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf21.id, + 'invoice': leaf23.id, + 'contact': branch2.id, + 'other': leaf23.id, + 'default': leaf23.id}, 'Invalid address resolution') + + # go up then down through siblings + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf21.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf21.id, + 'invoice': leaf23.id, + 'contact': branch2.id, + 'other': leaf23.id, + 'default': leaf23.id + }, 'Invalid address resolution, should scan commercial entity ancestor and its descendants') + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf22.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf21.id, + 'invoice': leaf23.id, + 'contact': leaf22.id, + 'other': leaf23.id, + 'default': leaf23.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants') + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf23.id], ['delivery', 'invoice', 'contact', 'other', 'default']), + {'delivery': leaf21.id, + 'invoice': leaf23.id, + 'contact': branch2.id, + 'other': leaf23.id, + 'default': leaf23.id}, 'Invalid address resolution, `default` should only override if no partner with specific type exists') + + # empty adr_pref means only 'default' + self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], []), + {'default': elmtree.id}, 'Invalid address resolution, no default means commercial entity ancestor') + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []), + {'default': branch1.id}, 'Invalid address resolution, no default means commercial entity ancestor') + branch11.write({'type': 'default'}) + self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []), + {'default': branch11.id}, 'Invalid address resolution, branch11 should now be default') + + + def test_50_res_partner_commercial_sync(self): + cr, uid = self.cr, self.uid + p0 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'Sigurd Sunknife', + 'email': 'ssunknife@gmail.com'})) + sunhelm = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'Sunhelm', + 'is_company': True, + 'street': 'Rainbow Street, 13', + 'phone': '1122334455', + 'email': 'info@sunhelm.com', + 'vat': 'BE0477472701', + 'child_ids': [(4, p0.id), + (0, 0, {'name': 'Alrik Greenthorn', + 'email': 'agr@sunhelm.com'})], + })) + p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'Otto Blackwood', + 'email': 'otto.blackwood@sunhelm.com', + 'parent_id': sunhelm.id})) + p11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, + {'name': 'Gini Graywool', + 'email': 'ggr@sunhelm.com', + 'parent_id': p1.id})) + p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid, + [('email', '=', 'agr@sunhelm.com')])[0]) + + for p in (p0, p1, p11, p2): + p.refresh() + self.assertEquals(p.commercial_id, sunhelm, 'Incorrect commercial entity resolution') + self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced') + sunhelmvat = 'BE0123456789' + sunhelm.write({'vat': sunhelmvat}) + for p in (p0, p1, p11, p2): + p.refresh() + self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced') + + p1vat = 'BE0987654321' + p1.write({'vat': p1vat}) + for p in (sunhelm, p0, p11, p2): + p.refresh() + self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities') + + # promote p1 to commercial entity + vals = p1.onchange_type(is_company=True)['value'] + p1.write(dict(vals, parent_id=sunhelm.id, + is_company=True, + name='Sunhelm Subsidiary')) + p1.refresh() + self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields') + self.assertEquals(p1.commercial_id, p1, 'Incorrect commercial entity resolution after setting is_company') + + # writing on parent should not touch child commercial entities + sunhelmvat2 = 'BE0112233445' + sunhelm.write({'vat': sunhelmvat2}) + p1.refresh() + self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields') + p0.refresh() + self.assertEquals(p0.vat, sunhelmvat2, 'Commercial fields must be automatically synced') + if __name__ == '__main__': unittest2.main() \ No newline at end of file From 41d3c2ae88d89daabbdba64b899a221a7aeebf81 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 8 Apr 2013 05:00:52 +0200 Subject: [PATCH 21/65] [FIX] sale: use invoicing partner rather than main one for analytic account context, spotted by Raphael Valyi on bug 1160365 lp bug: https://launchpad.net/bugs/1160365 fixed bzr revid: odo@openerp.com-20130408030052-xgk5p8zkagu21scs --- addons/sale/sale_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index 8a0c6c9e6a4..094e19c050f 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -156,7 +156,7 @@ - + From 70fbc25d932a341af8ef46ffd7bcc2eec750e514 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 8 Apr 2013 17:59:34 +0200 Subject: [PATCH 22/65] [IMP] base, res_partner and contacts management: improve usability and user experience. 1) whennever a contact is created from a parent record: allow to set a dedicated address 2) move the use_parent_address field near the address bzr revid: qdp-launchpad@openerp.com-20130408155934-bk2apzq1gcktqr6m --- openerp/addons/base/res/res_partner_view.xml | 34 ++++++++++++++------ 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 3650b4d6d9d..8b5736c9aea 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -141,11 +141,6 @@ domain="[('is_company', '=', True)]" context="{'default_is_company': True}" attrs="{'invisible': [('is_company','=', True)]}" on_change="onchange_address(use_parent_address, parent_id)" class="oe_inline"/> - -
@@ -160,6 +155,10 @@
+ From d734bf58cc0475bbeb65567a92216e6e79422576 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 16 Apr 2013 11:31:21 +0200 Subject: [PATCH 36/65] [FIX] res.partner: name_get: return "Company, Contact" rather than "Contact (Company)" to make it clearer that the company is selected as well bzr revid: odo@openerp.com-20130416093121-t5soophs2aui8rzq --- openerp/addons/base/res/res_partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index fe2cd26e43b..f578f969c4d 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -516,7 +516,7 @@ class res_partner(osv.osv, format_address): for record in self.browse(cr, uid, ids, context=context): name = record.name if record.parent_id: - name = "%s (%s)" % (name, record.parent_id.name) + name = "%s, %s" % (record.parent_id.name, name) if context.get('show_address'): name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context) name = name.replace('\n\n','\n') From 06cd0a1c7f99cb742a182a654f27e96f982b9d5b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 16 Apr 2013 11:34:03 +0200 Subject: [PATCH 37/65] [FIX] res.partner: avoid hiding `parent_id` and `child_ids` fields if they are set, irregardless of the rest of the `is_company` flag This prevents hiding real data and also allows creating more complex/flexible structures by setting the values of these fields before or after setting is_company, to reach the desired result. bzr revid: odo@openerp.com-20130416093403-9m484d30qqq5ab8l --- openerp/addons/base/res/res_partner_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 7c414da5966..ce97cba4992 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -139,7 +139,7 @@ @@ -185,7 +185,7 @@
- + From b8d99e7aa320c8ddd8c7a2ffdbc6391a1a443d31 Mon Sep 17 00:00:00 2001 From: Cedric Snauwaert Date: Thu, 18 Apr 2013 11:00:11 +0200 Subject: [PATCH 38/65] [FIX]sale: fix workflow problem when deleting an invoice the workflow should go to invoice_exception state bzr revid: csn@openerp.com-20130418090011-dyg175mvwrp8ilij --- addons/sale/sale.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index a6be2838171..7364932f91c 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -999,4 +999,22 @@ class mail_compose_message(osv.Model): wf_service.trg_validate(uid, 'sale.order', context['default_res_id'], 'quotation_sent', cr) return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context) +# +# account.invoice is defined in module account +# +class account_invoice(osv.Model): + """ Overwrite unlink method of account invoice to send a trigger to the sale workflow upon invoice deletion """ + _inherit = 'account.invoice' + + def unlink(self, cr, uid, ids, context=None): + #Cancel invoice(s) first before deleting them so that if any sale order are associated with them + #it will trigger the workflow to put the sale order in an invoice exception state + #if we can't cancel all invoices, do nothing + invoice_ids = self.search(cr, uid, [('id', 'in', ids), ('state', 'in', ['draft', 'cancel'])], context=context) + if len(invoice_ids)==len(ids): + wf_service = netsvc.LocalService("workflow") + for id in ids: + wf_service.trg_validate(uid, 'account.invoice', id, 'invoice_cancel', cr) + return super(account_invoice, self).unlink(cr, uid, ids, context=context) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From db4d08e3a995bb262ebbbdab2b75b466b7c187df Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 18 Apr 2013 11:24:05 +0200 Subject: [PATCH 39/65] [FIX] Extension of controller in-place with explicit spec of same _cp_path When extending a controller in-place (e.g. A(Controller), B(A)) and providing the exact same _cp_path as parent (no-op) execution path would go into handler for _cp_path overwriting and raise an assertion error for overwriting of existing controller. Except this is allowed (if ugly) pattern, so warn & ignore behavior (it is harmless). bzr revid: xmo@openerp.com-20130418092405-wrmmrd648b9koefu --- addons/web/http.py | 8 +++++++- addons/web/tests/test_dispatch.py | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/addons/web/http.py b/addons/web/http.py index f08d7c64c4d..9439d7aa547 100644 --- a/addons/web/http.py +++ b/addons/web/http.py @@ -381,6 +381,12 @@ class ControllerType(type): # inherit from a Controller subclass if path: + # if extending in place with same URL, ignore URL + if parent_path == path: + _logger.warn( + "Controller %s extending %s in-place should not " + "explicitly specify URL", cls, parent) + return _logger.warn("Re-exposing %s at %s.\n" "\tThis usage is unsupported.", parent.__name__, @@ -398,7 +404,7 @@ class Controller(object): def __new__(cls, *args, **kwargs): subclasses = [c for c in cls.__subclasses__() - if c._cp_path is cls._cp_path] + if c._cp_path == cls._cp_path] if subclasses: name = "%s (+%s)" % ( cls.__name__, diff --git a/addons/web/tests/test_dispatch.py b/addons/web/tests/test_dispatch.py index b1304fca7f1..b532cebac44 100644 --- a/addons/web/tests/test_dispatch.py +++ b/addons/web/tests/test_dispatch.py @@ -242,6 +242,29 @@ class TestSubclassing(DispatchCleanup): self.assertEqual('200 OK', status) self.assertEqual('1 2 3', ''.join(body)) + def test_extends_same_path(self): + """ + When subclassing an existing Controller and specifying the same + _cp_path as the parent, ??? + """ + class A(http.Controller): + _cp_path = '/foo' + @http.httprequest + def index(self, req): + return '1' + + class B(A): + _cp_path = '/foo' + @http.httprequest + def index(self, req): + return '2' + + self.app.load_addons() + + body, status, headers = self.client.get('/foo') + self.assertEqual('200 OK', status) + self.assertEqual('2', ''.join(body)) + def test_re_expose(self): """ An existing Controller should not be extended with a new cp_path From 3da2aaf488ed5a98980e90ad3034c23e92ab3b25 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 18 Apr 2013 11:43:15 +0200 Subject: [PATCH 40/65] [IMP] only use name of class being created: module is incorrect for dynamically created classes bzr revid: xmo@openerp.com-20130418094315-qk8m13s4zzvojauw --- addons/web/http.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/web/http.py b/addons/web/http.py index 9439d7aa547..52c9bc92e4c 100644 --- a/addons/web/http.py +++ b/addons/web/http.py @@ -367,7 +367,7 @@ class ControllerType(type): path = attrs.get('_cp_path') if Controller in bases: - assert path, "Controller subclass %s missing a _cp_path" % cls + assert path, "Controller subclass %s missing a _cp_path" % name else: parent_paths = set(base._cp_path for base in bases if issubclass(base, Controller)) @@ -385,7 +385,7 @@ class ControllerType(type): if parent_path == path: _logger.warn( "Controller %s extending %s in-place should not " - "explicitly specify URL", cls, parent) + "explicitly specify URL", name, parent) return _logger.warn("Re-exposing %s at %s.\n" "\tThis usage is unsupported.", @@ -395,7 +395,7 @@ class ControllerType(type): if path: assert path not in controllers_class,\ "Trying to expose %s at the same URL as %s" % ( - cls, controllers_class[path]) + name, controllers_class[path]) controllers_class[path] = cls From d4977dd3bb932ea05a37b75d4712dab362bab686 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 18 Apr 2013 14:56:40 +0200 Subject: [PATCH 41/65] [FIX] missing translation mark in error message lp bug: https://launchpad.net/bugs/1125159 fixed bzr revid: xmo@openerp.com-20130418125640-87g9sdowig7w565d --- addons/web/static/src/js/chrome.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index ef045f07931..02228a96b06 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -249,7 +249,9 @@ instance.web.CrashManager = instance.web.Class.extend({ } // yes, exception handling is shitty if (error.code === 300 && error.data && error.data.type == "client_exception" && error.data.debug.match("SessionExpiredException")) { - this.show_warning({type: "Session Expired", data: { fault_code: "Your OpenERP session expired. Please refresh the current web page." }}); + this.show_warning({type: "Session Expired", data: { + fault_code: _t("Your OpenERP session expired. Please refresh the current web page.") + }}); return; } if (error.data.fault_code) { From 46e95cb136b6864cbc76a0591ad329506b976ca0 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 18 Apr 2013 15:40:32 +0200 Subject: [PATCH 42/65] [FIX] account, account.move.line form view: the same method was defined twice, differently, and parameters were not correctly passed in onchanges bzr revid: qdp-launchpad@openerp.com-20130418134032-t3y4dk4sp4eu2031 --- addons/account/account_move_line.py | 20 +++++++------------- addons/account/account_view.xml | 6 +++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index b616eecdca9..58c4cc583b9 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -655,13 +655,7 @@ class account_move_line(osv.osv): } return result - def onchange_account_id(self, cr, uid, ids, account_id, context=None): - res = {'value': {}} - if account_id: - res['value']['account_tax_id'] = [x.id for x in self.pool.get('account.account').browse(cr, uid, account_id, context=context).tax_ids] - return res - - def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, date=False, journal=False): + def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, date=False, journal=False, context=None): partner_obj = self.pool.get('res.partner') payment_term_obj = self.pool.get('account.payment.term') journal_obj = self.pool.get('account.journal') @@ -675,8 +669,8 @@ class account_move_line(osv.osv): date = datetime.now().strftime('%Y-%m-%d') jt = False if journal: - jt = journal_obj.browse(cr, uid, journal).type - part = partner_obj.browse(cr, uid, partner_id) + jt = journal_obj.browse(cr, uid, journal, context=context).type + part = partner_obj.browse(cr, uid, partner_id, context=context) payment_term_id = False if jt and jt in ('purchase', 'purchase_refund') and part.property_supplier_payment_term: @@ -701,20 +695,20 @@ class account_move_line(osv.osv): elif part.supplier: val['account_id'] = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, id1) if val.get('account_id', False): - d = self.onchange_account_id(cr, uid, ids, val['account_id']) + d = self.onchange_account_id(cr, uid, ids, account_id=val['account_id'], partner_id=part.id, context=context) val.update(d['value']) return {'value':val} - def onchange_account_id(self, cr, uid, ids, account_id=False, partner_id=False): + def onchange_account_id(self, cr, uid, ids, account_id=False, partner_id=False, context=None): account_obj = self.pool.get('account.account') partner_obj = self.pool.get('res.partner') fiscal_pos_obj = self.pool.get('account.fiscal.position') val = {} if account_id: - res = account_obj.browse(cr, uid, account_id) + res = account_obj.browse(cr, uid, account_id, context=context) tax_ids = res.tax_ids if tax_ids and partner_id: - part = partner_obj.browse(cr, uid, partner_id) + part = partner_obj.browse(cr, uid, partner_id, context=context) tax_id = fiscal_pos_obj.map_tax(cr, uid, part and part.property_account_position or False, tax_ids)[0] else: tax_id = tax_ids and tax_ids[0].id or False diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index b8dcefdd3a4..d38684c2317 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -1112,7 +1112,7 @@ - + @@ -1288,7 +1288,7 @@ - + @@ -1352,7 +1352,7 @@ - + From dcfbadd97ea5c7c57cf6fc133d38a62e16e947a8 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 18 Apr 2013 15:53:56 +0200 Subject: [PATCH 43/65] [FIX] hr_expense, usability: added sum in tree view bzr revid: qdp-launchpad@openerp.com-20130418135356-p017meay192awm3y --- addons/hr_expense/hr_expense_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index 2511130a58e..3dc40ed749d 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -32,7 +32,7 @@ - + From dfbe68e69d8df437b7fe54bd242a608f94a8caec Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 18 Apr 2013 16:45:33 +0200 Subject: [PATCH 44/65] [IMP] res.partner: rename commercial_id to commercial_partner_id + make function field inheritable The name `commercial_partner_id` better reflects its purpose and the fact that it is a FK to a partner. An extra indirection through a lambda function was also added to the definition of the function field to make it possible to override it in other modules (otherwise the function is passed by copy directly and cannot be inherited later) bzr revid: odo@openerp.com-20130418144533-owupfwn6h83q432x --- openerp/addons/base/res/res_partner.py | 17 ++++++++++------- openerp/addons/base/tests/test_base.py | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index f578f969c4d..ff6e6e7c61d 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -195,7 +195,7 @@ class res_partner(osv.osv, format_address): result[obj.id] = obj.image != False return result - def _commercial_id_compute(self, cr, uid, ids, name, args, context=None): + def _commercial_partner_compute(self, cr, uid, ids, name, args, context=None): """ Returns the partner that is considered the commercial entity of this partner. The commercial entity holds the master data for all commercial fields (see :py:meth:`~_commercial_fields`) """ @@ -207,6 +207,9 @@ class res_partner(osv.osv, format_address): result[partner.id] = current_partner.id return result + # indirection to avoid passing a copy of the overridable method when declaring the function field + _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + _order = "name" _columns = { 'name': fields.char('Name', size=128, required=True, select=True), @@ -280,7 +283,7 @@ class res_partner(osv.osv, format_address): 'contact_address': fields.function(_address_display, type='char', string='Complete Address'), # technical field used for managing commercial fields - 'commercial_id': fields.function(_commercial_id_compute, type='many2one', relation='res.partner', string='Commercial Entity') + 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity') } def _default_category(self, cr, uid, context=None): @@ -416,16 +419,16 @@ class res_partner(osv.osv, format_address): def _commercial_sync_from_company(self, cr, uid, partner, context=None): """ Handle sync of commercial fields when a new parent commercial entity is set, as if they were related fields """ - if partner.commercial_id != partner: + if partner.commercial_partner_id != partner: commercial_fields = self._commercial_fields(cr, uid, context=context) - sync_vals = self._update_fields_values(cr, uid, partner.commercial_id, + sync_vals = self._update_fields_values(cr, uid, partner.commercial_partner_id, commercial_fields, context=context) return self.write(cr, uid, partner.id, sync_vals, context=context) def _commercial_sync_to_children(self, cr, uid, partner, context=None): """ Handle sync of commercial fields to descendants """ commercial_fields = self._commercial_fields(cr, uid, context=context) - sync_vals = self._update_fields_values(cr, uid, partner.commercial_id, + sync_vals = self._update_fields_values(cr, uid, partner.commercial_partner_id, commercial_fields, context=context) sync_children = [c for c in partner.child_ids if not c.is_company] for child in sync_children: @@ -451,7 +454,7 @@ class res_partner(osv.osv, format_address): # 2. To DOWNSTREAM: sync children if partner.child_ids: # 2a. Commercial Fields: sync if commercial entity - if partner.commercial_id == partner: + if partner.commercial_partner_id == partner: self._commercial_sync_to_children(cr, uid, partner, context=context) # 2b. Address fields: sync if address changed address_fields = self._address_fields(cr, uid, context=context) @@ -493,7 +496,7 @@ class res_partner(osv.osv, format_address): return {'type': 'ir.actions.act_window', 'res_model': 'res.partner', 'view_mode': 'form', - 'res_id': partner.commercial_id.id, + 'res_id': partner.commercial_partner_id.id, 'target': 'new', 'flags': {'form': {'action_buttons': True}}} diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 0455e7b5aff..ec192f2667e 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -219,7 +219,7 @@ class test_base(common.TransactionCase): for p in (p0, p1, p11, p2): p.refresh() - self.assertEquals(p.commercial_id, sunhelm, 'Incorrect commercial entity resolution') + self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution') self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced') sunhelmvat = 'BE0123456789' sunhelm.write({'vat': sunhelmvat}) @@ -240,7 +240,7 @@ class test_base(common.TransactionCase): name='Sunhelm Subsidiary')) p1.refresh() self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields') - self.assertEquals(p1.commercial_id, p1, 'Incorrect commercial entity resolution after setting is_company') + self.assertEquals(p1.commercial_partner_id, p1, 'Incorrect commercial entity resolution after setting is_company') # writing on parent should not touch child commercial entities sunhelmvat2 = 'BE0112233445' From e7aeabc8347e53d79bab5ec9c10e19af0f495900 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 18 Apr 2013 17:13:53 +0200 Subject: [PATCH 45/65] [FIX] account: minor javascript problem that made appear a stack trace lp bug: https://launchpad.net/bugs/1155605 fixed bzr revid: nicolas.vanhoren@openerp.com-20130418151353-dgfawgqgvama1u84 --- addons/account/static/src/js/account_move_reconciliation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/static/src/js/account_move_reconciliation.js b/addons/account/static/src/js/account_move_reconciliation.js index dbbfe3cc069..cbc0abc4f4d 100644 --- a/addons/account/static/src/js/account_move_reconciliation.js +++ b/addons/account/static/src/js/account_move_reconciliation.js @@ -26,7 +26,7 @@ openerp.account = function (instance) { if (this.partners) { this.$el.prepend(QWeb.render("AccountReconciliation", {widget: this})); this.$(".oe_account_recon_previous").click(function() { - self.current_partner = (self.current_partner - 1) % self.partners.length; + self.current_partner = (((self.current_partner - 1) % self.partners.length) + self.partners.length) % self.partners.length; self.search_by_partner(); }); this.$(".oe_account_recon_next").click(function() { From 3c5559045cbbdebe2e7347ae2ffd502c3a0b4d67 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 18 Apr 2013 17:38:29 +0200 Subject: [PATCH 46/65] [FIX] res.partner: add onchange warning when changing an existing contact's company bzr revid: odo@openerp.com-20130418153829-rmkd6xo1cajgfer5 --- openerp/addons/base/res/res_partner.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index ff6e6e7c61d..16ba66babd2 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -351,12 +351,22 @@ class res_partner(osv.osv, format_address): def value_or_id(val): """ return val or val.id if val is a browse record """ return val if isinstance(val, (bool, int, long, float, basestring)) else val.id - + result = {} if parent_id: + if ids: + partner = self.browse(cr, uid, ids[0], context=context) + if partner.parent_id and partner.parent_id.id != parent_id: + result['warning'] = {'title': _('Warning'), + 'message': _('Changing the company of a contact should only be done if it ' + 'was never correctly set. If an existing contact starts working for a new ' + 'company then a new contact should be created under that new ' + 'company. You can use the "Discard" button to abandon this change.')} parent = self.browse(cr, uid, parent_id, context=context) address_fields = self._address_fields(cr, uid, context=context) - return {'value': dict((key, value_or_id(parent[key])) for key in address_fields)} - return {'value': {'use_parent_address': False}} + result['value'] = dict((key, value_or_id(parent[key])) for key in address_fields) + else: + result['value'] = {'use_parent_address': False} + return result def onchange_state(self, cr, uid, ids, state_id, context=None): if state_id: From a9d5c2d37ef8150e90e6dc1082d721400075f468 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 18 Apr 2013 17:40:22 +0200 Subject: [PATCH 47/65] [FIX] res.partner: rename commercial_id to commercial_partner_id, following corresponding change in `base` bzr revid: odo@openerp.com-20130418154022-lt7frhp9c8f2boo0 --- addons/account/account_invoice.py | 2 +- addons/account_report_company/account_invoice.py | 4 ++-- addons/account_report_company/account_invoice_view.xml | 4 ++-- .../report/account_invoice_report.py | 8 ++++---- .../report/account_invoice_report_view.xml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 4611e0ab240..2d09753e584 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1735,7 +1735,7 @@ class res_partner(osv.osv): ''' Find the partner for which the accounting entries will be created ''' - # FIXME: after 7.0, to replace by function field partner.commercial_id + # FIXME: after 7.0, to replace by function field partner.commercial_partner_id #if the chosen partner is not a company and has a parent company, use the parent for the journal entries #because you want to invoice 'Agrolait, accounting department' but the journal items are for 'Agrolait' diff --git a/addons/account_report_company/account_invoice.py b/addons/account_report_company/account_invoice.py index aae1ee77d0e..fe4a7b2c256 100644 --- a/addons/account_report_company/account_invoice.py +++ b/addons/account_report_company/account_invoice.py @@ -25,7 +25,7 @@ class account_invoice(osv.Model): _inherit = 'account.invoice' _columns = { - 'partner_commercial_id': fields.related('partner_id', 'commercial_id', string='Commercial Entity', type='many2one', + 'commercial_partner_id': fields.related('partner_id', 'commercial_partner_id', string='Commercial Entity', type='many2one', relation='res.partner', store=True, readonly=True, help="The commercial entity that will be used on Journal Entries for this invoice") - } \ No newline at end of file + } diff --git a/addons/account_report_company/account_invoice_view.xml b/addons/account_report_company/account_invoice_view.xml index 2db2d77ad87..89479c5a5e7 100644 --- a/addons/account_report_company/account_invoice_view.xml +++ b/addons/account_report_company/account_invoice_view.xml @@ -6,7 +6,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/addons/account_report_company/report/account_invoice_report.py b/addons/account_report_company/report/account_invoice_report.py index 09cf1caca83..5941aef9e6e 100644 --- a/addons/account_report_company/report/account_invoice_report.py +++ b/addons/account_report_company/report/account_invoice_report.py @@ -23,14 +23,14 @@ from openerp.osv import osv, fields class account_invoice_report(osv.Model): _inherit = 'account.invoice.report' _columns = { - 'partner_commercial_id': fields.many2one('res.partner', 'Partner Company', help="Commercial Entity"), + 'commercial_partner_id': fields.many2one('res.partner', 'Partner Company', help="Commercial Entity"), } def _select(self): - return super(account_invoice_report, self)._select() + ", sub.partner_commercial_id as partner_commercial_id" + return super(account_invoice_report, self)._select() + ", sub.commercial_partner_id as commercial_partner_id" def _sub_select(self): - return super(account_invoice_report, self)._sub_select() + ", ai.partner_commercial_id as partner_commercial_id" + return super(account_invoice_report, self)._sub_select() + ", ai.commercial_partner_id as commercial_partner_id" def _group_by(self): - return super(account_invoice_report, self)._group_by() + ", ai.partner_commercial_id" + return super(account_invoice_report, self)._group_by() + ", ai.commercial_partner_id" diff --git a/addons/account_report_company/report/account_invoice_report_view.xml b/addons/account_report_company/report/account_invoice_report_view.xml index bfdc99b1361..90fa4bdf2ec 100644 --- a/addons/account_report_company/report/account_invoice_report_view.xml +++ b/addons/account_report_company/report/account_invoice_report_view.xml @@ -6,7 +6,7 @@ - + @@ -16,7 +16,7 @@ - + From 451f8df2506f8a78502fe7384726e4c3c1211dd7 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 18 Apr 2013 19:20:22 +0200 Subject: [PATCH 48/65] [FIX] sale: orders/quotations action should not force `display_address` flag Doing so affects autocompletion of search results, etc. while the fields on the form view are already properly displayed anyway. bzr revid: odo@openerp.com-20130418172022-e3lu35xq191jxcyu --- addons/sale/sale_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index a6cc7df1f12..9dc5f51d8aa 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -328,7 +328,7 @@ form tree,form,calendar,graph - {'show_address': 1} + {} [('state','not in',('draft','sent','cancel'))]

@@ -371,7 +371,7 @@ form tree,form,calendar,graph - {'show_address': 1} + {} [('state','in',('draft','sent','cancel'))] From 230b23e6cb4a1de55fa4ea521ccd71f25de9e20e Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Fri, 19 Apr 2013 06:17:48 +0000 Subject: [PATCH 49/65] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20130419061733-j4th561m2dju73zo bzr revid: launchpad_translations_on_behalf_of_openerp-20130419061748-4sz8agg8laqbyu4p --- addons/account/i18n/tr.po | 6 +++--- addons/project/i18n/tr.po | 8 ++++---- openerp/addons/base/i18n/tr.po | 11 +++++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/addons/account/i18n/tr.po b/addons/account/i18n/tr.po index 7ef00787437..bc886a80df7 100644 --- a/addons/account/i18n/tr.po +++ b/addons/account/i18n/tr.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-04-17 19:07+0000\n" +"PO-Revision-Date: 2013-04-18 19:19+0000\n" "Last-Translator: Ayhan KIZILTAN \n" "Language-Team: OpenERP Türkiye Yerelleştirmesi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-04-18 06:05+0000\n" +"X-Launchpad-Export-Date: 2013-04-19 06:17+0000\n" "X-Generator: Launchpad (build 16567)\n" "Language: tr\n" @@ -5681,7 +5681,7 @@ msgstr "KDV Hesabı Bildirimi" #. module: account #: view:account.bank.statement:0 msgid "Cancel Statement" -msgstr "" +msgstr "Hesap Özeti İptal" #. module: account #: help:account.config.settings,module_account_accountant:0 diff --git a/addons/project/i18n/tr.po b/addons/project/i18n/tr.po index 8278fd7faab..c4d09b1cb4c 100644 --- a/addons/project/i18n/tr.po +++ b/addons/project/i18n/tr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-04-14 07:42+0000\n" +"PO-Revision-Date: 2013-04-18 19:25+0000\n" "Last-Translator: Ayhan KIZILTAN \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-04-15 06:07+0000\n" -"X-Generator: Launchpad (build 16564)\n" +"X-Launchpad-Export-Date: 2013-04-19 06:17+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: project #: view:project.project:0 @@ -282,7 +282,7 @@ msgstr "Proje Yönetimi" #: model:ir.actions.act_window,name:project.action_project_task_delegate #: view:project.task.delegate:0 msgid "Project Task Delegate" -msgstr "Proje Görev Delege" +msgstr "Prtoje Görevi Yetkilndirme" #. module: project #: model:mail.message.subtype,name:project.mt_project_task_started diff --git a/openerp/addons/base/i18n/tr.po b/openerp/addons/base/i18n/tr.po index ef2983bc61a..117555be34e 100644 --- a/openerp/addons/base/i18n/tr.po +++ b/openerp/addons/base/i18n/tr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:36+0000\n" -"PO-Revision-Date: 2013-04-14 17:36+0000\n" -"Last-Translator: Ayhan KIZILTAN \n" +"PO-Revision-Date: 2013-04-18 16:28+0000\n" +"Last-Translator: Ediz Duman \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-04-15 06:06+0000\n" -"X-Generator: Launchpad (build 16564)\n" +"X-Launchpad-Export-Date: 2013-04-19 06:17+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -420,6 +420,9 @@ msgid "" "invoices from picking, OpenERP is able to add and compute the shipping " "line.\n" msgstr "" +"\n" +"Teslimat yöntemlerin de satış siparişleri eklemek ve toplama için izin " +"verir\n" #. module: base #: code:addons/base/ir/ir_filters.py:80 From 850396421693c405c2ab2763f3734628b09be7ad Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 15:43:35 +0200 Subject: [PATCH 50/65] [IMP] account_report_company: make res.partner.commercial_partner_id field stored, for further reporting needs This is not strictly necessary, but can be useful for other modules in order to ease SQL reporting, without even needing to store a denormalized copy of the "commercial partner" key on the documents themselves. Also renamed the Python fiel to something generic since it now inherits multiple models. bzr revid: odo@openerp.com-20130419134335-rhsg24f2uuwl3kla --- addons/account_report_company/__init__.py | 2 +- ...unt_invoice.py => account_report_company.py} | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) rename addons/account_report_company/{account_invoice.py => account_report_company.py} (63%) diff --git a/addons/account_report_company/__init__.py b/addons/account_report_company/__init__.py index 623cb467c25..42ec779494e 100644 --- a/addons/account_report_company/__init__.py +++ b/addons/account_report_company/__init__.py @@ -19,7 +19,7 @@ # ############################################################################## -import account_invoice +import account_report_company import report # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account_report_company/account_invoice.py b/addons/account_report_company/account_report_company.py similarity index 63% rename from addons/account_report_company/account_invoice.py rename to addons/account_report_company/account_report_company.py index fe4a7b2c256..d643acd0c95 100644 --- a/addons/account_report_company/account_invoice.py +++ b/addons/account_report_company/account_report_company.py @@ -21,6 +21,23 @@ from openerp.osv import osv, fields +class res_partner(osv.Model): + _inherit = 'res.partner' + + # indirection to avoid passing a copy of the overridable method when declaring the function field + _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + + _commercial_partner_id_store_triggers = { + 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]), + ['parent_id', 'is_company'], 10) + } + + _columns = { + # make the original field stored, in case it's needed for reporting purposes + 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', + store=_commercial_partner_id_store_triggers) + } + class account_invoice(osv.Model): _inherit = 'account.invoice' From cfb53f1aada7a04f32fae6d30add3ef25bab5b41 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 15:57:56 +0200 Subject: [PATCH 51/65] [FIX] res.partner: search using 'child_of' should include inactive children This is necessary for 2 reasons: - when searching on Business documents the search domain will be [('partner_id', 'child_of', 'ACME')] in order to match all descendants, and it must match inactive children as well - in other cases like for resolving IDs to update via store triggers, it is necessary that 'child_of' returns inactive children too. The implementation is tricky because the ORM automatically transform 'child_of' domains into recursive searches with [('parent_id', 'in', ids)], which is the same query that the reverse one2many 'child_ids' will also use to find contacts. The overridden search() therefore matches this domain pattern only when there is one criterion (to avoid side-effects in other cases) and a dummy extra 'domain' was added to the definition of the 'child_ids' o2m so it won't match. The net result is that child_ids will not return inactive children while child_of will return all descendants when it is the only criterion. This is the expected behavior whenever child_of is used on res.partner, because it's safer to always show business documents. The only side-effects will be for custom/manual search calls with a single criterion of the form ('parent_id','in', x) and those can be fixed by adding an extra domain component ('active','=',True), just like child_ids does. bzr revid: odo@openerp.com-20130419135756-2kbhwr23lygqdoob --- openerp/addons/base/res/res_partner.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 16ba66babd2..9ccd595e98a 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -216,7 +216,7 @@ class res_partner(osv.osv, format_address): 'date': fields.date('Date', select=1), 'title': fields.many2one('res.partner.title', 'Title'), 'parent_id': fields.many2one('res.partner', 'Related Company'), - 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'), + 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override 'ref': fields.char('Reference', size=64, select=1), 'lang': fields.selection(_lang_get, 'Language', help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."), @@ -568,6 +568,15 @@ class res_partner(osv.osv, format_address): rec_id = self.create(cr, uid, {self._rec_name: name or email, 'email': email or False}, context=context) return self.name_get(cr, uid, [rec_id], context)[0] + def _search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False, access_rights_uid=None): + """ Override search() to always show inactive children when searching via ``child_of`` operator. The ORM will + always call search() with a simple domain of the form [('parent_id', 'in', [ids])]. """ + # a special ``domain`` is set on the ``child_ids`` o2m to bypass this logic, as it uses similar domain expressions + if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in'): + context = dict(context or {}, active_test=False) + return super(res_partner, self)._search(cr, user, args, offset=offset, limit=limit, order=order, context=context, + count=count, access_rights_uid=access_rights_uid) + def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): if not args: args = [] From ea2544e43277b973c4338cf77c7d8753e9703d3a Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 19 Apr 2013 16:35:29 +0200 Subject: [PATCH 52/65] [FIX] pad: problem about pad title not being updated correctly, was solved by solving another, more serious, bug that didn't updated correctly the database backup of the pad lp bug: https://launchpad.net/bugs/1155039 fixed bzr revid: nicolas.vanhoren@openerp.com-20130419143529-jku5titoacaajft0 --- addons/pad/pad.py | 9 +++- addons/pad/static/src/js/pad.js | 72 +++++++++++++++---------------- addons/pad/static/src/xml/pad.xml | 37 +++++++--------- 3 files changed, 56 insertions(+), 62 deletions(-) diff --git a/addons/pad/pad.py b/addons/pad/pad.py index 90f5354054c..94d2097262d 100644 --- a/addons/pad/pad.py +++ b/addons/pad/pad.py @@ -84,10 +84,15 @@ class pad_common(osv.osv_memory): # Set the pad content in vals def _set_pad_value(self, cr, uid, vals, context=None): - for k,v in vals.items(): + for k in self._all_columns.keys(): field = self._all_columns[k].column if hasattr(field,'pad_content_field'): - vals[field.pad_content_field] = self.pad_get_content(cr, uid, v, context=context) + url = vals.get(k) + if not url and ("id" in vals): + url = self.read(cr, uid, vals["id"], [k], context=context)[k] + if url: + vals[field.pad_content_field] = self.pad_get_content(cr, uid, url, context=context) + def copy(self, cr, uid, id, default=None, context=None): if not default: diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js index b96047340ad..1a2de41745b 100644 --- a/addons/pad/static/src/js/pad.js +++ b/addons/pad/static/src/js/pad.js @@ -1,67 +1,63 @@ openerp.pad = function(instance) { - instance.web.form.FieldPad = instance.web.form.AbstractField.extend({ + instance.web.form.FieldPad = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeWidgetMixin, { template: 'FieldPad', - configured: false, content: "", - start: function() { - this._super(); - var self = this; - this.on('change:effective_readonly',this,function(){ - self.renderElement(); + init: function() { + this._super.apply(this, arguments); + this.set("configured", true); + this.on("change:configured", this, this.switch_configured); + }, + initialize_content: function() { + this.switch_configured(); + this.$('.oe_pad_switch').click(function() { + self.$el.toggleClass('oe_pad_fullscreen'); }); + this.render_value(); + }, + switch_configured: function() { + this.$(".oe_unconfigured").toggle(! this.get("configured")); + this.$(".oe_configured").toggle(this.get("configured")); }, render_value: function() { - var self = this; - var _super = _.bind(this._super, this); - if (this.get("value") === false || this.get("value") === "") { - self.view.dataset.call('pad_generate_url',{context:{ + var self = this; + if (this.get("configured") && ! this.get("value")) { + self.view.dataset.call('pad_generate_url', { + context: { model: self.view.model, field_name: self.name, object_id: self.view.datarecord.id - }}).done(function(data) { - if(data&&data.url){ - self.set({value: data.url}); - _super(data.url); - self.renderElement(); + }, + }).done(function(data) { + if (! data.url) { + self.set("configured", false); + } else { + self.set("value", data.url); } }); - } else { - self.renderElement(); } - this._dirty_flag = true; - }, - renderElement: function(){ - var self = this; + this.$('.oe_pad_content').html(""); var value = this.get('value'); if (this.pad_loading_request) { this.pad_loading_request.abort(); } - if(!_.str.startsWith(value,'http')){ - this.configured = false; - this.content = ""; - }else{ - this.configured = true; - if(!this.get('effective_readonly')){ - this.content = ''; - }else{ + if (_.str.startsWith(value, 'http')) { + if (! this.get('effective_readonly')) { + var content = ''; + this.$('.oe_pad_content').html(content); + this._dirty_flag = true; + } else { this.content = '

... Loading pad ...
'; - this.pad_loading_request = $.get(value+'/export/html') - .done(function(data){ + this.pad_loading_request = $.get(value + '/export/html').done(function(data) { groups = /\<\s*body\s*\>(.*?)\<\s*\/body\s*\>/.exec(data); data = (groups || []).length >= 2 ? groups[1] : ''; self.$('.oe_pad_content').html('
'); self.$('.oe_pad_readonly').html(data); - }).error(function(){ + }).fail(function() { self.$('.oe_pad_content').text('Unable to load pad'); }); } } - this._super(); - this.$('.oe_pad_content').html(this.content); - this.$('.oe_pad_switch').click(function(){ - self.$el.toggleClass('oe_pad_fullscreen'); - }); }, }); diff --git a/addons/pad/static/src/xml/pad.xml b/addons/pad/static/src/xml/pad.xml index bd3e296f9b3..f915e867b35 100644 --- a/addons/pad/static/src/xml/pad.xml +++ b/addons/pad/static/src/xml/pad.xml @@ -5,32 +5,25 @@ - -
-

- You must configure the etherpad through the menu Settings > Companies > Companies, in the configuration tab of your company. -

-
-
- - +
+

+ You must configure the etherpad through the menu Settings > Companies > Companies, in the configuration tab of your company. +

-
-
-
+
+ +
+ &Ntilde; +
+
+
+
+
+ + - -
-
- &Ntilde; -
-
-
-
-
-
From 1f2064cb93aae96868c5b7f430bbaca71248ab81 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 19 Apr 2013 16:42:38 +0200 Subject: [PATCH 53/65] [FIX] pad: revert part of previous fix because it could produce problems in some cases bzr revid: nicolas.vanhoren@openerp.com-20130419144238-0hq1rgmcacw5sw1r --- addons/pad/pad.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/addons/pad/pad.py b/addons/pad/pad.py index 94d2097262d..90f5354054c 100644 --- a/addons/pad/pad.py +++ b/addons/pad/pad.py @@ -84,15 +84,10 @@ class pad_common(osv.osv_memory): # Set the pad content in vals def _set_pad_value(self, cr, uid, vals, context=None): - for k in self._all_columns.keys(): + for k,v in vals.items(): field = self._all_columns[k].column if hasattr(field,'pad_content_field'): - url = vals.get(k) - if not url and ("id" in vals): - url = self.read(cr, uid, vals["id"], [k], context=context)[k] - if url: - vals[field.pad_content_field] = self.pad_get_content(cr, uid, url, context=context) - + vals[field.pad_content_field] = self.pad_get_content(cr, uid, v, context=context) def copy(self, cr, uid, id, default=None, context=None): if not default: From 83feb1c46f72389002aa3b30251dc1f71c3b972d Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 18:44:47 +0200 Subject: [PATCH 54/65] [REVERT] res.partner: undo change of ordering in name_search result, to be addressed via a stored display_name field (temporarily added by account_report_company module in 7.0) bzr revid: odo@openerp.com-20130419164447-wrmfghxi44au3273 --- openerp/addons/base/res/res_partner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 9ccd595e98a..d29e153e907 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -596,9 +596,9 @@ class res_partner(osv.osv, format_address): LEFT JOIN res_partner company ON partner.parent_id = company.id WHERE partner.email ''' + operator +''' %(name)s OR partner.name || ' (' || COALESCE(company.name,'') || ')' - ''' + operator + ' %(name)s ORDER BY partner.is_company DESC, partner.name' + limit_str, query_args) + ''' + operator + ' %(name)s ' + limit_str, query_args) ids = map(lambda x: x[0], cr.fetchall()) - ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, order="is_company desc, name", context=context) + ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context) if ids: return self.name_get(cr, uid, ids, context) return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) From 9b9c3fa59cb7ced71f3607a67ec3836804510dca Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 18:47:28 +0200 Subject: [PATCH 55/65] [FIX] res.partner.name_get: partners marked as "is_company" should appear as standalone This is more consistent with the way we expect reporting to work, and will also ensure that these companies appear right above their contacts in search order (which will match name_get) bzr revid: odo@openerp.com-20130419164728-25312wtyzt9h6egw --- openerp/addons/base/res/res_partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d29e153e907..2637b922f8c 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -528,7 +528,7 @@ class res_partner(osv.osv, format_address): res = [] for record in self.browse(cr, uid, ids, context=context): name = record.name - if record.parent_id: + if record.parent_id and not record.is_company: name = "%s, %s" % (record.parent_id.name, name) if context.get('show_address'): name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context) From 5e2ce8b709528f8bcf9376c84c49cb90d3422c2a Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 18:52:39 +0200 Subject: [PATCH 56/65] [IMP] account_report_company: add extra stored function field `display_name` on res.partner and use it for sorting This makes name_search() results, group_by, etc. all behave as expected bzr revid: odo@openerp.com-20130419165239-15szgi0e686k6mh9 --- .../account_report_company.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/addons/account_report_company/account_report_company.py b/addons/account_report_company/account_report_company.py index d643acd0c95..22719440dec 100644 --- a/addons/account_report_company/account_report_company.py +++ b/addons/account_report_company/account_report_company.py @@ -23,19 +23,27 @@ from openerp.osv import osv, fields class res_partner(osv.Model): _inherit = 'res.partner' - - # indirection to avoid passing a copy of the overridable method when declaring the function field - _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + _order = 'display_name' + + def _display_name_compute(self, cr, uid, ids, name, args, context=None): + return dict(self.name_get(cr, uid, ids, context=context)) _commercial_partner_id_store_triggers = { 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]), ['parent_id', 'is_company'], 10) } + # indirections to avoid passing a copy of the overridable method when declaring the function field + _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + _display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs) + _columns = { # make the original field stored, in case it's needed for reporting purposes 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', - store=_commercial_partner_id_store_triggers) + store=_commercial_partner_id_store_triggers), + + # extra field to allow ORDER BY to match visible names + 'display_name': fields.function(_display_name, type='char', string='Name', store=_commercial_partner_id_store_triggers), } class account_invoice(osv.Model): From 64f29cfa1010a5af437f36056c53db995e185e78 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 19:18:53 +0200 Subject: [PATCH 57/65] [IMP] account_report_company: use `display_name` instead of name in kanban and list views, so labels visually match order bzr revid: odo@openerp.com-20130419171853-dvfi5jvvlof9afoo --- addons/account_report_company/__openerp__.py | 1 + .../res_partner_view.xml | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 addons/account_report_company/res_partner_view.xml diff --git a/addons/account_report_company/__openerp__.py b/addons/account_report_company/__openerp__.py index 9ee15e1556c..6c2f89c62c0 100644 --- a/addons/account_report_company/__openerp__.py +++ b/addons/account_report_company/__openerp__.py @@ -48,6 +48,7 @@ directly integrated in the core accounting. 'depends': ['account'], 'data': [ 'account_invoice_view.xml', + 'res_partner_view.xml', 'report/account_invoice_report_view.xml', ], 'auto_install': True, diff --git a/addons/account_report_company/res_partner_view.xml b/addons/account_report_company/res_partner_view.xml new file mode 100644 index 00000000000..cae010f3066 --- /dev/null +++ b/addons/account_report_company/res_partner_view.xml @@ -0,0 +1,24 @@ + + + + + res.partner + + + + + + + + + + res.partner + + + + + + + + + \ No newline at end of file From 18ee18244f5646beeac4be90abd23cbe17c49775 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 19 Apr 2013 19:31:59 +0200 Subject: [PATCH 58/65] [FIX] test_expression: assertion was too sensitive to exact parameters Now that res.partner.child_ids has an extra domain attribute the exact number of parameters of queries using `child_ids` in the WHERE clause is different. bzr revid: odo@openerp.com-20130419173159-ef1onm3823hsi77n --- openerp/addons/base/tests/test_expression.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/tests/test_expression.py b/openerp/addons/base/tests/test_expression.py index 49bc7d57ca1..4f533a5e170 100644 --- a/openerp/addons/base/tests/test_expression.py +++ b/openerp/addons/base/tests/test_expression.py @@ -263,7 +263,7 @@ class test_expression(common.TransactionCase): "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition") self.assertIn('"res_partner__child_ids"."id"="res_partner__child_ids__bank_ids"."partner_id"', sql_query[1], "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition") - self.assertEqual(set([b_aa, b_ba]), set(sql_query[2]), + self.assertEqual(set([b_aa, b_ba]), set(sql_query[2][-2:]), "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect parameter") # -------------------------------------------------- From 16b38a053afea9436e21cf5325d83cf029a84d24 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 20 Apr 2013 02:47:13 +0200 Subject: [PATCH 59/65] [FIX] res.partner: fix invisible attrs on Contacts tab, empty o2m field results in `[]`, not `False` bzr revid: odo@openerp.com-20130420004713-0cblmquf4t6i2n0r --- openerp/addons/base/res/res_partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index ce97cba4992..741b6eb5cdd 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -185,7 +185,7 @@ - + From b91cd6127ad295a272c52b714d7ebefb3c40f446 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 20 Apr 2013 03:50:03 +0200 Subject: [PATCH 60/65] [REVERT] account_report_company: undo override of res.partner.commercial_partner_id field to store it, as the ORM does not support it and it's not strictly necessary It works when installing the module but would break everytime another module that inherits from res.partner is installed/update from command-line (e.g. -i/-u crm), as account_report_company is low in the dependency graph so the field is dropped when the ORM notices that the current field definition is not stored. This can be solved in trunk by making the field stored directly in 'base'. bzr revid: odo@openerp.com-20130420015003-8y48xrb14cjif60w --- .../account_report_company/account_report_company.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/addons/account_report_company/account_report_company.py b/addons/account_report_company/account_report_company.py index 22719440dec..0c102fcc4e1 100644 --- a/addons/account_report_company/account_report_company.py +++ b/addons/account_report_company/account_report_company.py @@ -28,22 +28,17 @@ class res_partner(osv.Model): def _display_name_compute(self, cr, uid, ids, name, args, context=None): return dict(self.name_get(cr, uid, ids, context=context)) - _commercial_partner_id_store_triggers = { + _display_name_store_triggers = { 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]), ['parent_id', 'is_company'], 10) } - # indirections to avoid passing a copy of the overridable method when declaring the function field - _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + # indirection to avoid passing a copy of the overridable method when declaring the function field _display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs) _columns = { - # make the original field stored, in case it's needed for reporting purposes - 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', - store=_commercial_partner_id_store_triggers), - # extra field to allow ORDER BY to match visible names - 'display_name': fields.function(_display_name, type='char', string='Name', store=_commercial_partner_id_store_triggers), + 'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers), } class account_invoice(osv.Model): From feefb0ad36f055167d21ae20ef3a5f5c928b709a Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 20 Apr 2013 04:26:42 +0200 Subject: [PATCH 61/65] [FIX] search views: use child_of operator for partner_id fields that can reference both companies and contacts The goal is to match both the Company and its contacts when searching for the Company bzr revid: odo@openerp.com-20130420022642-6qe8pp4ifexjms65 --- addons/account/project/project_view.xml | 2 +- .../account_analytic_analysis_view.xml | 2 +- addons/account_asset/account_asset_view.xml | 2 +- addons/account_asset/report/account_asset_report_view.xml | 2 +- addons/account_voucher/voucher_payment_receipt_view.xml | 4 ++-- addons/account_voucher/voucher_sales_purchase_view.xml | 4 ++-- addons/crm/crm_lead_view.xml | 4 ++-- addons/crm/crm_phonecall_view.xml | 2 +- addons/crm/report/crm_lead_report_view.xml | 2 +- addons/crm/report/crm_phonecall_report_view.xml | 2 +- addons/crm_claim/crm_claim_view.xml | 2 +- addons/crm_claim/report/crm_claim_report_view.xml | 2 +- addons/crm_helpdesk/crm_helpdesk_view.xml | 2 +- addons/crm_helpdesk/report/crm_helpdesk_report_view.xml | 1 + addons/mrp_repair/mrp_repair_view.xml | 2 +- addons/project/project_view.xml | 2 +- addons/project/report/project_report_view.xml | 2 +- addons/project_issue/project_issue_view.xml | 3 ++- addons/project_issue/report/project_issue_report_view.xml | 2 +- addons/stock/report/report_stock_move_view.xml | 2 +- addons/stock/stock_view.xml | 6 ++++-- 21 files changed, 28 insertions(+), 24 deletions(-) diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml index aa567d2fc79..79a1e76c7e7 100644 --- a/addons/account/project/project_view.xml +++ b/addons/account/project/project_view.xml @@ -31,7 +31,7 @@ - + diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml index a9437267611..8d7a89e4622 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml +++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml @@ -186,7 +186,7 @@ - + diff --git a/addons/account_asset/account_asset_view.xml b/addons/account_asset/account_asset_view.xml index c4cb17bded3..fe1fcf473ba 100644 --- a/addons/account_asset/account_asset_view.xml +++ b/addons/account_asset/account_asset_view.xml @@ -223,7 +223,7 @@ - + diff --git a/addons/account_asset/report/account_asset_report_view.xml b/addons/account_asset/report/account_asset_report_view.xml index 4865196c4a8..c772c6e4103 100644 --- a/addons/account_asset/report/account_asset_report_view.xml +++ b/addons/account_asset/report/account_asset_report_view.xml @@ -49,7 +49,7 @@ - + diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml index de873c9195c..109c2f9aec9 100644 --- a/addons/account_voucher/voucher_payment_receipt_view.xml +++ b/addons/account_voucher/voucher_payment_receipt_view.xml @@ -11,7 +11,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/addons/account_voucher/voucher_sales_purchase_view.xml b/addons/account_voucher/voucher_sales_purchase_view.xml index 05b783dd339..6a84a09d5e6 100644 --- a/addons/account_voucher/voucher_sales_purchase_view.xml +++ b/addons/account_voucher/voucher_sales_purchase_view.xml @@ -10,7 +10,7 @@ - + @@ -32,7 +32,7 @@ - + diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index fb18e747fd7..be153167473 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -328,7 +328,7 @@ - + @@ -546,7 +546,7 @@ - + diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml index 67df85e6178..4530f412e07 100644 --- a/addons/crm/crm_phonecall_view.xml +++ b/addons/crm/crm_phonecall_view.xml @@ -185,7 +185,7 @@ - + diff --git a/addons/crm/report/crm_lead_report_view.xml b/addons/crm/report/crm_lead_report_view.xml index 0e5df8837f1..f05e8ee896b 100644 --- a/addons/crm/report/crm_lead_report_view.xml +++ b/addons/crm/report/crm_lead_report_view.xml @@ -80,7 +80,7 @@ - + diff --git a/addons/crm/report/crm_phonecall_report_view.xml b/addons/crm/report/crm_phonecall_report_view.xml index 1f1a4f91046..06966f3a0a8 100644 --- a/addons/crm/report/crm_phonecall_report_view.xml +++ b/addons/crm/report/crm_phonecall_report_view.xml @@ -62,7 +62,7 @@ - + diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml index b1ab72e20f6..f545406187d 100644 --- a/addons/crm_claim/crm_claim_view.xml +++ b/addons/crm_claim/crm_claim_view.xml @@ -201,7 +201,7 @@ - + diff --git a/addons/crm_claim/report/crm_claim_report_view.xml b/addons/crm_claim/report/crm_claim_report_view.xml index a61490c6086..a9a4bcb27c1 100644 --- a/addons/crm_claim/report/crm_claim_report_view.xml +++ b/addons/crm_claim/report/crm_claim_report_view.xml @@ -63,7 +63,7 @@ - + diff --git a/addons/crm_helpdesk/crm_helpdesk_view.xml b/addons/crm_helpdesk/crm_helpdesk_view.xml index 6c0e3433afe..d833e7bbcf6 100644 --- a/addons/crm_helpdesk/crm_helpdesk_view.xml +++ b/addons/crm_helpdesk/crm_helpdesk_view.xml @@ -152,7 +152,7 @@ - + diff --git a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml index 05f502656d2..f6522a15c9f 100644 --- a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml +++ b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml @@ -62,6 +62,7 @@ + diff --git a/addons/mrp_repair/mrp_repair_view.xml b/addons/mrp_repair/mrp_repair_view.xml index d35a9ebcf1d..a4526b5b581 100644 --- a/addons/mrp_repair/mrp_repair_view.xml +++ b/addons/mrp_repair/mrp_repair_view.xml @@ -210,7 +210,7 @@ - + diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index e25a5b1eb93..f0092a1dd33 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -182,7 +182,7 @@ - + diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml index 10f3f4a8c7c..d9650e165ce 100644 --- a/addons/project/report/project_report_view.xml +++ b/addons/project/report/project_report_view.xml @@ -69,7 +69,7 @@ - + diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index f4710766d61..74c83afd304 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -139,7 +139,7 @@ project.issue - + @@ -150,6 +150,7 @@ + diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml index 47ea91fad5f..93233704e65 100644 --- a/addons/project_issue/report/project_issue_report_view.xml +++ b/addons/project_issue/report/project_issue_report_view.xml @@ -55,7 +55,7 @@ - + diff --git a/addons/stock/report/report_stock_move_view.xml b/addons/stock/report/report_stock_move_view.xml index 4f3e256389c..fcf99f6e51e 100644 --- a/addons/stock/report/report_stock_move_view.xml +++ b/addons/stock/report/report_stock_move_view.xml @@ -149,7 +149,7 @@ - + diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 14a1dca7dc7..83362ab5d6f 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -807,7 +807,7 @@ - + @@ -934,6 +934,7 @@ + @@ -1059,6 +1060,7 @@ + @@ -1370,7 +1372,7 @@ - + From 6a600ff3115d2e196a18287108eb1f87fda825fa Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Sat, 20 Apr 2013 06:48:40 +0000 Subject: [PATCH 62/65] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20130420064840-ctlb3ywgmfytczfj --- openerp/addons/base/i18n/he.po | 85 +++++++++++++++++++++++-------- openerp/addons/base/i18n/zh_CN.po | 70 ++++++++++++++++++++----- 2 files changed, 123 insertions(+), 32 deletions(-) diff --git a/openerp/addons/base/i18n/he.po b/openerp/addons/base/i18n/he.po index fc76958df2f..4d38b47ac82 100644 --- a/openerp/addons/base/i18n/he.po +++ b/openerp/addons/base/i18n/he.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:36+0000\n" -"PO-Revision-Date: 2013-04-16 08:22+0000\n" -"Last-Translator: Liron Achdut \n" +"PO-Revision-Date: 2013-04-19 12:49+0000\n" +"Last-Translator: sef \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: 2013-04-17 05:57+0000\n" +"X-Launchpad-Export-Date: 2013-04-20 06:48+0000\n" "X-Generator: Launchpad (build 16567)\n" #. module: base @@ -25,6 +25,9 @@ msgid "" "================================================\n" " " msgstr "" +"\n" +"רכיב לכתיבת והדפסת המחאות\n" +" " #. module: base #: view:res.partner.bank:0 @@ -53,6 +56,8 @@ msgid "" "The second argument of the many2many field %s must be a SQL table !You used " "%s, which is not a valid SQL table name." msgstr "" +"הארגומנט השני של השדה many2many %s חייב להיות טבלת SQL! השתמשת ב-%s, שאינו " +"שם תקף של טבלת SQL." #. module: base #: field:ir.ui.view,arch:0 @@ -63,12 +68,12 @@ msgstr "הצג ארכיטקטורה" #. module: base #: model:ir.module.module,summary:base.module_sale_stock msgid "Quotation, Sale Orders, Delivery & Invoicing Control" -msgstr "" +msgstr "ניהול הצעות מחיר, הזמנות, תעודות משלוח וחשבוניות" #. module: base #: selection:ir.sequence,implementation:0 msgid "No gap" -msgstr "" +msgstr "ללא פער" #. module: base #: selection:base.language.install,lang:0 @@ -85,7 +90,7 @@ msgstr "Spanish (PY) / ספרדית (PY)" msgid "" "Helps you manage your projects and tasks by tracking them, generating " "plannings, etc..." -msgstr "" +msgstr "עזרה בניהול פרויקטים ומשימות על ידי מעקב, יצירת תכנונים ועוד ..." #. module: base #: model:ir.module.module,summary:base.module_point_of_sale @@ -160,6 +165,8 @@ msgid "" "specified as a Python expression defining a list of triplets. For example: " "[('color','=','red')]" msgstr "" +"הדומיין החלופי להגבלת ערכים אפשריים לשדות יחסים, המוגדר כביטוי של פייטון " +"המגדיר רשימה של שלשות. לדוגמא: [('אדום','=','צבע')]" #. module: base #: field:res.partner,ref:0 @@ -179,7 +186,7 @@ msgstr "חלון מטרה" #. module: base #: field:ir.actions.report.xml,report_rml:0 msgid "Main Report File Path" -msgstr "" +msgstr "נתיב קובץ לדוח ראשי" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_analytic_plans @@ -200,6 +207,13 @@ msgid "" "revenue\n" "reports." msgstr "" +"\n" +"הנפקת חשבוניות מתוך הוצאות, רשומות שעות עבודה\n" +"========================================================\n" +"\n" +"רכיב להנפקת חשבוניות על פי הוצאות (שעות עבודה, הוצאות, וכו')\n" +"\n" +"באפשרותך להגדיר רשימות מחירים בניתוח חשבון, וליצור דוחות רווח צפוי" #. module: base #: code:addons/base/ir/ir_sequence.py:104 @@ -216,6 +230,8 @@ msgid "" "Properties of base fields cannot be altered in this manner! Please modify " "them through Python code, preferably through a custom addon!" msgstr "" +"לא ניתן לשנות את תכונות הבסיס באופן זה ! נא לשנות אותם ברמת הקוד, רצוי " +"באמצעות תוסף ייעודי" #. module: base #: code:addons/osv.py:151 @@ -232,7 +248,7 @@ msgstr "ir.ui.view.custom" #: code:addons/base/ir/ir_model.py:375 #, python-format msgid "Renaming sparse field \"%s\" is not allowed" -msgstr "" +msgstr "אין אישור לשינוי שם שדה \"%s\"" #. module: base #: model:res.country,name:base.sz @@ -274,7 +290,7 @@ msgstr "" #. module: base #: model:res.groups,name:base.group_multi_currency msgid "Multi Currencies" -msgstr "" +msgstr "ריבוי מטבעות" #. module: base #: model:ir.module.module,description:base.module_l10n_cl @@ -286,6 +302,10 @@ msgid "" "\n" " " msgstr "" +"\n" +"טבלאת חשבונאות ומס צ'יליאני\n" +"\n" +" " #. module: base #: model:ir.module.module,shortdesc:base.module_sale @@ -297,12 +317,12 @@ msgstr "ניהול מכירות" msgid "" "The internal user that is in charge of communicating with this contact if " "any." -msgstr "" +msgstr "המשתמש הפנימי האחראי לתקשורת עם איש קשר זה, אם קיים." #. module: base #: view:res.partner:0 msgid "Search Partner" -msgstr "" +msgstr "חפש שותף (ספק/לקוח)" #. module: base #: field:ir.module.category,module_nr:0 @@ -336,6 +356,12 @@ msgid "" " - tree_but_open\n" "For defaults, an optional condition" msgstr "" +"לעולות, אחת ממשבצות הפעולה האפשריות:\n" +" - לקוח_פעולה_מרובה\n" +" - לקוח_הדפסה_מרובה\n" +" - לקוח_ פעולה_קשורה\n" +" - עץ_אבל_פתוח\n" +"לברירות מחדל, תנאי חלופי" #. module: base #: sql_constraint:res.lang:0 @@ -390,6 +416,8 @@ msgid "" "There is already a shared filter set as default for %(model)s, delete or " "change it before setting a new default" msgstr "" +"כבר הוגדר מסנן משותף כברירת מחדל עבור %(model)s, יש למחוק או לשנות אותו לפני " +"בחירת מסנן ברירת מחדל חדש" #. module: base #: code:addons/orm.py:2649 @@ -534,7 +562,7 @@ msgstr "הגויאנה הצרפתית" #. module: base #: model:ir.module.module,summary:base.module_hr msgid "Jobs, Departments, Employees Details" -msgstr "עבודות, מחלקות, פרטי עובדים" +msgstr "משרות, מחלקות, פרטי עובדים" #. module: base #: model:ir.module.module,description:base.module_analytic @@ -573,6 +601,17 @@ msgid "" "* Use emails to automatically confirm and send acknowledgements for any " "event registration\n" msgstr "" +"\n" +"ארגון וניהול אירועים\n" +"======================================\n" +"\n" +"רכיב האירועים מאפשר את ניהול כל המשימות המשוייכות לאירוע בצורה יעילה: תכנון, " +"ניהול הרשמות, הגעה וכו'.\n" +"\n" +"תכונות עיקריות\n" +"------------\n" +"* ניהול אירועים והרשמות לאירועים\n" +"* שליחה אוטומטית של בקשות אישור הגעה בדוא\"ל\n" #. module: base #: selection:base.language.install,lang:0 @@ -627,7 +666,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (VE) / Español (VE)" -msgstr "" +msgstr "ספרדית(VE) / Español (VE)" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_timesheet_invoice @@ -637,7 +676,7 @@ msgstr "חשבונית על גליון שעות" #. module: base #: view:base.module.upgrade:0 msgid "Your system will be updated." -msgstr "" +msgstr "המערכת תעודכן" #. module: base #: field:ir.actions.todo,note:0 @@ -653,7 +692,7 @@ msgstr "שם מדינה" #. module: base #: model:res.country,name:base.co msgid "Colombia" -msgstr "Colombia" +msgstr "קולומביה" #. module: base #: model:res.partner.title,name:base.res_partner_title_mister @@ -666,7 +705,7 @@ msgid "" "The ISO country code in two chars.\n" "You can use this field for quick search." msgstr "" -"צופן ה-ISO בשתי אותיות.\n" +"קוד מדינה ISO בשתי אותיות.\n" "ניתן להשתמש בשדה זה לחיפוש מהיר." #. module: base @@ -715,22 +754,22 @@ msgstr "שדות מותאמים אישית חייבים להתחיל ב 'x_' !" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_mx msgid "Mexico - Accounting" -msgstr "" +msgstr "מקסיקו - חשבונאות" #. module: base #: help:ir.actions.server,action_id:0 msgid "Select the Action Window, Report, Wizard to be executed." -msgstr "בחר בחלון הפעלה,דוח,אשף שתרצה לבצע." +msgstr "בחלון ההפעלה ניתן להפעיל אשף או דו\"ח להפעלה ." #. module: base #: sql_constraint:ir.config_parameter:0 msgid "Key must be unique." -msgstr "" +msgstr "יש לבחור מפתח ייחודי" #. module: base #: model:ir.module.module,shortdesc:base.module_plugin_outlook msgid "Outlook Plug-In" -msgstr "" +msgstr "תוסף Outlook" #. module: base #: model:ir.module.module,description:base.module_account @@ -780,6 +819,12 @@ msgid "" "Contains the installer for marketing-related modules.\n" " " msgstr "" +"\n" +"רכיב שיווק.\n" +"===================\n" +"\n" +"מכיל את ההתקנות לרכיבי שיווק.\n" +" " #. module: base #: model:ir.module.module,description:base.module_web_linkedin diff --git a/openerp/addons/base/i18n/zh_CN.po b/openerp/addons/base/i18n/zh_CN.po index 86f0be62849..88ffcb8331e 100644 --- a/openerp/addons/base/i18n/zh_CN.po +++ b/openerp/addons/base/i18n/zh_CN.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:36+0000\n" -"PO-Revision-Date: 2013-01-12 11:35+0000\n" -"Last-Translator: 盈通 ccdos \n" +"PO-Revision-Date: 2013-04-20 06:45+0000\n" +"Last-Translator: Qian Jin \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-03-08 05:23+0000\n" -"X-Generator: Launchpad (build 16523)\n" +"X-Launchpad-Export-Date: 2013-04-20 06:48+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -33,7 +33,7 @@ msgstr "" #. module: base #: view:res.partner.bank:0 msgid "e.g. GEBABEBB" -msgstr "" +msgstr "例如:GEBABEBB" #. module: base #: model:res.country,name:base.sh @@ -581,6 +581,14 @@ msgid "" "that have no counterpart in the general financial accounts.\n" " " msgstr "" +"\n" +"用于定义财务分析项目的模块。\n" +"================================================\n" +"\n" +"在OpenERP中,财务分析虽与常规财务相连,但却是\n" +"完全独立的。因此,可以使用许多不同的分析操作,\n" +"即使在常规财务会计模块中没有对应功能。\n" +" " #. module: base #: model:ir.module.module,shortdesc:base.module_idea @@ -848,7 +856,7 @@ msgstr "" "\n" "OpenERP Web LinkedIn 模块.\n" "============================\n" -"这个模块在OpenERP上提供了一体化的Linke dIn\n" +"此模块用于在OpenERP中集成LinkedIn.\n" " " #. module: base @@ -875,7 +883,7 @@ msgstr "" #. module: base #: help:ir.cron,nextcall:0 msgid "Next planned execution date for this job." -msgstr "此任务的下一次执行时间" +msgstr "该任务的下次执行日期" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -1080,7 +1088,7 @@ msgstr "模块升级" #: view:res.partner.bank:0 #: view:res.users:0 msgid "ZIP" -msgstr "" +msgstr "邮政编码" #. module: base #: selection:base.language.install,lang:0 @@ -1114,7 +1122,10 @@ msgid "" " " msgstr "" "\n" -"这模块目的是管理员工的考勤 根据执行的签入/签出的动作保存员工帐户的考勤记录。\n" +"此模块用于管理员工的考勤.\n" +"==================================================\n" +"\n" +"以员工的登入/退出时间为准,记录员工考勤.\n" " " #. module: base @@ -1235,7 +1246,7 @@ msgstr "TGZ 压缩包" #: view:res.groups:0 msgid "" "Users added to this group are automatically added in the following groups." -msgstr "若有用户添加至本组时自动将用户添加到下面的组。" +msgstr "加入本群组的用户也将自动加入以下群组." #. module: base #: code:addons/base/ir/ir_model.py:733 @@ -1788,6 +1799,20 @@ msgid "" "in their pockets, this module is essential.\n" " " msgstr "" +"\n" +"管理午餐的基本模块\n" +"================================\n" +"\n" +"许多公司为给员工提供便利,会从熟悉的餐厅为其员工预定象三明治、披萨饼或其它形式的午餐。\n" +"\n" +"然而公司内部的午餐预定需要适当的管理,尤其是当员工和餐厅数量比较多的情况下。\n" +"\n" +"我们开发的“午餐订购”模块会使这个管理工作变得简单,并给员工提供了更多的工具盒便利。 \n" +"\n" +"除了提供完备的餐食和餐厅管理,本模块还可以根据员工的喜好提供快速订餐选项和显示提示信息。 \n" +"\n" +"如果想节省员工的时间,避免他们总是要准备很多零钱,这个模块就是必须的。\n" +" " #. module: base #: view:wizard.ir.model.menu.create:0 @@ -1830,7 +1855,7 @@ msgstr "该业务伙伴或者公司的网站" msgid "" "If you check this box, your customized translations will be overwritten and " "replaced by the official ones." -msgstr "如果勾上这个勾,数据库中的翻译将被服务器上的po文件中的翻译覆盖" +msgstr "如果选定,则定制翻译会被系统翻译覆盖替换。" #. module: base #: model:ir.actions.act_window,name:base.ir_action_report_xml @@ -2811,6 +2836,9 @@ msgid "" "==================================\n" " " msgstr "" +"\n" +"美国 - 会计科目\n" +" " #. module: base #: field:ir.actions.act_url,target:0 @@ -2867,6 +2895,16 @@ msgid "" " * Files by Partner (graph)\n" " * Files Size by Month (graph)\n" msgstr "" +"\n" +"这是一个完整的文档管理系统。\n" +"================================================\n" +" * 用户身份验证\n" +" * 文档索引:在Windows平台上不支持pptx和docx格式文件。\n" +" * 文档面板包含:\n" +" * 新文件列表\n" +" * 按资源类型的文件图表\n" +" * 按合作者的文件图表\n" +" * 按月的文件大小图表\n" #. module: base #: view:ir.actions.report.xml:0 @@ -3013,6 +3051,14 @@ msgid "" "This module is currently not compatible with the ``user_ldap`` module and\n" "will disable LDAP authentication completely if installed at the same time.\n" msgstr "" +"\n" +"加密密码\n" +"===================\n" +"\n" +"LDAP身份验证的内部功能:\n" +"-------------------------------\n" +"当前该模块与``user_ldap``模块并不兼容\n" +"如果二者同时安装,会禁用LDAP身份验证。\n" #. module: base #: model:res.groups,name:base.group_hr_manager @@ -14660,7 +14706,7 @@ msgstr "源模型" #. module: base #: view:ir.sequence:0 msgid "Day of the Week (0:Monday): %(weekday)s" -msgstr "" +msgstr "一周的第几天 (0:星期一):%(weekday)s" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:84 From d621d2651689f3e67f00c020d0df23bb7a5e42d5 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Fri, 19 Apr 2013 16:54:17 +0200 Subject: [PATCH 63/65] [FIX] orm, _generate_order_by(): allow to order by LOG_ACCESS_COLUMNS even if the column is not defined again in self._columns. Raising an error instead of silently skipping the order_by bzr revid: qdp-launchpad@openerp.com-20130419145417-2tix8ynmx51qiqkf --- openerp/osv/orm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 1296472fd95..870efd3dd8b 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4792,8 +4792,8 @@ class BaseModel(object): order_field = order_split[0].strip() order_direction = order_split[1].strip() if len(order_split) == 2 else '' inner_clause = None - if order_field == 'id': - order_by_elements.append('"%s"."id" %s' % (self._table, order_direction)) + if order_field == 'id' or (self._log_access and order_field in LOG_ACCESS_COLUMNS.keys()): + order_by_elements.append('"%s"."%s" %s' % (self._table, order_field, order_direction)) elif order_field in self._columns: order_column = self._columns[order_field] if order_column._classic_read: @@ -4811,6 +4811,8 @@ class BaseModel(object): inner_clause = self._generate_m2o_order_by(order_field, query) else: continue # ignore non-readable or "non-joinable" fields + else: + raise ValueError( _("Sorting field %s not found on model %s") %( order_field, self._name)) if inner_clause: if isinstance(inner_clause, list): for clause in inner_clause: From 7fda7e1dbde513ae12896d2555c57ed9a441dc25 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Fri, 19 Apr 2013 17:49:20 +0200 Subject: [PATCH 64/65] [FIX] ir_sequence: the field company_id does not exist in res.company, and thus cannot be used as sorting criterion in search() bzr revid: qdp-launchpad@openerp.com-20130419154920-ipddx1mszl2c5az4 --- openerp/addons/base/ir/ir_sequence.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 8ba94d37006..44c9e57af32 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -217,7 +217,7 @@ class ir_sequence(openerp.osv.osv.osv): def next_by_id(self, cr, uid, sequence_id, context=None): """ Draw an interpolated string using the specified sequence.""" self.check_access_rights(cr, uid, 'read') - company_ids = self.pool.get('res.company').search(cr, uid, [], order='company_id', context=context) + [False] + company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) + [False] ids = self.search(cr, uid, ['&',('id','=', sequence_id),('company_id','in',company_ids)]) return self._next(cr, uid, ids, context) @@ -234,8 +234,8 @@ class ir_sequence(openerp.osv.osv.osv): specific company will get higher priority. """ self.check_access_rights(cr, uid, 'read') - company_ids = self.pool.get('res.company').search(cr, uid, [], order='company_id', context=context) + [False] - ids = self.search(cr, uid, ['&',('code','=', sequence_code),('company_id','in',company_ids)]) + company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) + [False] + ids = self.search(cr, uid, ['&', ('code', '=', sequence_code), ('company_id', 'in', company_ids)]) return self._next(cr, uid, ids, context) def get_id(self, cr, uid, sequence_code_or_id, code_or_id='id', context=None): From 6a2da1c2f7a6e83bb30c578e74c1f8d2759444f5 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Sun, 21 Apr 2013 05:32:37 +0000 Subject: [PATCH 65/65] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20130421053215-jdbdrur8vk4zu5tc bzr revid: launchpad_translations_on_behalf_of_openerp-20130420064852-b6bt9syb79h1x16m bzr revid: launchpad_translations_on_behalf_of_openerp-20130421053233-g4dbsfidsqrs301v bzr revid: launchpad_translations_on_behalf_of_openerp-20130421053237-8jhzy2qe55bb766x --- addons/account/i18n/tr.po | 8 +- addons/base_import/i18n/pt_BR.po | 26 +- addons/point_of_sale/i18n/pt_BR.po | 265 +- addons/point_of_sale/i18n/tr.po | 190 +- addons/report_webkit/i18n/tr.po | 44 +- addons/web/i18n/fr_CA.po | 30 +- addons/web_graph/i18n/fr_CA.po | 138 + addons/web_kanban/i18n/fr_CA.po | 161 + openerp/addons/base/i18n/fr_CA.po | 15423 +++++++++++++++++++++++++++ openerp/addons/base/i18n/zh_CN.po | 2 +- 10 files changed, 16023 insertions(+), 264 deletions(-) create mode 100644 addons/web_graph/i18n/fr_CA.po create mode 100644 addons/web_kanban/i18n/fr_CA.po create mode 100644 openerp/addons/base/i18n/fr_CA.po diff --git a/addons/account/i18n/tr.po b/addons/account/i18n/tr.po index bc886a80df7..29c22bdb47c 100644 --- a/addons/account/i18n/tr.po +++ b/addons/account/i18n/tr.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-04-18 19:19+0000\n" +"PO-Revision-Date: 2013-04-21 01:20+0000\n" "Last-Translator: Ayhan KIZILTAN \n" "Language-Team: OpenERP Türkiye Yerelleştirmesi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-04-19 06:17+0000\n" +"X-Launchpad-Export-Date: 2013-04-21 05:32+0000\n" "X-Generator: Launchpad (build 16567)\n" "Language: tr\n" @@ -4048,7 +4048,7 @@ msgstr "Vergi Tablosu" #. module: account #: view:account.journal:0 msgid "Search Account Journal" -msgstr "Günlük Hesabı Ara" +msgstr "Hesap Günlüğü Ara" #. module: account #: model:ir.actions.act_window,name:account.action_invoice_tree_pending_invoice @@ -7243,7 +7243,7 @@ msgstr "Kullanıcı Hatası!" #. module: account #: view:account.open.closed.fiscalyear:0 msgid "Discard" -msgstr "Gözardı et" +msgstr "Vazgeç" #. module: account #: selection:account.account,type:0 diff --git a/addons/base_import/i18n/pt_BR.po b/addons/base_import/i18n/pt_BR.po index f032b98c302..f33d7028fbf 100644 --- a/addons/base_import/i18n/pt_BR.po +++ b/addons/base_import/i18n/pt_BR.po @@ -8,15 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-03-31 23:10+0000\n" -"Last-Translator: Fábio Martinelli - http://zupy.com.br " -"\n" +"PO-Revision-Date: 2013-04-20 04:26+0000\n" +"Last-Translator: Thiago Tognoli \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-04-01 05:31+0000\n" -"X-Generator: Launchpad (build 16546)\n" +"X-Launchpad-Export-Date: 2013-04-21 05:32+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: base_import #. openerp-web @@ -210,6 +209,13 @@ msgid "" "\n" " See the following question." msgstr "" +"Observe que caso seu Arquivo CSV\n" +" tenha tabulações como separadores, o OpenERP não " +"irá\n" +" detectar as separações. Você irá precisar trocar o\n" +" a opção de formato de arquivo em seu programa de " +"planilha eletrônica. \n" +" Confira essa questão." #. module: base_import #. openerp-web @@ -465,6 +471,8 @@ msgid "" "file to import. If you need a sample importable file, you\n" " can use the export tool to generate one." msgstr "" +"arquivo para importar. Se você precisa de um arquivo modelo, você\n" +" pode usar a ferramenta de exportação para gerar um." #. module: base_import #. openerp-web @@ -681,6 +689,8 @@ msgid "" "The first row of the\n" " file contains the label of the column" msgstr "" +"A primeira linha do\n" +" arquivo contém os títulos das colunas" #. module: base_import #: model:ir.model,name:base_import.model_base_import_tests_models_char_states @@ -1008,7 +1018,7 @@ msgstr "" #: code:addons/base_import/static/src/js/import.js:176 #, python-format msgid "Space" -msgstr "" +msgstr "Espaço" #. module: base_import #. openerp-web @@ -1110,7 +1120,7 @@ msgstr "" #: code:addons/base_import/static/src/js/import.js:184 #, python-format msgid "Comma" -msgstr "" +msgstr "Vírgula" #. module: base_import #: model:ir.model,name:base_import.model_base_import_tests_models_m2o_related @@ -1236,4 +1246,4 @@ msgstr "" #. module: base_import #: field:base_import.import,file:0 msgid "File" -msgstr "" +msgstr "Arquivo" diff --git a/addons/point_of_sale/i18n/pt_BR.po b/addons/point_of_sale/i18n/pt_BR.po index 47f1889ce8b..e64faffb898 100644 --- a/addons/point_of_sale/i18n/pt_BR.po +++ b/addons/point_of_sale/i18n/pt_BR.po @@ -8,20 +8,19 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-02-02 22:33+0000\n" -"Last-Translator: Fábio Martinelli - http://zupy.com.br " -"\n" +"PO-Revision-Date: 2013-04-20 22:44+0000\n" +"Last-Translator: Thiago Tognoli \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-03-28 05:52+0000\n" -"X-Generator: Launchpad (build 16546)\n" +"X-Launchpad-Export-Date: 2013-04-21 05:32+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: point_of_sale #: field:report.transaction.pos,product_nb:0 msgid "Product Nb." -msgstr "Produto No." +msgstr "Núm. Produto" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.action_trans_pos_tree_today @@ -116,7 +115,7 @@ msgstr "Detalhes das Vendas" #. module: point_of_sale #: constraint:pos.config:0 msgid "You cannot have two cash controls in one Point Of Sale !" -msgstr "Você não pode ter dois controles de caixa em um ponto de venda!" +msgstr "Você não pode ter dois controles de caixa em um Ponto de Venda!" #. module: point_of_sale #: field:pos.payment.report.user,user_id:0 @@ -158,9 +157,7 @@ msgid "" "touchscreen interface." msgstr "" "Você deve controlar o valor na caixa registradora, antes\n" -" " -" de iniciar as vendas através da " -"interface de toque." +" de iniciar as vendas através da interface de toque." #. module: point_of_sale #: report:account.statement:0 @@ -230,7 +227,7 @@ msgstr "Pesando" #. module: point_of_sale #: model:product.template,name:point_of_sale.fenouil_fenouil_product_template msgid "Fennel" -msgstr "erva-doce" +msgstr "Erva Doce" #. module: point_of_sale #. openerp-web @@ -279,7 +276,7 @@ msgstr "Informação Contábil" #: code:addons/point_of_sale/static/src/xml/pos.xml:427 #, python-format msgid "0.00€" -msgstr "" +msgstr "0.00" #. module: point_of_sale #: field:pos.session.opening,show_config:0 @@ -289,13 +286,13 @@ msgstr "Mostrar Configuração" #. module: point_of_sale #: report:pos.lines:0 msgid "Disc. (%)" -msgstr "Desconto (%)" +msgstr "Desc. (%)" #. module: point_of_sale #: report:pos.details:0 #: report:pos.details_summary:0 msgid "Total discount" -msgstr "Total de Desconto" +msgstr "Desconto total" #. module: point_of_sale #. openerp-web @@ -363,6 +360,9 @@ msgid "" "Check this if this point of sale should open by default in a self checkout " "mode. If unchecked, OpenERP uses the normal cashier mode by default." msgstr "" +"Marque esta opção se este ponto de venda deve ser aberto por padrão em modo " +"de auto atendimento. Se não marcada, o OpenERP irá usar o modo normal por " +"padrão." #. module: point_of_sale #: model:ir.actions.report.xml,name:point_of_sale.pos_sales_user @@ -406,7 +406,7 @@ msgstr "Abrir Caixa Registradora" #. module: point_of_sale #: view:pos.session.opening:0 msgid "Select your Point of Sale" -msgstr "Escolha seu Ponto de Vendas" +msgstr "Escolha seu Ponto de Venda" #. module: point_of_sale #: field:report.sales.by.margin.pos,total:0 @@ -442,18 +442,18 @@ msgstr "Para Pesar" #: code:addons/point_of_sale/static/src/xml/pos.xml:476 #, python-format msgid "Hardware Events" -msgstr "Eventos do Hardware" +msgstr "Eventos do Equipamento" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:301 #, python-format msgid "You should assign a Point of Sale to your session." -msgstr "Você precisa associar um Ponto de Vendas a sua sessão." +msgstr "Você precisa associar um Ponto de Venda a sua sessão." #. module: point_of_sale #: view:pos.order.line:0 msgid "Total qty" -msgstr "Total de Qtd" +msgstr "Qtd Total" #. module: point_of_sale #: model:product.template,name:point_of_sale.fanta_orange_33cl_product_template @@ -469,6 +469,10 @@ msgid "" "close this session, you can update the 'Closing Cash Control' to avoid any " "difference." msgstr "" +"Por favor, defina suas contas de lucros e perdas no seu método de pagamento " +"'%s'. Isso permitirá o OpenERP colocar a diferença de %.2f em seu saldo " +"final. Para fechar a sessão, você pode atualizar o 'Fechando Controle de " +"Caixa'para evitar qualquer diferença." #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:315 @@ -492,7 +496,7 @@ msgstr "" #. module: point_of_sale #: view:pos.session.opening:0 msgid ") is \"" -msgstr ") é \"" +msgstr ") está \"" #. module: point_of_sale #: model:product.template,name:point_of_sale.Onions_product_template @@ -516,12 +520,12 @@ msgstr "Em Andamento" #: view:pos.session:0 #: field:pos.session,opening_details_ids:0 msgid "Opening Cash Control" -msgstr "Controle de Abertura de Caixa" +msgstr "Abrindo Controle de Caixa" #. module: point_of_sale #: help:res.users,ean13:0 msgid "BarCode" -msgstr "Código de barras" +msgstr "Código de Barras" #. module: point_of_sale #: help:pos.category,image_medium:0 @@ -786,7 +790,7 @@ msgstr "Imprimir Relatório" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_bolognese_product_template msgid "Dr. Oetker Ristorante Bolognese" -msgstr "" +msgstr "Dr. Oetker Ristorante Bolognese" #. module: point_of_sale #: model:pos.category,name:point_of_sale.pizza @@ -796,7 +800,7 @@ msgstr "Pizza" #. module: point_of_sale #: view:pos.session:0 msgid "= Theoretical Balance" -msgstr "" +msgstr "= Balanço Teórico" #. module: point_of_sale #: code:addons/point_of_sale/wizard/pos_return.py:85 @@ -928,7 +932,7 @@ msgstr "Data de término" #. module: point_of_sale #: model:product.template,name:point_of_sale.pomme_jonagold_product_template msgid "Jonagold apples" -msgstr "" +msgstr "Jonagold apples" #. module: point_of_sale #: view:account.bank.statement:0 @@ -937,7 +941,7 @@ msgstr "" #: model:ir.model,name:point_of_sale.model_account_journal #: field:report.pos.order,journal_id:0 msgid "Journal" -msgstr "Registro" +msgstr "Diário" #. module: point_of_sale #: view:pos.session:0 @@ -947,7 +951,7 @@ msgstr "Demonstrativos" #. module: point_of_sale #: report:pos.details:0 msgid "Sales total(Revenue)" -msgstr "Vendas Totais" +msgstr "Total de vendas (Receita)" #. module: point_of_sale #: help:pos.config,group_by:0 @@ -983,7 +987,7 @@ msgstr "Lista de Caixas Registradoras" #. module: point_of_sale #: model:product.template,name:point_of_sale.maes_50cl_product_template msgid "Maes 50cl" -msgstr "" +msgstr "Maes 50cl" #. module: point_of_sale #: view:report.pos.order:0 @@ -1045,7 +1049,7 @@ msgstr "Spa Reine 33cl" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_discount msgid "Add a Global Discount" -msgstr "Adicionar Desconto Global" +msgstr "Adicionar um Desconto Global" #. module: point_of_sale #: view:pos.config:0 @@ -1055,7 +1059,7 @@ msgstr "Diários" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_prosciutto_product_template msgid "Dr. Oetker Ristorante Prosciutto" -msgstr "" +msgstr "Dr. Oetker Ristorante Prosciutto" #. module: point_of_sale #: model:product.template,name:point_of_sale.lays_light_paprika_170g_product_template @@ -1141,7 +1145,7 @@ msgstr "Re-impressão" #. module: point_of_sale #: model:product.template,name:point_of_sale.chimay_bleu_75cl_product_template msgid "Chimay Bleu 75cl" -msgstr "" +msgstr "Chimay Bleu 75cl" #. module: point_of_sale #: report:pos.payment.report.user:0 @@ -1171,7 +1175,7 @@ msgstr "No. de Linhas" #: code:addons/point_of_sale/static/src/xml/pos.xml:89 #, python-format msgid "Disc" -msgstr "Disco" +msgstr "Desc." #. module: point_of_sale #: view:pos.order:0 @@ -1181,7 +1185,7 @@ msgstr "(atualizar)" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_vanille_2,5l_product_template msgid "IJsboerke Vanilla 2.5L" -msgstr "" +msgstr "IJsboerke Vanilla 2.5L" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.action_report_pos_details @@ -1192,7 +1196,7 @@ msgstr "Detalhes da Venda" #. module: point_of_sale #: model:product.template,name:point_of_sale.evian_2l_product_template msgid "2L Evian" -msgstr "" +msgstr "2L Evian" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:373 @@ -1200,7 +1204,7 @@ msgstr "" #: code:addons/point_of_sale/wizard/pos_session_opening.py:34 #, python-format msgid "Start Point Of Sale" -msgstr "" +msgstr "Iniciar Ponto de Venda" #. module: point_of_sale #: model:pos.category,name:point_of_sale.pils @@ -1210,7 +1214,7 @@ msgstr "" #. module: point_of_sale #: help:pos.session,cash_register_balance_end_real:0 msgid "Computed using the cash control lines" -msgstr "" +msgstr "Calculado usando as linhas de controle de caixa" #. module: point_of_sale #: report:all.closed.cashbox.of.the.day:0 @@ -1232,7 +1236,7 @@ msgstr "ABC" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_dame_blanche_2,5l_product_template msgid "IJsboerke 2.5L White Lady" -msgstr "" +msgstr "IJsboerke 2.5L White Lady" #. module: point_of_sale #: field:pos.order,lines:0 @@ -1247,14 +1251,14 @@ msgstr "Total da Transação" #. module: point_of_sale #: model:product.template,name:point_of_sale.chaudfontaine_petillante_50cl_product_template msgid "Chaudfontaine Petillante 50cl" -msgstr "" +msgstr "Chaudfontaine Petillante 50cl" #. module: point_of_sale #. openerp-web #: code:addons/point_of_sale/static/src/xml/pos.xml:485 #, python-format msgid "Read Weighting Scale" -msgstr "" +msgstr "Lendo a Balança" #. module: point_of_sale #. openerp-web @@ -1317,7 +1321,7 @@ msgstr "Marcar como Obsoleto" #. module: point_of_sale #: model:product.template,name:point_of_sale.limon_product_template msgid "Stringers" -msgstr "" +msgstr "Limões" #. module: point_of_sale #: field:pos.order,pricelist_id:0 @@ -1384,19 +1388,19 @@ msgstr "Stella Artois 33cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.lays_naturel_300g_product_template msgid "Lays Natural XXL 300g" -msgstr "" +msgstr "Lays Natural XXL 300g" #. module: point_of_sale #. openerp-web #: code:addons/point_of_sale/static/src/xml/pos.xml:479 #, python-format msgid "Scan Item Unrecognized" -msgstr "" +msgstr "item Escaneado não Reconhecido" #. module: point_of_sale #: report:all.closed.cashbox.of.the.day:0 msgid "Today's Closed Cashbox" -msgstr "Fechamento de Caixa do dia" +msgstr "Fechamento de Caixa do Dia" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:897 @@ -1412,7 +1416,7 @@ msgstr "Fatura Provisória" #. module: point_of_sale #: model:product.template,name:point_of_sale.lays_paprika_oven_150g_product_template msgid "Oven Baked Lays Paprika 150g" -msgstr "" +msgstr "Oven Baked Lays Paprika 150g" #. module: point_of_sale #: report:pos.invoice:0 @@ -1464,7 +1468,7 @@ msgstr "Coca-Cola Light 2L" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_funghi_product_template msgid "Dr. Oetker Ristorante Funghi" -msgstr "" +msgstr "Dr. Oetker Ristorante Funghi" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.pos_category_action @@ -1492,7 +1496,7 @@ msgstr "Ean Inválido" #. module: point_of_sale #: model:product.template,name:point_of_sale.lindemans_kriek_37,5cl_product_template msgid "Lindemans Kriek 37.5cl" -msgstr "" +msgstr "Lindemans Kriek 37.5cl" #. module: point_of_sale #: view:pos.config:0 @@ -1509,7 +1513,7 @@ msgstr "Coca-Cola Zero 33cl" #: code:addons/point_of_sale/static/src/xml/pos.xml:405 #, python-format msgid "ä" -msgstr "" +msgstr "ä" #. module: point_of_sale #: report:pos.invoice:0 @@ -1538,7 +1542,7 @@ msgstr "Desconhecido" #. module: point_of_sale #: field:product.product,income_pdt:0 msgid "Point of Sale Cash In" -msgstr "" +msgstr "Colocar dinheiro no Ponto de Venda" #. module: point_of_sale #. openerp-web @@ -1623,7 +1627,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.boon_framboise_37,5cl_product_template msgid "Boon Framboise 37.5cl" -msgstr "" +msgstr "Boon Framboise 37.5cl" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_config @@ -1642,7 +1646,7 @@ msgstr "" #. module: point_of_sale #: field:product.product,expense_pdt:0 msgid "Point of Sale Cash Out" -msgstr "" +msgstr "Sacar do Ponto de Venda" #. module: point_of_sale #: selection:report.pos.order,month:0 @@ -1654,7 +1658,7 @@ msgstr "Novembro" #: code:addons/point_of_sale/static/src/xml/pos.xml:267 #, python-format msgid "Please scan an item or your member card" -msgstr "" +msgstr "Por favor escaneie um item ou seu cartão de associado" #. module: point_of_sale #: model:product.template,name:point_of_sale.poivron_verts_product_template @@ -1664,7 +1668,7 @@ msgstr "Pimentões Verdes" #. module: point_of_sale #: model:product.template,name:point_of_sale.timmermans_faro_37,5cl_product_template msgid "Timmermans Faro 37.5cl" -msgstr "" +msgstr "Timmermans Faro 37.5cl" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:410 @@ -1677,7 +1681,7 @@ msgstr "" #. module: point_of_sale #: view:pos.session:0 msgid "Validate Closing & Post Entries" -msgstr "" +msgstr "Validar Encerramento e Lançar Entradas" #. module: point_of_sale #: field:report.transaction.pos,no_trans:0 @@ -1720,7 +1724,7 @@ msgstr "Cancelar" #: code:addons/point_of_sale/static/src/xml/pos.xml:296 #, python-format msgid "Please put your product on the scale" -msgstr "" +msgstr "Por favor, coloque seu produto na balança" #. module: point_of_sale #: model:ir.actions.report.xml,name:point_of_sale.pos_details_summary @@ -1730,12 +1734,12 @@ msgstr "Vendas(Resumo)" #. module: point_of_sale #: model:product.template,name:point_of_sale.nectarine_product_template msgid "Peach" -msgstr "" +msgstr "Pêssego" #. module: point_of_sale #: model:product.template,name:point_of_sale.timmermans_kriek_37,5cl_product_template msgid "Timmermans Kriek 37.5cl" -msgstr "" +msgstr "Timmermans Kriek 37.5cl" #. module: point_of_sale #: field:pos.config,sequence_id:0 @@ -1768,7 +1772,7 @@ msgstr "fechar" #. module: point_of_sale #: model:ir.actions.report.xml,name:point_of_sale.report_user_label msgid "User Labels" -msgstr "" +msgstr "Etiquetas do Usuário" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_order_line @@ -1843,7 +1847,7 @@ msgstr "Ponto de Venda" #: code:addons/point_of_sale/static/src/xml/pos.xml:587 #, python-format msgid "Subtotal:" -msgstr "" +msgstr "Subtotal:" #. module: point_of_sale #: model:product.template,name:point_of_sale.coca_regular_33cl_product_template @@ -1891,7 +1895,7 @@ msgstr "Nome" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_gazeuse_33cl_product_template msgid "Spa Barisart 33cl" -msgstr "" +msgstr "Spa Barisart 33cl" #. module: point_of_sale #: view:pos.confirm:0 @@ -1919,6 +1923,9 @@ msgid "" "complete\n" " your purchase" msgstr "" +"Por favor, insira seu cartão no leitor e aguarde as instruções para " +"completar\n" +" sua compra" #. module: point_of_sale #: help:product.product,income_pdt:0 @@ -1930,7 +1937,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_moka_2,5l_product_template msgid "IJsboerke Mocha 2.5L" -msgstr "" +msgstr "IJsboerke Mocha 2.5L" #. module: point_of_sale #: field:pos.session,cash_control:0 @@ -1957,6 +1964,8 @@ msgid "" "Unable to open the session. You have to assign a sale journal to your point " "of sale." msgstr "" +"Não é possível abrir a sessão. Você tem que atribuir um diário de venda para " +"o seu ponto de venda." #. module: point_of_sale #: view:report.pos.order:0 @@ -2010,7 +2019,7 @@ msgstr "Estabelecimento:" #. module: point_of_sale #: field:account.journal,self_checkout_payment_method:0 msgid "Self Checkout Payment Method" -msgstr "" +msgstr "Forma de Pagamento do Auto Atendimento" #. module: point_of_sale #: view:pos.order:0 @@ -2056,7 +2065,7 @@ msgstr "caps lock" #. module: point_of_sale #: model:product.template,name:point_of_sale.grisette_cerise_25cl_product_template msgid "Grisette Cherry 25cl" -msgstr "" +msgstr "Grisette Cherry 25cl" #. module: point_of_sale #: report:pos.invoice:0 @@ -2146,12 +2155,12 @@ msgstr "Produtos" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_4formaggi_product_template msgid "Dr. Oetker Ristorante Quattro Formaggi" -msgstr "" +msgstr "Dr. Oetker Ristorante Quattro Formaggi" #. module: point_of_sale #: model:product.template,name:point_of_sale.croky_naturel_45g_product_template msgid "Croky Natural 45g" -msgstr "" +msgstr "Croky Natural 45g" #. module: point_of_sale #: model:product.template,name:point_of_sale.tomate_en_grappe_product_template @@ -2161,7 +2170,7 @@ msgstr "Tomates em Conjunto" #. module: point_of_sale #: model:ir.actions.client,name:point_of_sale.action_pos_pos msgid "Start Point of Sale" -msgstr "Iniciar Ponto de Vendas" +msgstr "Iniciar Ponto de Venda" #. module: point_of_sale #. openerp-web @@ -2195,7 +2204,7 @@ msgstr "Pedidos do Ponto de Vendas" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_et_fruit_50cl_product_template msgid "Spa Fruit and Orange 50cl" -msgstr "" +msgstr "Spa Fruit and Orange 50cl" #. module: point_of_sale #: view:pos.config:0 @@ -2391,7 +2400,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.jupiler_50cl_product_template msgid "Jupiler 50cl" -msgstr "" +msgstr "Jupiler 50cl" #. module: point_of_sale #: report:pos.details:0 @@ -2424,7 +2433,7 @@ msgstr "Sincronizada" #. module: point_of_sale #: model:product.template,name:point_of_sale.chimay_rouge_33cl_product_template msgid "Chimay Red 33cl" -msgstr "" +msgstr "Chimay Red 33cl" #. module: point_of_sale #: view:report.pos.order:0 @@ -2440,7 +2449,7 @@ msgstr "Imagem de tamanho Médio" #. module: point_of_sale #: model:product.template,name:point_of_sale.papillon_orange_product_template msgid "Orange Butterfly" -msgstr "" +msgstr "Laranja Butterfly" #. module: point_of_sale #: view:report.pos.order:0 @@ -2612,7 +2621,7 @@ msgstr "Linhas do demonstrativo" #. module: point_of_sale #: model:product.template,name:point_of_sale.croky_paprika_45g_product_template msgid "Croky Paprika 45g" -msgstr "" +msgstr "Croky Paprika 45g" #. module: point_of_sale #: view:pos.order:0 @@ -2676,12 +2685,12 @@ msgstr "Fatura" #: code:addons/point_of_sale/static/src/xml/pos.xml:701 #, python-format msgid "shift" -msgstr "" +msgstr "shift" #. module: point_of_sale #: model:product.template,name:point_of_sale.rochefort_8_33cl_product_template msgid "Rochefort \"8\" 33cl" -msgstr "" +msgstr "Rochefort \"8\" 33cl" #. module: point_of_sale #: view:account.bank.statement:0 @@ -2711,7 +2720,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.timmermans_geuze_37,5cl_product_template msgid "Timmermans Geuze 37.5cl" -msgstr "" +msgstr "Timmermans Geuze 37.5cl" #. module: point_of_sale #: view:pos.session:0 @@ -2734,7 +2743,7 @@ msgstr "Responsável" #. module: point_of_sale #: model:product.template,name:point_of_sale.croky_bolognaise_250g_product_template msgid "Croky Bolognese 250g" -msgstr "" +msgstr "Croky Bolognese 250g" #. module: point_of_sale #. openerp-web @@ -2748,7 +2757,7 @@ msgstr "Ean13 Personalizado" #: code:addons/point_of_sale/static/src/xml/pos.xml:465 #, python-format msgid "1.54€ Lemon" -msgstr "" +msgstr "1.54R$ Limão" #. module: point_of_sale #: field:pos.make.payment,payment_name:0 @@ -2782,12 +2791,12 @@ msgstr "Vendas por Margem de Usuário" #: report:pos.invoice:0 #, python-format msgid "Taxes:" -msgstr "Taxas:" +msgstr "Impostos:" #. module: point_of_sale #: model:product.template,name:point_of_sale.pepsi_max_33cl_product_template msgid "Pepsi Max 33cl" -msgstr "" +msgstr "Pepsi Max 33cl" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_report_pos_order @@ -2808,7 +2817,7 @@ msgstr "Produto" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_pollo_product_template msgid "Dr. Oetker Ristorante Pollo" -msgstr "" +msgstr "Dr. Oetker Ristorante Pollo" #. module: point_of_sale #: constraint:pos.session:0 @@ -2853,12 +2862,12 @@ msgstr "Sessão" #. module: point_of_sale #: model:product.template,name:point_of_sale.chaudfontaine_33cl_product_template msgid "Chaudfontaine 33cl" -msgstr "" +msgstr "Chaudfontaine 33cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_margherita_product_template msgid "Dr. Oetker La Margherita" -msgstr "" +msgstr "Dr. Oetker La Margherita" #. module: point_of_sale #: view:pos.order:0 @@ -2958,7 +2967,7 @@ msgstr "Gerente" #. module: point_of_sale #: model:product.template,name:point_of_sale.lays_poivre_sel_oven_150g_product_template msgid "Lays Salt and Pepper Oven Baked 150g" -msgstr "" +msgstr "Lays Salt and Pepper Oven Baked 150g" #. module: point_of_sale #: field:pos.details,date_start:0 @@ -3015,7 +3024,7 @@ msgstr "Procurar Pedido de Venda" #. module: point_of_sale #: field:pos.config,iface_self_checkout:0 msgid "Self Checkout Mode" -msgstr "" +msgstr "Modo de Auto Atendimento" #. module: point_of_sale #: field:account.journal,journal_user:0 @@ -3049,7 +3058,7 @@ msgstr "Relatório de Pagamento" #. module: point_of_sale #: model:product.template,name:point_of_sale.fanta_orange_25cl_product_template msgid "Fanta Orange 25cl" -msgstr "" +msgstr "Fanta Laranja 25cl" #. module: point_of_sale #: view:pos.confirm:0 @@ -3085,7 +3094,7 @@ msgstr "Motivo" #. module: point_of_sale #: model:product.template,name:point_of_sale.orangina_33cl_product_template msgid "Orangina 33cl" -msgstr "" +msgstr "Orangina 33cl" #. module: point_of_sale #: view:pos.config:0 @@ -3095,7 +3104,7 @@ msgstr "Definir como Inativo" #. module: point_of_sale #: model:product.template,name:point_of_sale.chimay_bleu_33cl_product_template msgid "Chimay Bleu 33cl" -msgstr "" +msgstr "Chimay Bleu 33cl" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.action_account_journal_form @@ -3111,7 +3120,7 @@ msgstr "Fritas" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_spinaci_product_template msgid "Dr. Oetker Ristorante Spinaci" -msgstr "" +msgstr "Dr. Oetker Ristorante Spinaci" #. module: point_of_sale #. openerp-web @@ -3143,7 +3152,7 @@ msgstr "Colocar dinheiro em" #. module: point_of_sale #: model:product.template,name:point_of_sale.fanta_zero_orange_1,5l_product_template msgid "Fanta Orange Zero 1.5L" -msgstr "" +msgstr "Fanta Laranja Zero 1.5L" #. module: point_of_sale #: model:product.template,name:point_of_sale.boni_orange_product_template @@ -3200,7 +3209,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.orangina_1,5l_product_template msgid "Orangina 1.5L" -msgstr "" +msgstr "Orangina 1.5L" #. module: point_of_sale #: view:report.pos.order:0 @@ -3234,17 +3243,17 @@ msgstr "Linha do Demonstrativo Bancário" #. module: point_of_sale #: model:product.template,name:point_of_sale.belle_vue_kriek_25cl_product_template msgid "Belle-Vue Kriek 25cl" -msgstr "" +msgstr "Belle-Vue Kriek 25cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.chaudfontaine_petillante_1,5l_product_template msgid "Chaudfontaine Petillante 1.5l" -msgstr "" +msgstr "Chaudfontaine Petillante 1.5l" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_stracciatella_2,5l_product_template msgid "IJsboerke Stracciatella 2.5L" -msgstr "" +msgstr "IJsboerke Stracciatella 2.5L" #. module: point_of_sale #: view:report.sales.by.user.pos:0 @@ -3256,7 +3265,7 @@ msgstr "Relatório do PDV" #. module: point_of_sale #: model:product.template,name:point_of_sale.chaudfontaine_1,5l_product_template msgid "Chaudfontaine 1.5l" -msgstr "" +msgstr "Chaudfontaine 1.5l" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:1069 @@ -3326,7 +3335,7 @@ msgstr "Coca-Cola Zero 50cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_tonno_product_template msgid "Dr. Oetker Ristorante Tonno" -msgstr "" +msgstr "Dr. Oetker Ristorante Tonno" #. module: point_of_sale #: report:pos.invoice:0 @@ -3368,7 +3377,7 @@ msgstr "cash.box.out" #. module: point_of_sale #: model:product.template,name:point_of_sale.fanta_zero_orange_33cl_product_template msgid "Fanta Zero Orange 33cl" -msgstr "" +msgstr "Fanta Laranja Zero 33cl" #. module: point_of_sale #: help:product.product,available_in_pos:0 @@ -3383,7 +3392,7 @@ msgstr "Dia da data do pedido" #. module: point_of_sale #: model:product.template,name:point_of_sale.maes_33cl_product_template msgid "Maes 33cl" -msgstr "" +msgstr "Maes 33cl" #. module: point_of_sale #. openerp-web @@ -3400,7 +3409,7 @@ msgstr "Configuração" #. module: point_of_sale #: model:product.template,name:point_of_sale.orval_33cl_product_template msgid "Orval 33cl" -msgstr "" +msgstr "Orval 33cl" #. module: point_of_sale #. openerp-web @@ -3433,7 +3442,7 @@ msgstr "Frutas Frescas" #. module: point_of_sale #: model:product.template,name:point_of_sale.lindemans_pecheresse_37,,5cl_product_template msgid "Lindemans sinful 37.5cl" -msgstr "" +msgstr "Lindemans sinful 37.5cl" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.action_pos_invoice @@ -3453,7 +3462,7 @@ msgstr "Imagem" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_gazeuse_1,5l_product_template msgid "Spa Barisart 1.5l" -msgstr "" +msgstr "Spa Barisart 1.5l" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:789 @@ -3465,7 +3474,7 @@ msgstr "Retornar Produtos" #. module: point_of_sale #: model:product.template,name:point_of_sale.jupiler_33cl_product_template msgid "Jupiler 33cl" -msgstr "" +msgstr "Jupiler 33cl" #. module: point_of_sale #. openerp-web @@ -3573,7 +3582,7 @@ msgstr "Balança Eletrônica" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_gazeuse_50cl_product_template msgid "Spa Barisart 50cl" -msgstr "" +msgstr "Spa Barisart 50cl" #. module: point_of_sale #: field:res.users,pos_config:0 @@ -3617,7 +3626,7 @@ msgstr "Pago" #: code:addons/point_of_sale/static/src/xml/pos.xml:464 #, python-format msgid "3.141Kg Oranges" -msgstr "" +msgstr "3.141Kg de Laranjas" #. module: point_of_sale #: report:pos.invoice:0 @@ -3633,7 +3642,7 @@ msgstr "Por favor informe um parceiro para a venda" #. module: point_of_sale #: model:pos.category,name:point_of_sale.fruity_beers msgid "Fruity Beers" -msgstr "" +msgstr "Cerveja de Frutas" #. module: point_of_sale #: view:pos.session:0 @@ -3645,7 +3654,7 @@ msgstr "" #: code:addons/point_of_sale/static/src/xml/pos.xml:463 #, python-format msgid "Soda 33cl" -msgstr "" +msgstr "Soda 33cl" #. module: point_of_sale #: help:pos.session,cash_register_balance_start:0 @@ -3666,7 +3675,7 @@ msgstr "Vendas do Usuário" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_hawaii_product_template msgid "Dr. Oetker Ristorante Hawaii" -msgstr "" +msgstr "Dr. Oetker Ristorante Hawaii" #. module: point_of_sale #. openerp-web @@ -3700,12 +3709,12 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.chaudfontaine_petillante_33cl_product_template msgid "Chaudfontaine Petillante 33cl" -msgstr "" +msgstr "Chaudfontaine Petillante 33cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.pepsi_max_2l_product_template msgid "Pepsi Max 2L" -msgstr "" +msgstr "Pepsi Max 2L" #. module: point_of_sale #: field:pos.session,details_ids:0 @@ -3715,17 +3724,17 @@ msgstr "Controle de Caixa" #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_vegetale_product_template msgid "Dr. Oetker Ristorante Vegetable" -msgstr "" +msgstr "Dr. Oetker Ristorante Vegetable" #. module: point_of_sale #: model:pos.category,name:point_of_sale.soda msgid "Soda" -msgstr "" +msgstr "Soda" #. module: point_of_sale #: model:product.template,name:point_of_sale.lays_paprika_300g_product_template msgid "Lays Paprika XXL 300g" -msgstr "" +msgstr "Lays Paprika XXL 300g" #. module: point_of_sale #: report:pos.invoice:0 @@ -3737,7 +3746,7 @@ msgstr "Reembolso" #: code:addons/point_of_sale/static/src/xml/pos.xml:417 #, python-format msgid "Your shopping cart is empty" -msgstr "" +msgstr "Seu Carrinho de Compras está vazio" #. module: point_of_sale #: code:addons/point_of_sale/report/pos_invoice.py:46 @@ -3748,7 +3757,7 @@ msgstr "Por favor crie uma fatura para esta venda." #. module: point_of_sale #: model:product.template,name:point_of_sale.oetker_mozzarella_product_template msgid "Dr. Oetker Ristorante Mozzarella" -msgstr "" +msgstr "Dr. Oetker Ristorante Mozzarella" #. module: point_of_sale #: report:pos.details:0 @@ -3759,7 +3768,7 @@ msgstr "Desc(%)" #. module: point_of_sale #: view:pos.session.opening:0 msgid "The session" -msgstr "" +msgstr "A sessão" #. module: point_of_sale #: view:pos.order:0 @@ -3784,12 +3793,12 @@ msgstr "Ordem de Linhas" #. module: point_of_sale #: view:pos.session.opening:0 msgid "PoS Session Opening" -msgstr "" +msgstr "Abrindo Sessão do PDV" #. module: point_of_sale #: field:pos.order.line,price_subtotal:0 msgid "Subtotal w/o Tax" -msgstr "" +msgstr "Subtotal Sem Impostos" #. module: point_of_sale #. openerp-web @@ -3802,7 +3811,7 @@ msgstr "excluir" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_50cl_product_template msgid "Spa Reine 50cl" -msgstr "" +msgstr "Spa Reine 50cl" #. module: point_of_sale #: model:product.template,name:point_of_sale.chicon_flandria_extra_product_template @@ -3813,22 +3822,22 @@ msgstr "" #: model:product.template,name:point_of_sale.lays_light_naturel_170g_product_template #: model:product.template,name:point_of_sale.lays_naturel_170g_product_template msgid "Lays Natural Light 170g" -msgstr "" +msgstr "Lays Natural Light 170g" #. module: point_of_sale #: model:product.template,name:point_of_sale.leffe_blonde_33cl_product_template msgid "Leffe Blonde 33cl" -msgstr "" +msgstr "Leffe Blonde 33cl" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.action_report_pos_payment msgid "Pyament Report" -msgstr "" +msgstr "Relatório de Pagamento" #. module: point_of_sale #: field:report.transaction.pos,jl_id:0 msgid "Cash Journals" -msgstr "" +msgstr "Diários de Dinheiro" #. module: point_of_sale #: view:pos.session:0 @@ -3838,12 +3847,12 @@ msgstr "Sessão:" #. module: point_of_sale #: field:pos.config,iface_print_via_proxy:0 msgid "Print via Proxy" -msgstr "" +msgstr "Imprimir via Proxy" #. module: point_of_sale #: report:pos.sales.user.today:0 msgid "Today's Sales By User" -msgstr "" +msgstr "Vendas de hoje por Usuário" #. module: point_of_sale #: help:account.journal,amount_authorized_diff:0 @@ -3889,7 +3898,7 @@ msgstr "Anotações Internas" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_chocolat_2,5l_product_template msgid "IJsboerke Chocolat 2.5L" -msgstr "" +msgstr "IJsboerke Chocolat 2.5L" #. module: point_of_sale #: help:pos.category,image_small:0 @@ -3902,7 +3911,7 @@ msgstr "" #. module: point_of_sale #: field:pos.session.opening,pos_state:0 msgid "Session Status" -msgstr "" +msgstr "Status da Sessão" #. module: point_of_sale #: field:pos.order,picking_id:0 @@ -3946,12 +3955,12 @@ msgstr "Editar" #. module: point_of_sale #: view:pos.session.opening:0 msgid "Click to continue the session." -msgstr "" +msgstr "Clique para continuar a sessão." #. module: point_of_sale #: view:pos.config:0 msgid "Set to Active" -msgstr "" +msgstr "Marque para Ativar" #. module: point_of_sale #: view:pos.category:0 @@ -3961,7 +3970,7 @@ msgstr "" #. module: point_of_sale #: view:pos.session.opening:0 msgid "Start Selling" -msgstr "" +msgstr "Começar a Vender" #. module: point_of_sale #: selection:report.pos.order,month:0 @@ -3994,7 +4003,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.leffe_9_33cl_product_template msgid "Leffe Brune \"9\" 33cl" -msgstr "" +msgstr "Leffe Brune \"9\" 33cl" #. module: point_of_sale #: help:account.journal,journal_user:0 @@ -4042,7 +4051,7 @@ msgstr "" #: code:addons/point_of_sale/static/src/xml/pos.xml:351 #, python-format msgid "Sorry, we could not create a session for this user." -msgstr "" +msgstr "Desculpe, não podemos criar uma sessão para esse usuário." #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:98 @@ -4050,7 +4059,7 @@ msgstr "" #: selection:pos.session.opening,pos_state:0 #, python-format msgid "Opening Control" -msgstr "" +msgstr "Abrindo Controle" #. module: point_of_sale #: view:report.pos.order:0 diff --git a/addons/point_of_sale/i18n/tr.po b/addons/point_of_sale/i18n/tr.po index 2b7b1eda953..0b2cc18b8d7 100644 --- a/addons/point_of_sale/i18n/tr.po +++ b/addons/point_of_sale/i18n/tr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-03-07 08:37+0000\n" -"PO-Revision-Date: 2013-03-27 12:20+0000\n" -"Last-Translator: Volkan Gezer \n" +"PO-Revision-Date: 2013-04-19 10:28+0000\n" +"Last-Translator: Ediz Duman \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-03-28 05:52+0000\n" -"X-Generator: Launchpad (build 16546)\n" +"X-Launchpad-Export-Date: 2013-04-20 06:48+0000\n" +"X-Generator: Launchpad (build 16567)\n" #. module: point_of_sale #: field:report.transaction.pos,product_nb:0 @@ -285,7 +285,7 @@ msgstr "Toplam indirim" #: code:addons/point_of_sale/static/src/xml/pos.xml:441 #, python-format msgid "Debug Window" -msgstr "" +msgstr "Hata Ayıklama Penceresi" #. module: point_of_sale #. openerp-web @@ -326,7 +326,7 @@ msgstr "İnd.(%)" #: code:addons/point_of_sale/point_of_sale.py:1006 #, python-format msgid "Please define income account for this product: \"%s\" (id:%d)." -msgstr "" +msgstr "Lütfen bu ürün için gelir hesabı belirtin: \"%s\" (id:%d)." #. module: point_of_sale #: view:report.pos.order:0 @@ -417,14 +417,14 @@ msgstr "Ödeme İsteği" #. module: point_of_sale #: field:product.product,to_weight:0 msgid "To Weight" -msgstr "" +msgstr "Ağırlık" #. module: point_of_sale #. openerp-web #: code:addons/point_of_sale/static/src/xml/pos.xml:476 #, python-format msgid "Hardware Events" -msgstr "" +msgstr "Donanım Etkinlikler" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:301 @@ -512,6 +512,9 @@ msgid "" "128x128px image, with aspect ratio preserved. Use this field in form views " "or some kanban views." msgstr "" +"Kategorinin orta boyutlu görüntü. Otomatik olarak korunmuş en boy oranına " +"sahip, bir 128x128px görüntü olarak yeniden boyutlandırılır. Form " +"görünümleri ya da kanban görünümlerinde bu alanı kullanın." #. module: point_of_sale #: view:pos.session.opening:0 @@ -528,7 +531,7 @@ msgstr "Günlük Operasyonlar" #: code:addons/point_of_sale/static/src/xml/pos.xml:42 #, python-format msgid "Google Chrome" -msgstr "" +msgstr "Google Chrome" #. module: point_of_sale #: model:pos.category,name:point_of_sale.sparkling_water @@ -718,12 +721,12 @@ msgstr "İşleme POS Yevmiye Girişlerini" #: code:addons/point_of_sale/static/src/xml/pos.xml:457 #, python-format msgid "Barcode Scanner" -msgstr "" +msgstr "Barkod Okuyucu" #. module: point_of_sale #: model:product.template,name:point_of_sale.pomme_granny_smith_product_template msgid "Granny Smith apples" -msgstr "" +msgstr "Granny Smith elma" #. module: point_of_sale #: help:product.product,expense_pdt:0 @@ -841,6 +844,8 @@ msgid "" "This field holds the image used as image for the cateogry, limited to " "1024x1024px." msgstr "" +"Bu alanda 1024x1024px sınırlı kategorik için resmi olarak kullanılan görüntü " +"tutar." #. module: point_of_sale #: model:product.template,name:point_of_sale.pepsi_max_50cl_product_template @@ -866,7 +871,7 @@ msgstr "" #. module: point_of_sale #: model:pos.category,name:point_of_sale.rouges_noyau_fruits msgid "Berries" -msgstr "" +msgstr "Meyveler" #. module: point_of_sale #: view:pos.ean_wizard:0 @@ -887,7 +892,7 @@ msgstr "Hata: Geçersiz barkod" #. module: point_of_sale #: model:pos.category,name:point_of_sale.legumes_racine msgid "Root vegetables" -msgstr "" +msgstr "Sebzeler" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.act_pos_open_statement @@ -905,7 +910,7 @@ msgstr "Bitiş Tarihi" #. module: point_of_sale #: model:product.template,name:point_of_sale.pomme_jonagold_product_template msgid "Jonagold apples" -msgstr "" +msgstr "Jonagold elma" #. module: point_of_sale #: view:account.bank.statement:0 @@ -932,6 +937,8 @@ msgid "" "Check this if you want to group the Journal Items by Product while closing a " "Session" msgstr "" +"Bir Oturum kapatırken Ürün tarafından Yevmiye öğeler gruplandırmak " +"istiyorsanız bu kontrol edin" #. module: point_of_sale #: report:pos.details:0 @@ -942,12 +949,12 @@ msgstr "Toplam ödeme" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_session_opening msgid "pos.session.opening" -msgstr "" +msgstr "pos.session.opening" #. module: point_of_sale #: view:res.users:0 msgid "Edit EAN" -msgstr "" +msgstr "EAN Düzenle" #. module: point_of_sale #: code:addons/point_of_sale/wizard/pos_open_statement.py:80 @@ -990,7 +997,7 @@ msgstr "Kullanıcının Ürünleri" #: code:addons/point_of_sale/point_of_sale.py:984 #, python-format msgid "The POS order must have lines when calling this method" -msgstr "" +msgstr "Bu yöntemi çağırırken POS sipariş hatları olmalıdır" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:1143 @@ -1055,7 +1062,7 @@ msgstr "dönen" #. module: point_of_sale #: view:product.product:0 msgid "Set a Custom EAN" -msgstr "" +msgstr "EAN Özel Ayarlama" #. module: point_of_sale #. openerp-web @@ -1067,12 +1074,12 @@ msgstr "Kalan:" #. module: point_of_sale #: model:pos.category,name:point_of_sale.legumes msgid "Fresh vegetables" -msgstr "" +msgstr "Taze sebzeler" #. module: point_of_sale #: view:pos.session:0 msgid "tab of the" -msgstr "" +msgstr "sekmesinde" #. module: point_of_sale #. openerp-web @@ -1096,7 +1103,7 @@ msgstr "" #. module: point_of_sale #: sql_constraint:pos.session:0 msgid "The name of this POS Session must be unique !" -msgstr "" +msgstr "Bu POS Oturum adı benzersiz olmalıdır!" #. module: point_of_sale #: view:pos.session:0 @@ -1167,7 +1174,7 @@ msgstr "Satış Detayları" #. module: point_of_sale #: model:product.template,name:point_of_sale.evian_2l_product_template msgid "2L Evian" -msgstr "" +msgstr "2L Evian" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:373 @@ -1202,12 +1209,12 @@ msgstr "Toplam satış" #: code:addons/point_of_sale/static/src/xml/pos.xml:741 #, python-format msgid "ABC" -msgstr "" +msgstr "ABC" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_dame_blanche_2,5l_product_template msgid "IJsboerke 2.5L White Lady" -msgstr "" +msgstr "Copy text \t IJsboerke 2.5L White Lady" #. module: point_of_sale #: field:pos.order,lines:0 @@ -1229,7 +1236,7 @@ msgstr "Chaudfontaine Petillante 50cl" #: code:addons/point_of_sale/static/src/xml/pos.xml:485 #, python-format msgid "Read Weighting Scale" -msgstr "" +msgstr "Ağırlık Ölçü Okuma" #. module: point_of_sale #. openerp-web @@ -1289,7 +1296,7 @@ msgstr "Satışlarım" #. module: point_of_sale #: view:pos.config:0 msgid "Set to Deprecated" -msgstr "" +msgstr "Kaldırılan Ayarlayın" #. module: point_of_sale #: model:product.template,name:point_of_sale.limon_product_template @@ -1325,6 +1332,8 @@ msgid "" "This sequence is automatically created by OpenERP but you can change it to " "customize the reference numbers of your orders." msgstr "" +"Bu sıralama otomatik OpenERP tarafından oluşturulur ancak siparişlerin " +"referans numaraları özelleştirmek için değiştirebilirsiniz." #. module: point_of_sale #. openerp-web @@ -1341,7 +1350,7 @@ msgstr "Orana göre aylık satışlar" #. module: point_of_sale #: model:product.template,name:point_of_sale.poivron_jaunes_product_template msgid "Yellow Peppers" -msgstr "" +msgstr "Sarı Biberler" #. module: point_of_sale #: view:pos.order:0 @@ -1379,7 +1388,7 @@ msgstr "Günün Kapanmış Kasaları" #: code:addons/point_of_sale/point_of_sale.py:897 #, python-format msgid "Selected orders do not have the same session!" -msgstr "" +msgstr "Seçilen siparişler aynı seansta yok!" #. module: point_of_sale #: report:pos.invoice:0 @@ -1431,7 +1440,7 @@ msgstr "Vergiler :" #: code:addons/point_of_sale/static/src/xml/pos.xml:271 #, python-format msgid "Thank you for shopping with us." -msgstr "" +msgstr "Bizimle alışveriş ettiğiniz için teşekkür ederiz." #. module: point_of_sale #: model:product.template,name:point_of_sale.coca_light_2l_product_template @@ -1452,7 +1461,7 @@ msgstr "Ürün Kategorileri" #. module: point_of_sale #: help:pos.config,journal_id:0 msgid "Accounting journal used to post sales entries." -msgstr "" +msgstr "Muhasebe Yevmiye satış kayıtları göndermek için kullanılır." #. module: point_of_sale #: field:report.transaction.pos,disc:0 @@ -1486,7 +1495,7 @@ msgstr "Coca-Cola Zero 33cl" #: code:addons/point_of_sale/static/src/xml/pos.xml:405 #, python-format msgid "ä" -msgstr "" +msgstr "ä" #. module: point_of_sale #: report:pos.invoice:0 @@ -1562,7 +1571,7 @@ msgstr "Kg" #. module: point_of_sale #: field:product.product,available_in_pos:0 msgid "Available in the Point of Sale" -msgstr "" +msgstr "Satış Noktası Mevcuttur" #. module: point_of_sale #: selection:pos.config,state:0 @@ -1572,14 +1581,14 @@ msgstr "Kaldırılmış" #. module: point_of_sale #: model:product.template,name:point_of_sale.coca_light_decaf_33cl_product_template msgid "Coca-Cola Light 33cl Decaf" -msgstr "" +msgstr "Coca-Cola Light 33cl Decaf" #. module: point_of_sale #. openerp-web #: code:addons/point_of_sale/static/src/xml/pos.xml:338 #, python-format msgid "The scanned product was not recognized" -msgstr "" +msgstr "Taranan ürün tanınmadı" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_report_transaction_pos @@ -1605,7 +1614,7 @@ msgstr "Boon Framboise 37.5cl" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_config msgid "pos.config" -msgstr "" +msgstr "pos.config" #. module: point_of_sale #: view:pos.ean_wizard:0 @@ -1617,7 +1626,7 @@ msgstr "" #. module: point_of_sale #: field:product.product,expense_pdt:0 msgid "Point of Sale Cash Out" -msgstr "" +msgstr "Satış Noktası Nakit Çıkış" #. module: point_of_sale #: selection:report.pos.order,month:0 @@ -1629,12 +1638,12 @@ msgstr "Kasım" #: code:addons/point_of_sale/static/src/xml/pos.xml:267 #, python-format msgid "Please scan an item or your member card" -msgstr "" +msgstr "Lütfen bir ürün veya üye kartı tarama" #. module: point_of_sale #: model:product.template,name:point_of_sale.poivron_verts_product_template msgid "Green Peppers" -msgstr "" +msgstr "Yeşil Biber" #. module: point_of_sale #: model:product.template,name:point_of_sale.timmermans_faro_37,5cl_product_template @@ -1652,7 +1661,7 @@ msgstr "" #. module: point_of_sale #: view:pos.session:0 msgid "Validate Closing & Post Entries" -msgstr "" +msgstr "Kapanış ve İşlem Girişler Doğrulama" #. module: point_of_sale #: field:report.transaction.pos,no_trans:0 @@ -1666,6 +1675,8 @@ msgid "" "There is no receivable account defined to make payment for the partner: " "\"%s\" (id:%d)." msgstr "" +"Partner için ödeme yapmak için tanımlanmış bir alacak hesabı yok: \"% s\" " +"(id:% d)." #. module: point_of_sale #: view:pos.config:0 @@ -1705,7 +1716,7 @@ msgstr "Satış (Özetleri)" #. module: point_of_sale #: model:product.template,name:point_of_sale.nectarine_product_template msgid "Peach" -msgstr "" +msgstr "Şeftali" #. module: point_of_sale #: model:product.template,name:point_of_sale.timmermans_kriek_37,5cl_product_template @@ -1715,7 +1726,7 @@ msgstr "Timmermans Kriek 37.5cl" #. module: point_of_sale #: field:pos.config,sequence_id:0 msgid "Order IDs Sequence" -msgstr "" +msgstr "Sipariş ID Sıralaması" #. module: point_of_sale #: report:pos.invoice:0 @@ -1770,7 +1781,7 @@ msgstr "Yazar Kasalar" #. module: point_of_sale #: help:pos.session,cash_register_balance_end:0 msgid "Computed with the initial cash control and the sum of all payments." -msgstr "" +msgstr "İlk nakit kontrolü ve tüm ödemeler toplamı ile hesaplanmıştır." #. module: point_of_sale #. openerp-web @@ -1907,7 +1918,7 @@ msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.ijsboerke_moka_2,5l_product_template msgid "IJsboerke Mocha 2.5L" -msgstr "" +msgstr "Copy text \t IJsboerke Mocha 2.5L" #. module: point_of_sale #: field:pos.session,cash_control:0 @@ -1934,6 +1945,7 @@ msgid "" "Unable to open the session. You have to assign a sale journal to your point " "of sale." msgstr "" +"Oturum açılamıyor. Satış noktasına bir satış yevmiyesi atamak zorundasınız." #. module: point_of_sale #: view:report.pos.order:0 @@ -2008,7 +2020,7 @@ msgstr "Satışelamanı" #: code:addons/point_of_sale/wizard/pos_box_out.py:91 #, python-format msgid "You have to open at least one cashbox." -msgstr "" +msgstr "En az bir kasa açmak zorunda." #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:1142 @@ -2019,14 +2031,14 @@ msgstr "FiyatListesi yok!" #. module: point_of_sale #: model:product.template,name:point_of_sale.poivron_rouges_product_template msgid "Red Pepper" -msgstr "" +msgstr "Kırmızı Biber" #. module: point_of_sale #. openerp-web #: code:addons/point_of_sale/static/src/xml/pos.xml:677 #, python-format msgid "caps lock" -msgstr "" +msgstr "büyük harf kilidi" #. module: point_of_sale #: model:product.template,name:point_of_sale.grisette_cerise_25cl_product_template @@ -2044,7 +2056,7 @@ msgstr "Matrah" #: code:addons/point_of_sale/static/src/xml/pos.xml:742 #, python-format msgid " " -msgstr "" +msgstr " " #. module: point_of_sale #: model:pos.category,name:point_of_sale.categ_others @@ -2054,7 +2066,7 @@ msgstr "Diğerleri" #. module: point_of_sale #: model:pos.category,name:point_of_sale.autres_legumes_frais msgid "Other fresh vegetables" -msgstr "" +msgstr "Diğer taze sebze" #. module: point_of_sale #: code:addons/point_of_sale/wizard/pos_open_statement.py:49 @@ -2068,11 +2080,13 @@ msgstr "Hiç Nakit Kasası Tanımlanmamış!" msgid "" "No cash statement found for this session. Unable to record returned cash." msgstr "" +"Bu oturum için nakit açıklamada bulunamadı. Geri nakit kaydetmek için " +"açılamıyor." #. module: point_of_sale #: model:pos.category,name:point_of_sale.oignons_ail_echalotes msgid "Onions / Garlic / Shallots" -msgstr "" +msgstr "Soğan / Sarımsak / Arpacık" #. module: point_of_sale #: model:product.template,name:point_of_sale.evian_50cl_product_template @@ -2108,7 +2122,7 @@ msgstr "Satış Satırı" #: code:addons/point_of_sale/static/src/xml/pos.xml:741 #, python-format msgid "123" -msgstr "" +msgstr "123" #. module: point_of_sale #: model:ir.actions.act_window,name:point_of_sale.product_normal_action @@ -2126,7 +2140,7 @@ msgstr "Dr. Oetker Ristorante Quattro Formaggi" #. module: point_of_sale #: model:product.template,name:point_of_sale.croky_naturel_45g_product_template msgid "Croky Natural 45g" -msgstr "" +msgstr "Croky Natural 45g" #. module: point_of_sale #: model:product.template,name:point_of_sale.tomate_en_grappe_product_template @@ -2136,7 +2150,7 @@ msgstr "" #. module: point_of_sale #: model:ir.actions.client,name:point_of_sale.action_pos_pos msgid "Start Point of Sale" -msgstr "" +msgstr "Satış Noktası Başlat" #. module: point_of_sale #. openerp-web @@ -2165,19 +2179,19 @@ msgstr "Sipariş Tarihi" #. module: point_of_sale #: view:pos.order:0 msgid "Point of Sale Orders" -msgstr "" +msgstr "Satış Noktası Siparişi" #. module: point_of_sale #: model:product.template,name:point_of_sale.spa_et_fruit_50cl_product_template msgid "Spa Fruit and Orange 50cl" -msgstr "" +msgstr "Spa Meyve ve Turuncu 50 cl" #. module: point_of_sale #: view:pos.config:0 #: field:pos.config,journal_ids:0 #: field:pos.session,journal_ids:0 msgid "Available Payment Methods" -msgstr "" +msgstr "Ödeme Yöntemleri" #. module: point_of_sale #: model:ir.actions.act_window,help:point_of_sale.product_normal_action @@ -2229,7 +2243,7 @@ msgstr "Kaynak" #: code:addons/point_of_sale/static/src/xml/pos.xml:461 #, python-format msgid "Admin Badge" -msgstr "" +msgstr "Yönetici Rozet" #. module: point_of_sale #: field:pos.make.payment,journal_id:0 @@ -2282,7 +2296,7 @@ msgstr "Su" #. module: point_of_sale #: model:ir.model,name:point_of_sale.model_pos_ean_wizard msgid "pos.ean_wizard" -msgstr "" +msgstr "pos.ean_wizard" #. module: point_of_sale #: selection:report.pos.order,month:0 @@ -2305,7 +2319,7 @@ msgstr "Ürün Mik." #. module: point_of_sale #: model:product.template,name:point_of_sale.pomme_golden_perlim_product_template msgid "Golden Apples Perlim" -msgstr "" +msgstr "Altın Elma" #. module: point_of_sale #: code:addons/point_of_sale/point_of_sale.py:100 @@ -2347,7 +2361,7 @@ msgstr "Bilinmeyen Ürün" #: code:addons/point_of_sale/static/src/xml/pos.xml:36 #, python-format msgid "" -msgstr "" +msgstr "" #. module: point_of_sale #: model:product.template,name:point_of_sale.jupiler_50cl_product_template @@ -2370,7 +2384,7 @@ msgstr "Coca-Cola Light Lemon 33cl" #: code:addons/point_of_sale/static/src/xml/pos.xml:33 #, python-format msgid "