commit
700d229760
|
@ -16,6 +16,7 @@ Depends:
|
|||
python,
|
||||
postgresql-client,
|
||||
python-dateutil,
|
||||
python-docutils,
|
||||
python-feedparser,
|
||||
python-gdata,
|
||||
python-ldap,
|
||||
|
|
|
@ -30,7 +30,6 @@ GNU Public Licence.
|
|||
(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
|
||||
"""
|
||||
|
||||
import imp
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
|
|
|
@ -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-07 04:55+0000\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-08 04:54+0000\n"
|
||||
"X-Generator: Launchpad (build 15914)\n"
|
||||
|
||||
#. module: base
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:44+0000\n"
|
||||
"PO-Revision-Date: 2012-08-20 15:45+0000\n"
|
||||
"Last-Translator: OpenERP Administrators <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-09-10 14:37+0000\n"
|
||||
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\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-09-05 04:43+0000\n"
|
||||
"X-Generator: Launchpad (build 15901)\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-11 04:50+0000\n"
|
||||
"X-Generator: Launchpad (build 15924)\n"
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.sh
|
||||
|
@ -604,7 +604,7 @@ msgstr "Испанский (VE) / Español (VE)"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_hr_timesheet_invoice
|
||||
msgid "Invoice on Timesheets"
|
||||
msgstr ""
|
||||
msgstr "Счет по затратам времени"
|
||||
|
||||
#. module: base
|
||||
#: view:base.module.upgrade:0
|
||||
|
@ -1269,7 +1269,7 @@ msgstr "Порт SMTP"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_import_sugarcrm
|
||||
msgid "SugarCRM Import"
|
||||
msgstr ""
|
||||
msgstr "Импорт SugarCRM"
|
||||
|
||||
#. module: base
|
||||
#: view:res.lang:0
|
||||
|
@ -1374,7 +1374,7 @@ msgstr "Система управления документами"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_crm_claim
|
||||
msgid "Claims Management"
|
||||
msgstr ""
|
||||
msgstr "Управление претензиями"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.ui.menu,name:base.menu_purchase_root
|
||||
|
@ -1749,6 +1749,12 @@ msgid ""
|
|||
" Apply Different Category for the product.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Базовый модуль управления ланчами\n"
|
||||
"\n"
|
||||
" Отслеживание заказов, движения средств, кассы, продукции.\n"
|
||||
" Возможность разнесения продукции по категориям.\n"
|
||||
" "
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.kg
|
||||
|
@ -1862,7 +1868,7 @@ msgstr ""
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_html_view
|
||||
msgid "Html View"
|
||||
msgstr ""
|
||||
msgstr "Просмотр HTML"
|
||||
|
||||
#. module: base
|
||||
#: field:res.currency,position:0
|
||||
|
@ -2533,7 +2539,7 @@ msgstr "Идеи"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_sale_crm
|
||||
msgid "Opportunity to Quotation"
|
||||
msgstr ""
|
||||
msgstr "Предложение в Запрос цен"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.module,description:base.module_sale_analytic_plans
|
||||
|
@ -2767,7 +2773,7 @@ msgstr "Словения"
|
|||
#. module: base
|
||||
#: help:res.currency,name:0
|
||||
msgid "Currency Code (ISO 4217)"
|
||||
msgstr ""
|
||||
msgstr "Код валюты (ISO 4217)"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.actions.act_window,name:base.res_log_act_window
|
||||
|
@ -3267,7 +3273,7 @@ msgstr "Режим SMTP-over-SSL недоступен"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_survey
|
||||
msgid "Survey"
|
||||
msgstr ""
|
||||
msgstr "Опрос"
|
||||
|
||||
#. module: base
|
||||
#: view:base.language.import:0
|
||||
|
@ -3315,7 +3321,7 @@ msgstr "Уругвай"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_fetchmail_crm
|
||||
msgid "eMail Gateway for Leads"
|
||||
msgstr ""
|
||||
msgstr "Шлюз эл.почты для кандидатов"
|
||||
|
||||
#. module: base
|
||||
#: selection:base.language.install,lang:0
|
||||
|
@ -3530,7 +3536,7 @@ msgstr ""
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_report_webkit
|
||||
msgid "Webkit Report Engine"
|
||||
msgstr ""
|
||||
msgstr "Инструмент создания отчетов Webkit"
|
||||
|
||||
#. module: base
|
||||
#: selection:publisher_warranty.contract,state:0
|
||||
|
@ -3557,7 +3563,7 @@ msgstr "Майотта"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_crm_todo
|
||||
msgid "Tasks on CRM"
|
||||
msgstr ""
|
||||
msgstr "Задачи по CRM"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_generic_modules_accounting
|
||||
|
@ -3683,12 +3689,12 @@ msgstr "Обнаружена рекурсия."
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_report_webkit_sample
|
||||
msgid "Webkit Report Samples"
|
||||
msgstr ""
|
||||
msgstr "Примеры отчетов Webkit"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_point_of_sale
|
||||
msgid "Point Of Sale"
|
||||
msgstr ""
|
||||
msgstr "Точка продажи"
|
||||
|
||||
#. module: base
|
||||
#: code:addons/base/module/module.py:302
|
||||
|
@ -3812,7 +3818,7 @@ msgstr "Проверка кода Ean"
|
|||
#. module: base
|
||||
#: field:res.partner,vat:0
|
||||
msgid "VAT"
|
||||
msgstr "ИНН"
|
||||
msgstr "НДС"
|
||||
|
||||
#. module: base
|
||||
#: field:res.users,new_password:0
|
||||
|
@ -3945,7 +3951,7 @@ msgstr "Поддержка iCal"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_fetchmail
|
||||
msgid "Email Gateway"
|
||||
msgstr ""
|
||||
msgstr "Шлюз эл.почты"
|
||||
|
||||
#. module: base
|
||||
#: code:addons/base/ir/ir_mail_server.py:439
|
||||
|
@ -4069,7 +4075,7 @@ msgstr "Португалия"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_share
|
||||
msgid "Share any Document"
|
||||
msgstr ""
|
||||
msgstr "Совместный доступ r любым документам"
|
||||
|
||||
#. module: base
|
||||
#: field:ir.module.module,certificate:0
|
||||
|
@ -4407,7 +4413,7 @@ msgstr "Код должен быть уникальным"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_hr_expense
|
||||
msgid "Expenses Management"
|
||||
msgstr ""
|
||||
msgstr "Управление расходами"
|
||||
|
||||
#. module: base
|
||||
#: view:workflow.activity:0
|
||||
|
@ -4418,7 +4424,7 @@ msgstr "Входящие переходы"
|
|||
#. module: base
|
||||
#: field:ir.values,value_unpickle:0
|
||||
msgid "Default value or action reference"
|
||||
msgstr ""
|
||||
msgstr "Значение по умолчанию или ссылка на действие"
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.sr
|
||||
|
@ -4558,7 +4564,7 @@ msgstr "Экваториальная Гвинея"
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_warning
|
||||
msgid "Warning Messages and Alerts"
|
||||
msgstr ""
|
||||
msgstr "Предупреждающие сообщения и оповещения"
|
||||
|
||||
#. module: base
|
||||
#: view:base.module.import:0
|
||||
|
@ -4870,7 +4876,7 @@ msgstr "Договор уже зарегистрирован в системе."
|
|||
#: model:ir.actions.act_window,name:base.action_res_partner_bank_type_form
|
||||
#: model:ir.ui.menu,name:base.menu_action_res_partner_bank_typeform
|
||||
msgid "Bank Account Types"
|
||||
msgstr ""
|
||||
msgstr "Типы банковского счета"
|
||||
|
||||
#. module: base
|
||||
#: help:ir.sequence,suffix:0
|
||||
|
@ -4880,7 +4886,7 @@ msgstr "Суффикс записи для нумерации"
|
|||
#. module: base
|
||||
#: help:ir.mail_server,smtp_user:0
|
||||
msgid "Optional username for SMTP authentication"
|
||||
msgstr ""
|
||||
msgstr "Необязательное имя пользователя для аутентификации SMTP"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.model,name:base.model_ir_actions_actions
|
||||
|
@ -4935,7 +4941,7 @@ msgstr ""
|
|||
#. module: base
|
||||
#: model:ir.module.module,shortdesc:base.module_web_chat
|
||||
msgid "Web Chat"
|
||||
msgstr ""
|
||||
msgstr "Веб-чат"
|
||||
|
||||
#. module: base
|
||||
#: field:res.company,rml_footer2:0
|
||||
|
@ -4966,7 +4972,7 @@ msgstr "Права доступа"
|
|||
#: code:addons/base/ir/ir_model.py:311
|
||||
#, python-format
|
||||
msgid "Changing the storing system for field \"%s\" is not allowed."
|
||||
msgstr ""
|
||||
msgstr "Изменение системы хранения для поля \"%s\" не допускается."
|
||||
|
||||
#. module: base
|
||||
#: help:res.partner.bank,company_id:0
|
||||
|
|
|
@ -28,6 +28,7 @@ import re
|
|||
import shutil
|
||||
import tempfile
|
||||
import urllib
|
||||
import urllib2
|
||||
import zipfile
|
||||
import zipimport
|
||||
|
||||
|
@ -36,8 +37,6 @@ try:
|
|||
except ImportError:
|
||||
from StringIO import StringIO # NOQA
|
||||
|
||||
import requests
|
||||
|
||||
import openerp
|
||||
from openerp import modules, pooler, release, tools, addons
|
||||
from openerp.tools.parse_version import parse_version
|
||||
|
@ -630,13 +629,12 @@ class module(osv.osv):
|
|||
try:
|
||||
for module_name in urls:
|
||||
try:
|
||||
r = requests.get(urls[module_name])
|
||||
r.raise_for_status()
|
||||
except requests.HTTPError, e:
|
||||
content = urllib2.urlopen(urls[module_name]).read()
|
||||
except Exception, e:
|
||||
_logger.exception('ggr')
|
||||
raise osv.except_osv('grrr', e)
|
||||
else:
|
||||
zipfile.ZipFile(StringIO(r.content)).extractall(tmp)
|
||||
zipfile.ZipFile(StringIO(content)).extractall(tmp)
|
||||
assert os.path.isdir(os.path.join(tmp, module_name))
|
||||
|
||||
for module_name in urls:
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
<corporate-header>
|
||||
<corporation type="zoom" name="company_id">
|
||||
<rml_header1 type="field" name="rml_header1"/>
|
||||
<rml_footer1 type="field" name="rml_footer1"/>
|
||||
<rml_footer2 type="field" name="rml_footer2"/>
|
||||
<rml_footer type="field" name="rml_footer"/>
|
||||
<title type="field" name="partner_id.title"/>
|
||||
<name type="field" name="partner_id.name"/>
|
||||
<street type="field" name="street"/>
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
<!--page bottom-->
|
||||
|
||||
<lines>1.5cm 2.2cm 19.9cm 2.2cm</lines>
|
||||
<drawCentredString x="10.5cm" y="1.7cm"><xsl:value-of select="//corporate-header/corporation/rml_footer1"/></drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="1.25cm"><xsl:value-of select="//corporate-header/corporation/rml_footer2"/></drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="1.7cm"><xsl:value-of select="//corporate-header/corporation/rml_footer"/></drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="0.8cm">Your contact : <xsl:value-of select="//corporate-header/user/name"/></drawCentredString>
|
||||
|
||||
</xsl:template>
|
||||
|
@ -73,8 +72,7 @@
|
|||
<!--page bottom-->
|
||||
|
||||
<lines>1.5cm 1.2cm 19.9cm 1.2cm</lines>
|
||||
<drawCentredString x="10.5cm" y="1.7cm"><xsl:value-of select="//corporate-header/corporation/rml_footer1"/></drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="1.25cm"><xsl:value-of select="//corporate-header/corporation/rml_footer2"/></drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="1.7cm"><xsl:value-of select="//corporate-header/corporation/rml_footer"/></drawCentredString>
|
||||
<!-- <drawCentredString x="10.5cm" y="0.8cm">Your contact : <xsl:value-of select="//corporate-header/user/name"/></drawCentredString>-->
|
||||
</xsl:template>
|
||||
|
||||
|
|
|
@ -233,8 +233,7 @@
|
|||
<table:table-column table:style-name="Table1.A"/>
|
||||
<table:table-row>
|
||||
<table:table-cell table:style-name="Table1.A1" table:value-type="string">
|
||||
<text:p text:style-name="P7">[[ company.rml_footer1 ]]</text:p>
|
||||
<text:p text:style-name="P7">[[ company.rml_footer2 ]]</text:p>
|
||||
<text:p text:style-name="P7">[[ company.rml_footer ]]</text:p>
|
||||
<text:p text:style-name="P7">Contact : [[ user.name ]]</text:p>
|
||||
</table:table-cell>
|
||||
</table:table-row>
|
||||
|
|
|
@ -7,15 +7,8 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
% if company['rml_footer1']:
|
||||
<p align = "center"><small><b>${company.rml_footer1}</b></small></br></p>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
% if company['rml_footer2']:
|
||||
<p align = "center"><small><b>${company.rml_footer2}</b></small></br></p>
|
||||
% if company['rml_footer']:
|
||||
<p align="center"><small><b>${company.rml_footer}</b></small></p>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -109,7 +109,7 @@ class res_partner_bank(osv.osv):
|
|||
if not context.get('address'):
|
||||
return value
|
||||
|
||||
for address in self.pool.get('res.partner').resolve_o2m_commands_to_record_dicts(
|
||||
for address in self.pool.get('res.partner').resolve_2many_commands(
|
||||
cursor, user, 'address', context['address'], ['type', field], context=context):
|
||||
|
||||
if address.get('type') == 'default':
|
||||
|
|
|
@ -91,8 +91,9 @@
|
|||
<group col="4">
|
||||
<field name="state"/>
|
||||
<field name="acc_number"/>
|
||||
<field name="company_id" on_change="onchange_company_id(company_id)" invisible="context.get('company_hide', True)" widget="selection"/>
|
||||
<field name="footer" attrs="{'invisible': [('company_id','=',False)]}"/>
|
||||
<field name="company_id" on_change="onchange_company_id(company_id)"
|
||||
invisible="context.get('company_hide', True)" widget="selection"/>
|
||||
<field name="footer" invisible="context.get('footer_hide', True)"/>
|
||||
</group>
|
||||
<group>
|
||||
<group name="owner" string="Bank Account Owner">
|
||||
|
@ -128,7 +129,7 @@
|
|||
<field name="acc_number"/>
|
||||
<field name="bank_name"/>
|
||||
<field name="company_id" invisible="context.get('company_hide', True)"/>
|
||||
<field name="footer" invisible="context.get('company_hide', True)"/>
|
||||
<field name="footer" invisible="context.get('footer_hide', True)"/>
|
||||
<field name="partner_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
|
|
@ -89,7 +89,6 @@ class res_company(osv.osv):
|
|||
result[company.id][field] = address[field] or False
|
||||
return result
|
||||
|
||||
|
||||
def _set_address_data(self, cr, uid, company_id, name, value, arg, context=None):
|
||||
""" Write the 'address' functional fields. """
|
||||
company = self.browse(cr, uid, company_id, context=context)
|
||||
|
@ -103,18 +102,18 @@ class res_company(osv.osv):
|
|||
part_obj.create(cr, uid, {name: value or False, 'parent_id': company.partner_id.id}, context=context)
|
||||
return True
|
||||
|
||||
|
||||
_columns = {
|
||||
'name': fields.related('partner_id', 'name', string='Company Name', size=128, required=True, store=True, type='char'),
|
||||
'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
|
||||
'child_ids': fields.one2many('res.company', 'parent_id', 'Child Companies'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner', required=True),
|
||||
'rml_header1': fields.char('Company Slogan', size=200, help="Appears by default on the top right corner of your printed documents (report header)."),
|
||||
'rml_footer1': fields.char('General Information Footer', size=200),
|
||||
'rml_footer2': fields.char('Bank Accounts Footer', size=250, help="Write here your bank accounts for customer payments."),
|
||||
'rml_header': fields.text('RML Header', required=True),
|
||||
'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."),
|
||||
'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),
|
||||
'currency_ids': fields.one2many('res.currency', 'company_id', 'Currency'),
|
||||
|
@ -138,15 +137,38 @@ class res_company(osv.osv):
|
|||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', 'The company name must be unique !')
|
||||
]
|
||||
def on_change_header(self, cr, uid, ids, phone, email, fax, website, vat, reg=False, context=None):
|
||||
val = []
|
||||
if phone: val.append(_('Phone: ')+phone)
|
||||
if fax: val.append(_('Fax: ')+fax)
|
||||
if website: val.append(_('Website: ')+website)
|
||||
if vat: val.append(_('TIN: ')+vat)
|
||||
if reg: val.append(_('Reg: ')+reg)
|
||||
return {'value': {'rml_footer1':' | '.join(val)}}
|
||||
|
||||
|
||||
def onchange_footer(self, cr, uid, ids, context=None):
|
||||
# when touched, the footer becomes custom
|
||||
return {'value': {'custom_footer': True}}
|
||||
|
||||
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):
|
||||
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
|
||||
|
||||
def on_change_country(self, cr, uid, ids, country_id, context=None):
|
||||
currency_id = self._get_euro(cr, uid, context=context)
|
||||
if country_id:
|
||||
|
@ -226,11 +248,17 @@ 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, *args, **argv):
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
self.cache_restart(cr)
|
||||
return super(res_company, self).write(cr, *args, **argv)
|
||||
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
|
||||
|
||||
def _get_euro(self, cr, uid, context=None):
|
||||
rate_obj = self.pool.get('res.currency.rate')
|
||||
|
@ -272,20 +300,22 @@ class res_company(osv.osv):
|
|||
return self._header_a4
|
||||
|
||||
_header_main = """
|
||||
<header>
|
||||
<header>
|
||||
<pageTemplate>
|
||||
<frame id="first" x1="1.3cm" y1="2.5cm" height="%s" width="19.0cm"/>
|
||||
<frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
|
||||
<stylesheet>
|
||||
<paraStyle name="main_footer" fontName="DejaVu Sans" fontSize="8.0" alignment="CENTER"/>
|
||||
</stylesheet>
|
||||
<pageGraphics>
|
||||
<!-- You Logo - Change X,Y,Width and Height -->
|
||||
<image x="1.3cm" y="%s" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
|
||||
<setFont name="DejaVu Sans" size="8"/>
|
||||
<fill color="black"/>
|
||||
<stroke color="black"/>
|
||||
|
||||
<!-- page header -->
|
||||
<lines>1.3cm %s 20cm %s</lines>
|
||||
|
||||
<drawRightString x="20cm" y="%s">[[ company.rml_header1 ]]</drawRightString>
|
||||
|
||||
|
||||
<drawString x="1.3cm" y="%s">[[ company.partner_id.name ]]</drawString>
|
||||
<drawString x="1.3cm" y="%s">[[ company.partner_id.street or '' ]]</drawString>
|
||||
<drawString x="1.3cm" y="%s">[[ company.partner_id.city or '' ]] - [[ company.partner_id.country_id and company.partner_id.country_id.name or '']]</drawString>
|
||||
|
@ -295,13 +325,19 @@ class res_company(osv.osv):
|
|||
<drawRightString x="7cm" y="%s">[[ company.partner_id.email or '' ]]</drawRightString>
|
||||
<lines>1.3cm %s 7cm %s</lines>
|
||||
|
||||
<!-- left margin -->
|
||||
<rotate degrees="90"/>
|
||||
<fill color="grey"/>
|
||||
<drawString x="2.65cm" y="-0.4cm">produced by OpenERP.com</drawString>
|
||||
<fill color="black"/>
|
||||
<rotate degrees="-90"/>
|
||||
|
||||
<!--page bottom-->
|
||||
|
||||
<lines>1.2cm 2.15cm 19.9cm 2.15cm</lines>
|
||||
|
||||
<drawCentredString x="10.5cm" y="1.7cm">[[ company.rml_footer1 ]]</drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="1.25cm">[[ company.rml_footer2 ]]</drawCentredString>
|
||||
<drawCentredString x="10.5cm" y="0.8cm">Contact : [[ user.name ]] - Page: <pageNumber/></drawCentredString>
|
||||
<lines>1.2cm 2.65cm 19.9cm 2.65cm</lines>
|
||||
<place x="1.3cm" y="0cm" height="2.55cm" width="19.0cm">
|
||||
<para style="main_footer">[[ company.rml_footer ]]</para>
|
||||
<para style="main_footer">Contact : [[ user.name ]] - Page: <pageNumber/></para>
|
||||
</place>
|
||||
</pageGraphics>
|
||||
</pageTemplate>
|
||||
</header>"""
|
||||
|
|
|
@ -31,19 +31,15 @@
|
|||
<h1>
|
||||
<field name="name" class="oe_inline"/>
|
||||
</h1>
|
||||
<label for="rml_header1" class="oe_edit_only"/>
|
||||
<div>
|
||||
<field name="rml_header1" placeholder="e.g. Global Business Solutions"/>
|
||||
</div>
|
||||
</div>
|
||||
<group col="4">
|
||||
<field name="partner_id" readonly="1" required="0" groups="base.group_no_one"/>
|
||||
<field name="parent_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="General Information">
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" readonly="1" required="0" groups="base.group_no_one"/>
|
||||
<label for="street" string="Address"/>
|
||||
<div>
|
||||
<field name="street" placeholder="Street..."/>
|
||||
|
@ -55,30 +51,36 @@
|
|||
</div>
|
||||
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}' on_change="on_change_country(country_id)"/>
|
||||
</div>
|
||||
<label for="rml_header1"/>
|
||||
<div>
|
||||
<field name="rml_header1" placeholder="e.g. Global Business Solutions"/>
|
||||
</div>
|
||||
<field name="website" widget="url" placeholder="e.g. www.openerp.com"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="phone" on_change="on_change_header(phone, email, fax, website, vat, company_registry)"/>
|
||||
<field name="fax" on_change="on_change_header(phone, email, fax, website, vat, company_registry)"/>
|
||||
<field name="email" on_change="on_change_header(phone, email, fax, website, vat, company_registry)"/>
|
||||
<field name="vat" on_change="on_change_header(phone, email, fax, website, vat, company_registry)"/>
|
||||
<field name="company_registry" on_change="on_change_header(phone, email, fax, website, vat, company_registry)"/>
|
||||
<field name="phone"/>
|
||||
<field name="fax"/>
|
||||
<field name="email"/>
|
||||
<field name="vat"/>
|
||||
<field name="company_registry"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Bank Accounts">
|
||||
<field name="bank_ids" colspan="4" nolabel="1"/>
|
||||
<label for="rml_footer2"/>
|
||||
<div name="bank_acc">
|
||||
<field name="rml_footer2"/>
|
||||
<!--<button name="%(bank_account_update)d" string="Set Bank Accounts" type="action" icon="gtk-go-forward" class="oe_inline"/>-->
|
||||
<field name="bank_ids" nolabel="1"
|
||||
context="{'default_company_id': active_id, 'footer_hide': False}"/>
|
||||
</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>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Header/Footer" groups="base.group_no_one">
|
||||
<group>
|
||||
<field name="paper_format" on_change="onchange_paper_format(paper_format)"/>
|
||||
<field name="rml_footer1"/>
|
||||
</group>
|
||||
<label for="rml_header"/>
|
||||
<field name="rml_header"/>
|
||||
<label for="rml_header2"/>
|
||||
|
@ -162,7 +164,7 @@
|
|||
<field name="sequence"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -190,4 +192,3 @@
|
|||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
import math
|
||||
import openerp
|
||||
import os
|
||||
from osv import osv, fields
|
||||
import re
|
||||
import tools
|
||||
|
@ -58,20 +57,20 @@ class res_partner_category(osv.osv):
|
|||
return super(res_partner_category, self).name_get(cr, uid, ids, context=context)
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
reads = self.read(cr, uid, ids, ['name','parent_id'], context=context)
|
||||
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
|
||||
name = record['parent_id'][1] + ' / ' + name
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
|
||||
if not args:
|
||||
args=[]
|
||||
args = []
|
||||
if not context:
|
||||
context={}
|
||||
context = {}
|
||||
if name:
|
||||
# Be sure name_search is symetric to name_get
|
||||
name = name.split(' / ')[-1]
|
||||
|
@ -85,23 +84,23 @@ class res_partner_category(osv.osv):
|
|||
res = self.name_get(cr, uid, ids, context=context)
|
||||
return dict(res)
|
||||
|
||||
_description='Partner Categories'
|
||||
_description = 'Partner Categories'
|
||||
_name = 'res.partner.category'
|
||||
_columns = {
|
||||
'name': fields.char('Category Name', required=True, size=64, translate=True),
|
||||
'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True, ondelete='cascade'),
|
||||
'complete_name': fields.function(_name_get_fnc, type="char", string='Full Name'),
|
||||
'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Child Categories'),
|
||||
'active' : fields.boolean('Active', help="The active field allows you to hide the category without removing it."),
|
||||
'parent_left' : fields.integer('Left parent', select=True),
|
||||
'parent_right' : fields.integer('Right parent', select=True),
|
||||
'active': fields.boolean('Active', help="The active field allows you to hide the category without removing it."),
|
||||
'parent_left': fields.integer('Left parent', select=True),
|
||||
'parent_right': fields.integer('Right parent', select=True),
|
||||
'partner_ids': fields.many2many('res.partner', id1='category_id', id2='partner_id', string='Partners'),
|
||||
}
|
||||
_constraints = [
|
||||
(osv.osv._check_recursion, 'Error ! You can not create recursive categories.', ['parent_id'])
|
||||
]
|
||||
_defaults = {
|
||||
'active' : lambda *a: 1,
|
||||
'active': lambda *a: 1,
|
||||
}
|
||||
_parent_store = True
|
||||
_parent_order = 'name'
|
||||
|
@ -113,7 +112,7 @@ class res_partner_title(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Title', required=True, size=46, translate=True),
|
||||
'shortcut': fields.char('Abbreviation', size=16, translate=True),
|
||||
'domain': fields.selection([('partner','Partner'),('contact','Contact')], 'Domain', required=True, size=24)
|
||||
'domain': fields.selection([('partner', 'Partner'), ('contact', 'Contact')], 'Domain', required=True, size=24)
|
||||
}
|
||||
_defaults = {
|
||||
'domain': 'contact',
|
||||
|
@ -129,13 +128,13 @@ POSTAL_ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'countr
|
|||
ADDRESS_FIELDS = POSTAL_ADDRESS_FIELDS + ('email', 'phone', 'fax', 'mobile', 'website', 'ref', 'lang')
|
||||
|
||||
class res_partner(osv.osv):
|
||||
_description='Partner'
|
||||
_description = 'Partner'
|
||||
_name = "res.partner"
|
||||
|
||||
def _address_display(self, cr, uid, ids, name, args, context=None):
|
||||
res={}
|
||||
res = {}
|
||||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
res[partner.id] =self._display_address(cr, uid, partner, context=context)
|
||||
res[partner.id] = self._display_address(cr, uid, partner, context=context)
|
||||
return res
|
||||
|
||||
def _get_image(self, cr, uid, ids, name, args, context=None):
|
||||
|
@ -143,7 +142,7 @@ class res_partner(osv.osv):
|
|||
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)
|
||||
|
||||
|
@ -151,7 +150,7 @@ class res_partner(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Name', size=128, required=True, select=True),
|
||||
'date': fields.date('Date', select=1),
|
||||
'title': fields.many2one('res.partner.title','Title'),
|
||||
'title': fields.many2one('res.partner.title', 'Title'),
|
||||
'parent_id': fields.many2one('res.partner', 'Owned by'),
|
||||
'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'),
|
||||
'ref': fields.char('Reference', size=64, select=1),
|
||||
|
@ -162,9 +161,9 @@ class res_partner(osv.osv):
|
|||
"It is important to set a value for this field. You should use the same timezone "
|
||||
"that is otherwise used to pick and render date and time values: your computer's timezone."),
|
||||
'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this partner if any.'),
|
||||
'vat': fields.char('TIN',size=32 ,help="Tax Identification Number. Check the box if the partner is subjected to taxes. Used by the some of the legal statements."),
|
||||
'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if the partner is subjected to taxes. Used by the some of the legal statements."),
|
||||
'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
|
||||
'website': fields.char('Website',size=64, help="Website of Partner or Company"),
|
||||
'website': fields.char('Website', size=64, help="Website of Partner or Company"),
|
||||
'comment': fields.text('Notes'),
|
||||
'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'), # should be removed in version 7, but kept until then for backward compatibility
|
||||
'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'),
|
||||
|
@ -175,8 +174,8 @@ class res_partner(osv.osv):
|
|||
'supplier': fields.boolean('Supplier', help="Check this box if the partner is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."),
|
||||
'employee': fields.boolean('Employee', help="Check this box if the partner is an Employee."),
|
||||
'function': fields.char('Job Position', size=128),
|
||||
'type': fields.selection( [('default','Default'), ('invoice','Invoice'),
|
||||
('delivery','Delivery'), ('contact','Contact'),
|
||||
'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'),
|
||||
('delivery', 'Delivery'), ('contact', 'Contact'),
|
||||
('other', 'Other')], 'Address Type',
|
||||
help="Used to select automatically the right address according to the context in sales and purchases documents."),
|
||||
'street': fields.char('Street', size=128),
|
||||
|
@ -193,25 +192,24 @@ class res_partner(osv.osv):
|
|||
'birthdate': fields.char('Birthdate', size=64),
|
||||
'is_company': fields.boolean('Company', help="Check if the contact is a company, otherwise it is a person"),
|
||||
'use_parent_address': fields.boolean('Use Company Address', help="Select this if you want to set company's address information for this contact"),
|
||||
# image: all image fields are base64 encoded and PIL-supported
|
||||
'image': fields.binary("Image",
|
||||
help="This field holds the image used as avatar for the "\
|
||||
"partner. The image is base64 encoded, and PIL-supported. "\
|
||||
"It is limited to a 1024x1024 px image."),
|
||||
help="This field holds the image used as avatar for the partner, limited to 1024x1024px"),
|
||||
'image_medium': fields.function(_get_image, fnct_inv=_set_image,
|
||||
string="Medium-sized image", type="binary", multi="_get_image",
|
||||
store = {
|
||||
store={
|
||||
'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
|
||||
},
|
||||
help="Medium-sized image of the partner. It is automatically "\
|
||||
"resized as a 180x180 px image, with aspect ratio preserved. "\
|
||||
"resized as a 128x128px 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="Small-sized image", type="binary", multi="_get_image",
|
||||
store = {
|
||||
store={
|
||||
'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
|
||||
},
|
||||
help="Small-sized image of the partner. It is automatically "\
|
||||
"resized as a 50x50 px image, with aspect ratio preserved. "\
|
||||
"resized as a 64x64px image, with aspect ratio preserved. "\
|
||||
"Use this field anywhere a small image is required."),
|
||||
'company_id': fields.many2one('res.company', 'Company', select=1),
|
||||
'color': fields.integer('Color Index'),
|
||||
|
@ -230,40 +228,28 @@ class res_partner(osv.osv):
|
|||
if is_company:
|
||||
image = open(openerp.modules.get_module_resource('base', 'static/src/img', 'company_image.png')).read()
|
||||
else:
|
||||
from PIL import Image
|
||||
from StringIO import StringIO
|
||||
color = (255,255,255)
|
||||
if colorize:
|
||||
from random import random
|
||||
color = (int(random() * 192 + 32), int(random() * 192 + 32), int(random() * 192 + 32))
|
||||
face = Image.open(openerp.modules.get_module_resource('base', 'static/src/img', 'avatar.png'))
|
||||
avatar = Image.new('RGB', face.size)
|
||||
avatar.paste(color)
|
||||
avatar.paste(face, mask=face)
|
||||
buffer = StringIO()
|
||||
avatar.save(buffer, 'PNG')
|
||||
image = buffer.getvalue()
|
||||
return image.encode('base64')
|
||||
image = tools.image_colorize(open(openerp.modules.get_module_resource('base', 'static/src/img', 'avatar.png')).read())
|
||||
return tools.image_resize_image_big(image.encode('base64'))
|
||||
|
||||
_defaults = {
|
||||
'active': True,
|
||||
'lang': lambda self, cr, uid, context: context.get('lang', 'en_US'),
|
||||
'tz': lambda self, cr, uid, context: context.get('tz', False),
|
||||
'lang': lambda self, cr, uid, ctx: ctx.get('lang', 'en_US'),
|
||||
'tz': lambda self, cr, uid, ctx: ctx.get('tz', False),
|
||||
'customer': True,
|
||||
'category_id': _default_category,
|
||||
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=c),
|
||||
'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=ctx),
|
||||
'color': 0,
|
||||
'is_company': False,
|
||||
'type': 'default',
|
||||
'use_parent_address': True,
|
||||
'image': lambda self, cr, uid, context: self._get_default_image(cr, uid, context.get('default_is_company', False), context),
|
||||
'image': lambda self, cr, uid, ctx: self._get_default_image(cr, uid, ctx.get('default_is_company', False), ctx),
|
||||
}
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
name = self.read(cr, uid, [id], ['name'], context)[0]['name']
|
||||
default.update({'name': _('%s (copy)')%(name)})
|
||||
default.update({'name': _('%s (copy)') % (name)})
|
||||
return super(res_partner, self).copy(cr, uid, id, default, context)
|
||||
|
||||
def onchange_type(self, cr, uid, ids, is_company, context=None):
|
||||
|
|
|
@ -244,14 +244,14 @@ class res_users(osv.osv):
|
|||
return result
|
||||
|
||||
_defaults = {
|
||||
'password' : '',
|
||||
'active' : True,
|
||||
'password': '',
|
||||
'active': True,
|
||||
'customer': False,
|
||||
'menu_id': _get_menu,
|
||||
'company_id': _get_company,
|
||||
'company_ids': _get_companies,
|
||||
'groups_id': _get_group,
|
||||
'image': lambda self, cr, uid, context: self.pool.get('res.partner')._get_default_image(cr, uid, False, context, colorize=True),
|
||||
'image': lambda self, cr, uid, ctx={}: self.pool.get('res.partner')._get_default_image(cr, uid, False, ctx, colorize=True),
|
||||
}
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
|
|
|
@ -86,12 +86,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.
|
||||
|
@ -238,9 +238,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()
|
||||
# Add the handler to the 'openerp' logger.
|
||||
logger = logging.getLogger('openerp')
|
||||
|
|
|
@ -892,8 +892,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
|
||||
|
@ -1308,7 +1308,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
|
||||
|
@ -2709,7 +2709,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):
|
||||
|
@ -2733,7 +2733,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
|
||||
|
@ -5013,66 +5013,56 @@ class BaseModel(object):
|
|||
|
||||
return True
|
||||
|
||||
def resolve_o2m_commands_to_record_dicts(self, cr, uid, field_name, o2m_commands, fields=None, context=None):
|
||||
""" Serializes o2m commands into record dictionaries (as if
|
||||
all the o2m records came from the database via a read()), and
|
||||
returns an iterable over these dictionaries.
|
||||
def resolve_2many_commands(self, cr, uid, field_name, commands, fields=None, context=None):
|
||||
""" Serializes one2many and many2many commands into record dictionaries
|
||||
(as if all the records came from the database via a read()). This
|
||||
method is aimed at onchange methods on one2many and many2many fields.
|
||||
|
||||
Because o2m commands might be creation commands, not all
|
||||
record ids will contain an ``id`` field. Commands matching an
|
||||
existing record (``UPDATE`` and ``LINK_TO``) will have an id.
|
||||
Because commands might be creation commands, not all record dicts
|
||||
will contain an ``id`` field. Commands matching an existing record
|
||||
will have an ``id``.
|
||||
|
||||
.. note:: ``CREATE``, ``UPDATE`` and ``LINK_TO`` stand for the
|
||||
o2m command codes ``0``, ``1`` and ``4``
|
||||
respectively
|
||||
|
||||
:param field_name: name of the o2m field matching the commands
|
||||
:type field_name: str
|
||||
:param o2m_commands: one2many commands to execute on ``field_name``
|
||||
:type o2m_commands: list((int|False, int|False, dict|False))
|
||||
:param fields: list of fields to read from the database, when applicable
|
||||
:type fields: list(str)
|
||||
:raises AssertionError: if a command is not ``CREATE``, ``UPDATE`` or ``LINK_TO``
|
||||
:returns: o2m records in a shape similar to that returned by
|
||||
``read()`` (except records may be missing the ``id``
|
||||
field if they don't exist in db)
|
||||
:rtype: ``list(dict)``
|
||||
:param field_name: name of the one2many or many2many field matching the commands
|
||||
:type field_name: str
|
||||
:param commands: one2many or many2many commands to execute on ``field_name``
|
||||
:type commands: list((int|False, int|False, dict|False))
|
||||
:param fields: list of fields to read from the database, when applicable
|
||||
:type fields: list(str)
|
||||
:returns: records in a shape similar to that returned by ``read()``
|
||||
(except records may be missing the ``id`` field if they don't exist in db)
|
||||
:rtype: list(dict)
|
||||
"""
|
||||
o2m_model = self._all_columns[field_name].column._obj
|
||||
result = [] # result (list of dict)
|
||||
record_ids = [] # ids of records to read
|
||||
updates = {} # {id: dict} of updates on particular records
|
||||
|
||||
# convert single ids and pairs to tripled commands
|
||||
commands = []
|
||||
for o2m_command in o2m_commands:
|
||||
if not isinstance(o2m_command, (list, tuple)):
|
||||
command = 4
|
||||
commands.append((command, o2m_command, False))
|
||||
elif len(o2m_command) == 1:
|
||||
(command,) = o2m_command
|
||||
commands.append((command, False, False))
|
||||
elif len(o2m_command) == 2:
|
||||
command, id = o2m_command
|
||||
commands.append((command, id, False))
|
||||
else:
|
||||
command = o2m_command[0]
|
||||
commands.append(o2m_command)
|
||||
assert command in (0, 1, 4), \
|
||||
"Only CREATE, UPDATE and LINK_TO commands are supported in resolver"
|
||||
for command in commands:
|
||||
if not isinstance(command, (list, tuple)):
|
||||
record_ids.append(command)
|
||||
elif command[0] == 0:
|
||||
result.append(command[2])
|
||||
elif command[0] == 1:
|
||||
record_ids.append(command[1])
|
||||
updates.setdefault(command[1], {}).update(command[2])
|
||||
elif command[0] in (2, 3):
|
||||
record_ids = [id for id in record_ids if id != command[1]]
|
||||
elif command[0] == 4:
|
||||
record_ids.append(command[1])
|
||||
elif command[0] == 5:
|
||||
result, record_ids = [], []
|
||||
elif command[0] == 6:
|
||||
result, record_ids = [], list(command[2])
|
||||
|
||||
# extract records to read, by id, in a mapping dict
|
||||
ids_to_read = [id for (command, id, _) in commands if command in (1, 4)]
|
||||
records_by_id = dict(
|
||||
(record['id'], record)
|
||||
for record in self.pool.get(o2m_model).read(
|
||||
cr, uid, ids_to_read, fields=fields, context=context))
|
||||
# read the records and apply the updates
|
||||
other_model = self.pool.get(self._all_columns[field_name].column._obj)
|
||||
for record in other_model.read(cr, uid, record_ids, fields=fields, context=context):
|
||||
record.update(updates.get(record['id'], {}))
|
||||
result.append(record)
|
||||
|
||||
record_dicts = []
|
||||
# merge record from db with record provided by command
|
||||
for command, id, record in commands:
|
||||
item = {}
|
||||
if command in (1, 4): item.update(records_by_id[id])
|
||||
if command in (0, 1): item.update(record)
|
||||
record_dicts.append(item)
|
||||
return record_dicts
|
||||
return result
|
||||
|
||||
# for backward compatibility
|
||||
resolve_o2m_commands_to_record_dicts = resolve_2many_commands
|
||||
|
||||
# keep this import here, at top it will cause dependency cycle errors
|
||||
import expression
|
||||
|
|
|
@ -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:
|
||||
|
@ -108,7 +106,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 = []
|
||||
|
@ -221,11 +219,9 @@ class report_custom(report_int):
|
|||
res_dic[prev].append(line)
|
||||
else:
|
||||
prev = line[groupby]
|
||||
if res_dic.has_key(line[groupby]):
|
||||
res_dic[line[groupby]].append(line)
|
||||
else:
|
||||
res_dic[line[groupby]] = []
|
||||
res_dic[line[groupby]].append(line)
|
||||
res_dic.setdefault(line[groupby], [])
|
||||
res_dic[line[groupby]].append(line)
|
||||
|
||||
#we use the keys in results since they are ordered, whereas in res_dic.heys() they aren't
|
||||
for key in filter(None, [x[groupby] for x in results]):
|
||||
row = []
|
||||
|
@ -267,7 +263,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':
|
||||
|
@ -365,7 +361,6 @@ class report_custom(report_int):
|
|||
order_date['Y'] = lambda x : x
|
||||
|
||||
abscissa = []
|
||||
tmp = {}
|
||||
|
||||
idx = 0
|
||||
date_idx = None
|
||||
|
@ -389,7 +384,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 +402,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 +483,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 +502,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]
|
||||
|
|
|
@ -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:])
|
||||
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
@ -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:
|
||||
|
|
|
@ -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 = '/'
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
##############################################################################
|
||||
|
||||
from openerp.report.render.rml2pdf import utils
|
||||
from lxml import etree
|
||||
import copy
|
||||
|
||||
class odt2odt(object):
|
||||
|
|
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
|
|
@ -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})
|
||||
|
@ -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}
|
||||
|
|
|
@ -22,9 +22,7 @@
|
|||
|
||||
import sys
|
||||
import StringIO
|
||||
import copy
|
||||
from lxml import etree
|
||||
import base64
|
||||
|
||||
import utils
|
||||
|
||||
|
@ -336,8 +334,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:
|
||||
|
|
|
@ -23,7 +23,6 @@ import copy
|
|||
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('\[\[(.+?)\]\]')
|
||||
|
@ -38,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:
|
||||
|
@ -47,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
|
||||
|
@ -56,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
|
||||
|
@ -74,11 +73,11 @@ def _process_text(self, txt):
|
|||
if sps:
|
||||
try:
|
||||
txt2 = eval(sps.pop(0),self.localcontext)
|
||||
except:
|
||||
except Exception:
|
||||
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
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ class simple(render.render):
|
|||
return self.result.getvalue()
|
||||
|
||||
if __name__=='__main__':
|
||||
import time
|
||||
s = simple()
|
||||
s.xml = '''<test>
|
||||
<author-list>
|
||||
|
@ -82,7 +81,7 @@ if __name__=='__main__':
|
|||
</author-list>
|
||||
</test>'''
|
||||
if s.render():
|
||||
print s.get()
|
||||
print s.get()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -126,12 +126,12 @@ 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.
|
||||
_logger.debug("Netrpc: %d threads", len(self.threads))
|
||||
# Not many threads should be serving at the same time, so log
|
||||
# their abuse.
|
||||
_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
|
||||
|
||||
|
|
|
@ -238,9 +238,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 <PASSWD> 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 <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)
|
||||
|
||||
|
@ -253,7 +253,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)
|
||||
|
@ -282,7 +282,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:
|
||||
|
@ -465,8 +465,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:
|
||||
|
@ -526,11 +525,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' \
|
||||
|
@ -695,7 +694,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:
|
||||
|
@ -732,7 +731,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:
|
||||
|
|
|
@ -716,6 +716,15 @@ class test_m2m(ImporterCase):
|
|||
class test_o2m(ImporterCase):
|
||||
model_name = 'export.one2many'
|
||||
|
||||
def test_name_get(self):
|
||||
# FIXME: bloody hell why can't this just name_create the record?
|
||||
self.assertRaises(
|
||||
IndexError,
|
||||
self.import_,
|
||||
['const', 'value'],
|
||||
[['5', u'Java is a DSL for taking large XML files'
|
||||
u' and converting them to stack traces']])
|
||||
|
||||
def test_single(self):
|
||||
self.assertEqual(
|
||||
self.import_(['const', 'value/value'], [
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import os
|
||||
import unittest2
|
||||
|
||||
import openerp
|
||||
|
@ -15,6 +14,10 @@ LINK_TO = lambda id: (4, id, False)
|
|||
DELETE_ALL = lambda: (5, False, False)
|
||||
REPLACE_WITH = lambda ids: (6, False, ids)
|
||||
|
||||
def sorted_by_id(list_of_dicts):
|
||||
"sort dictionaries by their 'id' field; useful for comparisons"
|
||||
return sorted(list_of_dicts, key=lambda d: d.get('id'))
|
||||
|
||||
class TestO2MSerialization(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -23,21 +26,18 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
|
||||
def test_no_command(self):
|
||||
" empty list of commands yields an empty list of records "
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', [])
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_CREATE_commands(self):
|
||||
" returns the VALUES dict as-is "
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address',
|
||||
map(CREATE, [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}]))
|
||||
self.assertEqual(results, [
|
||||
{'foo': 'bar'},
|
||||
{'foo': 'baz'},
|
||||
{'foo': 'baq'}
|
||||
])
|
||||
values = [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}]
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', map(CREATE, values))
|
||||
|
||||
self.assertEqual(results, values)
|
||||
|
||||
def test_LINK_TO_command(self):
|
||||
" reads the records from the database, records are returned with their ids. "
|
||||
|
@ -48,14 +48,14 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
]
|
||||
commands = map(LINK_TO, ids)
|
||||
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', commands, ['name'])
|
||||
|
||||
self.assertEqual(results, [
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
])
|
||||
]))
|
||||
|
||||
def test_bare_ids_command(self):
|
||||
" same as the equivalent LINK_TO commands "
|
||||
|
@ -65,14 +65,14 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
]
|
||||
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', ids, ['name'])
|
||||
|
||||
self.assertEqual(results, [
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
])
|
||||
]))
|
||||
|
||||
def test_UPDATE_command(self):
|
||||
" take the in-db records and merge the provided information in "
|
||||
|
@ -80,18 +80,32 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
id_bar = self.partner.create(self.cr, UID, {'name': 'bar'})
|
||||
id_baz = self.partner.create(self.cr, UID, {'name': 'baz', 'city': 'tag'})
|
||||
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', [
|
||||
LINK_TO(id_foo),
|
||||
UPDATE(id_bar, {'name': 'qux', 'city': 'tagtag'}),
|
||||
UPDATE(id_baz, {'name': 'quux'})
|
||||
], ['name', 'city'])
|
||||
|
||||
self.assertEqual(results, [
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'id': id_foo, 'name': 'foo', 'city': False},
|
||||
{'id': id_bar, 'name': 'qux', 'city': 'tagtag'},
|
||||
{'id': id_baz, 'name': 'quux', 'city': 'tag'}
|
||||
])
|
||||
]))
|
||||
|
||||
def test_DELETE_command(self):
|
||||
" deleted records are not returned at all. "
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': 'foo'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'bar'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
]
|
||||
commands = [DELETE(ids[0]), DELETE(ids[1]), DELETE(ids[2])]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', commands, ['name'])
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_mixed_commands(self):
|
||||
ids = [
|
||||
|
@ -99,28 +113,27 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
for name in ['NObar', 'baz', 'qux', 'NOquux', 'NOcorge', 'garply']
|
||||
]
|
||||
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', [
|
||||
CREATE({'name': 'foo'}),
|
||||
UPDATE(ids[0], {'name': 'bar'}),
|
||||
LINK_TO(ids[1]),
|
||||
LINK_TO(ids[2]),
|
||||
DELETE(ids[2]),
|
||||
UPDATE(ids[3], {'name': 'quux',}),
|
||||
UPDATE(ids[4], {'name': 'corge'}),
|
||||
CREATE({'name': 'grault'}),
|
||||
LINK_TO(ids[5])
|
||||
], ['name'])
|
||||
|
||||
self.assertEqual(results, [
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'name': 'foo'},
|
||||
{'id': ids[0], 'name': 'bar'},
|
||||
{'id': ids[1], 'name': 'baz'},
|
||||
{'id': ids[2], 'name': 'qux'},
|
||||
{'id': ids[3], 'name': 'quux'},
|
||||
{'id': ids[4], 'name': 'corge'},
|
||||
{'name': 'grault'},
|
||||
{'id': ids[5], 'name': 'garply'}
|
||||
])
|
||||
]))
|
||||
|
||||
def test_LINK_TO_pairs(self):
|
||||
"LINK_TO commands can be written as pairs, instead of triplets"
|
||||
|
@ -131,43 +144,20 @@ class TestO2MSerialization(common.TransactionCase):
|
|||
]
|
||||
commands = map(lambda id: (4, id), ids)
|
||||
|
||||
results = self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', commands, ['name'])
|
||||
|
||||
self.assertEqual(results, [
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
])
|
||||
]))
|
||||
|
||||
def test_singleton_commands(self):
|
||||
"DELETE_ALL can appear as a singleton"
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'address', [DELETE_ALL()], ['name'])
|
||||
|
||||
try:
|
||||
self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address', [(5,)], ['name'])
|
||||
except AssertionError:
|
||||
# 5 should fail with an assert error, but not e.g. a ValueError
|
||||
pass
|
||||
|
||||
def test_invalid_commands(self):
|
||||
"Commands with uncertain semantics in this context should be forbidden"
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address', [DELETE(42)], ['name'])
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address', [FORGET(42)], ['name'])
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address', [DELETE_ALL()], ['name'])
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
self.partner.resolve_o2m_commands_to_record_dicts(
|
||||
self.cr, UID, 'address', [REPLACE_WITH([42])], ['name'])
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -22,12 +22,15 @@
|
|||
import socket
|
||||
import cPickle
|
||||
import cStringIO
|
||||
import marshal
|
||||
|
||||
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,20 +66,19 @@ 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=''
|
||||
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 = ''
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
##############################################################################
|
||||
|
||||
import io
|
||||
from PIL import Image
|
||||
import StringIO
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageFilter
|
||||
from random import random
|
||||
|
||||
# ----------------------------------------
|
||||
# Image resizing
|
||||
# ----------------------------------------
|
||||
|
@ -47,15 +50,17 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
|
|||
image.
|
||||
- past the thumbnail on the transparent background and center
|
||||
it.
|
||||
|
||||
|
||||
:param base64_source: base64-encoded version of the source
|
||||
image
|
||||
image; if False, returns False
|
||||
:param size: tuple(height, width)
|
||||
:param encoding: the output encoding
|
||||
:param filetype: the output filetype
|
||||
:param avoid_if_small: do not resize if image height and width
|
||||
are smaller than the expected size.
|
||||
"""
|
||||
if not base64_source:
|
||||
return False
|
||||
image_stream = io.BytesIO(base64_source.decode(encoding))
|
||||
image = Image.open(image_stream)
|
||||
# check image size: do not create a thumbnail if avoiding smaller images
|
||||
|
@ -63,6 +68,7 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
|
|||
return base64_source
|
||||
# create a thumbnail: will resize and keep ratios
|
||||
image.thumbnail(size, Image.ANTIALIAS)
|
||||
image = image.filter(ImageFilter.SHARPEN)
|
||||
# create a transparent image for background
|
||||
background = Image.new('RGBA', size, (255, 255, 255, 0))
|
||||
# past the resized image on the background
|
||||
|
@ -72,42 +78,57 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
|
|||
background.save(background_stream, filetype)
|
||||
return background_stream.getvalue().encode(encoding)
|
||||
|
||||
def image_resize_image_big(base64_source, size=(1204, 1204), encoding='base64', filetype='PNG'):
|
||||
def image_resize_image_big(base64_source, size=(1204, 1204), encoding='base64', filetype='PNG', avoid_if_small=True):
|
||||
""" Wrapper on image_resize_image, to resize images larger than the standard
|
||||
'big' image size: 1024x1024px.
|
||||
:param base64_source: base64 encoded source image. If False,
|
||||
the function returns False.
|
||||
:param size, encoding, filetype, avoid_if_small: refer to image_resize_image
|
||||
"""
|
||||
if not base64_source:
|
||||
return False
|
||||
return image_resize_image(base64_source, size, encoding, filetype, True)
|
||||
return image_resize_image(base64_source, size, encoding, filetype, avoid_if_small)
|
||||
|
||||
def image_resize_image_medium(base64_source, size=(180, 180), encoding='base64', filetype='PNG'):
|
||||
def image_resize_image_medium(base64_source, size=(128, 128), encoding='base64', filetype='PNG', avoid_if_small=False):
|
||||
""" Wrapper on image_resize_image, to resize to the standard 'medium'
|
||||
image size: 180x180.
|
||||
:param base64_source: base64 encoded source image. If False,
|
||||
the function returns False.
|
||||
:param size, encoding, filetype, avoid_if_small: refer to image_resize_image
|
||||
"""
|
||||
if not base64_source:
|
||||
return False
|
||||
return image_resize_image(base64_source, size, encoding, filetype)
|
||||
|
||||
def image_resize_image_small(base64_source, size=(50, 50), encoding='base64', filetype='PNG'):
|
||||
return image_resize_image(base64_source, size, encoding, filetype, avoid_if_small)
|
||||
|
||||
def image_resize_image_small(base64_source, size=(64, 64), encoding='base64', filetype='PNG', avoid_if_small=False):
|
||||
""" Wrapper on image_resize_image, to resize to the standard 'small' image
|
||||
size: 50x50.
|
||||
:param base64_source: base64 encoded source image. If False,
|
||||
the function returns False.
|
||||
:param size, encoding, filetype, avoid_if_small: refer to image_resize_image
|
||||
"""
|
||||
if not base64_source:
|
||||
return False
|
||||
return image_resize_image(base64_source, size, encoding, filetype)
|
||||
return image_resize_image(base64_source, size, encoding, filetype, avoid_if_small)
|
||||
|
||||
# ----------------------------------------
|
||||
# Colors
|
||||
# ---------------------------------------
|
||||
|
||||
def image_colorize(original, randomize=True, color=(255, 255, 255)):
|
||||
""" Add a color to the transparent background of an image.
|
||||
:param original: file object on the original image file
|
||||
:param randomize: randomize the background color
|
||||
:param color: background-color, if not randomize
|
||||
"""
|
||||
# create a new image, based on the original one
|
||||
original = Image.open(io.BytesIO(original))
|
||||
image = Image.new('RGB', original.size)
|
||||
# generate the background color, past it as background
|
||||
if randomize:
|
||||
color = (int(random() * 192 + 32), int(random() * 192 + 32), int(random() * 192 + 32))
|
||||
image.paste(color)
|
||||
image.paste(original, mask=original)
|
||||
# return the new image
|
||||
buffer = StringIO.StringIO()
|
||||
image.save(buffer, 'PNG')
|
||||
return buffer.getvalue()
|
||||
|
||||
# ----------------------------------------
|
||||
# Misc image tools
|
||||
# ---------------------------------------
|
||||
|
||||
def image_get_resized_images(base64_source, return_big=False, return_medium=True, return_small=True,
|
||||
big_name='image', medium_name='image_medium', small_name='image_small'):
|
||||
big_name='image', medium_name='image_medium', small_name='image_small',
|
||||
avoid_resize_big=True, avoid_resize_medium=False, avoid_resize_small=False):
|
||||
""" Standard tool function that returns a dictionary containing the
|
||||
big, medium and small versions of the source image. This function
|
||||
is meant to be used for the methods of functional fields for
|
||||
|
@ -116,24 +137,22 @@ def image_get_resized_images(base64_source, return_big=False, return_medium=True
|
|||
Default parameters are given to be used for the getter of functional
|
||||
image fields, for example with res.users or res.partner. It returns
|
||||
only image_medium and image_small values, to update those fields.
|
||||
|
||||
:param base64_source: if set to False, other values are set to False
|
||||
also. The purpose is to be linked to the fields that hold images in
|
||||
OpenERP and that are binary fields.
|
||||
:param return_big: if set, return_dict contains the 'big_name' entry
|
||||
:param return_medium: if set, return_dict contains the 'medium_name' entry
|
||||
:param return_small: if set, return_dict contains the 'small_name' entry
|
||||
:param big_name: name related to the big version of the image;
|
||||
'image' by default.
|
||||
:param medium_name: name related to the medium version of the
|
||||
image; 'image_medium' by default.
|
||||
:param small_name: name related to the small version of the
|
||||
image; 'image_small' by default.
|
||||
|
||||
:param base64_source: base64-encoded version of the source
|
||||
image; if False, all returnes values will be False
|
||||
:param return_{..}: if set, computes and return the related resizing
|
||||
of the image
|
||||
:param {..}_name: key of the resized image in the return dictionary;
|
||||
'image', 'image_medium' and 'image_small' by default.
|
||||
:param avoid_resize_[..]: see avoid_if_small parameter
|
||||
:return return_dict: dictionary with resized images, depending on
|
||||
previous parameters.
|
||||
"""
|
||||
return_dict = dict()
|
||||
if return_big: return_dict[big_name] = image_resize_image_big(base64_source)
|
||||
if return_medium: return_dict[medium_name] = image_resize_image_medium(base64_source)
|
||||
if return_small: return_dict[small_name] = image_resize_image_small(base64_source)
|
||||
return return_dict
|
||||
if return_big:
|
||||
return_dict[big_name] = image_resize_image_big(base64_source, avoid_if_small=avoid_resize_big)
|
||||
if return_medium:
|
||||
return_dict[medium_name] = image_resize_image_medium(base64_source, avoid_if_small=avoid_resize_medium)
|
||||
if return_small:
|
||||
return_dict[small_name] = image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small)
|
||||
return return_dict
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue