From 82f780e948444cd9938613e99b3a77f32056f3ba Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Thu, 19 Jan 2012 20:16:54 +0100 Subject: [PATCH 001/265] [REM] unused imports. bzr revid: florent.xicluna@gmail.com-20120119191654-scm8c3o07icyz5b1 --- openerp/osv/fields.py | 3 --- openerp/tests/common.py | 1 - openerp/tests/test_orm.py | 1 - openerp/tiny_socket.py | 1 - 4 files changed, 6 deletions(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 871fc32f884..ff02a8c89f9 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -35,14 +35,11 @@ import base64 import datetime as DT import re -import string -import sys import warnings import xmlrpclib from psycopg2 import Binary import openerp -import openerp.netsvc as netsvc import openerp.tools as tools from openerp.tools.translate import _ from openerp.tools import float_round, float_repr diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 44696384ce7..93e5f6d5bc2 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import os import time import xmlrpclib diff --git a/openerp/tests/test_orm.py b/openerp/tests/test_orm.py index c11d4cd19d2..cf880933fe5 100644 --- a/openerp/tests/test_orm.py +++ b/openerp/tests/test_orm.py @@ -1,4 +1,3 @@ -import os import unittest2 import openerp diff --git a/openerp/tiny_socket.py b/openerp/tiny_socket.py index b4bed83a4c0..f86797f0f67 100644 --- a/openerp/tiny_socket.py +++ b/openerp/tiny_socket.py @@ -22,7 +22,6 @@ import socket import cPickle import cStringIO -import marshal import netsvc From e7838dfbc44472a444b1f58dd7869febbc5984b7 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Thu, 19 Jan 2012 20:17:56 +0100 Subject: [PATCH 002/265] [REF] fix weird indentation, not multiple of four. bzr revid: florent.xicluna@gmail.com-20120119191756-niny262vp1nvmpp8 --- openerp/netsvc.py | 16 ++++++++-------- openerp/osv/orm.py | 12 ++++++------ openerp/service/netrpc_server.py | 6 +++--- openerp/service/web_services.py | 10 +++++----- openerp/tests/test_xmlrpc.py | 4 ++-- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/openerp/netsvc.py b/openerp/netsvc.py index ca08a362771..53750ed84da 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -84,12 +84,12 @@ class Service(object): cls._services.pop(name) def LocalService(name): - # Special case for addons support, will be removed in a few days when addons - # are updated to directly use openerp.osv.osv.service. - if name == 'object_proxy': - return openerp.osv.osv.service + # Special case for addons support, will be removed in a few days when addons + # are updated to directly use openerp.osv.osv.service. + if name == 'object_proxy': + return openerp.osv.osv.service - return Service._services[name] + return Service._services[name] class ExportService(object): """ Proxy for exported services. @@ -198,9 +198,9 @@ def init_logger(): # server intended to test it. def init_alternative_logger(): class H(logging.Handler): - def emit(self, record): - if record.levelno > 20: - print record.levelno, record.pathname, record.msg + def emit(self, record): + if record.levelno > 20: + print record.levelno, record.pathname, record.msg handler = H() logger = logging.getLogger() logger.handlers = [] diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 1c12fab27c9..f2686708436 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -98,10 +98,10 @@ def transfer_node_to_modifiers(node, modifiers, context=None, in_tree_view=False if node.get('states'): if 'invisible' in modifiers and isinstance(modifiers['invisible'], list): - # TODO combine with AND or OR, use implicit AND for now. - modifiers['invisible'].append(('state', 'not in', node.get('states').split(','))) + # TODO combine with AND or OR, use implicit AND for now. + modifiers['invisible'].append(('state', 'not in', node.get('states').split(','))) else: - modifiers['invisible'] = [('state', 'not in', node.get('states').split(','))] + modifiers['invisible'] = [('state', 'not in', node.get('states').split(','))] for a in ('invisible', 'readonly', 'required'): if node.get(a): @@ -894,8 +894,8 @@ class BaseModel(object): for c in cls.__dict__.get(s, []): exist = False for c2 in range(len(new)): - #For _constraints, we should check field and methods as well - if new[c2][2]==c[2] and (new[c2][0] == c[0] \ + #For _constraints, we should check field and methods as well + if new[c2][2]==c[2] and (new[c2][0] == c[0] \ or getattr(new[c2][0],'__name__', True) == \ getattr(c[0],'__name__', False)): # If new class defines a constraint with @@ -2690,7 +2690,7 @@ class BaseModel(object): elif val in dict(self._columns[field].selection(self, cr, uid, context=context)): return raise except_orm(_('ValidateError'), - _('The value "%s" for the field "%s.%s" is not in the selection') % (value, self._table, field)) + _('The value "%s" for the field "%s.%s" is not in the selection') % (value, self._table, field)) def _check_removed_columns(self, cr, log=False): # iterate on the database columns to drop the NOT NULL constraints diff --git a/openerp/service/netrpc_server.py b/openerp/service/netrpc_server.py index f86d6d21273..efe26906720 100644 --- a/openerp/service/netrpc_server.py +++ b/openerp/service/netrpc_server.py @@ -125,9 +125,9 @@ class TinySocketServerThread(threading.Thread,netsvc.Server): ct.start() lt = len(self.threads) if (lt > 10) and (lt % 10 == 0): - # Not many threads should be serving at the same time, so log - # their abuse. - netsvc.Logger().notifyChannel("web-services", netsvc.LOG_DEBUG, + # Not many threads should be serving at the same time, so log + # their abuse. + netsvc.Logger().notifyChannel("web-services", netsvc.LOG_DEBUG, "Netrpc: %d threads" % len(self.threads)) self.socket.close() except Exception, e: diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 1bda0230c89..8c3db0e88af 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -521,11 +521,11 @@ GNU Public Licence. 'OS Name : %s\n' \ %(platform.platform(), platform.os.name) if os.name == 'posix': - if platform.system() == 'Linux': - lsbinfo = os.popen('lsb_release -a').read() - environment += '%s'%(lsbinfo) - else: - environment += 'Your System is not lsb compliant\n' + if platform.system() == 'Linux': + lsbinfo = os.popen('lsb_release -a').read() + environment += '%s'%(lsbinfo) + else: + environment += 'Your System is not lsb compliant\n' environment += 'Operating System Release : %s\n' \ 'Operating System Version : %s\n' \ 'Operating System Architecture : %s\n' \ diff --git a/openerp/tests/test_xmlrpc.py b/openerp/tests/test_xmlrpc.py index 954d3447360..ca0ae454437 100644 --- a/openerp/tests/test_xmlrpc.py +++ b/openerp/tests/test_xmlrpc.py @@ -19,8 +19,8 @@ ADMIN_USER_ID = common.ADMIN_USER_ID ADMIN_PASSWORD = common.ADMIN_PASSWORD def setUpModule(): - common.start_openerp() - common.create_xmlrpc_proxies() + common.start_openerp() + common.create_xmlrpc_proxies() tearDownModule = common.tearDownModule From efef81654b90e70a24d1a330c0ef8d9942e05444 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Thu, 19 Jan 2012 20:18:38 +0100 Subject: [PATCH 003/265] [REF] replace deprecated <> symbol. bzr revid: florent.xicluna@gmail.com-20120119191838-r07oybyiqbkfehsz --- openerp/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index f2686708436..dceb14a2710 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1303,7 +1303,7 @@ class BaseModel(object): if not line[i]: continue - if field[:len(prefix)] <> prefix: + if field[:len(prefix)] != prefix: if line[i] and skip: return False continue @@ -2666,7 +2666,7 @@ class BaseModel(object): # if val is a many2one, just write the ID if type(val) == tuple: val = val[0] - if (val<>False) or (type(val)<>bool): + if val is not False: cr.execute(update_query, (ss[1](val), key)) def _check_selection_field_value(self, cr, uid, field, value, context=None): From c749cd8fcc864e6103f55bcf7b12e0910f2ffa14 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Mon, 23 Jan 2012 15:29:32 +0100 Subject: [PATCH 004/265] =?UTF-8?q?[IMP]=C2=A0upgrade=20the=20Pickle=20pro?= =?UTF-8?q?tocol=20to=20consume=20less=20bandwidth.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bzr revid: florent.xicluna@gmail.com-20120123142932-idcqz4p46gvbvhfh --- openerp/tiny_socket.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openerp/tiny_socket.py b/openerp/tiny_socket.py index b4bed83a4c0..c3960afd054 100644 --- a/openerp/tiny_socket.py +++ b/openerp/tiny_socket.py @@ -28,6 +28,10 @@ import netsvc #.apidoc title: Net-RPC classes +# Pickle protocol version 2 is optimized compared to default (version 0) +PICKLE_PROTOCOL = 2 + + class Myexception(Exception): """ custom exception object store @@ -63,8 +67,8 @@ class mysocket: netsvc.close_socket(self.sock) def mysend(self, msg, exception=False, traceback=None): - msg = cPickle.dumps([msg,traceback]) - self.sock.sendall('%8d%s%s' % (len(msg), exception and "1" or "0", msg)) + msg = cPickle.dumps([msg, traceback], PICKLE_PROTOCOL) + self.sock.sendall('%8d%d%s' % (len(msg), bool(exception), msg)) def myreceive(self): buf='' From bac1a957193c5b76fc944d268d2b711809e34d19 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Mon, 23 Jan 2012 15:30:15 +0100 Subject: [PATCH 005/265] =?UTF-8?q?[IMP]=C2=A0merge=20two=20socket.recv=20?= =?UTF-8?q?into=20one.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bzr revid: florent.xicluna@gmail.com-20120123143015-gz22l5qre6ria8f4 --- openerp/tiny_socket.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openerp/tiny_socket.py b/openerp/tiny_socket.py index c3960afd054..87db82f6d91 100644 --- a/openerp/tiny_socket.py +++ b/openerp/tiny_socket.py @@ -72,15 +72,14 @@ class mysocket: def myreceive(self): buf='' - while len(buf) < 8: - chunk = self.sock.recv(8 - len(buf)) + while len(buf) < 9: + chunk = self.sock.recv(9 - len(buf)) if not chunk: raise socket.timeout buf += chunk - size = int(buf) - buf = self.sock.recv(1) - if buf != "0": - exception = buf + size = int(buf[:8]) + if buf[8] != "0": + exception = buf[8] else: exception = False msg = '' From 5c40627e4bd91c2355a4d196f62e1ccfa83aaf12 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 26 Jan 2012 14:30:13 +0100 Subject: [PATCH 006/265] [FIX] don't just print a warning if an @eval fails in an XML file bzr revid: xmo@openerp.com-20120126133013-5fnsouix8cutwlik --- openerp/tools/convert.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index 553aa48effc..ec3e67670c3 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -129,15 +129,14 @@ def _eval_xml(self, node, pool, cr, uid, idref, context=None): f_val = f_val[0] return f_val a_eval = node.get('eval','') - idref2 = {} if a_eval: idref2 = _get_idref(self, cr, uid, f_model, context, idref) try: return unsafe_eval(a_eval, idref2) except Exception: - logger = logging.getLogger('init') - logger.warning('could not eval(%s) for %s in %s' % (a_eval, node.get('name'), context), exc_info=True) - return "" + logging.getLogger('openerp.tools.convert.init').error( + 'Could not eval(%s) for %s in %s', a_eval, node.get('name'), context) + raise if t == 'xml': def _process(s, idref): m = re.findall('[^%]%\((.*?)\)[ds]', s) From 111d8b76f7e384a3b1a77d802b52eedbb7ae04c7 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 1 Feb 2012 13:33:11 +0100 Subject: [PATCH 007/265] [REF] one unused import and one redundant import. bzr revid: florent.xicluna@gmail.com-20120201123311-yvljvcj0luly77qt --- openerp-server | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openerp-server b/openerp-server index 334c1790526..5868b4f33d5 100755 --- a/openerp-server +++ b/openerp-server @@ -42,9 +42,6 @@ import openerp __author__ = openerp.release.author __version__ = openerp.release.version -import sys -import imp - def check_root_user(): """ Exit if the process's user is 'root' (on POSIX system).""" if os.name == 'posix': @@ -200,7 +197,7 @@ def quit_on_signals(): try: while quit_signals_received == 0: time.sleep(60) - except KeyboardInterrupt, e: + except KeyboardInterrupt: pass if config['pidfile']: From 1ef81548ba5dd463adaf20433b7bc4b39ebb8e78 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 15:22:48 +0100 Subject: [PATCH 008/265] [REF] additional cleanup after vmt's logging refactoring. bzr revid: florent.xicluna@gmail.com-20120208142248-p63odfqo673yqqml --- openerp/service/netrpc_server.py | 2 +- openerp/service/web_services.py | 17 ++++++++--------- openerp/wizard/__init__.py | 6 +----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/openerp/service/netrpc_server.py b/openerp/service/netrpc_server.py index 327ebc5bbdc..fcbfaf0ba82 100644 --- a/openerp/service/netrpc_server.py +++ b/openerp/service/netrpc_server.py @@ -131,7 +131,7 @@ class TinySocketServerThread(threading.Thread,netsvc.Server): _logger.debug("Netrpc: %d threads", len(self.threads)) self.socket.close() except Exception, e: - _logger.warning("Netrpc: closing because of exception %s" % str(e)) + _logger.warning("Netrpc: closing because of exception %s", e) self.socket.close() return False diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 43f4d1af639..661b74a6995 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -224,9 +224,9 @@ class db(netsvc.ExportService): if not data or res: _logger.error( - 'DUMP DB: %s failed! Please verify the configuration of the database password on the server. '\ - 'It should be provided as a -w command-line option, or as `db_password` in the '\ - 'server configuration file.\n %s' % (db_name, data)) + 'DUMP DB: %s failed! Please verify the configuration of the database password on the server. ' + 'It should be provided as a -w command-line option, or as `db_password` in the ' + 'server configuration file.\n %s', db_name, data) raise Exception, "Couldn't dump database" _logger.info('DUMP DB successful: %s', db_name) @@ -239,7 +239,7 @@ class db(netsvc.ExportService): self._set_pg_psw_env_var() if self.exp_db_exist(db_name): - _logger.warning('RESTORE DB: %s already exists' % (db_name,)) + _logger.warning('RESTORE DB: %s already exists', db_name) raise Exception, "Database already exists" self._create_empty_database(db_name) @@ -268,7 +268,7 @@ class db(netsvc.ExportService): res = stdout.close() if res: raise Exception, "Couldn't restore database" - _logger.info('RESTORE DB: %s' % (db_name)) + _logger.info('RESTORE DB: %s', db_name) return True finally: @@ -451,8 +451,7 @@ GNU Public Licence. backup_directory = os.path.join(tools.config['root_path'], 'backup', time.strftime('%Y-%m-%d-%H-%M')) if zips and not os.path.isdir(backup_directory): - _logger.info('create a new backup directory to \ - store the old modules: %s', backup_directory) + _logger.info('create a new backup directory to store the old modules: %s', backup_directory) os.makedirs(backup_directory) for module in zips: @@ -678,7 +677,7 @@ class report_spool(netsvc.ExportService): self._reports[id]['state'] = True except Exception, exception: - _logger.exception('Exception: %s\n', str(exception)) + _logger.exception('Exception: %s\n', exception) if hasattr(exception, 'name') and hasattr(exception, 'value'): self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) else: @@ -715,7 +714,7 @@ class report_spool(netsvc.ExportService): self._reports[id]['format'] = format self._reports[id]['state'] = True except Exception, exception: - _logger.exception('Exception: %s\n', str(exception)) + _logger.exception('Exception: %s\n', exception) if hasattr(exception, 'name') and hasattr(exception, 'value'): self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) else: diff --git a/openerp/wizard/__init__.py b/openerp/wizard/__init__.py index 7354a43498d..debf0f1e74f 100644 --- a/openerp/wizard/__init__.py +++ b/openerp/wizard/__init__.py @@ -31,7 +31,6 @@ import openerp.pooler as pooler from openerp.osv.osv import except_osv from openerp.osv.orm import except_orm -import sys _logger = logging.getLogger(__name__) @@ -168,10 +167,7 @@ class interface(netsvc.Service): or isinstance(e, except_orm): netsvc.abort_response(2, e.name, 'warning', e.value) else: - import traceback - tb_s = reduce(lambda x, y: x+y, traceback.format_exception( - sys.exc_type, sys.exc_value, sys.exc_traceback)) - _logger.error('Exception in call: ' + tb_s) + _logger.exception('Exception in call:') raise return res From 57ca8e47975101c57991cf89efe86c033ff8a6de Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 18:00:34 +0100 Subject: [PATCH 009/265] [REF] openerp.report: better use of isinstance. bzr revid: florent.xicluna@gmail.com-20120208170034-2w8szxy350qpwas6 --- openerp/report/custom.py | 2 +- openerp/report/render/rml2txt/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/report/custom.py b/openerp/report/custom.py index 051d1f29862..d06f2d721f7 100644 --- a/openerp/report/custom.py +++ b/openerp/report/custom.py @@ -108,7 +108,7 @@ class report_custom(report_int): key = levels.keys() for l in key: objs = eval('obj.'+l,{'obj': obj}) - if not isinstance(objs, browse_record_list) and type(objs) <> type([]): + if not isinstance(objs, (browse_record_list, list)): objs = [objs] field_new = [] cond_new = [] diff --git a/openerp/report/render/rml2txt/utils.py b/openerp/report/render/rml2txt/utils.py index 122411afb2d..c08210ecc79 100644 --- a/openerp/report/render/rml2txt/utils.py +++ b/openerp/report/render/rml2txt/utils.py @@ -75,9 +75,9 @@ def _process_text(self, txt): txt2 = eval(sps.pop(0),self.localcontext) except: txt2 = '' - if type(txt2) == type(0) or type(txt2) == type(0.0): + if isinstance(txt2, (int, float)): txt2 = str(txt2) - if type(txt2)==type('') or type(txt2)==type(u''): + if isinstance(txt2, basestring): result += txt2 return result From b5fa51f4a691b840e588bc33e4e960958860fd12 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 18:02:17 +0100 Subject: [PATCH 010/265] =?UTF-8?q?[REF]=C2=A0openerp.report:=20use=20the?= =?UTF-8?q?=20recommended=20syntax=20to=20raise=20error=20and=20never=20us?= =?UTF-8?q?e=20empty=20except:.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bzr revid: florent.xicluna@gmail.com-20120208170217-xsa5odzlhite0nda --- openerp/report/custom.py | 2 +- openerp/report/interface.py | 4 ++-- openerp/report/preprocess.py | 2 +- openerp/report/printscreen/ps_list.py | 2 +- openerp/report/render/rml2html/rml2html.py | 2 +- openerp/report/render/rml2pdf/trml2pdf.py | 2 +- openerp/report/render/rml2txt/utils.py | 8 ++++---- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/openerp/report/custom.py b/openerp/report/custom.py index d06f2d721f7..a03ae0b8a53 100644 --- a/openerp/report/custom.py +++ b/openerp/report/custom.py @@ -267,7 +267,7 @@ class report_custom(report_int): else: try: row.append(float(r[j])) - except: + except Exception: row.append(r[j]) results2.append(row) if report['type']=='pie': diff --git a/openerp/report/interface.py b/openerp/report/interface.py index 9a97c445671..69474a18433 100644 --- a/openerp/report/interface.py +++ b/openerp/report/interface.py @@ -44,8 +44,8 @@ class report_int(netsvc.Service): def __init__(self, name): assert not self.exists(name), 'The report "%s" already exists!' % name super(report_int, self).__init__(name) - if name[0:7]<>'report.': - raise Exception, 'ConceptionError, bad report name, should start with "report."' + if not name.startswith('report.'): + raise Exception('ConceptionError, bad report name, should start with "report."') self.name = name self.id = 0 self.name2 = '.'.join(name.split('.')[1:]) diff --git a/openerp/report/preprocess.py b/openerp/report/preprocess.py index e681860d7a2..93b6b4d1bc9 100644 --- a/openerp/report/preprocess.py +++ b/openerp/report/preprocess.py @@ -48,7 +48,7 @@ class report(object): try: while n.tag != txt.group(3): n = n.getparent() - except: + except Exception: n = node else: n = node.getparent() diff --git a/openerp/report/printscreen/ps_list.py b/openerp/report/printscreen/ps_list.py index dc280a53e3e..8f0629462f8 100644 --- a/openerp/report/printscreen/ps_list.py +++ b/openerp/report/printscreen/ps_list.py @@ -56,7 +56,7 @@ class report_printscreen_list(report_int): def _parse_string(self, view): try: dom = etree.XML(view.encode('utf-8')) - except: + except Exception: dom = etree.XML(view) return self._parse_node(dom) diff --git a/openerp/report/render/rml2html/rml2html.py b/openerp/report/render/rml2html/rml2html.py index 504492772df..a26f6eadaa6 100644 --- a/openerp/report/render/rml2html/rml2html.py +++ b/openerp/report/render/rml2html/rml2html.py @@ -98,7 +98,7 @@ class _flowable(object): try: if new_child.get('style').find('terp_tblheader')!= -1: new_node.tag = 'th' - except: + except Exception: pass process(node,new_node) if new_node.get('colWidths',False): diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index 96287166074..58457993142 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -424,7 +424,7 @@ class _rml_canvas(object): flow.drawOn(self.canvas,infos['x'],infos['y']) infos['height']-=h else: - raise ValueError, "Not enough space" + raise ValueError("Not enough space") def _line_mode(self, node): ljoin = {'round':1, 'mitered':0, 'bevelled':2} diff --git a/openerp/report/render/rml2txt/utils.py b/openerp/report/render/rml2txt/utils.py index c08210ecc79..95e99c32ce1 100644 --- a/openerp/report/render/rml2txt/utils.py +++ b/openerp/report/render/rml2txt/utils.py @@ -37,7 +37,7 @@ def _child_get(node, self=None, tagname=None): if n.get('rml_except', False): try: eval(n.get('rml_except'), {}, self.localcontext) - except: + except Exception: continue if n.get('rml_tag'): try: @@ -46,7 +46,7 @@ def _child_get(node, self=None, tagname=None): n2.tag = tag n2.attrib.update(attr) yield n2 - except: + except Exception: yield n else: yield n @@ -55,7 +55,7 @@ def _child_get(node, self=None, tagname=None): if self and self.localcontext and n.get('rml_except', False): try: eval(n.get('rml_except'), {}, self.localcontext) - except: + except Exception: continue if (tagname is None) or (n.tag==tagname): yield n @@ -73,7 +73,7 @@ def _process_text(self, txt): if sps: try: txt2 = eval(sps.pop(0),self.localcontext) - except: + except Exception: txt2 = '' if isinstance(txt2, (int, float)): txt2 = str(txt2) From 9621008df12a65730a123e389d84ef8b21e5941d Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 18:03:51 +0100 Subject: [PATCH 011/265] =?UTF-8?q?[REF]=C2=A0openerp.report:=20replace=20?= =?UTF-8?q?deprecated=20has=5Fkey.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bzr revid: florent.xicluna@gmail.com-20120208170351-1vmewmuufmxn7x52 --- openerp/report/custom.py | 14 +++++++------- openerp/report/print_xml.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/openerp/report/custom.py b/openerp/report/custom.py index a03ae0b8a53..b33065fcdee 100644 --- a/openerp/report/custom.py +++ b/openerp/report/custom.py @@ -221,7 +221,7 @@ class report_custom(report_int): res_dic[prev].append(line) else: prev = line[groupby] - if res_dic.has_key(line[groupby]): + if line[groupby] in res_dic: res_dic[line[groupby]].append(line) else: res_dic[line[groupby]] = [] @@ -389,7 +389,7 @@ class report_custom(report_int): if date_idx != None: for r in results: key = process_date['Y'](r[date_idx]) - if not data_by_year.has_key(key): + if key not in data_by_year: data_by_year[key] = [] for i in range(len(r)): r[i] = fct[i](r[i]) @@ -407,14 +407,14 @@ class report_custom(report_int): for d in data_by_year[line]: for idx in range(len(fields)-1): fields_bar.append({}) - if fields_bar[idx].has_key(d[0]): + if d[0] in fields_bar[idx]: fields_bar[idx][d[0]] += d[idx+1] else: fields_bar[idx][d[0]] = d[idx+1] for idx in range(len(fields)-1): data = {} for k in fields_bar[idx].keys(): - if data.has_key(k): + if k in data: data[k] += fields_bar[idx][k] else: data[k] = fields_bar[idx][k] @@ -488,7 +488,7 @@ class report_custom(report_int): if date_idx != None: for r in results: key = process_date['Y'](r[date_idx]) - if not data_by_year.has_key(key): + if key not in data_by_year: data_by_year[key] = [] for i in range(len(r)): r[i] = fct[i](r[i]) @@ -507,14 +507,14 @@ class report_custom(report_int): for d in data_by_year[line]: for idx in range(len(fields)-1): fields_bar.append({}) - if fields_bar[idx].has_key(d[0]): + if d[0] in fields_bar[idx]: fields_bar[idx][d[0]] += d[idx+1] else: fields_bar[idx][d[0]] = d[idx+1] for idx in range(len(fields)-1): data = {} for k in fields_bar[idx].keys(): - if data.has_key(k): + if k in data: data[k] += fields_bar[idx][k] else: data[k] = fields_bar[idx][k] diff --git a/openerp/report/print_xml.py b/openerp/report/print_xml.py index ee1b9a316b3..2137eabee79 100644 --- a/openerp/report/print_xml.py +++ b/openerp/report/print_xml.py @@ -200,7 +200,7 @@ class document(object): else: args = [] # get the object - if attrs.has_key('model'): + if 'model' in attrs: obj = self.pool.get(attrs['model']) else: if isinstance(browser, list): @@ -209,7 +209,7 @@ class document(object): obj = browser._table # get the ids - if attrs.has_key('ids'): + if 'ids' in attrs: ids = self.eval(browser, attrs['ids']) else: if isinstance(browser, list): From 7675d45c2c10e833bc5d5f0b3f905f1cca652a3d Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 18:04:56 +0100 Subject: [PATCH 012/265] [REF] openerp.report: fix weird indentation, not multiple of four. bzr revid: florent.xicluna@gmail.com-20120208170456-ak1ykpy6yel71ylc --- openerp/report/interface.py | 2 +- openerp/report/print_xml.py | 2 +- openerp/report/printscreen/ps_form.py | 2 +- openerp/report/render/rml2html/rml2html.py | 16 ++++++++-------- openerp/report/render/rml2pdf/trml2pdf.py | 2 +- openerp/report/render/rml2txt/rml2txt.py | 4 ++-- openerp/report/render/simple.py | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/openerp/report/interface.py b/openerp/report/interface.py index 69474a18433..17dc0973d7e 100644 --- a/openerp/report/interface.py +++ b/openerp/report/interface.py @@ -181,7 +181,7 @@ class report_rml(report_int): def create_pdf(self, rml, localcontext = None, logo=None, title=None): if not localcontext: - localcontext={} + localcontext = {} localcontext.update({'internal_header':self.internal_header}) if logo: self.bin_datas['logo'] = logo diff --git a/openerp/report/print_xml.py b/openerp/report/print_xml.py index 2137eabee79..c2af0984c2e 100644 --- a/openerp/report/print_xml.py +++ b/openerp/report/print_xml.py @@ -228,7 +228,7 @@ class document(object): if not isinstance(datas[atr['value']], (str, unicode)): txt = str(datas[atr['value']]) else: - txt = datas[atr['value']] + txt = datas[atr['value']] el.text = txt else: for el_cld in node: diff --git a/openerp/report/printscreen/ps_form.py b/openerp/report/printscreen/ps_form.py index 8e3823e6b03..cf6d77cbe26 100644 --- a/openerp/report/printscreen/ps_form.py +++ b/openerp/report/printscreen/ps_form.py @@ -120,7 +120,7 @@ class report_printscreen_list(report_int): line[f]=round(line[f],precision) col = etree.SubElement(node_line, 'col', tree='no') if line[f] != None: - col.text = tools.ustr(line[f] or '') + col.text = tools.ustr(line[f] or '') else: col.text = '/' diff --git a/openerp/report/render/rml2html/rml2html.py b/openerp/report/render/rml2html/rml2html.py index a26f6eadaa6..17ed2e3103e 100644 --- a/openerp/report/render/rml2html/rml2html.py +++ b/openerp/report/render/rml2html/rml2html.py @@ -232,7 +232,7 @@ class _rml_stylesheet(object): attr = {} attrs = ps.attrib for key, val in attrs.items(): - attr[key] = val + attr[key] = val attrs = [] for a in attr: if a in self._tags: @@ -296,13 +296,13 @@ class _rml_template(object): frames[(posy,posx,tmpl.get('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.get('width'))) for tmpl in pt.findall('pageGraphics'): for n in tmpl: - if n.tag == 'image': - self.data = rc + utils._process_text(self, n.text) - if n.tag in self._tags: - t = self._tags[n.tag](n, self.style,self.localcontext) - frames[(t.posy,t.posx,n.tag)] = t - else: - self.style.update(n) + if n.tag == 'image': + self.data = rc + utils._process_text(self, n.text) + if n.tag in self._tags: + t = self._tags[n.tag](n, self.style,self.localcontext) + frames[(t.posy,t.posx,n.tag)] = t + else: + self.style.update(n) keys = frames.keys() keys.sort() keys.reverse() diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index 58457993142..a17c03b40cb 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -82,7 +82,7 @@ class NumberedCanvas(canvas.Canvas): def showPage(self): self._currentPage +=1 if not self._flag: - self._pageCount += 1 + self._pageCount += 1 else: self.pages.update({self._currentPage:self._pageCount}) self._codes.append({'code': self._code, 'stack': self._codeStack}) diff --git a/openerp/report/render/rml2txt/rml2txt.py b/openerp/report/render/rml2txt/rml2txt.py index 4a30e0d2345..8a8c1b7f3c7 100755 --- a/openerp/report/render/rml2txt/rml2txt.py +++ b/openerp/report/render/rml2txt/rml2txt.py @@ -336,8 +336,8 @@ class _rml_stylesheet(object): attr = {} attrs = ps.attributes for i in range(attrs.length): - name = attrs.item(i).localName - attr[name] = ps.get(name) + name = attrs.item(i).localName + attr[name] = ps.get(name) attrs = [] for a in attr: if a in self._tags: diff --git a/openerp/report/render/simple.py b/openerp/report/render/simple.py index 4ce10991924..49d1adf148e 100644 --- a/openerp/report/render/simple.py +++ b/openerp/report/render/simple.py @@ -82,7 +82,7 @@ if __name__=='__main__': ''' if s.render(): - print s.get() + print s.get() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 6312fd9426d6ccdbbfdada88763961f4b29d5c06 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 18:07:00 +0100 Subject: [PATCH 013/265] [REF] openerp.report: remove unused imports and vars, simplify logging. bzr revid: florent.xicluna@gmail.com-20120208170700-csx9jb3nwmvq3dzj --- openerp/report/custom.py | 3 --- openerp/report/render/html2html/html2html.py | 2 -- openerp/report/render/makohtml2html/makohtml2html.py | 8 +++----- openerp/report/render/odt2odt/odt2odt.py | 1 - openerp/report/render/rml2html/rml2html.py | 2 +- openerp/report/render/rml2txt/rml2txt.py | 2 -- openerp/report/render/rml2txt/utils.py | 1 - openerp/report/render/simple.py | 1 - 8 files changed, 4 insertions(+), 16 deletions(-) diff --git a/openerp/report/custom.py b/openerp/report/custom.py index b33065fcdee..80dd9462175 100644 --- a/openerp/report/custom.py +++ b/openerp/report/custom.py @@ -21,7 +21,6 @@ import os import time -import openerp.netsvc as netsvc import openerp.tools as tools from openerp.tools.safe_eval import safe_eval as eval @@ -67,7 +66,6 @@ class report_custom(report_int): # def _row_get(self, cr, uid, objs, fields, conditions, row_canvas=None, group_by=None): result = [] - tmp = [] for obj in objs: tobreak = False for cond in conditions: @@ -365,7 +363,6 @@ class report_custom(report_int): order_date['Y'] = lambda x : x abscissa = [] - tmp = {} idx = 0 date_idx = None diff --git a/openerp/report/render/html2html/html2html.py b/openerp/report/render/html2html/html2html.py index 181c7f7ba67..09d7ad5e825 100644 --- a/openerp/report/render/html2html/html2html.py +++ b/openerp/report/render/html2html/html2html.py @@ -20,9 +20,7 @@ ############################################################################## from openerp.report.render.rml2pdf import utils -from lxml import etree import copy -import openerp.pooler as pooler import base64 import cStringIO import re diff --git a/openerp/report/render/makohtml2html/makohtml2html.py b/openerp/report/render/makohtml2html/makohtml2html.py index 57e57bd8d63..dbb3327a105 100644 --- a/openerp/report/render/makohtml2html/makohtml2html.py +++ b/openerp/report/render/makohtml2html/makohtml2html.py @@ -23,8 +23,7 @@ import mako from lxml import etree from mako.template import Template from mako.lookup import TemplateLookup -import openerp.netsvc as netsvc -import traceback, sys, os +import os _logger = logging.getLogger(__name__) @@ -126,9 +125,8 @@ class makohtml2html(object): final_html += self.format_header(etree_obj) final_html += self.format_body(etree_obj) return final_html - except Exception,e: - tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) - _logger.error('report :\n%s\n%s\n', tb_s, str(e)) + except Exception: + _logger.exception('report :') def parseNode(html, localcontext = {}): r = makohtml2html(html, localcontext) diff --git a/openerp/report/render/odt2odt/odt2odt.py b/openerp/report/render/odt2odt/odt2odt.py index d077207f4d7..b9713943dc8 100644 --- a/openerp/report/render/odt2odt/odt2odt.py +++ b/openerp/report/render/odt2odt/odt2odt.py @@ -20,7 +20,6 @@ ############################################################################## from openerp.report.render.rml2pdf import utils -from lxml import etree import copy class odt2odt(object): diff --git a/openerp/report/render/rml2html/rml2html.py b/openerp/report/render/rml2html/rml2html.py index 17ed2e3103e..90bd58af99a 100644 --- a/openerp/report/render/rml2html/rml2html.py +++ b/openerp/report/render/rml2html/rml2html.py @@ -39,7 +39,7 @@ import sys import cStringIO from lxml import etree import copy -import utils + from openerp.report.render.rml2pdf import utils class _flowable(object): diff --git a/openerp/report/render/rml2txt/rml2txt.py b/openerp/report/render/rml2txt/rml2txt.py index 8a8c1b7f3c7..ab1930d81ba 100755 --- a/openerp/report/render/rml2txt/rml2txt.py +++ b/openerp/report/render/rml2txt/rml2txt.py @@ -22,9 +22,7 @@ import sys import StringIO -import copy from lxml import etree -import base64 import utils diff --git a/openerp/report/render/rml2txt/utils.py b/openerp/report/render/rml2txt/utils.py index 95e99c32ce1..2bf66925527 100644 --- a/openerp/report/render/rml2txt/utils.py +++ b/openerp/report/render/rml2txt/utils.py @@ -22,7 +22,6 @@ import re import reportlab import reportlab.lib.units -from lxml import etree from openerp.tools.safe_eval import safe_eval as eval _regex = re.compile('\[\[(.+?)\]\]') diff --git a/openerp/report/render/simple.py b/openerp/report/render/simple.py index 49d1adf148e..cb3831c141f 100644 --- a/openerp/report/render/simple.py +++ b/openerp/report/render/simple.py @@ -66,7 +66,6 @@ class simple(render.render): return self.result.getvalue() if __name__=='__main__': - import time s = simple() s.xml = ''' From ab9db3f6227789fabf3fdfcd2eda016b996bfd28 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 22:33:13 +0100 Subject: [PATCH 014/265] [REM] more unused imports. bzr revid: florent.xicluna@gmail.com-20120208213313-1v0dugc59ch1fnnu --- openerp/service/http_server.py | 2 -- openerp/tests/addons/test_limits/models.py | 1 - 2 files changed, 3 deletions(-) diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py index 07e31ea9c7d..63e0d08fc92 100644 --- a/openerp/service/http_server.py +++ b/openerp/service/http_server.py @@ -44,10 +44,8 @@ import posixpath import urllib import os import logging -from SimpleXMLRPCServer import SimpleXMLRPCDispatcher from websrv_lib import * -import openerp.netsvc as netsvc import openerp.tools as tools try: diff --git a/openerp/tests/addons/test_limits/models.py b/openerp/tests/addons/test_limits/models.py index 5240acd23ab..32e2a9a16f4 100644 --- a/openerp/tests/addons/test_limits/models.py +++ b/openerp/tests/addons/test_limits/models.py @@ -27,7 +27,6 @@ class m(openerp.osv.osv.Model): return True def consume_cpu_time(self, cr, uid, seconds, context=None): - import os t0 = time.clock() t1 = time.clock() while t1 - t0 < seconds: From a1e5c645d97e4e8f48cec546e858643029b7424a Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 9 Feb 2012 22:33:17 +0100 Subject: [PATCH 015/265] postgres use postgres instead of template1 and template1 instead of template0 bzr revid: al@openerp.com-20120209213317-3tt4o0sj87764ocn --- openerp/service/web_services.py | 10 +++++----- openerp/tools/config.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 3a9ba89c002..24ec650e432 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -117,7 +117,7 @@ class db(netsvc.ExportService): return fn(*params) def _create_empty_database(self, name): - db = sql_db.db_connect('template1') + db = sql_db.db_connect('postgres') cr = db.cursor() chosen_template = tools.config['db_template'] try: @@ -176,7 +176,7 @@ class db(netsvc.ExportService): openerp.modules.registry.RegistryManager.delete(db_name) sql_db.close_db(db_name) - db = sql_db.db_connect('template1') + db = sql_db.db_connect('postgres') cr = db.cursor() cr.autocommit(True) # avoid transaction block try: @@ -278,7 +278,7 @@ class db(netsvc.ExportService): openerp.modules.registry.RegistryManager.delete(old_name) sql_db.close_db(old_name) - db = sql_db.db_connect('template1') + db = sql_db.db_connect('postgres') cr = db.cursor() cr.autocommit(True) # avoid transaction block try: @@ -306,7 +306,7 @@ class db(netsvc.ExportService): raise openerp.exceptions.AccessDenied() chosen_template = tools.config['db_template'] templates_list = tuple(set(['template0', 'template1', 'postgres', chosen_template])) - db = sql_db.db_connect('template1') + db = sql_db.db_connect('postgres') cr = db.cursor() try: try: @@ -544,7 +544,7 @@ GNU Public Licence. return http_server.list_http_services() def exp_check_connectivity(self): - return bool(sql_db.db_connect('template1')) + return bool(sql_db.db_connect('postgres')) def exp_get_os_time(self): return os.times() diff --git a/openerp/tools/config.py b/openerp/tools/config.py index d628447a7a8..a03937601dc 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -223,7 +223,7 @@ class configmanager(object): help="specify the database port", type="int") group.add_option("--db_maxconn", dest="db_maxconn", type='int', my_default=64, help="specify the the maximum number of physical connections to posgresql") - group.add_option("--db-template", dest="db_template", my_default="template0", + group.add_option("--db-template", dest="db_template", my_default="template1", help="specify a custom database template to create a new database") parser.add_option_group(group) From d52e838455be4b038064bd9a1d972869b13257c1 Mon Sep 17 00:00:00 2001 From: Bogdan Stanciu Date: Sun, 12 Feb 2012 12:45:09 +0100 Subject: [PATCH 016/265] [IMP] some English corrections & 'encoding' into 'coding' for several py files. No code change. bzr revid: bogdanovidiu.stanciu@gmail.com-20120212114509-yrw86zewyv70dow7 --- openerp/addons/base/i18n/af.po | 4 +- openerp/addons/base/i18n/am.po | 4 +- openerp/addons/base/i18n/ar.po | 4 +- openerp/addons/base/i18n/base.pot | 4 +- openerp/addons/base/i18n/bg.po | 4 +- openerp/addons/base/i18n/bs.po | 4 +- openerp/addons/base/i18n/ca.po | 4 +- openerp/addons/base/i18n/cs.po | 4 +- openerp/addons/base/i18n/da.po | 4 +- openerp/addons/base/i18n/de.po | 4 +- openerp/addons/base/i18n/el.po | 4 +- openerp/addons/base/i18n/en_GB.po | 6 +- openerp/addons/base/i18n/es.po | 4 +- openerp/addons/base/i18n/es_AR.po | 2 +- openerp/addons/base/i18n/es_CL.po | 4 +- openerp/addons/base/i18n/es_CR.po | 4 +- openerp/addons/base/i18n/es_EC.po | 4 +- openerp/addons/base/i18n/et.po | 4 +- openerp/addons/base/i18n/eu.po | 4 +- openerp/addons/base/i18n/fa.po | 4 +- openerp/addons/base/i18n/fa_AF.po | 4 +- openerp/addons/base/i18n/fi.po | 4 +- openerp/addons/base/i18n/fr.po | 8 +-- openerp/addons/base/i18n/gl.po | 4 +- openerp/addons/base/i18n/he.po | 4 +- openerp/addons/base/i18n/hr.po | 4 +- openerp/addons/base/i18n/hu.po | 4 +- openerp/addons/base/i18n/hy.po | 4 +- openerp/addons/base/i18n/id.po | 4 +- openerp/addons/base/i18n/is.po | 4 +- openerp/addons/base/i18n/it.po | 4 +- openerp/addons/base/i18n/ja.po | 4 +- openerp/addons/base/i18n/kk.po | 4 +- openerp/addons/base/i18n/ko.po | 4 +- openerp/addons/base/i18n/lt.po | 4 +- openerp/addons/base/i18n/lt_LT.po | 2 +- openerp/addons/base/i18n/lv.po | 4 +- openerp/addons/base/i18n/mk.po | 4 +- openerp/addons/base/i18n/mn.po | 4 +- openerp/addons/base/i18n/nb.po | 4 +- openerp/addons/base/i18n/nl.po | 91 ++++++++++++-------------- openerp/addons/base/i18n/nl_BE.po | 4 +- openerp/addons/base/i18n/nl_NL.po | 2 +- openerp/addons/base/i18n/pl.po | 4 +- openerp/addons/base/i18n/pt.po | 4 +- openerp/addons/base/i18n/pt_BR.po | 8 +-- openerp/addons/base/i18n/ro.po | 4 +- openerp/addons/base/i18n/ru.po | 4 +- openerp/addons/base/i18n/sk.po | 4 +- openerp/addons/base/i18n/sl.po | 4 +- openerp/addons/base/i18n/sq.po | 4 +- openerp/addons/base/i18n/sr.po | 4 +- openerp/addons/base/i18n/sr@latin.po | 4 +- openerp/addons/base/i18n/sv.po | 4 +- openerp/addons/base/i18n/th.po | 4 +- openerp/addons/base/i18n/tlh.po | 4 +- openerp/addons/base/i18n/tr.po | 4 +- openerp/addons/base/i18n/uk.po | 4 +- openerp/addons/base/i18n/uk_UA.po | 2 +- openerp/addons/base/i18n/ur.po | 4 +- openerp/addons/base/i18n/vi.po | 4 +- openerp/addons/base/i18n/zh_CN.po | 4 +- openerp/addons/base/i18n/zh_HK.po | 4 +- openerp/addons/base/i18n/zh_TW.po | 4 +- openerp/addons/base/ir/ir_actions.py | 4 +- openerp/addons/base/res/res_country.py | 5 +- openerp/release.py | 2 +- openerp/service/http_server.py | 4 +- openerp/service/websrv_lib.py | 4 +- openerp/tools/yaml_import.py | 2 +- 70 files changed, 181 insertions(+), 185 deletions(-) diff --git a/openerp/addons/base/i18n/af.po b/openerp/addons/base/i18n/af.po index 750498c192f..10b7c035815 100644 --- a/openerp/addons/base/i18n/af.po +++ b/openerp/addons/base/i18n/af.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/am.po b/openerp/addons/base/i18n/am.po index c1e1faad680..3214ddec3a7 100644 --- a/openerp/addons/base/i18n/am.po +++ b/openerp/addons/base/i18n/am.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po index 72c254eedb6..5912643d3c0 100644 --- a/openerp/addons/base/i18n/ar.po +++ b/openerp/addons/base/i18n/ar.po @@ -795,7 +795,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5545,7 +5545,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "رمز الولاية (ثلاثة حروف).\n" #. module: base diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index 357319afe91..c1ca9862e96 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -727,7 +727,7 @@ msgstr "" #: help:ir.actions.todo,type:0 msgid "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets automatically to Done." +"Launch Manually Once: after having been launched manually, it sets automatically to Done." msgstr "" #. module: base @@ -5037,7 +5037,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." "" msgstr "" diff --git a/openerp/addons/base/i18n/bg.po b/openerp/addons/base/i18n/bg.po index b44b49136f9..5f070859688 100644 --- a/openerp/addons/base/i18n/bg.po +++ b/openerp/addons/base/i18n/bg.po @@ -797,7 +797,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5552,7 +5552,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Кодът на държавата в три букви.\n" #. module: base diff --git a/openerp/addons/base/i18n/bs.po b/openerp/addons/base/i18n/bs.po index 8b489f353b9..f4a109a9f86 100644 --- a/openerp/addons/base/i18n/bs.po +++ b/openerp/addons/base/i18n/bs.po @@ -783,7 +783,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5469,7 +5469,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ca.po b/openerp/addons/base/i18n/ca.po index e9e3c958f8f..dbcc9dd3c31 100644 --- a/openerp/addons/base/i18n/ca.po +++ b/openerp/addons/base/i18n/ca.po @@ -807,7 +807,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5641,7 +5641,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El codi de la província de 3 caràcters.\n" #. module: base diff --git a/openerp/addons/base/i18n/cs.po b/openerp/addons/base/i18n/cs.po index 9d7f5fd42da..08924e330d5 100644 --- a/openerp/addons/base/i18n/cs.po +++ b/openerp/addons/base/i18n/cs.po @@ -806,7 +806,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5635,7 +5635,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Kód státu ve třech znacích.\n" #. module: base diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po index fc56fd78eba..d4fdbe01cc4 100644 --- a/openerp/addons/base/i18n/da.po +++ b/openerp/addons/base/i18n/da.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/de.po b/openerp/addons/base/i18n/de.po index 401ede6d3f9..13f9e6f19da 100644 --- a/openerp/addons/base/i18n/de.po +++ b/openerp/addons/base/i18n/de.po @@ -813,7 +813,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "Manuell: manuell gestartet" @@ -5678,7 +5678,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Der 3 stellige Staatencode\n" #. module: base diff --git a/openerp/addons/base/i18n/el.po b/openerp/addons/base/i18n/el.po index eca0eba1ee5..9f1dc8937e1 100644 --- a/openerp/addons/base/i18n/el.po +++ b/openerp/addons/base/i18n/el.po @@ -795,7 +795,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5589,7 +5589,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Ο κωδικός κατάστασης με 3 χαρακτήρες\n" #. module: base diff --git a/openerp/addons/base/i18n/en_GB.po b/openerp/addons/base/i18n/en_GB.po index ba564da1057..2c9d775d610 100644 --- a/openerp/addons/base/i18n/en_GB.po +++ b/openerp/addons/base/i18n/en_GB.po @@ -802,7 +802,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5618,8 +5618,8 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" -msgstr "The state code in three chars.\n" +msgid "The state code in max. three chars." +msgstr "The state code in max. three chars." #. module: base #: model:res.country,name:base.sj diff --git a/openerp/addons/base/i18n/es.po b/openerp/addons/base/i18n/es.po index 697adbf8dd3..4548e2692b8 100644 --- a/openerp/addons/base/i18n/es.po +++ b/openerp/addons/base/i18n/es.po @@ -842,7 +842,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5726,7 +5726,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El código de la provincia de 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/es_AR.po b/openerp/addons/base/i18n/es_AR.po index 5f2d8cb3305..e0a1569cffe 100644 --- a/openerp/addons/base/i18n/es_AR.po +++ b/openerp/addons/base/i18n/es_AR.po @@ -5583,7 +5583,7 @@ msgstr "STOCK_MEDIA_PAUSE" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El código de la provincia de 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/es_CL.po b/openerp/addons/base/i18n/es_CL.po index 9f432778665..e3ff1de6ef3 100644 --- a/openerp/addons/base/i18n/es_CL.po +++ b/openerp/addons/base/i18n/es_CL.po @@ -811,7 +811,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5652,7 +5652,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El código de la provincia de 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/es_CR.po b/openerp/addons/base/i18n/es_CR.po index e5e6a7f4e3f..a4d9a8129d5 100644 --- a/openerp/addons/base/i18n/es_CR.po +++ b/openerp/addons/base/i18n/es_CR.po @@ -879,7 +879,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" "Manual: Lanzado manualmente.\n" @@ -6736,7 +6736,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El código de la provincia de 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po index dfd3f325733..dadcd9c0e46 100644 --- a/openerp/addons/base/i18n/es_EC.po +++ b/openerp/addons/base/i18n/es_EC.po @@ -807,7 +807,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5642,7 +5642,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "El código de la provincia de 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/et.po b/openerp/addons/base/i18n/et.po index 0ad14eaff39..7552ae0719b 100644 --- a/openerp/addons/base/i18n/et.po +++ b/openerp/addons/base/i18n/et.po @@ -788,7 +788,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5499,7 +5499,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Maakonna kolmekohaline kood.\n" #. module: base diff --git a/openerp/addons/base/i18n/eu.po b/openerp/addons/base/i18n/eu.po index f63e1b6dc4f..378c973a0eb 100644 --- a/openerp/addons/base/i18n/eu.po +++ b/openerp/addons/base/i18n/eu.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fa.po b/openerp/addons/base/i18n/fa.po index 5e55e009c97..a465ce96c3c 100644 --- a/openerp/addons/base/i18n/fa.po +++ b/openerp/addons/base/i18n/fa.po @@ -786,7 +786,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5502,7 +5502,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "کد استان در ۳ نویسه‌ای.\n" #. module: base diff --git a/openerp/addons/base/i18n/fa_AF.po b/openerp/addons/base/i18n/fa_AF.po index 2b467ff72d1..e3d0389fe01 100644 --- a/openerp/addons/base/i18n/fa_AF.po +++ b/openerp/addons/base/i18n/fa_AF.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fi.po b/openerp/addons/base/i18n/fi.po index a68401483b1..a6cb99831fb 100644 --- a/openerp/addons/base/i18n/fi.po +++ b/openerp/addons/base/i18n/fi.po @@ -799,7 +799,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5620,7 +5620,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Osavaltion koodi kolmella kirjaimella.\n" #. module: base diff --git a/openerp/addons/base/i18n/fr.po b/openerp/addons/base/i18n/fr.po index c94296d2cbd..b47d352f885 100644 --- a/openerp/addons/base/i18n/fr.po +++ b/openerp/addons/base/i18n/fr.po @@ -815,7 +815,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5653,7 +5653,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Le code état en trois caractères.\n" #. module: base @@ -11276,7 +11276,7 @@ msgstr "Séquences" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss msgid "Mss" -msgstr "Mme" +msgstr "Mlle" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11404,7 +11404,7 @@ msgstr "Filtre" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam msgid "Ms." -msgstr "Mlle" +msgstr "Mme" #. module: base #: view:base.module.import:0 diff --git a/openerp/addons/base/i18n/gl.po b/openerp/addons/base/i18n/gl.po index e166e224d57..804c17bad22 100644 --- a/openerp/addons/base/i18n/gl.po +++ b/openerp/addons/base/i18n/gl.po @@ -808,7 +808,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5635,7 +5635,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "O código de estado en tres caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/he.po b/openerp/addons/base/i18n/he.po index 191882068f0..49655e7ae5c 100644 --- a/openerp/addons/base/i18n/he.po +++ b/openerp/addons/base/i18n/he.po @@ -785,7 +785,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5487,7 +5487,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "ביטוי הקוד בשלוש תוים.\n" #. module: base diff --git a/openerp/addons/base/i18n/hr.po b/openerp/addons/base/i18n/hr.po index 65fab4e5c30..bead1791bdc 100644 --- a/openerp/addons/base/i18n/hr.po +++ b/openerp/addons/base/i18n/hr.po @@ -840,7 +840,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5646,7 +5646,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Troznamenkasta šifra države/pokrajine/županije.\n" #. module: base diff --git a/openerp/addons/base/i18n/hu.po b/openerp/addons/base/i18n/hu.po index 6894d272558..d8a699102bf 100644 --- a/openerp/addons/base/i18n/hu.po +++ b/openerp/addons/base/i18n/hu.po @@ -804,7 +804,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5625,7 +5625,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Az állam kódja három karakterben.\n" #. module: base diff --git a/openerp/addons/base/i18n/hy.po b/openerp/addons/base/i18n/hy.po index 11c3cd40faf..b7e53816cae 100644 --- a/openerp/addons/base/i18n/hy.po +++ b/openerp/addons/base/i18n/hy.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/id.po b/openerp/addons/base/i18n/id.po index a62ce35ff65..323819ab4a5 100644 --- a/openerp/addons/base/i18n/id.po +++ b/openerp/addons/base/i18n/id.po @@ -779,7 +779,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5465,7 +5465,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/is.po b/openerp/addons/base/i18n/is.po index 87a31071d27..fb292a07512 100644 --- a/openerp/addons/base/i18n/is.po +++ b/openerp/addons/base/i18n/is.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/it.po b/openerp/addons/base/i18n/it.po index c5928215769..64f7a787c29 100644 --- a/openerp/addons/base/i18n/it.po +++ b/openerp/addons/base/i18n/it.po @@ -808,7 +808,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5645,7 +5645,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Il codice dello stato in 3 caratteri\n" #. module: base diff --git a/openerp/addons/base/i18n/ja.po b/openerp/addons/base/i18n/ja.po index 84f3f3d2c55..3b727699679 100644 --- a/openerp/addons/base/i18n/ja.po +++ b/openerp/addons/base/i18n/ja.po @@ -818,7 +818,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" "手動:手動起動\n" @@ -6134,7 +6134,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/kk.po b/openerp/addons/base/i18n/kk.po index 0205a66a540..de3a57e6e0f 100644 --- a/openerp/addons/base/i18n/kk.po +++ b/openerp/addons/base/i18n/kk.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ko.po b/openerp/addons/base/i18n/ko.po index c5026451183..a4141f5d609 100644 --- a/openerp/addons/base/i18n/ko.po +++ b/openerp/addons/base/i18n/ko.po @@ -784,7 +784,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5518,7 +5518,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "3문자의 상태 코드\n" #. module: base diff --git a/openerp/addons/base/i18n/lt.po b/openerp/addons/base/i18n/lt.po index 66ff76f538c..8e0ae0d384e 100644 --- a/openerp/addons/base/i18n/lt.po +++ b/openerp/addons/base/i18n/lt.po @@ -778,7 +778,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5483,7 +5483,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Savivaldybės kodas iš trijų simbolių.\n" #. module: base diff --git a/openerp/addons/base/i18n/lt_LT.po b/openerp/addons/base/i18n/lt_LT.po index eb5c33417cd..409e6fe1bb7 100644 --- a/openerp/addons/base/i18n/lt_LT.po +++ b/openerp/addons/base/i18n/lt_LT.po @@ -5407,7 +5407,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." "" msgstr "" diff --git a/openerp/addons/base/i18n/lv.po b/openerp/addons/base/i18n/lv.po index eedaf5de4fb..9f52a9bcaf8 100644 --- a/openerp/addons/base/i18n/lv.po +++ b/openerp/addons/base/i18n/lv.po @@ -786,7 +786,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5514,7 +5514,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Stāvokļa kods, sastāvošs no trīs burtiem.\n" #. module: base diff --git a/openerp/addons/base/i18n/mk.po b/openerp/addons/base/i18n/mk.po index 0544dbb6017..e5293173930 100644 --- a/openerp/addons/base/i18n/mk.po +++ b/openerp/addons/base/i18n/mk.po @@ -786,7 +786,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5472,7 +5472,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/mn.po b/openerp/addons/base/i18n/mn.po index b3f470baadd..7e7ce75c2ed 100644 --- a/openerp/addons/base/i18n/mn.po +++ b/openerp/addons/base/i18n/mn.po @@ -789,7 +789,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5537,7 +5537,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Мужийн код гурван тэмдэгтээр.\n" #. module: base diff --git a/openerp/addons/base/i18n/nb.po b/openerp/addons/base/i18n/nb.po index 42f7fd2da30..4d21f12d3c6 100644 --- a/openerp/addons/base/i18n/nb.po +++ b/openerp/addons/base/i18n/nb.po @@ -795,7 +795,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5533,7 +5533,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Koden til staten med tre karakterer.\n" #. module: base diff --git a/openerp/addons/base/i18n/nl.po b/openerp/addons/base/i18n/nl.po index 2b9799e8fa1..32a85ba06c4 100644 --- a/openerp/addons/base/i18n/nl.po +++ b/openerp/addons/base/i18n/nl.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-02-08 00:44+0000\n" -"PO-Revision-Date: 2012-02-12 19:08+0000\n" +"PO-Revision-Date: 2012-02-11 08:55+0000\n" "Last-Translator: Mario Gielissen \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-13 04:49+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-12 04:41+0000\n" +"X-Generator: Launchpad (build 14771)\n" #. module: base #: model:res.country,name:base.sh @@ -275,7 +275,7 @@ msgstr "Inuktitut / ᐃᓄᒃᑎᑐᑦ" #: model:ir.module.category,name:base.module_category_sales_management #: model:ir.module.module,shortdesc:base.module_sale msgid "Sales Management" -msgstr "Verkoopbeheer" +msgstr "" #. module: base #: view:res.partner:0 @@ -371,7 +371,7 @@ msgstr "Naam assistent" #. module: base #: model:res.groups,name:base.group_partner_manager msgid "Partner Manager" -msgstr "Partner beheer" +msgstr "" #. module: base #: model:ir.module.category,name:base.module_category_customer_relationship_management @@ -392,7 +392,7 @@ msgstr "Ongeldige group_by" #. module: base #: field:ir.module.category,child_ids:0 msgid "Child Applications" -msgstr "Child applicaties" +msgstr "" #. module: base #: field:res.partner,credit_limit:0 @@ -402,7 +402,7 @@ msgstr "Kredietlimiet" #. module: base #: model:ir.module.module,description:base.module_web_graph msgid "Openerp web graph view" -msgstr "Openerp web grafiek view" +msgstr "" #. module: base #: field:ir.model.data,date_update:0 @@ -412,7 +412,7 @@ msgstr "Wijzigingsdatum" #. module: base #: model:ir.module.module,shortdesc:base.module_base_action_rule msgid "Automated Action Rules" -msgstr "Automatische aktie regels" +msgstr "" #. module: base #: view:ir.attachment:0 @@ -573,7 +573,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_layout msgid "Sales Orders Print Layout" -msgstr "Verkooporder Afdruk Layout" +msgstr "" #. module: base #: selection:base.language.install,lang:0 @@ -752,7 +752,7 @@ msgstr "Eritrea" #. module: base #: sql_constraint:res.company:0 msgid "The company name must be unique !" -msgstr "De naam van het bedrijf moet uniek zijn!" +msgstr "" #. module: base #: view:res.config:0 @@ -790,7 +790,7 @@ msgstr "" #. module: base #: view:ir.mail_server:0 msgid "Security and Authentication" -msgstr "Beveiliging en Authenticatie" +msgstr "" #. module: base #: view:base.language.export:0 @@ -808,7 +808,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -881,7 +881,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_document_webdav msgid "Shared Repositories (WebDAV)" -msgstr "Gedeelde Repositories (WebDAV)" +msgstr "" #. module: base #: model:ir.module.module,description:base.module_import_google @@ -1105,7 +1105,7 @@ msgstr "" #: code:addons/base/ir/ir_mail_server.py:192 #, python-format msgid "Connection test failed!" -msgstr "Verbindings test mislukt!" +msgstr "" #. module: base #: selection:ir.actions.server,state:0 @@ -1227,12 +1227,12 @@ msgstr "Spaans (GT) / Spanje (GT)" #. module: base #: field:ir.mail_server,smtp_port:0 msgid "SMTP Port" -msgstr "SMTP poort" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_import_sugarcrm msgid "SugarCRM Import" -msgstr "SugarCRM Import" +msgstr "" #. module: base #: view:res.lang:0 @@ -1249,12 +1249,12 @@ msgstr "" #: code:addons/base/module/wizard/base_language_install.py:55 #, python-format msgid "Language Pack" -msgstr "Taalpakket" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_web_tests msgid "Tests" -msgstr "Testen" +msgstr "" #. module: base #: field:ir.ui.view_sc,res_id:0 @@ -1315,7 +1315,7 @@ msgstr "" #. module: base #: field:ir.module.category,parent_id:0 msgid "Parent Application" -msgstr "Parent applicatie" +msgstr "" #. module: base #: code:addons/base/res/res_users.py:222 @@ -1332,7 +1332,7 @@ msgstr "Om een taal te exporteren, geen taal kiezen." #: model:ir.module.module,shortdesc:base.module_document #: model:ir.module.module,shortdesc:base.module_knowledge msgid "Document Management System" -msgstr "Document Beheer Systeem" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_crm_claim @@ -1596,7 +1596,7 @@ msgstr "Drijvende comma" #: model:ir.module.category,name:base.module_category_warehouse_management #: model:ir.module.module,shortdesc:base.module_stock msgid "Warehouse Management" -msgstr "Magazijnbeheer" +msgstr "" #. module: base #: model:ir.model,name:base.model_res_request_link @@ -1769,8 +1769,6 @@ msgid "" "simplified payment mode encoding, automatic picking lists generation and " "more." msgstr "" -"Helpt u het meeste te halen uit uw kassa's met snelle codering, eenvoudige " -"betaalmethode codering, automatische piklijst generatie en meer." #. module: base #: model:res.country,name:base.mv @@ -1806,28 +1804,27 @@ msgstr "Dagen" #. module: base #: model:ir.module.module,shortdesc:base.module_web_rpc msgid "OpenERP Web web" -msgstr "OpenERP Web" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_html_view msgid "Html View" -msgstr "Html weergave" +msgstr "" #. module: base #: field:res.currency,position:0 msgid "Symbol position" -msgstr "Symbool positie" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_process msgid "Enterprise Process" -msgstr "Bedrijfsprocessen" +msgstr "" #. module: base #: help:ir.cron,function:0 msgid "Name of the method to be called when this job is processed." msgstr "" -"Naam van de methode die wordt aangeroepen als deze taak wordt uitgevoerd." #. module: base #: model:ir.module.module,shortdesc:base.module_hr_evaluation @@ -1849,7 +1846,7 @@ msgstr " (kopie)" #. module: base #: field:res.company,rml_footer1:0 msgid "General Information Footer" -msgstr "Algemene Info Voettekst" +msgstr "" #. module: base #: view:res.lang:0 @@ -1956,7 +1953,7 @@ msgstr "%s (kopie)" #. module: base #: model:ir.module.module,shortdesc:base.module_account_chart msgid "Template of Charts of Accounts" -msgstr "Grootboekschema template" +msgstr "" #. module: base #: field:res.partner.address,type:0 @@ -2043,12 +2040,12 @@ msgstr "Finland" #: code:addons/base/res/res_company.py:156 #, python-format msgid "Website: " -msgstr "Website: " +msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_administration msgid "Settings" -msgstr "Voorkeuren" +msgstr "" #. module: base #: selection:ir.actions.act_window,view_type:0 @@ -2080,8 +2077,6 @@ msgid "" "Display this bank account on the footer of printed documents like invoices " "and sales orders." msgstr "" -"Laat dit bankrekeningnummer zien in de voettekst van ieder afgedrukte " -"document zoals facturen en verkooporders." #. module: base #: view:base.language.import:0 @@ -2190,7 +2185,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_subscription msgid "Recurring Documents" -msgstr "Herhalende documenten" +msgstr "" #. module: base #: model:res.country,name:base.bs @@ -2229,7 +2224,7 @@ msgstr "Aantal bijgewerkte modules" #. module: base #: field:ir.cron,function:0 msgid "Method" -msgstr "Methode" +msgstr "" #. module: base #: view:res.partner.event:0 @@ -2253,7 +2248,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_base_setup msgid "Initial Setup Tools" -msgstr "Initiële Installatie Tools" +msgstr "" #. module: base #: field:ir.actions.act_window,groups_id:0 @@ -2315,7 +2310,7 @@ msgstr "Beginpagina componenten beheer" #. module: base #: field:res.company,rml_header1:0 msgid "Report Header / Company Slogan" -msgstr "Rapporthoofd / Bedrijfs slogan" +msgstr "" #. module: base #: model:res.country,name:base.pl @@ -2368,7 +2363,7 @@ msgstr "" #. module: base #: field:ir.mail_server,smtp_debug:0 msgid "Debugging" -msgstr "Fouten opsporen" +msgstr "" #. module: base #: model:ir.module.module,description:base.module_crm_helpdesk @@ -2478,12 +2473,12 @@ msgstr "Huidige koers" #. module: base #: model:ir.module.module,shortdesc:base.module_idea msgid "Ideas" -msgstr "Ideeën" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_sale_crm msgid "Opportunity to Quotation" -msgstr "Verkoopkans naar offerte" +msgstr "" #. module: base #: model:ir.module.module,description:base.module_sale_analytic_plans @@ -2510,7 +2505,7 @@ msgstr "" #. module: base #: model:ir.actions.report.xml,name:base.report_ir_model_overview msgid "Model Overview" -msgstr "Model Overzicht" +msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_product_margin @@ -2520,7 +2515,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_invoiced msgid "Invoicing" -msgstr "Facturering" +msgstr "" #. module: base #: field:ir.ui.view_sc,name:0 @@ -2561,7 +2556,7 @@ msgstr "" #: field:ir.model.data,res_id:0 #: field:ir.values,res_id:0 msgid "Record ID" -msgstr "Record-id" +msgstr "" #. module: base #: field:ir.actions.server,email:0 @@ -2645,7 +2640,7 @@ msgstr "Fout tijdens communicatie met de uitgevers garantie server." #: model:res.groups,name:base.group_sale_manager #: model:res.groups,name:base.group_tool_manager msgid "Manager" -msgstr "Beheer" +msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_custom @@ -2682,7 +2677,7 @@ msgstr "IDs opschonen" #. module: base #: view:res.groups:0 msgid "Inherited" -msgstr "Overgeërfd" +msgstr "" #. module: base #: field:ir.model.fields,serialization_field_id:0 @@ -2705,7 +2700,7 @@ msgstr "%y - Jaar zonder eeuw [00,99]." #: code:addons/base/res/res_company.py:155 #, python-format msgid "Fax: " -msgstr "Fax: " +msgstr "" #. module: base #: model:res.country,name:base.si @@ -5644,7 +5639,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "De provinciecode in drie karakters.\n" #. module: base diff --git a/openerp/addons/base/i18n/nl_BE.po b/openerp/addons/base/i18n/nl_BE.po index 526625a6597..7b720f4511d 100644 --- a/openerp/addons/base/i18n/nl_BE.po +++ b/openerp/addons/base/i18n/nl_BE.po @@ -790,7 +790,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5476,7 +5476,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/nl_NL.po b/openerp/addons/base/i18n/nl_NL.po index 216dc70bd16..061a453645b 100644 --- a/openerp/addons/base/i18n/nl_NL.po +++ b/openerp/addons/base/i18n/nl_NL.po @@ -5598,7 +5598,7 @@ msgstr "STOCK_MEDIA_PAUSE" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "De provinciecode in drie karakters.\n" #. module: base diff --git a/openerp/addons/base/i18n/pl.po b/openerp/addons/base/i18n/pl.po index f78e5733b36..e7bd3ec9b14 100644 --- a/openerp/addons/base/i18n/pl.po +++ b/openerp/addons/base/i18n/pl.po @@ -793,7 +793,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5578,7 +5578,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Trzyliterowy kod regionu\n" #. module: base diff --git a/openerp/addons/base/i18n/pt.po b/openerp/addons/base/i18n/pt.po index edec4cffb17..fe6b53693cb 100644 --- a/openerp/addons/base/i18n/pt.po +++ b/openerp/addons/base/i18n/pt.po @@ -802,7 +802,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5567,7 +5567,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "O código do estado com três caracteres\n" #. module: base diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po index 6f1dc01c7da..8eec70f77b6 100644 --- a/openerp/addons/base/i18n/pt_BR.po +++ b/openerp/addons/base/i18n/pt_BR.po @@ -13,8 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-13 04:49+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-12 04:42+0000\n" +"X-Generator: Launchpad (build 14771)\n" #. module: base #: model:res.country,name:base.sh @@ -840,7 +840,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" "Manual: Iniciado manualmente\n" @@ -5850,7 +5850,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "O código de situação com 3 caracteres.\n" #. module: base diff --git a/openerp/addons/base/i18n/ro.po b/openerp/addons/base/i18n/ro.po index 3e947cbbfc9..27ff3506cea 100644 --- a/openerp/addons/base/i18n/ro.po +++ b/openerp/addons/base/i18n/ro.po @@ -811,7 +811,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5649,7 +5649,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Codul statului, din trei caractere.\n" #. module: base diff --git a/openerp/addons/base/i18n/ru.po b/openerp/addons/base/i18n/ru.po index 62c4e6698cd..835efe3fa58 100644 --- a/openerp/addons/base/i18n/ru.po +++ b/openerp/addons/base/i18n/ru.po @@ -806,7 +806,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5628,7 +5628,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Код области из трёх букв.\n" #. module: base diff --git a/openerp/addons/base/i18n/sk.po b/openerp/addons/base/i18n/sk.po index 46f537ae09e..c4fb21e7f70 100644 --- a/openerp/addons/base/i18n/sk.po +++ b/openerp/addons/base/i18n/sk.po @@ -792,7 +792,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5574,7 +5574,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Kód štátu na 3 znaky.\n" #. module: base diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po index a344ffba70b..0de03559923 100644 --- a/openerp/addons/base/i18n/sl.po +++ b/openerp/addons/base/i18n/sl.po @@ -801,7 +801,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5617,7 +5617,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Koda zvezne države v treh znakih.\n" #. module: base diff --git a/openerp/addons/base/i18n/sq.po b/openerp/addons/base/i18n/sq.po index 38896cd6a56..297d3f37ea9 100644 --- a/openerp/addons/base/i18n/sq.po +++ b/openerp/addons/base/i18n/sq.po @@ -774,7 +774,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5460,7 +5460,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sr.po b/openerp/addons/base/i18n/sr.po index ad02d9eec00..65f02a38fce 100644 --- a/openerp/addons/base/i18n/sr.po +++ b/openerp/addons/base/i18n/sr.po @@ -795,7 +795,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5561,7 +5561,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Šifra države u ti karaktera.\n" #. module: base diff --git a/openerp/addons/base/i18n/sr@latin.po b/openerp/addons/base/i18n/sr@latin.po index 6435154a90a..92ba916bf1a 100644 --- a/openerp/addons/base/i18n/sr@latin.po +++ b/openerp/addons/base/i18n/sr@latin.po @@ -837,7 +837,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" "Ručno: Pokrenuto ručno.\n" @@ -5644,7 +5644,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sv.po b/openerp/addons/base/i18n/sv.po index ddb985cb2a8..c9d0a27b8c9 100644 --- a/openerp/addons/base/i18n/sv.po +++ b/openerp/addons/base/i18n/sv.po @@ -797,7 +797,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5583,7 +5583,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Landskod, tre tecken\n" #. module: base diff --git a/openerp/addons/base/i18n/th.po b/openerp/addons/base/i18n/th.po index 5dc4e9d0386..0951f766fca 100644 --- a/openerp/addons/base/i18n/th.po +++ b/openerp/addons/base/i18n/th.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tlh.po b/openerp/addons/base/i18n/tlh.po index b2500e94c1e..1c087b508eb 100644 --- a/openerp/addons/base/i18n/tlh.po +++ b/openerp/addons/base/i18n/tlh.po @@ -774,7 +774,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5460,7 +5460,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tr.po b/openerp/addons/base/i18n/tr.po index 49dea1a9448..b9d1bb2a7c5 100644 --- a/openerp/addons/base/i18n/tr.po +++ b/openerp/addons/base/i18n/tr.po @@ -806,7 +806,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5662,7 +5662,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Üç karakterden oluşan eyalet kodu.\n" #. module: base diff --git a/openerp/addons/base/i18n/uk.po b/openerp/addons/base/i18n/uk.po index 8a22baa55ba..1ded396d476 100644 --- a/openerp/addons/base/i18n/uk.po +++ b/openerp/addons/base/i18n/uk.po @@ -796,7 +796,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5507,7 +5507,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "Код області довжиною в три букви.\n" #. module: base diff --git a/openerp/addons/base/i18n/uk_UA.po b/openerp/addons/base/i18n/uk_UA.po index a33cdf8b473..87fbfe76e2b 100644 --- a/openerp/addons/base/i18n/uk_UA.po +++ b/openerp/addons/base/i18n/uk_UA.po @@ -5424,7 +5424,7 @@ msgstr "STOCK_MEDIA_PAUSE" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." "" msgstr "" diff --git a/openerp/addons/base/i18n/ur.po b/openerp/addons/base/i18n/ur.po index b9467f4518a..a45da1f2dad 100644 --- a/openerp/addons/base/i18n/ur.po +++ b/openerp/addons/base/i18n/ur.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/vi.po b/openerp/addons/base/i18n/vi.po index d12ece2051f..d8e03b80386 100644 --- a/openerp/addons/base/i18n/vi.po +++ b/openerp/addons/base/i18n/vi.po @@ -799,7 +799,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5490,7 +5490,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_CN.po b/openerp/addons/base/i18n/zh_CN.po index fe7a5cc0aaa..7b618b1e0e5 100644 --- a/openerp/addons/base/i18n/zh_CN.po +++ b/openerp/addons/base/i18n/zh_CN.po @@ -821,7 +821,7 @@ msgstr "OpenERP的翻译在Launchpad.net网站上进行,OpenERP项目本身也 msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" "手动:手动执行\n" @@ -5895,7 +5895,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "三个字符的省/州代码\n" #. module: base diff --git a/openerp/addons/base/i18n/zh_HK.po b/openerp/addons/base/i18n/zh_HK.po index 30dc4956d39..06a099c2196 100644 --- a/openerp/addons/base/i18n/zh_HK.po +++ b/openerp/addons/base/i18n/zh_HK.po @@ -775,7 +775,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5461,7 +5461,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_TW.po b/openerp/addons/base/i18n/zh_TW.po index cacb85a6f34..5b6c6c37767 100644 --- a/openerp/addons/base/i18n/zh_TW.po +++ b/openerp/addons/base/i18n/zh_TW.po @@ -779,7 +779,7 @@ msgstr "" msgid "" "Manual: Launched manually.\n" "Automatic: Runs whenever the system is reconfigured.\n" -"Launch Manually Once: after hacing been launched manually, it sets " +"Launch Manually Once: after having been launched manually, it sets " "automatically to Done." msgstr "" @@ -5470,7 +5470,7 @@ msgstr "" #. module: base #: help:res.country.state,code:0 -msgid "The state code in three chars.\n" +msgid "The state code in max. three chars." msgstr "三個字元之省或州代碼\n" #. module: base diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 236c6af7119..0a282503570 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -619,7 +619,7 @@ class actions_server(osv.osv): # ids : original ids # id : current id of the object # OUT: - # False : Finnished correctly + # False : Finished correctly # ACTION_ID : Action to launch # FIXME: refactor all the eval() calls in run()! @@ -831,7 +831,7 @@ class ir_actions_todo(osv.osv): 'type': fields.selection(TODO_TYPES, 'Type', required=True, help="""Manual: Launched manually. Automatic: Runs whenever the system is reconfigured. -Launch Manually Once: after hacing been launched manually, it sets automatically to Done."""), +Launch Manually Once: after having been launched manually, it sets automatically to Done."""), 'groups_id': fields.many2many('res.groups', 'res_groups_action_rel', 'uid', 'gid', 'Groups'), 'note': fields.text('Text', translate=True), 'category_id': fields.many2one('ir.actions.todo.category','Category'), diff --git a/openerp/addons/base/res/res_country.py b/openerp/addons/base/res/res_country.py index f240784dc47..d0269dd4df1 100644 --- a/openerp/addons/base/res/res_country.py +++ b/openerp/addons/base/res/res_country.py @@ -86,9 +86,10 @@ class CountryState(osv.osv): _columns = { 'country_id': fields.many2one('res.country', 'Country', required=True), - 'name': fields.char('State Name', size=64, required=True), + 'name': fields.char('State Name', size=64, required=True, + help='Administrative divisions of a country. E.g. Fed. State, Departement, Canton'), 'code': fields.char('State Code', size=3, - help='The state code in three chars.\n', required=True), + help='The state code in max. three chars.', required=True), } def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100): diff --git a/openerp/release.py b/openerp/release.py index bd3935713b9..1f573c54814 100644 --- a/openerp/release.py +++ b/openerp/release.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py index 07e31ea9c7d..5fb46b42ffc 100644 --- a/openerp/service/http_server.py +++ b/openerp/service/http_server.py @@ -5,10 +5,10 @@ # # # WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability of assessing all potential +# programmers who take the whole responsibility of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software +# guarantees and support are strongly advised to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or diff --git a/openerp/service/websrv_lib.py b/openerp/service/websrv_lib.py index 4da6536ed51..d9f654f4edb 100644 --- a/openerp/service/websrv_lib.py +++ b/openerp/service/websrv_lib.py @@ -3,10 +3,10 @@ # Copyright P. Christeas 2008-2010 # # WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability of assessing all potential +# programmers who take the whole responsibility of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software +# guarantees and support are strongly advised to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index c36376ba1b7..1c676e3a1c6 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- import threading import types import time # used to eval time.strftime expressions From 0ea407eb5ab51e604ad5550d8d0672bd659a3a73 Mon Sep 17 00:00:00 2001 From: Bogdan Stanciu Date: Sun, 12 Feb 2012 12:48:12 +0100 Subject: [PATCH 017/265] [IMP] added two address formats (CH and RO) bzr revid: bogdanovidiu.stanciu@gmail.com-20120212114812-dbt4jy0jxisn55x8 --- openerp/addons/base/base_data.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml index 03e62dd6ba6..1c4e7fc639b 100644 --- a/openerp/addons/base/base_data.xml +++ b/openerp/addons/base/base_data.xml @@ -197,6 +197,7 @@ Switzerland ch + Ivory Coast (Cote D'Ivoire) @@ -767,6 +768,7 @@ Romania ro + Russian Federation From 434af1f37af3267797a08b65b4c39ce132bbad4e Mon Sep 17 00:00:00 2001 From: Bogdan Stanciu Date: Sun, 12 Feb 2012 13:25:57 +0100 Subject: [PATCH 018/265] [IMP] corrected a few titles vs. "shortcuts" and added three titles to res.partner.title bzr revid: bogdanovidiu.stanciu@gmail.com-20120212122557-6od8yipxs6bp31ht --- openerp/addons/base/i18n/af.po | 6 ++-- openerp/addons/base/i18n/am.po | 6 ++-- openerp/addons/base/i18n/ar.po | 6 ++-- openerp/addons/base/i18n/base.pot | 35 ++++++++++++++++++-- openerp/addons/base/i18n/bg.po | 8 ++--- openerp/addons/base/i18n/bs.po | 6 ++-- openerp/addons/base/i18n/ca.po | 6 ++-- openerp/addons/base/i18n/cs.po | 8 ++--- openerp/addons/base/i18n/da.po | 6 ++-- openerp/addons/base/i18n/de.po | 6 ++-- openerp/addons/base/i18n/el.po | 6 ++-- openerp/addons/base/i18n/en_GB.po | 12 +++---- openerp/addons/base/i18n/es.po | 6 ++-- openerp/addons/base/i18n/es_CL.po | 6 ++-- openerp/addons/base/i18n/es_CR.po | 6 ++-- openerp/addons/base/i18n/es_EC.po | 10 +++--- openerp/addons/base/i18n/et.po | 6 ++-- openerp/addons/base/i18n/eu.po | 6 ++-- openerp/addons/base/i18n/fa.po | 6 ++-- openerp/addons/base/i18n/fa_AF.po | 6 ++-- openerp/addons/base/i18n/fi.po | 8 ++--- openerp/addons/base/i18n/fr.po | 6 ++-- openerp/addons/base/i18n/gl.po | 10 +++--- openerp/addons/base/i18n/he.po | 6 ++-- openerp/addons/base/i18n/hr.po | 6 ++-- openerp/addons/base/i18n/hu.po | 10 +++--- openerp/addons/base/i18n/hy.po | 6 ++-- openerp/addons/base/i18n/id.po | 6 ++-- openerp/addons/base/i18n/is.po | 6 ++-- openerp/addons/base/i18n/it.po | 10 +++--- openerp/addons/base/i18n/ja.po | 6 ++-- openerp/addons/base/i18n/kk.po | 6 ++-- openerp/addons/base/i18n/ko.po | 6 ++-- openerp/addons/base/i18n/lt.po | 6 ++-- openerp/addons/base/i18n/lv.po | 6 ++-- openerp/addons/base/i18n/mk.po | 6 ++-- openerp/addons/base/i18n/mn.po | 8 ++--- openerp/addons/base/i18n/nb.po | 8 ++--- openerp/addons/base/i18n/nl.po | 6 ++-- openerp/addons/base/i18n/nl_BE.po | 6 ++-- openerp/addons/base/i18n/pl.po | 6 ++-- openerp/addons/base/i18n/pt.po | 6 ++-- openerp/addons/base/i18n/pt_BR.po | 8 ++--- openerp/addons/base/i18n/ro.po | 6 ++-- openerp/addons/base/i18n/ru.po | 6 ++-- openerp/addons/base/i18n/sk.po | 6 ++-- openerp/addons/base/i18n/sl.po | 6 ++-- openerp/addons/base/i18n/sq.po | 6 ++-- openerp/addons/base/i18n/sr.po | 12 +++---- openerp/addons/base/i18n/sr@latin.po | 6 ++-- openerp/addons/base/i18n/sv.po | 8 ++--- openerp/addons/base/i18n/th.po | 6 ++-- openerp/addons/base/i18n/tlh.po | 6 ++-- openerp/addons/base/i18n/tr.po | 8 ++--- openerp/addons/base/i18n/uk.po | 6 ++-- openerp/addons/base/i18n/ur.po | 6 ++-- openerp/addons/base/i18n/vi.po | 6 ++-- openerp/addons/base/i18n/zh_CN.po | 8 ++--- openerp/addons/base/i18n/zh_HK.po | 6 ++-- openerp/addons/base/i18n/zh_TW.po | 6 ++-- openerp/addons/base/res/res_partner_data.xml | 21 ++++++++++-- 61 files changed, 250 insertions(+), 206 deletions(-) diff --git a/openerp/addons/base/i18n/af.po b/openerp/addons/base/i18n/af.po index 10b7c035815..5b00d0558af 100644 --- a/openerp/addons/base/i18n/af.po +++ b/openerp/addons/base/i18n/af.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/am.po b/openerp/addons/base/i18n/am.po index 3214ddec3a7..b1e142e769b 100644 --- a/openerp/addons/base/i18n/am.po +++ b/openerp/addons/base/i18n/am.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po index 5912643d3c0..98baaf19bf1 100644 --- a/openerp/addons/base/i18n/ar.po +++ b/openerp/addons/base/i18n/ar.po @@ -3745,7 +3745,7 @@ msgstr "GPL-2 أو إصدار أحدث" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11110,7 +11110,7 @@ msgstr "المتواليات" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11233,7 +11233,7 @@ msgstr "مرشح الفرز" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "السيدة" #. module: base diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index c1ca9862e96..0a97521219b 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -3430,7 +3430,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Sir" msgstr "" #. module: base @@ -10134,7 +10134,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -10249,7 +10249,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base @@ -11306,6 +11306,35 @@ msgstr "" msgid "Madam" msgstr "" +#. module: base +#: model:res.partner.title,name:base.res_partner_title_mister +msgid "Mister" +msgstr "" +#. module: base +#: model:res.partner.title,name:base.res_partner_title_doctor +msgid "Doctor" +msgstr "" +#. module: base +#: model:res.partner.title,name:base.res_partner_title_prof +msgid "Professor" +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_mister +msgid "Mr." +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_doctor +msgid "Dr." +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_prof +msgid "Prof." +msgstr "" + + #. module: base #: model:res.country,name:base.ee msgid "Estonia" diff --git a/openerp/addons/base/i18n/bg.po b/openerp/addons/base/i18n/bg.po index 5f070859688..327c1e65c8a 100644 --- a/openerp/addons/base/i18n/bg.po +++ b/openerp/addons/base/i18n/bg.po @@ -3751,8 +3751,8 @@ msgstr "GPL версия 2 или по-нова" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11115,7 +11115,7 @@ msgstr "Последователност" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11235,7 +11235,7 @@ msgstr "Филтър" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Г-жа" #. module: base diff --git a/openerp/addons/base/i18n/bs.po b/openerp/addons/base/i18n/bs.po index f4a109a9f86..bdf09238918 100644 --- a/openerp/addons/base/i18n/bs.po +++ b/openerp/addons/base/i18n/bs.po @@ -3690,7 +3690,7 @@ msgstr "GPL-2 ili novija verzija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11003,7 +11003,7 @@ msgstr "Sekvence" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11123,7 +11123,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ca.po b/openerp/addons/base/i18n/ca.po index dbcc9dd3c31..f4d57a65484 100644 --- a/openerp/addons/base/i18n/ca.po +++ b/openerp/addons/base/i18n/ca.po @@ -3805,7 +3805,7 @@ msgstr "GPL-2 o versió posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Sr." #. module: base @@ -11259,7 +11259,7 @@ msgstr "Seqüències" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Sra." #. module: base @@ -11385,7 +11385,7 @@ msgstr "Filtre" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/cs.po b/openerp/addons/base/i18n/cs.po index 08924e330d5..a72e16f34dc 100644 --- a/openerp/addons/base/i18n/cs.po +++ b/openerp/addons/base/i18n/cs.po @@ -3822,8 +3822,8 @@ msgstr "GPL-2 nebo pozdější verze" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11233,7 +11233,7 @@ msgstr "Posloupnosti" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Paní" #. module: base @@ -11355,7 +11355,7 @@ msgstr "Filtr" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Pan" #. module: base diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po index d4fdbe01cc4..53663056459 100644 --- a/openerp/addons/base/i18n/da.po +++ b/openerp/addons/base/i18n/da.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "Sekvenser" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/de.po b/openerp/addons/base/i18n/de.po index 13f9e6f19da..40bcd5b9b72 100644 --- a/openerp/addons/base/i18n/de.po +++ b/openerp/addons/base/i18n/de.po @@ -3835,7 +3835,7 @@ msgstr "GPL-2 oder höher" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Hr." #. module: base @@ -11360,7 +11360,7 @@ msgstr "Sequenzen" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Frau" #. module: base @@ -11485,7 +11485,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Frau" #. module: base diff --git a/openerp/addons/base/i18n/el.po b/openerp/addons/base/i18n/el.po index 9f1dc8937e1..22febb8de85 100644 --- a/openerp/addons/base/i18n/el.po +++ b/openerp/addons/base/i18n/el.po @@ -3776,7 +3776,7 @@ msgstr "GPL-2 ή μεταγενέστερη έκδοση" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11159,7 +11159,7 @@ msgstr "Ιεραρχήσεις" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11281,7 +11281,7 @@ msgstr "Φίλτρο" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Κα/Δς" #. module: base diff --git a/openerp/addons/base/i18n/en_GB.po b/openerp/addons/base/i18n/en_GB.po index 2c9d775d610..bc509103502 100644 --- a/openerp/addons/base/i18n/en_GB.po +++ b/openerp/addons/base/i18n/en_GB.po @@ -3790,8 +3790,8 @@ msgstr "GPL-2 or later version" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11221,8 +11221,8 @@ msgstr "Sequences" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11346,8 +11346,8 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." -msgstr "Ms." +msgid "Mrs." +msgstr "Mrs." #. module: base #: view:base.module.import:0 diff --git a/openerp/addons/base/i18n/es.po b/openerp/addons/base/i18n/es.po index 4548e2692b8..5ebd7d1a0dc 100644 --- a/openerp/addons/base/i18n/es.po +++ b/openerp/addons/base/i18n/es.po @@ -3887,7 +3887,7 @@ msgstr "GPL-2 o versión posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Sr." #. module: base @@ -11344,7 +11344,7 @@ msgstr "Secuencias" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Sra." #. module: base @@ -11471,7 +11471,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/es_CL.po b/openerp/addons/base/i18n/es_CL.po index e3ff1de6ef3..c87eb21ac41 100644 --- a/openerp/addons/base/i18n/es_CL.po +++ b/openerp/addons/base/i18n/es_CL.po @@ -3813,7 +3813,7 @@ msgstr "GPL-2 o versión posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Sr." #. module: base @@ -11270,7 +11270,7 @@ msgstr "Secuencias" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Sra." #. module: base @@ -11397,7 +11397,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/es_CR.po b/openerp/addons/base/i18n/es_CR.po index a4d9a8129d5..913775326c7 100644 --- a/openerp/addons/base/i18n/es_CR.po +++ b/openerp/addons/base/i18n/es_CR.po @@ -4442,7 +4442,7 @@ msgstr "GPL-2 o versión posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Sr." #. module: base @@ -13818,7 +13818,7 @@ msgstr "Secuencias" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Sra." #. module: base @@ -13945,7 +13945,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po index dadcd9c0e46..e81781da452 100644 --- a/openerp/addons/base/i18n/es_EC.po +++ b/openerp/addons/base/i18n/es_EC.po @@ -3805,8 +3805,8 @@ msgstr "GPL-2 o versión posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11264,8 +11264,8 @@ msgstr "Secuencias" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11391,7 +11391,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/et.po b/openerp/addons/base/i18n/et.po index 7552ae0719b..f2457c654a4 100644 --- a/openerp/addons/base/i18n/et.po +++ b/openerp/addons/base/i18n/et.po @@ -3713,7 +3713,7 @@ msgstr "GPL-2 või hilisem versioon" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11043,7 +11043,7 @@ msgstr "Jadad" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11163,7 +11163,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/eu.po b/openerp/addons/base/i18n/eu.po index 378c973a0eb..92667018edb 100644 --- a/openerp/addons/base/i18n/eu.po +++ b/openerp/addons/base/i18n/eu.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fa.po b/openerp/addons/base/i18n/fa.po index a465ce96c3c..c1a94fc9ce1 100644 --- a/openerp/addons/base/i18n/fa.po +++ b/openerp/addons/base/i18n/fa.po @@ -3715,7 +3715,7 @@ msgstr "مجوز GPL-2 یا نگارش بالاتر" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11048,7 +11048,7 @@ msgstr "دنباله‌ها" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11168,7 +11168,7 @@ msgstr "پالایه" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fa_AF.po b/openerp/addons/base/i18n/fa_AF.po index e3d0389fe01..27e99d07a6c 100644 --- a/openerp/addons/base/i18n/fa_AF.po +++ b/openerp/addons/base/i18n/fa_AF.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fi.po b/openerp/addons/base/i18n/fi.po index a6cb99831fb..3b27c52ae46 100644 --- a/openerp/addons/base/i18n/fi.po +++ b/openerp/addons/base/i18n/fi.po @@ -3793,7 +3793,7 @@ msgstr "GPL-2 tai myöhäisempi versio" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11226,7 +11226,7 @@ msgstr "Jaksot" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11352,8 +11352,8 @@ msgstr "Suodin" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." -msgstr "Ms." +msgid "Mrs." +msgstr "Mrs." #. module: base #: view:base.module.import:0 diff --git a/openerp/addons/base/i18n/fr.po b/openerp/addons/base/i18n/fr.po index b47d352f885..975b97a543f 100644 --- a/openerp/addons/base/i18n/fr.po +++ b/openerp/addons/base/i18n/fr.po @@ -3817,7 +3817,7 @@ msgstr "GPL-2 ou version supérieure" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "M." #. module: base @@ -11275,7 +11275,7 @@ msgstr "Séquences" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Mlle" #. module: base @@ -11403,7 +11403,7 @@ msgstr "Filtre" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Mme" #. module: base diff --git a/openerp/addons/base/i18n/gl.po b/openerp/addons/base/i18n/gl.po index 804c17bad22..66b56a02246 100644 --- a/openerp/addons/base/i18n/gl.po +++ b/openerp/addons/base/i18n/gl.po @@ -3805,8 +3805,8 @@ msgstr "GPL-2 ou versión posterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11245,8 +11245,8 @@ msgstr "Secuencias" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "MSS" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11372,7 +11372,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Ms" #. module: base diff --git a/openerp/addons/base/i18n/he.po b/openerp/addons/base/i18n/he.po index 49655e7ae5c..6d1a3501066 100644 --- a/openerp/addons/base/i18n/he.po +++ b/openerp/addons/base/i18n/he.po @@ -3702,7 +3702,7 @@ msgstr "גרסא GPL-2 או מאוחרת יותר." #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11030,7 +11030,7 @@ msgstr "רציפות" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11150,7 +11150,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/hr.po b/openerp/addons/base/i18n/hr.po index bead1791bdc..4460921847e 100644 --- a/openerp/addons/base/i18n/hr.po +++ b/openerp/addons/base/i18n/hr.po @@ -3835,7 +3835,7 @@ msgstr "GPL-2 ili novija verzija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "g." #. module: base @@ -11218,7 +11218,7 @@ msgstr "Sekvence" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "gđica" #. module: base @@ -11344,7 +11344,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "gđa." #. module: base diff --git a/openerp/addons/base/i18n/hu.po b/openerp/addons/base/i18n/hu.po index d8a699102bf..5d20eb6f771 100644 --- a/openerp/addons/base/i18n/hu.po +++ b/openerp/addons/base/i18n/hu.po @@ -3792,7 +3792,7 @@ msgstr "GPL-2 vagy korábbi verzió" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Úr" #. module: base @@ -11243,8 +11243,8 @@ msgstr "Sorszámok" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11372,8 +11372,8 @@ msgstr "Szűrő" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." -msgstr "Ms." +msgid "Mrs." +msgstr "Mrs." #. module: base #: view:base.module.import:0 diff --git a/openerp/addons/base/i18n/hy.po b/openerp/addons/base/i18n/hy.po index b7e53816cae..9984f2c03f4 100644 --- a/openerp/addons/base/i18n/hy.po +++ b/openerp/addons/base/i18n/hy.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/id.po b/openerp/addons/base/i18n/id.po index 323819ab4a5..cc5113f856f 100644 --- a/openerp/addons/base/i18n/id.po +++ b/openerp/addons/base/i18n/id.po @@ -3686,7 +3686,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10999,7 +10999,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11119,7 +11119,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/is.po b/openerp/addons/base/i18n/is.po index fb292a07512..425ea2516db 100644 --- a/openerp/addons/base/i18n/is.po +++ b/openerp/addons/base/i18n/is.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/it.po b/openerp/addons/base/i18n/it.po index 64f7a787c29..40f6a45e2ff 100644 --- a/openerp/addons/base/i18n/it.po +++ b/openerp/addons/base/i18n/it.po @@ -3810,8 +3810,8 @@ msgstr "GPL-2 o successiva" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11265,8 +11265,8 @@ msgstr "Sequenze" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11392,7 +11392,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sig.ra" #. module: base diff --git a/openerp/addons/base/i18n/ja.po b/openerp/addons/base/i18n/ja.po index 3b727699679..00064377974 100644 --- a/openerp/addons/base/i18n/ja.po +++ b/openerp/addons/base/i18n/ja.po @@ -4096,7 +4096,7 @@ msgstr "GPL-2 またはそれ以降のバージョン" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11674,7 +11674,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11794,7 +11794,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/kk.po b/openerp/addons/base/i18n/kk.po index de3a57e6e0f..70c941b9aa6 100644 --- a/openerp/addons/base/i18n/kk.po +++ b/openerp/addons/base/i18n/kk.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "Сүзгі" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "миссис" #. module: base diff --git a/openerp/addons/base/i18n/ko.po b/openerp/addons/base/i18n/ko.po index a4141f5d609..8fd9331052c 100644 --- a/openerp/addons/base/i18n/ko.po +++ b/openerp/addons/base/i18n/ko.po @@ -3729,7 +3729,7 @@ msgstr "GPL-2 또는 이후 버젼" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11056,7 +11056,7 @@ msgstr "시퀀스" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11176,7 +11176,7 @@ msgstr "필터" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/lt.po b/openerp/addons/base/i18n/lt.po index 8e0ae0d384e..821b0705ff5 100644 --- a/openerp/addons/base/i18n/lt.po +++ b/openerp/addons/base/i18n/lt.po @@ -3694,7 +3694,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11029,7 +11029,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11149,7 +11149,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Ponia" #. module: base diff --git a/openerp/addons/base/i18n/lv.po b/openerp/addons/base/i18n/lv.po index 9f52a9bcaf8..1402da79c00 100644 --- a/openerp/addons/base/i18n/lv.po +++ b/openerp/addons/base/i18n/lv.po @@ -3717,7 +3717,7 @@ msgstr "GPL-2 vai vēlāka versija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11063,7 +11063,7 @@ msgstr "Sērijas" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11183,7 +11183,7 @@ msgstr "Filtrs" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/mk.po b/openerp/addons/base/i18n/mk.po index e5293173930..83994f31964 100644 --- a/openerp/addons/base/i18n/mk.po +++ b/openerp/addons/base/i18n/mk.po @@ -3693,7 +3693,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11006,7 +11006,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11126,7 +11126,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/mn.po b/openerp/addons/base/i18n/mn.po index 7e7ce75c2ed..1f58def2e90 100644 --- a/openerp/addons/base/i18n/mn.po +++ b/openerp/addons/base/i18n/mn.po @@ -3746,8 +3746,8 @@ msgstr "GPL-2 болон дараагийн хувилбар" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11086,7 +11086,7 @@ msgstr "Дараалал" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Хатагтай" #. module: base @@ -11207,7 +11207,7 @@ msgstr "Шүүлт" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Хатагтай." #. module: base diff --git a/openerp/addons/base/i18n/nb.po b/openerp/addons/base/i18n/nb.po index 4d21f12d3c6..91fa3298775 100644 --- a/openerp/addons/base/i18n/nb.po +++ b/openerp/addons/base/i18n/nb.po @@ -3734,8 +3734,8 @@ msgstr "GPL-2 eller senere versjon" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11081,7 +11081,7 @@ msgstr "Sekvenser" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11201,7 +11201,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/nl.po b/openerp/addons/base/i18n/nl.po index 32a85ba06c4..311d04e0a54 100644 --- a/openerp/addons/base/i18n/nl.po +++ b/openerp/addons/base/i18n/nl.po @@ -3800,7 +3800,7 @@ msgstr "GPL-2 of latere versie" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Hr." #. module: base @@ -11252,7 +11252,7 @@ msgstr "Reeksen" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Mej." #. module: base @@ -11379,7 +11379,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Mw." #. module: base diff --git a/openerp/addons/base/i18n/nl_BE.po b/openerp/addons/base/i18n/nl_BE.po index 7b720f4511d..d9fcfaa86af 100644 --- a/openerp/addons/base/i18n/nl_BE.po +++ b/openerp/addons/base/i18n/nl_BE.po @@ -3697,7 +3697,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11010,7 +11010,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11130,7 +11130,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/pl.po b/openerp/addons/base/i18n/pl.po index e7bd3ec9b14..5e6569da9d7 100644 --- a/openerp/addons/base/i18n/pl.po +++ b/openerp/addons/base/i18n/pl.po @@ -3761,7 +3761,7 @@ msgstr "GPL-2 lub wersja późniejsza" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11159,7 +11159,7 @@ msgstr "Numeracje" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11281,7 +11281,7 @@ msgstr "Filtr" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Pani" #. module: base diff --git a/openerp/addons/base/i18n/pt.po b/openerp/addons/base/i18n/pt.po index fe6b53693cb..92315dee4ef 100644 --- a/openerp/addons/base/i18n/pt.po +++ b/openerp/addons/base/i18n/pt.po @@ -3757,7 +3757,7 @@ msgstr "GPL-2 ou version anterior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11162,7 +11162,7 @@ msgstr "Sequências" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11284,7 +11284,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Srª." #. module: base diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po index 8eec70f77b6..51e34a6e9be 100644 --- a/openerp/addons/base/i18n/pt_BR.po +++ b/openerp/addons/base/i18n/pt_BR.po @@ -3975,8 +3975,8 @@ msgstr "GPL-2 ou versão superior" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11709,7 +11709,7 @@ msgstr "Seqüências" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Sra" #. module: base @@ -11836,7 +11836,7 @@ msgstr "Filtro" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Sra." #. module: base diff --git a/openerp/addons/base/i18n/ro.po b/openerp/addons/base/i18n/ro.po index 27ff3506cea..2cbc45fb22d 100644 --- a/openerp/addons/base/i18n/ro.po +++ b/openerp/addons/base/i18n/ro.po @@ -3812,7 +3812,7 @@ msgstr "GPL-2 sau versiune mai nouă" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Dl." #. module: base @@ -11271,7 +11271,7 @@ msgstr "Secvențe" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "D-ra" #. module: base @@ -11399,7 +11399,7 @@ msgstr "Filtru" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Dna." #. module: base diff --git a/openerp/addons/base/i18n/ru.po b/openerp/addons/base/i18n/ru.po index 835efe3fa58..57ac744865d 100644 --- a/openerp/addons/base/i18n/ru.po +++ b/openerp/addons/base/i18n/ru.po @@ -3794,7 +3794,7 @@ msgstr "GPL версии 2 или более поздней" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "Г-н" #. module: base @@ -11243,7 +11243,7 @@ msgstr "Нумерация" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Г-жа" #. module: base @@ -11369,7 +11369,7 @@ msgstr "Фильтр" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Г-жа" #. module: base diff --git a/openerp/addons/base/i18n/sk.po b/openerp/addons/base/i18n/sk.po index c4fb21e7f70..c8f621a6ed8 100644 --- a/openerp/addons/base/i18n/sk.po +++ b/openerp/addons/base/i18n/sk.po @@ -3760,7 +3760,7 @@ msgstr "GPL-2 alebo novšia verzia" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "pán" #. module: base @@ -11163,7 +11163,7 @@ msgstr "Postupnosti" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "slečna" #. module: base @@ -11290,7 +11290,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "pani" #. module: base diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po index 0de03559923..45d82a64cd1 100644 --- a/openerp/addons/base/i18n/sl.po +++ b/openerp/addons/base/i18n/sl.po @@ -3789,7 +3789,7 @@ msgstr "GPL-2 ali naslednja verzija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "G." #. module: base @@ -11220,7 +11220,7 @@ msgstr "Zaporedja" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Gospodična" #. module: base @@ -11348,7 +11348,7 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Ga." #. module: base diff --git a/openerp/addons/base/i18n/sq.po b/openerp/addons/base/i18n/sq.po index 297d3f37ea9..6637361df72 100644 --- a/openerp/addons/base/i18n/sq.po +++ b/openerp/addons/base/i18n/sq.po @@ -3681,7 +3681,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10994,7 +10994,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11114,7 +11114,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sr.po b/openerp/addons/base/i18n/sr.po index 65f02a38fce..61d5fa09aff 100644 --- a/openerp/addons/base/i18n/sr.po +++ b/openerp/addons/base/i18n/sr.po @@ -3758,8 +3758,8 @@ msgstr "GPL-2 ili novija verzija" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11139,8 +11139,8 @@ msgstr "Sekvence" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11259,8 +11259,8 @@ msgstr "Filter" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." -msgstr "Ms." +msgid "Mrs." +msgstr "Mrs." #. module: base #: view:base.module.import:0 diff --git a/openerp/addons/base/i18n/sr@latin.po b/openerp/addons/base/i18n/sr@latin.po index 92ba916bf1a..114337effd1 100644 --- a/openerp/addons/base/i18n/sr@latin.po +++ b/openerp/addons/base/i18n/sr@latin.po @@ -3865,7 +3865,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11178,7 +11178,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11298,7 +11298,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sv.po b/openerp/addons/base/i18n/sv.po index c9d0a27b8c9..352e6ba4513 100644 --- a/openerp/addons/base/i18n/sv.po +++ b/openerp/addons/base/i18n/sv.po @@ -3768,8 +3768,8 @@ msgstr "GPL-2 eller senare version" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11176,7 +11176,7 @@ msgstr "Nummerserier" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Fru" #. module: base @@ -11300,7 +11300,7 @@ msgstr "Filtrera" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Frk." #. module: base diff --git a/openerp/addons/base/i18n/th.po b/openerp/addons/base/i18n/th.po index 0951f766fca..d91bddb206b 100644 --- a/openerp/addons/base/i18n/th.po +++ b/openerp/addons/base/i18n/th.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "ลำดับ" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tlh.po b/openerp/addons/base/i18n/tlh.po index 1c087b508eb..60cf53c393f 100644 --- a/openerp/addons/base/i18n/tlh.po +++ b/openerp/addons/base/i18n/tlh.po @@ -3681,7 +3681,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10994,7 +10994,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11114,7 +11114,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tr.po b/openerp/addons/base/i18n/tr.po index b9d1bb2a7c5..9ec92ff00cd 100644 --- a/openerp/addons/base/i18n/tr.po +++ b/openerp/addons/base/i18n/tr.po @@ -3824,8 +3824,8 @@ msgstr "GPL-2 veya sonraki sürümü" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." -msgstr "M." +msgid "Mr." +msgstr "Mr." #. module: base #: code:addons/base/module/module.py:519 @@ -11280,7 +11280,7 @@ msgstr "Silsileler" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "Bayan" #. module: base @@ -11404,7 +11404,7 @@ msgstr "Süzgeç" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "Bayan" #. module: base diff --git a/openerp/addons/base/i18n/uk.po b/openerp/addons/base/i18n/uk.po index 1ded396d476..f42d5e2d0e1 100644 --- a/openerp/addons/base/i18n/uk.po +++ b/openerp/addons/base/i18n/uk.po @@ -3717,7 +3717,7 @@ msgstr "GPL-2 або пізніша версія" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11046,7 +11046,7 @@ msgstr "Послідовності" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11166,7 +11166,7 @@ msgstr "Фільтр" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ur.po b/openerp/addons/base/i18n/ur.po index a45da1f2dad..582ee6bd2c5 100644 --- a/openerp/addons/base/i18n/ur.po +++ b/openerp/addons/base/i18n/ur.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/vi.po b/openerp/addons/base/i18n/vi.po index d8e03b80386..35e1c2cc32f 100644 --- a/openerp/addons/base/i18n/vi.po +++ b/openerp/addons/base/i18n/vi.po @@ -3709,7 +3709,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11028,7 +11028,7 @@ msgstr "Sequences" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11150,7 +11150,7 @@ msgstr "Bộ lọc" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_CN.po b/openerp/addons/base/i18n/zh_CN.po index 7b618b1e0e5..8a1ffd6136a 100644 --- a/openerp/addons/base/i18n/zh_CN.po +++ b/openerp/addons/base/i18n/zh_CN.po @@ -4081,7 +4081,7 @@ msgstr "GPL-2 或更新版本" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "先生" #. module: base @@ -11468,8 +11468,8 @@ msgstr "序列" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" -msgstr "Mss" +msgid "Miss" +msgstr "Miss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -11588,7 +11588,7 @@ msgstr "过滤" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "女士" #. module: base diff --git a/openerp/addons/base/i18n/zh_HK.po b/openerp/addons/base/i18n/zh_HK.po index 06a099c2196..78232e87ecf 100644 --- a/openerp/addons/base/i18n/zh_HK.po +++ b/openerp/addons/base/i18n/zh_HK.po @@ -3682,7 +3682,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -10995,7 +10995,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11115,7 +11115,7 @@ msgstr "" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_TW.po b/openerp/addons/base/i18n/zh_TW.po index 5b6c6c37767..116eca54d8d 100644 --- a/openerp/addons/base/i18n/zh_TW.po +++ b/openerp/addons/base/i18n/zh_TW.po @@ -3687,7 +3687,7 @@ msgstr "GPL-2 或更新版本" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir -msgid "M." +msgid "Mr." msgstr "" #. module: base @@ -11013,7 +11013,7 @@ msgstr "序列" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss -msgid "Mss" +msgid "Miss" msgstr "" #. module: base @@ -11133,7 +11133,7 @@ msgstr "過濾器" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_madam -msgid "Ms." +msgid "Mrs." msgstr "女士" #. module: base diff --git a/openerp/addons/base/res/res_partner_data.xml b/openerp/addons/base/res/res_partner_data.xml index 138e44176f0..5bcb65a0461 100644 --- a/openerp/addons/base/res/res_partner_data.xml +++ b/openerp/addons/base/res/res_partner_data.xml @@ -20,17 +20,32 @@ contact Madam - Ms. + Mrs. contact Miss - Mss + Miss contact Sir - M. + Sir + + + contact + Mister + Mr. + + + contact + Doctor + Dr. + + + contact + Professor + Prof. From 2332c23c30c05fb68c025a9a55522a382a394b0d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 23 Feb 2012 11:30:45 +0100 Subject: [PATCH 019/265] [IMP] replaces tools.misc.get_languages by the static dictionary it returns, rename that dict to ALL_LANGUAGES for clarity bzr revid: xmo@openerp.com-20120223103045-a44cl5kdkrnehc66 --- openerp/addons/base/res/res_lang.py | 2 +- openerp/tools/misc.py | 168 ++++++++++++++-------------- 2 files changed, 83 insertions(+), 87 deletions(-) diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py index 13acf109b04..261f401f6be 100644 --- a/openerp/addons/base/res/res_lang.py +++ b/openerp/addons/base/res/res_lang.py @@ -80,7 +80,7 @@ class lang(osv.osv): _logger.warning(msg, lang, lc) if not lang_name: - lang_name = tools.get_languages().get(lang, lang) + lang_name = tools.ALL_LANGUAGES.get(lang, lang) def fix_xa0(s): diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index a5c72900fc7..89cd8695078 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -550,95 +550,91 @@ def get_iso_codes(lang): lang = lang.split('_')[0] return lang -def get_languages(): - # The codes below are those from Launchpad's Rosetta, with the exception - # of some trivial codes where the Launchpad code is xx and we have xx_XX. - languages={ - 'ab_RU': u'Abkhazian / аҧсуа', - 'ar_AR': u'Arabic / الْعَرَبيّة', - 'bg_BG': u'Bulgarian / български език', - 'bs_BS': u'Bosnian / bosanski jezik', - 'ca_ES': u'Catalan / Català', - 'cs_CZ': u'Czech / Čeština', - 'da_DK': u'Danish / Dansk', - 'de_DE': u'German / Deutsch', - 'el_GR': u'Greek / Ελληνικά', - 'en_CA': u'English (CA)', - 'en_GB': u'English (UK)', - 'en_US': u'English (US)', - 'es_AR': u'Spanish (AR) / Español (AR)', - 'es_BO': u'Spanish (BO) / Español (BO)', - 'es_CL': u'Spanish (CL) / Español (CL)', - 'es_CO': u'Spanish (CO) / Español (CO)', - 'es_CR': u'Spanish (CR) / Español (CR)', - 'es_DO': u'Spanish (DO) / Español (DO)', - 'es_EC': u'Spanish (EC) / Español (EC)', - 'es_ES': u'Spanish / Español', - 'es_GT': u'Spanish (GT) / Español (GT)', - 'es_HN': u'Spanish (HN) / Español (HN)', - 'es_MX': u'Spanish (MX) / Español (MX)', - 'es_NI': u'Spanish (NI) / Español (NI)', - 'es_PA': u'Spanish (PA) / Español (PA)', - 'es_PE': u'Spanish (PE) / Español (PE)', - 'es_PR': u'Spanish (PR) / Español (PR)', - 'es_PY': u'Spanish (PY) / Español (PY)', - 'es_SV': u'Spanish (SV) / Español (SV)', - 'es_UY': u'Spanish (UY) / Español (UY)', - 'es_VE': u'Spanish (VE) / Español (VE)', - 'et_EE': u'Estonian / Eesti keel', - 'fa_IR': u'Persian / فارس', - 'fi_FI': u'Finnish / Suomi', - 'fr_BE': u'French (BE) / Français (BE)', - 'fr_CH': u'French (CH) / Français (CH)', - 'fr_FR': u'French / Français', - 'gl_ES': u'Galician / Galego', - 'gu_IN': u'Gujarati / ગુજરાતી', - 'he_IL': u'Hebrew / עִבְרִי', - 'hi_IN': u'Hindi / हिंदी', - 'hr_HR': u'Croatian / hrvatski jezik', - 'hu_HU': u'Hungarian / Magyar', - 'id_ID': u'Indonesian / Bahasa Indonesia', - 'it_IT': u'Italian / Italiano', - 'iu_CA': u'Inuktitut / ᐃᓄᒃᑎᑐᑦ', - 'ja_JP': u'Japanese / 日本語', - 'ko_KP': u'Korean (KP) / 한국어 (KP)', - 'ko_KR': u'Korean (KR) / 한국어 (KR)', - 'lt_LT': u'Lithuanian / Lietuvių kalba', - 'lv_LV': u'Latvian / latviešu valoda', - 'ml_IN': u'Malayalam / മലയാളം', - 'mn_MN': u'Mongolian / монгол', - 'nb_NO': u'Norwegian Bokmål / Norsk bokmål', - 'nl_NL': u'Dutch / Nederlands', - 'nl_BE': u'Flemish (BE) / Vlaams (BE)', - 'oc_FR': u'Occitan (FR, post 1500) / Occitan', - 'pl_PL': u'Polish / Język polski', - 'pt_BR': u'Portugese (BR) / Português (BR)', - 'pt_PT': u'Portugese / Português', - 'ro_RO': u'Romanian / română', - 'ru_RU': u'Russian / русский язык', - 'si_LK': u'Sinhalese / සිංහල', - 'sl_SI': u'Slovenian / slovenščina', - 'sk_SK': u'Slovak / Slovenský jazyk', - 'sq_AL': u'Albanian / Shqip', - 'sr_RS': u'Serbian (Cyrillic) / српски', - 'sr@latin': u'Serbian (Latin) / srpski', - 'sv_SE': u'Swedish / svenska', - 'te_IN': u'Telugu / తెలుగు', - 'tr_TR': u'Turkish / Türkçe', - 'vi_VN': u'Vietnamese / Tiếng Việt', - 'uk_UA': u'Ukrainian / українська', - 'ur_PK': u'Urdu / اردو', - 'zh_CN': u'Chinese (CN) / 简体中文', - 'zh_HK': u'Chinese (HK)', - 'zh_TW': u'Chinese (TW) / 正體字', - 'th_TH': u'Thai / ภาษาไทย', - 'tlh_TLH': u'Klingon', - } - return languages +ALL_LANGUAGES = { + 'ab_RU': u'Abkhazian / аҧсуа', + 'ar_AR': u'Arabic / الْعَرَبيّة', + 'bg_BG': u'Bulgarian / български език', + 'bs_BS': u'Bosnian / bosanski jezik', + 'ca_ES': u'Catalan / Català', + 'cs_CZ': u'Czech / Čeština', + 'da_DK': u'Danish / Dansk', + 'de_DE': u'German / Deutsch', + 'el_GR': u'Greek / Ελληνικά', + 'en_CA': u'English (CA)', + 'en_GB': u'English (UK)', + 'en_US': u'English (US)', + 'es_AR': u'Spanish (AR) / Español (AR)', + 'es_BO': u'Spanish (BO) / Español (BO)', + 'es_CL': u'Spanish (CL) / Español (CL)', + 'es_CO': u'Spanish (CO) / Español (CO)', + 'es_CR': u'Spanish (CR) / Español (CR)', + 'es_DO': u'Spanish (DO) / Español (DO)', + 'es_EC': u'Spanish (EC) / Español (EC)', + 'es_ES': u'Spanish / Español', + 'es_GT': u'Spanish (GT) / Español (GT)', + 'es_HN': u'Spanish (HN) / Español (HN)', + 'es_MX': u'Spanish (MX) / Español (MX)', + 'es_NI': u'Spanish (NI) / Español (NI)', + 'es_PA': u'Spanish (PA) / Español (PA)', + 'es_PE': u'Spanish (PE) / Español (PE)', + 'es_PR': u'Spanish (PR) / Español (PR)', + 'es_PY': u'Spanish (PY) / Español (PY)', + 'es_SV': u'Spanish (SV) / Español (SV)', + 'es_UY': u'Spanish (UY) / Español (UY)', + 'es_VE': u'Spanish (VE) / Español (VE)', + 'et_EE': u'Estonian / Eesti keel', + 'fa_IR': u'Persian / فارس', + 'fi_FI': u'Finnish / Suomi', + 'fr_BE': u'French (BE) / Français (BE)', + 'fr_CH': u'French (CH) / Français (CH)', + 'fr_FR': u'French / Français', + 'gl_ES': u'Galician / Galego', + 'gu_IN': u'Gujarati / ગુજરાતી', + 'he_IL': u'Hebrew / עִבְרִי', + 'hi_IN': u'Hindi / हिंदी', + 'hr_HR': u'Croatian / hrvatski jezik', + 'hu_HU': u'Hungarian / Magyar', + 'id_ID': u'Indonesian / Bahasa Indonesia', + 'it_IT': u'Italian / Italiano', + 'iu_CA': u'Inuktitut / ᐃᓄᒃᑎᑐᑦ', + 'ja_JP': u'Japanese / 日本語', + 'ko_KP': u'Korean (KP) / 한국어 (KP)', + 'ko_KR': u'Korean (KR) / 한국어 (KR)', + 'lt_LT': u'Lithuanian / Lietuvių kalba', + 'lv_LV': u'Latvian / latviešu valoda', + 'ml_IN': u'Malayalam / മലയാളം', + 'mn_MN': u'Mongolian / монгол', + 'nb_NO': u'Norwegian Bokmål / Norsk bokmål', + 'nl_NL': u'Dutch / Nederlands', + 'nl_BE': u'Flemish (BE) / Vlaams (BE)', + 'oc_FR': u'Occitan (FR, post 1500) / Occitan', + 'pl_PL': u'Polish / Język polski', + 'pt_BR': u'Portugese (BR) / Português (BR)', + 'pt_PT': u'Portugese / Português', + 'ro_RO': u'Romanian / română', + 'ru_RU': u'Russian / русский язык', + 'si_LK': u'Sinhalese / සිංහල', + 'sl_SI': u'Slovenian / slovenščina', + 'sk_SK': u'Slovak / Slovenský jazyk', + 'sq_AL': u'Albanian / Shqip', + 'sr_RS': u'Serbian (Cyrillic) / српски', + 'sr@latin': u'Serbian (Latin) / srpski', + 'sv_SE': u'Swedish / svenska', + 'te_IN': u'Telugu / తెలుగు', + 'tr_TR': u'Turkish / Türkçe', + 'vi_VN': u'Vietnamese / Tiếng Việt', + 'uk_UA': u'Ukrainian / українська', + 'ur_PK': u'Urdu / اردو', + 'zh_CN': u'Chinese (CN) / 简体中文', + 'zh_HK': u'Chinese (HK)', + 'zh_TW': u'Chinese (TW) / 正體字', + 'th_TH': u'Thai / ภาษาไทย', + 'tlh_TLH': u'Klingon', +} def scan_languages(): # Now it will take all languages from get languages function without filter it with base module languages - lang_dict = get_languages() + lang_dict = ALL_LANGUAGES ret = [(lang, lang_dict.get(lang, lang)) for lang in list(lang_dict)] ret.sort(key=lambda k:k[1]) return ret From 18d38fb5eebeb52ad88678a7017a4230c7783727 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 23 Feb 2012 11:32:07 +0100 Subject: [PATCH 020/265] [IMP] document tools.misc.scan_languages, make its implementation less retarded bzr revid: xmo@openerp.com-20120223103207-ra1a0dzcyoe745cx --- openerp/tools/misc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 89cd8695078..06105fbdb56 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -633,12 +633,12 @@ ALL_LANGUAGES = { } def scan_languages(): - # Now it will take all languages from get languages function without filter it with base module languages - lang_dict = ALL_LANGUAGES - ret = [(lang, lang_dict.get(lang, lang)) for lang in list(lang_dict)] - ret.sort(key=lambda k:k[1]) - return ret + """ Returns all languages supported by OpenERP for translation + :returns: a list of (lang_code, lang_name) pairs + :rtype: [(str, unicode)] + """ + return sorted(ALL_LANGUAGES.iteritems(), key=lambda k: k[1]) def get_user_companies(cr, user): def _get_company_children(cr, ids): From 25e699d72dc1d3e61af94402ad3e66b23cd24303 Mon Sep 17 00:00:00 2001 From: Samus Aran Date: Fri, 23 Mar 2012 16:08:50 +0100 Subject: [PATCH 021/265] [IMP] Creating new row in db also update write_date and write_uid bzr revid: cto@openerp.com-20120323150850-26j5ht8eexue86sh --- openerp/osv/orm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 32b039f6598..22c1a0bc183 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4172,9 +4172,9 @@ class BaseModel(object): and vals[field]: self._check_selection_field_value(cr, user, field, vals[field], context=context) if self._log_access: - upd0 += ',create_uid,create_date' - upd1 += ",%s,(now() at time zone 'UTC')" - upd2.append(user) + upd0 += ',create_uid,create_date,write_uid,write_date' + upd1 += ",%s,(now() at time zone 'UTC'),%s,(now() at time zone 'UTC')" + upd2.extend((user, user)) cr.execute('insert into "'+self._table+'" (id'+upd0+") values ("+str(id_new)+upd1+')', tuple(upd2)) self.check_access_rule(cr, user, [id_new], 'create', context=context) upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority) From c49f2418c25d508cd74387ca47f9963f55640c4c Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Wed, 4 Jul 2012 10:47:48 +0530 Subject: [PATCH 022/265] [FIX] Typo in Portuguese official language names. bzr revid: tpa@tinyerp.com-20120704051748-y41la206dwk67klv --- openerp/addons/base/i18n/base.pot | 4 ++-- openerp/tools/misc.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index b4d28052ba8..ae6825bfe8c 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -2155,7 +2155,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 -msgid "Portugese (BR) / Português (BR)" +msgid "Portuguese (BR) / Português (BR)" msgstr "" #. module: base @@ -3002,7 +3002,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 -msgid "Portugese / Português" +msgid "Portuguese / Português" msgstr "" #. module: base diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 3aad91fb7b8..a81e1e1f647 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -612,8 +612,8 @@ def get_languages(): 'nl_BE': u'Flemish (BE) / Vlaams (BE)', 'oc_FR': u'Occitan (FR, post 1500) / Occitan', 'pl_PL': u'Polish / Język polski', - 'pt_BR': u'Portugese (BR) / Português (BR)', - 'pt_PT': u'Portugese / Português', + 'pt_BR': u'Portuguese (BR) / Português (BR)', + 'pt_PT': u'Portuguese / Português', 'ro_RO': u'Romanian / română', 'ru_RU': u'Russian / русский язык', 'si_LK': u'Sinhalese / සිංහල', From 6e6ef1ed0f7408639ff43434917fc4110ecbf850 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 5 Jul 2012 18:24:11 +0530 Subject: [PATCH 023/265] [IMP] remove res.payterm which is not in any part of code of server or addons. bzr revid: tpa@tinyerp.com-20120705125411-fd1eazoofe5mpbvf --- openerp/addons/base/i18n/base.pot | 10 ---------- openerp/addons/base/res/res_partner.py | 8 -------- openerp/addons/base/res/res_partner_view.xml | 19 ------------------- 3 files changed, 37 deletions(-) diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index b4d28052ba8..6b97092d430 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -1317,11 +1317,6 @@ msgstr "" msgid "Create _Menu" msgstr "" -#. module: base -#: field:res.payterm,name:0 -msgid "Payment Term (short name)" -msgstr "" - #. module: base #: model:ir.model,name:base.model_res_bank #: view:res.bank:0 @@ -3206,11 +3201,6 @@ msgstr "" msgid "Error ! You cannot create recursive associated members." msgstr "" -#. module: base -#: view:res.payterm:0 -msgid "Payment Term" -msgstr "" - #. module: base #: selection:res.lang,direction:0 msgid "Right-to-Left" diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 2165c8ad16d..66c5dea1b11 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -27,14 +27,6 @@ from tools.translate import _ import logging import pooler -class res_payterm(osv.osv): - _description = 'Payment term' - _name = 'res.payterm' - _order = 'name' - _columns = { - 'name': fields.char('Payment Term (short name)', size=64), - } - class res_partner_category(osv.osv): def name_get(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 5159a7075cc..a6a4ad77c90 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -401,25 +401,6 @@ - - res.payterm - res.payterm - form - -
- - - -
-
-
- - Payment term - ir.actions.act_window - res.payterm - form - - + + + + + + + + + From aec461651e2671dd6bb1caf7ee21430c861c109f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 14 Aug 2012 14:31:12 +0200 Subject: [PATCH 037/265] [FIX] NUL byte in a file leads csv.reader to raise csv.Error bzr revid: xmo@openerp.com-20120814123112-p4iio7fl561ronln --- addons/base_import/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 07a3439419d..722a9bf848e 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -225,7 +225,7 @@ class ir_import(orm.TransientModel): 'headers': headers or False, 'preview': list(preview), } - except (TypeError, UnicodeDecodeError), e: + except (csv.Error, TypeError, UnicodeDecodeError), e: # Due to lazy generators, UnicodeDecodeError (for # instance) may only be raised when serializing the # preview to a list in the return. From 323b979146d6e0ba428a3e15e98f112cf9f80d43 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 14 Aug 2012 14:48:35 +0200 Subject: [PATCH 038/265] [ADD] error reporting to user during preview bzr revid: xmo@openerp.com-20120814124835-9nkqni98ie2eyt5r --- addons/base_import/__openerp__.py | 1 + addons/base_import/models.py | 2 +- addons/base_import/static/src/js/import.js | 12 ++++++++++-- addons/base_import/static/src/xml/import.xml | 8 +++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/addons/base_import/__openerp__.py b/addons/base_import/__openerp__.py index 230c514efc8..ab97e237909 100644 --- a/addons/base_import/__openerp__.py +++ b/addons/base_import/__openerp__.py @@ -27,6 +27,7 @@ Re-implement openerp's file import system: 'depends': ['base'], 'installable': True, 'auto_install': False, # set to true and allow uninstall? + 'css': ['static/src/css/import.css'], 'js': ['static/src/js/import.js'], 'qweb': ['static/src/xml/import.xml'], } diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 722a9bf848e..560a28f9067 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -231,7 +231,7 @@ class ir_import(orm.TransientModel): # preview to a list in the return. _logger.debug("Error during CSV parsing preview", exc_info=True) return { - 'error': _("Failed to parse CSV file: %s") % e, + 'error': str(e), # iso-8859-1 ensures decoding will always succeed, # even if it yields non-printable characters. This is # in case of UnicodeDecodeError (or csv.Error diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 5bb81d23cbb..559d74734e8 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -61,7 +61,7 @@ openerp.base_import = function (instance) { file_update: function (e) { if (!this.$('input.oe_import_file').val()) { return; } - // TODO: hide preview before calling set_file + this.$element.removeClass('oe_import_preview oe_import_error'); jsonp(this.$element, { url: '/base_import/set_file' }, this.proxy('file_updated')); @@ -76,7 +76,15 @@ openerp.base_import = function (instance) { }]).then(this.proxy('preview')); }, preview: function (result) { - this.$('table').html(QWeb.render('ImportView.preview', result)); + if (result.error) { + this.$element.addClass('oe_import_error'); + this.$('.oe_import_error_report').html( + QWeb.render('ImportView.error', result)); + } else { + this.$element.addClass('oe_import_preview'); + this.$('table').html( + QWeb.render('ImportView.preview', result)); + } }, }); }; diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index d2a3ec4f66d..7cf04c55292 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -1,6 +1,6 @@ -
+ @@ -9,6 +9,7 @@
+
@@ -22,4 +23,9 @@ > + +

Import preview failed due to:

+

Here is the start of the file we could not import:

+
+
From 8fa23a95186edd2f5bf6f223337d34f3a4e55e70 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 14 Aug 2012 16:14:56 +0200 Subject: [PATCH 039/265] [ADD] actual importing, no fields matching yet also no error pinpointing because API does not allow for it currently bzr revid: xmo@openerp.com-20120814141456-zh9kdbjy8wj1sxys --- addons/base_import/models.py | 29 ++++++++-- addons/base_import/static/src/js/import.js | 58 +++++++++++++++++--- addons/base_import/static/src/xml/import.xml | 17 +++++- 3 files changed, 89 insertions(+), 15 deletions(-) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 560a28f9067..a464649758d 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -11,6 +11,8 @@ try: except ImportError: from StringIO import StringIO +import psycopg2 + from openerp.osv import orm, fields from openerp.tools.translate import _ @@ -300,24 +302,39 @@ class ir_import(orm.TransientModel): record, fields, options, context=context) try: + _logger.info('importing %d rows...', len(data)) (code, record, message, _wat) = self.pool[record.res_model].import_data( cr, uid, import_fields, data, context=context) + _logger.info('done') + except Exception, e: + _logger.exception("Import failed") # TODO: remove when exceptions stop being an "expected" - # behavior of import_data on some invalid input. + # behavior of import_data on some (most) invalid + # input. code, record, message = -1, None, str(e) - if dryrun: - cr.execute('ROLLBACK TO SAVEPOINT import') - else: - cr.execute('RELEASE SAVEPOINT import') + # If transaction aborted, RELEASE SAVEPOINT is going to raise + # an InternalError (ROLLBACK should work, maybe). Ignore that. + # TODO: to handle multiple errors, create savepoint around + # write and release it in case of write error (after + # adding error to errors array) => can keep on trying to + # import stuff, and rollback at the end if there is any + # error in the results. + try: + if dryrun: + cr.execute('ROLLBACK TO SAVEPOINT import') + else: + cr.execute('RELEASE SAVEPOINT import') + except psycopg2.InternalError: + pass if code != -1: return [] # TODO: add key for error location? # TODO: error not within normal preview, how to display? Re-preview - # with higher count? + # with higher ``count``? return [{ 'type': 'error', 'message': message, diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 559d74734e8..037a9662b02 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -1,5 +1,6 @@ openerp.base_import = function (instance) { var QWeb = instance.web.qweb; + var _t = instance.web._t; var _lt = instance.web._lt; /** @@ -41,7 +42,14 @@ openerp.base_import = function (instance) { 'change input.oe_import_file': 'file_update' }, init: function (parent, dataset) { - this._super(parent, {}); + var self = this; + this._super(parent, { + buttons: [ + {text: _t("Import File"), click: function () { + self.do_import(); + }, 'class': 'oe_import_dialog_button'} + ] + }); this.res_model = parent.model; // import object id this.id = null; @@ -57,6 +65,15 @@ openerp.base_import = function (instance) { }); }, + import_options: function () { + return { + // TODO: customizable gangnam style + quote: '"', + separator: ',', + headers: true, + }; + }, + //- File change section file_update: function (e) { if (!this.$('input.oe_import_file').val()) { return; } @@ -69,22 +86,49 @@ openerp.base_import = function (instance) { file_updated: function () { // immediately trigger preview... // TODO: test that write // succeeded? - this.Import.call('parse_preview', [this.id, { - quote: '"', - separator: ',', - headers: true, - }]).then(this.proxy('preview')); + this.Import.call( + 'parse_preview', [this.id, this.import_options()]) + .then(this.proxy('preview')); }, preview: function (result) { if (result.error) { this.$element.addClass('oe_import_error'); this.$('.oe_import_error_report').html( - QWeb.render('ImportView.error', result)); + QWeb.render('ImportView.preview.error', result)); } else { this.$element.addClass('oe_import_preview'); this.$('table').html( QWeb.render('ImportView.preview', result)); } }, + + //- import itself + do_import: function () { + var fields = this.$('.oe_import_fields input').map(function (index, el) { + return el.value || false; + }).get(); + this.Import.call( + 'do', [this.id, fields, this.import_options()], { + // maybe could do a dryrun after successful + // preview or something (note: don't go to + // this.result if dryrun=true) + dryrun: false + }) + .then(this.proxy('result')); + }, + result: function (errors) { + if (!errors.length) { + if (this.getParent().reload_content) { + this.getParent().reload_content(); + } + this.close(); + return; + } + // import failed (or maybe just warnings, if we ever get + // warnings?) + this.$element.addClass('oe_import_error'); + this.$('.oe_import_error_report').html( + QWeb.render('ImportView.error', {errors: errors})); + }, }); }; diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 7cf04c55292..483c9a4a3cb 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -7,9 +7,9 @@ +
-
@@ -18,14 +18,27 @@ + + + + + + - +

Import preview failed due to:

Here is the start of the file we could not import:

+
    +
  • + + +
  • +
From 34f9664377ae837a7080b88a24c87b6ed88f88d0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 14 Aug 2012 16:29:33 +0200 Subject: [PATCH 040/265] [FIX] no field selected for import by the user bzr revid: xmo@openerp.com-20120814142933-myng67f2cily6vfg --- addons/base_import/models.py | 14 +++++++++-- addons/base_import/tests/test_cases.py | 32 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index a464649758d..2e44c686fd7 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -252,9 +252,12 @@ class ir_import(orm.TransientModel): :param list(str|bool): fields :returns: (data, fields) :rtype: (list(list(str)), list(str)) + :raises ValueError: in case the import data could not be converted """ # Get indices for non-empty fields indices = [index for index, field in enumerate(fields) if field] + if not indices: + raise ValueError(_("You must configure at least one field to import")) # If only one index, itemgetter will return an atom rather # than a 1-tuple if len(indices) == 1: mapper = lambda row: [row[indices[0]]] @@ -298,8 +301,15 @@ class ir_import(orm.TransientModel): cr.execute('SAVEPOINT import') (record,) = self.browse(cr, uid, [id], context=context) - data, import_fields = self._convert_import_data( - record, fields, options, context=context) + try: + data, import_fields = self._convert_import_data( + record, fields, options, context=context) + except ValueError, e: + return [{ + 'type': 'error', + 'message': str(e), + 'record': False, + }] try: _logger.info('importing %d rows...', len(data)) diff --git a/addons/base_import/tests/test_cases.py b/addons/base_import/tests/test_cases.py index 00230f9a3c0..e2b61c1928b 100644 --- a/addons/base_import/tests/test_cases.py +++ b/addons/base_import/tests/test_cases.py @@ -311,3 +311,35 @@ class test_convert_import_data(TransactionCase): ('foo', '2'), ('', '6'), ]) + + def test_nofield(self): + Import = self.registry('base_import.import') + + id = Import.create(self.cr, self.uid, { + 'res_model': 'base_import.tests.models.preview', + 'file': base64.b64encode('name,Some Value,Counter\n' + 'foo,1,2\n') + }) + + record = Import.browse(self.cr, self.uid, id) + self.assertRaises( + ValueError, + Import._convert_import_data, + record, [], + {'quote': '"', 'separator': ',', 'headers': True,}) + + def test_falsefields(self): + Import = self.registry('base_import.import') + + id = Import.create(self.cr, self.uid, { + 'res_model': 'base_import.tests.models.preview', + 'file': base64.b64encode('name,Some Value,Counter\n' + 'foo,1,2\n') + }) + + record = Import.browse(self.cr, self.uid, id) + self.assertRaises( + ValueError, + Import._convert_import_data, + record, [False, False, False], + {'quote': '"', 'separator': ',', 'headers': True,}) From 7f319f5a374842a2731e7fbacb468452be784c69 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 14 Aug 2012 19:23:22 +0200 Subject: [PATCH 041/265] [ADD] blahblahblahblah also basic CSS effects bzr revid: xmo@openerp.com-20120814172322-1hx09qqh90umjdcq --- addons/base_import/static/src/css/import.css | 27 ++++++++++++ addons/base_import/static/src/js/import.js | 27 +++++++++--- addons/base_import/static/src/xml/import.xml | 46 +++++++++++++++++--- 3 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 addons/base_import/static/src/css/import.css diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css new file mode 100644 index 00000000000..4bb1fdeaea0 --- /dev/null +++ b/addons/base_import/static/src/css/import.css @@ -0,0 +1,27 @@ +.oe_import dd, +.oe_import .oe_import_grid, +.oe_import .oe_import_error_report, +.oe_import .oe_import_with_file, +.oe_import .oe_import_noheaders { + display: none; +} + +.oe_import.oe_import_preview .oe_import_grid { + display: table; +} +.oe_import.oe_import_error .oe_import_error_report, +.oe_import.oe_import_with_file .oe_import_with_file, +.oe_import.oe_import_noheaders .oe_import_noheaders { + display: block; +} + +.oe_import .oe_import_error_report ul .oe_import_report_error { + background-color: #FFD9DB; +} +.oe_import .oe_import_error_report ul .oe_import_report_warning { + background-color: #FEFFD9; +} + +.oe_import .oe_import_noheaders { + color: #888; +} diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 037a9662b02..3a52ad548ec 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -39,7 +39,22 @@ openerp.base_import = function (instance) { template: 'ImportView', dialog_title: _lt("Import Data"), events: { - 'change input.oe_import_file': 'file_update' + 'change input.oe_import_file': 'file_update', + 'click input.oe_import_has_header': function (e) { + this.$element.toggleClass( + 'oe_import_noheaders', !e.target.checked); + this.settings_updated(); + }, + 'click a.oe_import_csv': function (e) { + e.preventDefault(); + }, + 'click a.oe_import_export': function (e) { + e.preventDefault(); + }, + 'click dt a': function (e) { + e.preventDefault(); + $(e.target).parent().next().toggle(); + } }, init: function (parent, dataset) { var self = this; @@ -70,21 +85,21 @@ openerp.base_import = function (instance) { // TODO: customizable gangnam style quote: '"', separator: ',', - headers: true, + headers: this.$('input.oe_import_has_header').prop('checked'), }; }, - //- File change section + //- File & settings change section file_update: function (e) { if (!this.$('input.oe_import_file').val()) { return; } this.$element.removeClass('oe_import_preview oe_import_error'); jsonp(this.$element, { url: '/base_import/set_file' - }, this.proxy('file_updated')); + }, this.proxy('settings_updated')); }, - file_updated: function () { - // immediately trigger preview... + settings_updated: function () { + this.$element.addClass('oe_import_with_file'); // TODO: test that write // succeeded? this.Import.call( 'parse_preview', [this.id, this.import_options()]) diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 483c9a4a3cb..bb4f1d742d5 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -4,15 +4,51 @@ - +

Upload your file

+

Select the .CSV + file to import. If you need a sample importable file, you + can use the export + tool to generate one.

+ -
- -
+
+

Map your data to OpenERP

+ + +

If the file contains + the column names, OpenERP can try auto-detecting the + field corresponding to the column. This makes imports + simpler especially when the file has many columns.

+ +
+ + + +

Frequently Asked Questions

+
+
Need to import data from an other application?
+
+

In order to re-create relationships between + different records, you should use the unique + identifier from the original application and + map it to the ID + column in OpenERP. When you + import an other record that links to the first + one, use XXX/ID + to the original unique identifier.

+

The ID + will also be used to update the original + import if you need to re-import modified data + later, it's thus good practice to specify it + whenever possible

+
+
+ -
Date: Wed, 22 Aug 2012 15:55:46 +0200 Subject: [PATCH 042/265] [BRANCH] locadis: first commit : start of the branch bzr revid: fva@openerp.com-20120822135546-kwbo893th1pv2vbs --- addons/locadis/__init__.py | 25 + addons/locadis/__openerp__.py | 56 ++ addons/locadis/point_of_sale.py | 1303 +++++++++++++++++++++++++ addons/locadis/static/src/css/pos.css | 4 + addons/locadis/static/src/js/hello.js | 12 + addons/locadis/static/src/js/main.js | 24 + addons/locadis/static/src/xml/pos.xml | 15 + 7 files changed, 1439 insertions(+) create mode 100644 addons/locadis/__init__.py create mode 100644 addons/locadis/__openerp__.py create mode 100644 addons/locadis/point_of_sale.py create mode 100644 addons/locadis/static/src/css/pos.css create mode 100644 addons/locadis/static/src/js/hello.js create mode 100644 addons/locadis/static/src/js/main.js create mode 100644 addons/locadis/static/src/xml/pos.xml diff --git a/addons/locadis/__init__.py b/addons/locadis/__init__.py new file mode 100644 index 00000000000..e57b362135b --- /dev/null +++ b/addons/locadis/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +#import point_of_sale + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/locadis/__openerp__.py b/addons/locadis/__openerp__.py new file mode 100644 index 00000000000..056b8da7fcf --- /dev/null +++ b/addons/locadis/__openerp__.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + 'name': 'Locadis Point Of Sale', + 'version': '1.0.1', + 'category': 'Point Of Sale', + "sequence": 6, + "summary": "Point of sale extensions for Locadis", + 'description': """ +FIXME: product description + """, + 'author': 'OpenERP SA', + 'images': ['images/cash_registers.jpeg', 'images/pos_analysis.jpeg','images/register_analysis.jpeg','images/sale_order_pos.jpeg','images/product_pos.jpeg'], + 'depends': ['point_of_sale'], + 'init_xml': [], + 'update_xml': [ + ], + 'demo_xml': [ + ], + 'test': [ + ], + 'installable': True, + 'application': True, + # Web client + 'js': [ + 'static/src/js/main.js' + ], + 'css': [ + 'static/src/css/pos.css' + ], + 'qweb': [ + 'static/src/xml/pos.xml' + ], + 'auto_install': False, +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/locadis/point_of_sale.py b/addons/locadis/point_of_sale.py new file mode 100644 index 00000000000..f4d32985688 --- /dev/null +++ b/addons/locadis/point_of_sale.py @@ -0,0 +1,1303 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import pdb +import openerp +import addons +import openerp.addons.product.product + +import time +from datetime import datetime +from dateutil.relativedelta import relativedelta +import logging + +import netsvc +from osv import fields, osv +import tools +from tools.translate import _ +from decimal import Decimal +import decimal_precision as dp + +_logger = logging.getLogger(__name__) + +class pos_config(osv.osv): + _name = 'pos.config' + + POS_CONFIG_STATE = [ + ('active', 'Active'), + ('inactive', 'Inactive'), + ('deprecated', 'Deprecated') + ] + + _columns = { + 'name' : fields.char('Point of Sale Name', size=32, select=1, + required=True, help="An internal identification of the point of sale"), + 'journal_ids' : fields.many2many('account.journal', 'pos_config_journal_rel', + 'pos_config_id', 'journal_id', 'Available Payment Methods', + domain="[('journal_user', '=', True )]",), + 'shop_id' : fields.many2one('sale.shop', 'Shop', + required=True), + 'journal_id' : fields.many2one('account.journal', 'Sale Journal', + domain=[('type', '=', 'sale')], + help="Accounting journal used to post sales entries."), + 'iface_self_checkout' : fields.boolean('Self Checkout Mode', + help="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."), + 'iface_cashdrawer' : fields.boolean('Cashdrawer Interface'), + 'iface_payment_terminal' : fields.boolean('Payment Terminal Interface'), + 'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'), + 'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'), + 'iface_print_via_proxy' : fields.boolean('Print via Proxy'), + + 'state' : fields.selection(POS_CONFIG_STATE, 'State', required=True, readonly=True), + 'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True, + help="This sequence is automatically created by OpenERP but you can change it "\ + "to customize the reference numbers of your orders."), + 'session_ids': fields.one2many('pos.session', 'config_id', 'Sessions'), + 'group_by' : fields.boolean('Group Journal Items', help="Check this if you want to group the Journal Items by Product while closing a Session"), + } + + def name_get(self, cr, uid, ids, context=None): + result = [] + states = { + 'opening_control': _('Opening Control'), + 'opened': _('In Progress'), + 'closing_control': _('Closing Control'), + 'closed': _('Closed & Posted'), + } + for record in self.browse(cr, uid, ids, context=context): + if (not record.session_ids) or (record.session_ids[0].state=='closed'): + result.append((record.id, record.name+' ('+_('not used')+')')) + continue + session = record.session_ids[0] + result.append((record.id, record.name + ' ('+session.user_id.name+')')) #, '+states[session.state]+')')) + return result + + + def _default_payment_journal(self, cr, uid, context=None): + res = self.pool.get('account.journal').search(cr, uid, [('type', 'in', ('bank','cash'))], limit=2) + return res or [] + + def _default_sale_journal(self, cr, uid, context=None): + res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1) + return res and res[0] or False + + def _default_shop(self, cr, uid, context=None): + res = self.pool.get('sale.shop').search(cr, uid, []) + return res and res[0] or False + + _defaults = { + 'state' : POS_CONFIG_STATE[0][0], + 'shop_id': _default_shop, + 'journal_id': _default_sale_journal, + 'journal_ids': _default_payment_journal, + 'group_by' : True, + } + + def set_active(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state' : 'active'}, context=context) + + def set_inactive(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state' : 'inactive'}, context=context) + + def set_deprecate(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state' : 'deprecated'}, context=context) + + def create(self, cr, uid, values, context=None): + proxy = self.pool.get('ir.sequence') + sequence_values = dict( + name='PoS %s' % values['name'], + padding=5, + prefix="%s/" % values['name'], + ) + sequence_id = proxy.create(cr, uid, sequence_values, context=context) + values['sequence_id'] = sequence_id + return super(pos_config, self).create(cr, uid, values, context=context) + + def unlink(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + if obj.sequence_id: + obj.sequence_id.unlink() + return super(pos_config, self).unlink(cr, uid, ids, context=context) + +class pos_session(osv.osv): + _name = 'pos.session' + _order = 'id desc' + + POS_SESSION_STATE = [ + ('opening_control', 'Opening Control'), # Signal open + ('opened', 'In Progress'), # Signal closing + ('closing_control', 'Closing Control'), # Signal close + ('closed', 'Closed & Posted'), + ] + + def _compute_cash_journal_id(self, cr, uid, ids, fieldnames, args, context=None): + result = dict.fromkeys(ids, False) + for record in self.browse(cr, uid, ids, context=context): + for st in record.statement_ids: + if st.journal_id.type == 'cash': + result[record.id] = st.journal_id.id + break + return result + + def _compute_cash_register_id(self, cr, uid, ids, fieldnames, args, context=None): + result = dict.fromkeys(ids, False) + for record in self.browse(cr, uid, ids, context=context): + for st in record.statement_ids: + if st.journal_id.type == 'cash': + result[record.id] = st.id + break + return result + + def _compute_controls(self, cr, uid, ids, fieldnames, args, context=None): + result = {} + + for record in self.browse(cr, uid, ids, context=context): + has_opening_control = False + has_closing_control = False + + for journal in record.config_id.journal_ids: + if journal.opening_control == True: + has_opening_control = True + if journal.closing_control == True: + has_closing_control = True + + if has_opening_control and has_closing_control: + break + + values = { + 'has_opening_control': has_opening_control, + 'has_closing_control': has_closing_control, + } + result[record.id] = values + + return result + + _columns = { + 'config_id' : fields.many2one('pos.config', 'Point of Sale', + help="The physical point of sale you will use.", + required=True, + select=1, + domain="[('state', '=', 'active')]", + ), + + 'name' : fields.char('Session ID', size=32, required=True, readonly=True), + 'user_id' : fields.many2one('res.users', 'Responsible', + required=True, + select=1, + readonly=True, + states={'opening_control' : [('readonly', False)]} + ), + 'start_at' : fields.datetime('Opening Date', readonly=True), + 'stop_at' : fields.datetime('Closing Date', readonly=True), + + 'state' : fields.selection(POS_SESSION_STATE, 'State', + required=True, readonly=True, + select=1), + + 'cash_journal_id' : fields.function(_compute_cash_journal_id, method=True, + type='many2one', relation='account.journal', + string='Cash Journal', store=True), + 'cash_register_id' : fields.function(_compute_cash_register_id, method=True, + type='many2one', relation='account.bank.statement', + string='Cash Register', store=True), + + 'opening_details_ids' : fields.related('cash_register_id', 'opening_details_ids', + type='one2many', relation='account.cashbox.line', + string='Opening Cash Control'), + 'details_ids' : fields.related('cash_register_id', 'details_ids', + type='one2many', relation='account.cashbox.line', + string='Cash Control'), + + 'cash_register_balance_end_real' : fields.related('cash_register_id', 'balance_end_real', + type='float', + digits_compute=dp.get_precision('Account'), + string="Ending Balance", + help="Computed using the cash control lines", + readonly=True), + 'cash_register_balance_start' : fields.related('cash_register_id', 'balance_start', + type='float', + digits_compute=dp.get_precision('Account'), + string="Starting Balance", + help="Computed using the cash control at the opening.", + readonly=True), + 'cash_register_total_entry_encoding' : fields.related('cash_register_id', 'total_entry_encoding', + string='Total Cash Transaction', + readonly=True), + 'cash_register_balance_end' : fields.related('cash_register_id', 'balance_end', + type='float', + digits_compute=dp.get_precision('Account'), + string="Computed Balance", + help="Computed with the initial cash control and the sum of all payments.", + readonly=True), + 'cash_register_difference' : fields.related('cash_register_id', 'difference', + type='float', + string='Difference', + help="Difference between the counted cash control at the closing and the computed balance.", + readonly=True), + + 'journal_ids' : fields.related('config_id', 'journal_ids', + type='many2many', + readonly=True, + relation='account.journal', + string='Available Payment Methods'), + 'order_ids' : fields.one2many('pos.order', 'session_id', 'Orders'), + + 'statement_ids' : fields.one2many('account.bank.statement', 'pos_session_id', 'Bank Statement', readonly=True), + 'has_opening_control' : fields.function(_compute_controls, string='Has Opening Control', multi='control', type='boolean'), + 'has_closing_control' : fields.function(_compute_controls, string='Has Closing Control', multi='control', type='boolean'), + } + + _defaults = { + 'name' : '/', + 'user_id' : lambda obj, cr, uid, context: uid, + 'state' : 'opening_control', + } + + _sql_constraints = [ + ('uniq_name', 'unique(name)', "The name of this POS Session must be unique !"), + ] + + def _check_unicity(self, cr, uid, ids, context=None): + for session in self.browse(cr, uid, ids, context=None): + # open if there is no session in 'opening_control', 'opened', 'closing_control' for one user + domain = [ + ('state', 'not in', ('closed','closing_control')), + ('user_id', '=', uid) + ] + count = self.search_count(cr, uid, domain, context=context) + if count>1: + return False + return True + + def _check_pos_config(self, cr, uid, ids, context=None): + for session in self.browse(cr, uid, ids, context=None): + domain = [ + ('state', '!=', 'closed'), + ('config_id', '=', session.config_id.id) + ] + count = self.search_count(cr, uid, domain, context=context) + if count>1: + return False + return True + + _constraints = [ + (_check_unicity, "You cannot create two active sessions with the same responsible!", ['user_id', 'state']), + (_check_pos_config, "You cannot create two active sessions related to the same point of sale!", ['config_id']), + ] + + def create(self, cr, uid, values, context=None): + config_id = values.get('config_id', False) or False + if config_id: + # journal_id is not required on the pos_config because it does not + # exists at the installation. If nothing is configured at the + # installation we do the minimal configuration. Impossible to do in + # the .xml files as the CoA is not yet installed. + jobj = self.pool.get('pos.config') + pos_config = jobj.browse(cr, uid, config_id, context=context) + if not pos_config.journal_id: + jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id'] + if jid: + jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context) + else: + raise osv.except_osv( _('error!'), + _("Unable to open the session. You have to assign a sale journal to your point of sale.")) + + # define some cash journal if no payment method exists + if not pos_config.journal_ids: + cashids = self.pool.get('account.journal').search(cr, uid, [('journal_user','=',True)], context=context) + if not cashids: + cashids = self.pool.get('account.journal').search(cr, uid, [('type','=','cash')], context=context) + self.pool.get('account.journal').write(cr, uid, cashids, {'journal_user': True}) + jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]}) + + + pos_config = jobj.browse(cr, uid, config_id, context=context) + bank_statement_ids = [] + for journal in pos_config.journal_ids: + bank_values = { + 'journal_id' : journal.id, + 'user_id' : uid, + } + statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context) + bank_statement_ids.append(statement_id) + + values.update({ + 'name' : pos_config.sequence_id._next(), + 'statement_ids' : [(6, 0, bank_statement_ids)], + 'config_id': config_id + }) + + return super(pos_session, self).create(cr, uid, values, context=context) + + def unlink(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + for statement in obj.statement_ids: + statement.unlink(context=context) + return True + + def wkf_action_open(self, cr, uid, ids, context=None): + # second browse because we need to refetch the data from the DB for cash_register_id + for record in self.browse(cr, uid, ids, context=context): + values = {} + if not record.start_at: + values['start_at'] = time.strftime('%Y-%m-%d %H:%M:%S') + values['state'] = 'opened' + record.write(values, context=context) + for st in record.statement_ids: + st.button_open(context=context) + + return self.open_frontend_cb(cr, uid, ids, context=context) + + def wkf_action_opening_control(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state' : 'opening_control'}, context=context) + + def wkf_action_closing_control(self, cr, uid, ids, context=None): + for session in self.browse(cr, uid, ids, context=context): + for statement in session.statement_ids: + if statement.id <> session.cash_register_id.id: + if statement.balance_end<>statement.balance_end_real: + self.pool.get('account.bank.statement').write(cr, uid, + [statement.id], {'balance_end_real': statement.balance_end}) + return self.write(cr, uid, ids, {'state' : 'closing_control', 'stop_at' : time.strftime('%Y-%m-%d %H:%M:%S')}, context=context) + + def wkf_action_close(self, cr, uid, ids, context=None): + # Close CashBox + bsl = self.pool.get('account.bank.statement.line') + for record in self.browse(cr, uid, ids, context=context): + for st in record.statement_ids: + if abs(st.difference) > st.journal_id.amount_authorized_diff: + # The pos manager can close statements with maximums. + if not self.pool.get('ir.model.access').check_groups(cr, uid, "point_of_sale.group_pos_manager"): + raise osv.except_osv( _('Error!'), + _("Your ending balance is too different from the theorical cash closing (%.2f), the maximum allowed is: %.2f. You can contact your manager to force it.") % (st.difference, st.journal_id.amount_authorized_diff)) + if st.difference: + if st.difference > 0.0: + name= _('Point of Sale Profit') + account_id = st.journal_id.profit_account_id.id + else: + account_id = st.journal_id.loss_account_id.id + name= _('Point of Sale Loss') + if not account_id: + raise osv.except_osv( _('Error!'), + _("Please set your profit and loss accounts on your payment method '%s'. This will allow OpenERP to post the difference of %.2f in your ending balance. To close this session, you can update the 'Closing Cash Control' to avoid any difference.") % (st.journal_id.name,st.difference)) + bsl.create(cr, uid, { + 'statement_id': st.id, + 'amount': st.difference, + 'ref': record.name, + 'name': name, + 'account_id': account_id + }, context=context) + + getattr(st, 'button_confirm_%s' % st.journal_id.type)(context=context) + self._confirm_orders(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state' : 'closed'}, context=context) + + obj = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'point_of_sale', 'menu_point_root')[1] + return { + 'type' : 'ir.actions.client', + 'name' : 'Point of Sale Menu', + 'tag' : 'reload', + 'params' : {'menu_id': obj}, + } + + def _confirm_orders(self, cr, uid, ids, context=None): + wf_service = netsvc.LocalService("workflow") + + for session in self.browse(cr, uid, ids, context=context): + order_ids = [order.id for order in session.order_ids if order.state == 'paid'] + + move_id = self.pool.get('account.move').create(cr, uid, {'ref' : session.name, 'journal_id' : session.config_id.journal_id.id, }, context=context) + + self.pool.get('pos.order')._create_account_move_line(cr, uid, order_ids, session, move_id, context=context) + + for order in session.order_ids: + if order.state != 'paid': + raise osv.except_osv( + _('Error!'), + _("You cannot confirm all orders of this session, because they have not the 'paid' status")) + else: + wf_service.trg_validate(uid, 'pos.order', order.id, 'done', cr) + + return True + + def open_frontend_cb(self, cr, uid, ids, context=None): + if not context: + context = {} + if not ids: + return {} + context.update({'session_id' : ids[0]}) + return { + 'type' : 'ir.actions.client', + 'name' : 'Start Point Of Sale', + 'tag' : 'pos.ui', + 'context' : context, + } + +class pos_order(osv.osv): + _name = "pos.order" + _description = "Point of Sale" + _order = "id desc" + + def create_from_ui(self, cr, uid, orders, context=None): + #_logger.info("orders: %r", orders) + order_ids = [] + for tmp_order in orders: + order = tmp_order['data'] + order_id = self.create(cr, uid, { + 'name': order['name'], + 'user_id': order['user_id'] or False, + 'session_id': order['pos_session_id'], + 'lines': order['lines'] + }, context) + + for payments in order['statement_ids']: + payment = payments[2] + self.add_payment(cr, uid, order_id, { + 'amount': payment['amount'] or 0.0, + 'payment_date': payment['name'], + 'payment_name': payment.get('note', False), + 'journal': payment['journal_id'] + }, context=context) + + if order['amount_return']: + session = self.pool.get('pos.session').browse(cr, uid, order['pos_session_id'], context=context) + self.add_payment(cr, uid, order_id, { + 'amount': -order['amount_return'], + 'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'), + 'payment_name': _('return'), + 'journal': session.cash_journal_id.id + }, context=context) + order_ids.append(order_id) + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr) + return order_ids + + def unlink(self, cr, uid, ids, context=None): + for rec in self.browse(cr, uid, ids, context=context): + if rec.state not in ('draft','cancel'): + raise osv.except_osv(_('Unable to Delete !'), _('In order to delete a sale, it must be new or cancelled.')) + return super(pos_order, self).unlink(cr, uid, ids, context=context) + + def onchange_partner_id(self, cr, uid, ids, part=False, context=None): + if not part: + return {'value': {}} + pricelist = self.pool.get('res.partner').browse(cr, uid, part, context=context).property_product_pricelist.id + return {'value': {'pricelist_id': pricelist}} + + def _amount_all(self, cr, uid, ids, name, args, context=None): + tax_obj = self.pool.get('account.tax') + cur_obj = self.pool.get('res.currency') + res = {} + for order in self.browse(cr, uid, ids, context=context): + res[order.id] = { + 'amount_paid': 0.0, + 'amount_return':0.0, + 'amount_tax':0.0, + } + val1 = val2 = 0.0 + cur = order.pricelist_id.currency_id + for payment in order.statement_ids: + res[order.id]['amount_paid'] += payment.amount + res[order.id]['amount_return'] += (payment.amount < 0 and payment.amount or 0) + for line in order.lines: + val1 += line.price_subtotal_incl + val2 += line.price_subtotal + res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val1-val2) + res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1) + return res + + def copy(self, cr, uid, id, default=None, context=None): + if not default: + default = {} + d = { + 'state': 'draft', + 'invoice_id': False, + 'account_move': False, + 'picking_id': False, + 'statement_ids': [], + 'nb_print': 0, + 'name': self.pool.get('ir.sequence').get(cr, uid, 'pos.order'), + } + d.update(default) + return super(pos_order, self).copy(cr, uid, id, d, context=context) + + _columns = { + 'name': fields.char('Order Ref', size=64, required=True, readonly=True), + 'company_id':fields.many2one('res.company', 'Company', required=True, readonly=True), + 'shop_id': fields.related('session_id', 'config_id', 'shop_id', relation='sale.shop', type='many2one', string='Shop', store=True, readonly=True), + 'date_order': fields.datetime('Order Date', readonly=True, select=True), + 'user_id': fields.many2one('res.users', 'Salesman', help="Person who uses the the cash register. It can be a reliever, a student or an interim employee."), + 'amount_tax': fields.function(_amount_all, string='Taxes', digits_compute=dp.get_precision('Point Of Sale'), multi='all'), + 'amount_total': fields.function(_amount_all, string='Total', multi='all'), + 'amount_paid': fields.function(_amount_all, string='Paid', states={'draft': [('readonly', False)]}, readonly=True, digits_compute=dp.get_precision('Point Of Sale'), multi='all'), + 'amount_return': fields.function(_amount_all, 'Returned', digits_compute=dp.get_precision('Point Of Sale'), multi='all'), + 'lines': fields.one2many('pos.order.line', 'order_id', 'Order Lines', states={'draft': [('readonly', False)]}, readonly=True), + 'statement_ids': fields.one2many('account.bank.statement.line', 'pos_statement_id', 'Payments', states={'draft': [('readonly', False)]}, readonly=True), + 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, states={'draft': [('readonly', False)]}, readonly=True), + 'partner_id': fields.many2one('res.partner', 'Customer', change_default=True, select=1, states={'draft': [('readonly', False)], 'paid': [('readonly', False)]}), + + 'session_id' : fields.many2one('pos.session', 'Session', + #required=True, + select=1, + domain="[('state', '=', 'opened')]", + states={'draft' : [('readonly', False)]}, + readonly=True), + + 'state': fields.selection([('draft', 'New'), + ('cancel', 'Cancelled'), + ('paid', 'Paid'), + ('done', 'Posted'), + ('invoiced', 'Invoiced')], + 'Status', readonly=True), + + 'invoice_id': fields.many2one('account.invoice', 'Invoice'), + 'account_move': fields.many2one('account.move', 'Journal Entry', readonly=True), + 'picking_id': fields.many2one('stock.picking', 'Picking', readonly=True), + 'note': fields.text('Internal Notes'), + 'nb_print': fields.integer('Number of Print', readonly=True), + + 'sale_journal': fields.related('session_id', 'config_id', 'journal_id', relation='account.journal', type='many2one', string='Sale Journal', store=True, readonly=True), + } + + def _default_session(self, cr, uid, context=None): + so = self.pool.get('pos.session') + session_ids = so.search(cr, uid, [('state','=', 'opened'), ('user_id','=',uid)], context=context) + return session_ids and session_ids[0] or False + + def _default_pricelist(self, cr, uid, context=None): + res = self.pool.get('sale.shop').search(cr, uid, [], context=context) + if res: + shop = self.pool.get('sale.shop').browse(cr, uid, res[0], context=context) + return shop.pricelist_id and shop.pricelist_id.id or False + return False + + _defaults = { + 'user_id': lambda self, cr, uid, context: uid, + 'state': 'draft', + 'name': '/', + 'date_order': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'nb_print': 0, + 'session_id': _default_session, + 'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id, + 'pricelist_id': _default_pricelist, + } + + def create(self, cr, uid, values, context=None): + values['name'] = self.pool.get('ir.sequence').get(cr, uid, 'pos.order') + return super(pos_order, self).create(cr, uid, values, context=context) + + def test_paid(self, cr, uid, ids, context=None): + """A Point of Sale is paid when the sum + @return: True + """ + for order in self.browse(cr, uid, ids, context=context): + if order.lines and not order.amount_total: + return True + if (not order.lines) or (not order.statement_ids) or \ + (abs(order.amount_total-order.amount_paid) > 0.00001): + return False + return True + + def create_picking(self, cr, uid, ids, context=None): + """Create a picking for each order and validate it.""" + picking_obj = self.pool.get('stock.picking') + partner_obj = self.pool.get('res.partner') + move_obj = self.pool.get('stock.move') + + for order in self.browse(cr, uid, ids, context=context): + if not order.state=='draft': + continue + addr = order.partner_id and partner_obj.address_get(cr, uid, [order.partner_id.id], ['delivery']) or {} + picking_id = picking_obj.create(cr, uid, { + 'origin': order.name, + 'partner_id': addr.get('delivery',False), + 'type': 'out', + 'company_id': order.company_id.id, + 'move_type': 'direct', + 'note': order.note or "", + 'invoice_state': 'none', + 'auto_picking': True, + }, context=context) + self.write(cr, uid, [order.id], {'picking_id': picking_id}, context=context) + location_id = order.shop_id.warehouse_id.lot_stock_id.id + output_id = order.shop_id.warehouse_id.lot_output_id.id + + for line in order.lines: + if line.product_id and line.product_id.type == 'service': + continue + if line.qty < 0: + location_id, output_id = output_id, location_id + + move_obj.create(cr, uid, { + 'name': line.name, + 'product_uom': line.product_id.uom_id.id, + 'product_uos': line.product_id.uom_id.id, + 'picking_id': picking_id, + 'product_id': line.product_id.id, + 'product_uos_qty': abs(line.qty), + 'product_qty': abs(line.qty), + 'tracking_id': False, + 'state': 'draft', + 'location_id': location_id, + 'location_dest_id': output_id, + }, context=context) + if line.qty < 0: + location_id, output_id = output_id, location_id + + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr) + picking_obj.force_assign(cr, uid, [picking_id], context) + return True + + def cancel_order(self, cr, uid, ids, context=None): + """ Changes order state to cancel + @return: True + """ + stock_picking_obj = self.pool.get('stock.picking') + for order in self.browse(cr, uid, ids, context=context): + wf_service.trg_validate(uid, 'stock.picking', order.picking_id.id, 'button_cancel', cr) + if stock_picking_obj.browse(cr, uid, order.picking_id.id, context=context).state <> 'cancel': + raise osv.except_osv(_('Error!'), _('Unable to cancel the picking.')) + self.write(cr, uid, ids, {'state': 'cancel'}, context=context) + return True + + def add_payment(self, cr, uid, order_id, data, context=None): + """Create a new payment for the order""" + if not context: + context = {} + statement_obj = self.pool.get('account.bank.statement') + statement_line_obj = self.pool.get('account.bank.statement.line') + prod_obj = self.pool.get('product.product') + property_obj = self.pool.get('ir.property') + curr_c = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id + curr_company = curr_c.id + order = self.browse(cr, uid, order_id, context=context) + args = { + 'amount': data['amount'], + } + if 'payment_date' in data: + args['date'] = data['payment_date'] + args['name'] = order.name + if data.get('payment_name', False): + args['name'] = args['name'] + ': ' + data['payment_name'] + account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context) + args['account_id'] = (order.partner_id and order.partner_id.property_account_receivable \ + and order.partner_id.property_account_receivable.id) or (account_def and account_def.id) or False + args['partner_id'] = order.partner_id and order.partner_id.id or None + + if not args['account_id']: + if not args['partner_id']: + msg = _('There is no receivable account defined to make payment.') + else: + msg = _('There is no receivable account defined to make payment for the partner: "%s" (id:%d).') % (order.partner_id.name, order.partner_id.id,) + raise osv.except_osv(_('Configuration Error!'), msg) + + context.pop('pos_session_id', False) + + try: + journal_id = long(data['journal']) + except Exception: + journal_id = False + + statement_id = False + for statement in order.session_id.statement_ids: + if statement.journal_id.id == journal_id: + statement_id = statement.id + break + + if not statement_id: + raise osv.except_osv(_('Error!'), _('You have to open at least one cashbox.')) + + args.update({ + 'statement_id' : statement_id, + 'pos_statement_id' : order_id, + 'journal_id' : journal_id, + 'type' : 'customer', + 'ref' : order.name, + }) + + statement_line_obj.create(cr, uid, args, context=context) + + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr) + wf_service.trg_write(uid, 'pos.order', order_id, cr) + + return statement_id + + def refund(self, cr, uid, ids, context=None): + """Create a copy of order for refund order""" + clone_list = [] + line_obj = self.pool.get('pos.order.line') + for order in self.browse(cr, uid, ids, context=context): + clone_id = self.copy(cr, uid, order.id, { + 'name': order.name + ' REFUND', + }, context=context) + clone_list.append(clone_id) + + for clone in self.browse(cr, uid, clone_list, context=context): + for order_line in clone.lines: + line_obj.write(cr, uid, [order_line.id], { + 'qty': -order_line.qty + }, context=context) + + new_order = ','.join(map(str,clone_list)) + abs = { + #'domain': "[('id', 'in', ["+new_order+"])]", + 'name': _('Return Products'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'pos.order', + 'res_id':clone_list[0], + 'view_id': False, + 'context':context, + 'type': 'ir.actions.act_window', + 'nodestroy': True, + 'target': 'current', + } + return abs + + def action_invoice_state(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state':'invoiced'}, context=context) + + def action_invoice(self, cr, uid, ids, context=None): + wf_service = netsvc.LocalService("workflow") + inv_ref = self.pool.get('account.invoice') + inv_line_ref = self.pool.get('account.invoice.line') + product_obj = self.pool.get('product.product') + inv_ids = [] + + for order in self.pool.get('pos.order').browse(cr, uid, ids, context=context): + if order.invoice_id: + inv_ids.append(order.invoice_id.id) + continue + + if not order.partner_id: + raise osv.except_osv(_('Error!'), _('Please provide a partner for the sale.')) + + acc = order.partner_id.property_account_receivable.id + inv = { + 'name': order.name, + 'origin': order.name, + 'account_id': acc, + 'journal_id': order.sale_journal.id or None, + 'type': 'out_invoice', + 'reference': order.name, + 'partner_id': order.partner_id.id, + 'comment': order.note or '', + 'currency_id': order.pricelist_id.currency_id.id, # considering partner's sale pricelist's currency + } + inv.update(inv_ref.onchange_partner_id(cr, uid, [], 'out_invoice', order.partner_id.id)['value']) + if not inv.get('account_id', None): + inv['account_id'] = acc + inv_id = inv_ref.create(cr, uid, inv, context=context) + + self.write(cr, uid, [order.id], {'invoice_id': inv_id, 'state': 'invoiced'}, context=context) + inv_ids.append(inv_id) + for line in order.lines: + inv_line = { + 'invoice_id': inv_id, + 'product_id': line.product_id.id, + 'quantity': line.qty, + } + inv_name = product_obj.name_get(cr, uid, [line.product_id.id], context=context)[0][1] + inv_line.update(inv_line_ref.product_id_change(cr, uid, [], + line.product_id.id, + line.product_id.uom_id.id, + line.qty, partner_id = order.partner_id.id, + fposition_id=order.partner_id.property_account_position.id)['value']) + if line.product_id.description_sale: + inv_line['note'] = line.product_id.description_sale + inv_line['price_unit'] = line.price_unit + inv_line['discount'] = line.discount + inv_line['name'] = inv_name + inv_line['invoice_line_tax_id'] = ('invoice_line_tax_id' in inv_line)\ + and [(6, 0, inv_line['invoice_line_tax_id'])] or [] + inv_line_ref.create(cr, uid, inv_line, context=context) + inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context) + wf_service.trg_validate(uid, 'pos.order', order.id, 'invoice', cr) + + if not inv_ids: return {} + + mod_obj = self.pool.get('ir.model.data') + res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_form') + res_id = res and res[1] or False + return { + 'name': _('Customer Invoice'), + 'view_type': 'form', + 'view_mode': 'form', + 'view_id': [res_id], + 'res_model': 'account.invoice', + 'context': "{'type':'out_invoice'}", + 'type': 'ir.actions.act_window', + 'nodestroy': True, + 'target': 'current', + 'res_id': inv_ids and inv_ids[0] or False, + } + + def create_account_move(self, cr, uid, ids, context=None): + return self._create_account_move_line(cr, uid, ids, None, None, context=context) + + def _create_account_move_line(self, cr, uid, ids, session=None, move_id=None, context=None): + # Tricky, via the workflow, we only have one id in the ids variable + """Create a account move line of order grouped by products or not.""" + account_move_obj = self.pool.get('account.move') + account_move_line_obj = self.pool.get('account.move.line') + account_period_obj = self.pool.get('account.period') + account_tax_obj = self.pool.get('account.tax') + user_proxy = self.pool.get('res.users') + property_obj = self.pool.get('ir.property') + + period = account_period_obj.find(cr, uid, context=context)[0] + + #session_ids = set(order.session_id for order in self.browse(cr, uid, ids, context=context)) + + if session and not all(session.id == order.session_id.id for order in self.browse(cr, uid, ids, context=context)): + raise osv.except_osv(_('Error!'), _('Selected orders do not have the same session!')) + + current_company = user_proxy.browse(cr, uid, uid, context=context).company_id + + grouped_data = {} + have_to_group_by = session and session.config_id.group_by or False + + def compute_tax(amount, tax, line): + if amount > 0: + tax_code_id = tax['base_code_id'] + tax_amount = line.price_subtotal * tax['base_sign'] + else: + tax_code_id = tax['ref_base_code_id'] + tax_amount = line.price_subtotal * tax['ref_base_sign'] + + return (tax_code_id, tax_amount,) + + for order in self.browse(cr, uid, ids, context=context): + if order.account_move: + continue + if order.state != 'paid': + continue + + user_company = user_proxy.browse(cr, order.user_id.id, order.user_id.id).company_id + + group_tax = {} + account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context).id + + order_account = order.partner_id and \ + order.partner_id.property_account_receivable and \ + order.partner_id.property_account_receivable.id or account_def or current_company.account_receivable.id + + if move_id is None: + # Create an entry for the sale + move_id = account_move_obj.create(cr, uid, { + 'ref' : order.name, + 'journal_id': order.sale_journal.id, + }, context=context) + + def insert_data(data_type, values): + # if have_to_group_by: + + sale_journal_id = order.sale_journal.id + + # 'quantity': line.qty, + # 'product_id': line.product_id.id, + values.update({ + 'date': order.date_order[:10], + 'ref': order.name, + 'journal_id' : sale_journal_id, + 'period_id' : period, + 'move_id' : move_id, + 'company_id': user_company and user_company.id or False, + }) + + if data_type == 'product': + key = ('product', values['product_id'],) + elif data_type == 'tax': + key = ('tax', values['tax_code_id'],) + elif data_type == 'counter_part': + key = ('counter_part', values['partner_id'], values['account_id']) + else: + return + + grouped_data.setdefault(key, []) + + # if not have_to_group_by or (not grouped_data[key]): + # grouped_data[key].append(values) + # else: + # pass + + if have_to_group_by: + if not grouped_data[key]: + grouped_data[key].append(values) + else: + current_value = grouped_data[key][0] + current_value['quantity'] = current_value.get('quantity', 0.0) + values.get('quantity', 0.0) + current_value['credit'] = current_value.get('credit', 0.0) + values.get('credit', 0.0) + current_value['debit'] = current_value.get('debit', 0.0) + values.get('debit', 0.0) + current_value['tax_amount'] = current_value.get('tax_amount', 0.0) + values.get('tax_amount', 0.0) + else: + grouped_data[key].append(values) + + # Create an move for each order line + + for line in order.lines: + tax_amount = 0 + taxes = [t for t in line.product_id.taxes_id] + computed_taxes = account_tax_obj.compute_all(cr, uid, taxes, line.price_unit * (100.0-line.discount) / 100.0, line.qty)['taxes'] + + for tax in computed_taxes: + tax_amount += round(tax['amount'], 2) + group_key = (tax['tax_code_id'], tax['base_code_id'], tax['account_collected_id'], tax['id']) + + group_tax.setdefault(group_key, 0) + group_tax[group_key] += round(tax['amount'], 2) + + amount = line.price_subtotal + + # Search for the income account + if line.product_id.property_account_income.id: + income_account = line.product_id.property_account_income.id + elif line.product_id.categ_id.property_account_income_categ.id: + income_account = line.product_id.categ_id.property_account_income_categ.id + else: + raise osv.except_osv(_('Error!'), _('Please define income '\ + 'account for this product: "%s" (id:%d).') \ + % (line.product_id.name, line.product_id.id, )) + + # Empty the tax list as long as there is no tax code: + tax_code_id = False + tax_amount = 0 + while computed_taxes: + tax = computed_taxes.pop(0) + tax_code_id, tax_amount = compute_tax(amount, tax, line) + + # If there is one we stop + if tax_code_id: + break + + # Create a move for the line + insert_data('product', { + 'name': line.product_id.name, + 'quantity': line.qty, + 'product_id': line.product_id.id, + 'account_id': income_account, + 'credit': ((amount>0) and amount) or 0.0, + 'debit': ((amount<0) and -amount) or 0.0, + 'tax_code_id': tax_code_id, + 'tax_amount': tax_amount, + 'partner_id': order.partner_id and order.partner_id.id or False + }) + + # For each remaining tax with a code, whe create a move line + for tax in computed_taxes: + tax_code_id, tax_amount = compute_tax(amount, tax, line) + if not tax_code_id: + continue + + insert_data('tax', { + 'name': _('Tax'), + 'product_id':line.product_id.id, + 'quantity': line.qty, + 'account_id': income_account, + 'credit': 0.0, + 'debit': 0.0, + 'tax_code_id': tax_code_id, + 'tax_amount': tax_amount, + }) + + # Create a move for each tax group + (tax_code_pos, base_code_pos, account_pos, tax_id)= (0, 1, 2, 3) + + for key, tax_amount in group_tax.items(): + tax = self.pool.get('account.tax').browse(cr, uid, key[tax_id], context=context) + insert_data('tax', { + 'name': _('Tax') + ' ' + tax.name, + 'quantity': line.qty, + 'product_id': line.product_id.id, + 'account_id': key[account_pos], + 'credit': ((tax_amount>0) and tax_amount) or 0.0, + 'debit': ((tax_amount<0) and -tax_amount) or 0.0, + 'tax_code_id': key[tax_code_pos], + 'tax_amount': tax_amount, + }) + + # counterpart + insert_data('counter_part', { + 'name': _("Trade Receivables"), #order.name, + 'account_id': order_account, + 'credit': ((order.amount_total < 0) and -order.amount_total) or 0.0, + 'debit': ((order.amount_total > 0) and order.amount_total) or 0.0, + 'partner_id': order.partner_id and order.partner_id.id or False + }) + + order.write({'state':'done', 'account_move': move_id}) + + for group_key, group_data in grouped_data.iteritems(): + for value in group_data: + account_move_line_obj.create(cr, uid, value, context=context) + + return True + + def action_payment(self, cr, uid, ids, context=None): + return self.write(cr, uid, ids, {'state': 'payment'}, context=context) + + def action_paid(self, cr, uid, ids, context=None): + self.create_picking(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state': 'paid'}, context=context) + return True + + def action_cancel(self, cr, uid, ids, context=None): + self.write(cr, uid, ids, {'state': 'cancel'}, context=context) + return True + + def action_done(self, cr, uid, ids, context=None): + self.create_account_move(cr, uid, ids, context=context) + return True + +class account_bank_statement(osv.osv): + _inherit = 'account.bank.statement' + _columns= { + 'user_id': fields.many2one('res.users', 'User', readonly=True), + } + _defaults = { + 'user_id': lambda self,cr,uid,c={}: uid + } +account_bank_statement() + +class account_bank_statement_line(osv.osv): + _inherit = 'account.bank.statement.line' + _columns= { + 'pos_statement_id': fields.many2one('pos.order', ondelete='cascade'), + } +account_bank_statement_line() + +class pos_order_line(osv.osv): + _name = "pos.order.line" + _description = "Lines of Point of Sale" + _rec_name = "product_id" + + def _amount_line_all(self, cr, uid, ids, field_names, arg, context=None): + res = dict([(i, {}) for i in ids]) + account_tax_obj = self.pool.get('account.tax') + cur_obj = self.pool.get('res.currency') + for line in self.browse(cr, uid, ids, context=context): + taxes = line.product_id.taxes_id + price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) + taxes = account_tax_obj.compute_all(cr, uid, line.product_id.taxes_id, price, line.qty, product=line.product_id, partner=line.order_id.partner_id or False) + + cur = line.order_id.pricelist_id.currency_id + res[line.id]['price_subtotal'] = cur_obj.round(cr, uid, cur, taxes['total']) + res[line.id]['price_subtotal_incl'] = cur_obj.round(cr, uid, cur, taxes['total_included']) + return res + + def onchange_product_id(self, cr, uid, ids, pricelist, product_id, qty=0, partner_id=False, context=None): + context = context or {} + if not product_id: + return {} + if not pricelist: + raise osv.except_osv(_('No Pricelist !'), + _('You have to select a pricelist in the sale form !\n' \ + 'Please set one before choosing a product.')) + + price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], + product_id, qty or 1.0, partner_id)[pricelist] + + result = self.onchange_qty(cr, uid, ids, product_id, 0.0, qty, price, context=context) + result['value']['price_unit'] = price + return result + + def onchange_qty(self, cr, uid, ids, product, discount, qty, price_unit, context=None): + result = {} + if not product: + return result + account_tax_obj = self.pool.get('account.tax') + cur_obj = self.pool.get('res.currency') + + prod = self.pool.get('product.product').browse(cr, uid, product, context=context) + + taxes = prod.taxes_id + price = price_unit * (1 - (discount or 0.0) / 100.0) + taxes = account_tax_obj.compute_all(cr, uid, prod.taxes_id, price, qty, product=prod, partner=False) + + result['price_subtotal'] = taxes['total'] + result['price_subtotal_incl'] = taxes['total_included'] + return {'value': result} + + _columns = { + 'company_id': fields.many2one('res.company', 'Company', required=True), + 'name': fields.char('Line No', size=32, required=True), + 'notice': fields.char('Discount Notice', size=128), + 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True, change_default=True), + 'price_unit': fields.float(string='Unit Price', digits=(16, 2)), + 'qty': fields.float('Quantity', digits=(16, 2)), + 'price_subtotal': fields.function(_amount_line_all, multi='pos_order_line_amount', string='Subtotal w/o Tax', store=True), + 'price_subtotal_incl': fields.function(_amount_line_all, multi='pos_order_line_amount', string='Subtotal', store=True), + 'discount': fields.float('Discount (%)', digits=(16, 2)), + 'order_id': fields.many2one('pos.order', 'Order Ref', ondelete='cascade'), + 'create_date': fields.datetime('Creation Date', readonly=True), + } + + _defaults = { + 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'pos.order.line'), + 'qty': lambda *a: 1, + 'discount': lambda *a: 0.0, + 'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id, + } + + def copy_data(self, cr, uid, id, default=None, context=None): + if not default: + default = {} + default.update({ + 'name': self.pool.get('ir.sequence').get(cr, uid, 'pos.order.line') + }) + return super(pos_order_line, self).copy_data(cr, uid, id, default, context=context) + +class pos_category(osv.osv): + _name = 'pos.category' + _description = "Point of Sale Category" + _order = "sequence, name" + def _check_recursion(self, cr, uid, ids, context=None): + level = 100 + while len(ids): + cr.execute('select distinct parent_id from pos_category where id IN %s',(tuple(ids),)) + ids = filter(None, map(lambda x:x[0], cr.fetchall())) + if not level: + return False + level -= 1 + return True + + _constraints = [ + (_check_recursion, 'Error ! You cannot create recursive categories.', ['parent_id']) + ] + + def name_get(self, cr, uid, ids, context=None): + if not len(ids): + return [] + reads = self.read(cr, uid, ids, ['name','parent_id'], context=context) + res = [] + for record in reads: + name = record['name'] + if record['parent_id']: + name = record['parent_id'][1]+' / '+name + res.append((record['id'], name)) + return res + + def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None): + res = self.name_get(cr, uid, ids, context=context) + return dict(res) + + def _get_image(self, cr, uid, ids, name, args, context=None): + result = dict.fromkeys(ids, False) + for obj in self.browse(cr, uid, ids, context=context): + result[obj.id] = tools.image_get_resized_images(obj.image) + return result + + def _set_image(self, cr, uid, id, name, value, args, context=None): + return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) + + _columns = { + 'name': fields.char('Name', size=64, required=True, translate=True), + 'complete_name': fields.function(_name_get_fnc, type="char", string='Name'), + 'parent_id': fields.many2one('pos.category','Parent Category', select=True), + 'child_id': fields.one2many('pos.category', 'parent_id', string='Children Categories'), + 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of product categories."), + + # NOTE: there is no 'default image', because by default we don't show thumbnails for categories. However if we have a thumbnail + # for at least one category, then we display a default image on the other, so that the buttons have consistent styling. + # In this case, the default image is set by the js code. + + 'image': fields.binary("Image", + help="This field holds the image used for the category. "\ + "The image is base64 encoded, and PIL-supported. "\ + "It is limited to a 1024x1024 px image."), + 'image_medium': fields.function(_get_image, fnct_inv=_set_image, + string="Medium-sized image", type="binary", multi="_get_image", + store = { + 'pos.category': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), + }, + help="Medium-sized image of the category. It is automatically "\ + "resized as a 180x180 px image, with aspect ratio preserved. "\ + "Use this field in form views or some kanban views."), + 'image_small': fields.function(_get_image, fnct_inv=_set_image, + string="Smal-sized image", type="binary", multi="_get_image", + store = { + 'pos.category': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), + }, + help="Small-sized image of the category. It is automatically "\ + "resized as a 50x50 px image, with aspect ratio preserved. "\ + "Use this field anywhere a small image is required."), + } + +import io, StringIO + +class ean_wizard(osv.osv_memory): + _name = 'pos.ean_wizard' + _columns = { + 'ean13_pattern': fields.char('Ean13 Pattern', size=32, required=True, translate=True), + } + def sanitize_ean13(self, cr, uid, ids, context): + for r in self.browse(cr,uid,ids): + ean13 = openerp.addons.product.product.sanitize_ean13(r.ean13_pattern) + m = context.get('active_model') + m_id = context.get('active_id') + self.pool.get(m).write(cr,uid,[m_id],{'ean13':ean13}) + return { 'type' : 'ir.actions.act_window_close' } + +class product_product(osv.osv): + _inherit = 'product.product' + + + #def _get_small_image(self, cr, uid, ids, prop, unknow_none, context=None): + # result = {} + # for obj in self.browse(cr, uid, ids, context=context): + # if not obj.product_image: + # result[obj.id] = False + # continue + + # image_stream = io.BytesIO(obj.product_image.decode('base64')) + # img = Image.open(image_stream) + # img.thumbnail((120, 100), Image.ANTIALIAS) + # img_stream = StringIO.StringIO() + # img.save(img_stream, "JPEG") + # result[obj.id] = img_stream.getvalue().encode('base64') + # return result + + _columns = { + 'income_pdt': fields.boolean('Point of Sale Cash In', help="This is a product you can use to put cash into a statement for the point of sale backend."), + 'expense_pdt': fields.boolean('Point of Sale Cash Out', help="This is a product you can use to take cash from a statement for the point of sale backend, exemple: money lost, transfer to bank, etc."), + 'pos_categ_id': fields.many2one('pos.category','Point of Sale Category', + help="If you want to sell this product through the point of sale, select the category it belongs to."), + 'to_weight' : fields.boolean('To Weight', help="This category contains products that should be weighted, mainly used for the self-checkout interface"), + } + _defaults = { + 'to_weight' : False, + } + + def edit_ean(self, cr, uid, ids, context): + return { + 'name': "Edit Ean", + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'pos.ean_wizard', + 'target' : 'new', + 'view_id': False, + 'context':context, + } + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/locadis/static/src/css/pos.css b/addons/locadis/static/src/css/pos.css new file mode 100644 index 00000000000..d9ec3ba7cee --- /dev/null +++ b/addons/locadis/static/src/css/pos.css @@ -0,0 +1,4 @@ + +.product-list-empty{ + text-align:center; +} diff --git a/addons/locadis/static/src/js/hello.js b/addons/locadis/static/src/js/hello.js new file mode 100644 index 00000000000..7deacfa994c --- /dev/null +++ b/addons/locadis/static/src/js/hello.js @@ -0,0 +1,12 @@ + +openerp.locadis = function(instance){ + console.log('Hello World!:',instance); + instance.point_of_sale.PosWidget = instance.point_of_sale.PosWidget.extend({ + init:function(parent,options){ + console.log('Tadaaam!',parent,options); + this._super(parent,options); + }, + }); + + /* REMOVE PRODUCTS FROM FIRST LEVEL IN SELF CHECKOUT */ +}; diff --git a/addons/locadis/static/src/js/main.js b/addons/locadis/static/src/js/main.js new file mode 100644 index 00000000000..1d0f41d8360 --- /dev/null +++ b/addons/locadis/static/src/js/main.js @@ -0,0 +1,24 @@ +openerp.locadis = function(instance){ + + var module = instance.point_of_sale; + var QWeb = instance.web.qweb; + + module.ProductListWidget = module.ProductListWidget.extend({ + template_empty: 'ProductEmptyListWidget', + get_category: function(){ + return this.getParent().product_categories_widget.category; + }, + renderElement: function(){ + var ss = this.pos_widget.screen_selector; + console.log('ss',ss); + if(this.get_category().name === 'Root' && ss && ss.get_user_mode() === 'cashier'){ + this.replaceElement(_.str.trim(QWeb.render(this.template_empty,{widget:this}))); + }else{ + this._super(); + } + }, + }); +}; + + + diff --git a/addons/locadis/static/src/xml/pos.xml b/addons/locadis/static/src/xml/pos.xml new file mode 100644 index 00000000000..f69c3b788df --- /dev/null +++ b/addons/locadis/static/src/xml/pos.xml @@ -0,0 +1,15 @@ + + + + +
+
+

Please scan an item

+ +
+
+
+
+ + +
From fe359ed90c75f95ed94ce4e66d686434929fad4c Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 23 Aug 2012 10:32:53 +0530 Subject: [PATCH 043/265] [FIX] remove unnecessary code. bzr revid: tpa@tinyerp.com-20120823050253-ng0muqz77h5cgv14 --- openerp/addons/base/res/res_partner_view.xml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 92a264f0089..018be644d75 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -426,25 +426,6 @@ - - res.payterm - res.payterm - -
- - - -
-
-
- - Payment term - ir.actions.act_window - res.payterm - form - - - Partner Categories From 0d70cdaaf51993a13acbf6964d34e71e601b0525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Thu, 23 Aug 2012 14:18:35 +0200 Subject: [PATCH 044/265] [IMP] locadis: dont_vidange and extra fields added to products bzr revid: fva@openerp.com-20120823121835-o3119dcmu9s0048t --- addons/locadis/__init__.py | 2 +- addons/locadis/__openerp__.py | 10 +++------- addons/locadis/static/src/css/pos.css | 4 +++- addons/locadis/static/src/xml/pos.xml | 3 +-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/addons/locadis/__init__.py b/addons/locadis/__init__.py index e57b362135b..60ffcac8393 100644 --- a/addons/locadis/__init__.py +++ b/addons/locadis/__init__.py @@ -19,7 +19,7 @@ # ############################################################################## -#import point_of_sale +import locadis # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/locadis/__openerp__.py b/addons/locadis/__openerp__.py index 056b8da7fcf..4ec8527fc7a 100644 --- a/addons/locadis/__openerp__.py +++ b/addons/locadis/__openerp__.py @@ -30,14 +30,10 @@ FIXME: product description """, 'author': 'OpenERP SA', - 'images': ['images/cash_registers.jpeg', 'images/pos_analysis.jpeg','images/register_analysis.jpeg','images/sale_order_pos.jpeg','images/product_pos.jpeg'], + 'images': [], 'depends': ['point_of_sale'], - 'init_xml': [], - 'update_xml': [ - ], - 'demo_xml': [ - ], - 'test': [ + 'data':[ + 'locadis_views.xml', ], 'installable': True, 'application': True, diff --git a/addons/locadis/static/src/css/pos.css b/addons/locadis/static/src/css/pos.css index d9ec3ba7cee..075b4dccc27 100644 --- a/addons/locadis/static/src/css/pos.css +++ b/addons/locadis/static/src/css/pos.css @@ -1,4 +1,6 @@ - +.point-of-sale .screen p{ + font-size: 24px; +} .product-list-empty{ text-align:center; } diff --git a/addons/locadis/static/src/xml/pos.xml b/addons/locadis/static/src/xml/pos.xml index f69c3b788df..5ce23396db8 100644 --- a/addons/locadis/static/src/xml/pos.xml +++ b/addons/locadis/static/src/xml/pos.xml @@ -4,12 +4,11 @@
-

Please scan an item

+

Please scan your products

- From 041b29e164a8a1737c5f11ee8447672fbcb3b474 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Fri, 24 Aug 2012 12:03:38 +0530 Subject: [PATCH 045/265] [MERGE]merge with main branch bzr revid: tch@tinyerp.com-20120824063338-xjf9tt2or8mp6kcg --- openerp/addons/base/res/res_bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index 95f05cf89d6..6c654097d15 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -201,7 +201,7 @@ class res_partner_bank(osv.osv): result = self._prepare_name_get(cr, uid, t, val, context=context) except: result += ' [Formatting Error]' - raise osv.except_osv(_("Warning"), _("You cannot avoid default format_layout to result in True")) + raise osv.except_osv(_("Error"), _("You cannot avoid default format_layout to result in True")) res.append((val.id, result)) return res From 523a7610c413d15fbfec104a8aa4c9d9de92085e Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Fri, 24 Aug 2012 12:39:07 +0530 Subject: [PATCH 046/265] [MERGE]merge with main branch bzr revid: tch@tinyerp.com-20120824070907-g6g6jpkj2t10kals --- openerp/addons/base/res/res_bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index 6c654097d15..dbf098f3535 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -201,7 +201,7 @@ class res_partner_bank(osv.osv): result = self._prepare_name_get(cr, uid, t, val, context=context) except: result += ' [Formatting Error]' - raise osv.except_osv(_("Error"), _("You cannot avoid default format_layout to result in True")) + raise osv.except_osv(_("Formating Error"), _("Invalid Bank name")) res.append((val.id, result)) return res From a932d1dc0069e13cd26b113c90aed0d4b3320ff4 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Fri, 24 Aug 2012 14:12:32 +0530 Subject: [PATCH 047/265] [MERGE]merge with main branch bzr revid: tch@tinyerp.com-20120824084232-8b0x7euh7m9f0yor --- openerp/addons/base/res/res_bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index dbf098f3535..112e64de812 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -201,7 +201,7 @@ class res_partner_bank(osv.osv): result = self._prepare_name_get(cr, uid, t, val, context=context) except: result += ' [Formatting Error]' - raise osv.except_osv(_("Formating Error"), _("Invalid Bank name")) + raise osv.except_osv(_("Formating Error"), _("Invalid Bank Account Type Name format.")) res.append((val.id, result)) return res From 7e59db5f0f04dfc165131566f2284d575e194fe6 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Fri, 24 Aug 2012 14:29:18 +0530 Subject: [PATCH 048/265] [MERGE]merge with main branch bzr revid: tch@tinyerp.com-20120824085918-y69p2653fsqw5t9y --- openerp/addons/base/res/res_bank.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index 112e64de812..d07b5d712f7 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -200,7 +200,6 @@ class res_partner_bank(osv.osv): val._data[val.id]['bank_name'] = _('BANK') result = self._prepare_name_get(cr, uid, t, val, context=context) except: - result += ' [Formatting Error]' raise osv.except_osv(_("Formating Error"), _("Invalid Bank Account Type Name format.")) res.append((val.id, result)) return res From 8c4ce402d1aa11e99c7d4e87bbb7e35f68334bc4 Mon Sep 17 00:00:00 2001 From: Hardik Date: Tue, 28 Aug 2012 12:11:11 +0530 Subject: [PATCH 049/265] [IMP]Improved base module as per requirement. bzr revid: hsa@tinyerp.com-20120828064111-msyv13aa07az17zo --- openerp/addons/base/res/res_config.py | 17 +++++++++++++++++ openerp/addons/base/res/res_users.py | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 3f4a052a36b..3399cd1153e 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -553,4 +553,21 @@ class res_config_settings(osv.osv_memory): return act_window.read(cr, uid, action_ids[0], [], context=context) return {} + def name_get(self, cr, uid, ids, context=None): + """ Override name_get method to return an appropriate configuration wizard + name, and not the generated name.""" + if not len(ids): + return [] + # name_get may receive int id instead of an id list + if isinstance(ids, (int, long)): + ids = [ids] + + act_window = self.pool.get('ir.actions.act_window') + action_ids = act_window.search(cr, uid, [('res_model', '=', self._name)], context=context) + name = self._name + if action_ids: + name = act_window.read(cr, uid, action_ids[0], ['name'], context=context)['name'] + + return [(record.id, name) for record in self.browse(cr, uid , ids, context=context)] + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index cddc02673b8..3078d94fd9d 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -51,7 +51,7 @@ class groups(osv.osv): else: res[g.id] = g.name return res - + _columns = { 'name': fields.char('Name', size=64, required=True, translate=True), 'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'), @@ -61,7 +61,7 @@ class groups(osv.osv): 'menu_access': fields.many2many('ir.ui.menu', 'ir_ui_menu_group_rel', 'gid', 'menu_id', 'Access Menu'), 'comment' : fields.text('Comment', size=250, translate=True), 'category_id': fields.many2one('ir.module.category', 'Application', select=True), - 'full_name': fields.function(_get_full_name, type='char', string='Group Name'), + 'full_name': fields.function(_get_full_name, type='char', string='Group Name', store=True), } _sql_constraints = [ @@ -815,7 +815,7 @@ class users_view(osv.osv): 'type': 'selection', 'string': app and app.name or _('Other'), 'selection': [(False, '')] + [(g.id, g.name) for g in gs], - 'help': '\n'.join(tips), + 'help': g.comment, } else: # boolean group fields From 00a456096399c39c5cd8e82772ddc36685efa003 Mon Sep 17 00:00:00 2001 From: "pso (OpenERP)" Date: Tue, 28 Aug 2012 18:17:50 +0530 Subject: [PATCH 050/265] [MERGE] Merged MDI's branch to fix the issue of name_get of ir.actions.todo bzr revid: pso@tinyerp.com-20120828124750-1kbqgdq0mrc0av2b --- openerp/addons/base/res/res_config.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 3f4a052a36b..8dcd5f769fe 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -552,5 +552,22 @@ class res_config_settings(osv.osv_memory): if action_ids: return act_window.read(cr, uid, action_ids[0], [], context=context) return {} + + def name_get(self, cr, uid, ids, context=None): + """ Override name_get method to return an appropriate configuration wizard + name, and not the generated name.""" + + if not len(ids): + return [] + # name_get may receive int id instead of an id list + if isinstance(ids, (int, long)): + ids = [ids] + + act_window = self.pool.get('ir.actions.act_window') + action_ids = act_window.search(cr, uid, [('res_model', '=', self._name)], context=context) + name = self._name + if action_ids: + name = act_window.read(cr, uid, action_ids[0], ['name'], context=context)['name'] + return [(record.id, name) for record in self.browse(cr, uid , ids, context=context)] # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 3abb39324779a68b2c28233ffb4a311200864c4f Mon Sep 17 00:00:00 2001 From: "pso (OpenERP)" Date: Tue, 28 Aug 2012 18:26:23 +0530 Subject: [PATCH 051/265] [IMP] Improvements bzr revid: pso@tinyerp.com-20120828125623-1nq457mpd1dijq4j --- openerp/addons/base/res/res_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 8dcd5f769fe..d6b42e970bf 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -557,7 +557,7 @@ class res_config_settings(osv.osv_memory): """ Override name_get method to return an appropriate configuration wizard name, and not the generated name.""" - if not len(ids): + if not ids: return [] # name_get may receive int id instead of an id list if isinstance(ids, (int, long)): From 7006b17af32d81ebf6b41cae2ca5ea50d1c0f061 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 30 Aug 2012 12:32:15 +0200 Subject: [PATCH 052/265] [IMP] un-b64 the import file field, use raw binary bzr revid: xmo@openerp.com-20120830103215-trv5cjg9jvj8ano1 --- addons/base_import/controllers.py | 2 +- addons/base_import/models.py | 12 +++++------ addons/base_import/tests/test_cases.py | 29 ++++++++++++-------------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/addons/base_import/controllers.py b/addons/base_import/controllers.py index bc014cd8265..d978730b482 100644 --- a/addons/base_import/controllers.py +++ b/addons/base_import/controllers.py @@ -15,7 +15,7 @@ class ImportController(openerpweb.Controller): import_id = int(import_id) written = req.session.model('base_import.import').write(import_id, { - 'file': base64.b64encode(file.read()), + 'file': file.read(), 'file_name': file.filename, 'file_type': file.content_type, }, req.session.eval_context(req.context)) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 2e44c686fd7..f340b582eaa 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -1,10 +1,7 @@ -import base64 -import codecs import csv import itertools import logging import operator -import random try: from cStringIO import StringIO @@ -24,7 +21,8 @@ class ir_import(orm.TransientModel): _columns = { 'res_model': fields.char('Model', size=64), - 'file': fields.binary('File'), + 'file': fields.binary( + 'File', help="File to check and/or import, raw binary (not base64)"), 'file_name': fields.char('File Name', size=None), 'file_mime': fields.char('File Type', size=None), } @@ -123,7 +121,7 @@ class ir_import(orm.TransientModel): :throws UnicodeDecodeError: if ``options.encoding`` is incorrect """ csv_iterator = csv.reader( - StringIO(base64.b64decode(record.file)), + StringIO(record.file), quotechar=options['quote'], delimiter=options['separator']) csv_nonempty = itertools.ifilter(None, csv_iterator) @@ -238,8 +236,8 @@ class ir_import(orm.TransientModel): # even if it yields non-printable characters. This is # in case of UnicodeDecodeError (or csv.Error # compounded with UnicodeDecodeError) - 'preview': base64.b64decode(record.file)[:ERROR_PREVIEW_BYTES]\ - .decode('iso-8859-1'), + 'preview': record.file[:ERROR_PREVIEW_BYTES] + .decode( 'iso-8859-1'), } def _convert_import_data(self, record, fields, options, context=None): diff --git a/addons/base_import/tests/test_cases.py b/addons/base_import/tests/test_cases.py index e2b61c1928b..420140cd2ac 100644 --- a/addons/base_import/tests/test_cases.py +++ b/addons/base_import/tests/test_cases.py @@ -167,15 +167,12 @@ class test_match_headers_multiple(TransactionCase): }) ) -import base64, csv class test_preview(TransactionCase): def make_import(self): Import = self.registry('base_import.import') id = Import.create(self.cr, self.uid, { 'res_model': 'res.users', - 'file': base64.b64encode( - u"로그인,언어\n".encode('euc_kr'), - "bob,1\n"), + 'file': u"로그인,언어\nbob,1\n".encode('euc_kr'), }) return Import, id @@ -211,10 +208,10 @@ class test_preview(TransactionCase): Import = self.registry('base_import.import') id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' + 'file': 'name,Some Value,Counter\n' 'foo,1,2\n' 'bar,3,4\n' - 'qux,5,6\n') + 'qux,5,6\n' }) result = Import.parse_preview(self.cr, self.uid, id, { @@ -248,10 +245,10 @@ class test_convert_import_data(TransactionCase): Import = self.registry('base_import.import') id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' + 'file': 'name,Some Value,Counter\n' 'foo,1,2\n' 'bar,3,4\n' - 'qux,5,6\n') + 'qux,5,6\n' }) record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( @@ -272,10 +269,10 @@ class test_convert_import_data(TransactionCase): Import = self.registry('base_import.import') id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' + 'file': 'name,Some Value,Counter\n' 'foo,1,2\n' 'bar,3,4\n' - 'qux,5,6\n') + 'qux,5,6\n' }) record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( @@ -296,10 +293,10 @@ class test_convert_import_data(TransactionCase): Import = self.registry('base_import.import') id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' + 'file': 'name,Some Value,Counter\n' 'foo,1,2\n' ',3,\n' - ',5,6\n') + ',5,6\n' }) record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( @@ -317,8 +314,8 @@ class test_convert_import_data(TransactionCase): id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' - 'foo,1,2\n') + 'file': 'name,Some Value,Counter\n' + 'foo,1,2\n' }) record = Import.browse(self.cr, self.uid, id) @@ -333,8 +330,8 @@ class test_convert_import_data(TransactionCase): id = Import.create(self.cr, self.uid, { 'res_model': 'base_import.tests.models.preview', - 'file': base64.b64encode('name,Some Value,Counter\n' - 'foo,1,2\n') + 'file': 'name,Some Value,Counter\n' + 'foo,1,2\n' }) record = Import.browse(self.cr, self.uid, id) From 246d9bd37f8cfe36a17f4e4d1ce89c8f44ff39a3 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 30 Aug 2012 12:32:45 +0200 Subject: [PATCH 053/265] [IMP] rename $element to $el bzr revid: xmo@openerp.com-20120830103245-3x8hzqquwqg27sji --- addons/base_import/static/src/js/import.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 3a52ad548ec..81b7397ba00 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -41,7 +41,7 @@ openerp.base_import = function (instance) { events: { 'change input.oe_import_file': 'file_update', 'click input.oe_import_has_header': function (e) { - this.$element.toggleClass( + this.$el.toggleClass( 'oe_import_noheaders', !e.target.checked); this.settings_updated(); }, @@ -93,13 +93,13 @@ openerp.base_import = function (instance) { file_update: function (e) { if (!this.$('input.oe_import_file').val()) { return; } - this.$element.removeClass('oe_import_preview oe_import_error'); - jsonp(this.$element, { + this.$el.removeClass('oe_import_preview oe_import_error'); + jsonp(this.$el, { url: '/base_import/set_file' }, this.proxy('settings_updated')); }, settings_updated: function () { - this.$element.addClass('oe_import_with_file'); + this.$el.addClass('oe_import_with_file'); // TODO: test that write // succeeded? this.Import.call( 'parse_preview', [this.id, this.import_options()]) @@ -107,11 +107,11 @@ openerp.base_import = function (instance) { }, preview: function (result) { if (result.error) { - this.$element.addClass('oe_import_error'); + this.$el.addClass('oe_import_error'); this.$('.oe_import_error_report').html( QWeb.render('ImportView.preview.error', result)); } else { - this.$element.addClass('oe_import_preview'); + this.$el.addClass('oe_import_preview'); this.$('table').html( QWeb.render('ImportView.preview', result)); } @@ -141,7 +141,7 @@ openerp.base_import = function (instance) { } // import failed (or maybe just warnings, if we ever get // warnings?) - this.$element.addClass('oe_import_error'); + this.$el.addClass('oe_import_error'); this.$('.oe_import_error_report').html( QWeb.render('ImportView.error', {errors: errors})); }, From b1407fc769bdde6a45c8214a7c74fbecfbae6234 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 30 Aug 2012 12:39:28 +0200 Subject: [PATCH 054/265] [FIX] field for file mime type is file_type, not file_mime bzr revid: xmo@openerp.com-20120830103928-rjtrdvkzrybfpi0c --- addons/base_import/controllers.py | 1 - addons/base_import/models.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/base_import/controllers.py b/addons/base_import/controllers.py index d978730b482..85ff993e92e 100644 --- a/addons/base_import/controllers.py +++ b/addons/base_import/controllers.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import base64 import simplejson try: diff --git a/addons/base_import/models.py b/addons/base_import/models.py index f340b582eaa..80c6df70a74 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -24,7 +24,7 @@ class ir_import(orm.TransientModel): 'file': fields.binary( 'File', help="File to check and/or import, raw binary (not base64)"), 'file_name': fields.char('File Name', size=None), - 'file_mime': fields.char('File Type', size=None), + 'file_type': fields.char('File Type', size=None), } def get_fields(self, cr, uid, model, context=None, From ca6323607e4b382a3fb9f54a841f35f529267622 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 30 Aug 2012 13:06:03 +0200 Subject: [PATCH 055/265] [IMP] make import objects live for 12 hours when transient cron is active bzr revid: xmo@openerp.com-20120830110603-8stvh3vpsn4vzr4f --- addons/base_import/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 80c6df70a74..0f1d8c5705e 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -18,6 +18,8 @@ ERROR_PREVIEW_BYTES = 200 _logger = logging.getLogger(__name__) class ir_import(orm.TransientModel): _name = 'base_import.import' + # allow imports to survive for 12h in case user is slow + _transient_max_hours = 12.0 _columns = { 'res_model': fields.char('Model', size=64), From e6136314ee05980d80613da39d3b871096231b78 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Thu, 30 Aug 2012 17:42:56 +0530 Subject: [PATCH 056/265] [IMP]Replace category to tag bzr revid: tch@tinyerp.com-20120830121256-kpgxk6spojucj96e --- addons/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project/project.py b/addons/project/project.py index 904e19671cb..d8457f2fb81 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -746,7 +746,7 @@ class task(base_stage, osv.osv): When the case is over, the state is set to \'Done\'.\ If the case needs to be reviewed then the state is \ set to \'Pending\'.'), - 'categ_ids': fields.many2many('project.category', string='Categories'), + 'categ_ids': fields.many2many('project.category', string='Tags'), 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State', help="A task's kanban state indicates special situations affecting it:\n" " * Normal is the default situation\n" From 7c632f13c5bb6a4a4cac6082c873ae0a34cf3032 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Thu, 30 Aug 2012 17:48:04 +0530 Subject: [PATCH 057/265] [IMP]In stage object replace state to status bzr revid: tch@tinyerp.com-20120830121804-xcem0nccdmz50f3c --- addons/crm/crm_view.xml | 2 +- addons/project/project_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml index b51f1288b95..8fa3927beea 100644 --- a/addons/crm/crm_view.xml +++ b/addons/crm/crm_view.xml @@ -183,7 +183,7 @@
- + diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index f864e207141..32b35a9f3f4 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -780,7 +780,7 @@ - + From 2063604ca8ead8846136dd1d9a6d4de249c40bfd Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Thu, 30 Aug 2012 18:13:55 +0530 Subject: [PATCH 058/265] [IMP]mrp:Improve ir.acrion.todo to jump mrp bzr revid: aja@tinyerp.com-20120830124355-5230z42d8f0up3sp --- addons/mrp/res_config_view.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/mrp/res_config_view.xml b/addons/mrp/res_config_view.xml index 4d94e611fdf..16ebbdcb05b 100644 --- a/addons/mrp/res_config_view.xml +++ b/addons/mrp/res_config_view.xml @@ -12,6 +12,9 @@ automatic 100 + + done + From 69af96255b340b14ff794826372d28ac0d0ff89c Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Thu, 30 Aug 2012 18:13:59 +0530 Subject: [PATCH 059/265] [IMP]In stage object replace state to status bzr revid: tch@tinyerp.com-20120830124359-yidn3iwmcq2ubnal --- addons/crm/crm.py | 2 +- addons/crm_claim/crm_claim.py | 2 +- addons/hr_recruitment/hr_recruitment.py | 2 +- addons/project/project.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index b45b8ea8712..b862e977c9a 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -75,7 +75,7 @@ class crm_case_stage(osv.osv): 'requirements': fields.text('Requirements'), 'section_ids':fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', string='Sections', help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), - 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), + 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related status for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), 'case_default': fields.boolean('Common to All Teams', help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."), 'fold': fields.boolean('Hide in Views when Empty', diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py index ec6252bcdca..ba45c95d065 100644 --- a/addons/crm_claim/crm_claim.py +++ b/addons/crm_claim/crm_claim.py @@ -49,7 +49,7 @@ class crm_claim_stage(osv.osv): 'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."), 'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections', help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), - 'state': fields.selection(crm.AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), + 'state': fields.selection(crm.AVAILABLE_STATES, 'State', required=True, help="The related status for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), 'case_refused': fields.boolean('Refused stage', help='Refused stages are specific stages for done.'), 'case_default': fields.boolean('Common to All Teams', diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 6b4839b7b2b..4ddc91fc519 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -61,7 +61,7 @@ class hr_recruitment_stage(osv.osv): 'name': fields.char('Name', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."), 'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."), - 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change according to the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."), + 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related status for the stage. The state of your document will automatically change according to the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."), 'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), 'requirements': fields.text('Requirements'), } diff --git a/addons/project/project.py b/addons/project/project.py index 904e19671cb..6f6207de27c 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -41,7 +41,7 @@ class project_task_type(osv.osv): help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."), 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'), 'state': fields.selection(_TASK_STATE, 'State', required=True, - help="The related state for the stage. The state of your document will automatically change regarding the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."), + help="The related status for the stage. The state of your document will automatically change regarding the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."), 'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), } From 302cabfccb151480895cf9bd8759701667f3a999 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 30 Aug 2012 14:52:32 +0200 Subject: [PATCH 060/265] [IMP] Make CSV options (quoting and separator) customizable Also autogen input ids so labels work correctly without collision risks, and make toggling links more flexible bzr revid: xmo@openerp.com-20120830125232-d7g7s5oid4qivaq2 --- addons/base_import/static/src/css/import.css | 8 ++++++ addons/base_import/static/src/js/import.js | 26 ++++++++++++-------- addons/base_import/static/src/xml/import.xml | 22 ++++++++++++++--- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css index 4bb1fdeaea0..63b53a9e5c1 100644 --- a/addons/base_import/static/src/css/import.css +++ b/addons/base_import/static/src/css/import.css @@ -1,4 +1,5 @@ .oe_import dd, +.oe_import .oe_import_toggled, .oe_import .oe_import_grid, .oe_import .oe_import_error_report, .oe_import .oe_import_with_file, @@ -25,3 +26,10 @@ .oe_import .oe_import_noheaders { color: #888; } + +.oe_import a.oe_import_toggle { + display: block; +} +.oe_import a.oe_import_toggle:before { + content: '> ' +} diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 81b7397ba00..99397304d16 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -38,22 +38,26 @@ openerp.base_import = function (instance) { instance.web.DataImport = instance.web.Dialog.extend({ template: 'ImportView', dialog_title: _lt("Import Data"), + defaults: { + quoting: '"', + separator: ',', + }, events: { 'change input.oe_import_file': 'file_update', - 'click input.oe_import_has_header': function (e) { - this.$el.toggleClass( - 'oe_import_noheaders', !e.target.checked); - this.settings_updated(); - }, + 'change input:not(.oe_import_file)': 'settings_updated', 'click a.oe_import_csv': function (e) { e.preventDefault(); }, 'click a.oe_import_export': function (e) { e.preventDefault(); }, - 'click dt a': function (e) { + 'click a.oe_import_toggle': function (e) { e.preventDefault(); - $(e.target).parent().next().toggle(); + var $el = $(e.target); + ($el.next().length + ? $el.next() + : $el.parent().next()) + .toggle(); } }, init: function (parent, dataset) { @@ -82,9 +86,8 @@ openerp.base_import = function (instance) { import_options: function () { return { - // TODO: customizable gangnam style - quote: '"', - separator: ',', + quote: this.$('input.oe_import_quoting').val(), + separator: this.$('input.oe_import_separator').val(), headers: this.$('input.oe_import_has_header').prop('checked'), }; }, @@ -106,6 +109,9 @@ openerp.base_import = function (instance) { .then(this.proxy('preview')); }, preview: function (result) { + this.$el.toggleClass( + 'oe_import_noheaders', + !this.$('input.oe_import_has_header').prop('checked')); if (result.error) { this.$el.addClass('oe_import_error'); this.$('.oe_import_error_report').html( diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index bb4f1d742d5..a85f8e960c1 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -1,5 +1,6 @@ + @@ -9,8 +10,9 @@ file to import. If you need a sample importable file, you can use the export tool to generate one.

- - + +

Map your data to OpenERP

@@ -25,11 +27,23 @@
- + + File Format Options… +
+ + + +
+ + +

Frequently Asked Questions

-
Need to import data from an other application?
+
+ Need to import data from an other application?

In order to re-create relationships between different records, you should use the unique From 3a9b697e9cafb41d3cfeef4f2095a7a3e37562b6 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Thu, 30 Aug 2012 18:31:19 +0530 Subject: [PATCH 061/265] [IMP]In stage object replace state to status bzr revid: tch@tinyerp.com-20120830130119-o1ofjtiwuhlmbu2x --- addons/mrp/res_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mrp/res_config.py b/addons/mrp/res_config.py index 555010c2be1..34717d985c0 100644 --- a/addons/mrp/res_config.py +++ b/addons/mrp/res_config.py @@ -65,7 +65,7 @@ class mrp_config_settings(osv.osv_memory): help="""Routings allow you to create and manage the manufacturing operations that should be followed within your work centers in order to produce a product. They are attached to bills of materials that will define the required raw materials."""), - 'group_mrp_properties': fields.boolean("allow several bill of materials per products", + 'group_mrp_properties': fields.boolean("allow several bill of materials per products using properties", implied_group='product.group_mrp_properties', help="""The selection of the right Bill of Material to use will depend on the properties specified on the sale order and the Bill of Material."""), 'module_product_manufacturer': fields.boolean("define manufacturers on products ", From 3f2ced5a06fe5f47dc813399efadcf4a9bdd592b Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Thu, 30 Aug 2012 18:33:59 +0530 Subject: [PATCH 062/265] [IMP]mrp:change default supply method bzr revid: aja@tinyerp.com-20120830130359-bslgfmtvoqcl12hf --- addons/mrp/mrp_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 99c8befbb6c..d7d59d5cfdd 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -649,7 +649,7 @@

- +

File Format Options… -
- - - -
- - +
+

+ + + +

Frequently Asked Questions

diff --git a/addons/base_import/tests/test_cases.py b/addons/base_import/tests/test_cases.py index 420140cd2ac..5479ae94428 100644 --- a/addons/base_import/tests/test_cases.py +++ b/addons/base_import/tests/test_cases.py @@ -179,7 +179,7 @@ class test_preview(TransactionCase): def test_encoding(self): Import, id = self.make_import() result = Import.parse_preview(self.cr, self.uid, id, { - 'quote': '"', + 'quoting': '"', 'separator': ',', }) self.assertTrue('error' in result) @@ -188,7 +188,7 @@ class test_preview(TransactionCase): Import, id = self.make_import() result = Import.parse_preview(self.cr, self.uid, id, { - 'quote': 'foo', + 'quoting': 'foo', 'separator': ',', 'encoding': 'euc_kr', }) @@ -198,7 +198,7 @@ class test_preview(TransactionCase): Import, id = self.make_import() result = Import.parse_preview(self.cr, self.uid, id, { - 'quote': '"', + 'quoting': '"', 'separator': 'bob', 'encoding': 'euc_kr', }) @@ -215,7 +215,7 @@ class test_preview(TransactionCase): }) result = Import.parse_preview(self.cr, self.uid, id, { - 'quote': '"', + 'quoting': '"', 'separator': ',', 'headers': True, }) @@ -253,7 +253,7 @@ class test_convert_import_data(TransactionCase): record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( record, ['name', 'somevalue', 'othervalue'], - {'quote': '"', 'separator': ',', 'headers': True,}) + {'quoting': '"', 'separator': ',', 'headers': True,}) self.assertItemsEqual(fields, ['name', 'somevalue', 'othervalue']) self.assertItemsEqual(data, [ @@ -277,7 +277,7 @@ class test_convert_import_data(TransactionCase): record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( record, ['name', False, 'othervalue'], - {'quote': '"', 'separator': ',', 'headers': True,}) + {'quoting': '"', 'separator': ',', 'headers': True,}) self.assertItemsEqual(fields, ['name', 'othervalue']) self.assertItemsEqual(data, [ @@ -301,7 +301,7 @@ class test_convert_import_data(TransactionCase): record = Import.browse(self.cr, self.uid, id) data, fields = Import._convert_import_data( record, ['name', False, 'othervalue'], - {'quote': '"', 'separator': ',', 'headers': True,}) + {'quoting': '"', 'separator': ',', 'headers': True,}) self.assertItemsEqual(fields, ['name', 'othervalue']) self.assertItemsEqual(data, [ @@ -323,7 +323,7 @@ class test_convert_import_data(TransactionCase): ValueError, Import._convert_import_data, record, [], - {'quote': '"', 'separator': ',', 'headers': True,}) + {'quoting': '"', 'separator': ',', 'headers': True,}) def test_falsefields(self): Import = self.registry('base_import.import') @@ -339,4 +339,4 @@ class test_convert_import_data(TransactionCase): ValueError, Import._convert_import_data, record, [False, False, False], - {'quote': '"', 'separator': ',', 'headers': True,}) + {'quoting': '"', 'separator': ',', 'headers': True,}) From 28d177e520800af7ef6333765a562246174c9eb4 Mon Sep 17 00:00:00 2001 From: Tejas Tank Date: Thu, 30 Aug 2012 19:53:48 +0530 Subject: [PATCH 065/265] [FIX] i18n address format bzr revid: tta@openerp.com-20120830142348-vm37rbyceaup8zfq --- openerp/addons/base/res/res_partner.py | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 93d12228ebe..f70b45d9472 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -507,6 +507,40 @@ class res_partner(osv.osv): args['company_name'] = '' return address_format % args + def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): + res = super(res_partner,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu) + if view_type == 'form': + fieldstyle = { 'state_id': {'placeholder': "State", 'style': "width:24%;", 'options': '{"no_open": true}', 'class': "oe_no_button"}, + 'city': {'placeholder': "City", 'style': "width: 40%;", 'options': '', 'class': ""}, + 'zip': {'placeholder': "ZIP", 'style': 'width:34%;', 'options': '', 'class': ""} + } + country_id = self.pool.get('res.users').browse(cr, uid, uid,context).company_id.country_id + if country_id and country_id.address_format: + address_format = country_id.address_format + else: + address_format = self._defaults['address_format'] + address_format = address_format.replace("_code","_id").replace("_name","_id") + fields = re.findall('(state_id|city|zip)', address_format) + + nodelist = [] + doc = etree.XML(res['arch']) + for field in ['city','state_id','zip']: + nodelist.append(doc.xpath("//field[@name='%s']" % (field))[0]) + + tot = len(fields) + for idx, node in enumerate(nodelist): + if idx < tot: + field = fields[idx] + node.set('name', fields[idx]) + node.set('style', fieldstyle[field]['style']) + node.set('placeholder', fieldstyle[field]['placeholder']) + node.set('options', fieldstyle[field]['options']) + node.set('class', fieldstyle[field]['class']) + else: + node.getparent().remove(node) + + res['arch'] = etree.tostring(doc) + return res # res.partner.address is deprecated; it is still there for backward compability only and will be removed in next version From 4431d24355b8a230c519eedaa886fa3f97802d77 Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Fri, 31 Aug 2012 10:30:28 +0530 Subject: [PATCH 066/265] [REM]Remove mrp_bom_revision bzr revid: aja@tinyerp.com-20120831050028-aoprwoo3bq8x0f75 --- addons/mrp/i18n/mrp.pot | 55 -------------------- addons/mrp/mrp.py | 21 -------- addons/mrp/mrp_view.xml | 37 +++---------- addons/mrp/security/ir.model.access.csv | 2 - addons/sale_mrp/security/ir.model.access.csv | 1 - 5 files changed, 7 insertions(+), 109 deletions(-) diff --git a/addons/mrp/i18n/mrp.pot b/addons/mrp/i18n/mrp.pot index 1223b21f55d..21c397bd1b0 100644 --- a/addons/mrp/i18n/mrp.pot +++ b/addons/mrp/i18n/mrp.pot @@ -196,11 +196,6 @@ msgstr "" msgid "For purchased material" msgstr "" -#. module: mrp -#: field:mrp.bom.revision,indice:0 -msgid "Revision" -msgstr "" - #. module: mrp #: model:ir.actions.act_window,help:mrp.product_form_config_action msgid "Create a product form for everything you buy or sell. Specify a supplier if the product can be purchased." @@ -435,11 +430,6 @@ msgstr "" msgid "For Services." msgstr "" -#. module: mrp -#: field:mrp.bom.revision,date:0 -msgid "Modification Date" -msgstr "" - #. module: mrp #: help:mrp.workcenter,costs_cycle_account_id:0 #: help:mrp.workcenter,costs_hour_account_id:0 @@ -493,11 +483,6 @@ msgstr "" msgid "Force Reservation" msgstr "" -#. module: mrp -#: field:mrp.bom.revision,author_id:0 -msgid "Author" -msgstr "" - #. module: mrp #: field:report.mrp.inout,value:0 msgid "Stock value" @@ -761,11 +746,6 @@ msgstr "" msgid "Ready to Produce" msgstr "" -#. module: mrp -#: field:mrp.bom.revision,name:0 -msgid "Modification name" -msgstr "" - #. module: mrp #: view:mrp.bom:0 #: view:mrp.production:0 @@ -1294,11 +1274,6 @@ msgstr "" msgid "Work Center Loads" msgstr "" -#. module: mrp -#: model:ir.model,name:mrp.model_mrp_bom_revision -msgid "Bill of Material Revision" -msgstr "" - #. module: mrp #: help:mrp.production,origin:0 msgid "Reference of the document that generated this production order request." @@ -1772,12 +1747,6 @@ msgstr "" msgid "Orange Juice" msgstr "" -#. module: mrp -#: field:mrp.bom.revision,bom_id:0 -#: field:procurement.order,bom_id:0 -msgid "BoM" -msgstr "" - #. module: mrp #: model:ir.model,name:mrp.model_report_mrp_inout #: view:report.mrp.inout:0 @@ -1795,17 +1764,6 @@ msgstr "" msgid "Waiting Goods" msgstr "" -#. module: mrp -#: field:mrp.bom.revision,last_indice:0 -msgid "last indice" -msgstr "" - -#. module: mrp -#: field:mrp.bom,revision_ids:0 -#: view:mrp.bom.revision:0 -msgid "BoM Revisions" -msgstr "" - #. module: mrp #: field:report.mrp.inout,date:0 #: field:report.workcenter.load,name:0 @@ -1987,19 +1945,6 @@ msgstr "" msgid "Change Product Qty" msgstr "" -#. module: mrp -#: view:mrp.bom.revision:0 -#: field:mrp.bom.revision,description:0 -#: view:mrp.property:0 -#: view:mrp.property.group:0 -#: field:mrp.routing,note:0 -#: view:mrp.routing.workcenter:0 -#: field:mrp.routing.workcenter,note:0 -#: view:mrp.workcenter:0 -#: field:mrp.workcenter,note:0 -msgid "Description" -msgstr "" - #. module: mrp #: view:board.board:0 msgid "Manufacturing board" diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 7b8442b4c46..07eeff23ca5 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -214,7 +214,6 @@ class mrp_bom(osv.osv): 'bom_id': fields.many2one('mrp.bom', 'Parent BoM', ondelete='cascade', select=True), 'routing_id': fields.many2one('mrp.routing', 'Routing', help="The list of operations (list of work centers) to produce the finished product. The routing is mainly used to compute work center costs during operations and to plan future loads on work centers based on production planning."), 'property_ids': fields.many2many('mrp.property', 'mrp_bom_property_rel', 'bom_id','property_id', 'Properties'), - 'revision_ids': fields.one2many('mrp.bom.revision', 'bom_id', 'BoM Revisions'), 'child_complete_ids': fields.function(_child_compute, relation='mrp.bom', string="BoM Hierarchy", type='many2many'), 'company_id': fields.many2one('res.company','Company',required=True), } @@ -374,26 +373,6 @@ class mrp_bom(osv.osv): mrp_bom() -class mrp_bom_revision(osv.osv): - _name = 'mrp.bom.revision' - _description = 'Bill of Material Revision' - _columns = { - 'name': fields.char('Modification name', size=64, required=True), - 'description': fields.text('Description'), - 'date': fields.date('Modification Date'), - 'indice': fields.char('Revision', size=16), - 'last_indice': fields.char('last indice', size=64), - 'author_id': fields.many2one('res.users', 'Author'), - 'bom_id': fields.many2one('mrp.bom', 'BoM', select=True), - } - - _defaults = { - 'author_id': lambda x, y, z, c: z, - 'date': fields.date.context_today, - } - -mrp_bom_revision() - def rounding(f, r): import math if not r: diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index d7d59d5cfdd..aa37e937af9 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -347,7 +347,7 @@
From 8303bef9ba219c6f4d2633062486b5c611a2a578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 13:14:44 +0200 Subject: [PATCH 120/265] [IMP] Chatter: added support for attachments. bzr revid: tde@openerp.com-20120906111444-n7bsjv0f10p9c3x4 --- addons/mail/mail_message.py | 2 +- addons/mail/static/src/css/mail.css | 20 +++- addons/mail/static/src/js/mail.js | 113 +++++++++++++++----- addons/mail/static/src/js/mail_followers.js | 2 +- addons/mail/static/src/xml/mail.xml | 32 +++++- 5 files changed, 135 insertions(+), 34 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index e4862ca9fb9..dd499f6f170 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -147,7 +147,7 @@ class mail_message(osv.Model): def _message_dict_get(self, cr, uid, msg, context=None): """ Return a dict representation of the message browse record. """ - attachment_ids = self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context) + attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)] author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0] author_user_id = self.pool.get('res.users').name_get(cr, uid, [msg.author_id.user_ids[0].id], context=context)[0] partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 240627c9e6c..34b090cde61 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -307,6 +307,22 @@ padding: 1px; } +/* attachment button: override of openerp values */ +.openerp .oe_mail_msg_content .oe_mail_compose_message_icons div.oe_hidden_input_file { + display: inline-block; + width: 24px; + height: 24px; +} +.openerp .oe_mail_msg_content .oe_mail_compose_message_icons input.oe_form_binary_file { + bottom: 0px; + top: auto; + left: auto; + right: 24px; + height: 24px; + width: 24px; + min-width: 24px; +} + /* ------------------------------------------------------------ */ /* Messages layout /* ------------------------------------------------------------ */ @@ -376,7 +392,7 @@ } /* Attachments list */ -.openerp ul.oe_mail_msg_attachments { +.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments { display: none; width: 100%; border-top: 1px solid #CCC; @@ -384,7 +400,7 @@ padding: .5em 0; list-style-position: inside; } -.openerp ul.oe_mail_msg_attachments li { +.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments li { float: none; margin: 0; padding: 0; diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index a5a64a59a8b..1f2d9fda6a6 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -37,6 +37,27 @@ openerp.mail = function(session) { }, }); + /** + * ------------------------------------------------------------ + * Sidebar + * ------------------------------------------------------------ + * + * Override of sidebar do_attachment_new method, to catch attachments added + * through the sidebar and show them in the Chatter composition form. + */ + + // session.web.Sidebar = session.web.Sidebar.extend({ + // do_attachment_new: function(attachment) { + // this._super(attachment); + // var message_ids = this.getParent().fields.message_ids || undefined; + // if (! message_ids) { return; } + // var compose_message_widget = message_ids.thread.compose_message_widget; + // if (! compose_message_widget) { return; } + // compose_message_widget.attachments.push(attachment); + // compose_message_widget.display_attachments(); + // }, + // }); + /** * ------------------------------------------------------------ * ChatterUtils @@ -60,12 +81,17 @@ openerp.mail = function(session) { mail.ChatterUtils = { - /** get an image in /web/binary/image?... */ - get_image: function(session_prefix, session_id, model, field, id) { - return session_prefix + '/web/binary/image?session_id=' + session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); + /** Get an image in /web/binary/image?... */ + get_image: function(session, model, field, id) { + return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); }, - /** check if the current user is the message author */ + /** Get the url of an attachment {'id': id} */ + get_attachment_url: function (session, attachment) { + return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id']; + }, + + /** Check if the current user is the message author */ is_author: function (widget, message_user_id) { return (widget.session && widget.session.uid != 0 && widget.session.uid == message_user_id); }, @@ -111,21 +137,22 @@ openerp.mail = function(session) { init: function (parent, options) { var self = this; this._super(parent); + this.attachment_ids = []; // options this.options = options || {}; this.options.context = options.context || {}; this.options.form_xml_id = options.form_xml_id || 'email_compose_message_wizard_form_chatter'; this.options.form_view_id = options.form_view_id || false; // debug - // console.groupCollapsed('New ComposeMessage: model', this.options.context.default_res_model, ', id', this.options.context.default_res_id); - // console.log('context:', this.options.context); - // console.groupEnd(); + console.groupCollapsed('New ComposeMessage: model', this.options.context.default_model, ', id', this.options.context.default_res_id); + console.log('context:', this.options.context); + console.groupEnd(); }, start: function () { this._super.apply(this, arguments); // customize display: add avatar, clean previous content - var user_avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.users', 'image_small', this.session.uid); + var user_avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); this.$el.find('img.oe_mail_icon').attr('src', user_avatar); this.$el.find('div.oe_mail_msg_content').empty(); // create a context for the dataset and default_get of the wizard @@ -156,10 +183,42 @@ openerp.mail = function(session) { }); // add the form, bind events, activate the form var msg_node = this.$el.find('div.oe_mail_msg_content'); - return $.when(this.form_view.appendTo(msg_node)).pipe(function() { - self.bind_events(); - self.form_view.do_show(); - }); + return $.when(this.form_view.appendTo(msg_node)).pipe(this.proxy('postprocess_create_form_view')); + }, + + postprocess_create_form_view: function () { + // handle attachment button + this.fileupload_id = _.uniqueId('oe_fileupload'); + var button_attach = this.$el.find('button.oe_mail_compose_message_attachment'); + var rendered = session.web.qweb.render('mail.compose_message.add_attachment', {'widget': this}); + $(rendered).insertBefore(button_attach); + // move the button inside div.oe_hidden_input_file + var input_node = this.$el.find('input[name=ufile]'); + button_attach.detach().insertAfter(input_node); + // set the function called when attachments are added + this.$el.find('input.oe_form_binary_file').change(this.on_attachment_changed); + this.bind_events(); + this.form_view.do_show(); + }, + + /** Called when the user submits a new attachment */ + on_attachment_changed: function(e) { + var $e = $(e.target); + if ($e.val() !== '') { + this.$el.find('form.oe_form_binary_form').submit(); + session.web.blockUI(); + } + }, + + display_attachments: function () { + var attach_node = this.$el.find('div.oe_mail_compose_message_attachments'); + var rendered = session.web.qweb.render('mail.thread.message.attachments', {'record': this}); + attach_node.empty(); + $(rendered).appendTo(attach_node); + this.$el.find('.oe_mail_msg_attachments').show(); + var composer_attachment_ids = _.pluck(this.attachment_ids, 'id'); + var onchange_like = {'value': {'attachment_ids': composer_attachment_ids}} + this.form_view.on_processed_onchange(onchange_like, []); }, /** @@ -170,6 +229,7 @@ openerp.mail = function(session) { refresh: function (new_context) { if (! this.form_view) return; var self = this; + this.attachments = []; this.options.context = _.extend(this.options.context, new_context || {}); this.ds_compose.context = _.extend(this.ds_compose.context, this.options.context); return this.ds_compose.call('default_get', [ @@ -184,11 +244,19 @@ openerp.mail = function(session) { * in the function. */ bind_events: function() { var self = this; - // event: click on 'Attachment' icon-link that opens the dialog to - // add an attachment. + // event: click on 'Attachment' button that opens the dialog to add an attachment. this.$el.on('click', 'button.oe_mail_compose_message_attachment', function (event) { event.stopImmediatePropagation(); }); + // event: add a new attachment + $(window).on(this.fileupload_id, function() { + var args = [].slice.call(arguments).slice(1); + var attachment = args[0]; + attachment['url'] = mail.ChatterUtils.get_attachment_url(self.session, attachment); + self.attachment_ids.push(attachment); + self.display_attachments(); + session.web.unblockUI(); + }); }, }), @@ -407,7 +475,6 @@ openerp.mail = function(session) { } else { self.display_record(record); - // if (self.options.thread_level >= 0) { self.thread = new mail.Thread(self, { 'context': { 'default_model': record.model, @@ -419,7 +486,6 @@ openerp.mail = function(session) { }); self.$el.find('li.oe_mail_thread_msg:last').append('
'); self.thread.appendTo(self.$el.find('div.oe_mail_thread_subthread:last')); - // } } }); if (! _expendable) { @@ -431,7 +497,7 @@ openerp.mail = function(session) { * - record.date: formatting according to the user timezone * - record.timerelative: relative time givein by timeago lib * - record.avatar: image url - * - record.attachments[].url: url of each attachment + * - record.attachment_ids[].url: url of each attachment * - record.is_author: is the current user the author of the record */ display_record: function (record) { // formatting and additional fields @@ -440,14 +506,11 @@ openerp.mail = function(session) { if (record.type == 'email') { record.avatar = ('/mail/static/src/img/email_icon.png'); } else { - record.avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.partner', 'image_small', record.author_id[0]); + record.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', record.author_id[0]); } - //TDE: FIX - if (record.attachments) { - for (var l in record.attachments) { - var url = self.session.origin + '/web/binary/saveas?session_id=' + self.session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id='+records[k].attachments[l].id; - record.attachments[l].url = url; - } + for (var l in record.attachment_ids) { + var attach = record.attachment_ids[l]; + attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach); } record.is_author = mail.ChatterUtils.is_author(this, record.author_user_id[0]); // render, add the expand feature @@ -473,7 +536,7 @@ openerp.mail = function(session) { }, display_user_avatar: function () { - var avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.users', 'image_small', this.options.uid); + var avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); return this.$el.find('img.oe_mail_icon').attr('src', avatar); }, diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index e5d216ed3d2..34976269285 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -79,7 +79,7 @@ openerp_mail_followers = function(session, mail) { var node_user_list = this.$el.find('ul.oe_mail_followers_display').empty(); this.$el.find('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')'); _(records).each(function (record) { - record.avatar_url = mail.ChatterUtils.get_image(self.session.prefix, self.session.session_id, 'res.partner', 'image_small', record.id); + record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id); $(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list); }); if (this.message_is_follower) { diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index f6be765c603..49e861ac870 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -73,6 +73,20 @@
+ + + + + /web/binary/upload_attachment + + + + + + + +
+ + From e34fcc076cdcda1ed6da1cd6ba6aa567eeb0d0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 14:20:46 +0200 Subject: [PATCH 121/265] [FIX] mail.js: fixed wrong res_id passed into subthreads; fixed message_post using a wrong dataset; fixed message_post calling message_fetch after posting with a proxy that gave default values, use a then without args instead. bzr revid: tde@openerp.com-20120906122046-g8vqkqlbb2ymb6ad --- addons/mail/static/src/js/mail.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 1f2d9fda6a6..94ce41802cc 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -478,7 +478,7 @@ openerp.mail = function(session) { self.thread = new mail.Thread(self, { 'context': { 'default_model': record.model, - 'default_id': record.res_id, + 'default_res_id': record.res_id, 'default_parent_id': record.id }, 'message_data': record.child_ids, 'thread_level': self.options.thread_level-1, 'show_header_compose': false, 'show_reply': self.options.thread_level > 1, @@ -547,9 +547,9 @@ openerp.mail = function(session) { var body = comment_node.val(); comment_node.val(''); } - return this.ds_post.call('message_post', [ - [this.options.context.res_id], body, false, 'comment', this.options.context.parent_id] - ).then(this.proxy('message_fetch')); + return this.ds_thread.call('message_post', [ + [this.options.context.default_res_id], body, false, 'comment', this.options.context.default_parent_id, undefined] + ).then(self.message_fetch()); }, /** Action: 'shows more' to fetch new messages */ From a1fe4532239a343054e0d3a05df94dd68f7ac359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 14:52:17 +0200 Subject: [PATCH 122/265] [IMP] mail_message: attachments deleted when unlinking are those with model=self._name, not only 'mail.mesage'. This allows to remove the unlink override in mail.compose.message. bzr revid: tde@openerp.com-20120906125217-27nlyveznh12bk63 --- addons/mail/mail_message.py | 4 ++-- addons/mail/wizard/mail_compose_message.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index dd499f6f170..c76d073c12b 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -310,11 +310,11 @@ class mail_message(osv.Model): attachments_to_delete = [] for mail in self.browse(cr, uid, ids, context=context): for attach in mail.attachment_ids: - if attach.res_model == 'mail.message' and attach.res_id == mail.id: + if attach.res_model == self._name and attach.res_id == mail.id: attachments_to_delete.append(attach.id) if attachments_to_delete: self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context) - return super(mail_message,self).unlink(cr, uid, ids, context=context) + return super(mail_message, self).unlink(cr, uid, ids, context=context) def notify(self, cr, uid, newid, context=None): """ Add the related record followers to the destination partner_ids. diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 3153ccc2069..b62cb11aee2 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -221,12 +221,6 @@ class mail_compose_message(osv.TransientModel): res.update(self._verify_partner_email(cr, uid, value[0][2], context=context)) return res - def unlink(self, cr, uid, ids, context=None): - # Cascade delete all attachments, as they are owned by the composition wizard - for wizard in self.read(cr, uid, ids, ['attachment_ids'], context=context): - self.pool.get('ir.attachment').unlink(cr, uid, wizard['attachment_ids'], context=context) - return super(mail_compose_message, self).unlink(cr, uid, ids, context=context) - def dummy(self, cr, uid, ids, context=None): """ TDE: defined to have buttons that do basically nothing. It is currently impossible to have buttons that do nothing special From 9b9bdae9e008e930eaf1cf208b90f66bdbdf4e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 15:42:01 +0200 Subject: [PATCH 123/265] [IMP] composer: attachments are attached to the mail.compose.message record, not the related document anymore. This way, when deleting the mail.compose.message, attachments will be unlinked. Added deletion cascaded to res_model and res_id = 0, because of attachments added on a not-already-saved composer. BTW, cleaned mail/__openerp__.py. bzr revid: tde@openerp.com-20120906134201-8845xov0mjbxh8mr --- addons/mail/__openerp__.py | 12 ++++++------ addons/mail/mail_message.py | 9 +++++---- addons/mail/static/src/xml/mail.xml | 4 ++-- addons/mail/wizard/mail_compose_message.py | 2 ++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index 99dd6bda6ac..08a98cb0a02 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -30,27 +30,27 @@ A business oriented Social Networking with a fully-integrated email and message =========================================================================================== The Social Networking module provides an unified social network -abstraction layer allowing applications to display a complete +abstraction layer allowing applications to display a complete communication history on documents. It gives the users the possibility to read and send messages and emails in an unified way. -It also provides a feeds page combined to a subscription mechanism, that +It also provides a feeds page combined to a subscription mechanism, that allows to follow documents, and to be constantly updated about recent news. - + The main features of the module are: ------------------------------------ * a clean and renewed communication history for any OpenERP document that can act as a discussion topic, * a discussion mean on documents, - * a subscription mechanism to be updated about new messages on + * a subscription mechanism to be updated about new messages on interesting documents, - * an unified feeds page to see recent messages and activity + * an unified feeds page to see recent messages and activity on followed documents, * user communication through the feeds page, * a threaded discussion design, * relies on the global outgoing mail server, an integrated email - management system allowing to send emails with a configurable + management system allowing to send emails with a configurable scheduler-based processing engine * includes an extensible generic email composition assistant, that can turn into a mass-mailing assistant, and is capable of interpreting diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index c76d073c12b..5fa9b8c45d7 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -306,11 +306,12 @@ class mail_message(osv.Model): def unlink(self, cr, uid, ids, context=None): # cascade-delete attachments that are directly attached to the message (should only happen - # for mail.messages that act as parent for a standalone mail.mail record. + # for mail.messages that act as parent for a standalone mail.mail record). Also remove + # attachment with a void id, because this can happen with the composer. attachments_to_delete = [] - for mail in self.browse(cr, uid, ids, context=context): - for attach in mail.attachment_ids: - if attach.res_model == self._name and attach.res_id == mail.id: + for message in self.browse(cr, uid, ids, context=context): + for attach in message.attachment_ids: + if attach.res_model == self._name and (attach.res_id == message.id or attach.res_id == 0): attachments_to_delete.append(attach.id) if attachments_to_delete: self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context) diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 49e861ac870..161c5e2fcbc 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -81,8 +81,8 @@ /web/binary/upload_attachment - - + + diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index b62cb11aee2..a112e82b590 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -262,6 +262,8 @@ class mail_compose_message(osv.TransientModel): post_values.update(email_dict) # post the message active_model_pool.message_post(cr, uid, [res_id], type='comment', context=context, **post_values) + # post process: update attachments, because id is not necessarily known when adding attachments in Chatter + self.pool.get('ir.attachment').write(cr, uid, [attach.id for attach in wizard.attachment_ids], {'res_id': wizard.id}, context=context) return {'type': 'ir.actions.act_window_close'} From b6eeb581aca218f61d2242929906e25b6ca44cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 15:46:52 +0200 Subject: [PATCH 124/265] [REM] mail.css: removed dead css specifications. bzr revid: tde@openerp.com-20120906134652-qc0br6b4kyxq5bdw --- addons/mail/static/src/css/mail.css | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 34b090cde61..bf272a9fe96 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -338,11 +338,7 @@ text-decoration: none; } -.openerp .oe_mail_msg_subtitle { - margin: 0 0 .5em 0; -} -.openerp .oe_mail_msg_footer, -.openerp .oe_mail_msg_subtitle { +.openerp .oe_mail_msg_footer { color: #888; } @@ -356,12 +352,12 @@ text-align: justify; } -.openerp .oe_mail_msg_body span.oe_mail_msg_tail { - display: inline; +.openerp .oe_mail_msg_body pre { + font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif; } -.openerp .oe_mail_oe_bold { - font-weight: bold; +.openerp .oe_mail_msg_body span.oe_mail_msg_tail { + display: inline; } /* Read more/less link */ From 07663470e5dda3ef0c61912590286fa6992f8aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Sep 2012 16:01:31 +0200 Subject: [PATCH 125/265] [FIX] mail.css: messages in 'pre' now use the OpenERP fonts, without margins. bzr revid: tde@openerp.com-20120906140131-72xxfox3c5ctm4pa --- addons/mail/static/src/css/mail.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index bf272a9fe96..8685ef88d81 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -352,8 +352,9 @@ text-align: justify; } -.openerp .oe_mail_msg_body pre { +.openerp .oe_mail_msg_record_body pre { font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif; + margin: 0px; } .openerp .oe_mail_msg_body span.oe_mail_msg_tail { From 910bc5f00a5ad4838cc3c2693dfd097134921a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 7 Sep 2012 13:54:22 +0200 Subject: [PATCH 126/265] [REV] Reverted hack about attachments, that was not good. bzr revid: tde@openerp.com-20120907115422-zfynv8pdsxk5p3vg --- addons/mail/mail_message.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 5fa9b8c45d7..18a88bb0b61 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -306,12 +306,11 @@ class mail_message(osv.Model): def unlink(self, cr, uid, ids, context=None): # cascade-delete attachments that are directly attached to the message (should only happen - # for mail.messages that act as parent for a standalone mail.mail record). Also remove - # attachment with a void id, because this can happen with the composer. + # for mail.messages that act as parent for a standalone mail.mail record). attachments_to_delete = [] for message in self.browse(cr, uid, ids, context=context): for attach in message.attachment_ids: - if attach.res_model == self._name and (attach.res_id == message.id or attach.res_id == 0): + if attach.res_model == self._name and attach.res_id == message.id: attachments_to_delete.append(attach.id) if attachments_to_delete: self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context) From 6acf8ed15d59581228467886c1e026c557346523 Mon Sep 17 00:00:00 2001 From: "Twinkle Christian (OpenERP)" Date: Fri, 7 Sep 2012 17:38:04 +0530 Subject: [PATCH 127/265] [IMP]Remove serverwarning bzr revid: tch@tinyerp.com-20120907060555-554i3iemfwfh6lwt bzr revid: tch@tinyerp.com-20120907120804-e4z6k6iuzukaipz2 --- openerp/addons/base/base_data.xml | 637 +++++++++++++++++- openerp/addons/base/i18n/es_MX.po | 2 +- openerp/addons/base/res/res_users.py | 3 + .../addons/test_impex/tests/test_export.py | 2 +- .../addons/test_impex/tests/test_import.py | 4 +- 5 files changed, 643 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml index 37c360b5cd8..6f4af968ec0 100644 --- a/openerp/addons/base/base_data.xml +++ b/openerp/addons/base/base_data.xml @@ -1110,9 +1110,644 @@ + + - + + USD + $ + 0.01 + 4 + + + + 1.2834 + + + + + + + VEF + Bs.F + 0.0001 + 4 + + + + 5.864 + + + + + + CAD + $ + 0.01 + 4 + + + + 1.3388 + + + + + + + CHF + CHF + 0.01 + 4 + + + + 1.3086 + + + + + + BRL + R$ + 0.01 + 4 + + + + 2.2344 + + + + + + CNY + ¥ + 0.01 + 4 + + + + 8.7556 + + + + + + + COP + $ + 0.01 + 4 + + + + 2933.8378 + + + + + + CZK + + 0.01 + 4 + + + + 26.5634 + + + + + + DKK + kr + 0.01 + 4 + + + + 7.4445 + + + + + + + HUF + Ft + 0.01 + 4 + + + + 271.5621 + + + + + + IDR + Rp + 0.01 + 4 + + + + 14352.00 + + + + + 11796.39 + + + + + + LVL + Ls + 0.01 + 4 + + + + 0.7086 + + + + + + + NOK + kr + 0.01 + 4 + + + + 7.8668 + + + + + + XPF + XPF + 1.00 + 4 + + + + 119.331742 + + + + + + PAB + B/. + 0.01 + 4 + + + + 1.2676 + + + + + + PLN + + 0.01 + 4 + + + + 4.1005 + + + + + + SEK + kr + 0.01 + 4 + + + + 10.3004 + + + + + + GBP + £ + 0.01 + 4 + + + + 0.8333 + + + + + + ARS + $ + 0.01 + 4 + + + + 5.0881 + + + + + + INR + + 0.01 + 4 + + + + 59.9739 + + + + + + AUD + $ + 0.01 + 4 + + + + 1.4070 + + + + + + UAH + + 0.01 + 4 + + + + 10.1969 + + + + + + VND + + 0.01 + 4 + + + + 26330.01 + + + + + + HKD + $ + 0.01 + 4 + + + + 11.1608 + + + + + + JPY + ¥ + 0.01 + 4 + + + + 133.62 + + + + + + BGN + лв + 0.01 + 4 + + + + 1.9558 + + + + + + LTL + Lt + 0.01 + 4 + + + + 3.4528 + + + + + + RON + lei + 0.01 + 4 + + + + 4.2253 + + + + + + HRK + kn + 0.01 + 4 + + + + 7.2936 + + + + + + RUB + руб + 0.01 + 4 + + + + 43.16 + + + + + + TRY + TL + 0.01 + 4 + + + + 2.1411 + + + + + + KRW + + 0.01 + 4 + + + + 1662.37 + + + + + + MXN + $ + 0.01 + 4 + + + + 18.6664 + + + + + + MYR + RM + 0.01 + 4 + + + + 4.8887 + + + + + + NZD + $ + 0.01 + 4 + + + + 1.9764 + + + + + + PHP + Php + 0.01 + 4 + + + + 66.1 + + + + + + SGD + $ + 0.01 + 4 + + + + 2.0126 + + + + + + THB + ฿ + 0.01 + 4 + + + + 47.779 + + + + + + ZAR + R + 0.01 + 4 + + + + 10.5618 + + + + + + International Bank + + + + CRC + 0.01 + 4 + ¢ + + + + 691.3153 + + + + + + localhost + localhost + + + + + + MUR + Rs + 0.01 + 4 + + + + 40.28 + + + + + + XOF + CFA + 1 + 4 + + + + 655.957 + + + + + + XAF + FCFA + 1 + 4 + + + + 655.957 + + + + + + UGX + USh + 1 + 4 + + + + 3401.91388 + + + + + + HNL + L + 0.01 + 4 + + + + 25 + + + + + + + CLP + $ + 0.01 + 4 + + + + 710 + + + + + + + UYU + $ + 0.01 + 4 + + + + + + 28.36 + + diff --git a/openerp/addons/base/i18n/es_MX.po b/openerp/addons/base/i18n/es_MX.po index cc9d519e705..dbc674d754a 100644 --- a/openerp/addons/base/i18n/es_MX.po +++ b/openerp/addons/base/i18n/es_MX.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-09-08 04:54+0000\n" +"X-Launchpad-Export-Date: 2012-09-07 04:55+0000\n" "X-Generator: Launchpad (build 15914)\n" #. module: base diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index d0f07daa004..8a80a171612 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -157,6 +157,9 @@ class res_users(osv.osv): 'user_email': fields.related('email', type='char', deprecated='Use the email field instead of user_email. This field will be removed with OpenERP 7.1.'), } + _sql_constraints = [ + ('email_uniq', 'UNIQUE (user_email)', 'You can not have two users with the same email!') + ] def on_change_company_id(self, cr, uid, ids, company_id): return {'warning' : { diff --git a/openerp/tests/addons/test_impex/tests/test_export.py b/openerp/tests/addons/test_impex/tests/test_export.py index 7e67ba581a1..26219b36d3b 100644 --- a/openerp/tests/addons/test_impex/tests/test_export.py +++ b/openerp/tests/addons/test_impex/tests/test_export.py @@ -245,7 +245,7 @@ class test_selection(CreatorCase): 'translatable': True, 'date_format': '%d.%m.%Y', 'decimal_point': ',', - 'thousand_sep': ' ', + 'thousands_sep': ' ', }) Translations = self.registry('ir.translation') for source, value in self.translations_fr: diff --git a/openerp/tests/addons/test_impex/tests/test_import.py b/openerp/tests/addons/test_impex/tests/test_import.py index 4712d53feff..a186323c754 100644 --- a/openerp/tests/addons/test_impex/tests/test_import.py +++ b/openerp/tests/addons/test_impex/tests/test_import.py @@ -393,7 +393,7 @@ class test_selection(ImporterCase): 'translatable': True, 'date_format': '%d.%m.%Y', 'decimal_point': ',', - 'thousand_sep': ' ', + 'thousands_sep': ' ', }) Translations = self.registry('ir.translation') for source, value in self.translations_fr: @@ -466,7 +466,7 @@ class test_selection_function(ImporterCase): 'translatable': True, 'date_format': '%d.%m.%Y', 'decimal_point': ',', - 'thousand_sep': ' ', + 'thousands_sep': ' ', }) Translations = self.registry('ir.translation') for source, value in self.translations_fr: From c8440c50943a9a1d820fe3b81323b928bbdbe3fc Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Mon, 10 Sep 2012 10:51:21 +0530 Subject: [PATCH 128/265] [IMP]: Improve readonly-ness of field bzr revid: aja@tinyerp.com-20120910052121-73o2wk7v8yb0ydzd --- addons/mrp/mrp.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index fcb420a475e..063643a2f0a 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -452,9 +452,9 @@ class mrp_production(osv.osv): readonly=True, states={'draft':[('readonly',False)]}, help="Location where the system will stock the finished products."), 'date_planned_end': fields.function(_production_date_end, type='date', string='Scheduled End Date'), - 'date_planned_date': fields.function(_production_date, type='date', string='Scheduled Date', states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), - 'date_planned': fields.datetime('Scheduled Date', required=True, select=1, states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), - 'date_start': fields.datetime('Start Date', select=True, states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), + 'date_planned_date': fields.function(_production_date, type='date', string='Scheduled Date', states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), + 'date_planned': fields.datetime('Scheduled Date', required=True, select=1, states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'confirmed':[('readonly',True)],'done':[('readonly',True)]}), + 'date_start': fields.datetime('Start Date', select=True, states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), 'date_finished': fields.datetime('End Date', select=True), 'bom_id': fields.many2one('mrp.bom', 'Bill of Material', domain=[('bom_id','=',False)], readonly=True, states={'draft':[('readonly',False)]}), @@ -463,11 +463,11 @@ class mrp_production(osv.osv): help="This is the Internal Picking List that brings the finished product to the production plan"), 'move_prod_id': fields.many2one('stock.move', 'Product Move', readonly=True), 'move_lines': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consume', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)],'in_production':[('readonly',True)],'ready':[('readonly',True)]}), - 'move_lines2': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Consumed Products', domain=[('state','in', ('done', 'cancel'))], states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), + 'move_lines2': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Consumed Products', domain=[('state','in', ('done', 'cancel'))], states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), 'move_created_ids': fields.one2many('stock.move', 'production_id', 'Products to Produce', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)],'in_production':[('readonly',True)],'ready':[('readonly',True)]}), 'move_created_ids2': fields.one2many('stock.move', 'production_id', 'Produced Products', domain=[('state','in', ('done', 'cancel'))]), - 'product_lines': fields.one2many('mrp.production.product.line', 'production_id', 'Scheduled goods',states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), - 'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation', states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), + 'product_lines': fields.one2many('mrp.production.product.line', 'production_id', 'Scheduled goods',states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), + 'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation', states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), 'state': fields.selection([('draft','New'),('cancel','Cancelled'),('picking_except', 'Picking Exception'),('confirmed','Waiting Goods'),('ready','Ready to Produce'),('in_production','Production Started'),('done','Done')],'Status', readonly=True, help='When the production order is created the state is set to \'Draft\'.\n If the order is confirmed the state is set to \'Waiting Goods\'.\n If any exceptions are there, the state is set to \'Picking Exception\'.\ \nIf the stock is available then the state is set to \'Ready to Produce\'.\n When the production gets started then the state is set to \'In Production\'.\n When the production is over, the state is set to \'Done\'.'), From b9c3b1efea26697f695195d6157ff38acb3ae6e5 Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Mon, 10 Sep 2012 11:44:09 +0530 Subject: [PATCH 129/265] [IMP]: Improve fields readonly-ness in mrp bzr revid: aja@tinyerp.com-20120910061409-g3ue25pqomfech3m --- addons/mrp/mrp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 063643a2f0a..7243d45bafc 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -436,8 +436,8 @@ class mrp_production(osv.osv): return dest_location_id.id _columns = { - 'name': fields.char('Reference', size=64, required=True, states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), - 'origin': fields.char('Source Document', size=64, help="Reference of the document that generated this production order request.", states={'in_production':[('readonly',True)],'ready':[('readonly',True)]}), + 'name': fields.char('Reference', size=64, required=True, states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), + 'origin': fields.char('Source Document', size=64, help="Reference of the document that generated this production order request.", states={'in_production':[('readonly',True)],'ready':[('readonly',True)],'done':[('readonly',True)]}), 'priority': fields.selection([('0','Not urgent'),('1','Normal'),('2','Urgent'),('3','Very Urgent')], 'Priority', select=True), 'product_id': fields.many2one('product.product', 'Product', required=True, readonly=True, states={'draft':[('readonly',False)]}), From 34d15bb862b67770f293c27d6ed1984f33ca69a8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 10 Sep 2012 09:20:32 +0200 Subject: [PATCH 130/265] [IMP] base_import: lexicographically sort fields in field-matching UI bzr revid: xmo@openerp.com-20120910072032-wbgafg3z45z4l29a --- addons/base_import/static/src/js/import.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 947955d94af..63a266ef6c0 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -199,6 +199,12 @@ openerp.base_import = function (instance) { traverse(field, []); }); + var cmp = function (field1, field2) { + return field1.text.localeCompare(field2.text); + + }; + regulars.sort(cmp); + o2m.sort(cmp); return basic.concat([ { text: _t("Normal Fields"), children: regulars }, { text: _t("Relation Fields"), children: o2m } From 57ff1302c6abff5064e9291317d57829ecbfaff7 Mon Sep 17 00:00:00 2001 From: Jigar Amin - OpenERP Date: Mon, 10 Sep 2012 15:21:04 +0530 Subject: [PATCH 131/265] [FIX] removed not needed states condition bzr revid: jam@tinyerp.com-20120910095104-sb0uco3gwzcr1vo3 --- addons/mrp/mrp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 7243d45bafc..b8ce7752402 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -1069,7 +1069,7 @@ class mrp_production_workcenter_line(osv.osv): _inherit = ['mail.thread'] _columns = { - 'name': fields.char('Work Order', size=64, required=True, states={'in_production':[('readonly',True)]}), + 'name': fields.char('Work Order', size=64, required=True), 'workcenter_id': fields.many2one('mrp.workcenter', 'Work Center', required=True), 'cycle': fields.float('Number of Cycles', digits=(16,2)), 'hour': fields.float('Number of Hours', digits=(16,2)), From 2305856f1ff5d28ec4999f6b019d68727d00cb8d Mon Sep 17 00:00:00 2001 From: Jigar Amin - OpenERP Date: Mon, 10 Sep 2012 16:43:59 +0530 Subject: [PATCH 132/265] [FIX] Update the group of the stock locations on field prodlot bzr revid: jam@tinyerp.com-20120910111359-2odv1fq5bj6wpr46 --- addons/mrp/mrp_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index e677b2564b4..ed60d1e550e 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -688,7 +688,7 @@ - + - - or Import - @@ -698,9 +695,10 @@ - - - Discard + + or + Discard + From e401ca9d69a5a4f76bad7b21a6c9882f97cdfbef Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 11 Sep 2012 08:38:49 +0200 Subject: [PATCH 135/265] [IMP] re-introduce Import button/link when base_import is installed bzr revid: xmo@openerp.com-20120911063849-xqw380wglzxviojf --- addons/base_import/static/src/css/import.css | 7 +++++++ addons/base_import/static/src/js/import.js | 19 +++++++++++++++++++ addons/base_import/static/src/xml/import.xml | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css index 6f4770ce34c..f6258f5aa50 100644 --- a/addons/base_import/static/src/css/import.css +++ b/addons/base_import/static/src/css/import.css @@ -1,3 +1,10 @@ +.openerp .oe_list_buttons .oe_alternative { + visibility: visible; +} +.openerp .oe_list_buttons.oe_editing .oe_list_button_import { + display: none; +} + .oe_import dd, .oe_import .oe_import_toggled, .oe_import .oe_import_grid, diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 63a266ef6c0..c2deb660ff2 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -35,6 +35,25 @@ openerp.base_import = function (instance) { $(form).ajaxSubmit(attributes); } + // if true, the 'Import', 'Export', etc... buttons will be shown + instance.web.ListView.prototype.defaults.import_enabled = true; + instance.web.ListView.include({ + on_loaded: function () { + var self = this; + var add_button = false; + if (!this.$buttons) { + add_button = true; + } + this._super.apply(this, arguments); + if(add_button) { + this.$buttons.on('click', '.oe_list_button_import', function() { + new instance.web.DataImport(self, self.dataset).open(); + return false; + }); + } + } + }); + instance.web.DataImport = instance.web.Dialog.extend({ template: 'ImportView', dialog_title: _lt("Import Data"), diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 733a93fd104..386348bea4b 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -92,4 +92,12 @@ + + + this.attr('t-if', 'widget.options.import_enabled'); + + + Import + + From 7bde4ab749e81b0010a552fa5d005a6d40c8757d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 11 Sep 2012 09:08:58 +0200 Subject: [PATCH 136/265] [IMP] add base_import to configurator bzr revid: xmo@openerp.com-20120911070858-3eb3ny4ts05togk2 --- addons/base_setup/res_config.py | 1 + addons/base_setup/res_config_view.xml | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/addons/base_setup/res_config.py b/addons/base_setup/res_config.py index 4826a50400d..e1920fc05d9 100644 --- a/addons/base_setup/res_config.py +++ b/addons/base_setup/res_config.py @@ -35,6 +35,7 @@ class base_config_settings(osv.osv_memory): 'module_auth_anonymous': fields.boolean('activate the public portal', help="""Enable the public part of openerp, openerp becomes a public website."""), 'module_auth_oauth': fields.boolean('use external authentication providers, sign in with google, facebook, ...'), + 'module_base_import': fields.boolean("Allow users to import data from CSV files"), } def open_company(self, cr, uid, ids, context=None): diff --git a/addons/base_setup/res_config_view.xml b/addons/base_setup/res_config_view.xml index 512c0a3f52e..3852ca03a05 100644 --- a/addons/base_setup/res_config_view.xml +++ b/addons/base_setup/res_config_view.xml @@ -59,6 +59,15 @@ + + From d8998dd2d46be98fa142314f2d7cf1993a82424f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 11 Sep 2012 10:42:15 +0200 Subject: [PATCH 137/265] [IMP] better views bzr revid: fp@tinyerp.com-20120911084215-1er8vwxc9zadiksf --- addons/account/account_view.xml | 32 ++++++------------- .../board_mrp_procurement_view.xml | 4 +-- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 5a3fd6b748a..8c0de73ef8c 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -2369,22 +2369,15 @@ -
-
-
diff --git a/addons/procurement/board_mrp_procurement_view.xml b/addons/procurement/board_mrp_procurement_view.xml index a01ec168efa..f30ea629d5e 100644 --- a/addons/procurement/board_mrp_procurement_view.xml +++ b/addons/procurement/board_mrp_procurement_view.xml @@ -15,9 +15,9 @@ board.board - + - + From 208dcc534f7f43dcfef0f30f7975f9f1bc647b35 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 11 Sep 2012 11:40:02 +0200 Subject: [PATCH 138/265] [FIX] web_linkedin: unbreak config settings layout bzr revid: odo@openerp.com-20120911094002-teg65gi2csps8f72 --- addons/web_linkedin/web_linkedin_view.xml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/addons/web_linkedin/web_linkedin_view.xml b/addons/web_linkedin/web_linkedin_view.xml index 8b4fa617bf3..05a5e32e41a 100644 --- a/addons/web_linkedin/web_linkedin_view.xml +++ b/addons/web_linkedin/web_linkedin_view.xml @@ -18,8 +18,8 @@ sale.config.settings -
-
+
+

To use the LinkedIn module with this database, an API Key is required. Please follow this procedure:

@@ -34,12 +34,11 @@
  • The programming tool is Javascript
  • -
  • Copy the API key down here:
  • +
  • Copy the API key here: + +
  • - - - - +
    From e089d497031aefcc32b225a6958dda9812daf71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 11 Sep 2012 11:40:07 +0200 Subject: [PATCH 139/265] [FIX] sale, mail: fixed Send by email, back to a wizard. Cleaned a bit some code related to that action. bzr revid: tde@openerp.com-20120911094007-svlzik5kgmp4nuvy --- .../wizard/mail_compose_message.py | 6 +++-- addons/mail/static/src/js/mail.js | 24 +++++++++---------- addons/sale/sale.py | 11 ++++++--- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py index 2baef6e6c90..c0cb7fc92e5 100644 --- a/addons/email_template/wizard/mail_compose_message.py +++ b/addons/email_template/wizard/mail_compose_message.py @@ -51,9 +51,11 @@ class mail_compose_message(osv.osv_memory): context = {} result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context) result['template_id'] = context.get('default_template_id', context.get('mail.compose.template_id', False)) - # force html when using templates + # pre-render the template if any if result.get('use_template'): - result['content_subtype'] = 'html' + onchange_res = self.onchange_use_template(cr, uid, [], result.get('use_template'), result.get('template_id'), + result.get('composition_mode'), result.get('model'), result.get('res_id'), context=context) + result.update(onchange_res['value']) return result _columns = { diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index e8d8e25e684..3f23e65f00d 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -17,19 +17,15 @@ openerp.mail = function(session) { */ session.web.FormView = session.web.FormView.extend({ - // TDE FIXME TODO: CHECK WITH NEW BRANCH do_action: function(action, on_close) { if (action.res_model == 'mail.compose.message' && + action.context && action.context.redirect == true && this.fields && this.fields.message_ids && this.fields.message_ids.view.get("actual_mode") != 'create') { - // debug - console.groupCollapsed('FormView do_action on mail.compose.message'); - console.log('message_ids field:', this.fields.message_ids); - console.groupEnd(); var record_thread = this.fields.message_ids; var thread = record_thread.thread; - thread.instantiate_composition_form('comment', true, false, 0, action.context); - return false; + thread.refresh_composition_form(action.context); + return true; } else { return this._super(action, on_close); @@ -174,7 +170,7 @@ openerp.mail = function(session) { this.ds_compose.context = _.extend(this.ds_compose.context, this.options.context); return this.ds_compose.call('default_get', [ ['subject', 'body_text', 'body', 'attachment_ids', 'partner_ids', 'composition_mode', - 'model', 'res_id', 'parent_id', 'content_subtype'], + 'use_template', 'template_id', 'model', 'res_id', 'parent_id', 'content_subtype'], this.ds_compose.get_context(), ]).then( function (result) { self.form_view.on_processed_onchange({'value': result}, []); }); }, @@ -365,6 +361,11 @@ openerp.mail = function(session) { return compose_done; }, + refresh_composition_form: function (context) { + if (! this.compose_message_widget) return; + return this.compose_message_widget.refresh(context); + }, + /** Clean the thread */ message_clean: function() { this.$el.find('div.oe_mail_thread_display').empty(); @@ -548,7 +549,6 @@ openerp.mail = function(session) { this.options.domain = this.options.domain || []; this.options.context = {'default_model': 'mail.thread', 'default_res_id': false}; this.options.thread_level = this.options.thread_level || 0; - this.thread_list = []; }, start: function() { @@ -564,7 +564,7 @@ openerp.mail = function(session) { }, destroy: function() { - for (var i in this.thread_list) { this.thread_list[i].destroy(); } + if (this.thread) { this.thread.destroy(); } this._super.apply(this, arguments); }, @@ -581,13 +581,13 @@ openerp.mail = function(session) { default_model: this.view.model }); // create and render Thread widget this.$el.find('div.oe_mail_recthread_main').empty(); - for (var i in this.thread_list) { this.thread_list[i].destroy(); } + if (this.thread) { this.thread.destroy(); } var thread = new mail.Thread(self, { 'context': this.options.context, 'thread_level': this.options.thread_level, 'show_header_compose': true, 'message_ids': this.get_value(), 'show_delete': true, 'composer': true }); - this.thread_list.push(thread); + this.thread = thread; return thread.appendTo(this.$el.find('div.oe_mail_recthread_main')); }, }); diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 6a6678d6163..553b8993ab8 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -769,13 +769,18 @@ class sale_order(osv.osv): template_id = template and template[1] or False res = mod_obj.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form') res_id = res and res[1] or False - ctx = dict(context, active_model='sale.order', active_id=ids[0]) - ctx.update({'mail.compose.template_id': template_id}) + ctx = dict(context) + ctx.update({ + 'default_model': 'sale.order', + 'default_res_id': ids[0], + 'default_use_template': True, + 'default_template_id': template_id, + }) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'mail.compose.message', - 'views': [(res_id,'form')], + 'views': [(res_id, 'form')], 'view_id': res_id, 'type': 'ir.actions.act_window', 'target': 'new', From 4bcdcf66c83c944cf3e9b0c426a935120cf5acb9 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 11 Sep 2012 11:57:58 +0200 Subject: [PATCH 140/265] [IMP] base_setup: make first label wrap bzr revid: odo@openerp.com-20120911095758-dyedax6zcddgokx4 --- addons/base_setup/res_config_view.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/base_setup/res_config_view.xml b/addons/base_setup/res_config_view.xml index 512c0a3f52e..4b333d939d6 100644 --- a/addons/base_setup/res_config_view.xml +++ b/addons/base_setup/res_config_view.xml @@ -14,9 +14,10 @@
    -
    - +
    - - + + ",""],legend:[1,"
    ","
    "],thead:[1,"

    From 559215872787079d38b2a0432b3655f7dedac6b8 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 12 Sep 2012 14:54:45 +0200 Subject: [PATCH 195/265] [IMP] Crop breadcrumb items bzr revid: fme@openerp.com-20120912125445-kuk7knes2a9ogzd5 --- addons/web/static/src/css/base.css | 7 +++++++ addons/web/static/src/css/base.sass | 6 ++++++ addons/web/static/src/js/views.js | 6 +++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 3c3be4bd2ea..679c3b32a18 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1239,6 +1239,13 @@ .openerp .oe_application > div { height: 100%; } +.openerp .oe_application .oe_breadcrumb_item { + display: inline-block; + max-width: 7em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} .openerp .oe_view_manager .oe_view_manager_body { height: inherit; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 4bf122c6146..7eff29d813e 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -987,6 +987,12 @@ $sheet-max-width: 860px text-decoration: underline > div height: 100% + .oe_breadcrumb_item + display: inline-block + max-width: 7em + white-space: nowrap + overflow: hidden + text-overflow: ellipsis // }}} // ViewManager common {{{ .oe_view_manager diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 2dffe9520a1..0ecb10c7fdc 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -20,7 +20,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ }, start: function() { this._super.apply(this, arguments); - this.$el.on('click', '.oe_breadcrumb_item', this.on_breadcrumb_clicked); + this.$el.on('click', 'a.oe_breadcrumb_item', this.on_breadcrumb_clicked); }, dialog_stop: function () { if (this.dialog) { @@ -95,7 +95,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ break; } } - var subindex = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); + var subindex = $e.parent().find('a.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); this.select_breadcrumb(index, subindex); }, select_breadcrumb: function(index, subindex) { @@ -148,7 +148,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ for (var j = 0; j < tit.length; j += 1) { var label = _.escape(tit[j]); if (i === this.breadcrumbs.length - 1 && j === tit.length - 1) { - titles.push(label); + titles.push(_.str.sprintf('%s', label)); } else { titles.push(_.str.sprintf('%s', item.id, label)); } From ecd3a8a5581922d77b94b55d8df5dfda730acf19 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 12 Sep 2012 15:22:15 +0200 Subject: [PATCH 196/265] [IMP] Do not overflow ellipsis on last breadcrumb item bzr revid: fme@openerp.com-20120912132215-qftamqpgekx0f3w9 --- addons/web/static/src/css/base.css | 2 +- addons/web/static/src/css/base.sass | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 679c3b32a18..05cd43db716 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1239,7 +1239,7 @@ .openerp .oe_application > div { height: 100%; } -.openerp .oe_application .oe_breadcrumb_item { +.openerp .oe_application .oe_breadcrumb_item:not(:last-child) { display: inline-block; max-width: 7em; white-space: nowrap; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 7eff29d813e..bab3d7c6ad4 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -987,7 +987,7 @@ $sheet-max-width: 860px text-decoration: underline > div height: 100% - .oe_breadcrumb_item + .oe_breadcrumb_item:not(:last-child) display: inline-block max-width: 7em white-space: nowrap From f0e9ae756376a6b6ecbbd6bb04d0b2319d63c39d Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 12 Sep 2012 15:26:24 +0200 Subject: [PATCH 197/265] [IMP] stock: remove notification on product when a stock move consumes a product bzr revid: rco@openerp.com-20120912132624-n7mpbywvxv3oputb --- addons/stock/stock.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 006af587c1f..ed242556703 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2539,11 +2539,6 @@ class stock_move(osv.osv): } self.write(cr, uid, [move.id], update_val) - product_obj = self.pool.get('product.product') - for new_move in self.browse(cr, uid, res, context=context): - message = _("Product has been consumed with '%s' quantity.") % (new_move.product_qty) - product_obj.message_post(cr, uid, [new_move.product_id.id], body=message, context=context) - self.action_done(cr, uid, res, context=context) return res From 26d162e80f2f714ab0845ea8346eceebb1f487eb Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 12 Sep 2012 15:27:33 +0200 Subject: [PATCH 198/265] [IMP] mrp: remove redundant domains in form view bzr revid: rco@openerp.com-20120912132733-eo0yfrn1v0dsxmhx --- addons/mrp/mrp_view.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 3167639b25a..8e0550a0c52 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -658,7 +658,7 @@ - + @@ -683,7 +683,7 @@ - + @@ -704,7 +704,7 @@ - + @@ -722,7 +722,7 @@ - + From 828ed33de7c2690405a8350ce9452606117d7a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 15:35:22 +0200 Subject: [PATCH 199/265] [ADD] mail: added Invite wizard, allowing to add partners to the followers. bzr revid: tde@openerp.com-20120912133522-af5dvae1rmburfwy --- addons/mail/mail_message.py | 24 ++++++++++ addons/mail/wizard/__init__.py | 1 + addons/mail/wizard/invite.py | 56 ++++++++++++++++++++++ addons/mail/wizard/invite_view.xml | 29 +++++++++++ addons/mail/wizard/mail_compose_message.py | 20 +------- 5 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 addons/mail/wizard/invite.py create mode 100644 addons/mail/wizard/invite_view.xml diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index e4862ca9fb9..6c65c6b302c 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -25,6 +25,7 @@ import tools from email.header import decode_header from operator import itemgetter from osv import osv, fields +from tools.translate import _ _logger = logging.getLogger(__name__) @@ -341,3 +342,26 @@ class mail_message(osv.Model): default = {} default.update(message_id=False, headers=False) return super(mail_message, self).copy(cr, uid, id, default=default, context=context) + + #------------------------------------------------------ + # Tools + #------------------------------------------------------ + + def verify_partner_email(self, cr, uid, partner_ids, context=None): + """ Verify that selected partner_ids have an email_address defined. + Otherwise throw a warning. """ + partner_wo_email_lst = [] + for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): + if not partner.email: + partner_wo_email_lst.append(partner) + if not partner_wo_email_lst: + return {} + warning_msg = _('The following partners chosen as recipients for the email have no email address linked :') + for partner in partner_wo_email_lst: + warning_msg += '\n- %s' % (partner.name) + return {'warning': { + 'title': _('Partners email addresses not found'), + 'message': warning_msg, + } + } + diff --git a/addons/mail/wizard/__init__.py b/addons/mail/wizard/__init__.py index 88b9581f68e..39a2d843354 100644 --- a/addons/mail/wizard/__init__.py +++ b/addons/mail/wizard/__init__.py @@ -19,6 +19,7 @@ # ############################################################################## +import invite import mail_compose_message # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py new file mode 100644 index 00000000000..71ae23304a8 --- /dev/null +++ b/addons/mail/wizard/invite.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2012-Today OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from osv import osv +from osv import fields + + +class invite_wizard(osv.osv_memory): + """ Wizard to invite partners and make them followers. """ + _name = 'mail.wizard.invite' + _description = 'Invite wizard' + + _columns = { + 'res_model': fields.char('Related Document Model', size=128, + required=True, select=1, + help='Model of the followed resource'), + 'res_id': fields.integer('Related Document ID', select=1, + help='Id of the followed resource'), + 'partner_ids': fields.many2many('res.partner', string='Partners'), + 'message': fields.text('Message'), + } + + def onchange_partner_ids(self, cr, uid, ids, value, context=None): + """ onchange_partner_ids (value format: [[6, 0, [3, 4]]]). The + basic purpose of this method is to check that destination partners + effectively have email addresses. Otherwise a warning is thrown. + """ + res = {'value': {}} + if not value or not value[0] or not value[0][0] == 6: + return + res.update(self.pool.get('mail.message').verify_partner_email(cr, uid, value[0][2], context=context)) + return res + + def add_followers(self, cr, uid, ids, context=None): + for wizard in self.browse(cr, uid, ids, context=context): + model_obj = self.pool.get(wizard.res_model) + model_obj.message_subscribe(cr, uid, [wizard.res_id], [p.id for p in wizard.partner_ids], context=context) + return {'type': 'ir.actions.act_window_close'} diff --git a/addons/mail/wizard/invite_view.xml b/addons/mail/wizard/invite_view.xml new file mode 100644 index 00000000000..b932f96dfe7 --- /dev/null +++ b/addons/mail/wizard/invite_view.xml @@ -0,0 +1,29 @@ + + + + + + + Add Followers + mail.wizard.invite + + + + + + + + +
    +
    + +
    +
    + +
    +
    diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 3153ccc2069..fa4ca090943 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -192,24 +192,6 @@ class mail_compose_message(osv.TransientModel): specific behavior. """ return {'value': {'content_subtype': value}} - def _verify_partner_email(self, cr, uid, partner_ids, context=None): - """ Verify that selected partner_ids have an email_address defined. - Otherwise throw a warning. """ - partner_wo_email_lst = [] - for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): - if not partner.email: - partner_wo_email_lst.append(partner) - if not partner_wo_email_lst: - return {} - warning_msg = _('The following partners chosen as recipients for the email have no email address linked :') - for partner in partner_wo_email_lst: - warning_msg += '\n- %s' % (partner.name) - return {'warning': { - 'title': _('Partners email addresses not found'), - 'message': warning_msg, - } - } - def onchange_partner_ids(self, cr, uid, ids, value, context=None): """ onchange_partner_ids (value format: [[6, 0, [3, 4]]]). The basic purpose of this method is to check that destination partners @@ -218,7 +200,7 @@ class mail_compose_message(osv.TransientModel): res = {'value': {}} if not value or not value[0] or not value[0][0] == 6: return - res.update(self._verify_partner_email(cr, uid, value[0][2], context=context)) + res.update(self.verify_partner_email(cr, uid, value[0][2], context=context)) return res def unlink(self, cr, uid, ids, context=None): From fa91789a52590870dfcd313bef75c114f8d2eb43 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 12 Sep 2012 15:35:37 +0200 Subject: [PATCH 200/265] [IMP] crm: rename 'state' into 'related status' on stages bzr revid: rco@openerp.com-20120912133537-pml9ft4rf9eba272 --- addons/crm/crm.py | 4 +++- addons/crm/crm_view.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index b862e977c9a..aff2bcb610b 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -75,7 +75,9 @@ class crm_case_stage(osv.osv): 'requirements': fields.text('Requirements'), 'section_ids':fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', string='Sections', help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), - 'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related status for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."), + 'state': fields.selection(AVAILABLE_STATES, 'Related Status', required=True, + help="The status of your document will automatically change regarding the selected stage. " \ + "For example, if a stage is related to the state 'Close', when your document reaches this stage, it is automatically closed."), 'case_default': fields.boolean('Common to All Teams', help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."), 'fold': fields.boolean('Hide in Views when Empty', diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml index 8fa3927beea..4f4d73d5f43 100644 --- a/addons/crm/crm_view.xml +++ b/addons/crm/crm_view.xml @@ -183,7 +183,7 @@
    - + From a126eb72b7894f4d38943a63d4a0d3948fcf3067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 15:36:27 +0200 Subject: [PATCH 201/265] [ADD] Chatter: added Invite button and its behavior. It calls the Invite wizard. Added a read_value in mail_followers, to reload the follower values after subscribing, unsubscribing or adding followers through the wizard. bzr revid: tde@openerp.com-20120912133627-pid0uazohsx37trt --- addons/mail/static/src/css/mail.css | 4 -- addons/mail/static/src/js/mail_followers.js | 57 ++++++++++++------- addons/mail/static/src/xml/mail_followers.xml | 3 +- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 815f0ec92c4..a92f6c52832 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -96,10 +96,6 @@ width: 120px; } -.openerp button.oe_mail_button_followers { - display: inline; -} - .openerp button.oe_mail_button_mouseout { color: white; background-color: #8a89ba; diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index e5d216ed3d2..c1ef6d2c844 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -31,17 +31,9 @@ openerp_mail_followers = function(session, mail) { }, start: function() { - var self = this; - // NB: all the widget should be modified to check the actual_mode property on view, not use - // any other method to know if the view is in create mode anymore + // use actual_mode property on view to know if the view is in create mode anymore this.view.on("change:actual_mode", this, this._check_visibility); this._check_visibility(); - this.$el.find('button.oe_mail_button_follow').click(function () { self.do_follow(); }) - .mouseover(function () { $(this).html('Follow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); }) - .mouseleave(function () { $(this).html('Not following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); }); - this.$el.find('button.oe_mail_button_unfollow').click(function () { self.do_unfollow(); }) - .mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); }) - .mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); }); this.reinit(); }, @@ -49,15 +41,41 @@ openerp_mail_followers = function(session, mail) { this.$el.toggle(this.view.get("actual_mode") !== "create"); }, - destroy: function () { - this._super.apply(this, arguments); - }, - reinit: function() { this.$el.find('button.oe_mail_button_follow').hide(); this.$el.find('button.oe_mail_button_unfollow').hide(); }, + bind_events: function() { + var self = this; + this.$el.find('button.oe_mail_button_follow').on('click', function () { self.do_follow(); }) + this.$el.find('button.oe_mail_button_unfollow').on('click', function () { self.do_unfollow(); }) + .mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); }) + .mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); }); + this.$el.find('button.oe_mail_button_invite').on('click', function(event) { + action = { + type: 'ir.actions.act_window', + res_model: 'mail.wizard.invite', + view_mode: 'form', + view_type: 'form', + views: [[false, 'form']], + target: 'new', + context: { + 'default_res_model': self.view.dataset.model, + 'default_res_id': self.view.datarecord.id + }, + } + self.do_action(action, function() { self.read_value(); }); + }); + }, + + read_value: function() { + var self = this; + return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) { + return results[0].message_follower_ids; + }).pipe(this.proxy('set_value')); + }, + set_value: function(value_) { this.reinit(); if (! this.view.datarecord.id || @@ -65,11 +83,12 @@ openerp_mail_followers = function(session, mail) { this.$el.find('div.oe_mail_recthread_aside').hide(); return; } - return this.fetch_followers(value_); + this.bind_events(); + return this.fetch_followers(value_ || this.get_value()); }, fetch_followers: function (value_) { - return this.ds_follow.call('read', [value_ || this.get_value(), ['name', 'user_ids']]).then(this.proxy('display_followers')); + return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers')); }, /** Display the followers, evaluate is_follower directly */ @@ -91,13 +110,13 @@ openerp_mail_followers = function(session, mail) { }, do_follow: function () { - var context = new session.web.CompoundContext(this.build_context(), {'read_back': true}); - return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('set_value')); + var context = new session.web.CompoundContext(this.build_context(), {}); + return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value')); }, do_unfollow: function () { - var context = new session.web.CompoundContext(this.build_context(), {'read_back': true}); - return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('set_value')); + var context = new session.web.CompoundContext(this.build_context(), {}); + return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value')); }, }); }; diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index 39622f42abf..32ce34d48d1 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -7,7 +7,8 @@ -->
    - + +
    From 83863d6f20ecc610d098d24011c156b52c57da26 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 12 Sep 2012 15:36:56 +0200 Subject: [PATCH 202/265] [FIX] Prevent window scrolling when opening an m2o dialog bzr revid: fme@openerp.com-20120912133656-z81oo9mi5s4yq22p --- addons/web/static/src/js/view_form.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 9cab9e868ad..ff9e0020946 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2779,7 +2779,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.$drop_down = this.$el.find(".oe_m2o_drop_down_button"); this.$follow_button = $(".oe_m2o_cm_button", this.$el); - this.$follow_button.click(function() { + this.$follow_button.click(function(ev) { + ev.preventDefault(); if (!self.get('value')) { self.focus(); return; From 7392ef4283763dcebc00cd5154f909c58d0368bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 15:37:11 +0200 Subject: [PATCH 203/265] [CLEAN] mail_thread: no need th have its hack about returning the new value after subscribing or unsubscribing. bzr revid: tde@openerp.com-20120912133711-tlt4pqm1cejjq9pv --- addons/mail/mail_thread.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index c0d6ac90fe6..d798007275f 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -623,14 +623,8 @@ class mail_thread(osv.AbstractModel): return self.message_subscribe(cr, uid, ids, partner_ids, context=context) def message_subscribe(self, cr, uid, ids, partner_ids, context=None): - """ Add partners to the records followers. - :param partner_ids: a list of partner_ids to subscribe - :param return: new value of followers if read_back key in context - """ - self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context) - if context and context.get('read_back'): - return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] - return [] + """ Add partners to the records followers. """ + return self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context) def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not @@ -640,14 +634,8 @@ class mail_thread(osv.AbstractModel): return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context) def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None): - """ Remove partners from the records followers. - :param partner_ids: a list of partner_ids to unsubscribe - :param return: new value of followers if read_back key in context - """ - self.write(cr, uid, ids, {'message_follower_ids': [(3, pid) for pid in partner_ids]}, context=context) - if context and context.get('read_back'): - return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] - return [] + """ Remove partners from the records followers. """ + return self.write(cr, uid, ids, {'message_follower_ids': [(3, pid) for pid in partner_ids]}, context=context) #------------------------------------------------------ # Thread state From 01803926245d4d8a81464d9af4559cfcbd77cb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 15:37:33 +0200 Subject: [PATCH 204/265] [ADD] mail: added wizard in __openerp__. bzr revid: tde@openerp.com-20120912133733-xh484b24txefyhjm --- addons/mail/__openerp__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index 99dd6bda6ac..e55baa9ed75 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -61,6 +61,7 @@ The main features of the module are: 'website': 'http://www.openerp.com', 'depends': ['base', 'base_tools', 'base_setup'], 'data': [ + 'wizard/invite_view.xml', 'wizard/mail_compose_message_view.xml', 'res_config_view.xml', 'mail_message_view.xml', From a16bf464f5f3492f26eb4958e109f10653b22051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 15:38:43 +0200 Subject: [PATCH 205/265] [IMP] mail: added a new behavior when sending notifications. Each notification can now be customized (subject, body); each partner to notify will receive a different ir_email. It is still the same mail_mail as a basis, but specific content can be send to partners (for example, portal links). Updated the tests as well.L bzr revid: tde@openerp.com-20120912133843-lltf7pzder386e2w --- addons/mail/mail_followers.py | 59 ++++++++++++----------- addons/mail/mail_mail.py | 85 +++++++++++++++++++++++----------- addons/mail/tests/test_mail.py | 57 ++++++++++++++++------- 3 files changed, 132 insertions(+), 69 deletions(-) diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index 2aba685c4fa..146dc4b257c 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -84,16 +84,44 @@ class mail_notification(osv.Model): notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg_id)], context=context) return self.write(cr, uid, notif_ids, {'read': True}, context=context) + def get_partners_to_notify(self, cr, uid, partner_ids, message, context=None): + """ Return the list of partners to notify, based on their preferences. + + :param message: browse_record of a mail.message + """ + notify_pids = [] + for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): + # Do not send an email to the writer + if partner.user_ids and partner.user_ids[0].id == uid: + continue + # Do not send to partners without email address defined + if not partner.email: + continue + # Partner does not want to receive any emails + if partner.notification_email_send == 'none': + continue + # Partner wants to receive only emails and comments + if partner.notification_email_send == 'comment' and message.type not in ('email', 'comment'): + continue + # Partner wants to receive only emails + if partner.notification_email_send == 'email' and message.type != 'email': + continue + notify_pids.append(partner.id) + return notify_pids + def notify(self, cr, uid, partner_ids, msg_id, context=None): """ Send by email the notification depending on the user preferences """ context = context or {} # mail_noemail (do not send email) or no partner_ids: do not send, return if context.get('mail_noemail') or not partner_ids: return True - - mail_mail = self.pool.get('mail.mail') msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context) + notify_partner_ids = self.get_partners_to_notify(cr, uid, partner_ids, msg, context=context) + if not notify_partner_ids: + return True + + mail_mail = self.pool.get('mail.mail') # add signature body_html = msg.body signature = msg.author_id and msg.author_id.user_ids[0].signature or '' @@ -107,27 +135,6 @@ class mail_notification(osv.Model): 'body_html': body_html, 'state': 'outgoing', } - - for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): - # Do not send an email to the writer - if partner.user_ids and partner.user_ids[0].id == uid: - continue - # Do not send to partners without email address defined - if not partner.email: - continue - # Partner does not want to receive any emails - if partner.notification_email_send == 'none': - continue - # Partner wants to receive only emails and comments - if partner.notification_email_send == 'comment' and msg.type not in ('email', 'comment'): - continue - # Partner wants to receive only emails - if partner.notification_email_send == 'email' and msg.type != 'email': - continue - if partner.email not in mail_values['email_to']: - mail_values['email_to'].append(partner.email) - if mail_values['email_to']: - mail_values['email_to'] = ', '.join(mail_values['email_to']) - email_notif_id = mail_mail.create(cr, uid, mail_values, context=context) - mail_mail.send(cr, uid, [email_notif_id], context=context) - return True + mail_values['email_to'] = ', '.join(mail_values['email_to']) + email_notif_id = mail_mail.create(cr, uid, mail_values, context=context) + return mail_mail.send(cr, uid, [email_notif_id], notifier_ids=notify_partner_ids, context=context) diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py index 8d3f3ab6e01..1cb9efa98e1 100644 --- a/addons/mail/mail_mail.py +++ b/addons/mail/mail_mail.py @@ -137,14 +137,46 @@ class mail_mail(osv.Model): mail.unlink() return True - def _send_get_mail_subject(self, cr, uid, mail, force=False, context=None): + def _send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None): """ if void and related document: ' posted on ' - :param mail: mail.mail browse_record """ + + :param force: force the 'Author posted'... subject + :param mail: mail.mail browse_record + :param partner: browse_record of the specific recipient partner + """ if force or (not mail.subject and mail.model and mail.res_id): return '%s posted on %s' % (mail.author_id.name, mail.record_name) return mail.subject - def send(self, cr, uid, ids, auto_commit=False, context=None): + def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None): + """ Return a specific ir_email body. The main purpose of this method + is to be inherited by Portal, to add a link for signing in, in + each notification email a partner receives. + + :param mail: mail.mail browse_record + :param partner: browse_record of the specific recipient partner + """ + return mail.body_html + + def _send_get_ir_email_dict(self, cr, uid, mail, partner=None, context=None): + """ Return a dictionary for specific ir_email values, depending on a + partner, or generic to the whole recipients given by mail.email_to. + + :param mail: mail.mail browse_record + :param partner: browse_record of the specific recipient partner + """ + body = self._send_get_mail_body(cr, uid, mail, partner=partner, context=context) + subject = self._send_get_mail_subject(cr, uid, mail, partner=partner, context=context) + body_alternative = tools.html2plaintext(body) + email_to = [partner.email] if partner else tools.email_split(mail.email_to) + return { + 'body': body, + 'body_alternative': body_alternative, + 'subject': subject, + 'email_to': email_to, + } + + def send(self, cr, uid, ids, auto_commit=False, notifier_ids=None, context=None): """ Sends the selected emails immediately, ignoring their current state (mails that have already been sent should not be passed unless they should actually be re-sent). @@ -160,35 +192,36 @@ class mail_mail(osv.Model): ir_mail_server = self.pool.get('ir.mail_server') for mail in self.browse(cr, uid, ids, context=context): try: - body = mail.body_html - subject = self._send_get_mail_subject(cr, uid, mail, context=context) - # handle attachments attachments = [] for attach in mail.attachment_ids: attachments.append((attach.datas_fname, base64.b64decode(attach.datas))) - - # use only sanitized html and set its plaintexted version as alternative - body_alternative = tools.html2plaintext(body) - content_subtype_alternative = 'plain' + # specific behavior to customize the send email for notified partners + ir_email_list = [] + if notifier_ids: + for partner in self.pool.get('res.partner').browse(cr, uid, notifier_ids, context=context): + ir_email_list.append(self._send_get_ir_email_dict(cr, uid, mail, partner=partner, context=context)) + else: + ir_email_list.append(self._send_get_ir_email_dict(cr, uid, mail, context=context)) # build an RFC2822 email.message.Message object and send it without queuing - msg = ir_mail_server.build_email( - email_from = mail.email_from, - email_to = tools.email_split(mail.email_to), - subject = subject, - body = body, - body_alternative = body_alternative, - email_cc = tools.email_split(mail.email_cc), - reply_to = mail.reply_to, - attachments = attachments, - message_id = mail.message_id, - references = mail.references, - object_id = mail.res_id and ('%s-%s' % (mail.res_id, mail.model)), - subtype = 'html', - subtype_alternative = content_subtype_alternative) - res = ir_mail_server.send_email(cr, uid, msg, - mail_server_id=mail.mail_server_id.id, context=context) + for ir_email in ir_email_list: + msg = ir_mail_server.build_email( + email_from = mail.email_from, + email_to = ir_email.get('email_to'), + subject = ir_email.get('subject'), + body = ir_email.get('body'), + body_alternative = ir_email.get('body_alternative'), + email_cc = tools.email_split(mail.email_cc), + reply_to = mail.reply_to, + attachments = attachments, + message_id = mail.message_id, + references = mail.references, + object_id = mail.res_id and ('%s-%s' % (mail.res_id, mail.model)), + subtype = 'html', + subtype_alternative = 'plain') + res = ir_mail_server.send_email(cr, uid, msg, + mail_server_id=mail.mail_server_id.id, context=context) if res: mail.write({'state': 'sent', 'message_id': res}) else: diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index f45745f31dc..24d7db67b54 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -19,6 +19,8 @@ # ############################################################################## +import tools + from openerp.tests import common from openerp.tools.html_sanitize import html_sanitize @@ -29,7 +31,7 @@ Received: by mail1.openerp.com (Postfix, from userid 10002) From: Sylvie Lelitre Subject: {subject} MIME-Version: 1.0 -Content-Type: multipart/alternative; +Content-Type: multipart/alternative; boundary="----=_Part_4200734_24778174.1344608186754" Date: Fri, 10 Aug 2012 14:16:26 +0000 Message-ID: <1198923581.41972151344608186760.JavaMail@agrolait.com> @@ -52,9 +54,9 @@ Content-Transfer-Encoding: quoted-printable =20 =20 - +

    Please call me as soon as possible this afternoon!

    - +

    --
    Sylvie

    @@ -88,10 +90,19 @@ class test_mail(common.TransactionCase): return True def _mock_build_email(self, *args, **kwargs): - self._build_email_args = args - self._build_email_kwargs = kwargs + self._build_email_args_list.append(args) + self._build_email_kwargs_list.append(kwargs) return self.build_email_real(*args, **kwargs) + def _init_mock_build_email(self): + self._build_email_args_list = [] + self._build_email_kwargs_list = [] + + def _mock_send_get_mail_body(self, *args, **kwargs): + # def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None) + body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner') + return body + def setUp(self): super(test_mail, self).setUp() self.ir_model = self.registry('ir.model') @@ -106,10 +117,14 @@ class test_mail(common.TransactionCase): self.res_partner = self.registry('res.partner') # Install mock SMTP gateway + self._init_mock_build_email() self.build_email_real = self.registry('ir.mail_server').build_email self.registry('ir.mail_server').build_email = self._mock_build_email self.registry('ir.mail_server').send_email = self._mock_smtp_gateway + # Mock _send_get_mail_body to test its functionality without other addons override + self.registry('mail.mail')._send_get_mail_body = self._mock_send_get_mail_body + # groups@.. will cause the creation of new mail groups self.mail_group_model_id = self.ir_model.search(self.cr, self.uid, [('model', '=', 'mail.group')])[0] self.mail_alias.create(self.cr, self.uid, {'alias_name': 'groups', @@ -153,7 +168,7 @@ class test_mail(common.TransactionCase): test_msg_id = '' mail_text = MAIL_TEMPLATE_PLAINTEXT.format(to='groups@example.com', subject='frogs', extra='', msg_id=test_msg_id) self.mail_thread.message_process(cr, uid, None, mail_text) - new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id','=',test_msg_id)])[0]) + new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id', '=', test_msg_id)])[0]) self.assertEqual(new_mail.body, '\n

    \nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
    \n', 'plaintext mail incorrectly parsed') @@ -274,18 +289,20 @@ class test_mail(common.TransactionCase): _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')] # CASE1: post comment, body and subject specified + self._init_mock_build_email() msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, type='comment') message = self.mail_message.browse(cr, uid, msg_id) - sent_email = self._build_email_kwargs + sent_emails = self._build_email_kwargs_list # Test: notifications have been deleted self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id)]), 'mail.mail notifications should have been auto-deleted!') # Test: mail_message: subject is _subject, body is _body1 (no formatting done) self.assertEqual(message.subject, _subject, 'mail.message subject incorrect') self.assertEqual(message.body, _body1, 'mail.message body incorrect') - # Test: sent_email: email send by server: correct subject, body; body_alternative - self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect') - self.assertEqual(sent_email['body'], _mail_body1, 'sent_email body incorrect') - self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1, 'sent_email body_alternative is incorrect') + # Test: sent_email: email send by server: correct subject, body, body_alternative + for sent_email in sent_emails: + self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect') + self.assertEqual(sent_email['body'], _mail_body1 + '\n
    Bert Tartopoils
    \n', 'sent_email body incorrect') + self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils', 'sent_email body_alternative is incorrect') # Test: mail_message: partner_ids = group followers message_pids = set([partner.id for partner in message.partner_ids]) test_pids = set([p_a_id, p_b_id, p_c_id]) @@ -295,14 +312,16 @@ class test_mail(common.TransactionCase): notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') # Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer) - self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect') + for sent_email in sent_emails: + self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect') # CASE2: post an email with attachments, parent_id, partner_ids # TESTS: automatic subject, signature in body_html, attachments propagation + self._init_mock_build_email() msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, type='email', partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments) message = self.mail_message.browse(cr, uid, msg_id2) - sent_email = self._build_email_kwargs + sent_emails = self._build_email_kwargs_list self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id2)]), 'mail.mail notifications should have been auto-deleted!') # Test: mail_message: subject is False, body is _body2 (no formatting done), parent_id is msg_id @@ -310,9 +329,11 @@ class test_mail(common.TransactionCase): self.assertEqual(message.body, html_sanitize(_body2), 'mail.message body incorrect') self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect') # Test: sent_email: email send by server: correct subject, body, body_alternative - self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect') - self.assertEqual(sent_email['body'], _mail_body2, 'sent_email body incorrect') - self.assertEqual(sent_email['body_alternative'], _mail_bodyalt2, 'sent_email body_alternative incorrect') + self.assertEqual(len(sent_emails), 2, 'sent_email number of sent emails incorrect') + for sent_email in sent_emails: + self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect') + self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect') + self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect') # Test: mail_message: partner_ids = group followers message_pids = set([partner.id for partner in message.partner_ids]) test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id]) @@ -322,7 +343,8 @@ class test_mail(common.TransactionCase): notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect') # Test: sent_email: email_to should contain b@b, c@c, not a@a (writer) - self.assertEqual(set(sent_email['email_to']), set(['b@b', 'c@c']), 'sent_email email_to incorrect') + for sent_email in sent_emails: + self.assertTrue(set(sent_email['email_to']).issubset(set(['b@b', 'c@c'])), 'sent_email email_to incorrect') # Test: attachments for attach in message.attachment_ids: self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect') @@ -458,6 +480,7 @@ class test_mail(common.TransactionCase): # It will be updated as soon as we have fixed specs ! cr, uid = self.cr, self.uid group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) + def _compare_structures(struct1, struct2, n=0): # print '%scompare structure' % ('\t' * n) self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect') From 58510a62e4b83d30fbfa843993737c0fa41bc418 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 12 Sep 2012 16:16:13 +0200 Subject: [PATCH 206/265] [IMP] mrp: improve code in wizard change_production_qty bzr revid: rco@openerp.com-20120912141613-l7aqxgr1bpn0g82u --- addons/mrp/wizard/change_production_qty.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index 1fe35abc201..9be34b6bd1e 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -68,7 +68,7 @@ class change_production_qty(osv.osv_memory): assert record_id, _('Active Id not found') prod_obj = self.pool.get('mrp.production') bom_obj = self.pool.get('mrp.bom') - move_lines_obj = self.pool.get('stock.move') + move_obj = self.pool.get('stock.move') for wiz_qty in self.browse(cr, uid, ids, context=context): prod = prod_obj.browse(cr, uid, record_id, context=context) prod_obj.write(cr, uid, [prod.id], {'product_qty': wiz_qty.product_qty}) @@ -88,17 +88,16 @@ class change_production_qty(osv.osv_memory): raise osv.except_osv(_('Error!'), _("Cannot find bill of material for this product.")) factor = prod.product_qty * prod.product_uom.factor / bom_point.product_uom.factor - res = bom_obj._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, []) - pick_move = {} - for move_ln in prod.picking_id.move_lines: - pick_move.update({move_ln.product_id.id: move_ln.id}) - for r in res[0]: + product_details, workcenter_details = \ + bom_obj._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, []) + product_move = dict((mv.product_id.id, mv.id) for mv in prod.picking_id.move_lines) + for r in product_details: if r['product_id'] == move.product_id.id: - move_lines_obj.write(cr, uid, [move.id], {'product_qty' : r['product_qty']}) - if r['product_id'] in pick_move: - move_lines_obj.write(cr, uid, [pick_move[r['product_id']]], {'product_qty' : r['product_qty']}) + move_obj.write(cr, uid, [move.id], {'product_qty': r['product_qty']}) + if r['product_id'] in product_move: + move_obj.write(cr, uid, [product_move[r['product_id']]], {'product_qty': r['product_qty']}) if prod.move_prod_id: - move_lines_obj.write(cr, uid, [prod.move_prod_id.id], {'product_qty' : wiz_qty.product_qty}) + move_obj.write(cr, uid, [prod.move_prod_id.id], {'product_qty' : wiz_qty.product_qty}) self._update_product_to_produce(cr, uid, prod, wiz_qty.product_qty, context=context) return {} From 423aca905aa619d632f745d34b72fee5b1413b98 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 12 Sep 2012 16:22:29 +0200 Subject: [PATCH 207/265] [IMP] translations: attempt to optimize out _get_source calls when there is not context lang bzr revid: odo@openerp.com-20120912142229-ir3h1z0yau09ivvw --- openerp/addons/base/ir/ir_translation.py | 2 +- openerp/osv/orm.py | 41 ++++++++++++------------ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index 3650f28d3f5..81afd857f18 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -267,7 +267,7 @@ class ir_translation(osv.osv): # FIXME: should assert that `source` is unicode and fix all callers to always pass unicode # so we can remove the string encoding/decoding. if not lang: - return u'' + return tools.ustr(source or '') if isinstance(types, basestring): types = (types,) if source: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index c8a77a8856c..1ca7927f1ac 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1443,7 +1443,7 @@ class BaseModel(object): def _validate(self, cr, uid, ids, context=None): context = context or {} - lng = context.get('lang', False) or 'en_US' + lng = context.get('lang') trans = self.pool.get('ir.translation') error_msgs = [] for constraint in self._constraints: @@ -1459,7 +1459,7 @@ class BaseModel(object): else: translated_msg = tmp_msg else: - translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, msg) or msg + translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, msg) error_msgs.append( _("Error occurred while validating the field(s) %s: %s") % (','.join(fields), translated_msg) ) @@ -3431,24 +3431,25 @@ class BaseModel(object): res[f]['readonly'] = True res[f]['states'] = {} - if 'string' in res[f]: - res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US') - if res_trans: - res[f]['string'] = res_trans - if 'help' in res[f]: - help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context.get('lang', False) or 'en_US') - if help_trans: - res[f]['help'] = help_trans - if 'selection' in res[f]: - if isinstance(field.selection, (tuple, list)): - sel = field.selection - sel2 = [] - for key, val in sel: - val2 = None - if val: - val2 = translation_obj._get_source(cr, user, self._name + ',' + f, 'selection', context.get('lang', False) or 'en_US', val) - sel2.append((key, val2 or val)) - res[f]['selection'] = sel2 + if 'lang' in context: + if 'string' in res[f]: + res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context['lang']) + if res_trans: + res[f]['string'] = res_trans + if 'help' in res[f]: + help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context['lang']) + if help_trans: + res[f]['help'] = help_trans + if 'selection' in res[f]: + if isinstance(field.selection, (tuple, list)): + sel = field.selection + sel2 = [] + for key, val in sel: + val2 = None + if val: + val2 = translation_obj._get_source(cr, user, self._name + ',' + f, 'selection', context['lang'], val) + sel2.append((key, val2 or val)) + res[f]['selection'] = sel2 return res From 3a9c29d327d875802ab2b7b330810e0348c06e21 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 16:46:26 +0200 Subject: [PATCH 208/265] [FIX] empty html area, developer should be able to force a widget bzr revid: fp@tinyerp.com-20120912144626-pl3ze0mltqt42uky --- addons/web/static/src/js/view_form.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index ff9e0020946..0e66ab6bfc3 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2404,10 +2404,6 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc template: 'FieldTextHtml', init: function() { this._super.apply(this, arguments); - if (this.field.type !== 'html' && ! this.options.safe) { - throw new Error(_.str.sprintf( - _t("Error with field %s, it is not allowed to use the widget 'html' with any other field type than 'html'"), this.string)); - } }, initialize_content: function() { var self = this; @@ -2441,7 +2437,7 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc }, render_value: function() { if (! this.get("effective_readonly")) { - this.$textarea.val(this.get('value')); + this.$textarea.val(this.get('value') || ''); this._updating_editor = true; this.$cleditor.updateFrame(); this._updating_editor = false; From bca11f7ff833e63feca4ae42d8b9c6a517ce0f2d Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 17:11:51 +0200 Subject: [PATCH 209/265] [IMP] better project kanban view bzr revid: fp@tinyerp.com-20120912151151-pmvuh7lmaozdrrkl --- addons/project/project_view.xml | 47 ++++++----------------- addons/project/static/src/css/project.css | 2 +- 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 19f63693967..ff8ac943a67 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -136,6 +136,7 @@ + @@ -249,47 +250,21 @@ - - - - - - - - - -
    Deadline
    Progress/
    +
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/addons/project/static/src/css/project.css b/addons/project/static/src/css/project.css index f90162fcc76..8381e6d68d3 100644 --- a/addons/project/static/src/css/project.css +++ b/addons/project/static/src/css/project.css @@ -3,7 +3,7 @@ } .oe_kanban_project { - width: 250px; + width: 220px; min-height: 160px; } From ed63dc38d27728d99d10ea9bab6c778f58aae91b Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 17:14:18 +0200 Subject: [PATCH 210/265] [IMP] simple name_get for projects and analytic accounts bzr revid: fp@tinyerp.com-20120912151418-8yuafykrvy8wfku8 --- addons/analytic/analytic.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py index d90e2006a71..66a67ad4219 100644 --- a/addons/analytic/analytic.py +++ b/addons/analytic/analytic.py @@ -96,22 +96,6 @@ class account_analytic_account(osv.osv): res[row['id']][field] = row[field] return self._compute_level_tree(cr, uid, ids, child_ids, res, fields, context) - def name_get(self, cr, uid, ids, context=None): - if isinstance(ids, (int, long)): - ids=[ids] - if not ids: - return [] - res = [] - for account in self.browse(cr, uid, ids, context=context): - data = [] - acc = account - while acc: - data.insert(0, acc.name) - acc = acc.parent_id - data = ' / '.join(data) - res.append((account.id, data)) - return res - def _complete_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict): res = self.name_get(cr, uid, ids) return dict(res) From b300e3d209a87f3834a746742c540df865b6be2d Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 17:38:52 +0200 Subject: [PATCH 211/265] [IMP] kanban css bzr revid: fp@tinyerp.com-20120912153852-3a3rgkow3t1c5yv2 --- addons/web_kanban/static/src/css/kanban.css | 2 +- addons/web_kanban/static/src/css/kanban.sass | 2 +- addons/web_kanban/static/src/xml/web_kanban.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index f63dd371604..ab7fef3972e 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -74,7 +74,6 @@ .openerp .oe_kanban_view .oe_kanban_group_title { font-size: 16px; font-weight: bold; - min-height: 32px; color: #333333; text-shadow: 0 1px 0 white; } @@ -105,6 +104,7 @@ } .openerp .oe_kanban_view .oe_kanban_aggregates { padding: 0; + margin: 0px; } .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title, .openerp .oe_kanban_view .oe_kanban_group_folded.oe_kanban_column > *, .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_aggregates, .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_add { display: none; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index ddafee12581..d282a978cca 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -92,7 +92,6 @@ .oe_kanban_group_title font-size: 16px font-weight: bold - min-height: 32px color: #333333 text-shadow: 0 1px 0 white > span @@ -121,6 +120,7 @@ height: 100% .oe_kanban_aggregates padding: 0 + margin: 0px .oe_kanban_group_folded .oe_kanban_group_title, &.oe_kanban_column > *, .oe_kanban_aggregates, .oe_kanban_add display: none diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index 8a1b27c9726..d2dc41b65a4 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -47,7 +47,7 @@
    - () +
      From a71f5132843d94c852fe559ced88598a0c4fdd01 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 12 Sep 2012 17:39:01 +0200 Subject: [PATCH 212/265] [FIX] css login and kanban bzr revid: al@openerp.com-20120912153901-faxihm41n34hn294 --- addons/web/static/src/css/base.css | 5 +++-- addons/web/static/src/css/base.sass | 5 +++-- addons/web_kanban/static/src/css/kanban.css | 5 +++++ addons/web_kanban/static/src/css/kanban.sass | 4 ++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 05cd43db716..e89e35cecf3 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -792,9 +792,10 @@ font-size: 14px; height: 100%; } -.openerp .oe_login li { +.openerp .oe_login ul, .openerp .oe_login li { + margin: 0; list-style-type: none; - padding-bottom: 4px; + padding: 0 0 4px 0; } .openerp .oe_login button { float: right; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index bab3d7c6ad4..e00c1e8401c 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -654,9 +654,10 @@ $sheet-max-width: 860px text-align: center font-size: 14px height: 100% - li + ul, li + margin: 0 list-style-type: none - padding-bottom: 4px + padding: 0 0 4px 0 button float: right display: inline-block diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index ab7fef3972e..48cf725ead3 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -84,6 +84,11 @@ vertical-align: top; padding: 6px 6px 6px 5px; } +.openerp .oe_kanban_view .oe_kanban_column ul, .openerp .oe_kanban_view .oe_kanban_column li, .openerp .oe_kanban_view .oe_kanban_group_header ul, .openerp .oe_kanban_view .oe_kanban_group_header li { + margin: 0; + padding: 0; + list-style-type: none; +} .openerp .oe_kanban_view .oe_kanban_group_header.oe_kanban_no_group { padding: 0px; } diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index d282a978cca..95a63dbd1a2 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -100,6 +100,10 @@ .oe_kanban_column, .oe_kanban_group_header vertical-align: top padding: 6px 6px 6px 5px + ul, li + margin: 0 + padding: 0 + list-style-type: none .oe_kanban_group_header.oe_kanban_no_group padding: 0px From d39593868094e695fa60df1e1f31eb3db3cd4d44 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 17:44:48 +0200 Subject: [PATCH 213/265] [IMP] kanban bzr revid: fp@tinyerp.com-20120912154448-2k7wscbhj6uyjcqy --- addons/web_kanban/static/src/xml/web_kanban.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index d2dc41b65a4..3537e96b4c8 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -49,7 +49,6 @@
    -
    • : From 30fb693c20745bb2e656732d7a6893b800ae0351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 17:53:00 +0200 Subject: [PATCH 214/265] [IMP] Portal: override of mail_mail to add the signin link into footer of send notifications. bzr revid: tde@openerp.com-20120912155300-8ilg2g24yl7qsjfg --- addons/mail/mail_mail.py | 14 +++++------ addons/portal/__init__.py | 1 + addons/portal/mail_mail.py | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 addons/portal/mail_mail.py diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py index 1cb9efa98e1..cf86c39f273 100644 --- a/addons/mail/mail_mail.py +++ b/addons/mail/mail_mail.py @@ -137,7 +137,7 @@ class mail_mail(osv.Model): mail.unlink() return True - def _send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None): + def send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None): """ if void and related document: ' posted on ' :param force: force the 'Author posted'... subject @@ -148,7 +148,7 @@ class mail_mail(osv.Model): return '%s posted on %s' % (mail.author_id.name, mail.record_name) return mail.subject - def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None): + def send_get_mail_body(self, cr, uid, mail, partner=None, context=None): """ Return a specific ir_email body. The main purpose of this method is to be inherited by Portal, to add a link for signing in, in each notification email a partner receives. @@ -158,15 +158,15 @@ class mail_mail(osv.Model): """ return mail.body_html - def _send_get_ir_email_dict(self, cr, uid, mail, partner=None, context=None): + def send_get_ir_email_dict(self, cr, uid, mail, partner=None, context=None): """ Return a dictionary for specific ir_email values, depending on a partner, or generic to the whole recipients given by mail.email_to. :param mail: mail.mail browse_record :param partner: browse_record of the specific recipient partner """ - body = self._send_get_mail_body(cr, uid, mail, partner=partner, context=context) - subject = self._send_get_mail_subject(cr, uid, mail, partner=partner, context=context) + body = self.send_get_mail_body(cr, uid, mail, partner=partner, context=context) + subject = self.send_get_mail_subject(cr, uid, mail, partner=partner, context=context) body_alternative = tools.html2plaintext(body) email_to = [partner.email] if partner else tools.email_split(mail.email_to) return { @@ -200,9 +200,9 @@ class mail_mail(osv.Model): ir_email_list = [] if notifier_ids: for partner in self.pool.get('res.partner').browse(cr, uid, notifier_ids, context=context): - ir_email_list.append(self._send_get_ir_email_dict(cr, uid, mail, partner=partner, context=context)) + ir_email_list.append(self.send_get_ir_email_dict(cr, uid, mail, partner=partner, context=context)) else: - ir_email_list.append(self._send_get_ir_email_dict(cr, uid, mail, context=context)) + ir_email_list.append(self.send_get_ir_email_dict(cr, uid, mail, context=context)) # build an RFC2822 email.message.Message object and send it without queuing for ir_email in ir_email_list: diff --git a/addons/portal/__init__.py b/addons/portal/__init__.py index 9c6cc59be7d..2bfc6df0d96 100644 --- a/addons/portal/__init__.py +++ b/addons/portal/__init__.py @@ -20,6 +20,7 @@ ############################################################################## import portal +import mail_mail import wizard diff --git a/addons/portal/mail_mail.py b/addons/portal/mail_mail.py new file mode 100644 index 00000000000..d7f4d05d5ac --- /dev/null +++ b/addons/portal/mail_mail.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2011 OpenERP S.A (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import tools +from osv import osv + + +class mail_mail_portal(osv.Model): + """ Update of mail_mail class, to add the signin URL to notifications. + """ + _name = 'mail.mail' + _inherit = ['mail.mail'] + + def _generate_portal_url(self, cr, uid, partner_id, portal_group_id, key, context=None): + """ . """ + base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='', context=context) + return base_url + '/login?action=signin&partner_id=%s&group=%s&key=%s' % (partner_id, portal_group_id, key) + + def send_get_mail_body(self, cr, uid, mail, partner=None, context=None): + """ Return a specific ir_email body. The main purpose of this method + is to be inherited by Portal, to add a link for signing in, in + each notification email a partner receives. + + :param mail: mail.mail browse_record + :param partner: browse_record of the specific recipient partner + """ + if partner: + url = self._generate_portal_url(cr, uid, partner.id, 12, 1234, context=context) + body = tools.append_content_to_html(mail.body_html, url) + return body + else: + return super(mail_mail_portal, self).send_get_mail_body(cr, uid, mail, partner=partner, context=context) From 918dc35da53232569e67caeb8256bb6e9f9608bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 17:53:13 +0200 Subject: [PATCH 215/265] [ADD] Portal: added skeleton files for tests. bzr revid: tde@openerp.com-20120912155313-xhx6hqyfr85t0ncw --- addons/portal/tests/__init__.py | 27 ++++++++++++++ addons/portal/tests/test_portal.py | 59 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 addons/portal/tests/__init__.py create mode 100644 addons/portal/tests/test_portal.py diff --git a/addons/portal/tests/__init__.py b/addons/portal/tests/__init__.py new file mode 100644 index 00000000000..c4717f80ebf --- /dev/null +++ b/addons/portal/tests/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +from . import test_portal + +checks = [ + test_portal, +] + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py new file mode 100644 index 00000000000..93b9d220149 --- /dev/null +++ b/addons/portal/tests/test_portal.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.tests import common + + +class test_portal(common.TransactionCase): + + def _mock_smtp_gateway(self, *args, **kwargs): + return True + + def _mock_build_email(self, *args, **kwargs): + self._build_email_args_list.append(args) + self._build_email_kwargs_list.append(kwargs) + return self.build_email_real(*args, **kwargs) + + def _init_mock_build_email(self): + self._build_email_args_list = [] + self._build_email_kwargs_list = [] + + def setUp(self): + super(test_portal, self).setUp() + self.ir_model = self.registry('ir.model') + self.mail_group = self.registry('mail.group') + self.mail_mail = self.registry('mail.mail') + self.res_users = self.registry('res.users') + self.res_partner = self.registry('res.partner') + + # Install mock SMTP gateway + self._init_mock_build_email() + self.build_email_real = self.registry('ir.mail_server').build_email + self.registry('ir.mail_server').build_email = self._mock_build_email + self.registry('ir.mail_server').send_email = self._mock_smtp_gateway + + # create a 'pigs' group that will be used through the various tests + self.group_pigs_id = self.mail_group.create(self.cr, self.uid, + {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) + + def test_00_mail_invite(self): + cr, uid = self.cr, self.uid + print 'cacaprout' From a5bed8994c913064e2d501de4667536a24c6cb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Wed, 12 Sep 2012 18:12:29 +0200 Subject: [PATCH 216/265] [IMP] point_of_sale: debug window bzr revid: fva@openerp.com-20120912161229-4lgcgt4xt2cdzceo --- addons/point_of_sale/static/src/css/pos.css | 75 +++++++++++++ addons/point_of_sale/static/src/js/devices.js | 99 +++++++++-------- addons/point_of_sale/static/src/js/models.js | 2 + addons/point_of_sale/static/src/js/screens.js | 13 +-- addons/point_of_sale/static/src/js/widgets.js | 102 +++++++++++++++--- addons/point_of_sale/static/src/xml/pos.xml | 49 +++++++++ 6 files changed, 270 insertions(+), 70 deletions(-) diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css index dbe79703329..a727986bb1c 100644 --- a/addons/point_of_sale/static/src/css/pos.css +++ b/addons/point_of_sale/static/src/css/pos.css @@ -1102,6 +1102,81 @@ .point-of-sale .pos-actionbar .button.rightalign{ float:right; } +/* ********* The Debug Widget ********* */ + +.point-of-sale .debug-widget{ + z-index:100000; + position: absolute; + right: 10px; + top: 10px; + width: 200px; + font-size: 10px; + + background: rgba(0,0,0,0.82); + color: white; + text-shadow: none; + padding-bottom: 10px; + box-shadow: 0px 3px 20px rgba(0,0,0,0.3); + cursor:move; +} +.point-of-sale .debug-widget .toggle{ + position: absolute; + font-size: 16px; + cursor:pointer; + top:0px; + right:0px; + padding:10px; + padding-right:15px; +} +.point-of-sale .debug-widget .content{ + overflow: hidden; +} +.point-of-sale .debug-widget h1{ + background:black; + padding-top: 10px; + padding-left: 10px; + margin-top:0; + margin-bottom:0; +} +.point-of-sale .debug-widget .category{ + background: black; + padding-left: 10px; + margin: 0px; + font-weight: bold; + padding-top:3px; + padding-bottom:3px; +} +.point-of-sale .debug-widget .button{ + padding: 5px; + padding-left: 15px; + display: block; + cursor:pointer; +} +.point-of-sale .debug-widget .button:hover{ + background: rgba(96,21,177,0.45); +} +.point-of-sale .debug-widget input{ + margin-left:10px; + margin-top:7px; +} +.point-of-sale .debug-widget .status{ + padding: 5px; + padding-left: 15px; + display: block; + cursor:default; +} +.point-of-sale .debug-widget .status.on{ + padding: 5px; + padding-left: 15px; + display: block; + background-color: green; +} +.point-of-sale .debug-widget .status.on{ + padding: 5px; + padding-left: 15px; + display: block; + background-color: #6cd11d; +} /* ********* The PopupWidgets ********* */ diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js index 46d11938128..65a28b5366a 100644 --- a/addons/point_of_sale/static/src/js/devices.js +++ b/addons/point_of_sale/static/src/js/devices.js @@ -1,26 +1,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sale - var debug_devices = new (instance.web.Class.extend({ - active: false, - payment_status: 'waiting_for_payment', - weight: 0, - activate: function(){ - this.active = true; - }, - deactivate: function(){ - this.active = false; - }, - set_weight: function(weight){ this.activate(); this.weight = weight; }, - accept_payment: function(){ this.activate(); this.payment_status = 'payment_accepted'; }, - reject_payment: function(){ this.activate(); this.payment_status = 'payment_rejected'; }, - delay_payment: function(){ this.activate(); this.payment_status = 'waiting_for_payment'; }, - }))(); - - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - window.debug_devices = debug_devices; - } - // this object interfaces with the local proxy to communicate to the various hardware devices // connected to the Point of Sale. As the communication only goes from the POS to the proxy, // methods are used both to signal an event, and to fetch information. @@ -38,20 +18,34 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal this.connection = new instance.web.JsonRPC(); this.connection.setup(url); + + this.bypass_proxy = false; + this.notifications = {}; }, message : function(name,params,success_callback, error_callback){ success_callback = success_callback || function(){}; error_callback = error_callback || function(){}; - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ console.log('PROXY:',name,params); } - if(!(debug_devices && debug_devices.active)){ - this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback); + var callbacks = this.notifications[name] || []; + for(var i = 0; i < callbacks.length; i++){ + callbacks[i](params); } + + this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback); + }, + + // this allows the client to be notified when a proxy call is made. The notification + // callback will be executed with the same arguments as the proxy call + add_notification: function(name, callback){ + if(!this.notifications[name]){ + this.notifications[name] = []; + } + this.notifications[name].push(callback); }, //a product has been scanned and recognized with success @@ -78,12 +72,12 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal //the client is starting to weight weighting_start: function(){ - this.weight = 0; - if(debug_devices){ - debug_devices.weigth = 0; + if(!this.weighting){ + this.weight = 0; + this.weighting = true; + this.bypass_proxy = false; + this.message('weighting_start'); } - this.weighting = true; - this.message('weighting_start'); }, //returns the weight on the scale. @@ -91,22 +85,29 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // and a weighting_end() weighting_read_kg: function(){ var self = this; - if(debug_devices && debug_devices.active){ - return debug_devices.weight; + if(this.bypass_proxy){ + return this.weight; }else{ this.message('weighting_read_kg',{},function(weight){ - if(self.weighting){ + if(self.weighting && !self.bypass_proxy){ self.weight = weight; } }); - return self.weight; + return this.weight; } }, + // sets a custom weight, ignoring the proxy returned value until the next weighting_end + debug_set_weight: function(kg){ + this.bypass_proxy = true; + this.weight = kg; + }, + // the client has finished weighting products weighting_end: function(){ this.weight = 0; this.weighting = false; + this.bypass_proxy = false; this.message('weighting_end'); }, @@ -116,9 +117,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal payment_request: function(price, method, info){ this.paying = true; this.payment_status = 'waiting_for_payment'; - if(debug_devices){ - debug_devices.payment_status = 'waiting_for_payment'; - } this.message('payment_request',{'price':price,'method':method,'info':info}); }, @@ -127,18 +125,30 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // returns 'waiting_for_payment' | 'payment_accepted' | 'payment_rejected' is_payment_accepted: function(){ var self = this; - if(debug_devices.active){ - return debug_devices.payment_status; + if(this.bypass_proxy){ + this.bypass_proxy = false; + return this.payment_status; }else{ this.message('is_payment_accepted', {}, function(payment_status){ if(self.paying){ self.payment_status = payment_status; } }); - return self.payment_status; + return this.payment_status; } }, + + // override what the proxy says and accept the payment + debug_accept_payment: function(){ + this.bypass_proxy = true; + this.payment_status = 'payment_accepted'; + }, + // override what the proxy says and reject the payment + debug_reject_payment: function(){ + this.bypass_proxy = true; + this.payment_status = 'payment_rejected'; + }, // the client cancels his payment payment_canceled: function(){ this.paying = false; @@ -241,18 +251,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal this.price_prefix_set = attributes.price_prefix_set || {'23':''}; this.cashier_prefix_set = attributes.cashier_prefix_set || {'041':''}; this.client_prefix_set = attributes.client_prefix_set || {'042':''}; - - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - var self = this; - window.simulate_ean = function(ean,strict){ - ean = ean.toString(); - if(!strict){ - ean = self.sanitize_ean(ean); - } - console.log('SIMULATE EAN: ',ean); - self.on_ean(ean); - } - } }, save_callbacks: function(){ @@ -356,7 +354,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal value: 0, unit: 'none', }; - console.log('ean',ean); function match_prefix(prefix_set, type){ for(prefix in prefix_set){ diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 49521377ccb..5fbba5088d4 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -24,6 +24,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal this.proxy = new module.ProxyDevice(); // used to communicate to the hardware devices via a local proxy this.db = new module.PosLS(); // a database used to store the products and categories this.db.clear('products','categories'); + this.debug = jQuery.deparam(jQuery.param.querystring()).debug !== undefined; //debug mode + // default attributes values. If null, it will be loaded below. this.set({ diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 3b580868e6b..d2c79f19928 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -560,21 +560,21 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa //we get the first cashregister marked as self-checkout var selfCheckoutRegisters = []; - for(var i = 0; i < this.pos.get('cashRegisters').models.length; i++){ - var cashregister = this.pos.get('cashRegisters').models[i]; + for(var i = 0; i < self.pos.get('cashRegisters').models.length; i++){ + var cashregister = self.pos.get('cashRegisters').models[i]; if(cashregister.self_checkout_payment_method){ selfCheckoutRegisters.push(cashregister); } } - var cashregister = selfCheckoutRegisters[0] || this.pos.get('cashRegisters').models[0]; + var cashregister = selfCheckoutRegisters[0] || self.pos.get('cashRegisters').models[0]; currentOrder.addPaymentLine(cashregister); self.pos.push_order(currentOrder.exportAsJSON()) currentOrder.destroy(); self.pos.proxy.transaction_end(); self.pos_widget.screen_selector.set_current_screen(self.next_screen); }else if(payment === 'payment_rejected'){ - clearInterval(this.intervalID); + clearInterval(self.intervalID); //TODO show a tryagain thingie ? } },500); @@ -603,13 +603,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa show_numpad: false, show_leftpane: false, barcode_product_action: function(ean){ - self.pos.proxy.transaction_start(); + this.pos.proxy.transaction_start(); this._super(ean); }, barcode_client_action: function(ean){ - self.pos.proxy.transaction_start(); + this.pos.proxy.transaction_start(); this._super(ean); + $('.goodbye-message').hide(); this.pos_widget.screen_selector.show_popup('choose-receipt'); }, diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index 2aaf9098329..c8e03ccff08 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -694,6 +694,91 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa }, }); + module.DebugWidget = module.PosBaseWidget.extend({ + template: "DebugWidget", + eans:{ + admin_badge: '0410300000004', + client_badge: '0420100000005', + invalid_ean: '1232456', + soda_33cl: '5449000000996', + oranges_kg: '2100002031410', + lemon_price: '2301000001560', + unknown_product: '9900000000004', + }, + events:[ + 'scan_item_success', + 'scan_item_error_unrecognized', + 'payment_request', + 'open_cashbox', + 'print_receipt', + 'print_pdf_invoice', + ], + minimized: false, + start: function(){ + var self = this; + + this.$el.draggable(); + this.$('.toggle').click(function(){ + var content = self.$('.content'); + var bg = self.$el; + if(!self.minimized){ + content.animate({'height':'0'},200); + }else{ + content.css({'height':'auto'}); + } + self.minimized = !self.minimized; + }); + this.$('.button.accept_payment').click(function(){ + self.pos.proxy.debug_accept_payment(); + }); + this.$('.button.reject_payment').click(function(){ + self.pos.proxy.debug_reject_payment(); + }); + this.$('.button.set_weight').click(function(){ + var kg = Number(self.$('input.weight').val()); + if(!Number.isNaN(kg)){ + self.pos.proxy.debug_set_weight(kg); + } + }); + this.$('.button.custom_ean').click(function(){ + var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0'); + self.$('input.ean').val(ean); + self.pos.barcode_reader.on_ean(ean); + }); + _.each(this.eans, function(ean, name){ + self.$('.button.'+name).click(function(){ + self.$('input.ean').val(ean); + self.pos.barcode_reader.on_ean(ean); + }); + }); + _.each(this.events, function(name){ + self.pos.proxy.add_notification(name,function(){ + console.log('Notification:',name); + self.$('.status.'+name).stop().clearQueue().css({'background-color':'#6CD11D'}); + self.$('.status.'+name).animate({'background-color':'black'},2000); + }); + }); + self.pos.proxy.add_notification('help_needed',function(){ + self.$('.status.help_needed').addClass('on'); + }); + self.pos.proxy.add_notification('help_canceled',function(){ + self.$('.status.help_needed').removeClass('on'); + }); + self.pos.proxy.add_notification('transaction_start',function(){ + self.$('.status.transaction').addClass('on'); + }); + self.pos.proxy.add_notification('transaction_end',function(){ + self.$('.status.transaction').removeClass('on'); + }); + self.pos.proxy.add_notification('weighting_start',function(){ + self.$('.status.weighting').addClass('on'); + }); + self.pos.proxy.add_notification('weighting_end',function(){ + self.$('.status.weighting').removeClass('on'); + }); + }, + }); + // The PosWidget is the main widget that contains all other widgets in the PointOfSale. // It is mainly composed of : // - a header, containing the list of orders @@ -718,14 +803,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.leftpane_width = '440px'; this.cashier_controls_visible = true; this.image_cache = new module.ImageCache(); // for faster products image display - - /* - //Epileptic mode - setInterval(function(){ - $('body').css({'-webkit-filter':'hue-rotate('+Math.random()*360+'deg)' }); - },100); - */ - }, start: function() { @@ -769,11 +846,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();}); self.$('.loader img').hide(); - if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){ - window.pos = self.pos; - window.pos_widget = self.pos_widget; - } - },function(){ // error when loading models data from the backend self.$('.loader img').hide(); return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id']) @@ -898,6 +970,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier', }); + if(this.pos.debug){ + this.debug_widget = new module.DebugWidget(this); + this.debug_widget.appendTo(this.$('#content')); + } }, changed_pending_operations: function () { diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index a0b129da2f9..7c8b18a9bc3 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -414,6 +414,55 @@
    + +
    +

    Debug Window

    +
    +
    +

    Payment Terminal

    + +
      +
    • Accept Payment
    • +
    • Reject Payment
    • +
    +

    Electronic Scale

    +
      +
    • +
    • Set Weight
    • +
    + +

    Barcode Scanner

    +
      +
    • +
    • Custom Ean13
    • +
    • Admin Badge
    • +
    • Client Badge
    • +
    • Soda 33cl
    • +
    • 3.141Kg Oranges
    • +
    • 1.54€ Lemon
    • +
    • Unknown Product
    • +
    • Invalid Ean
    • +
    + +

    Hardware Status

    +
      +
    • Help needed
    • +
    • Weighting
    • +
    • In Transaction
    • +
    +

    Hardware Events

    +
      +
    • Scan Item Success
    • +
    • Scan Item Unrecognized
    • +
    • Payment Request
    • +
    • Open Cashbox
    • + + +
    +
    +
    +
    +
  • From a1dec2072a5c02cac601f0c1b1590ccb39fa124e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 18:13:49 +0200 Subject: [PATCH 217/265] [FIX] Fixed test mocking wrong method. bzr revid: tde@openerp.com-20120912161349-ya5jvplze9ke3rtr --- addons/mail/tests/test_mail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index f5a0fa9d592..39f69ff0a68 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -122,8 +122,8 @@ class test_mail(common.TransactionCase): self.registry('ir.mail_server').build_email = self._mock_build_email self.registry('ir.mail_server').send_email = self._mock_smtp_gateway - # Mock _send_get_mail_body to test its functionality without other addons override - self.registry('mail.mail')._send_get_mail_body = self._mock_send_get_mail_body + # Mock send_get_mail_body to test its functionality without other addons override + self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body # groups@.. will cause the creation of new mail groups self.mail_group_model_id = self.ir_model.search(self.cr, self.uid, [('model', '=', 'mail.group')])[0] From 9dfca35b19d4e2cbc3ddbc74e36a4b5b0703275f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Wed, 12 Sep 2012 18:26:53 +0200 Subject: [PATCH 218/265] [IMP] point_of_sale: put debug window code in the right place bzr revid: fva@openerp.com-20120912162653-fnbvqwg4l51lveal --- addons/point_of_sale/static/src/js/widgets.js | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index c8e03ccff08..0ae127e0b1b 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -666,34 +666,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa hide: function(){ this.$el.hide(); }, }); - -// ---------- Main Point of Sale Widget ---------- - - // this is used to notify the user that data is being synchronized on the network - module.SynchNotificationWidget = module.PosBaseWidget.extend({ - template: "SynchNotificationWidget", - init: function(parent, options){ - options = options || {}; - this._super(parent, options); - }, - renderElement: function() { - var self = this; - this._super(); - this.$('.oe_pos_synch-notification-button').click(function(){ - self.pos.flush(); - }); - }, - start: function(){ - var self = this; - this.pos.bind('change:nbr_pending_operations', function(){ - self.renderElement(); - }); - }, - get_nbr_pending: function(){ - return this.pos.get('nbr_pending_operations'); - }, - }); - + // The debug widget lets the user control and monitor the hardware and software status + // without the use of the proxy module.DebugWidget = module.PosBaseWidget.extend({ template: "DebugWidget", eans:{ @@ -779,6 +753,34 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa }, }); +// ---------- Main Point of Sale Widget ---------- + + // this is used to notify the user that data is being synchronized on the network + module.SynchNotificationWidget = module.PosBaseWidget.extend({ + template: "SynchNotificationWidget", + init: function(parent, options){ + options = options || {}; + this._super(parent, options); + }, + renderElement: function() { + var self = this; + this._super(); + this.$('.oe_pos_synch-notification-button').click(function(){ + self.pos.flush(); + }); + }, + start: function(){ + var self = this; + this.pos.bind('change:nbr_pending_operations', function(){ + self.renderElement(); + }); + }, + get_nbr_pending: function(){ + return this.pos.get('nbr_pending_operations'); + }, + }); + + // The PosWidget is the main widget that contains all other widgets in the PointOfSale. // It is mainly composed of : // - a header, containing the list of orders From f49b54b2e022839e2631efbd4a5815ae3373016d Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 12 Sep 2012 18:29:11 +0200 Subject: [PATCH 219/265] [FIX] Fixed breadcrumb exception when two breadcrumbs are on the same object bzr revid: fme@openerp.com-20120912162911-q3yml2a5x96rmarp --- addons/web/static/src/js/views.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 0ecb10c7fdc..f5bf83c2c29 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -566,7 +566,8 @@ instance.web.ViewManager = instance.web.Widget.extend({ } return controller.get('title'); }); - if (next && next.action && next.action.res_id && self.active_view === 'form' && self.model === next.action.res_model && id === next.action.res_id) { + if (next && next.action && next.action.res_id && self.dataset && + self.active_view === 'form' && self.dataset.model === next.action.res_model && id === next.action.res_id) { // If the current active view is a formview and the next item in the breadcrumbs // is an action on same object (model / res_id), then we omit the current formview's title titles.pop(); From e7a24e7350efc7f38ad32df604cfdb813cfe452f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Sep 2012 18:36:18 +0200 Subject: [PATCH 220/265] [IMP] mail: invite wizard: added default message; added email send to the newly added followers. bzr revid: tde@openerp.com-20120912163618-rp67taqr24zp2yei --- addons/mail/wizard/invite.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index 71ae23304a8..4644dc1e55b 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -21,6 +21,7 @@ from osv import osv from osv import fields +from tools.translate import _ class invite_wizard(osv.osv_memory): @@ -38,6 +39,13 @@ class invite_wizard(osv.osv_memory): 'message': fields.text('Message'), } + _defaults = { + 'message': lambda s, *a, **k: s._get_default_message(*a, **k), + } + + def _get_default_message(self, cr, uid, context=None): + return _('You have been invited to follow a new document.') + def onchange_partner_ids(self, cr, uid, ids, value, context=None): """ onchange_partner_ids (value format: [[6, 0, [3, 4]]]). The basic purpose of this method is to check that destination partners @@ -52,5 +60,19 @@ class invite_wizard(osv.osv_memory): def add_followers(self, cr, uid, ids, context=None): for wizard in self.browse(cr, uid, ids, context=context): model_obj = self.pool.get(wizard.res_model) - model_obj.message_subscribe(cr, uid, [wizard.res_id], [p.id for p in wizard.partner_ids], context=context) + document = model_obj.browse(cr, uid, wizard.res_id, context=context) + + # filter partner_ids to get the new followers, to avoid sending email to already following partners + new_follower_ids = [p.id for p in wizard.partner_ids if p.id not in document.message_follower_ids] + model_obj.message_subscribe(cr, uid, [wizard.res_id], new_follower_ids, context=context) + + # send an email + if wizard.message: + for follower_id in new_follower_ids: + mail_mail = self.pool.get('mail.mail') + mail_id = mail_mail.create(cr, uid, { + 'body_html': '
    %s
    ' % wizard.message, + 'auto_delete': True, + }, context=context) + mail_mail.send(cr, uid, [mail_id], notifier_ids=[follower_id], context=context) return {'type': 'ir.actions.act_window_close'} From 5a5feab65b611c20fd42ef2ae91700311e37a4bd Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 19:16:24 +0200 Subject: [PATCH 221/265] [IMP] clean CSS and multiiline M2O bzr revid: fp@tinyerp.com-20120912171624-wx9pfhi9qb3vmxs6 --- addons/web/static/src/css/base.css | 5 +++-- addons/web/static/src/css/base.sass | 2 +- addons/web/static/src/js/view_form.js | 12 ++++-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index e89e35cecf3..b676173ddd8 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -25,6 +25,7 @@ display: none !important; } } + .openerp.openerp_webclient_container { height: 100%; position: relative; @@ -40,7 +41,7 @@ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5); /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ + */ */ } .openerp :-moz-placeholder { color: #afafb6 !important; @@ -243,7 +244,7 @@ border-radius: 0 0 2px 2px; } .openerp.ui-dialog .ui-dialog-buttonpane button { - margin: 0; + margin: 0 4px 0 0; } .openerp.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: left; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index e00c1e8401c..c8195506da0 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -266,7 +266,7 @@ $sheet-max-width: 860px margin: 0 @include radius(0 0 2px 2px) button - margin: 0 + margin: 0 4px 0 0 .ui-dialog-buttonset float: left .ui-button diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 0e66ab6bfc3..7d328f012fe 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2954,14 +2954,10 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc var lines = _.escape(str).split("\n"); var link = ""; var follow = ""; - if (! this.options.highlight_first_line) { - link = lines.join("
    "); - } else { - link = lines[0]; - follow = _.rest(lines).join("
    "); - if (follow) - link += "
    "; - } + link = lines[0]; + follow = _.rest(lines).join("
    "); + if (follow) + link += "
    "; var $link = this.$el.find('.oe_form_uri') .unbind('click') .html(link); From 5d3f9a09d11d861a6eea8c7f5fbacc7dd71626c3 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 12 Sep 2012 19:16:36 +0200 Subject: [PATCH 222/265] [IMP] usability, clean several screens bzr revid: fp@tinyerp.com-20120912171636-53vgvm34u579cmjv --- addons/account/account_installer.xml | 8 +++++-- addons/account/installer.py | 4 ++-- addons/sale/sale_view.xml | 2 +- .../sale/wizard/sale_make_invoice_advance.py | 6 +++--- .../sale/wizard/sale_make_invoice_advance.xml | 21 ++++++++++++------- .../stock/wizard/stock_change_product_qty.py | 2 +- .../wizard/stock_change_product_qty_view.xml | 2 +- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml index c92d4eda602..05a51fe0e40 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -14,8 +14,12 @@ +

    + Select a configuration package to setup automatically your + taxes and chart of accounts. +

    - + @@ -32,7 +36,7 @@ - Configure your Chart of Accounts + Configure Invoicing Data ir.actions.act_window account.installer diff --git a/addons/account/installer.py b/addons/account/installer.py index 60a34628b1b..6173ea9213e 100644 --- a/addons/account/installer.py +++ b/addons/account/installer.py @@ -45,12 +45,12 @@ class account_installer(osv.osv_memory): sorted(((m.name, m.shortdesc) for m in modules.browse(cr, uid, ids, context=context)), key=itemgetter(1))) - charts.insert(0, ('configurable', 'Generic Chart Of Accounts')) + charts.insert(0, ('configurable', _('Custom'))) return charts _columns = { # Accounting - 'charts': fields.selection(_get_charts, 'Chart of Accounts', + 'charts': fields.selection(_get_charts, 'Accounting Package', required=True, help="Installs localized accounting charts to match as closely as " "possible the accounting needs of your company based on your " diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index 31a37c1a921..af86cf9b218 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -183,7 +183,7 @@
  • - + diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index a672c6b680a..a2c45bead62 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -28,9 +28,9 @@ class sale_advance_payment_inv(osv.osv_memory): _columns = { 'advance_payment_method':fields.selection( - [('all', 'Invoice all the Sale Order'), ('percentage','Percentage'), ('fixed','Fixed Price'), - ('lines', 'Some Order Lines')], - 'Type', required=True, + [('all', 'Invoice the whole sale order'), ('percentage','Percentage'), ('fixed','Fixed price (deposit)'), + ('lines', 'Some order lines')], + 'Invoice Method', required=True, help="""Use All to create the final invoice. Use Percentage to invoice a percentage of the total amount. Use Fixed Price to invoice a specific amound in advance. diff --git a/addons/sale/wizard/sale_make_invoice_advance.xml b/addons/sale/wizard/sale_make_invoice_advance.xml index 97e9c843683..17821f519a6 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.xml +++ b/addons/sale/wizard/sale_make_invoice_advance.xml @@ -2,12 +2,17 @@ - Advance Invoice + Invoice Order sale.advance.payment.inv - + +

    + Select how you want to invoice this order. This + will create a draft invoice that can be modified + before validation. +

    -
    - +
    +
    ","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| -b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/addons/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js b/addons/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js deleted file mode 100644 index 85aa395e4f7..00000000000 --- a/addons/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js +++ /dev/null @@ -1,5111 +0,0 @@ -/*! - * jQuery Mobile v1.0a4.1 - * http://jquerymobile.com/ - * - * Copyright 2010, jQuery Project - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - */ -/*! - * jQuery UI Widget @VERSION - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ -(function( $, undefined ) { - -// jQuery 1.4+ -if ( $.cleanData ) { - var _cleanData = $.cleanData; - $.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - $( elem ).triggerHandler( "remove" ); - } - _cleanData( elems ); - }; -} else { - var _remove = $.fn.remove; - $.fn.remove = function( selector, keepData ) { - return this.each(function() { - if ( !keepData ) { - if ( !selector || $.filter( selector, [ this ] ).length ) { - $( "*", this ).add( [ this ] ).each(function() { - $( this ).triggerHandler( "remove" ); - }); - } - } - return _remove.call( $(this), selector, keepData ); - }); - }; -} - -$.widget = function( name, base, prototype ) { - var namespace = name.split( "." )[ 0 ], - fullName; - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName ] = function( elem ) { - return !!$.data( elem, name ); - }; - - $[ namespace ] = $[ namespace ] || {}; - $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - - var basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from -// $.each( basePrototype, function( key, val ) { -// if ( $.isPlainObject(val) ) { -// basePrototype[ key ] = $.extend( {}, val ); -// } -// }); - basePrototype.options = $.extend( true, {}, basePrototype.options ); - $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { - namespace: namespace, - widgetName: name, - widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, - widgetBaseClass: fullName - }, prototype ); - - $.widget.bridge( name, $[ namespace ][ name ] ); -}; - -$.widget.bridge = function( name, object ) { - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = Array.prototype.slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.extend.apply( null, [ true, options ].concat(args) ) : - options; - - // prevent calls to internal methods - if ( isMethodCall && options.charAt( 0 ) === "_" ) { - return returnValue; - } - - if ( isMethodCall ) { - this.each(function() { - var instance = $.data( this, name ); - if ( !instance ) { - throw "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'"; - } - if ( !$.isFunction( instance[options] ) ) { - throw "no such method '" + options + "' for " + name + " widget instance"; - } - var methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, name ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, name, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } -}; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - options: { - disabled: false - }, - _createWidget: function( options, element ) { - // $.widget.bridge stores the plugin instance, but we do it anyway - // so that it's stored even before the _create function runs - $.data( element, this.widgetName, this ); - this.element = $( element ); - this.options = $.extend( true, {}, - this.options, - this._getCreateOptions(), - options ); - - var self = this; - this.element.bind( "remove." + this.widgetName, function() { - self.destroy(); - }); - - this._create(); - this._trigger( "create" ); - this._init(); - }, - _getCreateOptions: function() { - var options = {}; - if ( $.metadata ) { - options = $.metadata.get( element )[ this.widgetName ]; - } - return options; - }, - _create: function() {}, - _init: function() {}, - - destroy: function() { - this.element - .unbind( "." + this.widgetName ) - .removeData( this.widgetName ); - this.widget() - .unbind( "." + this.widgetName ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetBaseClass + "-disabled " + - "ui-state-disabled" ); - }, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.extend( {}, this.options ); - } - - if (typeof key === "string" ) { - if ( value === undefined ) { - return this.options[ key ]; - } - options = {}; - options[ key ] = value; - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var self = this; - $.each( options, function( key, value ) { - self._setOption( key, value ); - }); - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - [ value ? "addClass" : "removeClass"]( - this.widgetBaseClass + "-disabled" + " " + - "ui-state-disabled" ) - .attr( "aria-disabled", value ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _trigger: function( type, event, data ) { - var callback = this.options[ type ]; - - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - data = data || {}; - - // copy original event properties over to the new event - // this would happen if we could call $.event.fix instead of $.Event - // but we don't have a way to force an event to be fixed multiple times - if ( event.originalEvent ) { - for ( var i = $.event.props.length, prop; i; ) { - prop = $.event.props[ --i ]; - event[ prop ] = event.originalEvent[ prop ]; - } - } - - this.element.trigger( event, data ); - - return !( $.isFunction(callback) && - callback.call( this.element[0], event, data ) === false || - event.isDefaultPrevented() ); - } -}; - -})( jQuery ); -/* -* jQuery Mobile Framework : widget factory extentions for mobile -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -$.widget( "mobile.widget", { - _getCreateOptions: function() { - var elem = this.element, - options = {}; - $.each( this.options, function( option ) { - var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) { - return "-" + c.toLowerCase(); - } ) ); - if ( value !== undefined ) { - options[ option ] = value; - } - }); - return options; - } -}); - -})( jQuery ); -/* -* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -var $window = $(window), - $html = $( "html" ), - - //media-query-like width breakpoints, which are translated to classes on the html element - resolutionBreakpoints = [320,480,768,1024]; - - -/* $.mobile.media method: pass a CSS media type or query and get a bool return - note: this feature relies on actual media query support for media queries, though types will work most anywhere - examples: - $.mobile.media('screen') //>> tests for screen media type - $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px - $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4) -*/ -$.mobile.media = (function() { - // TODO: use window.matchMedia once at least one UA implements it - var cache = {}, - testDiv = $( "
    " ), - fakeBody = $( "" ).append( testDiv ); - - return function( query ) { - if ( !( query in cache ) ) { - var styleBlock = document.createElement('style'), - cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }"; - //must set type for IE! - styleBlock.type = "text/css"; - if (styleBlock.styleSheet){ - styleBlock.styleSheet.cssText = cssrule; - } - else { - styleBlock.appendChild(document.createTextNode(cssrule)); - } - - $html.prepend( fakeBody ).prepend( styleBlock ); - cache[ query ] = testDiv.css( "position" ) === "absolute"; - fakeBody.add( styleBlock ).remove(); - } - return cache[ query ]; - }; -})(); - -/* - private function for adding/removing breakpoint classes to HTML element for faux media-query support - It does not require media query support, instead using JS to detect screen width > cross-browser support - This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace -*/ -function detectResolutionBreakpoints(){ - var currWidth = $window.width(), - minPrefix = "min-width-", - maxPrefix = "max-width-", - minBreakpoints = [], - maxBreakpoints = [], - unit = "px", - breakpointClasses; - - $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " + - maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit ); - - $.each(resolutionBreakpoints,function( i, breakPoint ){ - if( currWidth >= breakPoint ){ - minBreakpoints.push( minPrefix + breakPoint + unit ); - } - if( currWidth <= breakPoint ){ - maxBreakpoints.push( maxPrefix + breakPoint + unit ); - } - }); - - if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); } - if( maxBreakpoints.length ){ breakpointClasses += " " + maxBreakpoints.join(" "); } - - $html.addClass( breakpointClasses ); -}; - -/* $.mobile.addResolutionBreakpoints method: - pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes - Examples: - $.mobile.addResolutionBreakpoints( 500 ); - $.mobile.addResolutionBreakpoints( [500, 1200] ); -*/ -$.mobile.addResolutionBreakpoints = function( newbps ){ - if( $.type( newbps ) === "array" ){ - resolutionBreakpoints = resolutionBreakpoints.concat( newbps ); - } - else { - resolutionBreakpoints.push( newbps ); - } - resolutionBreakpoints.sort(function(a,b){ return a-b; }); - detectResolutionBreakpoints(); -}; - -/* on mobileinit, add classes to HTML element - and set handlers to update those on orientationchange and resize*/ -$(document).bind("mobileinit.htmlclass", function(){ - /* bind to orientationchange and resize - to add classes to HTML element for min/max breakpoints and orientation */ - $window.bind("orientationchange.htmlclass resize.htmlclass", function(event){ - //add orientation class to HTML element on flip/resize. - if(event.orientation){ - $html.removeClass( "portrait landscape" ).addClass( event.orientation ); - } - //add classes to HTML element for min/max breakpoints - detectResolutionBreakpoints(); - }); -}); - -/* Manually trigger an orientationchange event when the dom ready event fires. - This will ensure that any viewport meta tag that may have been injected - has taken effect already, allowing us to properly calculate the width of the - document. -*/ -$(function(){ - //trigger event manually - $window.trigger( "orientationchange.htmlclass" ); -}); - -})(jQuery);/* -* jQuery Mobile Framework : support tests -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. -* Note: Code is in draft form and is subject to change -*/ -(function($, undefined ) { - - - -var fakeBody = $( "" ).prependTo( "html" ), - fbCSS = fakeBody[0].style, - vendors = ['webkit','moz','o'], - webos = window.palmGetResource || window.PalmServiceBridge, //only used to rule out scrollTop - bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB - -//thx Modernizr -function propExists( prop ){ - var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), - props = (prop + ' ' + vendors.join(uc_prop + ' ') + uc_prop).split(' '); - for(var v in props){ - if( fbCSS[ v ] !== undefined ){ - return true; - } - } -}; - -//test for dynamic-updating base tag support (allows us to avoid href,src attr rewriting) -function baseTagTest(){ - var fauxBase = location.protocol + '//' + location.host + location.pathname + "ui-dir/", - base = $("head base"), - fauxEle = null, - href = ''; - if (!base.length) { - base = fauxEle = $("", {"href": fauxBase}).appendTo("head"); - } - else { - href = base.attr("href"); - } - var link = $( "" ).prependTo( fakeBody ), - rebase = link[0].href; - base[0].href = href ? href : location.pathname; - if (fauxEle) { - fauxEle.remove(); - } - return rebase.indexOf(fauxBase) === 0; -}; - - -//non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683 -//allows for inclusion of IE 6+, including Windows Mobile 7 -$.mobile.browser = {}; -$.mobile.browser.ie = (function() { - var v = 3, div = document.createElement('div'), a = div.all || []; - while (div.innerHTML = '', a[0]); - return v > 4 ? v : !v; -}()); - -$.extend( $.support, { - orientation: "orientation" in window, - touch: "ontouchend" in document, - cssTransitions: "WebKitTransitionEvent" in window, - pushState: !!history.pushState, - mediaquery: $.mobile.media('only all'), - cssPseudoElement: !!propExists('content'), - boxShadow: !!propExists('boxShadow') && !bb, - scrollTop: ("pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[0]) && !webos, - dynamicBaseTag: baseTagTest(), - eventCapture: ("addEventListener" in document) // This is a weak test. We may want to beef this up later. -}); - -fakeBody.remove(); - -//for ruling out shadows via css -if( !$.support.boxShadow ){ $('html').addClass('ui-mobile-nosupport-boxshadow'); } - -})( jQuery );/* -* jQuery Mobile Framework : "mouse" plugin -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ - -// This plugin is an experiment for abstracting away the touch and mouse -// events so that developers don't have to worry about which method of input -// the device their document is loaded on supports. -// -// The idea here is to allow the developer to register listeners for the -// basic mouse events, such as mousedown, mousemove, mouseup, and click, -// and the plugin will take care of registering the correct listeners -// behind the scenes to invoke the listener at the fastest possible time -// for that device, while still retaining the order of event firing in -// the traditional mouse environment, should multiple handlers be registered -// on the same element for different events. -// -// The current version exposes the following virtual events to jQuery bind methods: -// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" - -(function($, window, document, undefined) { - -var dataPropertyName = "virtualMouseBindings", - touchTargetPropertyName = "virtualTouchID", - virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "), - touchEventProps = "clientX clientY pageX pageY screenX screenY".split(" "), - activeDocHandlers = {}, - resetTimerID = 0, - startX = 0, - startY = 0, - startScrollX = 0, - startScrollY = 0, - didScroll = false, - clickBlockList = [], - blockMouseTriggers = false, - scrollTopSupported = $.support.scrollTop, - eventCaptureSupported = $.support.eventCapture, - $document = $(document), - nextTouchID = 1, - lastTouchID = 0; - -$.vmouse = { - moveDistanceThreshold: 10, - clickDistanceThreshold: 10, - resetTimerDuration: 1500 -}; - -function getNativeEvent(event) -{ - while (event && typeof event.originalEvent !== "undefined") { - event = event.originalEvent; - } - return event; -} - -function createVirtualEvent(event, eventType) -{ - var t = event.type; - event = $.Event(event); - event.type = eventType; - - var oe = event.originalEvent; - var props = $.event.props; - - // copy original event properties over to the new event - // this would happen if we could call $.event.fix instead of $.Event - // but we don't have a way to force an event to be fixed multiple times - if (oe) { - for ( var i = props.length, prop; i; ) { - prop = props[ --i ]; - event[prop] = oe[prop]; - } - } - - if (t.search(/^touch/) !== -1){ - var ne = getNativeEvent(oe), - t = ne.touches, - ct = ne.changedTouches, - touch = (t && t.length) ? t[0] : ((ct && ct.length) ? ct[0] : undefined); - if (touch){ - for (var i = 0, len = touchEventProps.length; i < len; i++){ - var prop = touchEventProps[i]; - event[prop] = touch[prop]; - } - } - } - - return event; -} - -function getVirtualBindingFlags(element) -{ - var flags = {}; - var $ele = $(element); - while ($ele && $ele.length){ - var b = $ele.data(dataPropertyName); - for (var k in b) { - if (b[k]){ - flags[k] = flags.hasVirtualBinding = true; - } - } - $ele = $ele.parent(); - } - return flags; -} - -function getClosestElementWithVirtualBinding(element, eventType) -{ - var $ele = $(element); - while ($ele && $ele.length){ - var b = $ele.data(dataPropertyName); - if (b && (!eventType || b[eventType])) { - return $ele; - } - $ele = $ele.parent(); - } - return null; -} - -function enableTouchBindings() -{ - if (!activeDocHandlers["touchbindings"]){ - $document.bind("touchend", handleTouchEnd) - - // On touch platforms, touching the screen and then dragging your finger - // causes the window content to scroll after some distance threshold is - // exceeded. On these platforms, a scroll prevents a click event from being - // dispatched, and on some platforms, even the touchend is suppressed. To - // mimic the suppression of the click event, we need to watch for a scroll - // event. Unfortunately, some platforms like iOS don't dispatch scroll - // events until *AFTER* the user lifts their finger (touchend). This means - // we need to watch both scroll and touchmove events to figure out whether - // or not a scroll happenens before the touchend event is fired. - - .bind("touchmove", handleTouchMove) - .bind("scroll", handleScroll); - - activeDocHandlers["touchbindings"] = 1; - } -} - -function disableTouchBindings() -{ - if (activeDocHandlers["touchbindings"]){ - $document.unbind("touchmove", handleTouchMove) - .unbind("touchend", handleTouchEnd) - .unbind("scroll", handleScroll); - activeDocHandlers["touchbindings"] = 0; - } -} - -function enableMouseBindings() -{ - lastTouchID = 0; - clickBlockList.length = 0; - blockMouseTriggers = false; - - // When mouse bindings are enabled, our - // touch bindings are disabled. - disableTouchBindings(); -} - -function disableMouseBindings() -{ - // When mouse bindings are disabled, our - // touch bindings are enabled. - enableTouchBindings(); -} - -function startResetTimer() -{ - clearResetTimer(); - resetTimerID = setTimeout(function(){ - resetTimerID = 0; - enableMouseBindings(); - }, $.vmouse.resetTimerDuration); -} - -function clearResetTimer() -{ - if (resetTimerID){ - clearTimeout(resetTimerID); - resetTimerID = 0; - } -} - -function triggerVirtualEvent(eventType, event, flags) -{ - var defaultPrevented = false; - - if ((flags && flags[eventType]) || (!flags && getClosestElementWithVirtualBinding(event.target, eventType))) { - var ve = createVirtualEvent(event, eventType); - $(event.target).trigger(ve); - defaultPrevented = ve.isDefaultPrevented(); - } - - return defaultPrevented; -} - -function mouseEventCallback(event) -{ - var touchID = $(event.target).data(touchTargetPropertyName); - if (!blockMouseTriggers && (!lastTouchID || lastTouchID !== touchID)){ - triggerVirtualEvent("v" + event.type, event); - } -} - -function handleTouchStart(event) -{ - var touches = getNativeEvent(event).touches; - if (touches && touches.length === 1){ - var target = event.target, - flags = getVirtualBindingFlags(target); - - if (flags.hasVirtualBinding){ - lastTouchID = nextTouchID++; - $(target).data(touchTargetPropertyName, lastTouchID); - - clearResetTimer(); - - disableMouseBindings(); - didScroll = false; - - var t = getNativeEvent(event).touches[0]; - startX = t.pageX; - startY = t.pageY; - - if (scrollTopSupported){ - startScrollX = window.pageXOffset; - startScrollY = window.pageYOffset; - } - - triggerVirtualEvent("vmouseover", event, flags); - triggerVirtualEvent("vmousedown", event, flags); - } - } -} - -function handleScroll(event) -{ - if (!didScroll){ - triggerVirtualEvent("vmousecancel", event, getVirtualBindingFlags(event.target)); - } - - didScroll = true; - startResetTimer(); -} - -function handleTouchMove(event) -{ - var t = getNativeEvent(event).touches[0]; - - var didCancel = didScroll, - moveThreshold = $.vmouse.moveDistanceThreshold; - didScroll = didScroll - || (scrollTopSupported && (startScrollX !== window.pageXOffset || startScrollY !== window.pageYOffset)) - || (Math.abs(t.pageX - startX) > moveThreshold || Math.abs(t.pageY - startY) > moveThreshold); - - var flags = getVirtualBindingFlags(event.target); - if (didScroll && !didCancel){ - triggerVirtualEvent("vmousecancel", event, flags); - } - triggerVirtualEvent("vmousemove", event, flags); - startResetTimer(); -} - -function handleTouchEnd(event) -{ - disableTouchBindings(); - - var flags = getVirtualBindingFlags(event.target); - triggerVirtualEvent("vmouseup", event, flags); - if (!didScroll){ - if (triggerVirtualEvent("vclick", event, flags)){ - // The target of the mouse events that follow the touchend - // event don't necessarily match the target used during the - // touch. This means we need to rely on coordinates for blocking - // any click that is generated. - var t = getNativeEvent(event).changedTouches[0]; - clickBlockList.push({ touchID: lastTouchID, x: t.clientX, y: t.clientY }); - - // Prevent any mouse events that follow from triggering - // virtual event notifications. - blockMouseTriggers = true; - } - } - triggerVirtualEvent("vmouseout", event, flags); - didScroll = false; - - startResetTimer(); -} - -function hasVirtualBindings($ele) -{ - var bindings = $ele.data(dataPropertyName), k; - if (bindings){ - for (k in bindings){ - if (bindings[k]){ - return true; - } - } - } - return false; -} - -function dummyMouseHandler(){} - -function getSpecialEventObject(eventType) -{ - var realType = eventType.substr(1); - return { - setup: function(data, namespace) { - // If this is the first virtual mouse binding for this element, - // add a bindings object to its data. - - var $this = $(this); - - if (!hasVirtualBindings($this)){ - $this.data(dataPropertyName, {}); - } - - // If setup is called, we know it is the first binding for this - // eventType, so initialize the count for the eventType to zero. - - var bindings = $this.data(dataPropertyName); - bindings[eventType] = true; - - // If this is the first virtual mouse event for this type, - // register a global handler on the document. - - activeDocHandlers[eventType] = (activeDocHandlers[eventType] || 0) + 1; - if (activeDocHandlers[eventType] === 1){ - $document.bind(realType, mouseEventCallback); - } - - // Some browsers, like Opera Mini, won't dispatch mouse/click events - // for elements unless they actually have handlers registered on them. - // To get around this, we register dummy handlers on the elements. - - $this.bind(realType, dummyMouseHandler); - - // For now, if event capture is not supported, we rely on mouse handlers. - if (eventCaptureSupported){ - // If this is the first virtual mouse binding for the document, - // register our touchstart handler on the document. - - activeDocHandlers["touchstart"] = (activeDocHandlers["touchstart"] || 0) + 1; - if (activeDocHandlers["touchstart"] === 1) { - $document.bind("touchstart", handleTouchStart); - } - } - }, - - teardown: function(data, namespace) { - // If this is the last virtual binding for this eventType, - // remove its global handler from the document. - - --activeDocHandlers[eventType]; - if (!activeDocHandlers[eventType]){ - $document.unbind(realType, mouseEventCallback); - } - - if (eventCaptureSupported){ - // If this is the last virtual mouse binding in existence, - // remove our document touchstart listener. - - --activeDocHandlers["touchstart"]; - if (!activeDocHandlers["touchstart"]) { - $document.unbind("touchstart", handleTouchStart); - } - } - - var $this = $(this), - bindings = $this.data(dataPropertyName); - bindings[eventType] = false; - - // Unregister the dummy event handler. - - $this.unbind(realType, dummyMouseHandler); - - // If this is the last virtual mouse binding on the - // element, remove the binding data from the element. - - if (!hasVirtualBindings($this)){ - $this.removeData(dataPropertyName); - } - } - }; -} - -// Expose our custom events to the jQuery bind/unbind mechanism. - -for (var i = 0; i < virtualEventNames.length; i++){ - $.event.special[virtualEventNames[i]] = getSpecialEventObject(virtualEventNames[i]); -} - -// Add a capture click handler to block clicks. -// Note that we require event capture support for this so if the device -// doesn't support it, we punt for now and rely solely on mouse events. -if (eventCaptureSupported){ - document.addEventListener("click", function(e){ - var cnt = clickBlockList.length; - var target = e.target; - if (cnt) { - var x = e.clientX, - y = e.clientY, - threshold = $.vmouse.clickDistanceThreshold; - - // The idea here is to run through the clickBlockList to see if - // the current click event is in the proximity of one of our - // vclick events that had preventDefault() called on it. If we find - // one, then we block the click. - // - // Why do we have to rely on proximity? - // - // Because the target of the touch event that triggered the vclick - // can be different from the target of the click event synthesized - // by the browser. The target of a mouse/click event that is syntehsized - // from a touch event seems to be implementation specific. For example, - // some browsers will fire mouse/click events for a link that is near - // a touch event, even though the target of the touchstart/touchend event - // says the user touched outside the link. Also, it seems that with most - // browsers, the target of the mouse/click event is not calculated until the - // time it is dispatched, so if you replace an element that you touched - // with another element, the target of the mouse/click will be the new - // element underneath that point. - // - // Aside from proximity, we also check to see if the target and any - // of its ancestors were the ones that blocked a click. This is necessary - // because of the strange mouse/click target calculation done in the - // Android 2.1 browser, where if you click on an element, and there is a - // mouse/click handler on one of its ancestors, the target will be the - // innermost child of the touched element, even if that child is no where - // near the point of touch. - - var ele = target; - while (ele) { - for (var i = 0; i < cnt; i++) { - var o = clickBlockList[i], - touchID = 0; - if ((ele === target && Math.abs(o.x - x) < threshold && Math.abs(o.y - y) < threshold) || $(ele).data(touchTargetPropertyName) === o.touchID){ - // XXX: We may want to consider removing matches from the block list - // instead of waiting for the reset timer to fire. - e.preventDefault(); - e.stopPropagation(); - return; - } - } - ele = ele.parentNode; - } - } - }, true); -} -})(jQuery, window, document);/* -* jQuery Mobile Framework : events -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -// add new event shortcuts -$.each( "touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) { - $.fn[ name ] = function( fn ) { - return fn ? this.bind( name, fn ) : this.trigger( name ); - }; - $.attrFn[ name ] = true; -}); - -var supportTouch = $.support.touch, - scrollEvent = "touchmove scroll", - touchStartEvent = supportTouch ? "touchstart" : "mousedown", - touchStopEvent = supportTouch ? "touchend" : "mouseup", - touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; - -function triggerCustomEvent(obj, eventType, event) -{ - var originalType = event.type; - event.type = eventType; - $.event.handle.call( obj, event ); - event.type = originalType; -} - -// also handles scrollstop -$.event.special.scrollstart = { - enabled: true, - - setup: function() { - var thisObject = this, - $this = $( thisObject ), - scrolling, - timer; - - function trigger( event, state ) { - scrolling = state; - triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event ); - } - - // iPhone triggers scroll after a small delay; use touchmove instead - $this.bind( scrollEvent, function( event ) { - if ( !$.event.special.scrollstart.enabled ) { - return; - } - - if ( !scrolling ) { - trigger( event, true ); - } - - clearTimeout( timer ); - timer = setTimeout(function() { - trigger( event, false ); - }, 50 ); - }); - } -}; - -// also handles taphold -$.event.special.tap = { - setup: function() { - var thisObject = this, - $this = $( thisObject ); - - $this - .bind("vmousedown", function( event ) { - if ( event.which && event.which !== 1 ) { - return false; - } - - var touching = true, - origTarget = event.target, - origEvent = event.originalEvent, - timer; - - function clearTapHandlers() { - touching = false; - clearTimeout(timer); - $this.unbind("vclick", clickHandler).unbind("vmousecancel", clearTapHandlers); - } - - function clickHandler(event) { - clearTapHandlers(); - - /* ONLY trigger a 'tap' event if the start target is - * the same as the stop target. - */ - if ( origTarget == event.target ) { - triggerCustomEvent( thisObject, "tap", event ); - } - } - - $this.bind("vmousecancel", clearTapHandlers).bind("vclick", clickHandler); - - timer = setTimeout(function() { - if ( touching ) { - triggerCustomEvent( thisObject, "taphold", event ); - } - }, 750 ); - }); - } -}; - -// also handles swipeleft, swiperight -$.event.special.swipe = { - setup: function() { - var thisObject = this, - $this = $( thisObject ); - - $this - .bind( touchStartEvent, function( event ) { - var data = event.originalEvent.touches ? - event.originalEvent.touches[ 0 ] : - event, - start = { - time: (new Date).getTime(), - coords: [ data.pageX, data.pageY ], - origin: $( event.target ) - }, - stop; - - function moveHandler( event ) { - if ( !start ) { - return; - } - - var data = event.originalEvent.touches ? - event.originalEvent.touches[ 0 ] : - event; - stop = { - time: (new Date).getTime(), - coords: [ data.pageX, data.pageY ] - }; - - // prevent scrolling - if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) { - event.preventDefault(); - } - } - - $this - .bind( touchMoveEvent, moveHandler ) - .one( touchStopEvent, function( event ) { - $this.unbind( touchMoveEvent, moveHandler ); - if ( start && stop ) { - if ( stop.time - start.time < 1000 && - Math.abs( start.coords[0] - stop.coords[0]) > 30 && - Math.abs( start.coords[1] - stop.coords[1]) < 75 ) { - start.origin - .trigger( "swipe" ) - - .trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" ); - } - } - start = stop = undefined; - }); - }); - } -}; - -(function($){ - // "Cowboy" Ben Alman - - var win = $(window), - special_event, - get_orientation, - last_orientation; - - $.event.special.orientationchange = special_event = { - setup: function(){ - // If the event is supported natively, return false so that jQuery - // will bind to the event using DOM methods. - if ( $.support.orientation ) { return false; } - - // Get the current orientation to avoid initial double-triggering. - last_orientation = get_orientation(); - - // Because the orientationchange event doesn't exist, simulate the - // event by testing window dimensions on resize. - win.bind( "resize", handler ); - }, - teardown: function(){ - // If the event is not supported natively, return false so that - // jQuery will unbind the event using DOM methods. - if ( $.support.orientation ) { return false; } - - // Because the orientationchange event doesn't exist, unbind the - // resize event handler. - win.unbind( "resize", handler ); - }, - add: function( handleObj ) { - // Save a reference to the bound event handler. - var old_handler = handleObj.handler; - - handleObj.handler = function( event ) { - // Modify event object, adding the .orientation property. - event.orientation = get_orientation(); - - // Call the originally-bound event handler and return its result. - return old_handler.apply( this, arguments ); - }; - } - }; - - // If the event is not supported natively, this handler will be bound to - // the window resize event to simulate the orientationchange event. - function handler() { - // Get the current orientation. - var orientation = get_orientation(); - - if ( orientation !== last_orientation ) { - // The orientation has changed, so trigger the orientationchange event. - last_orientation = orientation; - win.trigger( "orientationchange" ); - } - }; - - // Get the current page orientation. This method is exposed publicly, should it - // be needed, as jQuery.event.special.orientationchange.orientation() - special_event.orientation = get_orientation = function() { - var elem = document.documentElement; - return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape"; - }; - -})(jQuery); - -$.each({ - scrollstop: "scrollstart", - taphold: "tap", - swipeleft: "swipe", - swiperight: "swipe" -}, function( event, sourceEvent ) { - $.event.special[ event ] = { - setup: function() { - $( this ).bind( sourceEvent, $.noop ); - } - }; -}); - -})( jQuery ); -/*! - * jQuery hashchange event - v1.3 - 7/21/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ - -// Script: jQuery hashchange event -// -// *Version: 1.3, Last updated: 7/21/2010* -// -// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ -// GitHub - http://github.com/cowboy/jquery-hashchange/ -// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js -// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped) -// -// About: License -// -// Copyright (c) 2010 "Cowboy" Ben Alman, -// Dual licensed under the MIT and GPL licenses. -// http://benalman.com/about/license/ -// -// About: Examples -// -// These working examples, complete with fully commented code, illustrate a few -// ways in which this plugin can be used. -// -// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ -// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/ -// -// About: Support and Testing -// -// Information about what version or versions of jQuery this plugin has been -// tested with, what browsers it has been tested in, and where the unit tests -// reside (so you can test it yourself). -// -// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2 -// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5, -// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5. -// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ -// -// About: Known issues -// -// While this jQuery hashchange event implementation is quite stable and -// robust, there are a few unfortunate browser bugs surrounding expected -// hashchange event-based behaviors, independent of any JavaScript -// window.onhashchange abstraction. See the following examples for more -// information: -// -// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ -// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ -// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ -// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ -// -// Also note that should a browser natively support the window.onhashchange -// event, but not report that it does, the fallback polling loop will be used. -// -// About: Release History -// -// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more -// "removable" for mobile-only development. Added IE6/7 document.title -// support. Attempted to make Iframe as hidden as possible by using -// techniques from http://www.paciellogroup.com/blog/?p=604. Added -// support for the "shortcut" format $(window).hashchange( fn ) and -// $(window).hashchange() like jQuery provides for built-in events. -// Renamed jQuery.hashchangeDelay to and -// lowered its default value to 50. Added -// and properties plus document-domain.html -// file to address access denied issues when setting document.domain in -// IE6/7. -// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin -// from a page on another domain would cause an error in Safari 4. Also, -// IE6/7 Iframe is now inserted after the body (this actually works), -// which prevents the page from scrolling when the event is first bound. -// Event can also now be bound before DOM ready, but it won't be usable -// before then in IE6/7. -// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug -// where browser version is incorrectly reported as 8.0, despite -// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. -// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special -// window.onhashchange functionality into a separate plugin for users -// who want just the basic event & back button support, without all the -// extra awesomeness that BBQ provides. This plugin will be included as -// part of jQuery BBQ, but also be available separately. - -(function($,window,undefined){ - '$:nomunge'; // Used by YUI compressor. - - // Reused string. - var str_hashchange = 'hashchange', - - // Method / object references. - doc = document, - fake_onhashchange, - special = $.event.special, - - // Does the browser support window.onhashchange? Note that IE8 running in - // IE7 compatibility mode reports true for 'onhashchange' in window, even - // though the event isn't supported, so also test document.documentMode. - doc_mode = doc.documentMode, - supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 ); - - // Get location.hash (or what you'd expect location.hash to be) sans any - // leading #. Thanks for making this necessary, Firefox! - function get_fragment( url ) { - url = url || location.href; - return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' ); - }; - - // Method: jQuery.fn.hashchange - // - // Bind a handler to the window.onhashchange event or trigger all bound - // window.onhashchange event handlers. This behavior is consistent with - // jQuery's built-in event handlers. - // - // Usage: - // - // > jQuery(window).hashchange( [ handler ] ); - // - // Arguments: - // - // handler - (Function) Optional handler to be bound to the hashchange - // event. This is a "shortcut" for the more verbose form: - // jQuery(window).bind( 'hashchange', handler ). If handler is omitted, - // all bound window.onhashchange event handlers will be triggered. This - // is a shortcut for the more verbose - // jQuery(window).trigger( 'hashchange' ). These forms are described in - // the section. - // - // Returns: - // - // (jQuery) The initial jQuery collection of elements. - - // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and - // $(elem).hashchange() for triggering, like jQuery does for built-in events. - $.fn[ str_hashchange ] = function( fn ) { - return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange ); - }; - - // Property: jQuery.fn.hashchange.delay - // - // The numeric interval (in milliseconds) at which the - // polling loop executes. Defaults to 50. - - // Property: jQuery.fn.hashchange.domain - // - // If you're setting document.domain in your JavaScript, and you want hash - // history to work in IE6/7, not only must this property be set, but you must - // also set document.domain BEFORE jQuery is loaded into the page. This - // property is only applicable if you are supporting IE6/7 (or IE8 operating - // in "IE7 compatibility" mode). - // - // In addition, the property must be set to the - // path of the included "document-domain.html" file, which can be renamed or - // modified if necessary (note that the document.domain specified must be the - // same in both your main JavaScript as well as in this file). - // - // Usage: - // - // jQuery.fn.hashchange.domain = document.domain; - - // Property: jQuery.fn.hashchange.src - // - // If, for some reason, you need to specify an Iframe src file (for example, - // when setting document.domain as in ), you can - // do so using this property. Note that when using this property, history - // won't be recorded in IE6/7 until the Iframe src file loads. This property - // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7 - // compatibility" mode). - // - // Usage: - // - // jQuery.fn.hashchange.src = 'path/to/file.html'; - - $.fn[ str_hashchange ].delay = 50; - /* - $.fn[ str_hashchange ].domain = null; - $.fn[ str_hashchange ].src = null; - */ - - // Event: hashchange event - // - // Fired when location.hash changes. In browsers that support it, the native - // HTML5 window.onhashchange event is used, otherwise a polling loop is - // initialized, running every milliseconds to - // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7 - // compatibility" mode), a hidden Iframe is created to allow the back button - // and hash-based history to work. - // - // Usage as described in : - // - // > // Bind an event handler. - // > jQuery(window).hashchange( function(e) { - // > var hash = location.hash; - // > ... - // > }); - // > - // > // Manually trigger the event handler. - // > jQuery(window).hashchange(); - // - // A more verbose usage that allows for event namespacing: - // - // > // Bind an event handler. - // > jQuery(window).bind( 'hashchange', function(e) { - // > var hash = location.hash; - // > ... - // > }); - // > - // > // Manually trigger the event handler. - // > jQuery(window).trigger( 'hashchange' ); - // - // Additional Notes: - // - // * The polling loop and Iframe are not created until at least one handler - // is actually bound to the 'hashchange' event. - // * If you need the bound handler(s) to execute immediately, in cases where - // a location.hash exists on page load, via bookmark or page refresh for - // example, use jQuery(window).hashchange() or the more verbose - // jQuery(window).trigger( 'hashchange' ). - // * The event can be bound before DOM ready, but since it won't be usable - // before then in IE6/7 (due to the necessary Iframe), recommended usage is - // to bind it inside a DOM ready handler. - - // Override existing $.event.special.hashchange methods (allowing this plugin - // to be defined after jQuery BBQ in BBQ's source code). - special[ str_hashchange ] = $.extend( special[ str_hashchange ], { - - // Called only when the first 'hashchange' event is bound to window. - setup: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to create our own. And we don't want to call this - // until the user binds to the event, just in case they never do, since it - // will create a polling loop and possibly even a hidden Iframe. - $( fake_onhashchange.start ); - }, - - // Called only when the last 'hashchange' event is unbound from window. - teardown: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to stop ours (if possible). - $( fake_onhashchange.stop ); - } - - }); - - // fake_onhashchange does all the work of triggering the window.onhashchange - // event for browsers that don't natively support it, including creating a - // polling loop to watch for hash changes and in IE 6/7 creating a hidden - // Iframe to enable back and forward. - fake_onhashchange = (function(){ - var self = {}, - timeout_id, - - // Remember the initial hash so it doesn't get triggered immediately. - last_hash = get_fragment(), - - fn_retval = function(val){ return val; }, - history_set = fn_retval, - history_get = fn_retval; - - // Start the polling loop. - self.start = function() { - timeout_id || poll(); - }; - - // Stop the polling loop. - self.stop = function() { - timeout_id && clearTimeout( timeout_id ); - timeout_id = undefined; - }; - - // This polling loop checks every $.fn.hashchange.delay milliseconds to see - // if location.hash has changed, and triggers the 'hashchange' event on - // window when necessary. - function poll() { - var hash = get_fragment(), - history_hash = history_get( last_hash ); - - if ( hash !== last_hash ) { - history_set( last_hash = hash, history_hash ); - - $(window).trigger( str_hashchange ); - - } else if ( history_hash !== last_hash ) { - location.href = location.href.replace( /#.*/, '' ) + history_hash; - } - - timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay ); - }; - - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - $.browser.msie && !supports_onhashchange && (function(){ - // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8 - // when running in "IE7 compatibility" mode. - - var iframe, - iframe_src; - - // When the event is bound and polling starts in IE 6/7, create a hidden - // Iframe for history handling. - self.start = function(){ - if ( !iframe ) { - iframe_src = $.fn[ str_hashchange ].src; - iframe_src = iframe_src && iframe_src + get_fragment(); - - // Create hidden Iframe. Attempt to make Iframe as hidden as possible - // by using techniques from http://www.paciellogroup.com/blog/?p=604. - iframe = $('