[MERGE] merged with lp:~openerp/openobject-server/trunk

bzr revid: hmo@hmo-20100524074613-apd7uhbsogt38imy
This commit is contained in:
hmo
2010-05-24 13:16:13 +05:30
68 changed files with 2334 additions and 692 deletions
+2 -1
View File
@@ -9,7 +9,8 @@ include bin/server.pkey
include bin/gpl.txt
include man/openerp-server.1
include man/openerp_serverrc.5
recursive-include pixmaps
recursive-include pixmaps *
recursive-include win32 *
recursive-include doc *
recursive-include bin *xml *xsl *sql *rml *sxw *csv *rng
graft bin/addons/
+5 -8
View File
@@ -644,16 +644,13 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
try:
_load_data(cr, module_name, id_map, mode, 'test')
except Exception, e:
if tools.config.options['test-continue']:
logger.notifyChannel('ERROR', netsvc.LOG_TEST, e)
pass
else:
raise
logger.notifyChannel('ERROR', netsvc.LOG_TEST, e)
pass
finally:
if tools.config.options['test-rollback']:
cr.rollback()
else:
if tools.config.options['test-commit']:
cr.commit()
else:
cr.rollback()
def _load_data(cr, module_name, id_map, mode, kind):
noupdate = (kind == 'demo')
@@ -49,6 +49,7 @@
'module/module_report.xml',
'res/res_request_view.xml',
'res/res_lang_view.xml',
'res/res_log_view.xml',
'res/res_company_view.xml',
'res/partner/partner_report.xml',
'res/partner/partner_view.xml',
+6 -3
View File
@@ -87,6 +87,7 @@
<label colspan="4" string="Please note that you will have to logout and relog if you change your password."/>
<field name="context_lang" completion="1" readonly="0"/>
<field name="context_tz" completion="1" readonly="0" colspan="4"/>
<field name="view" colspan="4" readonly="0" />
<newline/>
<field colspan="4" name="signature" readonly="0"/>
</page>
@@ -108,16 +109,18 @@
<notebook colspan="4">
<page string="User">
<field name="address_id" select="1"/>
<field name="user_email" widget="email"/>
<field name="company_id" required="1"/>
<field name="action_id" required="True"/>
<field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
<field name="context_lang"/>
<field name="context_tz"/>
<field name="view" readonly="0" />
<group colspan="2" col="2">
<separator string="Signature" colspan="2"/>
<field colspan="2" name="signature" nolabel="1"/>
</group>
<group colspan="2" col="2">
<group colspan="2" col="2" expand="1">
<separator string="Access Rights (groups)" colspan="2"/>
<field colspan="2" nolabel="1" name="groups_id"/>
</group>
@@ -284,14 +287,14 @@
</form>
<xpath expr="//label[@string='description']"
position="attributes">
<attribute name="string">Choose between the simplified interface and the extended one. If you are testing OpenERP or using it for the first time, We suggest you use the simplified interface. It has less options and fields but is easier to understand. You will be able to switch to the extended interface later.</attribute>
<attribute name="string">Choose between the simplified interface and the extended one. We suggest you use the simplified interface. It has less options and fields but is easier to understand. You will be able to switch to the extended interface later.</attribute>
</xpath>
<xpath expr='//separator[@string="title"]' position='attributes'>
<attribute name='string'>Choose Your Interface</attribute>
</xpath>
<xpath expr='//separator[@string="vsep"]' position='attributes'>
<attribute name='string'></attribute>
<attribute name='rowspan'>14</attribute>
<attribute name='rowspan'>12</attribute>
</xpath>
<group string="res_config_contents" position="replace">
<group colspan="4">
+52 -52
View File
@@ -1,52 +1,52 @@
"country_id:id","name","code"
us,"Alabama","AL"
us,"Alaska","AK"
us,"Arizona","AZ"
us,"Arkansas","AR"
us,"California","CA"
us,"Colorado","CO"
us,"Connecticut","CT"
us,"Delaware","DE"
us,"District of Columbia","DC"
us,"Florida","FL"
us,"Georgia","GA"
us,"Hawaii","HI"
us,"Idaho","ID"
us,"Illinois","IL"
us,"Indiana","IN"
us,"Iowa","IA"
us,"Kansas","KS"
us,"Kentucky","KY"
us,"Louisiana","LA"
us,"Maine","ME"
us,"Montana","MT"
us,"Nebraska","NE"
us,"Nevada","NV"
us,"New Hampshire","NH"
us,"New Jersey","NJ"
us,"New Mexico","NM"
us,"New York","NY"
us,"North Carolina","NC"
us,"North Dakota","ND"
us,"Ohio","OH"
us,"Oklahoma","OK"
us,"Oregon","OR"
us,"Maryland","MD"
us,"Massachusetts","MA"
us,"Michigan","MI"
us,"Minnesota","MN"
us,"Mississippi","MS"
us,"Missouri","MO"
us,"Pennsylvania","PA"
us,"Rhode Island","RI"
us,"South Carolina","SC"
us,"South Dakota","SD"
us,"Tennessee","TN"
us,"Texas","TX"
us,"Utah","UT"
us,"Vermont","VT"
us,"Virginia","VA"
us,"Washington","WA"
us,"West Virginia","WV"
us,"Wisconsin","WI"
us,"Wyoming","WY"
"id","country_id:id","name","code"
state_us_1,us,"Alabama","AL"
state_us_2,us,"Alaska","AK"
state_us_3,us,"Arizona","AZ"
state_us_4,us,"Arkansas","AR"
state_us_5,us,"California","CA"
state_us_6,us,"Colorado","CO"
state_us_7,us,"Connecticut","CT"
state_us_8,us,"Delaware","DE"
state_us_9,us,"District of Columbia","DC"
state_us_10,us,"Florida","FL"
state_us_11,us,"Georgia","GA"
state_us_12,us,"Hawaii","HI"
state_us_13,us,"Idaho","ID"
state_us_14,us,"Illinois","IL"
state_us_15,us,"Indiana","IN"
state_us_16,us,"Iowa","IA"
state_us_17,us,"Kansas","KS"
state_us_18,us,"Kentucky","KY"
state_us_19,us,"Louisiana","LA"
state_us_20,us,"Maine","ME"
state_us_21,us,"Montana","MT"
state_us_22,us,"Nebraska","NE"
state_us_23,us,"Nevada","NV"
state_us_24,us,"New Hampshire","NH"
state_us_25,us,"New Jersey","NJ"
state_us_26,us,"New Mexico","NM"
state_us_27,us,"New York","NY"
state_us_28,us,"North Carolina","NC"
state_us_29,us,"North Dakota","ND"
state_us_30,us,"Ohio","OH"
state_us_31,us,"Oklahoma","OK"
state_us_32,us,"Oregon","OR"
state_us_33,us,"Maryland","MD"
state_us_34,us,"Massachusetts","MA"
state_us_35,us,"Michigan","MI"
state_us_36,us,"Minnesota","MN"
state_us_37,us,"Mississippi","MS"
state_us_38,us,"Missouri","MO"
state_us_39,us,"Pennsylvania","PA"
state_us_40,us,"Rhode Island","RI"
state_us_41,us,"South Carolina","SC"
state_us_42,us,"South Dakota","SD"
state_us_43,us,"Tennessee","TN"
state_us_44,us,"Texas","TX"
state_us_45,us,"Utah","UT"
state_us_46,us,"Vermont","VT"
state_us_47,us,"Virginia","VA"
state_us_48,us,"Washington","WA"
state_us_49,us,"West Virginia","WV"
state_us_50,us,"Wisconsin","WI"
state_us_51,us,"Wyoming","WY"
1 id country_id:id name code
2 state_us_1 us Alabama AL
3 state_us_2 us Alaska AK
4 state_us_3 us Arizona AZ
5 state_us_4 us Arkansas AR
6 state_us_5 us California CA
7 state_us_6 us Colorado CO
8 state_us_7 us Connecticut CT
9 state_us_8 us Delaware DE
10 state_us_9 us District of Columbia DC
11 state_us_10 us Florida FL
12 state_us_11 us Georgia GA
13 state_us_12 us Hawaii HI
14 state_us_13 us Idaho ID
15 state_us_14 us Illinois IL
16 state_us_15 us Indiana IN
17 state_us_16 us Iowa IA
18 state_us_17 us Kansas KS
19 state_us_18 us Kentucky KY
20 state_us_19 us Louisiana LA
21 state_us_20 us Maine ME
22 state_us_21 us Montana MT
23 state_us_22 us Nebraska NE
24 state_us_23 us Nevada NV
25 state_us_24 us New Hampshire NH
26 state_us_25 us New Jersey NJ
27 state_us_26 us New Mexico NM
28 state_us_27 us New York NY
29 state_us_28 us North Carolina NC
30 state_us_29 us North Dakota ND
31 state_us_30 us Ohio OH
32 state_us_31 us Oklahoma OK
33 state_us_32 us Oregon OR
34 state_us_33 us Maryland MD
35 state_us_34 us Massachusetts MA
36 state_us_35 us Michigan MI
37 state_us_36 us Minnesota MN
38 state_us_37 us Mississippi MS
39 state_us_38 us Missouri MO
40 state_us_39 us Pennsylvania PA
41 state_us_40 us Rhode Island RI
42 state_us_41 us South Carolina SC
43 state_us_42 us South Dakota SD
44 state_us_43 us Tennessee TN
45 state_us_44 us Texas TX
46 state_us_45 us Utah UT
47 state_us_46 us Vermont VT
48 state_us_47 us Virginia VA
49 state_us_48 us Washington WA
50 state_us_49 us West Virginia WV
51 state_us_50 us Wisconsin WI
52 state_us_51 us Wyoming WY
+16 -16
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-04-21 04:53+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"PO-Revision-Date: 2010-05-17 05:31+0000\n"
"Last-Translator: Boris <boris.t.ivanov@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: 2010-04-22 03:42+0000\n"
"X-Launchpad-Export-Date: 2010-05-18 05:14+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -83,7 +83,7 @@ msgstr "Създадени изгледи"
#. module: base
#: view:workflow.activity:0
msgid "Outgoing transitions"
msgstr "Изходящи промени"
msgstr "Изходящи преходи"
#. module: base
#: selection:ir.report.custom,frequency:0
@@ -1754,7 +1754,7 @@ msgstr "XSL"
#: code:addons/base/module/module.py:0
#, python-format
msgid "Can not upgrade module '%s'. It is not installed."
msgstr "Не може да бъде обновен модул '%s'. Той не е инсталиран."
msgstr "Модул '%s' не може да бъде обновен. Той не е инсталиран."
#. module: base
#: model:res.country,name:base.cu
@@ -2039,7 +2039,7 @@ msgstr "Извличане на език"
#. module: base
#: selection:maintenance.contract.wizard,state:0
msgid "Unvalidated"
msgstr "Непроверен"
msgstr "Невалидирано"
#. module: base
#: model:ir.ui.menu,name:base.next_id_9
@@ -2066,7 +2066,7 @@ msgstr "Също така може да вмъкнете \".po\" файлове.
#: code:addons/base/maintenance/maintenance.py:0
#, python-format
msgid "Unable to find a valid contract"
msgstr "Не може да се намери валиден договор"
msgstr "Не е намерeн валиден договор"
#. module: base
#: code:addons/base/ir/ir_actions.py:0
@@ -5002,7 +5002,7 @@ msgstr "Python код"
#: code:addons/base/module/wizard/wizard_module_import.py:0
#, python-format
msgid "Can not create the module file: %s !"
msgstr "Модулния файл: %s, не можеда да бъде създаден !"
msgstr "Модулния файл: %s, не можеда да бъде създаден !"
#. module: base
#: model:ir.module.module,description:base.module_meta_information
@@ -5028,7 +5028,7 @@ msgstr "Откажи"
#: code:addons/base/ir/ir_actions.py:0
#, python-format
msgid "Please specify server option --smtp-from !"
msgstr "Моля укажете опцията на сървъра --smtp-from !"
msgstr "Моля укажете опция на сървъра --smtp-from !"
#. module: base
#: selection:wizard.module.lang.export,format:0
@@ -6225,7 +6225,7 @@ msgstr "Извличане на файл с превод"
#. module: base
#: field:ir.ui.view_sc,user_id:0
msgid "User Ref."
msgstr "Справка за потребител"
msgstr "Потребителска справка"
#. module: base
#: model:ir.ui.menu,name:base.menu_base_config
@@ -6812,7 +6812,7 @@ msgstr "RML съдържание"
#. module: base
#: view:workflow.activity:0
msgid "Incoming transitions"
msgstr "Входящи промени"
msgstr "Входящи преходи"
#. module: base
#: model:res.country,name:base.cn
@@ -7277,7 +7277,7 @@ msgstr "Оригинал"
#. module: base
#: help:res.partner.address,partner_id:0
msgid "Keep empty for a private address, not related to partner."
msgstr "Оставете празно за личен адрес несвързан с партньора"
msgstr "Оставете празно за личен адрес нямащ отношение към партньора."
#. module: base
#: model:res.country,name:base.vu
@@ -7296,8 +7296,8 @@ msgid ""
"Save this document to a .tgz file. This archive containt UTF-8 %s files and "
"may be uploaded to launchpad."
msgstr ""
"Запази документа като .tgz файл. Този архив съдържа %s UTF-8 файлове и може "
"да бъде качен в launchpad."
"Запазете документа като .tgz файл. Този архив съдържа %s UTF-8 файлове и "
"може да бъде качен в launchpad."
#. module: base
#: wizard_button:module.upgrade,end,config:0
@@ -7728,7 +7728,7 @@ msgid ""
"invoice, then `object.invoice_address_id.mobile` is the field which gives "
"the correct mobile number"
msgstr ""
"Оказва полетата които ще се използват за доставяне на мобилен номер, напр., "
"Указва полетата които ще се използват за доставяне на мобилен номер, напр., "
"когато изберете фактура, тогава 'object.invoice_address_id.mobile' е полето "
"което дава правилния мобилен номер"
@@ -8080,7 +8080,7 @@ msgstr "полски / Język polski"
#. module: base
#: field:ir.exports,name:0
msgid "Export Name"
msgstr "Име на извлечането"
msgstr "Име на изнасянето"
#. module: base
#: help:res.partner.address,type:0
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-11 05:41+0000\n"
"PO-Revision-Date: 2010-05-23 04:28+0000\n"
"Last-Translator: goranc <goranc@gmail.com>\n"
"Language-Team: openerp-translators\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-05-12 04:19+0000\n"
"X-Launchpad-Export-Date: 2010-05-24 03:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Language: hr\n"
+9 -12
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-04-29 04:41+0000\n"
"PO-Revision-Date: 2010-05-17 05:31+0000\n"
"Last-Translator: eLBati - albatos.com <lorenzo.battistini@albatos.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: 2010-04-30 03:50+0000\n"
"X-Launchpad-Export-Date: 2010-05-18 05:14+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -901,7 +901,7 @@ msgstr "Relazione"
#. module: base
#: field:ir.model.access,perm_read:0
msgid "Read Access"
msgstr "Accesso di Lettura"
msgstr "Accesso in lettura"
#. module: base
#: model:ir.model,name:base.model_ir_exports
@@ -2150,10 +2150,7 @@ msgstr "Crea Menu"
msgid ""
"Value Added Tax number. Check the box if the partner is subjected to the "
"VAT. Used by the VAT legal statement."
msgstr ""
"numero di Partita IVA (Imposta sul valore Aggiunto - VAT). Seleziona la "
"casella se il partner è soggetto IVA. Usato dalla dichiarazione legale "
"sull'IVA."
msgstr "Seleziona la casella se il partner è soggetto IVA."
#. module: base
#: model:ir.actions.act_window,name:base.action_module_category_tree
@@ -2204,7 +2201,7 @@ msgstr "Registra Regole"
#. module: base
#: field:res.partner,vat:0
msgid "VAT"
msgstr "IVA"
msgstr "Partita IVA"
#. module: base
#: view:res.lang:0
@@ -3878,7 +3875,7 @@ msgstr "Esegui Conteggio"
#. module: base
#: field:ir.model.access,perm_create:0
msgid "Create Access"
msgstr "Crea Accesso"
msgstr "Accesso in creazione"
#. module: base
#: field:res.partner.address,state_id:0
@@ -5509,7 +5506,7 @@ msgstr "Sig.rina"
#. module: base
#: field:ir.model.access,perm_write:0
msgid "Write Access"
msgstr "Accesso Scrittura"
msgstr "Accesso in scrittura"
#. module: base
#: field:res.bank,city:0
@@ -7414,7 +7411,7 @@ msgstr ">"
#. module: base
#: field:ir.model.access,perm_unlink:0
msgid "Delete Permission"
msgstr "Cancella Autorizzazione"
msgstr "Permesso di cancellazione"
#. module: base
#: model:ir.model,name:base.model_multi_company_default
@@ -7682,7 +7679,7 @@ msgstr ""
#. module: base
#: constraint:res.partner:0
msgid "The VAT doesn't seem to be correct."
msgstr "L'IVA non sembra essere corretta"
msgstr "La P.IVA non sembra essere corretta"
#. module: base
#: selection:ir.report.custom.fields,operation:0
+2 -2
View File
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-server\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-11 05:36+0000\n"
"PO-Revision-Date: 2010-05-23 04:32+0000\n"
"Last-Translator: Harry (Open ERP) <hmo@tinyerp.com>\n"
"Language-Team: Japanese <ja@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-05-12 04:19+0000\n"
"X-Launchpad-Export-Date: 2010-05-24 03:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+28 -28
View File
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-01-04 06:03+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
"PO-Revision-Date: 2010-05-19 12:29+0000\n"
"Last-Translator: Olivier Dony (OpenERP) <Unknown>\n"
"Language-Team: Latvian <lv@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 03:51+0000\n"
"X-Launchpad-Export-Date: 2010-05-21 03:37+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -176,7 +176,7 @@ msgstr "ir.report.custom.fields"
#. module: base
#: view:res.partner:0
msgid "Search Partner"
msgstr ""
msgstr "Meklēt Partneri"
#. module: base
#: code:addons/base/module/wizard/wizard_export_lang.py:0
@@ -419,7 +419,7 @@ msgstr "Kolumbija"
#. module: base
#: view:ir.module.module:0
msgid "Schedule Upgrade"
msgstr ""
msgstr "Ieplānot Jauninājumus"
#. module: base
#: field:ir.actions.report.custom,report_id:0
@@ -593,7 +593,7 @@ msgstr ","
#. module: base
#: view:res.partner:0
msgid "My Partners"
msgstr ""
msgstr "Mani Partneri"
#. module: base
#: model:res.country,name:base.es
@@ -745,7 +745,7 @@ msgstr "Irāna"
#: model:ir.actions.act_window,name:base.res_request-act
#: model:ir.ui.menu,name:base.menu_res_request_act
msgid "My Requests"
msgstr ""
msgstr "Mani Pieprasījumi"
#. module: base
#: field:ir.sequence,name:0
@@ -1009,7 +1009,7 @@ msgstr "STOCK_COPY"
#: code:addons/base/ir/ir_model.py:0
#, python-format
msgid "Model %s Does not Exist !"
msgstr ""
msgstr "Modelis %s neeksistē !"
#. module: base
#: code:addons/base/module/module.py:0
@@ -1137,7 +1137,7 @@ msgstr "Lietotāja Atskaite"
#: code:addons/base/res/res_user.py:0
#, python-format
msgid " (copy)"
msgstr ""
msgstr " (kopija)"
#. module: base
#: view:ir.sequence:0
@@ -1303,7 +1303,7 @@ msgstr "Copy text \t STOCK_PROPERTIES"
#. module: base
#: view:res.partner.address:0
msgid "Search Contact"
msgstr ""
msgstr "Meklēt Kontaktu"
#. module: base
#: view:ir.module.module:0
@@ -1484,7 +1484,7 @@ msgstr "Esošā Likme"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "Greek / Ελληνικά"
msgstr ""
msgstr "Grieķu / Ελληνικά"
#. module: base
#: view:ir.values:0
@@ -1565,7 +1565,7 @@ msgstr "Epasta Adrese"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "French (BE) / Français (BE)"
msgstr ""
msgstr "Franču (BE) / Français (BE)"
#. module: base
#: code:addons/base/ir/ir_model.py:0
@@ -1603,7 +1603,7 @@ msgstr "Lauka Sasaistes"
#: model:ir.actions.act_window,name:base.res_request-closed
#: model:ir.ui.menu,name:base.next_id_12_close
msgid "My Closed Requests"
msgstr ""
msgstr "Mani Slēgie Pieprasījumi"
#. module: base
#: model:ir.ui.menu,name:base.menu_custom
@@ -1861,7 +1861,7 @@ msgstr "Pieejas Kontrole"
#: view:ir.module.module:0
#: field:ir.module.module,dependencies_id:0
msgid "Dependencies"
msgstr "Atkarīgie objekti"
msgstr "Atkarīgs no"
#. module: base
#: field:ir.report.custom.fields,bgcolor:0
@@ -1988,7 +1988,7 @@ msgstr "Modulis"
#: model:ir.actions.act_window,name:base.action_res_bank_form
#: model:ir.ui.menu,name:base.menu_action_res_bank_form
msgid "Bank List"
msgstr ""
msgstr "Banku Saraksts"
#. module: base
#: field:ir.attachment,description:0
@@ -2401,7 +2401,7 @@ msgstr ""
#: model:ir.actions.act_window,name:base.action_partner_customer_form
#: view:res.partner:0
msgid "Customers"
msgstr ""
msgstr "Klienti"
#. module: base
#: model:res.country,name:base.au
@@ -2603,7 +2603,7 @@ msgstr "STOCK_SAVE_AS"
#. module: base
#: selection:ir.translation,type:0
msgid "SQL Constraint"
msgstr ""
msgstr "SQL Ierobežojums"
#. module: base
#: field:ir.actions.server,srcmodel_id:0
@@ -2669,7 +2669,7 @@ msgstr "%c - Atbilstošais datuma un laika attēlojums."
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "Finland / Suomi"
msgstr ""
msgstr "Somu / Suomi"
#. module: base
#: model:res.country,name:base.bo
@@ -2931,7 +2931,7 @@ msgstr "Likmes"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "Albanian / Shqipëri"
msgstr ""
msgstr "Albāņu / Shqipëri"
#. module: base
#: model:res.country,name:base.sy
@@ -3192,7 +3192,7 @@ msgstr "Demo dati"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "English (UK)"
msgstr ""
msgstr "Angļu (UK)"
#. module: base
#: model:res.country,name:base.aq
@@ -3217,7 +3217,7 @@ msgstr "Tīmeklis"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "English (CA)"
msgstr ""
msgstr "Angļu (CA)"
#. module: base
#: field:res.partner.event,planned_revenue:0
@@ -3460,7 +3460,7 @@ msgstr "Partnera Adreses"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "Indonesian / Bahasa Indonesia"
msgstr ""
msgstr "Indonēziešu / Bahasa Indonesia"
#. module: base
#: model:res.country,name:base.cv
@@ -3625,7 +3625,7 @@ msgstr "Izveidot darbību"
#. module: base
#: selection:ir.actions.report.xml,report_type:0
msgid "HTML from HTML"
msgstr ""
msgstr "HTML no HTML"
#. module: base
#: selection:ir.actions.report.xml,report_type:0
@@ -4086,7 +4086,7 @@ msgstr "Faila Formāts"
#. module: base
#: field:res.lang,iso_code:0
msgid "ISO code"
msgstr ""
msgstr "ISO kods"
#. module: base
#: model:ir.model,name:base.model_res_config_view
@@ -4222,7 +4222,7 @@ msgstr "Izmainīt manus Uzstādījumus"
#. module: base
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
msgstr "Procesa definīcijā nepareizs modeļa nosaukums."
#. module: base
#: wizard_field:res.partner.sms_send,init,text:0
@@ -4344,7 +4344,7 @@ msgstr "Objekta Lauks"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "French (CH) / Français (CH)"
msgstr ""
msgstr "Franču (CH) / Français (CH)"
#. module: base
#: selection:ir.ui.menu,icon:0
@@ -4418,7 +4418,7 @@ msgstr "Atcelt atinstalāciju"
#: view:res.partner:0
#: view:res.partner.address:0
msgid "Communication"
msgstr ""
msgstr "Saziņa"
#. module: base
#: model:ir.model,name:base.model_ir_server_object_lines
@@ -6981,7 +6981,7 @@ msgstr "(year)="
#. module: base
#: rml:ir.module.reference:0
msgid "Dependencies :"
msgstr "Atkarīgie objekti:"
msgstr "Atkarīgs no:"
#. module: base
#: selection:ir.ui.menu,icon:0
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-11 05:58+0000\n"
"PO-Revision-Date: 2010-05-23 04:30+0000\n"
"Last-Translator: Anders Wallenquist <anders.wallenquist@vertel.se>\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: 2010-05-12 04:19+0000\n"
"X-Launchpad-Export-Date: 2010-05-24 03:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-11 05:47+0000\n"
"PO-Revision-Date: 2010-05-23 04:34+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.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: 2010-05-12 04:19+0000\n"
"X-Launchpad-Export-Date: 2010-05-24 03:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-11 06:16+0000\n"
"PO-Revision-Date: 2010-05-23 04:32+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\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: 2010-05-12 04:20+0000\n"
"X-Launchpad-Export-Date: 2010-05-24 03:46+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+1
View File
@@ -28,6 +28,7 @@ import ir_actions
import ir_report_custom
import ir_attachment
import ir_cron
import ir_filters
import ir_values
import ir_translation
import ir_exports
+54 -3
View File
@@ -230,8 +230,59 @@
</record>
<menuitem id="next_id_6" name="Actions" parent="base.next_id_4"/>
<menuitem action="ir_sequence_actions" id="menu_ir_sequence_actions" parent="next_id_6"/>
<!-- Filters form view-->
<record id="act_report_custom_view" model="ir.ui.view">
<record id="ir_filters_view_form" model="ir.ui.view">
<field name="name">ir.filters.form</field>
<field name="model">ir.filters</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Filters">
<field name="name" select="1"/>
<field name="user_id" select="1"/>
<field name="model_id"/>
<newline/>
<field name="domain"/>
<field name="context"/>
</form>
</field>
</record>
<!-- Filters tree view-->
<record id="ir_filters_view_tree" model="ir.ui.view">
<field name="name">ir.filters.tree</field>
<field name="model">ir.filters</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Filters">
<field name="name" select="1"/>
<field name="user_id" select="1"/>
<field name="model_id"/>
<field name="domain"/>
<field name="context"/>
</tree>
</field>
</record>
<!-- Filters action-->
<record id="actions_ir_filters_view" model="ir.actions.act_window">
<field name="name">Filters</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.filters</field>
<field name="view_type">form</field>
<field name="view_id" ref="ir_filters_view_tree"/>
</record>
<!-- Filters view menu-->
<menuitem parent="base.next_id_6" name="Filters"
id="menu_ir_filters" action="actions_ir_filters_view" />
<record id="act_report_custom_view" model="ir.ui.view">
<field name="name">ir.actions.report.custom</field>
<field name="model">ir.actions.report.custom</field>
<field name="type">form</field>
@@ -1251,14 +1302,14 @@
<field name="subject" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<field name="message" select="2" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e.[[ object.partner_id.name ]]" align="0.0"/>
<label colspan="4" string="Access all the fields related to the current object using expressions, i.e. object.partner_id.name " align="0.0"/>
</page>
<page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}">
<separator colspan="4" string="SMS Configuration"/>
<field name="mobile" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','sms')]}"/>
<field name="sms" colspan="4" attrs="{'required':[('state','=','sms')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
<label colspan="4" string="Access all the fields related to the current object using expressions, i.e. object.partner_id.name " align="0.0"/>
</page>
<page string="Create / Write / Copy" attrs="{'invisible':[('state','!=','object_create'), ('state','!=','object_write'), ('state','!=','object_copy')]}">
<separator colspan="4" string="Fields Mapping"/>
+22 -16
View File
@@ -455,7 +455,7 @@ class actions_server(osv.osv):
'type': lambda *a: 'ir.actions.server',
'sequence': lambda *a: 5,
'code': lambda *a: """# You can use the following variables
# - object
# - object or obj
# - time
# - cr
# - uid
@@ -532,7 +532,6 @@ class actions_server(osv.osv):
def run(self, cr, uid, ids, context={}):
logger = netsvc.Logger()
for action in self.browse(cr, uid, ids, context):
obj_pool = self.pool.get(action.model_id.model)
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
@@ -554,19 +553,26 @@ class actions_server(osv.osv):
return self.pool.get(action.action_id.type)\
.read(cr, uid, action.action_id.id, context=context)
if action.state == 'code':
localdict = {
'self': self.pool.get(action.model_id.model),
'context': context,
'time': time,
'ids': ids,
'cr': cr,
'uid': uid,
'object':obj
}
exec action.code in localdict
if 'action' in localdict:
return localdict['action']
if config['server_actions_allow_code']:
localdict = {
'self': self.pool.get(action.model_id.model),
'context': context,
'time': time,
'ids': ids,
'cr': cr,
'uid': uid,
'object':obj,
'obj': obj,
}
exec action.code in localdict
if 'action' in localdict:
return localdict['action']
else:
netsvc.Logger().notifyChannel(
self._name, netsvc.LOG_ERROR,
"%s is a `code` server action, but "
"it isn't allowed in this configuration.\n\n"
"See server options to enable it"%action)
if action.state == 'email':
user = config['email_from']
@@ -580,7 +586,7 @@ class actions_server(osv.osv):
logger.notifyChannel('email', netsvc.LOG_INFO, 'Partner Email address not Specified!')
continue
if not user:
raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !"))
raise osv.except_osv(_('Error'), _("Please specify server option --email-from !"))
subject = self.merge_message(cr, uid, action.subject, action, context)
body = self.merge_message(cr, uid, action.message, action, context)
+3
View File
@@ -146,16 +146,19 @@ class ir_cron(osv.osv, netsvc.Agent):
def create(self, cr, uid, vals, context=None):
res = super(ir_cron, self).create(cr, uid, vals, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
def write(self, cr, user, ids, vals, context=None):
res = super(ir_cron, self).write(cr, user, ids, vals, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
def unlink(self, cr, uid, ids, context=None):
res = super(ir_cron, self).unlink(cr, uid, ids, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
ir_cron()
+45
View File
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
class ir_filters(osv.osv):
'''
Filters
'''
_name = 'ir.filters'
_description = 'Filters'
def _list_all_models(self, cr, uid, context=None):
cr.execute("SELECT model, name from ir_model")
return cr.fetchall()
_columns = {
'name': fields.char('Action Name', size=64, translate=True, required=True),
'user_id':fields.many2one('res.users', 'User', help='False means for every user'),
'domain': fields.char('Domain Value', size=250, required=True),
'context': fields.char('Context Value', size=250, required=True),
'model_id': fields.selection(_list_all_models, 'Model', required=True),
}
ir_filters()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+7 -3
View File
@@ -82,6 +82,8 @@ class ir_model(osv.osv):
return super(ir_model,self).write(cr, user, ids, vals, context)
def create(self, cr, user, vals, context=None):
if context is None:
context = {}
if context and context.get('manual',False):
vals['state']='manual'
res = super(ir_model,self).create(cr, user, vals, context)
@@ -260,6 +262,8 @@ class ir_model_fields(osv.osv):
if 'model_id' in vals:
model_data = self.pool.get('ir.model').browse(cr, user, vals['model_id'])
vals['model'] = model_data.model
if context is None:
context = {}
if context and context.get('manual',False):
vals['state'] = 'manual'
res = super(ir_model_fields,self).create(cr, user, vals, context)
@@ -267,7 +271,7 @@ class ir_model_fields(osv.osv):
if not vals['name'].startswith('x_'):
raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !"))
if 'relation' in vals and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]):
if vals.get('relation',False) and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]):
raise except_orm(_('Error'), _("Model %s Does not Exist !" % vals['relation']))
if self.pool.get(vals['model']):
@@ -286,7 +290,7 @@ class ir_model_access(osv.osv):
_columns = {
'name': fields.char('Name', size=64, required=True),
'model_id': fields.many2one('ir.model', 'Object', required=True),
'group_id': fields.many2one('res.groups', 'Group'),
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade'),
'perm_read': fields.boolean('Read Access'),
'perm_write': fields.boolean('Write Access'),
'perm_create': fields.boolean('Create Access'),
@@ -453,7 +457,7 @@ class ir_model_data(osv.osv):
def _get_id(self, cr, uid, module, xml_id):
ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
if not ids:
raise Exception('No references to %s.%s' % (module, xml_id))
raise ValueError('No references to %s.%s' % (module, xml_id))
# the sql constraints ensure us we have only one result
return ids[0]
+6 -6
View File
@@ -150,8 +150,8 @@ class ir_translation(osv.osv):
if not context:
context = {}
ids = super(ir_translation, self).create(cursor, user, vals, context=context)
for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
return ids
@@ -159,16 +159,16 @@ class ir_translation(osv.osv):
if not context:
context = {}
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
return result
def unlink(self, cursor, user, ids, context=None):
if not context:
context = {}
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
result = super(ir_translation, self).unlink(cursor, user, ids, context=context)
return result
+22 -5
View File
@@ -31,6 +31,10 @@ def one_in(setA, setB):
return True
return False
def cond(C, X, Y):
if C: return X
return Y
class many2many_unique(fields.many2many):
def set(self, cr, obj, id, name, values, user=None, context=None):
if not values:
@@ -63,16 +67,24 @@ class ir_ui_menu(osv.osv):
# radical but this doesn't frequently happen
self._cache = {}
def search(self, cr, uid, args, offset=0, limit=2000, order=None,
context=None, count=False):
if context is None:
context = {}
ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order, context=context, count=(count and uid==1))
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
super_offset = cond(uid == 1, offset, 0)
super_limit = cond(uid == 1, limit, None)
super_count = cond(uid == 1, count, False)
ids = super(ir_ui_menu, self).search(cr, uid, args, super_offset,
super_limit, order,
context=context, count=super_count)
if uid == 1 or count:
return ids
if not ids:
if count:
return 0
return []
modelaccess = self.pool.get('ir.model.access')
user_groups = set(self.pool.get('res.users').read(cr, 1, uid, ['groups_id'])['groups_id'])
@@ -120,6 +132,11 @@ class ir_ui_menu(osv.osv):
result.append(menu.id)
self._cache[key] = True
if offset:
result = result[long(offset):]
if limit:
result = result[:long(limit)]
if count:
return len(result)
return result
+4
View File
@@ -200,6 +200,10 @@ class view_sc(osv.osv):
'resource': lambda *a: 'ir.ui.menu',
'user_id': lambda obj, cr, uid, context: uid,
}
_sql_constraints = [
('shortcut_unique', 'unique(res_id, user_id)', 'Shortcut for this menu already exists!'),
]
view_sc()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,16 @@
# -*- coding: utf8 -*-
__name__ = "res.partner.address: change type of 'function' field many2one to char"
def migrate(cr, version):
change_column_type(cr,'res_partner_address')
def change_column_type(cr,table):
cr.execute('SELECT id, name FROM res_partner_function')
all_function = cr.fetchall()
cr.execute('ALTER TABLE %s ADD COLUMN temp_function VARCHAR(64)' % table)
for fn in all_function:
cr.execute("UPDATE %s SET temp_function = '%s' WHERE function = %s" % (table,fn[1],fn[0]))
cr.execute("ALTER TABLE %s DROP COLUMN function CASCADE" % table)
cr.execute("ALTER TABLE %s RENAME COLUMN temp_function TO function" % table)
+6 -4
View File
@@ -146,11 +146,13 @@ class module(osv.osv):
], string='State', readonly=True),
'demo': fields.boolean('Demo data'),
'license': fields.selection([
('GPL-2', 'GPL-2'),
('GPL-2', 'GPL Version 2'),
('GPL-2 or any later version', 'GPL-2 or later version'),
('GPL-3', 'GPL-3'),
('GPL-3', 'GPL Version 3'),
('GPL-3 or any later version', 'GPL-3 or later version'),
('Other proprietary', 'Other proprietary')
('AGPL-3', 'Affero GPL-3'),
('Other OSI approved licence', 'Other OSI Approved Licence'),
('Other proprietary', 'Other Proprietary')
], string='License', readonly=True),
'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta", store=True),
'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta", store=True),
@@ -161,7 +163,7 @@ class module(osv.osv):
_defaults = {
'state': lambda *a: 'uninstalled',
'demo': lambda *a: False,
'license': lambda *a: 'GPL-2',
'license': lambda *a: 'AGPL-3',
}
_order = 'name'
+1 -3
View File
@@ -31,8 +31,6 @@ import res_company
import res_user
import res_request
import res_lang
import res_log
import ir_property
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

+1 -2
View File
@@ -40,8 +40,7 @@ class ir_property(osv.osv):
return res
def _models_get(self, cr, uid, context=None):
return self._models_field_get(cr, uid, 'model_id.model', 'model_id.name',
context)
return self._models_field_get(cr, uid, 'model', 'name', context)
def _models_get2(self, cr, uid, context=None):
return self._models_field_get(cr, uid, 'relation', 'relation', context)
+7 -22
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -27,21 +27,6 @@ import ir
import pooler
from tools.translate import _
class res_partner_function(osv.osv):
_name = 'res.partner.function'
_description = 'Function of the contact'
_columns = {
'name': fields.char('Function Name', size=64, required=True),
'code': fields.char('Code', size=8, required=True),
'ref':fields.char('Notes', size=32,),
}
_order = 'name'
_sql_constraints = [
('code_uniq', 'unique (code)', 'The Code of the Partner Function must be unique !')
]
res_partner_function()
class res_payterm(osv.osv):
_description = 'Payment term'
_name = 'res.payterm'
@@ -149,12 +134,12 @@ class res_partner(osv.osv):
'active': fields.boolean('Active'),
'customer': fields.boolean('Customer', help="Check this box if the partner is a customer."),
'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."),
'city': fields.related('address', 'city', type='char', string='City'),
'phone': fields.related('address', 'phone', type='char', string='Phone'),
'city': fields.related('address', 'city', type='char', string='City'),
'phone': fields.related('address', 'phone', type='char', string='Phone'),
'country': fields.related('address', 'country_id', type='many2one', relation='res.country', string='Country'),
'employee': fields.boolean('Employee', help="Check this box if the partner is an Employee."),
'email': fields.related('address', 'email', type='char', size=240, string='E-mail'),
'company_id': fields.many2one('res.company', 'Company', select=1),
'company_id': fields.many2one('res.company', 'Company', select=1),
}
def _default_category(self, cr, uid, context={}):
@@ -291,7 +276,7 @@ class res_partner_address(osv.osv):
_columns = {
'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', select=True, help="Keep empty for a private address, not related to partner."),
'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."),
'function': fields.many2one('res.partner.function', 'Function'),
'function': fields.char('Function', size=64),
'title': fields.selection(_contact_title_get, 'Title', size=32),
'name': fields.char('Contact Name', size=64, select=1),
'street': fields.char('Street', size=128),
@@ -469,7 +454,7 @@ class res_partner_category(osv.osv):
_columns = {
'partner_ids': fields.many2many('res.partner', 'res_partner_category_rel', 'category_id', 'partner_id', 'Partners'),
}
res_partner_category()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -33,19 +33,6 @@
<field name="shortcut">M.</field>
</record>
<record id="function_director" model="res.partner.function">
<field name="name">Director</field>
<field name="code">CEO</field>
</record>
<record id="function_it" model="res.partner.function">
<field name="name">Chief Technical Officer</field>
<field name="code">CTO</field>
</record>
<record id="function_sale" model="res.partner.function">
<field name="name">Salesman</field>
<field name="code">SAL</field>
</record>
<!-- Default bank account description -->
<record id="bank_normal" model="res.partner.bank.type">
<field name="name">Bank account</field>
+21 -1
View File
@@ -275,6 +275,26 @@
<field name="type">default</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_8delivery" model="res.partner.address">
<field name="city">Wavre</field>
<field name="name">Paul Lelitre</field>
<field name="zip">5478</field>
<field name="title">M.</field>
<field model="res.country" name="country_id" search="[('name','=','Belgium')]"/>
<field name="street">71 rue de Chimay</field>
<field name="type">delivery</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_8invoice" model="res.partner.address">
<field name="city">Wavre</field>
<field name="name">Serge Lelitre</field>
<field name="zip">5478</field>
<field name="title">M.</field>
<field model="res.country" name="country_id" search="[('name','=','Belgium')]"/>
<field name="street">69 rue de Chimay</field>
<field name="type">invoice</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_9" model="res.partner.address">
<field name="city">Paris</field>
<field name="name">Arthur Grosbonnet</field>
@@ -357,7 +377,7 @@
<record id="res_partner_asustek_request" model="res.request">
<field name="name">ASUSTEK-Subject</field>
<field name="act_to" ref="user_demo"/>
<field name="ref_doc1">res.partner,2</field>
<field name="ref_doc1" ref="res_partner_asus"/>
</record>
</data>
</openerp>
+9 -41
View File
@@ -9,41 +9,6 @@
<menuitem id="menu_base_config_partner" name="Partners" parent="menu_base_config" sequence="10" groups="base.group_extended"/>
<menuitem id="menu_base_config_contact" name="Contacts" parent="menu_base_config" sequence="20" />
<!--
================================
Function
================================
-->
<record id="view_partner_function_form" model="ir.ui.view">
<field name="name">res.partner.function.form</field>
<field name="model">res.partner.function</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Contact Functions">
<field name="name" select="1"/>
<field name="code" select="1"/>
</form>
</field>
</record>
<record id="view_partner_function_tree" model="ir.ui.view">
<field name="name">res.partner.function.tree</field>
<field name="model">res.partner.function</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Contact Functions">
<field name="code"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="action_partner_function_form" model="ir.actions.act_window">
<field name="name">Contact Functions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.function</field>
<field name="view_type">form</field>
</record>
<menuitem action="action_partner_function_form" id="menu_partner_function_form" parent="base.menu_base_config_contact" sequence="20"/>
<!--
=====================
Partner Address
@@ -347,24 +312,27 @@
<field name="arch" type="xml">
<search string="Search Partner">
<group col='10' colspan='4'>
<filter string="My Partners" icon="terp-partner" domain="[('user_id','=',uid)]"/>
<separator orientation="vertical"/>
<filter string="Customers" icon="terp-partner" domain="[('customer','=',1)]" help="Customer Partners"/>
<filter string="Suppliers" icon="terp-partner" domain="[('supplier','=',1)]" help="Supplier Partners"/>
<filter string="Employees" icon="terp-partner" domain="[('employee','=',1)]" help="Employee Partners"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="address" select="1"/>
<field name="country" select="1"/>
<field name="category_id" select="1"/>
<field name="user_id" select="1"/>
<field name="user_id" select="1">
<filter string="My Partners" icon="terp-partner" domain="[('user_id','=',uid)]"/>
</field>
</group>
<newline />
<group expand="0" string="Group By..." colspan="16">
<filter string="Salesman" icon="terp-crm" domain="[]" context="{'group_by' : 'user_id'}" />
</group>
</search>
</field>
</record>
<record id="action_partner_form" model="ir.actions.act_window">
<field name="name">Partners</field>
<field name="name">Customers</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
@@ -639,7 +607,7 @@
/>
<record id="ir_ui_view_sc_partner0" model="ir.ui.view_sc">
<field name="name">Partner</field>
<field name="name">Address Book</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="menu_partner_form"/>
+10 -3
View File
@@ -25,7 +25,6 @@ import os
import tools
from tools.translate import _
class multi_company_default(osv.osv):
"""
Manage multi company default value
@@ -85,7 +84,8 @@ class res_company(osv.osv):
'logo' : fields.binary('Logo'),
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
'currency_ids': fields.one2many('res.currency', 'company_id', 'Currency'),
'user_ids': fields.many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', 'Accepted Users')
'user_ids': fields.many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', 'Accepted Users'),
'account_no':fields.char('Account No.', size=64),
}
def search(self, cr, uid, args, offset=0, limit=None, order=None,
@@ -179,6 +179,12 @@ class res_company(osv.osv):
level -= 1
return True
def _get_logo(self, cr, uid, ids):
return open(os.path.join(
tools.config['root_path'], '..', 'pixmaps', 'openerp-header.png'),
'rb') .read().encode('base64')
def _get_header2(self,cr,uid,ids):
return """
<header>
@@ -240,7 +246,8 @@ class res_company(osv.osv):
_defaults = {
'currency_id': _get_euro,
'rml_header':_get_header,
'rml_header2': _get_header2
'rml_header2': _get_header2,
'logo':_get_logo
}
_constraints = [
+4 -3
View File
@@ -60,11 +60,11 @@ class lang(osv.osv):
('name_uniq', 'unique (name)', 'The name of the language must be unique !'),
('code_uniq', 'unique (code)', 'The code of the language must be unique !'),
]
@tools.cache(skiparg=3)
def _lang_data_get(self, cr, uid, lang_id, monetary=False):
conv = localeconv()
lang_obj=self.browse(cr,uid,lang_id)
lang_obj = self.browse(cr, uid, lang_id)
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
decimal_point = lang_obj.decimal_point
grouping = lang_obj.grouping
@@ -80,6 +80,7 @@ class lang(osv.osv):
if not grouping:
return (s, 0)
result = ""
seps = 0
spaces = ""
@@ -129,7 +130,7 @@ class lang(osv.osv):
parts = formatted.split('.')
if grouping:
parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary, grouping=lang_grouping, thousands_sep=thousands_sep)
parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary, grouping=lang_grouping, thousands_sep=thousands_sep)
formatted = decimal_point.join(parts)
while seps:
+44
View File
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields, osv
class res_log(osv.osv_memory):
_name = 'res.log'
_columns = {
'name': fields.char('Message', size=128, help='The logging message.', required=True),
'user_id': fields.many2one('res.users','User', required=True),
'res_model': fields.char('Object', size=128),
'res_id': fields.integer('Object ID'),
'secondary': fields.boolean('Secondary Log', help='Do not display this log if it belongs to the same object the user is working on')
}
_defaults = {
'user_id': lambda self,cr,uid,ctx: uid
}
_order='id desc'
# TODO: do not return secondary log if same object than in the model (but unlink it)
def get(self, cr, uid, context={}):
ids = self.search(cr, uid, [('user_id','=',uid)], context=context)
result = self.read(cr, uid, ids, ['name','res_model','res_id'], context=context)
self.unlink(cr, uid, ids, context=context)
return result
res_log()
+56
View File
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="res_log_search" model="ir.ui.view">
<field name="name">res.log.search</field>
<field name="model">res.log</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Logs">
<filter icon="terp-sale" string="My Logs" domain="[('user_id','=',uid)]" name="my"/>
<separator orientation="vertical"/>
<field name="name"/>
<field name="user_id"/>
<field name="res_model"/>
</search>
</field>
</record>
<record id="res_log_tree" model="ir.ui.view">
<field name="name">res.log.tree</field>
<field name="model">res.log</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Logs">
<field name="name"/>
<field name="user_id"/>
</tree>
</field>
</record>
<record id="res_log_form" model="ir.ui.view">
<field name="name">res.log.form</field>
<field name="model">res.log</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Logs">
<group colspan="4" col="6">
<field name="name" colspan="4"/>
<field name="user_id" />
<field name="res_model"/>
<field name="res_id"/>
</group>
</form>
</field>
</record>
<record id="res_log_act_window" model="ir.actions.act_window">
<field name="name">Logs</field>
<field name="res_model">res.log</field>
<field name="view_type">form</field>
<field name="context">{'search_default_my': 1}</field>
</record>
<menuitem
action="res_log_act_window"
id="menu_res_log_act_window"
parent="base.next_id_4"/>
</data>
</openerp>
+7 -3
View File
@@ -6,9 +6,13 @@
<field name="name">Partner Manager</field>
</record>
<record model="ir.ui.menu" id="menu_base_config">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="menu_base_partner">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="menu_base_config">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
</data>
</openerp>
+74 -10
View File
@@ -22,6 +22,7 @@
from osv import fields,osv
from osv.orm import except_orm, browse_record
import tools
import operator
import pytz
import pooler
from tools.translate import _
@@ -82,6 +83,11 @@ class groups(osv.osv):
default['name'] = default['name'] + _(' (copy)')
return super(groups, self).copy(cr, uid, id, default, context=context)
def get_extended_interface_group(self, cr, uid, context=None):
data_obj = self.pool.get('ir.model.data')
extended_group_data_id = data_obj._get_id(cr, uid, 'base', 'group_extended')
return data_obj.browse(cr, uid, extended_group_data_id, context=context).res_id
groups()
class roles(osv.osv):
@@ -106,10 +112,11 @@ roles()
def _lang_get(self, cr, uid, context={}):
obj = self.pool.get('res.lang')
ids = obj.search(cr, uid, [])
ids = obj.search(cr, uid, [('translatable','=',True)])
res = obj.read(cr, uid, ids, ['code', 'name'], context)
res = [(r['code'], r['name']) for r in res]
return res
def _tz_get(self,cr,uid, context={}):
return [(x, x) for x in pytz.all_timezones]
@@ -166,6 +173,47 @@ class users(osv.osv):
body=self.get_welcome_mail_body(
cr, uid, context=context) % user)
def _set_interface_type(self, cr, uid, ids, name, value, arg, context=None):
"""Implementation of 'view' function field setter, sets the type of interface of the users.
@param name: Name of the field
@param arg: User defined argument
@param value: new value returned
@return: True/False
"""
if not value or value not in ['simple','extended']:
return False
group_obj = self.pool.get('res.groups')
extended_group_id = group_obj.get_extended_interface_group(cr, uid, context=context)
self.write(cr, uid, ids, { 'groups_id': [((3 if value == 'simple' else 4), extended_group_id)]}, context=context)
return True
def _get_interface_type(self, cr, uid, ids, name, args, context=None):
"""Implementation of 'view' function field getter, returns the type of interface of the users.
@param field_name: Name of the field
@param arg: User defined argument
@return: Dictionary of values
"""
group_obj = self.pool.get('res.groups')
extended_group_id = group_obj.get_extended_interface_group(cr, uid, context=context)
extended_users = group_obj.read(cr, uid, extended_group_id, ['users'], context=context)['users']
return dict(zip(ids, ['extended' if user in extended_users else 'simple' for user in ids]))
def _email_get(self, cr, uid, ids, name, arg, context=None):
return dict(map(operator.attrgetter('id', 'address_id.email'), self.browse(cr, uid, ids, context=context)))
def _email_set(self, cr, uid, ids, name, value, arg, context=None):
if not isinstance(ids,list):
ids = [ids]
address_obj = self.pool.get('res.partner.address')
for user in self.browse(cr, uid, ids, context=context):
if user.address_id:
address_obj.write(cr, uid, user.address_id.id, {'email': value or None}, context=context)
else:
address_id = address_obj.create(cr, uid, {'name': user.name, 'email': value or None}, context=context)
self.write(cr, uid, ids, {'address_id': address_id}, context)
return True
_columns = {
'name': fields.char('Name', size=64, required=True, select=True,
help="The new user's real name, used for searching"
@@ -194,7 +242,12 @@ class users(osv.osv):
'context_tz': fields.selection(_tz_get, 'Timezone', size=64,
help="The user's timezone, used to perform timezone conversions "
"between the server and the client."),
'view': fields.function(_get_interface_type, method=True, type='selection', fnct_inv=_set_interface_type,
selection=[('simple','Simplified'),('extended','Extended')],
string='Interface', help="Choose between the simplified interface and the extended one"),
'user_email': fields.function(_email_get, method=True, fnct_inv=_email_set, string='Email', type="char"),
}
def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'):
def override_password(o):
if 'password' in o and ( 'id' not in o or o['id'] != uid ):
@@ -208,6 +261,15 @@ class users(osv.osv):
result = override_password(result)
else:
result = map(override_password, result)
if isinstance(result, list):
for rec in result:
if not rec.get('action_id',True):
rec['action_id'] = (self._get_menu(cr, uid),'Menu')
else:
if not result.get('action_id',True):
result['action_id'] = (self._get_menu(cr, uid),'Menu')
return result
@@ -430,6 +492,13 @@ class groups2(osv.osv): ##FIXME: Is there a reason to inherit this object ?
_columns = {
'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
}
def unlink(self, cr, uid, ids, context=None):
for record in self.read(cr, uid, ids, ['users'], context=context):
if record['users']:
raise osv.except_osv(_('Warning !'), _('Make sure you have no users linked with the group(s)!'))
return super(groups2, self).unlink(cr, uid, ids, context=context)
groups2()
class res_config_view(osv.osv_memory):
@@ -446,15 +515,10 @@ class res_config_view(osv.osv_memory):
}
def execute(self, cr, uid, ids, context=None):
res=self.read(cr,uid,ids)[0]
users_obj = self.pool.get('res.users')
group_obj=self.pool.get('res.groups')
if 'view' in res and res['view'] and res['view']=='extended':
group_ids=group_obj.search(cr,uid,[('name','ilike','Extended')])
if group_ids and len(group_ids):
users_obj.write(cr, uid, [uid],{
'groups_id':[(4,group_ids[0])]
}, context=context)
res = self.read(cr, uid, ids)[0]
self.pool.get('res.users').write(cr, uid, [uid],
{'view':res['view']}, context=context)
res_config_view()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1 -3
View File
@@ -19,7 +19,7 @@
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
"access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1
"access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,1
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,0
"access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0
"access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0
"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0
@@ -73,8 +73,6 @@
"access_res_partner_event_group_partner_manager","res_partner_event group_partner_manager","model_res_partner_event","group_partner_manager",1,1,1,1
"access_res_partner_event_type_group_partner_manager","res_partner_event_type group_partner_manager","model_res_partner_event_type","group_partner_manager",1,1,1,1
"access_res_partner_event_type_group_user","res_partner_event_type group_user","model_res_partner_event_type","group_user",1,0,0,0
"access_res_partner_function_group_user","res_partner_function group_user","model_res_partner_function","group_partner_manager",1,1,1,1
"access_res_partner_function_group_partner_manager","res_partner_function group_partner_manager","model_res_partner_function","group_user",1,0,0,0
"access_res_partner_som_group_user","res_partner_som group_user","model_res_partner_som","group_partner_manager",1,1,1,1
"access_res_partner_som_group_partner_manager","res_partner_som group_partner_manager","model_res_partner_som","group_user",1,0,0,0
"access_res_partner_title_group_user","res_partner_title group_user","model_res_partner_title","group_partner_manager",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
19 access_ir_module_module_group_user ir_module_module group_user model_ir_module_module group_system 1 1 1 1
20 access_ir_module_module_dependency_group_system ir_module_module_dependency group_system model_ir_module_module_dependency group_system 1 1 1 1
21 access_ir_property_group_user ir_property group_user model_ir_property 1 0 0 0
22 access_ir_property_group_user_manager ir_property group_manager model_ir_property base.group_partner_manager 1 1 1 1 0
23 access_ir_report_custom_group_system ir_report_custom group_system model_ir_report_custom 1 0 0 0
24 access_ir_report_custom_fields_group_system ir_report_custom_fields group_system model_ir_report_custom_fields 1 0 0 0
25 access_ir_rule_group_user ir_rule group_user model_ir_rule 1 0 0 0
73 access_res_partner_event_group_partner_manager res_partner_event group_partner_manager model_res_partner_event group_partner_manager 1 1 1 1
74 access_res_partner_event_type_group_partner_manager res_partner_event_type group_partner_manager model_res_partner_event_type group_partner_manager 1 1 1 1
75 access_res_partner_event_type_group_user res_partner_event_type group_user model_res_partner_event_type group_user 1 0 0 0
access_res_partner_function_group_user res_partner_function group_user model_res_partner_function group_partner_manager 1 1 1 1
access_res_partner_function_group_partner_manager res_partner_function group_partner_manager model_res_partner_function group_user 1 0 0 0
76 access_res_partner_som_group_user res_partner_som group_user model_res_partner_som group_partner_manager 1 1 1 1
77 access_res_partner_som_group_partner_manager res_partner_som group_partner_manager model_res_partner_som group_user 1 0 0 0
78 access_res_partner_title_group_user res_partner_title group_user model_res_partner_title group_partner_manager 1 1 1 1
+4 -3
View File
@@ -47,11 +47,12 @@
<rng:define name="assert">
<rng:element name="assert">
<rng:attribute name="model" />
<rng:optional><rng:attribute name="search" /> </rng:optional>
<rng:optional><rng:attribute name="search" /></rng:optional>
<rng:optional><rng:attribute name="count" /></rng:optional>
<rng:optional><rng:attribute name="string" /></rng:optional>
<rng:optional><rng:attribute name="id" /></rng:optional>
<rng:optional><rng:attribute name="severity" /></rng:optional>
<rng:oneOrMore>
<rng:zeroOrMore>
<rng:element name="test">
<rng:attribute name="expr"/>
<rng:choice>
@@ -59,7 +60,7 @@
<rng:empty />
</rng:choice>
</rng:element>
</rng:oneOrMore>
</rng:zeroOrMore>
</rng:element>
</rng:define>
+19 -1
View File
@@ -24,9 +24,11 @@
#
##############################################################################
import errno
import logging
import logging.handlers
import os
import socket
import sys
import threading
import time
@@ -358,6 +360,21 @@ class Server:
res.extend(srv.stats() for srv in cls.__servers)
return '\n'.join(res)
def _close_socket(self):
if os.name != 'nt':
try:
self.socket.shutdown(getattr(socket, 'SHUT_RDWR', 2))
except socket.error, e:
if e.errno != errno.ENOTCONN: raise
# OSX, socket shutdowns both sides if any side closes it
# causing an error 57 'Socket is not connected' on shutdown
# of the other side (or something), see
# http://bugs.python.org/issue4397
self.__logger.debug(
'"%s" when shutting down server socket, '
'this is normal under OS X', e)
self.socket.close()
class OpenERPDispatcherException(Exception):
def __init__(self, exception, traceback):
self.exception = exception
@@ -365,7 +382,8 @@ class OpenERPDispatcherException(Exception):
class OpenERPDispatcher:
def log(self, title, msg):
Logger().notifyChannel('%s' % title, LOG_DEBUG_RPC, pformat(msg))
if tools.config['log_level'] == logging.DEBUG_RPC:
Logger().notifyChannel('%s' % title, LOG_DEBUG_RPC, pformat(msg))
def dispatch(self, service_name, method, params):
try:
+5 -2
View File
@@ -280,8 +280,11 @@ class expression(object):
c = context.copy()
c['active_test'] = False
res_ids = field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)
right = map(lambda x: x[0], res_ids)
self.__exp[i] = (left, 'in', right)
if not res_ids:
self.__exp[i] = ('id','=',0)
else:
right = map(lambda x: x[0], res_ids)
self.__exp[i] = (left, 'in', right)
else:
# other field type
# add the time part to datetime field when it's not there:
+2 -2
View File
@@ -39,7 +39,7 @@ from psycopg2 import Binary
import warnings
import tools
from tools.translate import _
def _symbol_set(symb):
if symb == None or symb == False:
@@ -748,7 +748,7 @@ class related(function):
ids=[ids]
objlst = obj.browse(cr, uid, ids)
for data in objlst:
t_id=None
t_id = None
t_data = data
relation = obj._name
for i in range(len(self.arg)):
+135 -62
View File
@@ -49,6 +49,7 @@ import string
import sys
import time
import traceback
import datetime
import types
import fields
@@ -58,6 +59,7 @@ from tools.translate import _
import copy
import sys
import operator
try:
from lxml import etree
@@ -86,7 +88,6 @@ def last_day_of_current_month():
def intersect(la, lb):
return filter(lambda x: x in lb, la)
class except_orm(Exception):
def __init__(self, name, value):
self.name = name
@@ -276,7 +277,7 @@ class browse_record(object):
else:
new_data[n] = data[n]
self._data[data['id']].update(new_data)
if not name in self._data[self._id]:
#how did this happen?
self.logger.notifyChannel("browse_record", netsvc.LOG_ERROR,
@@ -398,8 +399,17 @@ class orm_template(object):
_inherits = {}
_table = None
_invalids = set()
_log_create = False
CONCURRENCY_CHECK_FIELD = '__last_update'
def log(self, cr, uid, id, message, secondary=False, context=None):
return self.pool.get('res.log').create(cr, uid, {
'name': message,
'res_model': self._name,
'secondary': secondary,
'res_id': id},
context=context
)
def view_init(self, cr , uid , fields_list, context=None):
"""Override this method to do specific things when a view on the object is opened."""
@@ -438,7 +448,7 @@ class orm_template(object):
'name': k,
'field_description': f.string.replace("'", " "),
'ttype': f._type,
'relation': f._obj or 'NULL',
'relation': f._obj or '',
'view_load': (f.view_load and 1) or 0,
'select_level': tools.ustr(f.select or 0),
'readonly':(f.readonly and 1) or 0,
@@ -535,6 +545,8 @@ class orm_template(object):
return browse_null()
def __export_row(self, cr, uid, row, fields, context=None):
if context is None:
context = {}
def check_type(field_type):
if field_type == 'float':
@@ -588,9 +600,9 @@ class orm_template(object):
cols = selection_field(self._inherits)
if cols and cols._type == 'selection':
sel_list = cols.selection
if type(sel_list) == type([]):
r = [x[1] for x in sel_list if r==x[0]][0]
if r and type(sel_list) == type([]):
r = [x[1] for x in sel_list if r==x[0]]
r = r and r[0] or False
if not r:
if f[i] in self._columns:
r = check_type(self._columns[f[i]]._type)
@@ -617,7 +629,7 @@ class orm_template(object):
for rr in r :
if isinstance(rr.name, browse_record):
rr = rr.name
rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id])
rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id], context=context)
rr_name = rr_name and rr_name[0] and rr_name[0][1] or ''
dt += tools.ustr(rr_name or '') + ','
data[fpos] = dt[:-1]
@@ -630,7 +642,7 @@ class orm_template(object):
i += 1
if i == len(f):
if isinstance(r, browse_record):
r = self.pool.get(r._table_name).name_get(cr, uid, [r.id])
r = self.pool.get(r._table_name).name_get(cr, uid, [r.id], context=context)
r = r and r[0] and r[0][1] or ''
data[fpos] = tools.ustr(r or '')
return [data] + lines
@@ -786,12 +798,12 @@ class orm_template(object):
module, xml_id = line[i].rsplit('.', 1)
else:
module, xml_id = current_module, line[i]
id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
res_res_id = ir_model_data_obj.read(cr, uid, [id],
['res_id'])
if res_res_id:
res_id = res_res_id[0]['res_id']
record_id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
ir_model_data = ir_model_data_obj.read(cr, uid, [record_id], ['res_id'])
if ir_model_data:
res_id = ir_model_data[0]['res_id']
else:
raise ValueError('No references to %s.%s' % (module, xml_id))
row[field[-1][:-3]] = res_id or False
continue
if (len(field) == len(prefix)+1) and \
@@ -985,7 +997,8 @@ class orm_template(object):
msg = _('Insertion Failed! ' + e[1])
return (-1, res, 'Line ' + str(counter) +' : ' + msg, '' )
#Raising Uncaught exception
raise
return (-1, res, 'Line ' + str(counter) +' : ' + str(e), '' )
for lang in translate:
context2 = context.copy()
context2['lang'] = lang
@@ -994,6 +1007,8 @@ class orm_template(object):
data = pickle.load(file(config.get('import_partial')))
data[filename] = initial_size - len(datas) + original_value
pickle.dump(data, file(config.get('import_partial'),'wb'))
if context.get('defer_parent_store_computation'):
self._parent_store_compute(cr)
cr.commit()
#except Exception, e:
@@ -1007,6 +1022,8 @@ class orm_template(object):
#
# TODO: Send a request with the result and multi-thread !
#
if context.get('defer_parent_store_computation'):
self._parent_store_compute(cr)
return (done, 0, 0, 0)
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
@@ -1023,7 +1040,14 @@ class orm_template(object):
for constraint in self._constraints:
fun, msg, fields = constraint
if not fun(self, cr, uid, ids):
translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) or msg
# Check presence of __call__ directly instead of using
# callable() because it will be deprecated as of Python 3.0
if hasattr(msg, '__call__'):
txt_msg, params = msg(self, cr, uid, ids)
tmp_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=txt_msg) or txt_msg
translated_msg = tmp_msg % params
else:
translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) or msg
error_msgs.append(
_("Error occurred while validating the field(s) %s: %s") % (','.join(fields), translated_msg)
)
@@ -1092,8 +1116,7 @@ class orm_template(object):
if getattr(self._columns[f], arg, None):
res[f][arg] = getattr(self._columns[f], arg)
#TODO: optimize
res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US')
res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US', self._columns[f].string)
if res_trans:
res[f]['string'] = res_trans
help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context.get('lang', False) or 'en_US')
@@ -1708,7 +1731,8 @@ class orm_template(object):
for lang in langs:
for field in vals:
if field in self._columns:
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
src = self._columns[field].string
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field], src)
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), vals)
if cols:
@@ -1824,6 +1848,12 @@ class orm_memory(orm_template):
for field in upd_todo:
self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
self._validate(cr, user, [id_new], context)
if self._log_create and not (context and context.get('no_store_function', False)):
message = self._description + \
" '" + \
self.name_get(cr, user, [id_new], context=context)[0][1] + \
"' "+ _("created.")
self.log(cr, user, id_new, message, True, context=context)
wf_service = netsvc.LocalService("workflow")
wf_service.trg_create(user, self._name, id_new, cr)
return id_new
@@ -1911,7 +1941,6 @@ class orm_memory(orm_template):
res=e.__dict__['_expression__exp']
return res or []
def search(self, cr, user, args, offset=0, limit=None, order=None,
context=None, count=False):
if not context:
@@ -2116,6 +2145,8 @@ class orm(orm_template):
return (tables, where_clause)
def _parent_store_compute(self, cr):
if not self._parent_store:
return
logger = netsvc.Logger()
logger.notifyChannel('orm', netsvc.LOG_INFO, 'Computing parent left and right for table %s...' % (self._table, ))
def browse_rec(root, pos=0):
@@ -2204,8 +2235,8 @@ class orm(orm_template):
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)' % (self._table, ))
if 'parent_right' not in self._columns:
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, ))
if self._columns[self._parent_name].ondelete<>'cascade':
logger.notifyChannel('orm', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name))
if self._columns[self._parent_name].ondelete != 'cascade':
logger.notifyChannel('orm', netsvc.LOG_ERROR, "The column %s on object %s must be set as ondelete='cascade'" % (self._parent_name, self._name))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
cr.commit()
@@ -2451,6 +2482,8 @@ class orm(orm_template):
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (self._table,))
create = not bool(cr.fetchone())
cr.commit() # start a new transaction
for (key, con, _) in self._sql_constraints:
conname = '%s_%s' % (self._table, key)
cr.execute("SELECT conname FROM pg_constraint where conname=%s", (conname,))
@@ -2460,6 +2493,7 @@ class orm(orm_template):
cr.commit()
except:
logger.notifyChannel('orm', netsvc.LOG_WARNING, 'unable to add \'%s\' constraint on table %s !\n If you want to have it, you should update the records and execute manually:\nALTER table %s ADD CONSTRAINT %s_%s %s' % (con, self._table, self._table, self._table, key, con,))
cr.rollback()
if create:
if hasattr(self, "_sql"):
@@ -2470,6 +2504,7 @@ class orm(orm_template):
cr.commit()
if store_compute:
self._parent_store_compute(cr)
cr.commit()
return todo_end
def __init__(self, cr):
@@ -2625,11 +2660,16 @@ class orm(orm_template):
for i in range(len(field_value)):
field_value2.append({})
for field2 in field_value[i]:
if obj._columns[field2]._type in ('many2one', 'one2one'):
if field2 in obj._columns.keys() and obj._columns[field2]._type in ('many2one', 'one2one'):
obj2 = self.pool.get(obj._columns[field2]._obj)
if not obj2.search(cr, uid,
[('id', '=', field_value[i][field2])]):
continue
elif field2 in obj._inherit_fields.keys() and obj._inherit_fields[field2][2]._type in ('many2one', 'one2one'):
obj2 = self.pool.get(obj._inherit_fields[field2][2]._obj)
if not obj2.search(cr, uid,
[('id', '=', field_value[i][field2])]):
continue
# TODO add test for many2many and one2many
field_value2[i][field2] = field_value[i][field2]
field_value = field_value2
@@ -3086,6 +3126,24 @@ class orm(orm_template):
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
# No direct update of parent_left/right
vals.pop('parent_left', None)
vals.pop('parent_right', None)
parents_changed = []
if self._parent_store and (self._parent_name in vals):
# The parent_left/right computation may take up to
# 5 seconds. No need to recompute the values if the
# parent is the same. Get the current value of the parent
base_query = 'SELECT id FROM %s WHERE id IN %%s AND %s' % \
(self._table, self._parent_name)
params = (tuple(ids),)
parent_val = vals[self._parent_name]
if parent_val:
cr.execute(base_query + " != %s", params + (parent_val,))
else:
cr.execute(base_query + " IS NULL", params)
parents_changed = map(operator.itemgetter(0), cr.fetchall())
upd0 = []
upd1 = []
@@ -3175,41 +3233,48 @@ class orm(orm_template):
self.pool.get(table).write(cr, user, nids, v, context)
self._validate(cr, user, ids, context)
# TODO: use _order to set dest at the right position and not first node of parent
if self._parent_store and (self._parent_name in vals):
# TODO: use _order to set dest at the right position and not first node of parent
# We can't defer parent_store computation because the stored function
# fields that are computer may refer (directly or indirectly) to
# parent_left/right (via a child_of domain)
if parents_changed:
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
for id in ids:
# Find Position of the element
if vals[self._parent_name]:
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (vals[self._parent_name],))
else:
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+' is null order by '+(self._parent_order or self._order))
result_p = cr.fetchall()
position = None
for (pleft,pright,pid) in result_p:
if pid == id:
break
position = pright+1
order = self._parent_order or self._order
parent_val = vals[self._parent_name]
if parent_val:
clause, params = '%s=%%s' % (self._parent_name,), (parent_val,)
else:
clause, params = '%s IS NULL' % (self._parent_name,), ()
cr.execute('SELECT parent_right, id FROM %s WHERE %s ORDER BY %s' % (self._table, clause, order), params)
parents = cr.fetchall()
# It's the first node of the parent: position = parent_left+1
if not position:
if not vals[self._parent_name]:
position = 1
else:
cr.execute('select parent_left from '+self._table+' where id=%s', (vals[self._parent_name],))
position = cr.fetchone()[0]+1
# We have the new position !
cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (id,))
pleft,pright = cr.fetchone()
for id in parents_changed:
cr.execute('SELECT parent_left, parent_right FROM %s WHERE id=%%s' % (self._table,), (id,))
pleft, pright = cr.fetchone()
distance = pright - pleft + 1
if position>pleft and position<=pright:
# Find Position of the element
position = None
for (parent_pright, parent_id) in parents:
if parent_id == id:
break
position = parent_pright+1
# It's the first node of the parent
if not position:
if not parent_val:
position = 1
else:
cr.execute('select parent_left from '+self._table+' where id=%s', (parent_val,))
position = cr.fetchone()[0]+1
if pleft < position <= pright:
raise except_orm(_('UserError'), _('Recursivity Detected.'))
if pleft<position:
if pleft < position:
cr.execute('update '+self._table+' set parent_left=parent_left+%s where parent_left>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_left=parent_left+%s, parent_right=parent_right+%s where parent_left>=%s and parent_left<%s', (position-pleft,position-pleft, pleft, pright))
@@ -3390,7 +3455,7 @@ class orm(orm_template):
self.check_access_rule(cr, user, [id_new], 'create', context=context)
upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority)
if self._parent_store:
if self._parent_store and not context.get('defer_parent_store_computation'):
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
@@ -3434,6 +3499,12 @@ class orm(orm_template):
self.pool.get(object)._store_set_values(cr, user, ids, fields2, context)
done.append((object, ids, fields2))
if self._log_create and not (context and context.get('no_store_function', False)):
message = self._description + \
" '" + \
self.name_get(cr, user, [id_new], context=context)[0][1] + \
"' "+ _("created.")
self.log(cr, user, id_new, message, True, context=context)
wf_service = netsvc.LocalService("workflow")
wf_service.trg_create(user, self._name, id_new, cr)
return id_new
@@ -3612,8 +3683,9 @@ class orm(orm_template):
* '&' (default), '|', '!'
"""
if not context:
if context is None:
context = {}
self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
# compute the where, order by, limit and offset clauses
(qu1, qu2, tables) = self._where_calc(cr, user, args, context=context)
dom = self.pool.get('ir.rule').domain_get(cr, user, self._name, 'read', context=context)
@@ -3723,9 +3795,9 @@ class orm(orm_template):
:return: dictionary containing all the field values
"""
if not context:
if context is None:
context = {}
if not default:
if default is None:
default = {}
if 'state' not in default:
if 'state' in self._defaults:
@@ -3734,7 +3806,11 @@ class orm(orm_template):
else:
default['state'] = self._defaults['state']
data = self.read(cr, uid, [id], context=context)[0]
context_wo_lang = context
if 'lang' in context:
del context_wo_lang['lang']
data = self.read(cr, uid, [id], context=context_wo_lang)[0]
fields = self.fields_get(cr, uid, context=context)
trans_data=[]
for f in fields:
@@ -3769,17 +3845,14 @@ class orm(orm_template):
trans_obj = self.pool.get('ir.translation')
#TODO: optimize translations
trans_name=''
for f in fields:
trans_flag=True
trans_name = ''
if f in self._columns and self._columns[f].translate:
trans_name=self._name+","+f
trans_name = self._name+","+f
elif f in self._inherit_fields and self._inherit_fields[f][2].translate:
trans_name=self._inherit_fields[f][0]+","+f
else:
trans_flag=False
trans_name = self._inherit_fields[f][0] + "," + f
if trans_flag:
if trans_name:
trans_ids = trans_obj.search(cr, uid, [
('name', '=', trans_name),
('res_id','=',data['id'])
+19 -3
View File
@@ -30,7 +30,7 @@ import copy
import sys
import traceback
import logging
from psycopg2 import IntegrityError
from psycopg2 import IntegrityError, errorcodes
from tools.func import wraps
@@ -65,7 +65,22 @@ class osv_pool(netsvc.Service):
for key in self._sql_error.keys():
if key in inst[0]:
self.abortResponse(1, 'Constraint Error', 'warning', self._sql_error[key])
self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
if inst.pgcode == errorcodes.NOT_NULL_VIOLATION:
msg = 'Sorry, this record cannot be deleted at the moment because other records still reference it.'
self.logger.debug("IntegrityError", exc_info=True)
try:
context = inst.pgerror.split('"public".')[1]
model_name = table = context.split('"')[1]
model = table.replace("_",".")
model_obj = self.get(model)
if model_obj:
model_name = model_obj._description or model_obj._name
msg += '\n\n[object with reference: %s - %s]' % (model_name, model)
except Exception:
pass
self.abortResponse(1, 'Integrity Error', 'warning', msg)
else:
self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
except Exception, e:
self.logger.exception("Uncaught exception")
raise
@@ -253,7 +268,8 @@ class osv(osv_base, orm.orm):
for c in cls.__dict__.get(s, []):
exist = False
for c2 in range(len(new)):
if new[c2][2]==c[2]:
#For _constraints, we should check field and methods as well
if new[c2][2]==c[2] and new[c2][0]==c[0]:
new[c2] = c
exist = True
break
+2 -2
View File
@@ -21,8 +21,8 @@
##############################################################################
name = 'openerp-server'
version = '5.2dev'
major_version = '5.2'
version = '6.0dev'
major_version = '6.0'
description = 'OpenERP Server'
long_desc = '''\
OpenERP is a complete ERP and CRM. The main features are accounting (analytic
+1
View File
@@ -36,6 +36,7 @@ from pychart import *
import misc
import cStringIO
from lxml import etree
from tools.translate import _
class external_pdf(render.render):
def __init__(self, pdf):
+5 -5
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -35,7 +35,7 @@ class report(object):
for node in root_node:
if node.tag == etree.Comment:
continue
if node.text:
if node.text or node.tail:
def _sub3(txt):
n = node
while n.tag != txt.group(2):
@@ -71,9 +71,9 @@ class report(object):
n = n.getparent()
n.set('rml_loop', txt.group(2))
return '[['+txt.group(1)+"''"+txt.group(4)+']]'
t = _regex1.sub(_sub1, node.text)
t = _regex1.sub(_sub1, node.text or node.tail)
if t == " ":
t = _regex11.sub(_sub1, node.text)
t = _regex11.sub(_sub1, node.text or node.tail)
t = _regex3.sub(_sub3, t)
node.text = _regex2.sub(_sub2, t)
self.preprocess_rml(node,type)
+25 -16
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -52,13 +52,20 @@ class _rml_styles(object,):
def __init__(self, nodes, localcontext):
self.localcontext = localcontext
self.styles = {}
self.styles_obj = {}
self.names = {}
self.table_styles = {}
self.default_style = reportlab.lib.styles.getSampleStyleSheet()
for node in nodes:
for style in node.findall('blockTableStyle'):
self.table_styles[style.get('id')] = self._table_style_get(style)
for style in node.findall('paraStyle'):
self.styles[style.get('name')] = self._para_style_update(style)
sname = style.get('name')
self.styles[sname] = self._para_style_update(style)
self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname])
for variable in node.findall('initialize'):
for name in variable.findall('name'):
self.names[ name.get('id')] = name.get('value')
@@ -126,17 +133,19 @@ class _rml_styles(object,):
def para_style_get(self, node):
style = False
if node.get('style'):
if node.get('style') in self.styles:
styles = reportlab.lib.styles.getSampleStyleSheet()
sname = node.get('style')
style = reportlab.lib.styles.ParagraphStyle(sname, styles["Normal"], **self.styles[sname])
sname = node.get('style')
if sname:
if sname in self.styles_obj:
style = self.styles_obj[sname]
else:
sys.stderr.write('Warning: style not found, %s - setting default!\n' % (node.get('style'),) )
if not style:
styles = reportlab.lib.styles.getSampleStyleSheet()
style = styles['Normal']
style.__dict__.update(self._para_style_update(node))
style = self.default_style['Normal']
para_update = self._para_style_update(node)
if para_update:
# update style only is necessary
style = copy.deepcopy(style)
style.__dict__.update(para_update)
return style
class _rml_doc(object):
@@ -167,7 +176,7 @@ class _rml_doc(object):
from reportlab.lib.fonts import addMapping
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont(fontname, filename ))
if (mode == 'all'):
addMapping(face, 0, 0, fontname) #normal
@@ -417,11 +426,11 @@ class _rml_canvas(object):
self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
def setFont(self, node):
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import pdfmetrics
fname = node.get('name')
#TODO : other fonts should be supported
#TODO : other fonts should be supported
if fname not in pdfmetrics.standardFonts:
fname = self.canvas._fontname
fname = self.canvas._fontname
return self.canvas.setFont(fname, utils.unit_get(node.get('size')))
def render(self, node):
@@ -565,7 +574,7 @@ class _rml_flowable(object):
def _illustration(self, node):
class Illustration(platypus.flowables.Flowable):
def __init__(self, node, localcontext, styles, self2):
self.localcontext = localcontext
self.localcontext = localcontext.copy()
self.node = node
self.styles = styles
self.width = utils.unit_get(node.get('width'))
+2 -2
View File
@@ -441,8 +441,8 @@ class report_sxw(report_rml, preprocess.report):
rml_parser.set_context(objs, data, ids, report_xml.report_type)
processed_rml = etree.XML(rml)
if report_xml.header:
rml_parser._add_header(processed_rml)
processed_rml = self.preprocess_rml(processed_rml,report_xml.report_type)
rml_parser._add_header(processed_rml, self.header)
processed_rml = self.preprocess_rml(processed_rml,report_xml.report_type)
if rml_parser.logo:
logo = base64.decodestring(rml_parser.logo)
create_doc = self.generators[report_xml.report_type]
+12 -16
View File
@@ -31,9 +31,11 @@
"""
from websrv_lib import *
import netsvc
import errno
import threading
import tools
import os
import select
import socket
import xmlrpclib
@@ -128,31 +130,25 @@ class BaseHttpDaemon(threading.Thread, netsvc.Server):
"Error occur when starting the server daemon: %s" % (e,))
raise
@property
def socket(self):
return self.server.socket
def attach(self, path, gw):
pass
def stop(self):
self.running = False
if os.name != 'nt':
try:
self.server.socket.shutdown(
getattr(socket, 'SHUT_RDWR', 2))
except socket.error, e:
if e.errno != 57: raise
# OSX, socket shutdowns both sides if any side closes it
# causing an error 57 'Socket is not connected' on shutdown
# of the other side (or something), see
# http://bugs.python.org/issue4397
netsvc.Logger().notifyChannel(
'server', netsvc.LOG_DEBUG,
'"%s" when shutting down server socket, '
'this is normal under OS X'%e)
self.server.socket.close()
self._close_socket()
def run(self):
self.running = True
while self.running:
self.server.handle_request()
try:
self.server.handle_request()
except (socket.error, select.error), e:
if self.running or e.args[0] != errno.EBADF:
raise
return True
class HttpDaemon(BaseHttpDaemon):
+6 -8
View File
@@ -27,6 +27,7 @@ import netsvc
import threading
import tools
import os
import select
import socket
import tiny_socket
@@ -50,7 +51,6 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
self.sock = None
def run(self):
# import select
self.running = True
try:
ts = tiny_socket.mysocket(self.sock)
@@ -103,10 +103,13 @@ class TinySocketServerThread(threading.Thread,netsvc.Server):
"starting NET-RPC service at %s port %d" % (interface or '0.0.0.0', port,))
def run(self):
# import select
try:
self.running = True
while self.running:
timeout = self.socket.gettimeout()
fd_sets = select.select([self.socket], [], [], timeout)
if not fd_sets[0]:
continue
(clientsocket, address) = self.socket.accept()
ct = TinySocketClientThread(clientsocket, self.threads)
clientsocket = None
@@ -129,12 +132,7 @@ class TinySocketServerThread(threading.Thread,netsvc.Server):
self.running = False
for t in self.threads:
t.stop()
try:
self.socket.shutdown(
getattr(socket, 'SHUT_RDWR', 2))
self.socket.close()
except:
return False
self._close_socket()
def stats(self):
res = "Net-RPC: " + ( (self.running and "running") or "stopped")
+2 -2
View File
@@ -283,8 +283,8 @@ class db(netsvc.ExportService):
## Not True: in fact, check if connection to database is possible. The database may exists
return bool(sql_db.db_connect(db_name))
def exp_list(self):
if not tools.config['list_db']:
def exp_list(self, document=False):
if not tools.config['list_db'] and not document:
raise Exception('AccessDenied')
db = sql_db.db_connect('template1')
+40 -22
View File
@@ -100,7 +100,7 @@ class Cursor(object):
msg = "Cursor not closed explicitly\n" \
"Cursor was created at %s:%s"
self.__logger.warn(msg, *self.__caller)
self.close()
self._close(True)
@check
def execute(self, query, params=None):
@@ -118,7 +118,7 @@ class Cursor(object):
params = params or None
res = self._obj.execute(query, params)
except psycopg2.ProgrammingError, pe:
self.__logger.error("Programming error: %s, in query %s" % (pe, query))
self.__logger.error("Programming error: %s, in query %s", pe, query)
raise
except Exception:
self.__logger.exception("bad query: %s", self._obj.query)
@@ -177,6 +177,9 @@ class Cursor(object):
@check
def close(self):
return self._close(False)
def _close(self, leak=False):
if not self._obj:
return
@@ -194,7 +197,12 @@ class Cursor(object):
# part because browse records keep a reference to the cursor.
del self._obj
self.__closed = True
self._pool.give_back(self._cnx)
if leak:
self._cnx.leaked = True
else:
keep_in_pool = self.dbname not in ('template1', 'template0', 'postgres')
self._pool.give_back(self._cnx, keep_in_pool=keep_in_pool)
@check
def autocommit(self, on):
@@ -214,6 +222,9 @@ class Cursor(object):
return getattr(self._obj, name)
class PsycoConnection(psycopg2.extensions.connection):
pass
class ConnectionPool(object):
__logger = logging.getLogger('db.connection_pool')
@@ -239,57 +250,64 @@ class ConnectionPool(object):
count = len(self._connections)
return "ConnectionPool(used=%d/count=%d/max=%d)" % (used, count, self._maxconn)
def _debug(self, msg):
self.__logger.debug(repr(self))
self.__logger.debug(msg)
def _debug(self, msg, *args):
msg = '%r ' + msg
self.__logger.debug(msg, self, *args)
@locked
def borrow(self, dsn):
self._debug('Borrow connection to %s' % (dsn,))
self._debug('Borrow connection to %r', dsn)
# free leaked connections
for i, (cnx, _) in tools.reverse_enumerate(self._connections):
if getattr(cnx, 'leaked', False):
delattr(cnx, 'leaked')
self._connections.pop(i)
self._connections.append((cnx, False))
self._debug('Free leaked connection to %r', cnx.dsn)
result = None
for i, (cnx, used) in enumerate(self._connections):
if not used and dsn_are_equals(cnx.dsn, dsn):
self._debug('Existing connection found at index %d' % i)
self._connections.pop(i)
self._connections.append((cnx, True))
self._debug('Existing connection found at index %d', i)
result = cnx
break
if result:
return result
return cnx
if len(self._connections) >= self._maxconn:
# try to remove the oldest connection not used
for i, (cnx, used) in enumerate(self._connections):
if not used:
self._debug('Removing old connection at index %d: %s' % (i, cnx.dsn))
self._connections.pop(i)
self._debug('Removing old connection at index %d: %r', i, cnx.dsn)
break
else:
# note: this code is called only if the for loop has completed (no break)
raise PoolError('The Connection Pool Is Full')
self._debug('Create new connection')
result = psycopg2.connect(dsn=dsn)
result = psycopg2.connect(dsn=dsn, connection_factory=PsycoConnection)
self._connections.append((result, True))
self._debug('Create new connection')
return result
@locked
def give_back(self, connection):
self._debug('Give back connection to %s' % (connection.dsn,))
def give_back(self, connection, keep_in_pool=True):
self._debug('Give back connection to %r', connection.dsn)
for i, (cnx, used) in enumerate(self._connections):
if cnx is connection:
self._connections.pop(i)
self._connections.append((cnx, False))
if keep_in_pool:
self._connections.append((cnx, False))
self._debug('Put connection to %r in pool', cnx.dsn)
else:
self._debug('Forgot connection to %r', cnx.dsn)
break
else:
raise PoolError('This connection does not below to the pool')
@locked
def close_all(self, dsn):
self._debug('Close all connections to %s' % (dsn,))
self._debug('Close all connections to %r', dsn)
for i, (cnx, used) in tools.reverse_enumerate(self._connections):
if dsn_are_equals(cnx.dsn, dsn):
cnx.close()
@@ -305,7 +323,7 @@ class Connection(object):
def cursor(self, serialized=False):
cursor_type = serialized and 'serialized ' or ''
self.__logger.debug('create %scursor to "%s"' % (cursor_type, self.dbname,))
self.__logger.debug('create %scursor to %r', cursor_type, self.dbname)
return Cursor(self._pool, self.dbname, serialized=serialized)
def serialized_cursor(self):
+18 -16
View File
@@ -83,8 +83,7 @@ class configmanager(object):
'list_db' : True,
'timezone' : False, # to override the default TZ
'test-disable' : False,
'test-rollback' : True,
'test-continue' : False
'test-commit' : False,
}
self.misc = {}
@@ -124,7 +123,6 @@ class configmanager(object):
parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=self._LOGLEVELS.keys(),
help="specify the level at which a failed assertion will stop the server. Accepted values: %s" % (self._LOGLEVELS.keys(),))
parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='deprecated since v6.0, replaced by module decimal_precision')
parser.add_option('--no-database-list', action="store_false", dest='list_db', default=True, help="disable the ability to return the list of databases")
if self.has_ssl:
group = optparse.OptionGroup(parser, "SSL Configuration")
@@ -137,17 +135,15 @@ class configmanager(object):
default="server.pkey",
help="specify the private key file for the SSL connection")
parser.add_option_group(group)
# Testing Group
group = optparse.OptionGroup(parser, "Testing Configuration")
group.add_option("--test-disable", action="store_true", dest="test_disable",
default=False, help="Disable loading test files.")
group.add_option("--test-no-rollback", action="store_false", dest="test_rollback",
default=True, help="Don't rollback after running test.")
group.add_option("--test-continue", action="store_true", dest="test_continue",
default=False, help="Display exception but then test should continue.")
group.add_option("--test-commit", action="store_true", dest="test_commit",
default=False, help="Commit database changes performed by tests.")
parser.add_option_group(group)
# Logging Group
group = optparse.OptionGroup(parser, "Logging Configuration")
group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
@@ -164,8 +160,7 @@ class configmanager(object):
group.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email')
group.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
group.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port', type="int")
if self.has_ssl:
group.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
group.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
group.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
group.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
parser.add_option_group(group)
@@ -202,6 +197,13 @@ class configmanager(object):
action="callback", callback=self._check_addons_path, nargs=1, type="string")
parser.add_option_group(group)
security = optparse.OptionGroup(parser, 'Security-related options')
security.add_option('--no-database-list', action="store_false", dest='list_db', default=True, help="disable the ability to return the list of databases")
security.add_option('--enable-code-actions', action='store_true',
dest='server_actions_allow_code', default=False,
help='Enables server actions of state "code". Warning, this is a security risk.')
parser.add_option_group(security)
def parse_config(self):
(opt, args) = self.parser.parse_args()
@@ -247,13 +249,13 @@ class configmanager(object):
self.options['pidfile'] = False
keys = ['interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout',
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout','smtp_ssl',
'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path',
'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',]
if self.has_ssl:
keys.extend(['smtp_ssl', 'secure_cert_file', 'secure_pkey_file'])
keys.extend(['secure_cert_file', 'secure_pkey_file'])
keys.append('secure')
for arg in keys:
@@ -261,7 +263,8 @@ class configmanager(object):
self.options[arg] = getattr(opt, arg)
keys = ['language', 'translate_out', 'translate_in', 'debug_mode',
'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog', 'list_db']
'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog',
'list_db', 'server_actions_allow_code']
if self.has_ssl and not self.options['secure']:
keys.append('secure')
@@ -288,8 +291,7 @@ class configmanager(object):
self.options['init'] = opt.init and dict.fromkeys(opt.init.split(','), 1) or {}
self.options["demo"] = not opt.without_demo and self.options['init'] or {}
self.options["test-disable"] = opt.test_disable
self.options["test-rollback"] = opt.test_rollback
self.options["test-continue"] = opt.test_continue
self.options["test-commit"] = opt.test_commit
self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {}
self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
+49 -19
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -26,11 +26,9 @@ import os.path
import pickle
import re
import sys
import time
from datetime import datetime
from lxml import etree
import ir
import misc
import netsvc
@@ -79,6 +77,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
return f_val
a_eval = node.get('eval','')
if a_eval:
import time
idref2 = idref.copy()
idref2['time'] = time
idref2['DateTime'] = datetime
@@ -253,6 +252,14 @@ form: module.record_id""" % (xml_id,)
self.pool.get(d_model).unlink(cr, self.uid, ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids)
def _remove_ir_values(self, cr, name, value, model):
ir_value_ids = self.pool.get('ir.values').search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)])
if ir_value_ids:
self.pool.get('ir.values').unlink(cr, self.uid, ir_value_ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids)
return True
def _tag_report(self, cr, rec, data_node=None):
res = {}
for dest,f in (('name','string'),('model','model'),('report_name','name')):
@@ -262,16 +269,17 @@ form: module.record_id""" % (xml_id,)
if rec.get(field):
res[dest] = rec.get(field).encode('utf8')
if rec.get('auto'):
res['auto'] = eval(rec.get('auto'))
res['auto'] = eval(rec.get('auto','False'))
if rec.get('sxw'):
sxw_content = misc.file_open(rec.get('sxw')).read()
res['report_sxw_content'] = sxw_content
if rec.get('header'):
res['header'] = eval(rec.get('header'))
res['header'] = eval(rec.get('header','False'))
if rec.get('report_type'):
res['report_type'] = rec.get('report_type')
res['multi'] = rec.get('multi') and eval(rec.get('multi'))
res['multi'] = rec.get('multi') and eval(rec.get('multi','False'))
xml_id = rec.get('id','').encode('utf8')
self._test_xml_id(xml_id)
@@ -291,12 +299,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if not rec.get('menu') or eval(rec.get('menu','')):
if not rec.get('menu') or eval(rec.get('menu','False')):
keyword = str(rec.get('keyword', 'client_print_multi'))
keys = [('action',keyword),('res_model',res['model'])]
value = 'ir.actions.report.xml,'+str(id)
replace = rec.get('replace', True)
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and eval(rec.get('menu','False'))==False:
# Special check for report having attribute menu=False on update
value = 'ir.actions.report.xml,'+str(id)
self._remove_ir_values(cr, res['name'], value, res['model'])
return False
def _tag_function(self, cr, rec, data_node=None):
@@ -313,7 +325,7 @@ form: module.record_id""" % (xml_id,)
name = rec.get("name",'').encode('utf8')
xml_id = rec.get('id','').encode('utf8')
self._test_xml_id(xml_id)
multi = rec.get('multi','') and eval(rec.get('multi',''))
multi = rec.get('multi','') and eval(rec.get('multi','False'))
res = {'name': string, 'wiz_name': name, 'multi': multi, 'model': model}
if rec.get('groups'):
@@ -332,12 +344,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.get('menu') or eval(rec.get('menu',''))) and id:
if (not rec.get('menu') or eval(rec.get('menu','False'))) and id:
keyword = str(rec.get('keyword','') or 'client_action_multi')
keys = [('action',keyword),('res_model',model)]
value = 'ir.actions.wizard,'+str(id)
replace = rec.get("replace",'') or True
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False):
# Special check for wizard having attribute menu=False on update
value = 'ir.actions.wizard,'+str(id)
self._remove_ir_values(cr, string, value, model)
def _tag_url(self, cr, rec, data_node=None):
url = rec.get("string",'').encode('utf8')
@@ -351,12 +367,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.get('menu') or eval(rec.get('menu',''))) and id:
if (not rec.get('menu') or eval(rec.get('menu','False'))) and id:
keyword = str(rec.get('keyword','') or 'client_action_multi')
keys = [('action',keyword)]
value = 'ir.actions.url,'+str(id)
replace = rec.get("replace",'') or True
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False):
# Special check for URL having attribute menu=False on update
value = 'ir.actions.url,'+str(id)
self._remove_ir_values(cr, url, value, "ir.actions.url")
def _tag_act_window(self, cr, rec, data_node=None):
name = rec.get('name','').encode('utf-8')
@@ -369,21 +389,22 @@ form: module.record_id""" % (xml_id,)
domain = rec.get('domain','').encode('utf-8') or '{}'
context = rec.get('context','').encode('utf-8') or '{}'
res_model = rec.get('res_model','').encode('utf-8')
src_model = rec.get('src_model','').encode('utf-8')
src_model = rec.get('src_model','').encode('utf-8')
view_type = rec.get('view_type','').encode('utf-8') or 'form'
view_mode = rec.get('view_mode','').encode('utf-8') or 'tree,form'
usage = rec.get('usage','').encode('utf-8')
limit = rec.get('limit','').encode('utf-8')
auto_refresh = rec.get('auto_refresh','').encode('utf-8')
uid = self.uid
# def ref() added because , if context has ref('id') eval wil use this ref
active_id=str("active_id") # for further reference in client/bin/tools/__init__.py
active_id = str("active_id") # for further reference in client/bin/tools/__init__.py
def ref(str_id):
return self.id_get(cr, None, str_id)
context=eval(context)
context = eval(context)
# domain = eval(domain) # XXX need to test this line -> uid, active_id, active_ids, ...
res = {
'name': name,
@@ -720,7 +741,12 @@ form: module.record_id""" % (xml_id,)
if f_ref=="null":
f_val = False
else:
f_val = self.id_get(cr, f_model, f_ref)
if f_name in model._columns \
and model._columns[f_name]._type == 'reference':
val = self.model_id_get(cr, f_model, f_ref)
f_val = val[0] + ',' + str(val[1])
else:
f_val = self.id_get(cr, f_model, f_ref)
else:
f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
if model._columns.has_key(f_name):
@@ -738,13 +764,17 @@ form: module.record_id""" % (xml_id,)
def id_get(self, cr, model, id_str):
if id_str in self.idref:
return self.idref[id_str]
return self.model_id_get(cr, model, id_str)[1]
def model_id_get(self, cr, model, id_str):
model_data_obj = self.pool.get('ir.model.data')
mod = self.module
if '.' in id_str:
mod,id_str = id_str.split('.')
result = self.pool.get('ir.model.data')._get_id(cr, self.uid, mod, id_str)
res = self.pool.get('ir.model.data').read(cr, self.uid, [result], ['res_id'])
result = model_data_obj._get_id(cr, self.uid, mod, id_str)
res = model_data_obj.read(cr, self.uid, [result], ['model', 'res_id'])
if res and res[0] and res[0]['res_id']:
return int(res[0]['res_id'])
return res[0]['model'], int(res[0]['res_id'])
return False
def parse(self, de):
+30 -18
View File
@@ -101,7 +101,7 @@ def init_db(cr):
values (%s, %s, %s, %s, %s, %s, %s, %s, %s)', (
id, info.get('author', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), p_id, state, info.get('certificate')))
info.get('description', ''), p_id, state, info.get('certificate') or None))
cr.execute('insert into ir_model_data \
(name,model,module, res_id, noupdate) values (%s,%s,%s,%s,%s)', (
'module_meta_information', 'ir.module.module', i, id, True))
@@ -820,6 +820,22 @@ class cache(object):
def to_xml(s):
return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
def get_encodings():
yield 'utf8'
from locale import getpreferredencoding
prefenc = getpreferredencoding()
if prefenc:
yield prefenc
prefenc = {
'latin1': 'latin9',
'iso-8859-1': 'iso8859-15',
'cp1252': '1252',
}.get(prefenc.lower())
if prefenc:
yield prefenc
def ustr(value):
"""This method is similar to the builtin `str` method, except
it will return Unicode string.
@@ -829,29 +845,25 @@ def ustr(value):
@rtype: unicode
@return: unicode string
"""
orig = value
if isinstance(value, Exception):
return exception_to_unicode(value)
if isinstance(value, unicode):
return value
if hasattr(value, '__unicode__'):
try:
return unicode(value)
if not isinstance(value, str):
value = str(value)
try: # first try utf-8
return unicode(value, 'utf-8')
except:
pass
try: # then extened iso-8858
return unicode(value, 'iso-8859-15')
except:
pass
for ln in get_encodings():
try:
return unicode(value, ln)
except:
pass
raise UnicodeError('unable de to convert %r' % (orig,))
# else use default system locale
from locale import getlocale
return unicode(value, getlocale()[1])
def exception_to_unicode(e):
if (sys.version_info[:2] < (2,6)) and hasattr(e, 'message'):
@@ -914,7 +926,7 @@ def get_languages():
'fr_BE': u'French (BE) / Français (BE)',
'fr_CH': u'French (CH) / Français (CH)',
'fr_FR': u'French / Français',
'gl_ES': u'Galician / Spain',
'gl_ES': u'Galician / Galego',
'gu_IN': u'Gujarati / India',
'hi_IN': u'Hindi / India',
'hr_HR': u'Croatian / hrvatski jezik',
@@ -939,8 +951,8 @@ def get_languages():
'ro_RO': u'Romanian / limba română',
'ru_RU': u'Russian / русский язык',
'si_LK': u'Sinhalese / Sri Lanka',
'sk_SK': u'Slovak / Slovakia',
'sl_SL': u'Slovenian / slovenščina',
'sl_SI': u'Slovenian / slovenščina',
'sk_SK': u'Slovak / Slovenský jazyk',
'sq_AL': u'Albanian / Shqipëri',
'sr_RS': u'Serbian / Serbia',
'sv_SE': u'Swedish / svenska',
+35 -22
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -596,23 +596,30 @@ def trans_generate(lang, modules, dbname=None):
push_translation(module, 'model', name, xml_name, encode(trad))
# parse source code for _() calls
def get_module_from_path(path,mod_paths=None):
if not mod_paths:
# First, construct a list of possible paths
def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
mod_paths=[def_path]
for adp in ad_paths:
mod_paths.append(adp)
if not adp.startswith('/'):
mod_paths.append(os.path.join(def_path,adp))
elif adp.startswith(def_path):
mod_paths.append(adp[len(def_path)+1:])
for mp in mod_paths:
if path.startswith(mp) and (os.path.dirname(path) != mp):
path = path[len(mp)+1:]
return path.split(os.path.sep)[0]
def get_module_from_path(path, mod_paths=None):
# if not mod_paths:
## First, construct a list of possible paths
# def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
# ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
# mod_paths=[def_path]
# for adp in ad_paths:
# mod_paths.append(adp)
# if not adp.startswith('/'):
# mod_paths.append(os.path.join(def_path,adp))
# elif adp.startswith(def_path):
# mod_paths.append(adp[len(def_path)+1:])
# for mp in mod_paths:
# if path.startswith(mp) and (os.path.dirname(path) != mp):
# path = path[len(mp)+1:]
# return path.split(os.path.sep)[0]
path_dir = os.path.dirname(path[1:])
if path_dir:
if os.path.exists(os.path.join(tools.config['addons_path'],path[1:])):
return path.split(os.path.sep)[1]
else:
root_addons = os.path.join(tools.config['root_path'], 'addons')
if os.path.exists(os.path.join(root_addons,path[1:])):
return path.split(os.path.sep)[1]
return 'base' # files that are not in a module are considered as being in 'base' module
modobj = pool.get('ir.module.module')
@@ -699,6 +706,11 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
if not lang_name:
lang_name = tools.get_languages().get(lang, lang)
def fix_xa0(s):
if s == '\xa0':
return '\xc2\xa0'
return s
lang_info = {
'code': lang,
'iso_code': iso_lang,
@@ -706,9 +718,10 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
'translatable': 1,
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
'decimal_point' : str(locale.localeconv()['decimal_point']).replace('\xa0', '\xc2\xa0'),
'thousands_sep' : str(locale.localeconv()['thousands_sep']).replace('\xa0', '\xc2\xa0'),
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
}
try:
lang_obj.create(cr, uid, lang_info)
finally:
@@ -767,7 +780,7 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
# the same source
obj = pool.get(model)
if obj:
if not field in obj._columns:
if field not in obj.fields_get_keys(cr, uid):
continue
ids = obj.search(cr, uid, [(field, '=', dic['src'])])
+1 -1
View File
@@ -682,7 +682,7 @@ class YamlInterpreter(object):
self.logger.exception(e)
except Exception, e:
self.logger.exception(e)
raise e
raise
def _process_node(self, node):
if is_comment(node):
+40
View File
@@ -0,0 +1,40 @@
# Copyright (C) 2009 Deng Xiyue <manphiz-guest@users.alioth.debian.org>
# This file is distributed under the same license as the openerp-server package.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-server\n"
"Report-Msgid-Bugs-To: openerp-server@packages.debian.org\n"
"POT-Creation-Date: 2009-08-24 22:41+0300\n"
"PO-Revision-Date: 2010-05-21 04:19+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"Language-Team: 桃園小白 <hasrhgni@msn.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-05-22 03:59+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"X-Poedit-Country: TAIWAN\n"
"X-Poedit-Language: Chinese\n"
"X-Poedit-SourceCharset: utf-8\n"
#. Type: string
#. Description
#: ../openerp-server.templates:1001
msgid "Dedicated system account for the Open ERP server:"
msgstr "Open ERP 專屬系統管理員帳號:"
#. Type: string
#. Description
#: ../openerp-server.templates:1001
msgid ""
"The Open ERP server must use a dedicated account for its operation so that "
"the system's security is not compromised by running it with superuser "
"privileges."
msgstr "Open ERP 必須指定一個專屬系統管理員帳號來進行操作,如此才不會因最高權限管理者在運行時損毀了系統的安全性。"
#. Type: string
#. Description
#: ../openerp-server.templates:1001
msgid "Please choose that account's username."
msgstr "請選擇帳號的用戶名稱。"
+931 -177
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
2010-07-XX: 6.0.0
=================
Improvements (server)
---------------------
* support of 'ref' attribute for importing 'reference' field values, as for many2one fields.
* experimental xml2yml script in /tools for conversion of XML data/test files to the new YAML format
+1 -1
View File
@@ -6,7 +6,7 @@ formats=rpm
[bdist_rpm]
# release must exactly match 'release' as set in bin/release.py
release=3
release=10
requires=python >= 2.4
#build-requires=python-devel >= 2.3
+10 -6
View File
@@ -44,7 +44,7 @@ sys.path.append(join(os.path.abspath(os.path.dirname(__file__)), "bin"))
execfile(join('bin', 'release.py'))
if sys.argv[1] == 'bdist_rpm':
if 'bdist_rpm' in sys.argv:
version = version.split('-')[0]
# get python short version
@@ -60,6 +60,7 @@ required_modules = [
('pytz', 'Timezone handling library for Python'),
('reportlab', 'reportlab module'),
('yaml', 'YAML parser and emitter for Python'),
('pywebdav', 'PyWebDAV is a standards compliant WebDAV server and library written in Python'),
]
def check_modules():
@@ -176,11 +177,14 @@ options = {
"compressed": 1,
"optimize": 2,
"dist_dir": 'dist',
"packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "encodings",
"dateutil", "wizard", "pychart", "PIL", "pyparsing",
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "yaml"],
"packages": [
"lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml", "xml.dom", "xml.xpath",
"encodings", "dateutil", "wizard", "pychart", "PIL", "pyparsing",
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "mako", "poplib",
"imaplib", "smtplib", "email", "yaml","pywebdav",
],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}
}
@@ -23,6 +23,7 @@
# TODO handle the case of zip modules
import os
import optparse
import sys
import glob
@@ -37,29 +38,48 @@ def load_information_from_description_file(module):
return {}
if len(sys.argv) == 2 and (sys.argv[1] in ['-h', '--help']):
print >>sys.stderr, 'Usage: module_graph.py [module1 module2 module3]\n\tWhen no module is specified, all modules in current directory are used'
sys.exit(1)
def get_valid_path(paths, module):
for path in paths:
full = os.path.join(path, module)
if os.path.exists(full):
return full
return None
modules = sys.argv[1:]
if not len(modules):
modules = map(os.path.dirname, glob.glob(os.path.join('*', '__openerp__.py')))
modules += map(os.path.dirname, glob.glob(os.path.join('*', '__terp__.py')))
parser = optparse.OptionParser(usage="%prog [options] [module1 [module2 ...]]")
parser.add_option("-p", "--addons-path", dest="path", help="addons directory", action="append")
(opt, args) = parser.parse_args()
done = []
modules = []
if not opt.path:
opt.path = ["."]
if not args:
for path in opt.path:
modules += map(os.path.dirname, glob.glob(os.path.join(path, '*', '__openerp__.py')))
modules += map(os.path.dirname, glob.glob(os.path.join(path, '*', '__terp__.py')))
else:
for module in args:
valid_path = get_valid_path(opt.path, module)
if valid_path:
modules.append(valid_path)
all_modules = set(map(os.path.basename, modules))
print 'digraph G {'
while len(modules):
f = modules.pop(0)
done.append(f)
module_name = os.path.basename(f)
all_modules.add(module_name)
info = load_information_from_description_file(f)
if info.get('installable', True):
for name in info['depends']:
if name not in done+modules:
modules.append(name)
if not os.path.exists(name):
print '\t%s [color=red]' % (name,)
print '\t%s -> %s;' % (f, name)
for name in info.get('depends',[]):
valid_path = get_valid_path(opt.path, name)
if name not in all_modules:
if valid_path:
modules.append(valid_path)
else:
all_modules.add(name)
print '\t%s [color=red]' % (name,)
print '\t%s -> %s;' % (module_name, name)
print '}'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+345
View File
@@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
Experimental script for conversion between OpenERP's XML serialization format
and the new YAML serialization format introduced in OpenERP 6.0.
Intended to be used as a quick preprocessor for converting data/test files, then
to be fine-tuned manually.
"""
import yaml
import logging
from lxml import etree
__VERSION__ = '0.0.2'
def toString(value):
value='"' + value + '"'
return value
class XmlTag(etree.ElementBase):
def _to_yaml(self):
child_tags = []
for node in self:
if hasattr(node, '_to_yaml'):
child_tags.append(node._to_yaml())
return self.tag(attrib=self.attrib, child_tags=child_tags)
class YamlTag(object):
"""
Superclass for constructors of custom tags defined in yaml file.
"""
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
self.attrib = self.__dict__.get('attrib', {})
self.child_tags = self.__dict__.get('child_tags', '')
def __getitem__(self, key):
return getattr(self, key)
def __getattr__(self, attr):
return None
def __repr__(self):
for k,v in self.attrib.iteritems():
if str(v) and str(v)[0] in ['[', '{', '#', '*', '(']:
self.attrib[k] = toString(self.attrib[k]).replace("'", '')
st = self.yaml_tag + ' ' + str(self.attrib)
return st
# attrib tags
class ref(YamlTag):
yaml_tag = u'!ref'
def __init__(self, expr="False"):
self.expr = expr
def __repr__(self):
return "'%s'"%str(self.expr)
class Eval(YamlTag):
yaml_tag = u'!eval'
def __init__(self, expr="False"):
self.expr = expr
def __repr__(self):
value=str(self.expr)
if value.find("6,") != -1:
value = eval(str(eval(value)))
value=value[0][2]
value = [[value]]
else:
try:
value=int(value)
except:
if value and value[0] in ['[', '{', '#', '*', '(']:
value = value.replace('"', r'\"')
value = toString(value)
else:
try:
value = eval(value)
except Exception:
pass
return value
class Search(YamlTag):
yaml_tag = u'!ref'
# test tag
class xml_test(XmlTag):
def _to_yaml(self):
expr = self.attrib.get('expr')
text = self.text
if text:
expr = expr + ' == ' + '"%s"'%text
return [[expr]]
class xml_data(etree.ElementBase):
def _to_yaml(self):
value = self.attrib.get('noupdate', "0")
return data(value)
# field tag:
class xml_field(etree.ElementBase):
def _to_yaml(self):
field = ' ' + self.attrib.pop('name','unknown')
if self.attrib.get('search', None):
value = Search(attrib=self.attrib, child_tags='').__repr__()
else:
attr = (self.attrib.get('ref', None) and 'ref') or (self.attrib.get('eval', None) and 'eval') or 'None'
value = Eval(self.attrib.get(attr, self.text)).__repr__() or ''
return {field: value}
# value tag
class xml_value(etree.ElementBase):
def _to_yaml(self):
if self.attrib.get('eval', None):
key, val = 'eval', '"'+self.attrib.get('eval')+'"'
elif self.attrib.get('model', None):
key, val = 'model', self.attrib.get('model')
val=val.replace("'",'""')
self.attrib.pop(key)
d={}
for k,v in self.attrib.iteritems():
if k == 'search':
v = '"' + v + '"'
k='--' + k
v=v.replace("'",'""')
d[k] = v
if d:
ls=[[{key:val},dict(d)]]
else:
ls=[[{key:val}]]
return ls
# data tag
class data(YamlTag):
yaml_tag = u'!context'
def __init__(self, noupdate="0"):
self.child_tags = {' noupdate':noupdate}
def __repr__(self):
return "!!context"
# Record tag
class Record(YamlTag):
yaml_tag = u'!record'
class xml_record(XmlTag):
tag=Record
def _to_yaml(self):
child_tags = {}
for node in self:
if hasattr(node, '_to_yaml'):
child_tags.update(node._to_yaml())
return Record(attrib=self.attrib, child_tags=child_tags)
# ir_set tag
class Ir_Set(YamlTag):
yaml_tag = u'!ir_set'
def __repr__(self):
st = self.yaml_tag
return st
class xml_ir_set(XmlTag):
tag=Ir_Set
def _to_yaml(self):
child_tags = {}
for node in self:
if hasattr(node, '_to_yaml'):
child_tags.update(node._to_yaml())
return Ir_Set(attrib=self.attrib, child_tags=child_tags)
# workflow tag
class Workflow(YamlTag):
yaml_tag = u'!workflow'
class xml_workflow(XmlTag):
tag=Workflow
# function tag
class Function(YamlTag):
yaml_tag = u'!function'
class xml_function(XmlTag):
tag=Function
# function tag
class Assert(YamlTag):
yaml_tag = u'!assert'
class xml_assert(XmlTag):
tag=Assert
# menuitem tagresult.append(yaml.safe_dump(obj, default_flow_style=False, allow_unicode=True).replace("'",''))
class MenuItem(YamlTag):
yaml_tag = u'!menuitem'
class xml_menuitem(XmlTag):
tag=MenuItem
# act_window tag
class ActWindow(YamlTag):
yaml_tag = u'!act_window'
class xml_act_window(XmlTag):
tag=ActWindow
# report tag
class Report(YamlTag):
yaml_tag = u'!report'
class xml_report(XmlTag):
tag=Report
# deletes tag
class Delete(YamlTag):
yaml_tag = u'!delete'
class xml_delete(XmlTag):
tag=Delete
# python tag
class Python(YamlTag):
yaml_tag = u'!python'
class xml_python(XmlTag):
tag=Python
# context tag
class Context(YamlTag):
yaml_tag = u'!context'
class xml_context(XmlTag):
tag=Context
# url tag
class Url(YamlTag):
yaml_tag = u'!url'
class xml_url(XmlTag):
tag=Url
# delete tag
class Delete(YamlTag):
yaml_tag = u'!delete'
class xml_delete(XmlTag):
tag=Delete
def represent_data(dumper, data):
return dumper.represent_mapping(u'tag:yaml.org,2002:map', [('!'+str(data), data.child_tags)])
yaml.SafeDumper.add_representer(Record, represent_data)
yaml.SafeDumper.add_representer(data, represent_data)
yaml.SafeDumper.add_representer(Workflow, represent_data)
yaml.SafeDumper.add_representer(Function, represent_data)
yaml.SafeDumper.add_representer(Assert, represent_data)
yaml.SafeDumper.add_representer(MenuItem, represent_data)
yaml.SafeDumper.add_representer(Ir_Set, represent_data)
yaml.SafeDumper.add_representer(Python, represent_data)
yaml.SafeDumper.add_representer(Context, represent_data)
class MyLookup(etree.CustomElementClassLookup):
def lookup(self, node_type, document, namespace, name):
if node_type=='element':
return {
'data': xml_data,
'record': xml_record,
'field': xml_field,
'workflow': xml_workflow,
'function': xml_function,
'value': xml_value,
'assert': xml_assert,
'test': xml_test,
'menuitem': xml_menuitem,
'act_window': xml_act_window,
'report': xml_report,
'delete': xml_delete,
'python': xml_python,
'context': xml_context,
'url': xml_url,
'ir_set': xml_ir_set,
}.get(name, None)
elif node_type=='comment':
return None#xml_comment
return None
class xml_parse(object):
def __init__(self):
self.context = {}
def parse(self, fname):
parser = etree.XMLParser()
parser.setElementClassLookup(MyLookup())
result = []
self.root = etree.XML(file(fname).read(), parser)
for data in self.root:
if hasattr(data, '_to_yaml'):
obj = data._to_yaml()
if obj.yaml_tag == '!context':
result.append(yaml.dump(str(obj)).replace("'",'').split('\n')[0])
result.append(yaml.dump(obj.child_tags, default_flow_style=False).replace("'",''))
else:
result.append(yaml.safe_dump(obj, default_flow_style=False, allow_unicode=True).replace("'",''))
self.context.update(data.attrib)
for tag in data:
if tag.tag == etree.Comment:
result.append(tag)
else:
if hasattr(tag, '_to_yaml'):
obj = tag._to_yaml()
if not obj.child_tags:
result.append(yaml.dump('!'+str(obj), default_flow_style=False, allow_unicode=True, width=999).replace("'",''))
else:
result.append(yaml.safe_dump(obj, default_flow_style=False, allow_unicode=True, width=999).replace('\n:', ':\n').replace("'",''))
print "# Experimental OpenERP xml-to-yml conversion! (v%s)"%__VERSION__
print "# Please use this as a first conversion/preprocessing step,"
print "# not as a production-ready tool!"
for record in result:
if type(record) != type(''):
record=str(record)
l= record.split("\n")
for line in l:
print '#' + str(line)
continue
record=str(record)
record = record.replace('- --',' ') #for value tag
record = record.replace('!!', '- \n !') #for all parent tags
record = record.replace('- - -', ' -') #for many2many fields
record = record.replace('? ', '') #for long expressions
record = record.replace('""', "'") #for string-value under value tag
print record
if __name__=='__main__':
import optparse
import sys
parser = optparse.OptionParser(
usage = '%s file.xml' % sys.argv[0])
(opt, args) = parser.parse_args()
if len(args) != 1:
parser.error("incorrect number of arguments")
fname = sys.argv[1]
p = xml_parse()
p.parse(fname)