bzr revid: chs@openerp.com-20120911120807-8wvvh0tubdoqkwa0
This commit is contained in:
Christophe Simonis 2012-09-11 14:08:07 +02:00
commit 700d229760
40 changed files with 410 additions and 405 deletions

1
debian/control vendored
View File

@ -16,6 +16,7 @@ Depends:
python,
postgresql-client,
python-dateutil,
python-docutils,
python-feedparser,
python-gdata,
python-ldap,

View File

@ -30,7 +30,6 @@ GNU Public Licence.
(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
"""
import imp
import logging
import os
import signal

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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"/>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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':

View File

@ -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>

View File

@ -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>"""

View File

@ -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>

View File

@ -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):

View File

@ -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):

View File

@ -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')

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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()

View File

@ -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:

View File

@ -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 = '/'

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -20,7 +20,6 @@
##############################################################################
from openerp.report.render.rml2pdf import utils
from lxml import etree
import copy
class odt2odt(object):

View File

@ -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()

View File

@ -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}

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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'], [

View File

@ -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:

View File

@ -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:

View File

@ -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 = ''

View File

@ -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

View File

@ -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