[MERGE]:trunk
bzr revid: apa@tinyerp.com-20120914053836-rt02ojybaaeirlr5
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -62,8 +62,6 @@
|
||||
<field name="name">Your Company</field>
|
||||
<field name="partner_id" ref="main_partner"/>
|
||||
<field name="rml_header1">Your Company Slogan</field>
|
||||
<field name="rml_footer1">Web: http://www.yourcompany.com - Tel: +33 1 49 51 23 94</field>
|
||||
<field name="rml_footer2">Bank Accounts... to be configured in menu Settings > Accounting/Invoicing.</field>
|
||||
<field name="currency_id" ref="base.EUR"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -55,29 +55,26 @@
|
||||
<div>
|
||||
<field name="rml_header1" placeholder="e.g. Global Business Solutions"/>
|
||||
</div>
|
||||
<field name="website" widget="url" placeholder="e.g. www.openerp.com"/>
|
||||
<field name="website" widget="url" placeholder="e.g. www.openerp.com"
|
||||
on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="phone"/>
|
||||
<field name="fax"/>
|
||||
<field name="email"/>
|
||||
<field name="vat"/>
|
||||
<field name="company_registry"/>
|
||||
<field name="phone" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="fax" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="email" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="vat" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="company_registry" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Bank Accounts">
|
||||
<field name="bank_ids" nolabel="1"
|
||||
context="{'default_company_id': active_id, 'footer_hide': False}"/>
|
||||
<field name="bank_ids" nolabel="1" context="{'default_company_id': active_id, 'footer_hide': False}"
|
||||
on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
</group>
|
||||
<group string="Report Footer Configuration">
|
||||
<field name="paper_format" on_change="onchange_paper_format(paper_format)"/>
|
||||
<field name="custom_footer" invisible="1"/>
|
||||
<label for="rml_footer"/>
|
||||
<div>
|
||||
<field name="rml_footer" on_change="onchange_footer()"/>
|
||||
<button string="Set Automatic Footer" type="object" name="set_auto_footer"
|
||||
attrs="{'invisible': [('custom_footer','=',False)]}" class="oe_edit_only"/>
|
||||
</div>
|
||||
<field name="custom_footer" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="rml_footer" attrs="{'invisible': [('custom_footer','=',False)]}"/>
|
||||
<field name="rml_footer_readonly" attrs="{'invisible': [('custom_footer','=',True)]}"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Header/Footer" groups="base.group_no_one">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
<record id="ad" model="res.country">
|
||||
<field name="name">Andorra, Principality of</field>
|
||||
<field name="code">ad</field>
|
||||
@@ -106,7 +106,7 @@
|
||||
<record id="be" model="res.country">
|
||||
<field name="name">Belgium</field>
|
||||
<field name="code">be</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="currency_id" ref="EUR"/>
|
||||
</record>
|
||||
<record id="bf" model="res.country">
|
||||
@@ -386,7 +386,7 @@
|
||||
<record id="fr" model="res.country">
|
||||
<field name="name">France</field>
|
||||
<field name="code">fr</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="currency_id" ref="EUR"/>
|
||||
</record>
|
||||
<record id="ga" model="res.country">
|
||||
@@ -532,7 +532,7 @@
|
||||
<record id="in" model="res.country">
|
||||
<field name="name">India</field>
|
||||
<field name="code">in</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(zip)s\n%(state_name)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(zip)s\n%(state_name)s\n%(country_name)s'" />
|
||||
<field name="currency_id" ref="INR"/>
|
||||
</record>
|
||||
<record id="io" model="res.country">
|
||||
@@ -838,7 +838,7 @@
|
||||
<record id="nl" model="res.country">
|
||||
<field name="name">Netherlands</field>
|
||||
<field name="code">nl</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
|
||||
<field name="currency_id" ref="EUR"/>
|
||||
</record>
|
||||
<record id="no" model="res.country">
|
||||
@@ -1174,7 +1174,7 @@
|
||||
</record>
|
||||
<record id="uk" model="res.country">
|
||||
<field name="name">United Kingdom</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s\n%(state_name)s\n%(zip)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s\n%(state_name)s\n%(zip)s\n%(country_name)s'" />
|
||||
<field name="code">gb</field>
|
||||
<field name="currency_id" ref="GBP"/>
|
||||
</record>
|
||||
@@ -1186,7 +1186,7 @@
|
||||
<record id="us" model="res.country">
|
||||
<field name="name">United States</field>
|
||||
<field name="code">us</field>
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s'" />
|
||||
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s'" />
|
||||
<field name="currency_id" ref="USD"/>
|
||||
</record>
|
||||
<record id="uy" model="res.country">
|
||||
@@ -1281,5 +1281,5 @@
|
||||
<field name="code">zw</field>
|
||||
<field name="currency_id" ref="ZWD"/>
|
||||
</record>
|
||||
</data>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -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):
|
||||
|
||||
@@ -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': """
|
||||
<div class="address_format">
|
||||
<field name="city" placeholder="City" style="width: 50%%"/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 47%%" options='{"no_open": true}'/>
|
||||
<br/>
|
||||
<field name="zip" placeholder="ZIP"/>
|
||||
</div>
|
||||
""",
|
||||
'%(zip)s %(city)s': """
|
||||
<div class="address_format">
|
||||
<field name="zip" placeholder="ZIP" style="width: 40%%"/>
|
||||
<field name="city" placeholder="City" style="width: 57%%"/>
|
||||
<br/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" options='{"no_open": true}'/>
|
||||
</div>
|
||||
""",
|
||||
'%(city)s\n%(state_name)s\n%(zip)s': """
|
||||
<div class="address_format">
|
||||
<field name="city" placeholder="City"/>
|
||||
<field name="state_id" class="oe_no_button" placeholder="State" options='{"no_open": true}'/>
|
||||
<field name="zip" placeholder="ZIP"/>
|
||||
</div>
|
||||
"""
|
||||
}
|
||||
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,
|
||||
|
||||
@@ -96,8 +96,18 @@
|
||||
<form string="Contact" version="7.0">
|
||||
<field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/>
|
||||
<div class="oe_title">
|
||||
<div class="oe_edit_only">
|
||||
<label for="name"/> (
|
||||
<field name="is_company" on_change="onchange_type(is_company)" class="oe_inline"/> <label for="is_company" string="Is a Company?"/>)
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" default_focus="1" placeholder="Name" />
|
||||
</h1>
|
||||
<field name="parent_id"
|
||||
placeholder="Company"
|
||||
domain="[('is_company', '=', True)]" context="{'default_is_company': True}"
|
||||
attrs="{'invisible': [('is_company','=', True)]}"/>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="category_id" widget="many2many_tags" placeholder="Tags..."/>
|
||||
<field name="function" placeholder="e.g. Sales Director"/>
|
||||
<field name="email" required="context.get('force_email', False)"/>
|
||||
@@ -112,6 +122,7 @@
|
||||
<record id="view_partner_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.form</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field eval="1" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Partners" version="7.0">
|
||||
<sheet>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.oe_module_vignette {
|
||||
padding: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
.oe_module_icon, .oe_module_desc {
|
||||
display: inline-block;
|
||||
|
||||
+26
-24
@@ -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)
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
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 <PASSWD> 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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
+17
-16
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user