diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 937c9cbd20b..590d3b11a87 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -36,7 +36,7 @@ The kernel of OpenERP, needed for all installation. 'data': [ 'base_data.xml', 'currency_data.xml', - 'country_data.xml', + 'res/res_country_data.xml', 'security/base_security.xml', 'base_menu.xml', 'res/res_security.xml', diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml index 2fa9910758d..4c429fe56ff 100644 --- a/openerp/addons/base/base_data.xml +++ b/openerp/addons/base/base_data.xml @@ -62,8 +62,6 @@ Your Company Your Company Slogan - Web: http://www.yourcompany.com - Tel: +33 1 49 51 23 94 - Bank Accounts... to be configured in menu Settings > Accounting/Invoicing. 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/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index 3bfbd822dae..3d6fce8113a 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -172,37 +172,35 @@ class res_partner_bank(osv.osv): ('required', field.required)] return res - def _prepare_name_get(self, cr, uid, bank_type_obj, bank_obj, context=None): + def _prepare_name_get(self, cr, uid, bank_dicts, context=None): + """ Format the name of a res.partner.bank. + This function is designed to be inherited to add replacement fields. + :param bank_dicts: a list of res.partner.bank dicts, as returned by the method read() + :return: [(id, name), ...], as returned by the method name_get() """ - Format the name of a res.partner.bank. - This function is designed to be inherited to add replacement fields. - :param browse_record bank_type_obj: res.partner.bank.type object - :param browse_record bank_obj: res.partner.bank object - :rtype: str - :return: formatted name of a res.partner.bank record - """ - return bank_type_obj.format_layout % bank_obj._data[bank_obj.id] + # prepare a mapping {code: format_layout} for all bank types + bank_type_obj = self.pool.get('res.partner.bank.type') + bank_types = bank_type_obj.browse(cr, uid, bank_type_obj.search(cr, uid, []), context=context) + bank_code_format = dict((bt.code, bt.format_layout) for bt in bank_types) + + res = [] + for data in bank_dicts: + name = data['acc_number'] + if data['state'] and bank_code_format.get(data['state']): + try: + if not data.get('bank_name'): + data['bank_name'] = _('BANK') + name = bank_code_format[data['state']] % data + except Exception: + raise osv.except_osv(_("Formating Error"), _("Invalid Bank Account Type Name format.")) + res.append((data.get('id', False), name)) + return res def name_get(self, cr, uid, ids, context=None): if not len(ids): return [] - bank_type_obj = self.pool.get('res.partner.bank.type') - res = [] - for val in self.browse(cr, uid, ids, context=context): - result = val.acc_number - if val.state: - type_ids = bank_type_obj.search(cr, uid, [('code','=',val.state)]) - if type_ids: - t = bank_type_obj.browse(cr, uid, type_ids[0], context=context) - try: - # avoid the default format_layout to result in "False: ..." - if not val._data[val.id]['bank_name']: - val._data[val.id]['bank_name'] = _('BANK') - result = self._prepare_name_get(cr, uid, t, val, context=context) - except Exception: - raise osv.except_osv(_("Formating Error"), _("Invalid Bank Account Type Name format.")) - res.append((val.id, result)) - return res + bank_dicts = self.read(cr, uid, ids, context=context) + return self._prepare_name_get(cr, uid, bank_dicts, context=context) def onchange_company_id(self, cr, uid, ids, company_id, context=None): result = {} diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 83b24b55a93..b27476b2c92 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -111,8 +111,8 @@ class res_company(osv.osv): 'rml_header1': fields.char('Company Slogan', size=200, help="Appears by default on the top right corner of your printed documents (report header)."), 'rml_header2': fields.text('RML Internal Header', required=True), 'rml_header3': fields.text('RML Internal Header for Landscape Reports', required=True), - 'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports. Automatically set based on company details, "\ - "but may also be customized by directly editing it."), + 'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports."), + 'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True), 'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually. Otherwise it will be filled in automatically."), 'logo': fields.related('partner_id', 'image', string="Logo", type="binary"), 'currency_id': fields.many2one('res.currency', 'Currency', required=True), @@ -138,36 +138,28 @@ class res_company(osv.osv): ('name_uniq', 'unique (name)', 'The company name must be unique !') ] - def onchange_footer(self, cr, uid, ids, context=None): - # when touched, the footer becomes custom - return {'value': {'custom_footer': True}} + def onchange_footer(self, cr, uid, ids, custom_footer, phone, fax, email, website, vat, company_registry, bank_ids, context=None): + if custom_footer: + return {} - def set_auto_footer(self, cr, uid, ids, context=None): - # unset the flag 'custom_footer'; this will automatically compute the footer - return self.write(cr, uid, ids, {'custom_footer': False}, context=context) - - def compute_footer(self, cr, uid, ids, context=None): + # first line (notice that missing elements are filtered out before the join) + res = ' | '.join(filter(bool, [ + phone and '%s: %s' % (_('Phone'), phone), + fax and '%s: %s' % (_('Fax'), fax), + email and '%s: %s' % (_('Email'), email), + website and '%s: %s' % (_('Website'), website), + vat and '%s: %s' % (_('TIN'), vat), + company_registry and '%s: %s' % (_('Reg'), company_registry), + ])) + # second line: bank accounts res_partner_bank = self.pool.get('res.partner.bank') - for company in self.browse(cr, uid, ids, context): - if not company.custom_footer: - # first line (notice that missing elements are filtered out before the join) - res = ' | '.join(filter(bool, [ - company.phone and '%s: %s' % (_('Phone'), company.phone), - company.fax and '%s: %s' % (_('Fax'), company.fax), - company.email and '%s: %s' % (_('Email'), company.email), - company.website and '%s: %s' % (_('Website'), company.website), - company.vat and '%s: %s' % (_('TIN'), company.vat), - company.company_registry and '%s: %s' % (_('Reg'), company.company_registry), - ])) - # second line: bank accounts - account_ids = [acc.id for acc in company.bank_ids if acc.footer] - account_names = res_partner_bank.name_get(cr, uid, account_ids, context=context) - if account_names: - title = _('Bank Accounts') if len(account_names) > 1 else _('Bank Account') - res += '\n%s: %s' % (title, ', '.join(name for id, name in account_names)) - # update footer - self.write(cr, uid, [company.id], {'rml_footer': res}, context=context) - return True + account_data = self.resolve_2many_commands(cr, uid, 'bank_ids', bank_ids, context=context) + account_names = res_partner_bank._prepare_name_get(cr, uid, account_data, context=context) + if account_names: + title = _('Bank Accounts') if len(account_names) > 1 else _('Bank Account') + res += '\n%s: %s' % (title, ', '.join(name for id, name in account_names)) + + return {'value': {'rml_footer': res, 'rml_footer_readonly': res}} def on_change_country(self, cr, uid, ids, country_id, context=None): currency_id = self._get_euro(cr, uid, context=context) @@ -248,17 +240,11 @@ class res_company(osv.osv): self.cache_restart(cr) company_id = super(res_company, self).create(cr, uid, vals, context=context) obj_partner.write(cr, uid, partner_id, {'company_id': company_id}, context=context) - self.compute_footer(cr, uid, [company_id], context=context) return company_id def write(self, cr, uid, ids, values, context=None): self.cache_restart(cr) - if isinstance(ids, (int, long)): - ids = [ids] - super(res_company, self).write(cr, uid, ids, values, context=context) - if 'rml_footer' not in values: - self.compute_footer(cr, uid, ids, context=context) - return True + return super(res_company, self).write(cr, uid, ids, values, context=context) def _get_euro(self, cr, uid, context=None): rate_obj = self.pool.get('res.currency.rate') diff --git a/openerp/addons/base/res/res_company_view.xml b/openerp/addons/base/res/res_company_view.xml index b92cfba19b6..cac53b7a76a 100644 --- a/openerp/addons/base/res/res_company_view.xml +++ b/openerp/addons/base/res/res_company_view.xml @@ -55,29 +55,26 @@
- + - - - - - + + + + + - + - - diff --git a/openerp/addons/base/country_data.xml b/openerp/addons/base/res/res_country_data.xml similarity index 99% rename from openerp/addons/base/country_data.xml rename to openerp/addons/base/res/res_country_data.xml index d4d880cb8ed..068850727e8 100644 --- a/openerp/addons/base/country_data.xml +++ b/openerp/addons/base/res/res_country_data.xml @@ -1,7 +1,7 @@ - + + diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py index 07b220a6ee3..2b135a6f34a 100644 --- a/openerp/addons/base/res/res_lang.py +++ b/openerp/addons/base/res/res_lang.py @@ -77,7 +77,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/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 52200c3fb02..008e8048a5d 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -28,6 +28,48 @@ from tools.translate import _ import logging import pooler import pytz +from lxml import etree + +class format_address(object): + def fields_view_get_address(self, cr, uid, arch, context={}): + user_obj = self.pool.get('res.users') + fmt = user_obj.browse(cr, uid, uid,context).company_id.country_id + fmt = fmt and fmt.address_format + layouts = { + '%(city)s %(state_code)s\n%(zip)s': """ +
+ + +
+ +
+ """, + '%(zip)s %(city)s': """ +
+ + +
+ +
+ """, + '%(city)s\n%(state_name)s\n%(zip)s': """ +
+ + + +
+ """ + } + for k,v in layouts.items(): + if fmt and (k in fmt): + doc = etree.fromstring(arch) + for node in doc.xpath("//div[@class='address_format']"): + tree = etree.fromstring(v) + node.getparent().replace(node, tree) + arch = etree.tostring(doc) + break + return arch + def _tz_get(self,cr,uid, context=None): return [(x, x) for x in pytz.all_timezones] @@ -119,7 +161,7 @@ def _lang_get(self, cr, uid, context=None): POSTAL_ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id') ADDRESS_FIELDS = POSTAL_ADDRESS_FIELDS + ('email', 'phone', 'fax', 'mobile', 'website', 'ref', 'lang') -class res_partner(osv.osv): +class res_partner(osv.osv, format_address): _description = 'Partner' _name = "res.partner" @@ -143,7 +185,7 @@ class res_partner(osv.osv): 'name': fields.char('Name', size=128, required=True, select=True), 'date': fields.date('Date', select=1), 'title': fields.many2one('res.partner.title', 'Title'), - 'parent_id': fields.many2one('res.partner', 'Owned by'), + 'parent_id': fields.many2one('res.partner', 'Company'), 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'), 'ref': fields.char('Reference', size=64, select=1), 'lang': fields.selection(_lang_get, 'Language', @@ -226,9 +268,10 @@ class res_partner(osv.osv): def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): if (not view_id) and (view_type=='form') and context and context.get('force_email', False): view_id = self.pool.get('ir.model.data').get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1] - - return super(res_partner, self).fields_view_get(cr, user, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) - + res = super(res_partner,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu) + if view_type == 'form': + res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context) + return res _defaults = { 'active': True, diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 18b5fd76a49..906232c86ab 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -96,8 +96,18 @@
+
+
+

+ +

+ - @@ -112,6 +122,7 @@ res.partner.form res.partner + diff --git a/openerp/addons/base/static/src/css/modules.css b/openerp/addons/base/static/src/css/modules.css index d13f932e4f1..ec98eacfcc7 100644 --- a/openerp/addons/base/static/src/css/modules.css +++ b/openerp/addons/base/static/src/css/modules.css @@ -1,5 +1,5 @@ .oe_module_vignette { - padding: 8px; + padding: 4px; } .oe_module_icon, .oe_module_desc { display: inline-block; diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index d81833b17a6..48689c3c26e 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) ) @@ -3412,7 +3412,8 @@ class BaseModel(object): if context is None: context = {} - write_access = self.check_access_rights(cr, user, 'write') or self.check_access_rights(cr, user, 'create') + write_access = self.check_access_rights(cr, user, 'write', raise_exception=False) \ + or self.check_access_rights(cr, user, 'create', raise_exception=False) res = {} @@ -3431,24 +3432,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 @@ -4273,9 +4275,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) diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 5bc4eb7b9aa..1eebac9a7a0 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -18,7 +18,8 @@ # along with this program. If not, see . # ############################################################################## - +from __future__ import with_statement +import contextlib import base64 import locale import logging @@ -98,8 +99,6 @@ class db(netsvc.ExportService): self.id = 0 self.id_protect = threading.Semaphore() - self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var - def dispatch(self, method, params): if method in [ 'create', 'get_progress', 'drop', 'dump', 'restore', 'rename', @@ -118,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: @@ -179,7 +178,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: @@ -205,23 +204,28 @@ class db(netsvc.ExportService): cr.close() return True + @contextlib.contextmanager + def _set_pg_password_in_environment(self): + """ On Win32, pg_dump (and pg_restore) require that + :envvar:`PGPASSWORD` be set - def _set_pg_psw_env_var(self): - # see http://www.postgresql.org/docs/8.4/static/libpq-envars.html - # FIXME: This is not thread-safe, and should never be enabled for - # SaaS (giving SaaS users the super-admin password is not a good idea - # anyway) - if tools.config['db_password'] and not os.environ.get('PGPASSWORD', ''): + This context management method handles setting + :envvar:`PGPASSWORD` iif win32 and the envvar is not already + set, and removing it afterwards. + """ + if os.name != 'nt' or os.environ.get('PGPASSWORD'): + yield + else: os.environ['PGPASSWORD'] = tools.config['db_password'] - self._pg_psw_env_var_is_set = True + try: + yield + finally: + del os.environ['PGPASSWORD'] - def _unset_pg_psw_env_var(self): - if self._pg_psw_env_var_is_set: - os.environ['PGPASSWORD'] = '' def exp_dump(self, db_name): - try: - self._set_pg_psw_env_var() + logger = logging.getLogger('openerp.service.web_services.db.dump') + with self._set_pg_password_in_environment(): cmd = ['pg_dump', '--format=c', '--no-owner'] if tools.config['db_user']: cmd.append('--username=' + tools.config['db_user']) @@ -237,23 +241,20 @@ class db(netsvc.ExportService): res = stdout.close() if not data or res: - _logger.error( + 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) raise Exception, "Couldn't dump database" - _logger.info('DUMP DB successful: %s', db_name) + logger.info('DUMP DB successful: %s', db_name) return base64.encodestring(data) - finally: - self._unset_pg_psw_env_var() def exp_restore(self, db_name, data): - try: - self._set_pg_psw_env_var() - + logger = logging.getLogger('openerp.service.web_services.db.restore') + with self._set_pg_password_in_environment(): 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) @@ -282,17 +283,15 @@ 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: - self._unset_pg_psw_env_var() def exp_rename(self, old_name, new_name): 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: @@ -320,7 +319,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: @@ -557,7 +556,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/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 03507ee7012..9aff3704f8b 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: diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 3a4329433eb..ce157c5e697 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) diff --git a/openerp/tools/image.py b/openerp/tools/image.py index f673906f328..38997978326 100644 --- a/openerp/tools/image.py +++ b/openerp/tools/image.py @@ -66,8 +66,9 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file # check image size: do not create a thumbnail if avoiding smaller images if avoid_if_small and image.size[0] <= size[0] and image.size[1] <= size[1]: return base64_source - # create a thumbnail: will resize and keep ratios + # create a thumbnail: will resize and keep ratios, then sharpen for better looking result image.thumbnail(size, Image.ANTIALIAS) + image.convert('RGB') image = image.filter(ImageFilter.SHARPEN) # create a transparent image for background background = Image.new('RGBA', size, (255, 255, 255, 0)) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 2858a7e1f23..27b81489b55 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -142,6 +142,8 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): adps = addons.module.ad_paths rtp = os.path.normcase(os.path.abspath(config['root_path'])) + basename = name + if os.path.isabs(name): # It is an absolute path # Is it below 'addons_path' or 'root_path'? @@ -154,7 +156,7 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): else: # It is outside the OpenERP root: skip zipfile lookup. base, name = os.path.split(name) - return _fileopen(name, mode=mode, basedir=base, pathinfo=pathinfo) + return _fileopen(name, mode=mode, basedir=base, pathinfo=pathinfo, basename=basename) if name.replace(os.sep, '/').startswith('addons/'): subdir = 'addons' @@ -172,16 +174,19 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): for adp in adps: try: return _fileopen(name2, mode=mode, basedir=adp, - pathinfo=pathinfo) + pathinfo=pathinfo, basename=basename) except IOError: pass # Second, try to locate in root_path - return _fileopen(name, mode=mode, basedir=rtp, pathinfo=pathinfo) + return _fileopen(name, mode=mode, basedir=rtp, pathinfo=pathinfo, basename=basename) -def _fileopen(path, mode, basedir, pathinfo): +def _fileopen(path, mode, basedir, pathinfo, basename=None): name = os.path.normpath(os.path.join(basedir, path)) + + if basename is None: + basename = name # Give higher priority to module directories, which is # a more common case than zipped modules. if os.path.isfile(name): @@ -220,8 +225,8 @@ def _fileopen(path, mode, basedir, pathinfo): pass # Not found if name.endswith('.rml'): - raise IOError('Report %r doesn\'t exist or deleted' % name) - raise IOError('File not found: %s' % name) + raise IOError('Report %r doesn\'t exist or deleted' % basename) + raise IOError('File not found: %s' % basename) #---------------------------------------------------------- @@ -601,10 +606,7 @@ 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={ +ALL_LANGUAGES = { 'ab_RU': u'Abkhazian / аҧсуа', 'ar_AR': u'Arabic / الْعَرَبيّة', 'bg_BG': u'Bulgarian / български език', @@ -685,15 +687,14 @@ def get_languages(): 'th_TH': u'Thai / ภาษาไทย', 'tlh_TLH': u'Klingon', } - return languages def scan_languages(): - # Now it will take all languages from get languages function without filter it with base module languages - lang_dict = get_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):