merge upstream

bzr revid: chs@openerp.com-20121217172614-3z1pstu5th26wuuc
This commit is contained in:
Christophe Simonis 2012-12-17 18:26:14 +01:00
commit 0c7f17c0ac
106 changed files with 25369 additions and 3327 deletions

1
debian/control vendored
View File

@ -19,6 +19,7 @@ Depends:
python-docutils,
python-feedparser,
python-gdata,
python-jinja2,
python-ldap,
python-libxslt1,
python-lxml,

View File

@ -135,6 +135,9 @@ The view describes how the edition form or the data tree/list appear on screen.
A form can be called by an action opening in 'Tree' mode. The form view is generally opened from the list mode (like if the user pushes on 'switch view').
.. _domain:
.. _domains:
The domain
----------

View File

@ -141,10 +141,6 @@ for users who do not belong to the authorized groups:
.. note:: The tests related to this feature are in ``openerp/tests/test_acl.py``.
.. warning:: At the time of writing the implementation of this feature is partial
and does not yet restrict read/write RPC access to the field.
The corresponding test is written already but currently disabled.
Workflow transition rules
+++++++++++++++++++++++++

View File

@ -10,3 +10,4 @@ Miscellanous
06_misc_need_action_specs.rst
06_misc_user_img_specs.rst
06_misc_import.rst
06_misc_auto_join.rst

75
doc/06_misc_auto_join.rst Normal file
View File

@ -0,0 +1,75 @@
.. _performing_joins_in_select:
Perfoming joins in select
=========================
.. versionadded:: 7.0
Starting with OpenERP 7.0, an ``auto_join`` attribute is added on *many2one* and
*one2many* fields. The purpose is to allow the automatic generation of joins in
select queries. This attribute is set to False by default, therefore not changing
the default behavior. Please note that we consider this feature as still experimental
and should be used only if you understand its limitations and targets.
Without ``_auto_join``, the behavior of expression.parse() is the same as before.
Leafs holding a path beginning with many2one or one2many fields perform a search
on the relational table. The result is then used to replace the leaf content.
For example, if you have on res.partner a domain like ``[('bank_ids.name',
'like', 'foo')]`` with bank_ids linking to res.partner.bank, 3 queries will be
performed :
- 1 on res_partner_bank, with domain ``[('name', '=', 'foo')]``, that returns a
list of res.partner.bank ids (bids)
- 1 on res_partner, with a domain ``['bank_ids', 'in', bids)]``, that returns a
list of res.partner ids (pids)
- 1 on res_partner, with a domain ``[('id', 'in', pids)]``
When the ``auto_join`` attribute is True on a relational field, the destination
table will be joined to produce only one query.
- the relational table is accessed using an alias: ``'"res_partner_bank"
as res_partner__bank_ids``. The alias is generated using the relational field
name. This allows to have multiple joins with different join conditions on the
same table, depending on the domain.
- there is a join condition between the destination table and the main table:
``res_partner__bank_ids."partner_id"=res_partner."id"``
- the condition is then written on the relational table:
``res_partner__bank_ids."name" = 'foo'``
This manipulation is performed in expression.parse(). It checks leafs that
contain a path, i.e. any domain containing a '.'. It then checks whether the
first item of the path is a *many2one* or *one2many* field with the ``auto_join``
attribute set. If set, it adds a join query and recursively analyzes the
remaining of the leaf, using the same behavior. If the remaining path also holds
a path with auto_join fields, it will add all tables and add every necessary
join conditions.
Chaining joins allows to reduce the number of queries performed, and to avoid
having too long equivalent leaf replacement in domains. Indeed, the internal
queries produced by this behavior can be very costly, because they were generally
select queries without limit that could lead to huge ('id', 'in', [...])
leafs to analyze and execute.
Some limitations exist on this feature that limits its current use as of version
7.0. **This feature is therefore considered as experimental, and used
to speedup some precise bottlenecks in OpenERP**.
List of known issues and limitations:
- using ``auto_join`` bypasses the business logic; no name search is performed,
only direct matches between ids using join conditions
- ir.rules are not taken into account when analyzing and adding the join
conditions
List of already-supported corner cases :
- one2many fields having a domain attribute. Static domains as well as dynamic
domain are supported
- auto_join leading to functional searchable fields
Typical use in OpenERP 7.0:
- in mail module: notification_ids field on mail_message, allowing to speedup
the display of the various mailboxes
- in mail module: message_ids field on mail_thread, allowing to speedup the
display of needaction counters and documents having unread messages

View File

@ -76,9 +76,9 @@ This phase also generates the ``rows`` indexes for any
Conversion
++++++++++
This second phase takes the record dicts, extracts the :ref:`dbid` and
:ref:`xid` if present and attempts to convert each field to a type
matching what OpenERP expects to write.
This second phase takes the record dicts, extracts the :term:`database
ID` and :term:`external ID` if present and attempts to convert each
field to a type matching what OpenERP expects to write.
* Empty fields (empty strings) are replaced with the ``False`` value
@ -141,14 +141,14 @@ If ``name_search`` finds no value, an error is generated. If
``name_search`` finds multiple value, a warning is generated to warn
the user of ``name_search`` collisions.
If the specified field is a :ref:`xid` (``m2o/id``), the
If the specified field is a :term:`external ID` (``m2o/id``), the
corresponding record it looked up in the database and used as the
field's value. If no record is found matching the provided external
ID, an error is generated.
If the specified field is a :ref:`dbid` (``m2o/.id``), the process is
the same as for external ids (on database identifiers instead of
external ones).
If the specified field is a :term:`database ID` (``m2o/.id``), the
process is the same as for external ids (on database identifiers
instead of external ones).
Many to Many field
~~~~~~~~~~~~~~~~~~
@ -161,11 +161,11 @@ One to Many field
~~~~~~~~~~~~~~~~~
For each o2m record extracted, if the record has a ``name``,
:ref:`xid` or :ref:`dbid` the :ref:`dbid` is looked up and checked
through the same process as for m2o fields.
:term:`external ID` or :term:`database ID` the :term:`database ID` is
looked up and checked through the same process as for m2o fields.
If a :ref:`dbid` was found, a LINK_TO command is emmitted, followed by
an UPDATE with the non-db values for the relational field.
If a :term:`database ID` was found, a LINK_TO command is emmitted,
followed by an UPDATE with the non-db values for the relational field.
Otherwise a CREATE command is emmitted.

View File

@ -27,5 +27,15 @@ OpenERP Server API
api_core.rst
api_models.rst
Concepts
''''''''
.. glossary::
Database ID
The primary key of a record in a PostgreSQL table (or a
virtual version thereof), usually varies from one database to
the next.
External ID

View File

@ -85,7 +85,6 @@ The kernel of OpenERP, needed for all installation.
'res/ir_property_view.xml',
'security/base_security.xml',
'security/ir.model.access.csv',
'security/ir.model.access-1.csv', # res.partner.address is deprecated; it is still there for backward compability only and will be removed in next version
],
'demo': [
'base_demo.xml',

View File

@ -32,6 +32,7 @@
<record id="main_partner" model="res.partner" context="{'default_is_company': True}">
<field name="name">Your Company</field>
<field name="company_id" eval="None"/>
<field name="image" eval="False"/>
<field name="customer" eval="False"/>
<field name="is_company" eval="True"/>
<field name="street"></field>

View File

@ -7,6 +7,74 @@
<field name="customer" eval="False"/>
<field name="email">demo@example.com</field>
</record>
<record id="main_partner" model="res.partner">
<field name="image">iVBORw0KGgoAAAANSUhEUgAAALQAAAAuCAYAAACBMDMXAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDCAo7GWN31l0AAA1fSURBVHja
7Zx5dFXFHcc/eQk7KBiUTVGRRezA8ahYamgRFbWAcmyPe+uGSrW1FrFqF9u61bZWm1Kx1lgVpHVp
3ShVVBTcBYSyDHHBulEUhVRBRJJA0j/m95rJZOa++zYS2vs95xLevLkzc+d+72++v99v7oMECRIk
SJAgQYIECRIkSJAgQYIECQqB9skUFA4luZ6ooRzoA/QGPgWqlfn7/4aBwJHAEUA/oANwA3C/Vaen
/N3gnPs14ErgaGB9QscdSGgNewHj5TgC6Oyp9h6wylTnUQULdsI52U2Oj4GaiHoVwC3AcM93a4DB
QHfgAeAwoBFYAVwjZe2AamA/ma8jA6SeAowDtgH18neb9Rmg1DrK5Ggn1r+dlH8ObAE+A24D5su5
/YCZVtvu30an/XQf7eXYJNe7BlhMvHs+DPhNRJ8pGbd9Lem/24C10t/bMpebsrHEAzXco6FBQ6Mc
72qYoeEaDZdoqNKwSMMWq06jhuc1jNxJiHww8ILcwEaZuHnANz0P/qFAg1XXd9wKvB/4bgZwvnxf
AawTsu/uGddlwKtCxsYCHZOs9vsBS4APCtT2QuCYGIReBnxUgP4+Aa4DukRaaG2Wzl8D35KnA7Eo
l4v1bfCcs4c87fYF1QMXK/h9GybzaOBpsQw+PAucC6yWzw8CJ+TZZwPwE7kZ+wBzgVpZ/WoCq+kM
ecBcrBDS18pRJ39LgF5yfBHoKvUnAH/3tHMg8A9P+RZgmvRRAwwAFHAG0NFTf5vM6Ysx5uFY4DFP
+QYxCq8DG4Eh0uaEQDuzAnNjiKnhRcfaPqShWwyLXqLhaufcRg3faKNk3gV4N4Yl+Fz0bgdgeYz6
f5KlfVtEnanWOMqFMEuBHoGxTgq0c3FMKfWW1D84ot7HnvbXBOr2F0PgG9O/gE4xxtUhcP7iQP3j
ga2Bc071EXKASAqbjPN12Hr52ijV8KbTxgbtX1JbGzOyXOLWigXMVCf98A8RvfhhoF6ZNZZ9RH4s
Bnb1jHVCHoQGeFzq94uo81oWhEZkUkg6fCnmuD7JgtCI0+3r7+6UQ8TOwEPy5KWxHjjdJzFCULAd
+IVTXA5UtjEydw8uU2HUyTLow/sit74rcqKv1J0iJJoo0Y8tUr8vcJR1/jtC2qHyoLnINxKyVm78
RxF1su1jfcR9PTiLNrLBTYHy4a7VvcPjtV+vzI3KFjNFx9k4TRuHqq1gRIZIT4M4TDeKZu4D7CtO
zUjReD8SP2M8cJI4jA8A35eyPpaunA2cjPE1TgWeEX1o4xXgFOA44ETnu9o8r3eatFkfUSeXPpYH
yrvFPD/bPj/AHyIuL7Os8wSZbByHblYuM6egTpsw3iAPiRa1EULv7SHwCglpLRBn8BPPeZ2B74im
rXO+SwFnAXfJ3E0HrnCs4mfAvcB9gXHNEX29scDXu0yOQmNdlkQvBNYAB7j92frtp76JVfktc+94
CD00jmMp9d5ULQnj1h0EbFXROi+EOw+Exy6FASWwsRLeWGwcjkiUwujr4Y5x0Khafv2cRBNKgc+v
g6pnYfDj/mW+MaKbtibPouDTyltltSkWenrKlpZZ1vkQT4U78uz0XU/Z/hHkbC9L9cXibMwEzvTU
GwX8QEJR5VI2WZmoQhyntauE4c6Wp7wM4E7zUFyojIWMM747gXM89Z4GLpIQZ++JUHsjjFHwUisR
bprM0+lFav9wT9k1GbR6Pugmss3FC2kLfWZgGZmbZ8c+bTQ0QJZREuayv+/qIeL1wLc92ncSGQit
Tabph8D3MIH4hRJ9SHv9ewH3aRimTIgr0/jae/oYIpJhoBOaGkfrEfqrGXRzPhiGSd03I5ZEIoqF
SZ6yB4C5KW2s01hfBWUcmXzQ31NW5hAgpY1jtcBD9lVWvaHAStGuPhkyTJtlPkTmgZhA/8/EcgxR
8GXR0fc7+nhCzPEtcvoYLaQd6BnCm61E5nJgT2JIqRywPyabajt/DwqfivUA7Ss+iRu9OT9NrsPw
xzzfKEDn/QMeapoAe4jjNFb6G+wjtDb7HeYBm2WJv18mzrYMnYRIr3vIPAIjA7piQopHK5FDCrZr
uFsiFM30mTO+1R5/YKHVxxlAlTgr9Z4lcVkRSXuO3Mc6uT77OoZhsnm1Beqri0RuTpSVLn2dS0Rm
zM7gG2SLMZjsZAlmm8BVjn5+DRN6/Xea0KG9Fu8VIYrQjNDypJViUq4rMOnO3azvq7WRA08Joc9O
x8M1POFZ6uo9ZO4LPGzJl4dVS23fxflcHRhfDU1ZvLo0SbWJOU/FkPovMsF3We3VWW0WA8Pxb5LC
GUO+eASTqXOxUqJXjUW4tmnG7njl7M8x+Y46e/nvlYVDFxuSJu8eiHzYkZXNymQSu9A85VsvVnu2
jOU8J7nzsaftDZ6yKgyp0/idp44tudbT5BTa49vFGd8yBbXaWKpLxOovtOSNjZdV8ZZggEdlBdps
WeISWfEmilRqV4B+7gkQepgs+X8owrVdIM57bwljLpdjCZ4IXFnAW8yb0AG5AcayIsu9HRwf7Dh6
K4DTRDON9ITvXD1bp5xthLLl9VjbkiiTzLDrfEUmDEwGb7IyxHDH58Y8F2mjTacBxyhLfnjCWPOK
rJOfAH4b+G6WWNCOBejnXrknx3m+uwGzyei9Al/b83LEQgr//orNSjRJHjgksOw9GeFguJLnWmB8
YCwHxHC6zqL5HpQqh8xjxTtOiV4foUzq3wfl8eTvBipVcy2domU2tNiEjsIqTKa3QwEt5qZAKK2K
VkYqECssxFN2lqdsftr6xSD0OGCmatqymSn896RD1hLL8v63/3RoTcPNEpbsJuG4Q1W0zrUJvV10
dZknPKUcr/9Tojfa7AgspHBvxKzF7NH24Wg8cfkdTehXPeWleernAZgQlm9ZCmGI83kL8MtA+50x
O9O8UkYwWuSK7USM1Sb8ls7mnQj0VEZmbMlwWV+wVzDx8M/3bNpy5caCAoQ/88XX8Sc/csVtONLN
wk1E7+YrKsoChO5fAOtc4rHOT0Wc40qI6cq/jwJMksNuf6Nngke4MkrCTT8GXlLNw1uZHtAUcJBV
tKtES3xzV+F8for/PTQC54mf42rzXcU5nNBaFtq3zHbKde+y3Hw389iASVVHRURcQs+O6MaVEtOU
2fBjw400PK3gMgXPZ0NmwaE0DycSWj0w8eC2op996IlxlvPFakySyofxmBBmqxD6nwGRPyiP5c21
8Jc5UQAXIx2Z8yGBjS3ahM5OcCxvZYzx1+QxT+Ocz0sVvOwZWy9MEiiNTcrKdrYRzCHeq1FxcCPm
DRsfKmnaOrvjCC3Wymc9L8rBOvel5buDdylz4VEY5Xyeq8JB+tMcj/3SQBRkkOfhzTT+kpiEnh+o
V+GJMLQldMVsuo96uDvGLAPjG0zC7yP0IP57pL72O+VEaPl7Ky0tzkk6xlZPiwydMO/RlVvF9wGT
Y5zuEuHZiLq2F12pPMF8IWafDKR0zxkLLNWOsylW9yCn+nMx5YaWf8o0XKmbz00uKMnz/FHiN9Vk
kCQudoswCMsinP2JYoDiyCAXvXImtHjq59E8m5XC/DzBHjHI3AsTPTjcchquAk6NsZ+5FLMN1MaL
gbqThVwNmJTnVF89se5vO8V76pYrARqGaxO+e0wcSzfbeKxDpEbCgX73wewtLwdrebB750nIXM/v
iElcnRJDfvUM8KRHxDlXE977c7MTIXLRDv9eonJyiLaVWSTQ2ujf6ZbTUAEs18bJe9KVAaJnz8W8
M5e2iK+KZp4TcwwH4mwTBa7ScJOVSu6CeWVpOmZb5xnKJDai8JzHMZyrTcjpbem3Qm7048DwQBza
tezVykMIbUjjWvLj5JgBTFH+dH02ODlQfqlYwjrrqBcrtzfGKJVE+BPt5f6N9ji/aVyAyRSuxbwB
b2Or8OAZzyrSQxzjKcDfaHLeO2Ik6vERq9GFovk/JHNY1b+ECXmuxOxPsPP/myRMsxITlRiE2RDT
yfJ6rwVmZfNCrTYvlIbStpsxKfj9ZAKqgEsikjN2u70lghNlWaqBqSqw71u21q6n+Z6UW5W5uW7d
AzyaeQ0mVp3vvvI9MSns0QXS0tdhwpfI3Ga7tXU8Zv+Ii1vwzI2F20UJVJBFOltwWxz5WuZZrj8D
rtDGqpyE0dFDxZKNshy4GiH4HGC2Mv/PVdfZqBWLUYJJoJQCfwX+rPw/SEJAdqzTxgGqFNnQXuTC
aszGlnnAjAwhvH3lvGWy8lRjUuU+pH9T4yB56B8BflWg3/vrLku6pumHZNI/pZD+2az0z365Rz1N
P0CTPh622v4U+KPUSx91lvz0tbk2MM7LZTz1YsW3Csc6ypGOdH1k9Vnn9G33WWb9/6WcLHSExUth
HKZtwDpVmO2IaDM5fZ3oyu0iez6IY41j9FEqS+8Glc3voGXfTwrYXZklMkEroKQ1O9fGAr7lRgpa
8d27BDs5Uq3cvxsV2E5x3+xIkBC6qHD18yrV0oNOkGCntdBLkluSYKcktGTN3ID7K8ktSbCzWugx
Hqc0IXSCnZbQRzqf68k9lp0gQasT+iiPQ7g1uSUJ8kFZK+nn/ph9Fo2Y1PZKmv96UYIEOeE/+J4k
BZrmED0AAAAASUVORK5CYII=
</field>
</record>
<record id="user_demo" model="res.users">
<field name="partner_id" ref="base.partner_demo"/>
<field name="login">demo</field>
@ -14,7 +82,7 @@
<field name="signature">--
Mr Demo</field>
<field name="company_id" ref="main_company"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_user'), ref('base.group_partner_manager')])]"/>
<field name="image">/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP
ERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e
Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCACEAIQDASIA

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-server\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-08-20 15:47+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"PO-Revision-Date: 2012-12-16 23:21+0000\n"
"Last-Translator: David Bowers <sales@skitzotek.com>\n"
"Language-Team: English (United Kingdom) <en_GB@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: 2012-12-04 05:02+0000\n"
"X-Generator: Launchpad (build 16335)\n"
"X-Launchpad-Export-Date: 2012-12-17 04:44+0000\n"
"X-Generator: Launchpad (build 16372)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -48,7 +48,7 @@ msgid ""
"The second argument of the many2many field %s must be a SQL table !You used "
"%s, which is not a valid SQL table name."
msgstr ""
"The second argument of the many2many field %s must be a SQL table !You used "
"The second argument of the many2many field %s must be a SQL table! You used "
"%s, which is not a valid SQL table name."
#. module: base
@ -101,7 +101,7 @@ msgstr ""
msgid ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
msgstr ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
"Model name in which the method to be called is located, e.g. 'res.partner'."
#. module: base
#: view:ir.module.module:0
@ -123,6 +123,17 @@ msgid ""
" * Product Attributes\n"
" "
msgstr ""
"\n"
"A module which adds manufacturers and attributes to the product form.\n"
"=====================================================================\n"
"\n"
"You can now define the following for a product:\n"
"-----------------------------------------------\n"
" * Manufacturer\n"
" * Manufacturer Product Name\n"
" * Manufacturer Product Code\n"
" * Product Attributes\n"
" "
#. module: base
#: field:ir.actions.client,params:0
@ -226,6 +237,35 @@ msgid ""
"* Planned Revenue by Stage and User (graph)\n"
"* Opportunities by Stage (graph)\n"
msgstr ""
"\n"
"The generic OpenERP Customer Relationship Management\n"
"=====================================================\n"
"\n"
"This application enables a group of people to intelligently and efficiently "
"manage leads, opportunities, meetings and phone calls.\n"
"\n"
"It manages key tasks such as communication, identification, prioritization, "
"assignment, resolution and notification.\n"
"\n"
"OpenERP ensures that all cases are successfully tracked by users, customers "
"and suppliers. It can automatically send reminders, escalate a request, "
"trigger specific methods and many other actions based on your own enterprise "
"rules.\n"
"\n"
"The greatest thing about this system is that users don't need to do anything "
"special. The CRM module has an email gateway for the synchronization "
"interface between mails and OpenERP. That way, users can just send emails to "
"the request tracker.\n"
"\n"
"OpenERP will take care of thanking them for their message, automatically "
"routing it to the appropriate staff and make sure all future correspondence "
"gets to the right place.\n"
"\n"
"\n"
"Dashboard for CRM will include:\n"
"-------------------------------\n"
"* Planned Revenue by Stage and User (graph)\n"
"* Opportunities by Stage (graph)\n"
#. module: base
#: code:addons/base/ir/ir_model.py:397
@ -235,7 +275,7 @@ msgid ""
"them through Python code, preferably through a custom addon!"
msgstr ""
"Properties of base fields cannot be altered in this manner! Please modify "
"them through Python code, preferably through a custom addon!"
"them through Python code, preferably by a custom addon!"
#. module: base
#: code:addons/osv.py:130
@ -318,6 +358,7 @@ msgid ""
"The internal user that is in charge of communicating with this contact if "
"any."
msgstr ""
"The internal user who is in charge of communicating with this contact if any."
#. module: base
#: view:res.partner:0
@ -625,6 +666,19 @@ msgid ""
"* Use emails to automatically confirm and send acknowledgements for any "
"event registration\n"
msgstr ""
"\n"
"Organization and management of Events.\n"
"======================================\n"
"\n"
"The event module allows you to efficiently organise events and all related "
"tasks: planning, registration tracking,\n"
"attendance, etc.\n"
"\n"
"Key Features\n"
"------------\n"
"* Manage your Events and Registrations\n"
"* Use emails to automatically confirm and send acknowledgements for any "
"event registration\n"
#. module: base
#: selection:base.language.install,lang:0
@ -860,7 +914,7 @@ msgstr "Eritrea"
#. module: base
#: sql_constraint:res.company:0
msgid "The company name must be unique !"
msgstr "The company name must be unique !"
msgstr "The company name must be unique!"
#. module: base
#: model:ir.ui.menu,name:base.menu_base_action_rule_admin
@ -884,6 +938,9 @@ msgid ""
"image, with aspect ratio preserved. Use this field anywhere a small image is "
"required."
msgstr ""
"Small-sized image of this contact. It is automatically resized to 64x64 "
"pixels with the aspect ratio preserved. Use this field anywhere a small "
"image is required."
#. module: base
#: help:ir.actions.server,mobile:0
@ -892,7 +949,7 @@ msgid ""
"invoice, then `object.invoice_address_id.mobile` is the field which gives "
"the correct mobile number"
msgstr ""
"Provides fields that be used to fetch the mobile number, e.g. you select the "
"Provides fields used to fetch the mobile number, e.g. you select the "
"invoice, then `object.invoice_address_id.mobile` is the field which gives "
"the correct mobile number"
@ -988,8 +1045,6 @@ msgid ""
"Provide the field name that the record id refers to for the write operation. "
"If it is empty it will refer to the active id of the object."
msgstr ""
"Provide the field name that the record id refers to for the write operation. "
"If it is empty it will refer to the active id of the object."
#. module: base
#: help:ir.actions.report.xml,report_type:0
@ -1089,6 +1144,13 @@ msgid ""
"actions(Sign in/Sign out) performed by them.\n"
" "
msgstr ""
"\n"
"This module aims to manage employees' attendances.\n"
"==================================================\n"
"\n"
"Keeps account of the attendances of employees based on the\n"
"actions (Sign in/Sign out) performed by them.\n"
" "
#. module: base
#: model:res.country,name:base.nu
@ -1148,7 +1210,7 @@ msgid ""
msgstr ""
"Expression containing a value specification. \n"
"When Formula type is selected, this field may be a Python expression that "
"can use the same values as for the condition field on the server action.\n"
"can use the same values as the condition field on the server action.\n"
"If Value type is selected, the value will be used directly without "
"evaluation."
@ -1234,7 +1296,7 @@ msgstr "Guam (USA)"
#. module: base
#: sql_constraint:res.country:0
msgid "The name of the country must be unique !"
msgstr "The country name must be unique !"
msgstr "The country name must be unique!"
#. module: base
#: field:ir.module.module,installed_version:0
@ -1382,9 +1444,9 @@ msgid ""
"decimal number [00,53]. All days in a new year preceding the first Monday "
"are considered to be in week 0."
msgstr ""
"%W - Week number of the year (Monday as the first day of the week) as a "
"decimal number [00,53]. All days in a new year preceding the first Monday "
"are considered to be in week 0."
"%W - Week number of the year (Monday being the first day of the week) as an "
"integer [00,53]. All days in a new year preceding the first Monday are "
"considered to be in week 0."
#. module: base
#: code:addons/base/module/wizard/base_language_install.py:53
@ -1724,8 +1786,8 @@ msgid ""
"'%s' contains too many dots. XML ids should not contain dots ! These are "
"used to refer to other modules data, as in module.reference_id"
msgstr ""
"'%s' contains too many dots. XML ids should not contain dots ! These are "
"used to refer to other modules data, as in module.reference_id"
"'%s' contains too many dots. XML ids should not contain dots! These are used "
"to refer to other modules' data, as in module.reference_id"
#. module: base
#: model:ir.module.module,summary:base.module_sale
@ -1872,8 +1934,8 @@ msgid ""
"simplified payment mode encoding, automatic picking lists generation and "
"more."
msgstr ""
"Get the most out of your points of sales with fast sale encoding, simplified "
"payment mode encoding, automatic picking lists generation and more."
"Get the most out of your points of sale with fast sale encoding, simplified "
"payment mode encoding, automatic pick list generation and more."
#. module: base
#: code:addons/base/ir/ir_fields.py:165
@ -2021,6 +2083,14 @@ msgid ""
"with the effect of creating, editing and deleting either ways.\n"
" "
msgstr ""
"\n"
"Synchronization of project task work entries with timesheet entries.\n"
"====================================================================\n"
"\n"
"This module lets you transfer the entries under tasks defined for Project\n"
"Management to the Timesheet line entries for a particular date and user\n"
"with the effect of creating, editing and deleting either way.\n"
" "
#. module: base
#: model:ir.model,name:base.model_ir_model_access
@ -2132,6 +2202,25 @@ msgid ""
"* *Before Delivery*: A Draft invoice is created and must be paid before "
"delivery\n"
msgstr ""
"\n"
"Manage sales quotations and orders\n"
"==================================\n"
"\n"
"This module makes the link between the sales and warehouse management "
"applications.\n"
"\n"
"Preferences\n"
"-----------\n"
"* Shipping: Choice of delivery at once or partial delivery\n"
"* Invoicing: choose how invoices will be paid\n"
"* Incoterms: International Commercial terms\n"
"\n"
"You can choose flexible invoicing methods:\n"
"\n"
"* *On Demand*: Invoices are created manually from Sales Orders when needed\n"
"* *On Delivery Order*: Invoices are generated from picking (delivery)\n"
"* *Before Delivery*: A Draft invoice is created and must be paid before "
"delivery\n"
#. module: base
#: field:ir.ui.menu,complete_name:0
@ -2155,9 +2244,9 @@ msgid ""
"decimal number [00,53]. All days in a new year preceding the first Sunday "
"are considered to be in week 0."
msgstr ""
"%U - Week number of the year (Sunday as the first day of the week) as a "
"decimal number [00,53]. All days in a new year preceding the first Sunday "
"are considered to be in week 0."
"%U - Week number of the year (Sunday being the first day of the week) as an "
"integer [00,53]. All days in a new year preceding the first Sunday are "
"considered to be in week 0."
#. module: base
#: view:base.language.export:0
@ -2316,6 +2405,28 @@ msgid ""
"* Maximal difference between timesheet and attendances\n"
" "
msgstr ""
"\n"
"Record and validate timesheets and attendance easily\n"
"====================================================\n"
"\n"
"This application supplies a new screen enabling you to manage both "
"attendance (Sign in/Sign out) and your work encoding (timesheet) by period. "
"Timesheet entries are made by employees each day. At the end of the defined "
"period, employees validate their sheet and the manager must then approve "
"their team's entries. Periods are defined in the company forms and you can "
"set them to run monthly or weekly.\n"
"\n"
"The complete timesheet validation process is:\n"
"---------------------------------------------\n"
"* Draft sheet\n"
"* Confirmation at the end of the period by the employee\n"
"* Validation by the project manager\n"
"\n"
"The validation can be configured in the company:\n"
"------------------------------------------------\n"
"* Period size (Day, Week, Month)\n"
"* Maximal difference between timesheet and attendances\n"
" "
#. module: base
#: code:addons/base/ir/ir_fields.py:342
@ -2371,7 +2482,7 @@ msgstr "Belize"
#. module: base
#: help:ir.actions.report.xml,header:0
msgid "Add or not the corporate RML header"
msgstr "Add or not the corporate RML header"
msgstr "Optionally add the corporate RML header"
#. module: base
#: model:res.country,name:base.ge
@ -2410,6 +2521,32 @@ msgid ""
"\n"
" "
msgstr ""
"\n"
" \n"
"Belgian localization for in/outgoing invoices (prereq to account_coda):\n"
"=========================================================================\n"
" - Rename 'reference' field labels to 'Communication'\n"
" - Add support for Belgian Structured Communication\n"
"\n"
"A Structured Communication can be generated automatically on outgoing "
"invoices according to the following algorithms:\n"
"-----------------------------------------------------------------------------"
"----------------------------------------\n"
" 1) Random : +++RRR/RRRR/RRRDD+++\n"
" **R..R =** Random Digits, **DD =** Check Digits\n"
" 2) Date : +++DOY/YEAR/SSSDD+++\n"
" **DOY =** Day of the Year, **SSS =** Sequence Number, **DD =** Check "
"Digits\n"
" 3) Customer Reference +++RRR/RRRR/SSSDDD+++\n"
" **R..R =** Customer Reference without non-numeric characters, **SSS "
"=** Sequence Number, **DD =** Check Digits \n"
" \n"
"The preferred type of Structured Communication and associated Algorithm can "
"be\n"
"specified on the Partner records. A 'random' Structured Communication will\n"
"generated if no algorithm is specified on the Partner record. \n"
"\n"
" "
#. module: base
#: model:res.country,name:base.pl
@ -2454,8 +2591,8 @@ msgid ""
"order in Object, and you can have loop on the sales order line. Expression = "
"`object.order_line`."
msgstr ""
"Enter the field/expression that will return the list. E.g. select the sale "
"order in Object, and you can have loop on the sales order line. Expression = "
"Enter the field/expression that will return the list. E.g. selecting the "
"sale order in Object, you can loop on the sales order line: Expression = "
"`object.order_line`."
#. module: base
@ -2546,6 +2683,27 @@ msgid ""
"Print product labels with barcode.\n"
" "
msgstr ""
"\n"
"This is the base module for managing products and pricelists in OpenERP.\n"
"========================================================================\n"
"\n"
"Products support variants, various pricing methods, supplier information,\n"
"made to stock/order, different units of measures, packaging and other "
"properties.\n"
"\n"
"Pricelists support:\n"
"-------------------\n"
" * Multiple-levels of discount (by product, category, quantities)\n"
" * Compute price based on different criteria:\n"
" * Other pricelist\n"
" * Cost price\n"
" * List price\n"
" * Supplier price\n"
"\n"
"Set pricelist preferences by product and/or partner.\n"
"\n"
"Print product labels with barcode.\n"
" "
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_default
@ -2563,6 +2721,18 @@ msgid ""
" * Date\n"
" "
msgstr ""
"\n"
"Set default values for your analytic accounts.\n"
"==============================================\n"
"\n"
"Allows to automatically select analytic accounts based on criteria:\n"
"---------------------------------------------------------------------\n"
" * Product\n"
" * Partner\n"
" * User\n"
" * Company\n"
" * Date\n"
" "
#. module: base
#: field:res.company,rml_header1:0
@ -2887,6 +3057,29 @@ msgid ""
"* Purchase Analysis\n"
" "
msgstr ""
"\n"
"Manage goods requirement by Purchase Orders easily\n"
"==================================================\n"
"\n"
"Purchase management enables you to track your suppliers' price quotations "
"and convert them into purchase orders if necessary.\n"
"OpenERP has several methods of monitoring invoices and tracking the receipt "
"of ordered goods. You can handle partial deliveries in OpenERP with the "
"ability to keep track of items yet to be delivered from orders and to issue "
"reminders automatically.\n"
"\n"
"OpenERPs replenishment-management rules enable the system to generate draft "
"purchase orders automatically. Alternatively you can configure it to run a "
"lean process driven entirely by current production needs.\n"
"\n"
"Dashboard / Reports for Purchase Management will include:\n"
"---------------------------------------------------------\n"
"* Request for Quotations\n"
"* Purchase Orders Waiting Approval \n"
"* Monthly Purchases by Category\n"
"* Receptions Analysis\n"
"* Purchase Analysis\n"
" "
#. module: base
#: model:ir.model,name:base.model_ir_actions_act_window_close
@ -3016,6 +3209,15 @@ msgid ""
" * ``base_stage``: stage management\n"
" "
msgstr ""
"\n"
"This module handles state and stage. It is derived from the crm_base and "
"crm_case classes of crm.\n"
"============================================================================="
"======================\n"
"\n"
" * ``base_state``: state management\n"
" * ``base_stage``: stage management\n"
" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_linkedin
@ -3312,6 +3514,8 @@ msgid ""
"For more details about translating OpenERP in your language, please refer to "
"the"
msgstr ""
"For more details about translating OpenERP into your language, please refer "
"to the"
#. module: base
#: field:res.partner,image:0
@ -3563,19 +3767,11 @@ msgid ""
"Canadian accounting charts and localizations.\n"
" "
msgstr ""
"\n"
"This is the module to manage the English and French - Canadian accounting "
"chart in OpenERP.\n"
"============================================================================="
"==============\n"
"\n"
"Canadian accounting charts and localisations.\n"
" "
#. module: base
#: view:base.module.import:0
msgid "Select module package to import (.zip file):"
msgstr "Select module package to import (.zip file):"
msgstr "Select module package to import (*.zip file):"
#. module: base
#: view:ir.filters:0
@ -3674,6 +3870,14 @@ msgid ""
"easily\n"
"keep track and order all your purchase orders.\n"
msgstr ""
"\n"
"This module allows you to manage your Purchase Requisition.\n"
"===========================================================\n"
"\n"
"When a purchase order is created, you now have the opportunity to save the\n"
"related requisition. By regrouping, this new object will allow you to "
"easily\n"
"keep track of and order all your purchase orders.\n"
#. module: base
#: help:ir.mail_server,smtp_host:0
@ -3798,13 +4002,13 @@ msgstr "If not set, acts as a default value for new resources"
#: code:addons/orm.py:4213
#, python-format
msgid "Recursivity Detected."
msgstr "Recursivity detected."
msgstr "Recursion detected."
#. module: base
#: code:addons/base/module/module.py:345
#, python-format
msgid "Recursion error in modules dependencies !"
msgstr "Recursion error in modules dependencies !"
msgstr "Recursion error in modules dependencies!"
#. module: base
#: model:ir.module.module,description:base.module_analytic_user_function

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-12-09 23:26+0000\n"
"Last-Translator: lambdasoftware <development@lambdasoftware.net>\n"
"PO-Revision-Date: 2012-12-13 16:14+0000\n"
"Last-Translator: Roberto Lizana (trey.es) <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: 2012-12-10 04:36+0000\n"
"X-Generator: Launchpad (build 16341)\n"
"X-Launchpad-Export-Date: 2012-12-14 05:35+0000\n"
"X-Generator: Launchpad (build 16369)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -97,7 +97,7 @@ msgstr "Interfaz de pantalla táctil para tiendas"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
msgid "Indian Payroll"
msgstr ""
msgstr "Nomina de la India"
#. module: base
#: help:ir.cron,model:0
@ -365,6 +365,8 @@ msgid ""
"Database ID of record to open in form view, when ``view_mode`` is set to "
"'form' only"
msgstr ""
"Id. de la base datos del registro para abrir en el formulario de vista, "
"cuando se establece el modo de visto únicamente a 'formulario'"
#. module: base
#: field:res.partner.address,name:0
@ -440,6 +442,8 @@ msgid ""
"There is already a shared filter set as default for %(model)s, delete or "
"change it before setting a new default"
msgstr ""
"Ya existe un filtro compartido por defecto para %(model)s, elimínelo o "
"cámbielo antes de configurar uno nuevo"
#. module: base
#: code:addons/orm.py:2648
@ -591,7 +595,7 @@ msgstr "Guayana francesa"
#. module: base
#: model:ir.module.module,summary:base.module_hr
msgid "Jobs, Departments, Employees Details"
msgstr ""
msgstr "Trabajos, departamentos y detalles de empleados"
#. module: base
#: model:ir.module.module,description:base.module_analytic
@ -607,6 +611,16 @@ msgid ""
"that have no counterpart in the general financial accounts.\n"
" "
msgstr ""
"\n"
"Módulo para definir el objeto contabilidad analítica\n"
"===============================================\n"
"\n"
"En OpenERP, las cuentas analíticas están enlazadas con las cuentas "
"generales\n"
"pero se tratan de forma totalmente independiente. Por tanto, se pueden "
"introducir\n"
"operaciones analíticas sin contrapartida en la contabilidad financiera\n"
" "
#. module: base
#: field:ir.ui.view.custom,ref_id:0
@ -630,6 +644,26 @@ msgid ""
"* Use emails to automatically confirm and send acknowledgements for any "
"event registration\n"
msgstr ""
"\n"
"Organización y gestión de eventos.\n"
"======================================\n"
"\n"
"EL módulo 'event' le permite organizar eventos y todas sus tareas "
"relacionadas de forma eficiente: planificación,\n"
"seguimiento del registro, asistencia, etc...\n"
"\n"
"Funcionalidades clave\n"
"------------------------\n"
"* Gestione sus eventos y registros\n"
"* Use emails para confirmar y enviar automáticamente acuses de recibo para "
"cada evento del registro\n"
"\n"
"\n"
"Key Features\n"
"------------\n"
"* Manage your Events and Registrations\n"
"* Use emails to automatically confirm and send acknowledgements for any "
"event registration\n"
#. module: base
#: selection:base.language.install,lang:0
@ -839,6 +873,11 @@ msgid ""
"This module provides the Integration of the LinkedIn with OpenERP.\n"
" "
msgstr ""
"\n"
"Módulo web de LinkedIn para OpenERP.\n"
"=================================\n"
"Este módulo provee integración de LinkedIn con OpenERP.\n"
" "
#. module: base
#: help:ir.actions.act_window,src_model:0
@ -886,7 +925,7 @@ msgstr "Rumanía - Contabilidad"
#. module: base
#: model:ir.model,name:base.model_res_config_settings
msgid "res.config.settings"
msgstr ""
msgstr "Parámetros de configuración"
#. module: base
#: help:res.partner,image_small:0
@ -916,7 +955,7 @@ msgstr "Seguridad y autenticación"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_calendar
msgid "Web Calendar"
msgstr ""
msgstr "Calendario web"
#. module: base
#: selection:base.language.install,lang:0
@ -1041,6 +1080,7 @@ msgstr "Zimbabwe"
msgid ""
"Type of the constraint: `f` for a foreign key, `u` for other constraints."
msgstr ""
"Tipo de restricción: 'f' para un clave ajena, 'u' para otras restricciones."
#. module: base
#: view:ir.actions.report.xml:0
@ -1129,7 +1169,7 @@ msgstr "Otra licencia aprobada por OSI"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_gantt
msgid "Web Gantt"
msgstr ""
msgstr "Diagrama Gantt web"
#. module: base
#: model:ir.actions.act_window,name:base.act_menu_create
@ -1182,7 +1222,7 @@ msgstr "Principado de Andorra"
#. module: base
#: field:ir.rule,perm_read:0
msgid "Apply for Read"
msgstr ""
msgstr "Aplicar para lectura"
#. module: base
#: model:res.country,name:base.mn
@ -1212,7 +1252,7 @@ msgstr ""
#: code:addons/base/ir/ir_model.py:727
#, python-format
msgid "Document model"
msgstr ""
msgstr "Modelo de documento"
#. module: base
#: view:res.lang:0
@ -1262,12 +1302,12 @@ msgstr "¡El nombre del país debe ser único!"
#. module: base
#: field:ir.module.module,installed_version:0
msgid "Latest Version"
msgstr ""
msgstr "Última versión"
#. module: base
#: view:ir.rule:0
msgid "Delete Access Right"
msgstr ""
msgstr "Eliminar derecho de acceso"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:213
@ -1294,7 +1334,7 @@ msgstr "Islas Caimán"
#. module: base
#: view:ir.rule:0
msgid "Record Rule"
msgstr ""
msgstr "Regla de registro"
#. module: base
#: model:res.country,name:base.kr
@ -1423,7 +1463,7 @@ msgstr "Tests"
#. module: base
#: field:ir.actions.report.xml,attachment:0
msgid "Save as Attachment Prefix"
msgstr ""
msgstr "Prefijo del adjunto al guardar como"
#. module: base
#: field:ir.ui.view_sc,res_id:0
@ -1460,7 +1500,7 @@ msgstr "Haití"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_fr_hr_payroll
msgid "French Payroll"
msgstr ""
msgstr "Nomina de Francia"
#. module: base
#: view:ir.ui.view:0
@ -1631,7 +1671,7 @@ msgstr "No existe un idioma con código \"%s\""
#: model:ir.module.category,name:base.module_category_social_network
#: model:ir.module.module,shortdesc:base.module_mail
msgid "Social Network"
msgstr ""
msgstr "Red social"
#. module: base
#: view:res.lang:0
@ -1641,12 +1681,12 @@ msgstr "%Y - Año con siglo."
#. module: base
#: view:res.company:0
msgid "Report Footer Configuration"
msgstr ""
msgstr "Configuración de pie de informe"
#. module: base
#: field:ir.translation,comments:0
msgid "Translation comments"
msgstr ""
msgstr "Comentarios de traducción"
#. module: base
#: model:ir.module.module,description:base.module_lunch
@ -1711,7 +1751,7 @@ msgstr ""
#. module: base
#: help:res.partner,website:0
msgid "Website of Partner or Company"
msgstr ""
msgstr "Sitio web de la empresa o compañía"
#. module: base
#: help:base.language.install,overwrite:0
@ -1758,7 +1798,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_sale
msgid "Quotations, Sale Orders, Invoicing"
msgstr ""
msgstr "Presupuestos, órdenes de venta, facturación"
#. module: base
#: field:res.users,login:0
@ -1909,6 +1949,7 @@ msgstr ""
#, python-format
msgid "Unknown value '%s' for boolean field '%%(field)s', assuming '%s'"
msgstr ""
"Valor desconocido '%s' para el campo booleano '%%(field)s', se asume '%s'"
#. module: base
#: model:res.country,name:base.nl
@ -1923,7 +1964,7 @@ msgstr ""
#. module: base
#: selection:ir.translation,state:0
msgid "Translation in Progress"
msgstr ""
msgstr "Traducción en curso"
#. module: base
#: model:ir.model,name:base.model_ir_rule
@ -1938,7 +1979,7 @@ msgstr "Días"
#. module: base
#: model:ir.module.module,summary:base.module_fleet
msgid "Vehicle, leasing, insurances, costs"
msgstr ""
msgstr "Vehículo, leasing, seguros, costes"
#. module: base
#: view:ir.model.access:0
@ -1978,6 +2019,8 @@ msgid ""
"Check this box if this contact is a supplier. If it's not checked, purchase "
"people will not see it when encoding a purchase order."
msgstr ""
"Marque esta casilla si el contacto es un proveedor. Si no está marcada, el "
"equipo de compras no lo verá cuando esté haciendo una orden de compra."
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_evaluation
@ -2025,7 +2068,7 @@ msgstr "Crear tareas en OV"
#: code:addons/base/ir/ir_model.py:316
#, python-format
msgid "This column contains module data and cannot be removed!"
msgstr ""
msgstr "¡Esta columna contiene datos del módulo y no puede ser eliminada!"
#. module: base
#: field:ir.attachment,res_model:0
@ -2170,7 +2213,7 @@ msgstr "Ruta completa"
#. module: base
#: view:base.language.export:0
msgid "The next step depends on the file format:"
msgstr ""
msgstr "El siguiente paso depende del formato del archivo:"
#. module: base
#: model:ir.module.module,shortdesc:base.module_idea
@ -2215,7 +2258,7 @@ msgstr "Crear / Escribir / Copiar"
#. module: base
#: view:ir.sequence:0
msgid "Second: %(sec)s"
msgstr ""
msgstr "Segundo: %(sec)s"
#. module: base
#: field:ir.actions.act_window,view_mode:0
@ -2602,7 +2645,7 @@ msgstr ""
#. module: base
#: field:res.company,rml_header1:0
msgid "Company Slogan"
msgstr ""
msgstr "Lema de la empresa"
#. module: base
#: model:res.country,name:base.bb
@ -2626,7 +2669,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_oauth_signup
msgid "Signup with OAuth2 Authentication"
msgstr ""
msgstr "Registro con autenticación OAuth2"
#. module: base
#: selection:ir.model,state:0
@ -2653,7 +2696,7 @@ msgstr "Griego / Ελληνικά"
#. module: base
#: field:res.company,custom_footer:0
msgid "Custom Footer"
msgstr ""
msgstr "Pie de página personalizado."
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_crm
@ -3105,6 +3148,8 @@ msgid ""
"the user will have an access to the sales configuration as well as statistic "
"reports."
msgstr ""
"el usuario tendrá acceso a la configuración de ventas así como a los "
"informes estadísticos."
#. module: base
#: model:res.country,name:base.nz
@ -3191,6 +3236,8 @@ msgid ""
"the user will have an access to the human resources configuration as well as "
"statistic reports."
msgstr ""
"el usuario tendrá acceso a la configuración de recursos humanos así como a "
"los informes estadísticos."
#. module: base
#: model:ir.module.module,description:base.module_web_shortcuts
@ -3300,7 +3347,7 @@ msgstr "Sweden"
#. module: base
#: field:ir.actions.report.xml,report_file:0
msgid "Report File"
msgstr ""
msgstr "Archivo de informe"
#. module: base
#: selection:ir.actions.act_window.view,view_mode:0
@ -3333,7 +3380,7 @@ msgstr ""
#: code:addons/orm.py:3839
#, python-format
msgid "Missing document(s)"
msgstr ""
msgstr "Falta el documento(s)"
#. module: base
#: model:ir.model,name:base.model_res_partner_bank_type
@ -3348,6 +3395,8 @@ msgid ""
"For more details about translating OpenERP in your language, please refer to "
"the"
msgstr ""
"Para más información acerca de la traducción de OpenERP a su idioma, por "
"favor contacta con"
#. module: base
#: field:res.partner,image:0
@ -3634,6 +3683,7 @@ msgstr "Malta"
msgid ""
"Only users with the following access level are currently allowed to do that"
msgstr ""
"Sólo usuarios con los siguientes permisos están autorizados a hacer esto"
#. module: base
#: field:ir.actions.server,fields_lines:0
@ -3784,7 +3834,7 @@ msgstr "Interacción entre reglas"
#: field:res.company,rml_footer:0
#: field:res.company,rml_footer_readonly:0
msgid "Report Footer"
msgstr ""
msgstr "Pie de página del informe"
#. module: base
#: selection:res.lang,direction:0
@ -4305,7 +4355,7 @@ msgstr "Planes de cuentas"
#. module: base
#: model:ir.ui.menu,name:base.menu_event_main
msgid "Events Organization"
msgstr ""
msgstr "Organización de eventos"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_customer_form
@ -4333,7 +4383,7 @@ msgstr "Campo base"
#. module: base
#: model:ir.module.category,name:base.module_category_managing_vehicles_and_contracts
msgid "Managing vehicles and contracts"
msgstr ""
msgstr "Gestión de vehiculos y contratos"
#. module: base
#: model:ir.module.module,description:base.module_base_setup
@ -4459,7 +4509,7 @@ msgstr ""
#. module: base
#: field:res.partner,parent_id:0
msgid "Related Company"
msgstr ""
msgstr "Empresa relacionada"
#. module: base
#: help:ir.actions.act_url,help:0
@ -4594,7 +4644,7 @@ msgstr "Hindi / हिंदी"
#: model:ir.actions.act_window,name:base.action_view_base_language_install
#: model:ir.ui.menu,name:base.menu_view_base_language_install
msgid "Load a Translation"
msgstr ""
msgstr "Cargar una traducción"
#. module: base
#: field:ir.module.module,latest_version:0
@ -4925,7 +4975,7 @@ msgstr "Aplicaciones específicas de la industria"
#. module: base
#: model:ir.module.module,shortdesc:base.module_google_docs
msgid "Google Docs integration"
msgstr ""
msgstr "Integración con Google Docs"
#. module: base
#: code:addons/base/ir/ir_fields.py:328
@ -4987,7 +5037,7 @@ msgstr "Lesotho"
#. module: base
#: view:base.language.export:0
msgid ", or your preferred text editor"
msgstr ""
msgstr ", o su editor de texto preferido"
#. module: base
#: model:ir.module.module,shortdesc:base.module_crm_partner_assign
@ -5595,7 +5645,7 @@ msgstr ""
#. module: base
#: model:res.groups,name:base.group_sale_salesman_all_leads
msgid "See all Leads"
msgstr ""
msgstr "Ver todas las iniciativas"
#. module: base
#: model:res.country,name:base.ci
@ -5615,7 +5665,7 @@ msgstr "%w - Día de la semana [0(domingo),6]."
#. module: base
#: model:ir.ui.menu,name:base.menu_ir_filters
msgid "User-defined Filters"
msgstr ""
msgstr "Filtros definidos por el usuario"
#. module: base
#: field:ir.actions.act_window_close,name:0
@ -5835,7 +5885,7 @@ msgstr "Etiopía"
#. module: base
#: model:ir.module.category,name:base.module_category_authentication
msgid "Authentication"
msgstr ""
msgstr "Autentificación"
#. module: base
#: model:res.country,name:base.sj
@ -5869,7 +5919,7 @@ msgstr "título"
#: code:addons/base/ir/ir_fields.py:147
#, python-format
msgid "true"
msgstr ""
msgstr "verdadero"
#. module: base
#: model:ir.model,name:base.model_base_language_install
@ -5879,7 +5929,7 @@ msgstr "Instalar idioma"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_11
msgid "Services"
msgstr ""
msgstr "Servicios"
#. module: base
#: view:ir.translation:0
@ -6160,6 +6210,8 @@ msgstr ""
msgid ""
"Administrative divisions of a country. E.g. Fed. State, Departement, Canton"
msgstr ""
"División administrativa de un país. Por ejemplo Comunidad Autónoma, "
"Provincia, Ayuntamiento"
#. module: base
#: view:res.partner.bank:0
@ -6321,7 +6373,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_reset_password
msgid "Reset Password"
msgstr ""
msgstr "Restablecer contraseña"
#. module: base
#: view:ir.attachment:0
@ -6438,6 +6490,7 @@ msgstr "Cabo Verde"
#: model:res.groups,comment:base.group_sale_salesman
msgid "the user will have access to his own data in the sales application."
msgstr ""
"El usuario tendrá acceso a sus propios datos en la aplicación ventas."
#. module: base
#: model:res.groups,comment:base.group_user
@ -6695,7 +6748,7 @@ msgstr "Israel"
#: code:addons/base/res/res_config.py:444
#, python-format
msgid "Cannot duplicate configuration!"
msgstr ""
msgstr "¡No se puede duplicar la configuración!"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_syscohada
@ -6804,7 +6857,7 @@ msgstr ""
#. module: base
#: view:ir.sequence:0
msgid "Week of the Year: %(woy)s"
msgstr ""
msgstr "Semana del año: %(woy)s"
#. module: base
#: field:res.users,id:0
@ -6874,7 +6927,7 @@ msgstr "Títulos de empresa"
#: code:addons/base/ir/ir_fields.py:228
#, python-format
msgid "Use the format '%s'"
msgstr ""
msgstr "Use el formato '%s'"
#. module: base
#: help:ir.actions.act_window,auto_refresh:0
@ -7219,7 +7272,7 @@ msgstr "Traducible"
#. module: base
#: help:base.language.import,code:0
msgid "ISO Language and Country code, e.g. en_US"
msgstr ""
msgstr "Código ISO de idioma y país, ej. es_ES"
#. module: base
#: model:res.country,name:base.vn
@ -7328,7 +7381,7 @@ msgstr ""
#. module: base
#: field:res.partner,function:0
msgid "Job Position"
msgstr ""
msgstr "Puesto de trabajo"
#. module: base
#: view:res.partner:0
@ -7900,7 +7953,7 @@ msgstr "Inicio"
#: view:res.partner:0
#: field:res.partner,user_id:0
msgid "Salesperson"
msgstr ""
msgstr "Comercial"
#. module: base
#: view:res.lang:0
@ -7965,7 +8018,7 @@ msgstr "Contraseña opcional para la autenticación SMTP"
#: code:addons/base/ir/ir_model.py:719
#, python-format
msgid "Sorry, you are not allowed to modify this document."
msgstr ""
msgstr "Lo siento, no está autorizado para modificar este documento."
#. module: base
#: code:addons/base/res/res_config.py:350
@ -8310,7 +8363,7 @@ msgstr "Bélgica - Contabilidad"
#. module: base
#: view:ir.model.access:0
msgid "Access Control"
msgstr ""
msgstr "Control de acceso"
#. module: base
#: model:res.country,name:base.kw
@ -8778,7 +8831,7 @@ msgstr ""
#. module: base
#: view:base.language.export:0
msgid "documentation"
msgstr ""
msgstr "documentación"
#. module: base
#: help:ir.model,osv_memory:0
@ -8823,7 +8876,7 @@ msgstr "%b - Nombre abreviado del mes."
#: code:addons/base/ir/ir_model.py:721
#, python-format
msgid "Sorry, you are not allowed to delete this document."
msgstr ""
msgstr "Lo siento, no está autorizado a eliminar este documento."
#. module: base
#: constraint:ir.rule:0
@ -8974,12 +9027,12 @@ msgstr ""
#. module: base
#: model:res.partner.category,name:base.res_partner_category_5
msgid "Silver"
msgstr ""
msgstr "Plata"
#. module: base
#: field:res.partner.title,shortcut:0
msgid "Abbreviation"
msgstr ""
msgstr "Abreviatura"
#. module: base
#: model:ir.ui.menu,name:base.menu_crm_case_job_req_main
@ -9182,7 +9235,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_warehouse_management
msgid "Warehouse"
msgstr ""
msgstr "Almacén"
#. module: base
#: field:ir.exports,resource:0
@ -9215,7 +9268,7 @@ msgstr "8. %I:%M:%S %p ==> 06:25:20 PM"
#. module: base
#: view:ir.filters:0
msgid "Filters shared with all users"
msgstr ""
msgstr "Filtros compartidos con todos los usuarios"
#. module: base
#: view:ir.translation:0
@ -9445,7 +9498,7 @@ msgstr "Modelos"
#: code:addons/base/module/module.py:472
#, python-format
msgid "The `base` module cannot be uninstalled"
msgstr ""
msgstr "El modulo `base`no puede ser desinstalado"
#. module: base
#: code:addons/base/ir/ir_cron.py:390
@ -9472,7 +9525,7 @@ msgstr "osv_memory.autovacuum"
#: code:addons/base/ir/ir_model.py:720
#, python-format
msgid "Sorry, you are not allowed to create this kind of document."
msgstr ""
msgstr "Lo siento, no estás autorizado a crear este tipo de documento."
#. module: base
#: field:base.language.export,lang:0
@ -9888,7 +9941,7 @@ msgstr ""
#. module: base
#: field:res.partner,use_parent_address:0
msgid "Use Company Address"
msgstr ""
msgstr "Utilizar la dirección de la empresa"
#. module: base
#: model:ir.module.module,summary:base.module_hr_holidays
@ -10252,7 +10305,7 @@ msgstr "Isla Pitcairn"
#. module: base
#: field:res.partner,category_id:0
msgid "Tags"
msgstr ""
msgstr "Etiquetas"
#. module: base
#: view:base.module.upgrade:0
@ -10272,7 +10325,7 @@ msgstr "Reglas de registros"
#. module: base
#: view:multi_company.default:0
msgid "Multi Company"
msgstr ""
msgstr "Multi compañía"
#. module: base
#: model:ir.module.category,name:base.module_category_portal
@ -10289,7 +10342,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:295
#, python-format
msgid "See all possible values"
msgstr ""
msgstr "Ver todos los posibles valores"
#. module: base
#: model:ir.module.module,description:base.module_claim_from_delivery
@ -10344,7 +10397,7 @@ msgstr "Guinea Bissau"
#. module: base
#: field:ir.actions.report.xml,header:0
msgid "Add RML Header"
msgstr ""
msgstr "Añadir cabecera RML"
#. module: base
#: help:res.company,rml_footer:0
@ -10556,6 +10609,8 @@ msgstr "ir.traduccion"
msgid ""
"Please contact your system administrator if you think this is an error."
msgstr ""
"Por favor, contacte con el administrador del sistema si piensa que esto es "
"un error."
#. module: base
#: code:addons/base/module/module.py:519
@ -10752,7 +10807,7 @@ msgstr ""
#. module: base
#: help:res.partner,ean13:0
msgid "BarCode"
msgstr ""
msgstr "Código de Barras"
#. module: base
#: help:ir.model.fields,model_id:0
@ -10851,7 +10906,7 @@ msgstr "No puede eliminar el idioma que está actualmente activo!"
#: code:addons/base/ir/ir_model.py:1023
#, python-format
msgid "Permission Denied"
msgstr ""
msgstr "Permiso denegado"
#. module: base
#: field:ir.ui.menu,child_id:0
@ -11089,7 +11144,7 @@ msgstr "Árabe / الْعَرَبيّة"
#. module: base
#: selection:ir.translation,state:0
msgid "Translated"
msgstr ""
msgstr "Traducido"
#. module: base
#: model:ir.actions.act_window,name:base.action_inventory_form
@ -11210,7 +11265,7 @@ msgstr ""
#. module: base
#: view:ir.filters:0
msgid "Shared"
msgstr ""
msgstr "Compartido"
#. module: base
#: code:addons/base/module/module.py:336
@ -11288,6 +11343,9 @@ msgid ""
"Allow users to sign up through OAuth2 Provider.\n"
"===============================================\n"
msgstr ""
"\n"
"Permite registrar a los usuarios a través de un proveedor OAuth2.\n"
"===============================================\n"
#. module: base
#: view:ir.cron:0
@ -11344,7 +11402,7 @@ msgstr "Granada"
#. module: base
#: help:res.partner,customer:0
msgid "Check this box if this contact is a customer."
msgstr ""
msgstr "Marque esta casilla si el contacto es un cliente."
#. module: base
#: view:ir.actions.server:0
@ -11380,7 +11438,7 @@ msgstr ""
#. module: base
#: field:res.users,partner_id:0
msgid "Related Partner"
msgstr ""
msgstr "Empresa relacionada"
#. module: base
#: code:addons/osv.py:151
@ -11962,7 +12020,7 @@ msgstr "Ref. usuario"
#: code:addons/base/ir/ir_fields.py:227
#, python-format
msgid "'%s' does not seem to be a valid datetime for field '%%(field)s'"
msgstr ""
msgstr "'%s' no parece una fecha valida para el campo '%%(field)s'"
#. module: base
#: model:res.partner.bank.type.field,name:base.bank_normal_field_bic
@ -12116,7 +12174,7 @@ msgstr "Información de la conexión"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_prof
msgid "Professor"
msgstr ""
msgstr "Profesor"
#. module: base
#: model:res.country,name:base.hm
@ -12146,7 +12204,7 @@ msgstr ""
#. module: base
#: field:res.users,login_date:0
msgid "Latest connection"
msgstr ""
msgstr "Última conexión"
#. module: base
#: field:res.groups,implied_ids:0
@ -12229,7 +12287,7 @@ msgstr "Binario"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_doctor
msgid "Doctor"
msgstr ""
msgstr "Doctor"
#. module: base
#: model:ir.module.module,description:base.module_mrp_repair
@ -12286,7 +12344,7 @@ msgstr "Otras empresas"
#: view:workflow.workitem:0
#: field:workflow.workitem,state:0
msgid "Status"
msgstr ""
msgstr "Estado"
#. module: base
#: model:ir.actions.act_window,name:base.action_currency_form
@ -12298,7 +12356,7 @@ msgstr "Monedas"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_8
msgid "Consultancy Services"
msgstr ""
msgstr "Servicios de consultoría"
#. module: base
#: help:ir.values,value:0
@ -12413,7 +12471,7 @@ msgstr "Abastecimientos"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_6
msgid "Bronze"
msgstr ""
msgstr "Bronce"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_payroll_account
@ -12443,12 +12501,12 @@ msgstr "Mes de creación"
#. module: base
#: field:ir.module.module,demo:0
msgid "Demo Data"
msgstr ""
msgstr "Datos de ejemplo"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_mister
msgid "Mr."
msgstr ""
msgstr "Sr."
#. module: base
#: model:res.country,name:base.mv
@ -12636,7 +12694,7 @@ msgstr "BANCO"
#: model:ir.module.category,name:base.module_category_point_of_sale
#: model:ir.module.module,shortdesc:base.module_point_of_sale
msgid "Point of Sale"
msgstr ""
msgstr "Terminal punto de venta"
#. module: base
#: model:ir.module.module,description:base.module_mail
@ -12944,7 +13002,7 @@ msgstr "Chipre"
#. module: base
#: field:res.users,new_password:0
msgid "Set Password"
msgstr ""
msgstr "Establecer contraseña"
#. module: base
#: field:ir.actions.server,subject:0
@ -13413,7 +13471,7 @@ msgstr "Zaire"
#. module: base
#: model:ir.module.module,summary:base.module_project
msgid "Projects, Tasks"
msgstr ""
msgstr "Proyectos, tareas"
#. module: base
#: field:workflow.instance,res_id:0
@ -13431,7 +13489,7 @@ msgstr "Información"
#: code:addons/base/ir/ir_fields.py:147
#, python-format
msgid "false"
msgstr ""
msgstr "falso"
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_analysis
@ -13739,7 +13797,7 @@ msgstr "Actividad destino"
#. module: base
#: model:ir.module.module,shortdesc:base.module_project_issue
msgid "Issue Tracker"
msgstr ""
msgstr "Seguimiento de errores"
#. module: base
#: view:base.module.update:0
@ -13819,6 +13877,8 @@ msgid ""
"Check this to define the report footer manually. Otherwise it will be "
"filled in automatically."
msgstr ""
"Marque si quiere definir el pie de informe manualmente. En otro caso se "
"rellenará automáticamente."
#. module: base
#: view:res.partner:0
@ -14008,7 +14068,7 @@ msgstr "Configuración del sistema realizada."
#: view:ir.config_parameter:0
#: model:ir.ui.menu,name:base.ir_config_menu
msgid "System Parameters"
msgstr ""
msgstr "Parámetros del sistema"
#. module: base
#: model:ir.module.module,description:base.module_l10n_ch
@ -14077,7 +14137,7 @@ msgstr "Acción en múltiples doc."
#: model:ir.actions.act_window,name:base.action_partner_title_partner
#: model:ir.ui.menu,name:base.menu_partner_title_partner
msgid "Titles"
msgstr ""
msgstr "Títulos"
#. module: base
#: model:ir.module.module,description:base.module_anonymization
@ -14218,7 +14278,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_gengo
msgid "Automated Translations through Gengo API"
msgstr ""
msgstr "Traducción automática a través de Gengo"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_payment
@ -14378,12 +14438,12 @@ msgstr "Tasa monetaria"
#: view:base.module.upgrade:0
#: field:base.module.upgrade,module_info:0
msgid "Modules to Update"
msgstr ""
msgstr "Módulos a actualizar"
#. module: base
#: model:ir.ui.menu,name:base.menu_custom_multicompany
msgid "Multi-Companies"
msgstr ""
msgstr "Multi-Compañías"
#. module: base
#: field:workflow,osv:0
@ -14499,7 +14559,7 @@ msgstr "Uso de la acción"
#. module: base
#: field:ir.module.module,name:0
msgid "Technical Name"
msgstr ""
msgstr "Nombre técnico"
#. module: base
#: model:ir.model,name:base.model_workflow_workitem
@ -14550,7 +14610,7 @@ msgstr "Alemania - Contabilidad"
#. module: base
#: view:ir.sequence:0
msgid "Day of the Year: %(doy)s"
msgstr ""
msgstr "Día del año: %(doy)s"
#. module: base
#: field:ir.ui.menu,web_icon:0
@ -14820,7 +14880,7 @@ msgstr "Servicio de Post-venta"
#. module: base
#: field:base.language.import,code:0
msgid "ISO Code"
msgstr ""
msgstr "Código ISO"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_fr
@ -14835,7 +14895,7 @@ msgstr "Lanzar"
#. module: base
#: selection:res.partner,type:0
msgid "Shipping"
msgstr ""
msgstr "Envío"
#. module: base
#: model:ir.module.module,description:base.module_project_mrp
@ -15382,7 +15442,7 @@ msgstr "Seychelles"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_4
msgid "Gold"
msgstr ""
msgstr "Oro"
#. module: base
#: code:addons/base/res/res_company.py:159

File diff suppressed because it is too large Load Diff

15072
openerp/addons/base/i18n/hi.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-11-28 13:28+0000\n"
"PO-Revision-Date: 2012-12-14 04:43+0000\n"
"Last-Translator: gobi <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: 2012-12-04 04:58+0000\n"
"X-Generator: Launchpad (build 16335)\n"
"X-Launchpad-Export-Date: 2012-12-15 05:03+0000\n"
"X-Generator: Launchpad (build 16372)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -614,7 +614,7 @@ msgstr "Харьцааны Нэр"
#. module: base
#: view:ir.rule:0
msgid "Create Access Right"
msgstr ""
msgstr "Хандах Эрх Үүсгэх"
#. module: base
#: model:res.country,name:base.tv
@ -1346,7 +1346,7 @@ msgstr "Андорра, Principality of"
#. module: base
#: field:ir.rule,perm_read:0
msgid "Apply for Read"
msgstr ""
msgstr "Уншихаар Хэрэгжүүлэх"
#. module: base
#: model:res.country,name:base.mn
@ -1431,7 +1431,7 @@ msgstr "Сүүлийн Хувилбар"
#. module: base
#: view:ir.rule:0
msgid "Delete Access Right"
msgstr ""
msgstr "Хандах Эрхийг Устгах"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:213
@ -1486,7 +1486,7 @@ msgstr "Дэмжигчид"
#. module: base
#: field:ir.rule,perm_unlink:0
msgid "Apply for Delete"
msgstr ""
msgstr "Устгахаар Хэрэгжүүлэх"
#. module: base
#: selection:ir.property,type:0
@ -1561,6 +1561,9 @@ msgid ""
" for uploading to OpenERP's translation "
"platform,"
msgstr ""
"TGZ формат: Энэ нь шахагдсан архив бөгөөд PO файлуудыг агуулсан\n"
" шууд OpenERP-н орчуулгын хөрсрүү хуулахад "
"тохиромжтой файл юм."
#. module: base
#: view:res.lang:0
@ -1587,7 +1590,7 @@ msgstr "Тест"
#. module: base
#: field:ir.actions.report.xml,attachment:0
msgid "Save as Attachment Prefix"
msgstr ""
msgstr "Хавсралтыг нэрлэж хадгалах угтвар"
#. module: base
#: field:ir.ui.view_sc,res_id:0
@ -1624,7 +1627,7 @@ msgstr "Гаити"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_fr_hr_payroll
msgid "French Payroll"
msgstr ""
msgstr "Фран Цалин"
#. module: base
#: view:ir.ui.view:0
@ -1698,6 +1701,33 @@ msgid ""
"Also implements IETF RFC 5785 for services discovery on a http server,\n"
"which needs explicit configuration in openerp-server.conf too.\n"
msgstr ""
"\n"
"Энэ модулиар баримтуудын хувьд WebDAV сервер идэвхжинэ.\n"
"===============================================================\n"
"\n"
"Ингэснээр OpenObject дахь хавсралт баримтуудыг нийцтэй ямар ч интернет \n"
"тольдруураар харах боломжтой.\n"
"\n"
"Суулгасан дараагаараа WebDAV сервер нь серверийн тохиргооны файлын [webdav] "
"\n"
" гэсэн хэсэгт тохиргоог хийх боломжтой.\n"
"Серверийн тохиргооны параметр нь:\n"
"\n"
" [webdav]\n"
" ; enable = True ; http(s) протоколь дээр WebDAV идэвхжинэ\n"
" ; vdir = webdav ; WebDAV ажиллах директорын нэр.\n"
" ; энэхүү webdav гэсэн анхны утгын хувьд \n"
" ; дараах байдлаар хандана \\\"http://localhost:8069/webdav/\n"
" ; verbose = True ; webdav-н дэлгэрэнгүй мэдэгдэлтэй горимыг нээнэ\n"
" ; debug = True ; webdav-н дебаагдах горимыг идэвхжүүлнэ.\n"
" ; ингэснээр мессежүүд нь python log-руу бичигдэнэ. \n"
" ; логийн түвшин нь \\\"debug\\\" болон \\\"debug_rpc\\\" байдаг. эдгээр "
"\n"
"сонголтыг\n"
" ; хэвээр нь үлдээж болно.\n"
"\n"
"Түүнчлэн IETF RFC 5785-г http серверт хэрэгжүүлдэг. Тодорхой тохиргоог \n"
"openerp-server.conf-д тохируулах хэрэгтэй.\n"
#. module: base
#: model:ir.module.category,name:base.module_category_purchase_management
@ -1745,6 +1775,12 @@ msgid ""
"=============\n"
" "
msgstr ""
"\n"
"Энэ модуль нь хэрэв гомдол, порталь суулгагдсан байгаа бол гомдол меню болон "
"боломжийг портальд нэмдэг.\n"
"============================================================================="
"=============\n"
" "
#. module: base
#: model:ir.actions.act_window,help:base.action_res_partner_bank_account_form
@ -1791,7 +1827,7 @@ msgstr "Кодгүй хэл \"%s\" байна"
#: model:ir.module.category,name:base.module_category_social_network
#: model:ir.module.module,shortdesc:base.module_mail
msgid "Social Network"
msgstr ""
msgstr "Нийгмийн Сүлжээ"
#. module: base
#: view:res.lang:0
@ -1832,6 +1868,28 @@ msgid ""
"in their pockets, this module is essential.\n"
" "
msgstr ""
"\n"
"Энэ модуль нь үдийн цайг менеж хийх модуль.\n"
"================================\n"
"\n"
"Компаниуд нь ажилчиддаа орчин, нөхцлийг таатай болгох үүднээс олон "
"нийлүүлэгчээс хачиртай талх, пицца гэх мэтийг захиалах боломжийг санал "
"болгодог.\n"
"\n"
"Гэхдээ олон тооны ажилтан, нийлүүлэгч нар байгаа тохиолдолд зөв удирдлага "
"шаардлагатай болдог.\n"
"\n"
"\n"
"\"Үдийн цайны Захиалга\" модуль нь энэ менежментийг хялбар болгож ажилчидад "
"илүү өргөн багаж, хэрэглэгээг санал болгодог.\n"
"\n"
"Цаашлаад ажилчны тохиргоо дээр үндэслэн сануулга, хоол хурдан захиалах "
"боломж зэрэгийг санал болгодогоороо хоол болон нийлүүлэгчийн менежментийг "
"бүрэн гүйцэд болгодог.\n"
"\n"
"Ажилчид заавал задгай мөнгө кармалж явах заваан ажлаас ажилчдаа чөлөөлж "
"ажилчдынхаа цагийг хэмнэхэд энэ модуль нь туйлын чухал.\n"
" "
#. module: base
#: view:wizard.ir.model.menu.create:0
@ -1871,7 +1929,7 @@ msgstr ""
#. module: base
#: help:res.partner,website:0
msgid "Website of Partner or Company"
msgstr ""
msgstr "Харилцагч эсвэл Компаний веб сайт"
#. module: base
#: help:base.language.install,overwrite:0
@ -1916,7 +1974,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_sale
msgid "Quotations, Sale Orders, Invoicing"
msgstr ""
msgstr "Үнийн санал, Борлуулалтын Захиалга, Нэхэмжлэл"
#. module: base
#: field:res.users,login:0
@ -1935,7 +1993,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_project_issue
msgid "Portal Issue"
msgstr ""
msgstr "Портал Асуудал"
#. module: base
#: model:ir.ui.menu,name:base.menu_tools
@ -1955,11 +2013,15 @@ msgid ""
"Launch Manually Once: after having been launched manually, it sets "
"automatically to Done."
msgstr ""
"Гараар: Гараар ажилуулна.\n"
"Автомат: Системийн тохиргоо өөрчлөгдөх бүрт автомат ажиллана.\n"
"Гараар нэг удаа: гараар ажилуулсан дараа автоматаар Хийгдсэн болж \n"
"тохируулагдана."
#. module: base
#: field:res.partner,image_small:0
msgid "Small-sized image"
msgstr ""
msgstr "Жижиг-хэмжээт зураг"
#. module: base
#: model:ir.module.module,shortdesc:base.module_stock
@ -2040,6 +2102,15 @@ msgid ""
"It assigns manager and user access rights to the Administrator and only user "
"rights to the Demo user. \n"
msgstr ""
"\n"
"Санхүүгийн Хандах Эрх.\n"
"=========================\n"
"\n"
"Энэ модуль нь санхүүгийн журнал, дансны мод гэх мэт бүх боломж руу хандах \n"
"хандалтыг удирдах боломжийг олгодог.\n"
"\n"
"Энэ нь менежер, хэрэглэгч хандалтын эрхийг Администраторт олгож Demo \n"
"хэрэглэгчид хэрэглэгч эрхийг олгодог. \n"
#. module: base
#: field:ir.attachment,res_id:0
@ -2066,6 +2137,8 @@ msgstr ""
#, python-format
msgid "Unknown value '%s' for boolean field '%%(field)s', assuming '%s'"
msgstr ""
"'%s' гэсэн утга boolean '%%(field)s' талбарт мэдэгдэхгүй утга, '%s' гэж үзэж "
"байна"
#. module: base
#: model:res.country,name:base.nl
@ -2075,12 +2148,12 @@ msgstr "Нидерланд"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_event
msgid "Portal Event"
msgstr ""
msgstr "Порталь Үйл явдал"
#. module: base
#: selection:ir.translation,state:0
msgid "Translation in Progress"
msgstr ""
msgstr "Орчуулга Хийгдэж байна"
#. module: base
#: model:ir.model,name:base.model_ir_rule
@ -2095,7 +2168,7 @@ msgstr "Өдөр"
#. module: base
#: model:ir.module.module,summary:base.module_fleet
msgid "Vehicle, leasing, insurances, costs"
msgstr ""
msgstr "Машин, лизинг, даатгал, өртөгүүд"
#. module: base
#: view:ir.model.access:0
@ -2123,6 +2196,23 @@ msgid ""
"synchronization with other companies.\n"
" "
msgstr ""
"\n"
"Энэ модуль нь ерөнхиий тохиолдолд хуваалцах боломжийг таны OpenERP өгөгдлийн "
"\n"
"баазад олгодог багаж юм.\n"
"========================================================================\n"
"\n"
"Энэ нь 'хуваалцах' даруулыг нэмдэг бөгөөд OpenERP-н дуртай өгөгдлийг хамт \n"
"ажиллагч, захиалагч, найз нартайгаа хуваалцах боломжийг вебэд олгодог.\n"
"\n"
"Систем нь шинэ хэрэглэгч болон группыг автоматаар үүсгэдэг. Зохистой хандах "
"\n"
"дүрэмийг ir.rules-д автоматаар нэмж зөвхөн хуваалцсан өгөгдөл рүү хандах \n"
"хандалтын хяналтаар хангаддаг.\n"
"\n"
"Энэ нь хамтран ажиллах, мэдлэгээ хуваалцах, бусад компанитай мэдээллээ \n"
"ижилтгэх зэрэгт маш зохимжтой.\n"
" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_process
@ -2135,6 +2225,8 @@ msgid ""
"Check this box if this contact is a supplier. If it's not checked, purchase "
"people will not see it when encoding a purchase order."
msgstr ""
"Хэрэв холбогч нь нийлүүлэгч бол үүнийг тэмдэглэнэ. Хэрэв тэмдэглээгүй бол "
"худалдан авалтын хүмүүст худалдан авалтын захиалга шивэх үед харагдахгүй."
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_evaluation
@ -2207,6 +2299,15 @@ msgid ""
"with the effect of creating, editing and deleting either ways.\n"
" "
msgstr ""
"\n"
"Төслийн даалгаврыг ажлын цагийн хуваарьтай ижилтгэх.\n"
"====================================================================\n"
"\n"
"Энэ модуль нь Төслийн Менежмент модуль дахь даалгавруудыг Цагийн хуваарийн\n"
"ажлууд руу тодорхой огноонд тодорхой хэрэглэгчид шилжүүлдэг. Мөн цагийн \n"
"хуваариас нөгөө чиглэлд үүсгэх, засах, устгах\n"
"хоёр чиглэлд хийх боломжтой.\n"
" "
#. module: base
#: model:ir.model,name:base.model_ir_model_access

File diff suppressed because it is too large Load Diff

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-12-07 10:59+0000\n"
"Last-Translator: Rui Franco (multibase.pt) <Unknown>\n"
"PO-Revision-Date: 2012-12-11 10:27+0000\n"
"Last-Translator: Virgílio Oliveira <virgilio.oliveira@multibase.pt>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-12-08 04:58+0000\n"
"X-Generator: Launchpad (build 16341)\n"
"X-Launchpad-Export-Date: 2012-12-12 04:38+0000\n"
"X-Generator: Launchpad (build 16361)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -525,7 +525,7 @@ msgstr ""
#. module: base
#: field:ir.model.relation,name:0
msgid "Relation Name"
msgstr ""
msgstr "Nome da relação"
#. module: base
#: view:ir.rule:0
@ -693,7 +693,7 @@ msgstr "Colômbia"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_mister
msgid "Mister"
msgstr ""
msgstr "Sr."
#. module: base
#: help:res.country,code:0
@ -1008,7 +1008,7 @@ msgstr "Preferências de email"
#: code:addons/base/ir/ir_fields.py:196
#, python-format
msgid "'%s' does not seem to be a valid date for field '%%(field)s'"
msgstr ""
msgstr "%s' não parece ser uma data válida para o campo '%%(field)s'"
#. module: base
#: view:res.partner:0
@ -1025,6 +1025,8 @@ msgstr "Zimbabué"
msgid ""
"Type of the constraint: `f` for a foreign key, `u` for other constraints."
msgstr ""
"Tipo de restrição: `f` para uma chave estrangeira, `u` para outras "
"restrições."
#. module: base
#: view:ir.actions.report.xml:0
@ -1621,7 +1623,7 @@ msgstr "Configuração do rodapé de relatório"
#. module: base
#: field:ir.translation,comments:0
msgid "Translation comments"
msgstr ""
msgstr "Comentários à tradução"
#. module: base
#: model:ir.module.module,description:base.module_lunch
@ -1686,7 +1688,7 @@ msgstr ""
#. module: base
#: help:res.partner,website:0
msgid "Website of Partner or Company"
msgstr ""
msgstr "Sítio web do parceiro ou da empresa"
#. module: base
#: help:base.language.install,overwrite:0
@ -1892,7 +1894,7 @@ msgstr "Países Baixos"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_event
msgid "Portal Event"
msgstr ""
msgstr "Evento do portal"
#. module: base
#: selection:ir.translation,state:0
@ -2189,7 +2191,7 @@ msgstr "Criar / Escrever / Copiar"
#. module: base
#: view:ir.sequence:0
msgid "Second: %(sec)s"
msgstr ""
msgstr "Segundo: %(sec)s"
#. module: base
#: field:ir.actions.act_window,view_mode:0
@ -2946,7 +2948,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:175
#, python-format
msgid "'%s' does not seem to be an integer for field '%%(field)s'"
msgstr ""
msgstr "'%s' não aparenta ser um número inteiro para o campo '%%(field)s'"
#. module: base
#: model:ir.module.category,description:base.module_category_report_designer
@ -3826,7 +3828,7 @@ msgstr "Togo"
#: field:ir.actions.act_window,res_model:0
#: field:ir.actions.client,res_model:0
msgid "Destination Model"
msgstr ""
msgstr "Modelo de destino"
#. module: base
#: selection:ir.sequence,implementation:0
@ -4400,7 +4402,7 @@ msgstr ""
#. module: base
#: field:res.partner,parent_id:0
msgid "Related Company"
msgstr ""
msgstr "Empresa relacionada"
#. module: base
#: help:ir.actions.act_url,help:0
@ -4835,7 +4837,7 @@ msgstr "Workflows"
#. module: base
#: model:ir.ui.menu,name:base.next_id_73
msgid "Purchase"
msgstr ""
msgstr "Compra"
#. module: base
#: selection:base.language.install,lang:0
@ -5310,7 +5312,7 @@ msgstr "Separador Decimal"
#: code:addons/orm.py:5245
#, python-format
msgid "Missing required value for the field '%s'."
msgstr ""
msgstr "Falta o valor do campo '%s'."
#. module: base
#: model:ir.model,name:base.model_res_partner_address
@ -5374,7 +5376,7 @@ msgstr "Ilha Bouvet"
#. module: base
#: field:ir.model.constraint,type:0
msgid "Constraint Type"
msgstr ""
msgstr "Tipo de restrição"
#. module: base
#: field:res.company,child_ids:0
@ -5537,7 +5539,7 @@ msgstr "%w - Número de dias da semana [0(Sunday),6]."
#. module: base
#: model:ir.ui.menu,name:base.menu_ir_filters
msgid "User-defined Filters"
msgstr ""
msgstr "Filtros definidos pelo utilizador"
#. module: base
#: field:ir.actions.act_window_close,name:0
@ -6951,7 +6953,7 @@ msgstr "Ficheiro do módulo importado com sucesso!"
#: view:ir.model.constraint:0
#: model:ir.ui.menu,name:base.ir_model_constraint_menu
msgid "Model Constraints"
msgstr ""
msgstr "Restrições de modelo"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_timesheet
@ -7720,7 +7722,7 @@ msgstr "Canadá"
#. module: base
#: view:base.language.export:0
msgid "Launchpad"
msgstr ""
msgstr "Launchpad"
#. module: base
#: help:res.currency.rate,currency_rate_type_id:0
@ -7890,7 +7892,7 @@ msgstr "Assistente"
#: code:addons/base/ir/ir_fields.py:304
#, python-format
msgid "database id"
msgstr ""
msgstr "id da base de dados"
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_import
@ -8460,7 +8462,7 @@ msgstr "Nepal"
#. module: base
#: model:ir.module.module,shortdesc:base.module_document_page
msgid "Document Page"
msgstr ""
msgstr "Página do documento"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_ar
@ -8650,6 +8652,10 @@ msgid ""
"\n"
"(Document type: %s)"
msgstr ""
"Para este tipo de documento, só pode aceder a registos que tenham sido "
"criados por si.\n"
"\n"
"(Tipo de documento: %s)"
#. module: base
#: view:base.language.export:0
@ -8722,7 +8728,7 @@ msgstr "Multi Ações"
#. module: base
#: model:ir.module.module,summary:base.module_mail
msgid "Discussions, Mailing Lists, News"
msgstr ""
msgstr "Discussões, listas de correio, notícias"
#. module: base
#: model:ir.module.module,description:base.module_fleet
@ -9085,7 +9091,7 @@ msgstr "8. %I:%M:%S %p ==> 06:25:20 PM"
#. module: base
#: view:ir.filters:0
msgid "Filters shared with all users"
msgstr ""
msgstr "Filtros partilhados com todos os utilizadores"
#. module: base
#: view:ir.translation:0
@ -9495,7 +9501,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:317
#, python-format
msgid "external id"
msgstr ""
msgstr "id externo"
#. module: base
#: view:ir.model:0
@ -10027,7 +10033,7 @@ msgstr "res.request"
#. module: base
#: field:res.partner,image_medium:0
msgid "Medium-sized image"
msgstr ""
msgstr "Imagem de média dimensão"
#. module: base
#: view:ir.model:0
@ -10185,7 +10191,7 @@ msgstr ""
#. module: base
#: help:res.company,rml_footer:0
msgid "Footer text displayed at the bottom of all reports."
msgstr ""
msgstr "Texto de rodapé mostrados no final de todos os relatórios."
#. module: base
#: model:ir.module.module,shortdesc:base.module_note_pad
@ -10608,7 +10614,7 @@ msgstr "Tipos de Sequências"
#: code:addons/base/res/res_bank.py:195
#, python-format
msgid "Formating Error"
msgstr ""
msgstr "Erro de formatação"
#. module: base
#: model:res.country,name:base.ye
@ -10930,7 +10936,7 @@ msgstr "Domínio"
#: code:addons/base/ir/ir_fields.py:167
#, python-format
msgid "Use '1' for yes and '0' for no"
msgstr ""
msgstr "Use '1' para sim e '0' para não"
#. module: base
#: model:ir.module.module,shortdesc:base.module_marketing_campaign
@ -11172,7 +11178,7 @@ msgstr ""
#. module: base
#: field:res.users,partner_id:0
msgid "Related Partner"
msgstr ""
msgstr "Parceiro relacionado"
#. module: base
#: code:addons/osv.py:151
@ -11897,7 +11903,7 @@ msgstr "Informação da Ligação"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_prof
msgid "Professor"
msgstr ""
msgstr "Professor"
#. module: base
#: model:res.country,name:base.hm
@ -12193,7 +12199,7 @@ msgstr "Aquisições"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_6
msgid "Bronze"
msgstr ""
msgstr "Bronze"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_payroll_account
@ -12223,7 +12229,7 @@ msgstr "Mês de Criação"
#. module: base
#: field:ir.module.module,demo:0
msgid "Demo Data"
msgstr ""
msgstr "Dados de demonstração"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_mister
@ -12383,7 +12389,7 @@ msgstr ""
#. module: base
#: field:ir.actions.report.xml,report_sxw:0
msgid "SXW Path"
msgstr ""
msgstr "Caminho de SXW"
#. module: base
#: model:ir.module.module,description:base.module_account_asset
@ -12416,7 +12422,7 @@ msgstr "BANCO"
#: model:ir.module.category,name:base.module_category_point_of_sale
#: model:ir.module.module,shortdesc:base.module_point_of_sale
msgid "Point of Sale"
msgstr ""
msgstr "Ponto de venda"
#. module: base
#: model:ir.module.module,description:base.module_mail
@ -13180,7 +13186,7 @@ msgstr "Zaire"
#. module: base
#: model:ir.module.module,summary:base.module_project
msgid "Projects, Tasks"
msgstr ""
msgstr "Projetos, tarefas"
#. module: base
#: field:workflow.instance,res_id:0
@ -13198,7 +13204,7 @@ msgstr "Informação"
#: code:addons/base/ir/ir_fields.py:147
#, python-format
msgid "false"
msgstr ""
msgstr "falso"
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_analysis
@ -13594,7 +13600,7 @@ msgstr "Instalar Módulos"
#. module: base
#: model:ir.ui.menu,name:base.menu_import_crm
msgid "Import & Synchronize"
msgstr ""
msgstr "Importar e sincronizar"
#. module: base
#: view:res.partner:0
@ -13839,7 +13845,7 @@ msgstr "Ação em multiplos documentos."
#: model:ir.actions.act_window,name:base.action_partner_title_partner
#: model:ir.ui.menu,name:base.menu_partner_title_partner
msgid "Titles"
msgstr ""
msgstr "Títulos"
#. module: base
#: model:ir.module.module,description:base.module_anonymization
@ -13900,7 +13906,7 @@ msgstr "Luxemburgo"
#. module: base
#: model:ir.module.module,summary:base.module_base_calendar
msgid "Personal & Shared Calendar"
msgstr ""
msgstr "Calendários personalizado e partilhado"
#. module: base
#: selection:res.request,priority:0
@ -14022,7 +14028,7 @@ msgstr "Dicas & Oportunidades"
#. module: base
#: model:res.country,name:base.gg
msgid "Guernsey"
msgstr ""
msgstr "Guernsey"
#. module: base
#: selection:base.language.install,lang:0
@ -14364,17 +14370,17 @@ msgstr ""
#. module: base
#: view:base.language.export:0
msgid "Export Settings"
msgstr ""
msgstr "Configurações de exportação"
#. module: base
#: field:ir.actions.act_window,src_model:0
msgid "Source Model"
msgstr ""
msgstr "Modelo fonte"
#. module: base
#: view:ir.sequence:0
msgid "Day of the Week (0:Monday): %(weekday)s"
msgstr ""
msgstr "Dia da semana (0:segunda feira): %(weekday)s"
#. module: base
#: code:addons/base/module/wizard/base_module_upgrade.py:84
@ -14589,7 +14595,7 @@ msgstr "Lançar"
#. module: base
#: selection:res.partner,type:0
msgid "Shipping"
msgstr ""
msgstr "Envio"
#. module: base
#: model:ir.module.module,description:base.module_project_mrp
@ -14741,7 +14747,7 @@ msgstr "Módulos Genéricos"
#. module: base
#: model:res.country,name:base.mk
msgid "Macedonia, the former Yugoslav Republic of"
msgstr ""
msgstr "Macedónia (Antiga República Jugoslava)"
#. module: base
#: model:res.country,name:base.rw
@ -14878,7 +14884,7 @@ msgstr "Holanda - Contabilidade"
#. module: base
#: model:res.country,name:base.gs
msgid "South Georgia and the South Sandwich Islands"
msgstr ""
msgstr "Geórgia do Sul e Ilhas Sandwich do Sul"
#. module: base
#: view:res.lang:0
@ -15305,7 +15311,7 @@ msgstr "Parceiros: "
#. module: base
#: view:res.partner:0
msgid "Is a Company?"
msgstr ""
msgstr "É uma empresa?"
#. module: base
#: code:addons/base/res/res_company.py:159
@ -15413,7 +15419,7 @@ msgstr "Russo / русский язык"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_signup
msgid "Signup"
msgstr ""
msgstr "Registo"
#~ msgid "SMS - Gateway: clickatell"
#~ msgstr "SMS - Gateway: clickatell"

View File

@ -7,15 +7,15 @@ msgstr ""
"Project-Id-Version: pt_BR\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-12-07 22:22+0000\n"
"PO-Revision-Date: 2012-12-16 22:18+0000\n"
"Last-Translator: Fábio Martinelli - http://zupy.com.br "
"<webmaster@guaru.net>\n"
"Language-Team: <pt@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: 2012-12-08 04:58+0000\n"
"X-Generator: Launchpad (build 16341)\n"
"X-Launchpad-Export-Date: 2012-12-17 04:44+0000\n"
"X-Generator: Launchpad (build 16372)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -26,8 +26,8 @@ msgid ""
" "
msgstr ""
"\n"
"Módulo para Verificar Escrita e Impressão.\n"
"========================================\n"
"Módulo para Criar e Imprimir Cheques.\n"
"=====================================\n"
" "
#. module: base
@ -93,7 +93,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_point_of_sale
msgid "Touchscreen Interface for Shops"
msgstr "Interface Touchscreen para lojas"
msgstr "Interface Toque na Tela para Lojas"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
@ -159,7 +159,7 @@ msgstr ""
#. module: base
#: help:res.partner,employee:0
msgid "Check this box if this contact is an Employee."
msgstr "Marque se este contato é um empregado."
msgstr "Marque a opção se este contato é um empregado."
#. module: base
#: help:ir.model.fields,domain:0
@ -255,6 +255,34 @@ msgid ""
"* Planned Revenue by Stage and User (graph)\n"
"* Opportunities by Stage (graph)\n"
msgstr ""
"\n"
"CRM - Gestão de Relacionamento com o Cliente\n"
"================================================== ===\n"
"\n"
"Este aplicativo permite que um grupo de pessoas gerencie de forma "
"inteligente e eficiente prospectos, oportunidades, reuniões e telefonemas.\n"
"\n"
"Ele gerencia tarefas essenciais, como a comunicação, a identificação, "
"priorização, atribuição, resolução e notificação.\n"
"\n"
"O OpenERP garante que todos os casos são rastreado com sucesso por usuários, "
"clientes e fornecedores. É possível enviar automaticamente lembretes, "
"escalar o pedido, acionar métodos específicos e muitas outras ações com base "
"em suas próprias regras empresariais.\n"
"\n"
"A melhor coisa sobre este sistema é que os usuários não precisam fazer nada "
"de especial. O módulo de CRM tem um gateway de e-mail para a interface de "
"sincronização entre e-mails e OpenERP. Dessa forma, os usuários podem enviar "
"e-mails apenas para o rastreador do pedido.\n"
"\n"
"O OpenERP vai cuidar de agradecê-los por sua mensagem, encaminhá-la para o "
"pessoal apropriado automaticamente e certificar-se de que toda a futura "
"correspondência chegue ao lugar certo.\n"
"\n"
"O Painel para CRM inclue:\n"
"-----------------------------------\n"
"* Receita planejada por estágio e usuário (gráfico)\n"
"* Oportunidades por estágio (gráfico)\n"
#. module: base
#: code:addons/base/ir/ir_model.py:397
@ -6566,7 +6594,7 @@ msgstr "Cancelar Entradas de Diário"
#. module: base
#: field:res.partner,tz_offset:0
msgid "Timezone offset"
msgstr ""
msgstr "Deslocamento de Fuso Horário"
#. module: base
#: model:ir.module.module,description:base.module_marketing_campaign
@ -7910,7 +7938,7 @@ msgstr "Ref. Visão de Pesquisa"
#. module: base
#: help:res.users,partner_id:0
msgid "Partner-related data of the user"
msgstr ""
msgstr "Dados do usuário relacionado ao Parceiro"
#. module: base
#: model:ir.module.module,description:base.module_crm_todo
@ -8409,7 +8437,7 @@ msgstr "Determina onde o símbolo deve ser colocado após ou antes o valor."
#. module: base
#: model:ir.module.module,shortdesc:base.module_pad_project
msgid "Pad on tasks"
msgstr ""
msgstr "Blocos nas Tarefas"
#. module: base
#: model:ir.model,name:base.model_base_update_translations
@ -9535,6 +9563,18 @@ msgid ""
"Thank you in advance for your cooperation.\n"
"Best Regards,"
msgstr ""
"Prezado Senhor / Senhora,\n"
"\n"
"Nossos registros indicam que alguns pagamentos em sua conta estão em aberto. "
"Por favor, veja os detalhes abaixo.\n"
"Se o valor já tiver sido pago, por favor desconsidere este aviso. Caso "
"contrário, regularize os pagamentos o mais breve possível.\n"
"Se você tiver alguma dúvida sobre seus pagamentos, por favor, entre em "
"contato conosco.\n"
"\n"
"Obrigado antecipadamente pela sua colaboração.\n"
"\n"
"Atenciosamente,"
#. module: base
#: view:ir.module.category:0
@ -9680,6 +9720,14 @@ msgid ""
"If set to true it allows user to cancel entries & invoices.\n"
" "
msgstr ""
"\n"
"Permite cancelar entradas contábeis.\n"
"====================================\n"
"\n"
"Este módulo adiciona um campo 'Permitir Cancelamento de Entradas' no "
"formulário de um diário contábil.\n"
"Se estiver marcado permite ao usuário cancelar entradas & faturas.\n"
" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_plugin
@ -10113,7 +10161,7 @@ msgstr "Descrição dos Campos"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic_contract_hr_expense
msgid "Contracts Management: hr_expense link"
msgstr ""
msgstr "Gerenciamento de Contratos: link hr_expense"
#. module: base
#: view:ir.attachment:0
@ -10730,7 +10778,7 @@ msgstr "A fazer"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_hr_employees
msgid "Portal HR employees"
msgstr ""
msgstr "Portal RH funcionários"
#. module: base
#: selection:base.language.install,lang:0
@ -11696,6 +11744,17 @@ msgid ""
"automatically new claims based on incoming emails.\n"
" "
msgstr ""
"\n"
"\n"
"Gerenciar solicitações dos clientes.\n"
"================================================== "
"==============================\n"
"Esta aplicação permite-lhe controlar as solicitações e reclamações dos seus "
"clientes / fornecedores.\n"
"\n"
"É totalmente integrado com o gateway de e-mail para que você possa criar\n"
"novos pedidos automaticamente baseados em e-mails recebidos.\n"
" "
#. module: base
#: selection:ir.module.module,license:0
@ -13523,6 +13582,9 @@ msgid ""
"128x128px image, with aspect ratio preserved. Use this field in form views "
"or some kanban views."
msgstr ""
"Imagem média deste contato. Ela é automaticamente redimensionada como uma "
"imagem de 128x128px, mantendo o aspecto original. Utilize este campo em "
"visões de formulário ou algumas visões de kanban."
#. module: base
#: view:base.update.translations:0
@ -13798,12 +13860,12 @@ msgstr "Espanha - Contabilidade(PGCE 2008)"
#. module: base
#: model:ir.module.module,shortdesc:base.module_stock_no_autopicking
msgid "Picking Before Manufacturing"
msgstr ""
msgstr "Separação antes da Produção"
#. module: base
#: model:ir.module.module,summary:base.module_note_pad
msgid "Sticky memos, Collaborative"
msgstr ""
msgstr "Notas Colaborativas (post it)"
#. module: base
#: model:res.country,name:base.wf
@ -14067,6 +14129,10 @@ msgid ""
"your home page.\n"
"You can track your suppliers, customers and other contacts.\n"
msgstr ""
"\n"
"Este módulo oferece uma visão rápida da sua agenda de endereços, acessível a "
"partir de sua página inicial.\n"
"Você pode acompanhar os seus fornecedores, clientes e outros contatos.\n"
#. module: base
#: help:res.company,custom_footer:0
@ -14520,7 +14586,7 @@ msgstr "Prospectos & Oportunidades"
#. module: base
#: model:res.country,name:base.gg
msgid "Guernsey"
msgstr ""
msgstr "Guernsey"
#. module: base
#: selection:base.language.install,lang:0
@ -15042,7 +15108,7 @@ msgstr "Relatórios Avançados"
#. module: base
#: model:ir.module.module,summary:base.module_purchase
msgid "Purchase Orders, Receptions, Supplier Invoices"
msgstr ""
msgstr "Pedidos de Compra, Recepções, Faturas de Fornecedores"
#. module: base
#: model:ir.module.module,description:base.module_hr_payroll
@ -15247,7 +15313,7 @@ msgstr "Módulos Genéricos"
#. module: base
#: model:res.country,name:base.mk
msgid "Macedonia, the former Yugoslav Republic of"
msgstr ""
msgstr "Macedônia"
#. module: base
#: model:res.country,name:base.rw
@ -15384,7 +15450,7 @@ msgstr "Holanda - Contabilidade"
#. module: base
#: model:res.country,name:base.gs
msgid "South Georgia and the South Sandwich Islands"
msgstr ""
msgstr "Geórgia do Sul e Ilhas Sandwich do Sul"
#. module: base
#: view:res.lang:0
@ -15681,6 +15747,8 @@ msgid ""
"Tax Identification Number. Check the box if this contact is subjected to "
"taxes. Used by the some of the legal statements."
msgstr ""
"Número de Identificação Fiscal. Marque a caixa se este contato está sujeito "
"a impostos. Usado pela algumas das declarações legais."
#. module: base
#: field:res.partner.bank,partner_id:0
@ -15857,6 +15925,16 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Clique para adicionar um contato em sua agenda de "
"endereços.\n"
" </p><p>\n"
" O OpenERP auxilia a rastrear todas as atividades "
"relacionadas a\n"
" um cliente; debates, histórico de oportunidades\n"
" de negócios, documentos, etc.\n"
" </p>\n"
" "
#. module: base
#: model:res.partner.category,name:base.res_partner_category_2

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-03 16:01+0000\n"
"PO-Revision-Date: 2012-08-20 15:27+0000\n"
"Last-Translator: Dorin <dhongu@gmail.com>\n"
"PO-Revision-Date: 2012-12-16 18:26+0000\n"
"Last-Translator: Fekete Mihai <mihai@erpsystems.ro>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-12-04 04:59+0000\n"
"X-Generator: Launchpad (build 16335)\n"
"X-Launchpad-Export-Date: 2012-12-17 04:44+0000\n"
"X-Generator: Launchpad (build 16372)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@ -24,6 +24,10 @@ msgid ""
"================================================\n"
" "
msgstr ""
"\n"
"Modul pentru Verifica Scrisul si Verifica Imprimarea.\n"
"================================================\n"
" "
#. module: base
#: model:res.country,name:base.sh
@ -59,7 +63,7 @@ msgstr "Alcatuirea vizualizarii"
#. module: base
#: model:ir.module.module,summary:base.module_sale_stock
msgid "Quotation, Sale Orders, Delivery & Invoicing Control"
msgstr ""
msgstr "Cotatie, Ordine de vanzari, Controlul Livrarii & Facturarii"
#. module: base
#: selection:ir.sequence,implementation:0
@ -88,25 +92,25 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_point_of_sale
msgid "Touchscreen Interface for Shops"
msgstr ""
msgstr "Interfata cu Ecran tactil pentru Magazine"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
msgid "Indian Payroll"
msgstr ""
msgstr "Stat de plata indian"
#. module: base
#: help:ir.cron,model:0
msgid ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
msgstr ""
"Numele modelului unde este localizata metoda care urmeaza a fi efectuata, de "
"exemplu 'res.partener'."
"Numele modelului unde este localizata metoda care va fi numita, de exemplu "
"'res.partener'."
#. module: base
#: view:ir.module.module:0
msgid "Created Views"
msgstr "Afisari Create"
msgstr "Vizualizari Create"
#. module: base
#: model:ir.module.module,description:base.module_product_manufacturer
@ -123,6 +127,17 @@ msgid ""
" * Product Attributes\n"
" "
msgstr ""
"\n"
"Un modul care adauga producatori si atribute la formularul produsului.\n"
"====================================================================\n"
"\n"
"Acum puteti defini urmatoarele pentru un produs:\n"
"-----------------------------------------------\n"
" * Producator\n"
" * Numele Producatorului Produsului\n"
" * Codul Producatorului Produsului\n"
" * Atributele Produsului\n"
" "
#. module: base
#: field:ir.actions.client,params:0
@ -136,11 +151,14 @@ msgid ""
"The module adds google user in res user.\n"
"========================================\n"
msgstr ""
"\n"
"Acest modul adauga utilizatorul google la utilizatorul res.\n"
"========================================\n"
#. module: base
#: help:res.partner,employee:0
msgid "Check this box if this contact is an Employee."
msgstr ""
msgstr "Bifati aceasta casuta daca acest contact este un Angajat."
#. module: base
#: help:ir.model.fields,domain:0

File diff suppressed because it is too large Load Diff

View File

@ -671,7 +671,7 @@ class actions_server(osv.osv):
context['object'] = obj
for i in expr:
context['active_id'] = i.id
result = self.run(cr, uid, [action.loop_action.id], context)
self.run(cr, uid, [action.loop_action.id], context)
if action.state == 'object_write':
res = {}
@ -716,8 +716,6 @@ class actions_server(osv.osv):
expr = exp.value
res[exp.col1.name] = expr
obj_pool = None
res_id = False
obj_pool = self.pool.get(action.srcmodel_id.model)
res_id = obj_pool.create(cr, uid, res)
if action.record_id:
@ -736,7 +734,7 @@ class actions_server(osv.osv):
model = action.copy_object.split(',')[0]
cid = action.copy_object.split(',')[1]
obj_pool = self.pool.get(model)
res_id = obj_pool.copy(cr, uid, int(cid), res)
obj_pool.copy(cr, uid, int(cid), res)
return False

View File

@ -231,7 +231,7 @@ class ir_cron(osv.osv):
_logger.warning('Tried to poll an undefined table on database %s.', db_name)
else:
raise
except Exception, ex:
except Exception:
_logger.warning('Exception in cron:', exc_info=True)
finally:

View File

@ -24,9 +24,6 @@ from osv import osv, fields
from tools.translate import _
class ir_filters(osv.osv):
'''
Filters
'''
_name = 'ir.filters'
_description = 'Filters'

View File

@ -228,7 +228,7 @@ class ir_mail_server(osv.osv):
:param int port: SMTP port to connect to
:param user: optional username to authenticate with
:param password: optional password to authenticate with
:param string encryption: optional: ``'ssl'`` | ``'starttls'``
:param string encryption: optional, ``'ssl'`` | ``'starttls'``
:param bool smtp_debug: toggle debugging of SMTP sessions (all i/o
will be output in logs)
"""

View File

@ -158,9 +158,10 @@ class ir_model(osv.osv):
if context is None: context = {}
if isinstance(ids, (int, long)):
ids = [ids]
if not context.get(MODULE_UNINSTALL_FLAG) and \
any(model.state != 'manual' for model in self.browse(cr, user, ids, context)):
raise except_orm(_('Error'), _("Model '%s' contains module data and cannot be removed!") % (model.name,))
if not context.get(MODULE_UNINSTALL_FLAG):
for model in self.browse(cr, user, ids, context):
if model.state != 'manual':
raise except_orm(_('Error'), _("Model '%s' contains module data and cannot be removed!") % (model.name,))
self._drop_table(cr, user, ids, context)
res = super(ir_model, self).unlink(cr, user, ids, context)
@ -256,7 +257,7 @@ class ir_model_fields(osv.osv):
'selection': "",
'domain': "[]",
'name': 'x_',
'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
'state': lambda self,cr,uid,ctx=None: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
'on_delete': 'set null',
'select_level': '0',
'size': 64,
@ -271,7 +272,7 @@ class ir_model_fields(osv.osv):
except Exception:
_logger.warning('Invalid selection list definition for fields.selection', exc_info=True)
raise except_orm(_('Error'),
_("The Selection Options expression is not a valid Pythonic expression." \
_("The Selection Options expression is not a valid Pythonic expression."
"Please provide an expression in the [('key','Label'), ...] format."))
check = True
@ -514,7 +515,7 @@ class ir_model_constraint(Model):
# double-check we are really going to delete all the owners of this schema element
cr.execute("""SELECT id from ir_model_constraint where name=%s""", (data.name,))
external_ids = [x[0] for x in cr.fetchall()]
if (set(external_ids)-ids_set):
if set(external_ids)-ids_set:
# as installed modules have defined this element we must not delete it!
continue
@ -567,13 +568,12 @@ class ir_model_relation(Model):
ids.reverse()
for data in self.browse(cr, uid, ids, context):
model = data.model
model_obj = self.pool.get(model)
name = openerp.tools.ustr(data.name)
# double-check we are really going to delete all the owners of this schema element
cr.execute("""SELECT id from ir_model_relation where name = %s""", (data.name,))
external_ids = [x[0] for x in cr.fetchall()]
if (set(external_ids)-ids_set):
if set(external_ids)-ids_set:
# as installed modules have defined this element we must not delete it!
continue
@ -585,7 +585,7 @@ class ir_model_relation(Model):
# drop m2m relation tables
for table in to_drop_table:
cr.execute('DROP TABLE %s CASCADE'% (table),)
cr.execute('DROP TABLE %s CASCADE'% table,)
_logger.info('Dropped table %s', table)
cr.commit()
@ -862,7 +862,7 @@ class ir_model_data(osv.osv):
res = self.read(cr, uid, data_id, ['model', 'res_id'])
if not res['res_id']:
raise ValueError('No such external ID currently defined in the system: %s.%s' % (module, xml_id))
return (res['model'], res['res_id'])
return res['model'], res['res_id']
def get_object(self, cr, uid, module, xml_id, context=None):
"""Returns a browsable record for the given module name and xml_id or raise ValueError if not found"""
@ -903,7 +903,7 @@ class ir_model_data(osv.osv):
# records created during module install should not display the messages of OpenChatter
context = dict(context, install_mode=True)
if xml_id and ('.' in xml_id):
assert len(xml_id.split('.'))==2, _("'%s' contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id") % (xml_id)
assert len(xml_id.split('.'))==2, _("'%s' contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id") % xml_id
module, xml_id = xml_id.split('.')
if (not xml_id) and (not self.doinit):
return False
@ -1073,7 +1073,6 @@ class ir_model_data(osv.osv):
if model == 'ir.model.fields')
ir_model_relation = self.pool.get('ir.model.relation')
relation_ids = ir_model_relation.search(cr, uid, [('module', 'in', modules_to_remove)])
ir_module_module = self.pool.get('ir.module.module')
modules_to_remove_ids = ir_module_module.search(cr, uid, [('name', 'in', modules_to_remove)])
relation_ids = ir_model_relation.search(cr, uid, [('module', 'in', modules_to_remove_ids)])

View File

@ -21,8 +21,9 @@
from osv import osv
class ir_needaction_mixin(osv.AbstractModel):
'''Mixin class for objects using the need action feature.
"""Mixin class for objects using the need action feature.
Need action feature can be used by models that have to be able to
signal that an action is required on a particular record. If in
@ -36,7 +37,7 @@ class ir_needaction_mixin(osv.AbstractModel):
This class also offers several global services:
- ``_needaction_count``: returns the number of actions uid has to perform
'''
"""
_name = 'ir.needaction_mixin'
_needaction = True
@ -55,9 +56,10 @@ class ir_needaction_mixin(osv.AbstractModel):
# "Need action" API
#------------------------------------------------------
def _needaction_count(self, cr, uid, domain=[], context=None):
def _needaction_count(self, cr, uid, domain=None, context=None):
""" Get the number of actions uid has to perform. """
dom = self._needaction_domain_get(cr, uid, context=context)
if not dom:
return 0
return self.search(cr, uid, (domain or []) +dom, context=context, count=True)
res = self.search(cr, uid, (domain or []) + dom, limit=100, order='id DESC', context=context)
return len(res)

View File

@ -52,7 +52,7 @@ class ir_rule(osv.osv):
eval_context = self._eval_context(cr, uid)
for rule in self.browse(cr, uid, ids, context):
if rule.domain_force:
res[rule.id] = expression.normalize(eval(rule.domain_force, eval_context))
res[rule.id] = expression.normalize_domain(eval(rule.domain_force, eval_context))
else:
res[rule.id] = []
return res
@ -130,7 +130,7 @@ class ir_rule(osv.osv):
for rule in self.browse(cr, SUPERUSER_ID, rule_ids):
# read 'domain' as UID to have the correct eval context for the rule.
rule_domain = self.read(cr, uid, rule.id, ['domain'])['domain']
dom = expression.normalize(rule_domain)
dom = expression.normalize_domain(rule_domain)
for group in rule.groups:
if group in user.groups_id:
group_domains.setdefault(group, []).append(dom)

View File

@ -140,7 +140,7 @@ class ir_sequence(openerp.osv.osv.osv):
values = self._add_missing_default_values(cr, uid, values, context)
values['id'] = super(ir_sequence, self).create(cr, uid, values, context)
if values['implementation'] == 'standard':
f = self._create_sequence(cr, values['id'], values['number_increment'], values['number_next'])
self._create_sequence(cr, values['id'], values['number_increment'], values['number_next'])
return values['id']
def unlink(self, cr, uid, ids, context=None):

View File

@ -134,7 +134,7 @@ class ir_translation_import_cursor(object):
""" % (self._parent_table, self._table_name, self._parent_table, find_expr))
if self._debug:
cr.execute('SELECT COUNT(*) FROM ONLY %s' % (self._parent_table))
cr.execute('SELECT COUNT(*) FROM ONLY %s' % self._parent_table)
c1 = cr.fetchone()[0]
cr.execute('SELECT COUNT(*) FROM ONLY %s AS irt, %s AS ti WHERE %s' % \
(self._parent_table, self._table_name, find_expr))
@ -217,11 +217,11 @@ class ir_translation(osv.osv):
def _get_ids(self, cr, uid, name, tt, lang, ids):
translations = dict.fromkeys(ids, False)
if ids:
cr.execute('select res_id,value ' \
'from ir_translation ' \
'where lang=%s ' \
'and type=%s ' \
'and name=%s ' \
cr.execute('select res_id,value '
'from ir_translation '
'where lang=%s '
'and type=%s '
'and name=%s '
'and res_id IN %s',
(lang,tt,name,tuple(ids)))
for res_id, value in cr.fetchall():
@ -237,10 +237,10 @@ class ir_translation(osv.osv):
self._get_ids.clear_cache(self, uid, name, tt, lang, res_id)
self._get_source.clear_cache(self, uid, name, tt, lang)
cr.execute('delete from ir_translation ' \
'where lang=%s ' \
'and type=%s ' \
'and name=%s ' \
cr.execute('delete from ir_translation '
'where lang=%s '
'and type=%s '
'and name=%s '
'and res_id IN %s',
(lang,tt,name,tuple(ids),))
for id in ids:

View File

@ -44,9 +44,8 @@ class ir_ui_menu(osv.osv):
def __init__(self, *args, **kwargs):
self.cache_lock = threading.RLock()
self._cache = {}
r = super(ir_ui_menu, self).__init__(*args, **kwargs)
super(ir_ui_menu, self).__init__(*args, **kwargs)
self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache')
return r
def clear_cache(self):
with self.cache_lock:
@ -66,7 +65,7 @@ class ir_ui_menu(osv.osv):
modelaccess = self.pool.get('ir.model.access')
user_groups = set(self.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['groups_id'])['groups_id'])
result = []
for menu in self.browse(cr, SUPERUSER_ID, ids, context=context):
for menu in self.browse(cr, uid, ids, context=context):
# this key works because user access rights are all based on user's groups (cfr ir_model_access.check)
key = (cr.dbname, menu.id, tuple(user_groups))
if key in self._cache:
@ -144,7 +143,7 @@ class ir_ui_menu(osv.osv):
return res
def _get_full_name(self, cr, uid, ids, name=None, args=None, context=None):
if context == None:
if context is None:
context = {}
res = {}
for elmt in self.browse(cr, uid, ids, context=context):
@ -168,9 +167,22 @@ class ir_ui_menu(osv.osv):
self.clear_cache()
return super(ir_ui_menu, self).write(*args, **kwargs)
def unlink(self, *args, **kwargs):
def unlink(self, cr, uid, ids, context=None):
# Detach children and promote them to top-level, because it would be unwise to
# cascade-delete submenus blindly. We also can't use ondelete=set null because
# that is not supported when _parent_store is used (would silently corrupt it).
# TODO: ideally we should move them under a generic "Orphans" menu somewhere?
if isinstance(ids, (int, long)):
ids = [ids]
local_context = dict(context or {})
local_context['ir.ui.menu.full_list'] = True
direct_children_ids = self.search(cr, uid, [('parent_id', 'in', ids)], context=local_context)
if direct_children_ids:
self.write(cr, uid, direct_children_ids, {'parent_id': False})
result = super(ir_ui_menu, self).unlink(cr, uid, ids, context=context)
self.clear_cache()
return super(ir_ui_menu, self).unlink(*args, **kwargs)
return result
def copy(self, cr, uid, id, default=None, context=None):
ir_values_obj = self.pool.get('ir.values')
@ -182,7 +194,7 @@ class ir_ui_menu(osv.osv):
next_num=int(concat[0])+1
datas['name']=rex.sub(('(%d)'%next_num),datas['name'])
else:
datas['name']=datas['name']+'(1)'
datas['name'] += '(1)'
self.write(cr,uid,[res],{'name':datas['name']})
ids = ir_values_obj.search(cr, uid, [
('model', '=', 'ir.ui.menu'),
@ -307,7 +319,9 @@ class ir_ui_menu(osv.osv):
'name': fields.char('Menu', size=64, required=True, translate=True),
'sequence': fields.integer('Sequence'),
'child_id': fields.one2many('ir.ui.menu', 'parent_id', 'Child IDs'),
'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True, ondelete="restrict"),
'parent_left': fields.integer('Parent Left', select=True),
'parent_right': fields.integer('Parent Right', select=True),
'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel',
'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\
"If this field is empty, OpenERP will compute visibility based on the related object's read access."),
@ -348,5 +362,6 @@ class ir_ui_menu(osv.osv):
'sequence': 10,
}
_order = "sequence,id"
_parent_store = True
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -254,7 +254,7 @@ class view(osv.osv):
if label:
for lbl in eval(label):
if t.has_key(tools.ustr(lbl)) and tools.ustr(t[lbl])=='False':
label_string = label_string + ' '
label_string += ' '
else:
label_string = label_string + " " + tools.ustr(t[lbl])
labels[str(t['id'])] = (a['id'],label_string)

View File

@ -307,10 +307,10 @@ class ir_values(osv.osv):
ORDER BY v.user_id, u.company_id"""
params = ('default', model, uid, uid)
if condition:
query = query % 'AND v.key2 = %s'
query %= 'AND v.key2 = %s'
params += (condition[:200],)
else:
query = query % 'AND v.key2 is NULL'
query %= 'AND v.key2 is NULL'
cr.execute(query, params)
# keep only the highest priority default for each field
@ -417,7 +417,7 @@ class ir_values(osv.osv):
continue
# keep only the first action registered for each action name
results[action['name']] = (action['id'], action['name'], action_def)
except except_orm, e:
except except_orm:
continue
return sorted(results.values())

View File

@ -77,8 +77,10 @@ def graph_get(cr, graph, wkf_ids, nested, workitem, processed_subflows):
for t in transitions:
if not t['act_to'] in activities:
continue
args = {}
args['label'] = str(t['condition']).replace(' or ', '\\nor ').replace(' and ', '\\nand ')
args = {
'label': str(t['condition']).replace(' or ', '\\nor ')
.replace(' and ','\\nand ')
}
if t['signal']:
args['label'] += '\\n'+str(t['signal'])
args['style'] = 'bold'
@ -94,20 +96,19 @@ def graph_get(cr, graph, wkf_ids, nested, workitem, processed_subflows):
activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
graph.add_edge(pydot.Edge( str(activity_from) ,str(activity_to), fontsize='10', **args))
nodes = cr.dictfetchall()
cr.execute('select * from wkf_activity where flow_start=True and wkf_id in ('+','.join(['%s']*len(wkf_ids))+')', wkf_ids)
start = cr.fetchone()[0]
cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id in ("+','.join(['%s']*len(wkf_ids))+')', wkf_ids)
stop = cr.fetchall()
if (stop):
if stop:
stop = (stop[0][1], dict(stop))
else:
stop = ("stop",{})
return ((start,{}),stop)
return (start, {}), stop
def graph_instance_get(cr, graph, inst_id, nested=False):
workitems = {}
cr.execute('select wkf_id from wkf_instance where id=%s', (inst_id,))
inst = cr.fetchall()
@ -169,7 +170,7 @@ showpage'''
inst_id = inst_id[0]
graph_instance_get(cr, graph, inst_id, data.get('nested', False))
ps_string = graph.create(prog='dot', format='ps')
except Exception, e:
except Exception:
_logger.exception('Exception in call:')
# string is in PS, like the success message would have been
ps_string = '''%PS-Adobe-3.0
@ -206,13 +207,13 @@ class report_graph(report.interface.report_int):
def result(self):
if self.obj.is_done():
return (True, self.obj.get(), 'pdf')
return True, self.obj.get(), 'pdf'
else:
return (False, False, False)
return False, False, False
def create(self, cr, uid, ids, data, context=None):
self.obj = report_graph_instance(cr, uid, ids, data)
return (self.obj.get(), 'pdf')
return self.obj.get(), 'pdf'
report_graph('report.workflow.instance.graph', 'ir.workflow')

View File

@ -390,16 +390,20 @@ class module(osv.osv):
# Mark the given modules to be installed.
self.state_update(cr, uid, ids, 'to install', ['uninstalled'], context)
# Mark (recursively) the newly satisfied modules to also be installed:
# Mark (recursively) the newly satisfied modules to also be installed
# Select all auto-installable (but not yet installed) modules.
domain = [('state', '=', 'uninstalled'), ('auto_install', '=', True)]
uninstalled_ids = self.search(cr, uid, domain, context=context)
uninstalled_modules = self.browse(cr, uid, uninstalled_ids, context=context)
# Keep those with all their dependencies satisfied.
# Keep those with:
# - all dependencies satisfied (installed or to be installed),
# - at least one dependency being 'to install'
satisfied_states = frozenset(('installed', 'to install', 'to upgrade'))
def all_depencies_satisfied(m):
return all(x.state in ('to install', 'installed', 'to upgrade') for x in m.dependencies_id)
states = set(d.state for d in m.dependencies_id)
return states.issubset(satisfied_states) and ('to install' in states)
to_install_modules = filter(all_depencies_satisfied, uninstalled_modules)
to_install_ids = map(lambda m: m.id, to_install_modules)

View File

@ -3,16 +3,16 @@
<template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
<pageTemplate id="first">
<frame id="first" x1="42.0" y1="42.0" width="511" height="758"/>
<header>
<pageGraphics>
<setFont name="Helvetica-Bold" size="9"/>
<drawString x="1.0cm" y="28.1cm">[[ company.name ]]</drawString>
<drawRightString x="20cm" y="28.1cm"> Reference Guide </drawRightString>
<lineMode width="0.7"/>
<stroke color="black"/>
<lines>1cm 28cm 20cm 28cm</lines>
</pageGraphics>
</header>
<header>
<pageGraphics>
<setFont name="Helvetica-Bold" size="9"/>
<drawString x="1.0cm" y="28.1cm">[[ company.name ]]</drawString>
<drawRightString x="20cm" y="28.1cm"> Reference Guide </drawRightString>
<lineMode width="0.7"/>
<stroke color="black"/>
<lines>1cm 28cm 20cm 28cm</lines>
</pageGraphics>
</header>
</pageTemplate>
</template>
@ -236,7 +236,7 @@
<tr>
<td>
<para style="terp_default_9">[[ repeatIn(objdoc2(object.model) or [], 'sline') ]]</para>
<para style="terp_default_9"> [[ sline ]] </para>
<para style="terp_default_9"> [[ sline ]] </para>
</td>
</tr>
</blockTable>

View File

@ -1,75 +0,0 @@
# -*- 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/>.
#
##############################################################################
import os
import glob
import imp
import tools
import zipfile
from osv import osv
class base_module_scan(osv.osv_memory):
""" scan module """
_name = "base.module.scan"
_description = "scan module"
def watch_dir(self, cr, uid, ids, context):
mod_obj = self.pool.get('ir.module.module')
all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state'])
known_modules = [x['name'] for x in all_mods]
ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py'))
modules = [module_name_re.match(name).group(1) for name in ls_ad]
for fname in os.listdir(tools.config['addons_path']):
if zipfile.is_zipfile(fname):
modules.append( fname.split('.')[0])
for module in modules:
if module in known_modules:
continue
terp = mod_obj.get_module_info(module)
if not terp.get('installable', True):
continue
# XXX check if this code is correct...
fm = imp.find_module(module)
try:
imp.load_module(module, *fm)
finally:
if fm[0]:
fm[0].close()
values = mod_obj.get_values_from_terp(terp)
mod_id = mod_obj.create(cr, uid, dict(name=module, state='uninstalled', **values))
dependencies = terp.get('depends', [])
for d in dependencies:
cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d))
for module in known_modules:
terp = mod_obj.get_module_info(module)
if terp.get('installable', True):
for mod in all_mods:
if mod['name'] == module and mod['state'] == 'uninstallable':
mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'})
return {}
base_module_scan()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_base_module_scan" model="ir.ui.view">
<field name="name">Module Scan</field>
<field name="model">base.module.scan</field>
<field name="arch" type="xml">
<form string="Scan for new modules" version="7.0">
<label string="This function will check if you installed new modules in the 'addons' path of your server installation."/>
<footer>
<button name="watch_dir" string="Check new modules" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_view_base_module_scan" model="ir.actions.act_window">
<field name="name">Module Scan</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">base.module.scan</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -18,13 +18,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv
from osv import fields
import os
import tools
import openerp
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp import tools
from openerp.tools import image_resize_image
from tools.translate import _
from tools.safe_eval import safe_eval as eval
@ -102,6 +102,16 @@ class res_company(osv.osv):
part_obj.create(cr, uid, {name: value or False, 'parent_id': company.partner_id.id}, context=context)
return True
def _get_logo_web(self, cr, uid, ids, _field_name, _args, context=None):
result = dict.fromkeys(ids, False)
for record in self.browse(cr, uid, ids, context=context):
size = (180, None)
result[record.id] = image_resize_image(record.partner_id.image, size)
return result
def _get_companies_from_partner(self, cr, uid, ids, context=None):
return self.pool['res.company'].search(cr, uid, [('partner_id', 'in', ids)], context=context)
_columns = {
'name': fields.related('partner_id', 'name', string='Company Name', size=128, required=True, store=True, type='char'),
'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
@ -115,6 +125,10 @@ class res_company(osv.osv):
'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True),
'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually. Otherwise it will be filled in automatically."),
'logo': fields.related('partner_id', 'image', string="Logo", type="binary"),
'logo_web': fields.function(_get_logo_web, string="Logo Web", type="binary", store={
'res.company': (lambda s, c, u, i, x: i, ['partner_id'], 10),
'res.partner': (_get_companies_from_partner, ['image'], 10),
}),
'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'),
@ -352,7 +366,4 @@ class res_company(osv.osv):
]
res_company()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,10 +21,10 @@
<form string="Company" version="7.0">
<sheet>
<div>
<field name="logo" nolabel="1" widget="image" class="oe_avatar oe_left"/>
<field name="logo" widget="image" class="oe_avatar oe_left"/>
</div>
<div class="oe_right oe_button_box" name="button_box">
<button name="%(preview_report)d" string="Preview Header/Footer" type="action" icon="gtk-print" class="oe_inline oe_right"/>
<button name="%(preview_report)d" string="Preview Header/Footer" type="action"/>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>

View File

@ -309,7 +309,7 @@ class res_config_installer(osv.osv_memory):
hooks_results = set()
for module in base:
hook = getattr(self, '_if_%s'%(module), None)
hook = getattr(self, '_if_%s'% module, None)
if hook:
hooks_results.update(hook(cr, uid, ids, context=None) or set())

View File

@ -1186,7 +1186,7 @@
<record id="us" model="res.country">
<field name="name">United States</field>
<field name="code">us</field>
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s'" />
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s, %(state_code)s %(zip)s\n%(country_name)s'" />
<field name="currency_id" ref="USD"/>
</record>
<record id="uy" model="res.country">

View File

@ -99,7 +99,7 @@ class res_currency(osv.osv):
res = super(res_currency, self).read(cr, user, ids, fields, context, load)
currency_rate_obj = self.pool.get('res.currency.rate')
values = res
if not isinstance(values, (list)):
if not isinstance(values, list):
values = [values]
for r in values:
if r.__contains__('rate_ids'):
@ -217,7 +217,7 @@ class res_currency(osv.osv):
if round:
return self.round(cr, uid, to_currency, from_amount * rate)
else:
return (from_amount * rate)
return from_amount * rate
res_currency()

View File

@ -168,7 +168,7 @@ class lang(osv.osv):
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
return (grouping, thousands_sep, decimal_point)
return grouping, thousands_sep, decimal_point
def write(self, cr, uid, ids, vals, context=None):
for lang_id in ids :
@ -231,7 +231,7 @@ lang()
def original_group(s, grouping, thousands_sep=''):
if not grouping:
return (s, 0)
return s, 0
result = ""
seps = 0

View File

@ -208,10 +208,6 @@ class res_partner(osv.osv, format_address):
'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
'website': fields.char('Website', size=64, help="Website of Partner or Company"),
'comment': fields.text('Notes'),
'address': fields.one2many('res.partner.address', 'partner_id', 'Addresses',
deprecated="The address information is now directly stored on each Partner record. "\
"Multiple contacts with their own address can be added via the child_ids relationship. "\
"This field will be removed as of OpenERP 7.1."),
'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'),
'credit_limit': fields.float(string='Credit Limit'),
'ean13': fields.char('EAN13', size=13),
@ -309,7 +305,7 @@ class res_partner(osv.osv, format_address):
if default is None:
default = {}
name = self.read(cr, uid, [id], ['name'], context)[0]['name']
default.update({'name': _('%s (copy)') % (name)})
default.update({'name': _('%s (copy)') % name})
return super(res_partner, self).copy(cr, uid, id, default, context)
def onchange_type(self, cr, uid, ids, is_company, context=None):
@ -519,7 +515,7 @@ class res_partner(osv.osv, format_address):
def view_header_get(self, cr, uid, view_id, view_type, context):
res = super(res_partner, self).view_header_get(cr, uid, view_id, view_type, context)
if res: return res
if (not context.get('category_id', False)):
if not context.get('category_id', False):
return False
return _('Partners: ')+self.pool.get('res.partner.category').browse(cr, uid, context['category_id'], context).name
@ -538,7 +534,7 @@ class res_partner(osv.osv, format_address):
The purpose of this function is to build and return an address formatted accordingly to the
standards of the country where it belongs.
:param address: browse record of the res.partner.address to format
:param address: browse record of the res.partner to format
:returns: the address formatted in a display that fit its country habits (or the default ones
if not country is specified)
:rtype: string
@ -564,55 +560,4 @@ class res_partner(osv.osv, format_address):
address_format = '%(company_name)s\n' + address_format
return address_format % args
# res.partner.address is deprecated; it is still there for backward compability only and will be removed in next version
class res_partner_address(osv.osv):
_table = "res_partner"
_name = 'res.partner.address'
_order = 'type, name'
_columns = {
'parent_id': fields.many2one('res.partner', 'Company', ondelete='set null', select=True),
'partner_id': fields.related('parent_id', type='many2one', relation='res.partner', string='Partner'), # for backward compatibility
'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.char('Function', size=128),
'title': fields.many2one('res.partner.title','Title'),
'name': fields.char('Contact Name', size=64, select=1),
'street': fields.char('Street', size=128),
'street2': fields.char('Street2', size=128),
'zip': fields.char('Zip', change_default=True, size=24),
'city': fields.char('City', size=128),
'state_id': fields.many2one("res.country.state", 'Fed. State', domain="[('country_id','=',country_id)]"),
'country_id': fields.many2one('res.country', 'Country'),
'email': fields.char('Email', size=240),
'phone': fields.char('Phone', size=64),
'fax': fields.char('Fax', size=64),
'mobile': fields.char('Mobile', size=64),
'birthdate': fields.char('Birthdate', size=64),
'is_customer_add': fields.related('partner_id', 'customer', type='boolean', string='Customer'),
'is_supplier_add': fields.related('partner_id', 'supplier', type='boolean', string='Supplier'),
'active': fields.boolean('Active', help="Uncheck the active field to hide the contact."),
'company_id': fields.many2one('res.company', 'Company',select=1),
'color': fields.integer('Color Index'),
}
_defaults = {
'active': True,
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=c),
'color': 0,
'type': 'default',
}
def write(self, cr, uid, ids, vals, context=None):
logging.getLogger('res.partner').warning("Deprecated use of res.partner.address")
if 'partner_id' in vals:
vals['parent_id'] = vals.get('partner_id')
del(vals['partner_id'])
return self.pool.get('res.partner').write(cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context=None):
logging.getLogger('res.partner').warning("Deprecated use of res.partner.address")
if 'partner_id' in vals:
vals['parent_id'] = vals.get('partner_id')
del(vals['partner_id'])
return self.pool.get('res.partner').create(cr, uid, vals, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -58,7 +58,7 @@ class res_request(osv.osv):
ids = map(lambda x:x[0], cr.fetchall())
cr.execute('select id from res_request where act_from=%s and (act_to<>%s) and (trigger_date<=%s or trigger_date is null) and active=True and state != %s', (uid,uid,time.strftime('%Y-%m-%d'), 'closed'))
ids2 = map(lambda x:x[0], cr.fetchall())
return (ids, ids2)
return ids, ids2
_columns = {
'create_date': fields.datetime('Created Date', readonly=True),

View File

@ -253,7 +253,7 @@ class res_users(osv.osv):
# User can write on a few of his own fields (but not his groups for example)
SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz']
# User can read a few of his own fields
SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id', '__last_update']
SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'tz_offset', 'groups_id', 'partner_id', '__last_update']
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
def override_password(o):

View File

@ -93,7 +93,7 @@
<field name="image" widget='image' class="oe_left oe_avatar" options='{"preview_image": "image_medium", "size": [90, 90]}'/>
<div class="oe_title">
<div class="oe_edit_only">
<label for="name"/> (
<label for="name"/>
</div>
<h1>
<field name="name" default_focus="1" placeholder="Name" />

View File

@ -1,4 +0,0 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_res_partner_address_group_partner_manager","res_partner_address group_partner_manager","model_res_partner_address","group_partner_manager",1,1,1,1
"access_res_partner_address_group_user","res_partner_address group_user","model_res_partner_address","group_user",1,0,0,0
"access_res_partner_address","res.partner.address","model_res_partner_address","group_system",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_res_partner_address_group_partner_manager res_partner_address group_partner_manager model_res_partner_address group_partner_manager 1 1 1 1
3 access_res_partner_address_group_user res_partner_address group_user model_res_partner_address group_user 1 0 0 0
4 access_res_partner_address res.partner.address model_res_partner_address group_system 1 1 1 1

View File

@ -1,8 +1,9 @@
import test_base, test_expression, test_search, test_ir_values
import test_base, test_expression, test_search, test_ir_values, test_menu
checks = [
test_base,
test_expression,
test_search,
test_ir_values,
test_menu,
]

View File

@ -1,11 +1,33 @@
import unittest2
from openerp.osv.orm import BaseModel
import openerp.tests.common as common
class test_expression(common.TransactionCase):
def test_in_not_in_m2m(self):
def _reinit_mock(self):
self.query_list = list()
def _mock_base_model_where_calc(self, model, *args, **kwargs):
""" Mock build_email to be able to test its values. Store them into
some internal variable for latter processing. """
self.query_list.append(self._base_model_where_calc(model, *args, **kwargs))
# return the lastly stored query, the one the ORM wants to perform
return self.query_list[-1]
def setUp(self):
super(test_expression, self).setUp()
# Mock BaseModel._where_calc(), to be able to proceed to some tests about generated expression
self._reinit_mock()
self._base_model_where_calc = BaseModel._where_calc
BaseModel._where_calc = lambda model, cr, uid, args, context: self._mock_base_model_where_calc(model, cr, uid, args, context)
def tearDown(self):
# Remove mocks
BaseModel._where_calc = self._base_model_where_calc
super(test_expression, self).tearDown()
def test_00_in_not_in_m2m(self):
registry, cr, uid = self.registry, self.cr, self.uid
# Create 4 partners with no category, or one or two categories (out of two categories).
@ -70,3 +92,346 @@ class test_expression(common.TransactionCase):
# self.assertTrue(a not in with_any_other_than_a, "Search for category_id with any other than cat_a failed (1).")
# self.assertTrue(ab in with_any_other_than_a, "Search for category_id with any other than cat_a failed (2).")
def test_10_expression_parse(self):
# TDE note: those tests have been added when refactoring the expression.parse() method.
# They come in addition to the already existing test_osv_expression.yml; maybe some tests
# will be a bit redundant
registry, cr, uid = self.registry, self.cr, self.uid
users_obj = registry('res.users')
# Create users
a = users_obj.create(cr, uid, {'name': 'test_A', 'login': 'test_A'})
b1 = users_obj.create(cr, uid, {'name': 'test_B', 'login': 'test_B'})
b1_user = users_obj.browse(cr, uid, [b1])[0]
b2 = users_obj.create(cr, uid, {'name': 'test_B2', 'login': 'test_B2', 'parent_id': b1_user.partner_id.id})
# Test1: simple inheritance
user_ids = users_obj.search(cr, uid, [('name', 'like', 'test')])
self.assertEqual(set(user_ids), set([a, b1, b2]), 'searching through inheritance failed')
user_ids = users_obj.search(cr, uid, [('name', '=', 'test_B')])
self.assertEqual(set(user_ids), set([b1]), 'searching through inheritance failed')
# Test2: inheritance + relational fields
user_ids = users_obj.search(cr, uid, [('child_ids.name', 'like', 'test_B')])
self.assertEqual(set(user_ids), set([b1]), 'searching through inheritance failed')
def test_20_auto_join(self):
registry, cr, uid = self.registry, self.cr, self.uid
# Get models
partner_obj = registry('res.partner')
state_obj = registry('res.country.state')
bank_obj = registry('res.partner.bank')
# Get test columns
partner_state_id_col = partner_obj._columns.get('state_id') # many2one on res.partner to res.country.state
partner_parent_id_col = partner_obj._columns.get('parent_id') # many2one on res.partner to res.partner
state_country_id_col = state_obj._columns.get('country_id') # many2one on res.country.state on res.country
partner_child_ids_col = partner_obj._columns.get('child_ids') # one2many on res.partner to res.partner
partner_bank_ids_col = partner_obj._columns.get('bank_ids') # one2many on res.partner to res.partner.bank
category_id_col = partner_obj._columns.get('category_id') # many2many on res.partner to res.partner.category
# Get the first bank account type to be able to create a res.partner.bank
bank_type = bank_obj._bank_type_get(cr, uid)[0]
# Get country/state data
country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0]
state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2)
# Create demo data: partners and bank object
p_a = partner_obj.create(cr, uid, {'name': 'test__A', 'state_id': state_ids[0]})
p_b = partner_obj.create(cr, uid, {'name': 'test__B', 'state_id': state_ids[1]})
p_aa = partner_obj.create(cr, uid, {'name': 'test__AA', 'parent_id': p_a, 'state_id': state_ids[0]})
p_ab = partner_obj.create(cr, uid, {'name': 'test__AB', 'parent_id': p_a, 'state_id': state_ids[1]})
p_ba = partner_obj.create(cr, uid, {'name': 'test__BA', 'parent_id': p_b, 'state_id': state_ids[0]})
b_aa = bank_obj.create(cr, uid, {'name': '__bank_test_a', 'state': bank_type[0], 'partner_id': p_aa, 'acc_number': '1234'})
b_ab = bank_obj.create(cr, uid, {'name': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ab, 'acc_number': '5678'})
b_ba = bank_obj.create(cr, uid, {'name': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ba, 'acc_number': '9876'})
# --------------------------------------------------
# Test1: basics about the attribute
# --------------------------------------------------
category_id_col._auto_join = True
self.assertRaises(NotImplementedError, partner_obj.search, cr, uid, [('category_id.name', '=', 'foo')])
category_id_col._auto_join = False
# --------------------------------------------------
# Test2: one2many
# --------------------------------------------------
name_test = 'test_a'
# Do: one2many without _auto_join
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('bank_ids.name', 'like', name_test)])
# Test result
self.assertEqual(set(partner_ids), set([p_aa]),
"_auto_join off: ('bank_ids.name', 'like', '..'): incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 3,
"_auto_join off: ('bank_ids.name', 'like', '..') should produce 3 queries (1 in res_partner_bank, 2 on res_partner)")
sql_query = self.query_list[0].get_sql()
self.assertIn('res_partner_bank', sql_query[0],
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect main table")
self.assertIn('"res_partner_bank"."name" like %s', sql_query[1],
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect where condition")
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect parameter")
sql_query = self.query_list[2].get_sql()
self.assertIn('res_partner', sql_query[0],
"_auto_join off: ('bank_ids.name', 'like', '..') third query incorrect main table")
self.assertIn('"res_partner"."id" in (%s)', sql_query[1],
"_auto_join off: ('bank_ids.name', 'like', '..') third query incorrect where condition")
self.assertEqual(set([p_aa]), set(sql_query[2]),
"_auto_join off: ('bank_ids.name', 'like', '..') third query incorrect parameter")
# Do: cascaded one2many without _auto_join
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('child_ids.bank_ids.id', 'in', [b_aa, b_ba])])
# Test result
self.assertEqual(set(partner_ids), set([p_a, p_b]),
"_auto_join off: ('child_ids.bank_ids.id', 'in', [..]): incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 5,
"_auto_join off: ('child_ids.bank_ids.id', 'in', [..]) should produce 5 queries (1 in res_partner_bank, 4 on res_partner)")
# Do: one2many with _auto_join
partner_bank_ids_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('bank_ids.name', 'like', 'test_a')])
# Test result
self.assertEqual(set(partner_ids), set([p_aa]),
"_auto_join on: ('bank_ids.name', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 1,
"_auto_join on: ('bank_ids.name', 'like', '..') should produce 1 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect main table")
self.assertIn('"res_partner_bank" as "res_partner__bank_ids"', sql_query[0],
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect join")
self.assertIn('"res_partner__bank_ids"."name" like %s', sql_query[1],
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect where condition")
self.assertIn('"res_partner"."id"="res_partner__bank_ids"."partner_id"', sql_query[1],
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect join condition")
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect parameter")
# Do: one2many with _auto_join, test final leaf is an id
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('bank_ids.id', 'in', [b_aa, b_ab])])
# Test result
self.assertEqual(set(partner_ids), set([p_aa, p_ab]),
"_auto_join on: ('bank_ids.id', 'in', [..]) incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 1,
"_auto_join on: ('bank_ids.id', 'in', [..]) should produce 1 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect main table")
self.assertIn('"res_partner__bank_ids"."id" in (%s,%s)', sql_query[1],
"_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect where condition")
self.assertEqual(set([b_aa, b_ab]), set(sql_query[2]),
"_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect parameter")
# Do: 2 cascaded one2many with _auto_join, test final leaf is an id
partner_child_ids_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('child_ids.bank_ids.id', 'in', [b_aa, b_ba])])
# Test result
self.assertEqual(set(partner_ids), set([p_a, p_b]),
"_auto_join on: ('child_ids.bank_ids.id', 'not in', [..]): incorrect result")
# # Test produced queries
self.assertEqual(len(self.query_list), 1,
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) should produce 1 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) incorrect main table")
self.assertIn('"res_partner" as "res_partner__child_ids"', sql_query[0],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join")
self.assertIn('"res_partner_bank" as "res_partner__child_ids__bank_ids"', sql_query[0],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join")
self.assertIn('"res_partner__child_ids__bank_ids"."id" in (%s,%s)', sql_query[1],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect where condition")
self.assertIn('"res_partner"."id"="res_partner__child_ids"."parent_id"', sql_query[1],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition")
self.assertIn('"res_partner__child_ids"."id"="res_partner__child_ids__bank_ids"."partner_id"', sql_query[1],
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition")
self.assertEqual(set([b_aa, b_ba]), set(sql_query[2]),
"_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect parameter")
# --------------------------------------------------
# Test3: many2one
# --------------------------------------------------
name_test = 'US'
# Do: many2one without _auto_join
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)),
"_auto_join off: ('state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 3,
"_auto_join off: ('state_id.country_id.code', 'like', '..') should produce 3 queries (1 on res_country, 1 on res_country_state, 1 on res_partner)")
# Do: many2one with 1 _auto_join on the first many2one
partner_state_id_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)),
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 2,
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') should produce 2 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_country"', sql_query[0],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect main table")
self.assertIn('"res_country"."code" like %s', sql_query[1],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
self.assertEqual(['%' + name_test + '%'], sql_query[2],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect parameter")
sql_query = self.query_list[1].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect main table")
self.assertIn('"res_country_state" as "res_partner__state_id"', sql_query[0],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect join")
self.assertIn('"res_partner__state_id"."country_id" in (%s)', sql_query[1],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect where condition")
self.assertIn('"res_partner"."state_id"="res_partner__state_id"."id"', sql_query[1],
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect join condition")
# Do: many2one with 1 _auto_join on the second many2one
partner_state_id_col._auto_join = False
state_country_id_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)),
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 2,
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') should produce 2 query")
# -- first query
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_country_state"', sql_query[0],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect main table")
self.assertIn('"res_country" as "res_country_state__country_id"', sql_query[0],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect join")
self.assertIn('"res_country_state__country_id"."code" like %s', sql_query[1],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
self.assertIn('"res_country_state"."country_id"="res_country_state__country_id"."id"', sql_query[1],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect join condition")
self.assertEqual(['%' + name_test + '%'], sql_query[2],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect parameter")
# -- second query
sql_query = self.query_list[1].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect main table")
self.assertIn('"res_partner"."state_id" in', sql_query[1],
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect where condition")
# Do: many2one with 2 _auto_join
partner_state_id_col._auto_join = True
state_country_id_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)),
"_auto_join on: ('state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 1,
"_auto_join on: ('state_id.country_id.code', 'like', '..') should produce 1 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner"', sql_query[0],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect main table")
self.assertIn('"res_country_state" as "res_partner__state_id"', sql_query[0],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join")
self.assertIn('"res_country" as "res_partner__state_id__country_id"', sql_query[0],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join")
self.assertIn('"res_partner__state_id__country_id"."code" like %s', sql_query[1],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect where condition")
self.assertIn('"res_partner"."state_id"="res_partner__state_id"."id"', sql_query[1],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join condition")
self.assertIn('"res_partner__state_id"."country_id"="res_partner__state_id__country_id"."id"', sql_query[1],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join condition")
self.assertEqual(['%' + name_test + '%'], sql_query[2],
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect parameter")
# --------------------------------------------------
# Test4: domain attribute on one2many fields
# --------------------------------------------------
partner_child_ids_col._auto_join = True
partner_bank_ids_col._auto_join = True
partner_child_ids_col._domain = lambda self: ['!', ('name', '=', self._name)]
partner_bank_ids_col._domain = [('acc_number', 'like', '1')]
# Do: 2 cascaded one2many with _auto_join, test final leaf is an id
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, ['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa, b_ba])])
# Test result: at least one of our added data
self.assertTrue(set([p_a]).issubset(set(partner_ids)),
"_auto_join on one2many with domains incorrect result")
self.assertTrue(set([p_ab, p_ba]) not in set(partner_ids),
"_auto_join on one2many with domains incorrect result")
# Test produced queries that domains effectively present
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner__child_ids__bank_ids"."acc_number" like %s', sql_query[1],
"_auto_join on one2many with domains incorrect result")
# TDE TODO: check first domain has a correct table name
self.assertIn('"res_partner__child_ids"."name" = %s', sql_query[1],
"_auto_join on one2many with domains incorrect result")
partner_child_ids_col._domain = lambda self: [('name', '=', '__%s' % self._name)]
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, ['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa, b_ba])])
# Test result: no one
self.assertFalse(partner_ids,
"_auto_join on one2many with domains incorrect result")
# ----------------------------------------
# Test5: result-based tests
# ----------------------------------------
partner_bank_ids_col._auto_join = False
partner_child_ids_col._auto_join = False
partner_state_id_col._auto_join = False
partner_parent_id_col._auto_join = False
state_country_id_col._auto_join = False
partner_child_ids_col._domain = []
partner_bank_ids_col._domain = []
# Do: ('child_ids.state_id.country_id.code', 'like', '..') without _auto_join
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('child_ids.state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b]).issubset(set(partner_ids)),
"_auto_join off: ('child_ids.state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 5,
"_auto_join off: ('child_ids.state_id.country_id.code', 'like', '..') number of queries incorrect")
# Do: ('child_ids.state_id.country_id.code', 'like', '..') with _auto_join
partner_child_ids_col._auto_join = True
partner_state_id_col._auto_join = True
state_country_id_col._auto_join = True
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, [('child_ids.state_id.country_id.code', 'like', name_test)])
# Test result: at least our added data + demo data
self.assertTrue(set([p_a, p_b]).issubset(set(partner_ids)),
"_auto_join on: ('child_ids.state_id.country_id.code', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 1,
"_auto_join on: ('child_ids.state_id.country_id.code', 'like', '..') number of queries incorrect")
# Remove mocks and modifications
partner_bank_ids_col._auto_join = False
partner_child_ids_col._auto_join = False
partner_state_id_col._auto_join = False
partner_parent_id_col._auto_join = False
state_country_id_col._auto_join = False
if __name__ == '__main__':
unittest2.main()

View File

@ -0,0 +1,34 @@
import unittest2
import openerp.tests.common as common
class test_menu(common.TransactionCase):
def setUp(self):
super(test_menu,self).setUp()
self.Menus = self.registry('ir.ui.menu')
def test_00_menu_deletion(self):
"""Verify that menu deletion works properly when there are child menus, and those
are indeed made orphans"""
cr, uid, Menus = self.cr, self.uid, self.Menus
# Generic trick necessary for search() calls to avoid hidden menus
ctx = {'ir.ui.menu.full_list': True}
root_id = Menus.create(cr, uid, {'name': 'Test root'})
child1_id = Menus.create(cr, uid, {'name': 'Test child 1', 'parent_id': root_id})
child2_id = Menus.create(cr, uid, {'name': 'Test child 2', 'parent_id': root_id})
child21_id = Menus.create(cr, uid, {'name': 'Test child 2-1', 'parent_id': child2_id})
all_ids = [root_id, child1_id, child2_id, child21_id]
# delete and check that direct children are promoted to top-level
# cfr. explanation in menu.unlink()
Menus.unlink(cr, uid, [root_id])
remaining_ids = Menus.search(cr, uid, [('id', 'in', all_ids)], order="id", context=ctx)
self.assertEqual([child1_id, child2_id, child21_id], remaining_ids)
orphan_ids = Menus.search(cr, uid, [('id', 'in', all_ids), ('parent_id', '=', False)], order="id", context=ctx)
self.assertEqual([child1_id, child2_id], orphan_ids)

View File

@ -2,16 +2,17 @@ import unittest2
import openerp.tests.common as common
class test_expression(common.TransactionCase):
def test_search_order(self):
class test_search(common.TransactionCase):
def test_00_search_order(self):
registry, cr, uid = self.registry, self.cr, self.uid
# Create 6 partners with a given name, and a given creation order to
# ensure the order of their ID. Some are set as unactive to verify they
# are by default excluded from the searches and to provide a second
# `order` argument.
# Create 6 partners with a given name, and a given creation order to
# ensure the order of their ID. Some are set as unactive to verify they
# are by default excluded from the searches and to provide a second
# `order` argument.
partners = registry('res.partner')
c = partners.create(cr, uid, {'name': 'test_search_order_C'})
@ -23,9 +24,9 @@ class test_expression(common.TransactionCase):
# The tests.
# The basic searches should exclude records that have active = False.
# The order of the returned ids should be given by the `order`
# parameter of search().
# The basic searches should exclude records that have active = False.
# The order of the returned ids should be given by the `order`
# parameter of search().
name_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name asc")
self.assertEqual([a, ab, b, c], name_asc, "Search with 'NAME ASC' order failed.")
@ -36,9 +37,9 @@ class test_expression(common.TransactionCase):
id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id desc")
self.assertEqual([ab, b, a, c], id_desc, "Search with 'ID DESC' order failed.")
# The inactive records shouldn't be excluded as soon as a condition on
# that field is present in the domain. The `order` parameter of
# search() should support any legal coma-separated values.
# The inactive records shouldn't be excluded as soon as a condition on
# that field is present in the domain. The `order` parameter of
# search() should support any legal coma-separated values.
active_asc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc")
self.assertEqual([d, e, c, a, b, ab], active_asc_id_asc, "Search with 'ACTIVE ASC, ID ASC' order failed.")
@ -57,4 +58,52 @@ class test_expression(common.TransactionCase):
id_desc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc")
self.assertEqual([e, ab, b, a, d, c], id_desc_active_desc, "Search with 'ID DESC, ACTIVE DESC' order failed.")
def test_10_inherits_m2order(self):
registry, cr, uid = self.registry, self.cr, self.uid
users_obj = registry('res.users')
# Find Employee group
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
group_employee_id = group_employee_ref and group_employee_ref[1] or False
# Get country/state data
country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0]
state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2)
country_be_id = registry('res.country').search(cr, uid, [('code', 'like', 'BE')])[0]
# Create test users
search_user = users_obj.create(cr, uid, {'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee_id])]})
a = users_obj.create(cr, uid, {'name': '__test_A', 'login': '__test_A', 'country_id': country_be_id, 'state_id': country_be_id})
b = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__a_test_B', 'country_id': country_us_id, 'state_id': state_ids[1]})
c = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__z_test_B', 'country_id': country_us_id, 'state_id': state_ids[0]})
# Do: search on res.users, order on a field on res.partner to try inherits'd fields, then res.users
user_ids = users_obj.search(cr, search_user, [], order='name asc, login desc')
expected_ids = [search_user, a, c, b]
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
# Do: order on many2one and inherits'd fields
user_ids = users_obj.search(cr, search_user, [], order='state_id asc, country_id desc, name asc, login desc')
expected_ids = [c, b, a, search_user]
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
# Do: order on many2one and inherits'd fields
user_ids = users_obj.search(cr, search_user, [], order='country_id desc, state_id desc, name asc, login desc')
expected_ids = [search_user, b, c, a]
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
# Do: order on many2one, but not by specifying in order parameter of search, but by overriding _order of res_users
old_order = users_obj._order
users_obj._order = 'country_id desc, name asc, login desc'
user_ids = users_obj.search(cr, search_user, [])
expected_ids = [search_user, c, b, a]
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
users_obj._order = old_order
if __name__ == '__main__':
unittest2.main()

View File

@ -30,6 +30,7 @@ import time
import pickle
import base64
import socket
import string
admin_passwd = 'admin'
waittime = 10
@ -67,10 +68,10 @@ def execute(connector, method, *args):
except socket.error,e:
if e.args[0] == 111:
if wait_count > wait_limit:
print "Server is taking too long to start, it has exceeded the maximum limit of %d seconds."%(wait_limit)
print "Server is taking too long to start, it has exceeded the maximum limit of %d seconds." % wait_limit
clean()
sys.exit(1)
print 'Please wait %d sec to start server....'%(waittime)
print 'Please wait %d sec to start server....' % waittime
wait_count += 1
time.sleep(waittime)
res = execute(connector, method, *args)
@ -136,7 +137,7 @@ def check_quality(uri, user, pwd, dbname, modules, quality_logs):
detail_html +='''<div id=\"%s\"><h3>%s (Score : %s)</h3><font color=red><h5>%s</h5></font>%s</div>'''%(test.replace(' ', '-'), test, score, msg, detail.get('detail', ''))
test_detail[test] = (score,msg,detail.get('detail',''))
html += "</ul>"
html += "%s"%(detail_html)
html += "%s"% detail_html
html += "</div></body></html>"
if not os.path.isdir(quality_logs):
os.mkdir(quality_logs)
@ -305,13 +306,11 @@ options = {
'port' : opt.port or 8069,
'netport':opt.netport or 8070,
'database': opt.db_name or 'terp',
'modules' : opt.modules or [],
'modules' : map(string.strip, opt.modules.split(',')) if opt.modules else [],
'login' : opt.login or 'admin',
'pwd' : opt.pwd or '',
'extra-addons':opt.extra_addons or []
}
options['modules'] = opt.modules and map(lambda m: m.strip(), opt.modules.split(',')) or []
# Hint:i18n-import=purchase:ar_AR.po+sale:fr_FR.po,nl_BE.po
if opt.translate_in:
translate = opt.translate_in

View File

@ -94,10 +94,8 @@ def setup_pid_file():
def preload_registry(dbname):
""" Preload a registry, and start the cron."""
try:
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=openerp.tools.config['init'] or openerp.tools.config['update'], pooljobs=False)
# jobs will start to be processed later, when openerp.cron.start_master_thread() is called by openerp.service.start_services()
registry.schedule_cron_jobs()
update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=update_module, pooljobs=False)
except Exception:
_logger.exception('Failed to initialize database `%s`.', dbname)

View File

@ -110,7 +110,7 @@ def get_encodings(hint_encoding='utf-8'):
# some defaults (also taking care of pure ASCII)
for charset in ['utf8','latin1']:
if not (hint_encoding) or (charset.lower() != hint_encoding.lower()):
if not hint_encoding or (charset.lower() != hint_encoding.lower()):
yield charset
from locale import getpreferredencoding
@ -129,7 +129,7 @@ def ustr(value, hint_encoding='utf-8', errors='strict'):
:param: value: the value to convert
:param: hint_encoding: an optional encoding that was detecte
upstream and should be tried first to decode ``value``.
:param str error: optional `errors` flag to pass to the unicode
:param str errors: optional `errors` flag to pass to the unicode
built-in to indicate how illegal character values should be
treated when converting a string: 'strict', 'ignore' or 'replace'
(see ``unicode()`` constructor).

View File

@ -146,6 +146,14 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
cr.execute("select (now() at time zone 'UTC')::timestamp")
dt_before_load = cr.fetchone()[0]
# Query manual fields for all models at once and save them on the registry
# so the initialization code for each model does not have to do it
# one model at a time.
pool.fields_by_model = {}
cr.execute('SELECT * FROM ir_model_fields WHERE state=%s', ('manual',))
for field in cr.dictfetchall():
pool.fields_by_model.setdefault(field['model'], []).append(field)
# register, instantiate and initialize models for each modules
for index, package in enumerate(graph):
module_name = package.name
@ -159,6 +167,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
load_openerp_module(package.name)
models = pool.load(cr, package)
loaded_modules.append(package.name)
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
init_module_models(cr, package.name, models)
@ -220,6 +229,10 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
delattr(package, kind)
cr.commit()
# The query won't be valid for models created later (i.e. custom model
# created after the registry has been loaded), so empty its result.
pool.fields_by_model = None
cr.commit()
@ -239,7 +252,7 @@ def _check_module_names(cr, module_names):
incorrect_names = mod_names.difference([x['name'] for x in cr.dictfetchall()])
_logger.warning('invalid module names, ignored: %s', ", ".join(incorrect_names))
def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_modules):
def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_modules, perform_checks):
"""Loads modules marked with ``states``, adding them to ``graph`` and
``loaded_modules`` and returns a list of installed/upgraded modules."""
processed_modules = []
@ -248,7 +261,7 @@ def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_m
module_list = [name for (name,) in cr.fetchall() if name not in graph]
graph.add_modules(cr, module_list, force)
_logger.debug('Updating graph with %d more modules', len(module_list))
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules)
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks)
processed_modules.extend(processed)
loaded_modules.extend(loaded)
if not processed: break
@ -293,7 +306,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# processed_modules: for cleanup step after install
# loaded_modules: to avoid double loading
report = pool._assertion_report
loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report)
loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=update_module, report=report)
if tools.config['load_language']:
for lang in tools.config['load_language'].split(','):
@ -333,11 +346,11 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# be dropped in STEP 6 later, before restarting the loading
# process.
states_to_load = ['installed', 'to upgrade', 'to remove']
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
processed_modules.extend(processed)
if update_module:
states_to_load = ['to install']
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
processed_modules.extend(processed)
# load custom models

View File

@ -50,6 +50,7 @@ class Registry(object):
self._init = True
self._init_parent = {}
self._assertion_report = assertion_report.assertion_report()
self.fields_by_model = None
# modules fully loaded (maintained during init phase by `loading` module)
self._init_modules = set()

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,9 @@
Fields Attributes:
* _classic_read: is a classic sql fields
* _type : field type
* _auto_join: for one2many and many2one fields, tells whether select
queries will join the relational table instead of replacing the
field condition by an equivalent-one based on a search.
* readonly
* required
* size
@ -67,6 +70,7 @@ class _column(object):
"""
_classic_read = True
_classic_write = True
_auto_join = False
_prefetch = True
_properties = False
_type = 'unknown'
@ -427,9 +431,10 @@ class many2one(_column):
_symbol_f = lambda x: x or None
_symbol_set = (_symbol_c, _symbol_f)
def __init__(self, obj, string='unknown', **args):
def __init__(self, obj, string='unknown', auto_join=False, **args):
_column.__init__(self, string=string, **args)
self._obj = obj
self._auto_join = auto_join
def get(self, cr, obj, ids, name, user=None, context=None, values=None):
if context is None:
@ -496,11 +501,12 @@ class one2many(_column):
_prefetch = False
_type = 'one2many'
def __init__(self, obj, fields_id, string='unknown', limit=None, **args):
def __init__(self, obj, fields_id, string='unknown', limit=None, auto_join=False, **args):
_column.__init__(self, string=string, **args)
self._obj = obj
self._fields_id = fields_id
self._limit = limit
self._auto_join = auto_join
#one2many can't be used as condition for defaults
assert(self.change_default != True)
@ -662,7 +668,7 @@ class many2many(_column):
col1 = '%s_id' % source_model._table
if not col2:
col2 = '%s_id' % dest_model._table
return (tbl, col1, col2)
return tbl, col1, col2
def _get_query_and_where_params(self, cr, model, ids, values, where_params):
""" Extracted from ``get`` to facilitate fine-tuning of the generated
@ -1298,7 +1304,7 @@ class sparse(function):
def __init__(self, serialization_field, **kwargs):
self.serialization_field = serialization_field
return super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', **kwargs)
super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', **kwargs)
@ -1554,7 +1560,7 @@ class column_info(object):
def __str__(self):
return '%s(%s, %s, %s, %s, %s)' % (
self.__name__, self.name, self.column,
self.__class__.__name__, self.name, self.column,
self.parent_model, self.parent_column, self.original_parent)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -58,7 +58,6 @@ import types
import psycopg2
from lxml import etree
import warnings
import fields
import openerp
@ -455,7 +454,7 @@ class browse_record(object):
new_data[field_name] = browse_null()
elif field_column._type in ('one2many', 'many2many') and len(result_line[field_name]):
new_data[field_name] = self._list_class([browse_record(self._cr, self._uid, id, self._table.pool.get(field_column._obj), self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process) for id in result_line[field_name]], self._context)
elif field_column._type in ('reference'):
elif field_column._type == 'reference':
if result_line[field_name]:
if isinstance(result_line[field_name], browse_record):
new_data[field_name] = result_line[field_name]
@ -866,10 +865,6 @@ class BaseModel(object):
parent_names = [parent_names]
else:
name = cls._name
# for res.parnter.address compatiblity, should be remove in v7
if 'res.partner.address' in parent_names:
parent_names.pop(parent_names.index('res.partner.address'))
parent_names.append('res.partner')
if not name:
raise TypeError('_name is mandatory in case of multiple inheritance')
@ -1019,45 +1014,50 @@ class BaseModel(object):
# Load manual fields
cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", ('state', 'ir.model.fields'))
if cr.fetchone():
# Check the query is already done for all modules of if we need to
# do it ourselves.
if self.pool.fields_by_model is not None:
manual_fields = self.pool.fields_by_model.get(self._name, [])
else:
cr.execute('SELECT * FROM ir_model_fields WHERE model=%s AND state=%s', (self._name, 'manual'))
for field in cr.dictfetchall():
if field['name'] in self._columns:
continue
attrs = {
'string': field['field_description'],
'required': bool(field['required']),
'readonly': bool(field['readonly']),
'domain': eval(field['domain']) if field['domain'] else None,
'size': field['size'],
'ondelete': field['on_delete'],
'translate': (field['translate']),
'manual': True,
#'select': int(field['select_level'])
}
manual_fields = cr.dictfetchall()
for field in manual_fields:
if field['name'] in self._columns:
continue
attrs = {
'string': field['field_description'],
'required': bool(field['required']),
'readonly': bool(field['readonly']),
'domain': eval(field['domain']) if field['domain'] else None,
'size': field['size'],
'ondelete': field['on_delete'],
'translate': (field['translate']),
'manual': True,
#'select': int(field['select_level'])
}
if field['serialization_field_id']:
cr.execute('SELECT name FROM ir_model_fields WHERE id=%s', (field['serialization_field_id'],))
attrs.update({'serialization_field': cr.fetchone()[0], 'type': field['ttype']})
if field['ttype'] in ['many2one', 'one2many', 'many2many']:
attrs.update({'relation': field['relation']})
self._columns[field['name']] = fields.sparse(**attrs)
elif field['ttype'] == 'selection':
self._columns[field['name']] = fields.selection(eval(field['selection']), **attrs)
elif field['ttype'] == 'reference':
self._columns[field['name']] = fields.reference(selection=eval(field['selection']), **attrs)
elif field['ttype'] == 'many2one':
self._columns[field['name']] = fields.many2one(field['relation'], **attrs)
elif field['ttype'] == 'one2many':
self._columns[field['name']] = fields.one2many(field['relation'], field['relation_field'], **attrs)
elif field['ttype'] == 'many2many':
_rel1 = field['relation'].replace('.', '_')
_rel2 = field['model'].replace('.', '_')
_rel_name = 'x_%s_%s_%s_rel' % (_rel1, _rel2, field['name'])
self._columns[field['name']] = fields.many2many(field['relation'], _rel_name, 'id1', 'id2', **attrs)
else:
self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
if field['serialization_field_id']:
cr.execute('SELECT name FROM ir_model_fields WHERE id=%s', (field['serialization_field_id'],))
attrs.update({'serialization_field': cr.fetchone()[0], 'type': field['ttype']})
if field['ttype'] in ['many2one', 'one2many', 'many2many']:
attrs.update({'relation': field['relation']})
self._columns[field['name']] = fields.sparse(**attrs)
elif field['ttype'] == 'selection':
self._columns[field['name']] = fields.selection(eval(field['selection']), **attrs)
elif field['ttype'] == 'reference':
self._columns[field['name']] = fields.reference(selection=eval(field['selection']), **attrs)
elif field['ttype'] == 'many2one':
self._columns[field['name']] = fields.many2one(field['relation'], **attrs)
elif field['ttype'] == 'one2many':
self._columns[field['name']] = fields.one2many(field['relation'], field['relation_field'], **attrs)
elif field['ttype'] == 'many2many':
_rel1 = field['relation'].replace('.', '_')
_rel2 = field['model'].replace('.', '_')
_rel_name = 'x_%s_%s_%s_rel' % (_rel1, _rel2, field['name'])
self._columns[field['name']] = fields.many2many(field['relation'], _rel_name, 'id1', 'id2', **attrs)
else:
self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
self._inherits_check()
self._inherits_reload()
if not self._sequence:
@ -1742,7 +1742,7 @@ class BaseModel(object):
views = {}
xml = "<form>"
for f in node:
if f.tag in ('field'):
if f.tag == 'field':
xml += etree.tostring(f, encoding="utf-8")
xml += "</form>"
new_xml = etree.fromstring(encode(xml))
@ -2011,7 +2011,7 @@ class BaseModel(object):
view = etree.Element('calendar', string=self._description)
etree.SubElement(view, 'field', self._rec_name_fallback(cr, user, context))
if (self._date_name not in self._columns):
if self._date_name not in self._columns:
date_found = False
for dt in ['date', 'date_start', 'x_date', 'x_date_start']:
if dt in self._columns:
@ -2032,7 +2032,7 @@ class BaseModel(object):
self._columns, 'date_delay'):
raise except_orm(
_('Invalid Object Architecture!'),
_("Insufficient fields to generate a Calendar View for %s, missing a date_stop or a date_delay" % (self._name)))
_("Insufficient fields to generate a Calendar View for %s, missing a date_stop or a date_delay" % self._name))
return view
@ -2412,7 +2412,7 @@ class BaseModel(object):
:rtype: tuple
:return: the :meth:`~.name_get` pair value for the newly-created record.
"""
rec_id = self.create(cr, uid, {self._rec_name: name}, context);
rec_id = self.create(cr, uid, {self._rec_name: name}, context)
return self.name_get(cr, uid, [rec_id], context)[0]
# private implementation of name_search, allows passing a dedicated user for the name_get part to
@ -2676,7 +2676,7 @@ class BaseModel(object):
groupby = group_by
for r in cr.dictfetchall():
for fld, val in r.items():
if val == None: r[fld] = False
if val is None: r[fld] = False
alldata[r['id']] = r
del r['id']
@ -2721,22 +2721,17 @@ class BaseModel(object):
return result
def _inherits_join_add(self, current_table, parent_model_name, query):
def _inherits_join_add(self, current_model, parent_model_name, query):
"""
Add missing table SELECT and JOIN clause to ``query`` for reaching the parent table (no duplicates)
:param current_table: current model object
:param current_model: current model object
:param parent_model_name: name of the parent model for which the clauses should be added
:param query: query object on which the JOIN should be added
"""
inherits_field = current_table._inherits[parent_model_name]
inherits_field = current_model._inherits[parent_model_name]
parent_model = self.pool.get(parent_model_name)
parent_table_name = parent_model._table
quoted_parent_table_name = '"%s"' % parent_table_name
if quoted_parent_table_name not in query.tables:
query.tables.append(quoted_parent_table_name)
query.where_clause.append('(%s.%s = %s.id)' % (current_table._table, inherits_field, parent_table_name))
parent_alias, parent_alias_statement = query.add_join((current_model._table, parent_model._table, inherits_field, 'id', inherits_field), implicit=True)
return parent_alias
def _inherits_join_calc(self, field, query):
"""
@ -2748,12 +2743,13 @@ class BaseModel(object):
:return: qualified name of field, to be used in SELECT clause
"""
current_table = self
parent_alias = '"%s"' % current_table._table
while field in current_table._inherit_fields and not field in current_table._columns:
parent_model_name = current_table._inherit_fields[field][0]
parent_table = self.pool.get(parent_model_name)
self._inherits_join_add(current_table, parent_model_name, query)
parent_alias = self._inherits_join_add(current_table, parent_model_name, query)
current_table = parent_table
return '"%s".%s' % (current_table._table, field)
return '%s."%s"' % (parent_alias, field)
def _parent_store_compute(self, cr):
if not self._parent_store:
@ -3102,7 +3098,7 @@ class BaseModel(object):
else:
default = self._defaults[k]
if (default is not None):
if default is not None:
ss = self._columns[k]._symbol_set
query = 'UPDATE "%s" SET "%s"=%s WHERE "%s" is NULL' % (self._table, k, ss[0], k)
cr.execute(query, (ss[1](default),))
@ -3181,7 +3177,7 @@ class BaseModel(object):
# and add constraints if needed
if isinstance(f, fields.many2one):
if not self.pool.get(f._obj):
raise except_orm('Programming Error', ('There is no reference available for %s') % (f._obj,))
raise except_orm('Programming Error', 'There is no reference available for %s' % (f._obj,))
dest_model = self.pool.get(f._obj)
ref = dest_model._table
# ir_actions is inherited so foreign key doesn't work on it
@ -3267,8 +3263,8 @@ class BaseModel(object):
elif not self._columns['parent_right'].select:
_logger.error('parent_right column on object %s must be indexed! Add select=1 to the field definition)',
self._table)
if self._columns[self._parent_name].ondelete != 'cascade':
_logger.error("The column %s on object %s must be set as ondelete='cascade'",
if self._columns[self._parent_name].ondelete not in ('cascade', 'restrict'):
_logger.error("The column %s on object %s must be set as ondelete='cascade' or 'restrict'",
self._parent_name, self._name)
cr.commit()
@ -3308,7 +3304,7 @@ class BaseModel(object):
# TODO the condition could use fields_get_keys().
if f._fields_id not in other._columns.keys():
if f._fields_id not in other._inherit_fields.keys():
raise except_orm('Programming Error', ("There is no reference field '%s' found for '%s'") % (f._fields_id, f._obj,))
raise except_orm('Programming Error', "There is no reference field '%s' found for '%s'" % (f._fields_id, f._obj,))
def _m2m_raise_or_create_relation(self, cr, f):
m2m_tbl, col1, col2 = f._sql_names(self)
@ -3316,7 +3312,7 @@ class BaseModel(object):
cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (m2m_tbl,))
if not cr.dictfetchall():
if not self.pool.get(f._obj):
raise except_orm('Programming Error', ('Many2Many destination model does not exist: `%s`') % (f._obj,))
raise except_orm('Programming Error', 'Many2Many destination model does not exist: `%s`' % (f._obj,))
dest_model = self.pool.get(f._obj)
ref = dest_model._table
cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL, "%s" INTEGER NOT NULL, UNIQUE("%s","%s"))' % (m2m_tbl, col1, col2, col1, col2))
@ -3450,8 +3446,8 @@ class BaseModel(object):
_logger.info('Missing many2one field definition for _inherits reference "%s" in "%s", using default one.', field_name, self._name)
self._columns[field_name] = fields.many2one(table, string="Automatically created field to link to parent %s" % table,
required=True, ondelete="cascade")
elif not self._columns[field_name].required or self._columns[field_name].ondelete.lower() != "cascade":
_logger.warning('Field definition for _inherits reference "%s" in "%s" must be marked as "required" with ondelete="cascade", forcing it.', field_name, self._name)
elif not self._columns[field_name].required or self._columns[field_name].ondelete.lower() not in ("cascade", "restrict"):
_logger.warning('Field definition for _inherits reference "%s" in "%s" must be marked as "required" with ondelete="cascade" or "restrict", forcing it to required + cascade.', field_name, self._name)
self._columns[field_name].required = True
self._columns[field_name].ondelete = "cascade"
@ -3490,7 +3486,7 @@ class BaseModel(object):
:param cr: database cursor
:param user: current user id
:param fields: list of fields
:param allfields: list of fields
:param context: context arguments, like lang, time zone
:return: dictionary of field dictionaries, each one describing a field of the business object
:raise AccessError: * if user has no create/write rights on the requested object
@ -3541,6 +3537,37 @@ class BaseModel(object):
return res
def check_field_access_rights(self, cr, user, operation, fields, context=None):
"""
Check the user access rights on the given fields. This raises Access
Denied if the user does not have the rights. Otherwise it returns the
fields (as is if the fields is not falsy, or the readable/writable
fields if fields is falsy).
"""
def p(field_name):
"""Predicate to test if the user has access to the given field name."""
# Ignore requested field if it doesn't exist. This is ugly but
# it seems to happen at least with 'name_alias' on res.partner.
if field_name not in self._all_columns:
return True
field = self._all_columns[field_name].column
if field.groups:
return self.user_has_groups(cr, user, groups=field.groups, context=context)
else:
return True
if not fields:
fields = filter(p, self._all_columns.keys())
else:
filtered_fields = filter(lambda a: not p(a), fields)
if filtered_fields:
_logger.warning('Access Denied by ACLs for operation: %s, uid: %s, model: %s, fields: %s', operation, user, self._name, ', '.join(filtered_fields))
raise except_orm(
_('Access Denied'),
_('The requested operation cannot be completed due to security restrictions. '
'Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \
(self._description, operation))
return fields
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
""" Read records with given ids with the given fields
@ -3566,8 +3593,7 @@ class BaseModel(object):
if not context:
context = {}
self.check_access_rights(cr, user, 'read')
if not fields:
fields = list(set(self._columns.keys() + self._inherit_fields.keys()))
fields = self.check_field_access_rights(cr, user, 'read', fields)
if isinstance(ids, (int, long)):
select = [ids]
else:
@ -3589,7 +3615,7 @@ class BaseModel(object):
context = {}
if not ids:
return []
if fields_to_read == None:
if fields_to_read is None:
fields_to_read = self._columns.keys()
# Construct a clause for the security rules.
@ -3633,15 +3659,16 @@ class BaseModel(object):
else:
res = map(lambda x: {'id': x}, ids)
for f in fields_pre:
if f == self.CONCURRENCY_CHECK_FIELD:
continue
if self._columns[f].translate:
ids = [x['id'] for x in res]
#TODO: optimize out of this loop
res_trans = self.pool.get('ir.translation')._get_ids(cr, user, self._name+','+f, 'model', context.get('lang', False) or 'en_US', ids)
for r in res:
r[f] = res_trans.get(r['id'], False) or r[f]
if context.get('lang'):
for f in fields_pre:
if f == self.CONCURRENCY_CHECK_FIELD:
continue
if self._columns[f].translate:
ids = [x['id'] for x in res]
#TODO: optimize out of this loop
res_trans = self.pool.get('ir.translation')._get_ids(cr, user, self._name+','+f, 'model', context['lang'], ids)
for r in res:
r[f] = res_trans.get(r['id'], False) or r[f]
for table in self._inherits:
col = self._inherits[table]
@ -4023,6 +4050,7 @@ class BaseModel(object):
"""
readonly = None
self.check_field_access_rights(cr, user, 'write', vals.keys())
for field in vals.copy():
fobj = None
if field in self._columns:
@ -4662,11 +4690,27 @@ class BaseModel(object):
:param query: the current query object
"""
def apply_rule(added_clause, added_params, added_tables, parent_model=None, child_object=None):
""" :param string parent_model: string of the parent model
:param model child_object: model object, base of the rule application
"""
if added_clause:
if parent_model and child_object:
# as inherited rules are being applied, we need to add the missing JOIN
# to reach the parent table (if it was not JOINed yet in the query)
child_object._inherits_join_add(child_object, parent_model, query)
parent_alias = child_object._inherits_join_add(child_object, parent_model, query)
# inherited rules are applied on the external table -> need to get the alias and replace
parent_table = self.pool.get(parent_model)._table
added_clause = [clause.replace('"%s"' % parent_table, '"%s"' % parent_alias) for clause in added_clause]
# change references to parent_table to parent_alias, because we now use the alias to refer to the table
new_tables = []
for table in added_tables:
# table is just a table name -> switch to the full alias
if table == '"%s"' % parent_table:
new_tables.append('"%s" as "%s"' % (parent_table, parent_alias))
# table is already a full statement -> replace reference to the table to its alias, is correct with the way aliases are generated
else:
new_tables.append(table.replace('"%s"' % parent_table, '"%s"' % parent_alias))
added_tables = new_tables
query.where_clause += added_clause
query.where_clause_params += added_params
for table in added_tables:
@ -4677,12 +4721,14 @@ class BaseModel(object):
# apply main rules on the object
rule_obj = self.pool.get('ir.rule')
apply_rule(*rule_obj.domain_get(cr, uid, self._name, mode, context=context))
rule_where_clause, rule_where_clause_params, rule_tables = rule_obj.domain_get(cr, uid, self._name, mode, context=context)
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables)
# apply ir.rules from the parents (through _inherits)
for inherited_model in self._inherits:
kwargs = dict(parent_model=inherited_model, child_object=self) #workaround for python2.5
apply_rule(*rule_obj.domain_get(cr, uid, inherited_model, mode, context=context), **kwargs)
rule_where_clause, rule_where_clause_params, rule_tables = rule_obj.domain_get(cr, uid, inherited_model, mode, context=context)
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables,
parent_model=inherited_model, child_object=self)
def _generate_m2o_order_by(self, order_field, query):
"""
@ -4717,17 +4763,16 @@ class BaseModel(object):
# extract the field names, to be able to qualify them and add desc/asc
m2o_order_list = []
for order_part in m2o_order.split(","):
m2o_order_list.append(order_part.strip().split(" ",1)[0].strip())
m2o_order_list.append(order_part.strip().split(" ", 1)[0].strip())
m2o_order = m2o_order_list
# Join the dest m2o table if it's not joined yet. We use [LEFT] OUTER join here
# as we don't want to exclude results that have NULL values for the m2o
src_table, src_field = qualified_field.replace('"','').split('.', 1)
query.join((src_table, dest_model._table, src_field, 'id'), outer=True)
qualify = lambda field: '"%s"."%s"' % (dest_model._table, field)
src_table, src_field = qualified_field.replace('"', '').split('.', 1)
dst_alias, dst_alias_statement = query.add_join((src_table, dest_model._table, src_field, 'id', src_field), implicit=False, outer=True)
qualify = lambda field: '"%s"."%s"' % (dst_alias, field)
return map(qualify, m2o_order) if isinstance(m2o_order, list) else qualify(m2o_order)
def _generate_order_by(self, order_spec, query):
"""
Attempt to consruct an appropriate ORDER BY clause based on order_spec, which must be
@ -4735,7 +4780,8 @@ class BaseModel(object):
:raise" except_orm in case order_spec is malformed
"""
order_by_clause = self._order
order_by_clause = ''
order_spec = order_spec or self._order
if order_spec:
order_by_elements = []
self._check_qorder(order_spec)
@ -4753,7 +4799,7 @@ class BaseModel(object):
elif order_column._type == 'many2one':
inner_clause = self._generate_m2o_order_by(order_field, query)
else:
continue # ignore non-readable or "non-joinable" fields
continue # ignore non-readable or "non-joinable" fields
elif order_field in self._inherit_fields:
parent_obj = self.pool.get(self._inherit_fields[order_field][3])
order_column = parent_obj._columns[order_field]
@ -4762,7 +4808,7 @@ class BaseModel(object):
elif order_column._type == 'many2one':
inner_clause = self._generate_m2o_order_by(order_field, query)
else:
continue # ignore non-readable or "non-joinable" fields
continue # ignore non-readable or "non-joinable" fields
if inner_clause:
if isinstance(inner_clause, list):
for clause in inner_clause:
@ -4825,7 +4871,7 @@ class BaseModel(object):
Copy given record's data with all its fields values
:param cr: database cursor
:param user: current user id
:param uid: current user id
:param id: id of the record to copy
:param default: field values to override in the original values of the copied record
:type default: dictionary
@ -4984,7 +5030,7 @@ class BaseModel(object):
"""
if type(ids) in (int, long):
ids = [ids]
query = 'SELECT id FROM "%s"' % (self._table)
query = 'SELECT id FROM "%s"' % self._table
cr.execute(query + "WHERE ID IN %s", (tuple(ids),))
return [x[0] for x in cr.fetchall()]

View File

@ -21,6 +21,7 @@
#.apidoc title: Query object
def _quote(to_quote):
if '"' not in to_quote:
return '"%s"' % to_quote
@ -67,15 +68,35 @@ class Query(object):
# LEFT JOIN "table_c" ON ("table_a"."table_a_col2" = "table_c"."table_c_col")
self.joins = joins or {}
def join(self, connection, outer=False):
"""Adds the JOIN specified in ``connection``.
def _get_table_aliases(self):
from openerp.osv.expression import get_alias_from_query
return [get_alias_from_query(from_statement)[1] for from_statement in self.tables]
:param connection: a tuple ``(lhs, table, lhs_col, col)``.
The join corresponds to the SQL equivalent of::
def _get_alias_mapping(self):
from openerp.osv.expression import get_alias_from_query
mapping = {}
for table in self.tables:
alias, statement = get_alias_from_query(table)
mapping[statement] = table
return mapping
(lhs.lhs_col = table.col)
def add_join(self, connection, implicit=True, outer=False):
""" Join a destination table to the current table.
:param outer: True if a LEFT OUTER JOIN should be used, if possible
:param implicit: False if the join is an explicit join. This allows
to fall back on the previous implementation of ``join`` before
OpenERP 7.0. It therefore adds the JOIN specified in ``connection``
If True, the join is done implicitely, by adding the table alias
in the from clause and the join condition in the where clause
of the query. Implicit joins do not handle outer parameter.
:param connection: a tuple ``(lhs, table, lhs_col, col, link)``.
The join corresponds to the SQL equivalent of::
(lhs.lhs_col = table.col)
Note that all connection elements are strings. Please refer to expression.py for more details about joins.
:param outer: True if a LEFT OUTER JOIN should be used, if possible
(no promotion to OUTER JOIN is supported in case the JOIN
was already present in the query, as for the moment
implicit INNER JOINs are only connected from NON-NULL
@ -83,39 +104,54 @@ class Query(object):
``_inherits`` or when a domain criterion explicitly
adds filtering)
"""
(lhs, table, lhs_col, col) = connection
lhs = _quote(lhs)
table = _quote(table)
assert lhs in self.tables, "Left-hand-side table must already be part of the query!"
if table in self.tables:
# already joined, must ignore (promotion to outer and multiple joins not supported yet)
pass
from openerp.osv.expression import generate_table_alias
(lhs, table, lhs_col, col, link) = connection
alias, alias_statement = generate_table_alias(lhs, [(table, link)])
if implicit:
if alias_statement not in self.tables:
self.tables.append(alias_statement)
condition = '("%s"."%s" = "%s"."%s")' % (lhs, lhs_col, alias, col)
self.where_clause.append(condition)
else:
# already joined
pass
return alias, alias_statement
else:
# add JOIN
self.tables.append(table)
self.joins.setdefault(lhs, []).append((table, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
return self
aliases = self._get_table_aliases()
assert lhs in aliases, "Left-hand-side table %s must already be part of the query tables %s!" % (lhs, str(self.tables))
if alias_statement in self.tables:
# already joined, must ignore (promotion to outer and multiple joins not supported yet)
pass
else:
# add JOIN
self.tables.append(alias_statement)
self.joins.setdefault(lhs, []).append((alias, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
return alias, alias_statement
def get_sql(self):
"""Returns (query_from, query_where, query_params)"""
""" Returns (query_from, query_where, query_params). """
from openerp.osv.expression import get_alias_from_query
query_from = ''
tables_to_process = list(self.tables)
alias_mapping = self._get_alias_mapping()
def add_joins_for_table(table, query_from):
for (dest_table, lhs_col, col, join) in self.joins.get(table,[]):
tables_to_process.remove(dest_table)
query_from += ' %s %s ON (%s."%s" = %s."%s")' % \
(join, dest_table, table, lhs_col, dest_table, col)
for (dest_table, lhs_col, col, join) in self.joins.get(table, []):
tables_to_process.remove(alias_mapping[dest_table])
query_from += ' %s %s ON ("%s"."%s" = "%s"."%s")' % \
(join, alias_mapping[dest_table], table, lhs_col, dest_table, col)
query_from = add_joins_for_table(dest_table, query_from)
return query_from
for table in tables_to_process:
query_from += table
if table in self.joins:
query_from = add_joins_for_table(table, query_from)
table_alias = get_alias_from_query(table)[1]
if table_alias in self.joins:
query_from = add_joins_for_table(table_alias, query_from)
query_from += ','
query_from = query_from[:-1] # drop last comma
return (query_from, " AND ".join(self.where_clause), self.where_clause_params)
query_from = query_from[:-1] # drop last comma
return query_from, " AND ".join(self.where_clause), self.where_clause_params
def __str__(self):
return '<osv.Query: "SELECT ... FROM %s WHERE %s" with params: %r>' % self.get_sql()

View File

@ -96,7 +96,7 @@ class report_custom(report_int):
else:
# Process group_by data first
key = []
if group_by != None and fields[group_by] != None:
if group_by is not None and fields[group_by] is not None:
if fields[group_by][0] in levels.keys():
key.append(fields[group_by][0])
for l in levels.keys():
@ -144,10 +144,11 @@ class report_custom(report_int):
parent_field = self.pool.get('ir.model.fields').read(cr, uid, [report['field_parent'][0]], ['model'])
model_name = self.pool.get('ir.model').read(cr, uid, [report['model_id'][0]], ['model'], context=context)[0]['model']
fct = {}
fct['id'] = lambda x : x
fct['gety'] = lambda x: x.split('-')[0]
fct['in'] = lambda x: x.split(',')
fct = {
'id': lambda x: x,
'gety': lambda x: x.split('-')[0],
'in': lambda x: x.split(',')
}
new_fields = []
new_cond = []
for f in fields:
@ -212,7 +213,7 @@ class report_custom(report_int):
new_res = []
prev = None
if groupby != None:
if groupby is not None:
res_dic = {}
for line in results:
if not line[groupby] and prev in res_dic:
@ -272,7 +273,7 @@ class report_custom(report_int):
res = self._create_bars(cr,uid, ids, report, fields, results2, context)
elif report['type']=='line':
res = self._create_lines(cr,uid, ids, report, fields, results2, context)
return (self.obj.get(), 'pdf')
return self.obj.get(), 'pdf'
def _create_tree(self, uid, ids, report, fields, level, results, context):
pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
@ -322,7 +323,7 @@ class report_custom(report_int):
col.attrib.update(para='yes',
tree='yes',
space=str(3*shift)+'mm')
if line[f] != None:
if line[f] is not None:
col.text = prefix+str(line[f]) or ''
else:
col.text = '/'
@ -350,15 +351,17 @@ class report_custom(report_int):
x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
process_date = {}
process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
process_date['M'] = lambda x : x.split('-')[1]
process_date['Y'] = lambda x : x.split('-')[0]
process_date = {
'D': lambda x: reduce(lambda xx, yy: xx + '-' + yy, x.split('-')[1:3]),
'M': lambda x: x.split('-')[1],
'Y': lambda x: x.split('-')[0]
}
order_date = {}
order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
order_date['M'] = lambda x : x
order_date['Y'] = lambda x : x
order_date = {
'D': lambda x: time.mktime((2005, int(x.split('-')[0]), int(x.split('-')[1]), 0, 0, 0, 0, 0, 0)),
'M': lambda x: x,
'Y': lambda x: x
}
abscissa = []
@ -381,7 +384,7 @@ class report_custom(report_int):
# plots are usually displayed year by year
# so we do so if the first field is a date
data_by_year = {}
if date_idx != None:
if date_idx is not None:
for r in results:
key = process_date['Y'](r[date_idx])
if key not in data_by_year:
@ -447,15 +450,17 @@ class report_custom(report_int):
can.show(80,380,'/16/H'+report['title'])
process_date = {}
process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
process_date['M'] = lambda x : x.split('-')[1]
process_date['Y'] = lambda x : x.split('-')[0]
process_date = {
'D': lambda x: reduce(lambda xx, yy: xx + '-' + yy, x.split('-')[1:3]),
'M': lambda x: x.split('-')[1],
'Y': lambda x: x.split('-')[0]
}
order_date = {}
order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
order_date['M'] = lambda x : x
order_date['Y'] = lambda x : x
order_date = {
'D': lambda x: time.mktime((2005, int(x.split('-')[0]), int(x.split('-')[1]), 0, 0, 0, 0, 0, 0)),
'M': lambda x: x,
'Y': lambda x: x
}
ar = area.T(size=(350,350),
x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
@ -480,7 +485,7 @@ class report_custom(report_int):
# plot are usually displayed year by year
# so we do so if the first field is a date
data_by_year = {}
if date_idx != None:
if date_idx is not None:
for r in results:
key = process_date['Y'](r[date_idx])
if key not in data_by_year:
@ -602,7 +607,7 @@ class report_custom(report_int):
node_line = etree.SubElement(lines, 'row')
for f in range(len(fields)):
col = etree.SubElement(node_line, 'col', tree='no')
if line[f] != None:
if line[f] is not None:
col.text = line[f] or ''
else:
col.text = '/'

View File

@ -52,7 +52,7 @@ def _1000_to_text(chiffre):
d2 = chiffre/100
if d2>0 and d:
return centaine[d2]+' '+d
elif d2>1 and not(d):
elif d2>1 and not d:
return centaine[d2]+'s'
else:
return centaine[d2] or d

View File

@ -55,13 +55,12 @@ class report_int(netsvc.Service):
def create(self, cr, uid, ids, datas, context=None):
return False
"""
Class to automatically build a document using the transformation process:
XML -> DATAS -> RML -> PDF
-> HTML
using a XSL:RML transformation
"""
class report_rml(report_int):
"""
Automatically builds a document using the transformation process:
XML -> DATAS -> RML -> PDF -> HTML
using a XSL:RML transformation
"""
def __init__(self, name, table, tmpl, xsl):
super(report_rml, self).__init__(name)
self.table = table
@ -85,7 +84,7 @@ class report_rml(report_int):
xml = tools.ustr(xml).encode('utf8')
report_type = datas.get('report_type', 'pdf')
if report_type == 'raw':
return (xml,report_type)
return xml, report_type
rml = self.create_rml(cr, xml, uid, context)
pool = pooler.get_pool(cr.dbname)
ir_actions_report_xml_obj = pool.get('ir.actions.report.xml')
@ -93,7 +92,7 @@ class report_rml(report_int):
self.title = report_xml_ids and ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name or 'OpenERP Report'
create_doc = self.generators[report_type]
pdf = create_doc(rml, title=self.title)
return (pdf, report_type)
return pdf, report_type
def create_xml(self, cr, uid, ids, datas, context=None):
if not context:
@ -244,10 +243,10 @@ class report_rml(report_int):
return obj.get()
def _get_path(self):
ret = []
ret.append(self.tmpl.replace(os.path.sep, '/').rsplit('/',1)[0]) # Same dir as the report rml
ret.append('addons')
ret.append(tools.config['root_path'])
return ret
return [
self.tmpl.replace(os.path.sep, '/').rsplit('/', 1)[0],
'addons',
tools.config['root_path']
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -65,7 +65,7 @@ class report_printscreen_list(report_int):
fields_order = self._parse_string(result['arch'])
rows = model.read(cr, uid, datas['ids'], result['fields'].keys() )
self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model._description)
return (self.obj.get(), 'pdf')
return self.obj.get(), 'pdf'
def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
@ -119,7 +119,7 @@ class report_printscreen_list(report_int):
precision=(('digits' in fields[f]) and fields[f]['digits'][1]) or 2
line[f]=round(line[f],precision)
col = etree.SubElement(node_line, 'col', tree='no')
if line[f] != None:
if line[f] is not None:
col.text = tools.ustr(line[f] or '')
else:
col.text = '/'

View File

@ -115,7 +115,7 @@ class report_printscreen_list(report_int):
rows_new += [elem for elem in rows if elem['id'] == id]
rows = rows_new
res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model_desc)
return (self.obj.get(), 'pdf')
return self.obj.get(), 'pdf'
def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
@ -147,7 +147,7 @@ class report_printscreen_list(report_int):
for i in range(0, len(fields_order)):
temp.append(0)
tsum.append(0)
ince = -1;
ince = -1
for f in fields_order:
s = 0
ince += 1
@ -230,14 +230,14 @@ class report_printscreen_list(report_int):
col.text = line[f] = 'Undefined'
col.set('tree', 'undefined')
if line[f] != None:
if line[f] is not None:
col.text = tools.ustr(line[f] or '')
if float_flag:
col.set('tree','float')
if line.get('__no_leaf') and temp[count] == 1 and f != 'id' and not line['__context']['group_by']:
tsum[count] = float(tsum[count]) + float(line[f])
if not line.get('__group') and f != 'id' and temp[count] == 1:
tsum[count] = float(tsum[count]) + float(line[f]);
tsum[count] = float(tsum[count]) + float(line[f])
else:
col.text = '/'
@ -245,7 +245,7 @@ class report_printscreen_list(report_int):
for f in range(0, len(fields_order)):
col = etree.SubElement(node_line, 'col', para='group', tree='no')
col.set('tree', 'float')
if tsum[f] != None:
if tsum[f] is not None:
if tsum[f] != 0.0:
digits = fields[fields_order[f]].get('digits', (16, 2))
prec = '%%.%sf' % (digits[1], )

View File

@ -106,7 +106,7 @@ class FlateDecode(object):
if predictor != 1:
columns = decodeParms["/Columns"]
# PNG prediction:
if predictor >= 10 and predictor <= 15:
if 10 <= predictor <= 15:
output = StringIO()
# PNG prediction can vary from row to row
rowlength = columns + 1
@ -191,7 +191,7 @@ class ASCII85Decode(object):
break
else:
c = ord(c) - 33
assert c >= 0 and c < 85
assert 0 <= c < 85
group += [ c ]
if len(group) >= 5:
b = group[0] * (85**4) + \

View File

@ -81,7 +81,7 @@ def readObject(stream, pdf):
return NumberObject.readFromStream(stream)
peek = stream.read(20)
stream.seek(-len(peek), 1) # reset to start
if re.match(r"(\d+)\s(\d+)\sR[^a-zA-Z]", peek) != None:
if re.match(r"(\d+)\s(\d+)\sR[^a-zA-Z]", peek) is not None:
return IndirectObject.readFromStream(stream, pdf)
else:
return NumberObject.readFromStream(stream)
@ -169,7 +169,7 @@ class IndirectObject(PdfObject):
def __eq__(self, other):
return (
other != None and
other is not None and
isinstance(other, IndirectObject) and
self.idnum == other.idnum and
self.generation == other.generation and
@ -489,7 +489,7 @@ class DictionaryObject(dict, PdfObject):
# return None if no metadata was found on the document root.
def getXmpMetadata(self):
metadata = self.get("/Metadata", None)
if metadata == None:
if metadata is None:
return None
metadata = metadata.getObject()
import xmp

View File

@ -53,13 +53,7 @@ import utils
from generic import *
from utils import readNonWhitespace, readUntilWhitespace, ConvertFunctionsToVirtualList
if version_info < ( 2, 4 ):
from sets import ImmutableSet as frozenset
if version_info < ( 2, 5 ):
from md5 import md5
else:
from hashlib import md5
from hashlib import md5
##
# This class supports writing PDF files out, given pages produced by another
@ -197,7 +191,7 @@ class PdfFileWriter(object):
# flag is on.
def encrypt(self, user_pwd, owner_pwd = None, use_128bit = True):
import time, random
if owner_pwd == None:
if owner_pwd is None:
owner_pwd = user_pwd
if use_128bit:
V = 2
@ -251,7 +245,7 @@ class PdfFileWriter(object):
# copying in a new copy of the page object.
for objIndex in xrange(len(self._objects)):
obj = self._objects[objIndex]
if isinstance(obj, PageObject) and obj.indirectRef != None:
if isinstance(obj, PageObject) and obj.indirectRef is not None:
data = obj.indirectRef
if not externalReferenceMap.has_key(data.pdf):
externalReferenceMap[data.pdf] = {}
@ -305,7 +299,7 @@ class PdfFileWriter(object):
trailer.writeToStream(stream, None)
# eof
stream.write("\nstartxref\n%s\n%%%%EOF\n" % (xref_location))
stream.write("\nstartxref\n%s\n%%%%EOF\n" % xref_location)
def _sweepIndirectReferences(self, externMap, data):
if isinstance(data, DictionaryObject):
@ -340,7 +334,7 @@ class PdfFileWriter(object):
return data
else:
newobj = externMap.get(data.pdf, {}).get(data.generation, {}).get(data.idnum, None)
if newobj == None:
if newobj is None:
newobj = data.pdf.getObject(data)
self._objects.append(None) # placeholder
idnum = len(self._objects)
@ -426,7 +420,7 @@ class PdfFileReader(object):
# Stability: Added in v1.0, will exist for all v1.x releases.
# @return Returns an integer.
def getNumPages(self):
if self.flattenedPages == None:
if self.flattenedPages is None:
self._flatten()
return len(self.flattenedPages)
@ -445,7 +439,7 @@ class PdfFileReader(object):
def getPage(self, pageNumber):
## ensure that we're not trying to access an encrypted PDF
#assert not self.trailer.has_key("/Encrypt")
if self.flattenedPages == None:
if self.flattenedPages is None:
self._flatten()
return self.flattenedPages[pageNumber]
@ -465,7 +459,7 @@ class PdfFileReader(object):
# @return Returns a dict which maps names to {@link #Destination
# destinations}.
def getNamedDestinations(self, tree=None, retval=None):
if retval == None:
if retval is None:
retval = {}
catalog = self.trailer["/Root"]
@ -477,7 +471,7 @@ class PdfFileReader(object):
if names.has_key("/Dests"):
tree = names['/Dests']
if tree == None:
if tree is None:
return retval
if tree.has_key("/Kids"):
@ -493,7 +487,7 @@ class PdfFileReader(object):
if isinstance(val, DictionaryObject) and val.has_key('/D'):
val = val['/D']
dest = self._buildDestination(key, val)
if dest != None:
if dest is not None:
retval[key] = dest
return retval
@ -511,7 +505,7 @@ class PdfFileReader(object):
# Stability: Added in v1.10, will exist for all future v1.x releases.
# @return Returns a nested list of {@link #Destination destinations}.
def getOutlines(self, node=None, outlines=None):
if outlines == None:
if outlines is None:
outlines = []
catalog = self.trailer["/Root"]
@ -522,7 +516,7 @@ class PdfFileReader(object):
node = lines["/First"]
self._namedDests = self.getNamedDestinations()
if node == None:
if node is None:
return outlines
# see if there are any more outlines
@ -588,9 +582,9 @@ class PdfFileReader(object):
NameObject("/Resources"), NameObject("/MediaBox"),
NameObject("/CropBox"), NameObject("/Rotate")
)
if inherit == None:
if inherit is None:
inherit = dict()
if pages == None:
if pages is None:
self.flattenedPages = []
catalog = self.trailer["/Root"].getObject()
pages = catalog["/Pages"].getObject()
@ -616,7 +610,7 @@ class PdfFileReader(object):
def getObject(self, indirectReference):
retval = self.resolvedObjects.get(indirectReference.generation, {}).get(indirectReference.idnum, None)
if retval != None:
if retval is not None:
return retval
if indirectReference.generation == 0 and \
self.xref_objStm.has_key(indirectReference.idnum):
@ -844,7 +838,6 @@ class PdfFileReader(object):
else:
# no xref table found at specified location
assert False
break
def _pairs(self, array):
i = 0
@ -959,10 +952,10 @@ def getRectangle(self, name, defaults):
retval = self.get(name)
if isinstance(retval, RectangleObject):
return retval
if retval == None:
if retval is None:
for d in defaults:
retval = self.get(d)
if retval != None:
if retval is not None:
break
if isinstance(retval, IndirectObject):
retval = self.pdf.getObject(retval)

View File

@ -78,7 +78,7 @@ class ConvertFunctionsToVirtualList(object):
len_self = len(self)
if index < 0:
# support negative indexes
index = len_self + index
index += len_self
if index < 0 or index >= len_self:
raise IndexError, "sequence index out of range"
return self.getFunction(index)

View File

@ -66,7 +66,7 @@ class XmpInformation(PdfObject):
for desc in self.rdfRoot.getElementsByTagNameNS(RDF_NAMESPACE, "Description"):
if desc.getAttributeNS(RDF_NAMESPACE, "about") == aboutUri:
attr = desc.getAttributeNodeNS(namespace, name)
if attr != None:
if attr is not None:
yield attr
for element in desc.getElementsByTagNameNS(namespace, name):
yield element
@ -187,7 +187,7 @@ class XmpInformation(PdfObject):
else:
value = self._getText(element)
break
if value != None:
if value is not None:
value = converter(value)
ns_cache = self.cache.setdefault(namespace, {})
ns_cache[name] = value
@ -353,5 +353,5 @@ class XmpInformation(PdfObject):
custom_properties = property(custom_properties)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -391,7 +391,7 @@ class _rml_doc(object):
list_story.append(story_text)
del f
if template.data:
tag = '''<img src = '%s' width=80 height=72/>'''%(template.data)
tag = '''<img src = '%s' width=80 height=72/>'''% template.data
else:
tag = ''
self.result +='''

View File

@ -28,14 +28,14 @@ regex_t = re.compile('\(([0-9\.]*),([0-9\.]*),([0-9\.]*)\)')
regex_h = re.compile('#([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])')
def get(col_str):
if col_str == None:
if col_str is None:
col_str = ''
global allcols
if col_str in allcols.keys():
return allcols[col_str]
res = regex_t.search(col_str, 0)
if res:
return (float(res.group(1)),float(res.group(2)),float(res.group(3)))
return float(res.group(1)), float(res.group(2)), float(res.group(3))
res = regex_h.search(col_str, 0)
if res:
return tuple([ float(int(res.group(i),16))/255 for i in range(1,4)])

View File

@ -96,7 +96,7 @@ class NumberedCanvas(canvas.Canvas):
key=self._pageCounter
if not self.pages.get(key,False):
while not self.pages.get(key,False):
key = key + 1
key += 1
self.setFont("Helvetica", 8)
self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40),
" %(this)i / %(total)i" % {
@ -123,7 +123,7 @@ class PageCount(platypus.Flowable):
self.story_count = story_count
def draw(self):
self.canv.beginForm("pageCount%d" % (self.story_count))
self.canv.beginForm("pageCount%d" % self.story_count)
self.canv.setFont("Helvetica", utils.unit_get(str(8)))
self.canv.drawString(0, 0, str(self.canv.getPageNumber()))
self.canv.endForm()
@ -268,18 +268,18 @@ class _rml_doc(object):
if fontname not in pdfmetrics._fonts:
pdfmetrics.registerFont(TTFont(fontname, filename))
if (mode == 'all'):
if mode == 'all':
addMapping(face, 0, 0, fontname) #normal
addMapping(face, 0, 1, fontname) #italic
addMapping(face, 1, 0, fontname) #bold
addMapping(face, 1, 1, fontname) #italic and bold
elif (mode== 'normal') or (mode == 'regular'):
addMapping(face, 0, 0, fontname) #normal
elif (mode == 'italic'):
elif mode == 'italic':
addMapping(face, 0, 1, fontname) #italic
elif (mode == 'bold'):
elif mode == 'bold':
addMapping(face, 1, 0, fontname) #bold
elif (mode == 'bolditalic'):
elif mode == 'bolditalic':
addMapping(face, 1, 1, fontname) #italic and bold
def _textual_image(self, node):
@ -602,7 +602,7 @@ class _rml_Illustration(platypus.flowables.Flowable):
self.height = utils.unit_get(node.get('height'))
self.self2 = self2
def wrap(self, *args):
return (self.width, self.height)
return self.width, self.height
def draw(self):
drw = _rml_draw(self.localcontext ,self.node,self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title)
drw.render(self.canv, None)
@ -890,7 +890,7 @@ class TinyDocTemplate(platypus.BaseDocTemplate):
self.canv._storyCount = 0
def ___handle_pageBegin(self):
self.page = self.page + 1
self.page += 1
self.pageTemplate.beforeDrawPage(self.canv,self)
self.pageTemplate.checkPageSize(self.canv,self)
self.pageTemplate.onPage(self.canv,self)

View File

@ -29,7 +29,8 @@ import utils
Font_size= 10.0
def verbose(text):
sys.stderr.write(text+"\n");
sys.stderr.write(text+"\n")
class textbox(object):
"""A box containing plain text.
@ -107,11 +108,11 @@ class textbox(object):
def haplines(self,arr,offset,cc= ''):
""" Horizontaly append lines
"""
while (len(self.lines) < len(arr)):
while len(self.lines) < len(arr):
self.lines.append("")
for i in range(len(self.lines)):
while (len(self.lines[i]) < offset):
while len(self.lines[i]) < offset:
self.lines[i] += " "
for i in range(len(arr)):
self.lines[i] += cc +arr[i]
@ -220,7 +221,7 @@ class _flowable(object):
def rec_render(self,node):
""" Recursive render: fill outarr with text of current node
"""
if node.tag != None:
if node.tag is not None:
if node.tag in self._tags:
self._tags[node.tag](node)
else:
@ -255,12 +256,10 @@ class _rml_tmpl_frame(_rml_tmpl_tag):
self.posx = posx
def tag_start(self):
return "frame start"
return '<table border="0" width="%d"><tr><td width="%d">&nbsp;</td><td>' % (self.width+self.posx,self.posx)
def tag_end(self):
return True
def tag_stop(self):
return "frame stop"
return '</td></tr></table><br/>'
def tag_mergeable(self):
return False
@ -282,24 +281,7 @@ class _rml_tmpl_draw_string(_rml_tmpl_tag):
def tag_start(self):
return "draw string \"%s\" @(%d,%d)..\n" %("txt",self.posx,self.posy)
self.pos.sort()
res = '\\table ...'
posx = 0
i = 0
for (x,y,align,txt, style, fs) in self.pos:
if align=="left":
pos2 = len(txt)*fs
res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
posx = x+pos2
if align=="right":
res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
posx = x
if align=="center":
res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
posx = 2*x-posx
i+=1
res+='\\table end'
return res
def merge(self, ds):
self.pos+=ds.pos
@ -316,10 +298,6 @@ class _rml_tmpl_draw_lines(_rml_tmpl_tag):
def tag_start(self):
return "draw lines..\n"
if self.ok:
return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
else:
return ''
class _rml_stylesheet(object):
def __init__(self, stylesheet, doc):
@ -456,11 +434,6 @@ class _rml_template(object):
def end(self):
return "template end\n"
result = ''
while not self.loop:
result += self.frame_start()
result += self.frame_stop()
return result
class _rml_doc(object):
def __init__(self, node, localcontext=None, images=None, path='.', title=None):

View File

@ -441,7 +441,7 @@ class report_sxw(report_rml, preprocess.report):
raise NotImplementedError(_('Unknown report type: %s') % report_type)
fnct_ret = fnct(cr, uid, ids, data, report_xml, context)
if not fnct_ret:
return (False,False)
return False, False
return fnct_ret
def create_source_odt(self, cr, uid, ids, data, report_xml, context=None):
@ -531,7 +531,7 @@ class report_sxw(report_rml, preprocess.report):
logo = base64.decodestring(rml_parser.logo)
create_doc = self.generators[report_xml.report_type]
pdf = create_doc(etree.tostring(processed_rml),rml_parser.localcontext,logo,title.encode('utf8'))
return (pdf, report_xml.report_type)
return pdf, report_xml.report_type
def create_single_odt(self, cr, uid, ids, data, report_xml, context=None):
if not context:
@ -644,7 +644,7 @@ class report_sxw(report_rml, preprocess.report):
sxw_z.close()
final_op = sxw_io.getvalue()
sxw_io.close()
return (final_op, mime_type)
return final_op, mime_type
def create_single_html2html(self, cr, uid, ids, data, report_xml, context=None):
if not context:
@ -666,7 +666,7 @@ class report_sxw(report_rml, preprocess.report):
create_doc = self.generators['html2html']
html = etree.tostring(create_doc(html_dom, html_parser.localcontext))
return (html.replace('&amp;','&').replace('&lt;', '<').replace('&gt;', '>').replace('</br>',''), report_type)
return html.replace('&amp;','&').replace('&lt;', '<').replace('&gt;', '>').replace('</br>',''), report_type
def create_single_mako2html(self, cr, uid, ids, data, report_xml, context=None):
mako_html = report_xml.report_rml_content
@ -675,7 +675,7 @@ class report_sxw(report_rml, preprocess.report):
html_parser.set_context(objs, data, ids, 'html')
create_doc = self.generators['makohtml2html']
html = create_doc(mako_html,html_parser.localcontext)
return (html,'html')
return html,'html'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -139,7 +139,7 @@ class OpenERPAuthProvider(AuthProvider):
uid = security.login(db,user,passwd)
if uid is False:
return False
return (user, passwd, db, uid)
return user, passwd, db, uid
except Exception,e:
_logger.debug("Fail auth: %s" % e )
return False

View File

@ -181,13 +181,13 @@ class db(netsvc.ExportService):
def exp_get_progress(self, id):
if self.actions[id]['thread'].isAlive():
# return openerp.modules.init_progress[db_name]
return (min(self.actions[id].get('progress', 0),0.95), [])
return min(self.actions[id].get('progress', 0),0.95), []
else:
clean = self.actions[id]['clean']
if clean:
users = self.actions[id]['users']
self.actions.pop(id)
return (1.0, users)
return 1.0, users
else:
e = self.actions[id]['exception'] # TODO this seems wrong: actions[id]['traceback'] is set, but not 'exception'.
self.actions.pop(id)
@ -552,7 +552,7 @@ GNU Public Licence.
if os.name == 'posix':
if platform.system() == 'Linux':
lsbinfo = os.popen('lsb_release -a').read()
environment += '%s'%(lsbinfo)
environment += '%s'% lsbinfo
else:
environment += 'Your System is not lsb compliant\n'
environment += 'Operating System Release : %s\n' \

View File

@ -226,9 +226,9 @@ class HttpOptions:
Sometimes, like in special DAV folders, the OPTIONS may contain
extra keywords, perhaps also dependant on the request url.
@param the options already. MUST be copied before being altered
@return the updated options.
:param opts: MUST be copied before being altered
:returns: the updated options.
"""
return opts

View File

@ -302,10 +302,10 @@ class Worker(object):
self.multi.pipe_ping(self.watchdog_pipe)
self.sleep()
self.process_work()
_logger.info("Worker (%s) exiting...",self.pid)
_logger.info("Worker (%s) exiting. request_count: %s.", self.pid, self.request_count)
self.stop()
except Exception,e:
_logger.exception("Worker (%s) Exception occured, exiting..."%self.pid)
_logger.exception("Worker (%s) Exception occured, exiting..." % self.pid)
# should we use 3 to abort everything ?
sys.exit(1)

View File

@ -74,8 +74,8 @@ import threading
from inspect import currentframe
import re
re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$');
re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$')
re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$')
sql_counter = 0
@ -226,11 +226,11 @@ class Cursor(object):
params = params or None
res = self._obj.execute(query, params)
except psycopg2.ProgrammingError, pe:
if (self._default_log_exceptions if log_exceptions is None else log_exceptions):
if self._default_log_exceptions if log_exceptions is None else log_exceptions:
_logger.error("Programming error: %s, in query %s", pe, query)
raise
except Exception:
if (self._default_log_exceptions if log_exceptions is None else log_exceptions):
if self._default_log_exceptions if log_exceptions is None else log_exceptions:
_logger.exception("bad query: %s", self._obj.query or query)
raise
@ -357,11 +357,6 @@ class Cursor(object):
def __getattr__(self, name):
return getattr(self._obj, name)
""" Set the mode of postgres operations for all cursors
"""
"""Obtain the mode of postgres operations for all cursors
"""
class PsycoConnection(psycopg2.extensions.connection):
pass
@ -521,8 +516,8 @@ def db_connect(db_name):
return Connection(_Pool, db_name)
def close_db(db_name):
global _Pool
""" You might want to call openerp.modules.registry.RegistryManager.delete(db_name) along this function."""
global _Pool
if _Pool:
_Pool.close_all(dsn(db_name))
ct = currentThread()

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010 OpenERP S.A. http://www.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/>.
#
##############################################################################
from test_osv import *
from test_translate import *
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -8,9 +8,11 @@ Tests can be explicitely added to the `fast_suite` or `checks` lists or not.
See the :ref:`test-framework` section in the :ref:`features` list.
"""
from . import test_expression, test_mail, test_ir_sequence, test_orm,\
from . import test_acl
from . import test_expression, test_mail, test_ir_sequence, test_orm, \
test_fields, test_basecase, \
test_view_validation, test_uninstall, test_misc, test_db_cursor
test_view_validation, test_uninstall, test_misc, test_db_cursor, \
test_osv, test_translate
from . import test_ir_filters
fast_suite = [
@ -19,6 +21,7 @@ fast_suite = [
]
checks = [
test_acl,
test_expression,
test_mail,
test_db_cursor,
@ -27,6 +30,8 @@ checks = [
test_basecase,
test_view_validation,
test_misc,
test_osv,
test_translate,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,9 @@
import unittest2
from lxml import etree
import openerp
from openerp.tools.misc import mute_logger
import common
# test group that demo user should not have
@ -55,6 +58,7 @@ class TestACL(common.TransactionCase):
self.tech_group.write({'users': [(3, self.demo_uid)]})
self.res_currency._columns['rate'].groups = False
@mute_logger('openerp.osv.orm')
def test_field_crud_restriction(self):
"Read/Write RPC access to restricted field should be forbidden"
# Verify the test environment first
@ -65,12 +69,10 @@ class TestACL(common.TransactionCase):
# Now restrict access to the field and check it's forbidden
self.res_partner._columns['bank_ids'].groups = GROUP_TECHNICAL_FEATURES
# FIXME TODO: enable next tests when access rights checks per field are implemented
# from openerp.osv.orm import except_orm
# with self.assertRaises(except_orm):
# self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])
# with self.assertRaises(except_orm):
# self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})
with self.assertRaises(openerp.osv.orm.except_orm):
self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])
with self.assertRaises(openerp.osv.orm.except_orm):
self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})
# Add the restricted group, and check that it works again
self.tech_group.write({'users': [(4, self.demo_uid)]})
@ -86,4 +88,4 @@ class TestACL(common.TransactionCase):
if __name__ == '__main__':
unittest2.main()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -2,11 +2,12 @@ import unittest2
import openerp
class test_domain_normalization(unittest2.TestCase):
def test_normalize_domain(self):
expression = openerp.osv.expression
norm_domain = domain = ['&',(1,'=',1),('a','=','b')]
assert norm_domain == expression.normalize(domain), "Normalized domains should be left untouched"
domain = [('x','in',['y','z']),('a.v','=','e'),'|','|',('a','=','b'),'!',('c','>','d'),('e','!=','f'),('g','=','h')]
norm_domain = ['&','&','&'] + domain
assert norm_domain == expression.normalize(domain), "Non-normalized domains should be properly normalized"
norm_domain = domain = ['&', (1, '=', 1), ('a', '=', 'b')]
assert norm_domain == expression.normalize_domain(domain), "Normalized domains should be left untouched"
domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')]
norm_domain = ['&', '&', '&'] + domain
assert norm_domain == expression.normalize_domain(domain), "Non-normalized domains should be properly normalized"

View File

@ -53,31 +53,46 @@ class TestRelatedField(common.TransactionCase):
def test_1_single_related(self):
""" test a related field with a single indirection like fields.related('foo') """
# add a related field test_related_company_id on res.partner
# and simulate a _inherits_reload() to populate _all_columns.
old_columns = self.partner._columns
old_all_columns = self.partner._all_columns
self.partner._columns = dict(old_columns)
self.partner._all_columns = dict(old_all_columns)
self.partner._columns.update({
'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
})
self.partner._all_columns.update({
'single_related_company_id': fields.column_info('single_related_company_id', self.partner._columns['single_related_company_id'], None, None, None)
})
self.do_test_company_field('single_related_company_id')
# restore res.partner fields
self.partner._columns = old_columns
self.partner._all_columns = old_all_columns
def test_2_related_related(self):
""" test a related field referring to a related field """
# add a related field on a related field on res.partner
# and simulate a _inherits_reload() to populate _all_columns.
old_columns = self.partner._columns
old_all_columns = self.partner._all_columns
self.partner._columns = dict(old_columns)
self.partner._all_columns = dict(old_all_columns)
self.partner._columns.update({
'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
'related_related_company_id': fields.related('single_related_company_id', type='many2one', obj='res.company'),
})
self.partner._all_columns.update({
'single_related_company_id': fields.column_info('single_related_company_id', self.partner._columns['single_related_company_id'], None, None, None),
'related_related_company_id': fields.column_info('related_related_company_id', self.partner._columns['related_related_company_id'], None, None, None)
})
self.do_test_company_field('related_related_company_id')
# restore res.partner fields
self.partner._columns = old_columns
self.partner._all_columns = old_all_columns
def test_3_read_write(self):
""" write on a related field """

View File

@ -182,7 +182,7 @@ class TestO2MSerialization(common.TransactionCase):
def test_no_command(self):
" empty list of commands yields an empty list of records "
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', [])
self.cr, UID, 'child_ids', [])
self.assertEqual(results, [])
@ -190,7 +190,7 @@ class TestO2MSerialization(common.TransactionCase):
" returns the VALUES dict as-is "
values = [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}]
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', map(CREATE, values))
self.cr, UID, 'child_ids', map(CREATE, values))
self.assertEqual(results, values)
@ -204,7 +204,7 @@ class TestO2MSerialization(common.TransactionCase):
commands = map(LINK_TO, ids)
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', commands, ['name'])
self.cr, UID, 'child_ids', commands, ['name'])
self.assertEqual(sorted_by_id(results), sorted_by_id([
{'id': ids[0], 'name': 'foo'},
@ -221,7 +221,7 @@ class TestO2MSerialization(common.TransactionCase):
]
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', ids, ['name'])
self.cr, UID, 'child_ids', ids, ['name'])
self.assertEqual(sorted_by_id(results), sorted_by_id([
{'id': ids[0], 'name': 'foo'},
@ -236,7 +236,7 @@ class TestO2MSerialization(common.TransactionCase):
id_baz = self.partner.create(self.cr, UID, {'name': 'baz', 'city': 'tag'})
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', [
self.cr, UID, 'child_ids', [
LINK_TO(id_foo),
UPDATE(id_bar, {'name': 'qux', 'city': 'tagtag'}),
UPDATE(id_baz, {'name': 'quux'})
@ -258,7 +258,7 @@ class TestO2MSerialization(common.TransactionCase):
commands = [DELETE(ids[0]), DELETE(ids[1]), DELETE(ids[2])]
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', commands, ['name'])
self.cr, UID, 'child_ids', commands, ['name'])
self.assertEqual(results, [])
@ -269,7 +269,7 @@ class TestO2MSerialization(common.TransactionCase):
]
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', [
self.cr, UID, 'child_ids', [
CREATE({'name': 'foo'}),
UPDATE(ids[0], {'name': 'bar'}),
LINK_TO(ids[1]),
@ -300,7 +300,7 @@ class TestO2MSerialization(common.TransactionCase):
commands = map(lambda id: (4, id), ids)
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', commands, ['name'])
self.cr, UID, 'child_ids', commands, ['name'])
self.assertEqual(sorted_by_id(results), sorted_by_id([
{'id': ids[0], 'name': 'foo'},
@ -311,7 +311,7 @@ class TestO2MSerialization(common.TransactionCase):
def test_singleton_commands(self):
"DELETE_ALL can appear as a singleton"
results = self.partner.resolve_2many_commands(
self.cr, UID, 'address', [DELETE_ALL()], ['name'])
self.cr, UID, 'child_ids', [DELETE_ALL()], ['name'])
self.assertEqual(results, [])

View File

@ -22,45 +22,45 @@
import unittest
from openerp.osv.query import Query
class QueryTestCase(unittest.TestCase):
def test_basic_query(self):
query = Query()
query.tables.extend(['"product_product"','"product_template"'])
query.tables.extend(['"product_product"', '"product_template"'])
query.where_clause.append("product_product.template_id = product_template.id")
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
query.join(("product_product", "res_user", "user_id", "id"), outer=True) # outer join
query.add_join(("product_template", "product_category", "categ_id", "id", "categ_id"), implicit=False, outer=False) # add normal join
query.add_join(("product_product", "res_user", "user_id", "id", "user_id"), implicit=False, outer=True) # outer join
self.assertEquals(query.get_sql()[0].strip(),
""""product_product" LEFT JOIN "res_user" ON ("product_product"."user_id" = "res_user"."id"),"product_template" JOIN "product_category" ON ("product_template"."categ_id" = "product_category"."id") """.strip())
""""product_product" LEFT JOIN "res_user" as "product_product__user_id" ON ("product_product"."user_id" = "product_product__user_id"."id"),"product_template" JOIN "product_category" as "product_template__categ_id" ON ("product_template"."categ_id" = "product_template__categ_id"."id") """.strip())
self.assertEquals(query.get_sql()[1].strip(), """product_product.template_id = product_template.id""".strip())
def test_query_chained_explicit_joins(self):
query = Query()
query.tables.extend(['"product_product"','"product_template"'])
query.tables.extend(['"product_product"', '"product_template"'])
query.where_clause.append("product_product.template_id = product_template.id")
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
query.join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
query.add_join(("product_template", "product_category", "categ_id", "id", "categ_id"), implicit=False, outer=False) # add normal join
query.add_join(("product_template__categ_id", "res_user", "user_id", "id", "user_id"), implicit=False, outer=True) # CHAINED outer join
self.assertEquals(query.get_sql()[0].strip(),
""""product_product","product_template" JOIN "product_category" ON ("product_template"."categ_id" = "product_category"."id") LEFT JOIN "res_user" ON ("product_category"."user_id" = "res_user"."id")""".strip())
""""product_product","product_template" JOIN "product_category" as "product_template__categ_id" ON ("product_template"."categ_id" = "product_template__categ_id"."id") LEFT JOIN "res_user" as "product_template__categ_id__user_id" ON ("product_template__categ_id"."user_id" = "product_template__categ_id__user_id"."id")""".strip())
self.assertEquals(query.get_sql()[1].strip(), """product_product.template_id = product_template.id""".strip())
def test_mixed_query_chained_explicit_implicit_joins(self):
query = Query()
query.tables.extend(['"product_product"','"product_template"'])
query.tables.extend(['"product_product"', '"product_template"'])
query.where_clause.append("product_product.template_id = product_template.id")
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
query.join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
query.add_join(("product_template", "product_category", "categ_id", "id", "categ_id"), implicit=False, outer=False) # add normal join
query.add_join(("product_template__categ_id", "res_user", "user_id", "id", "user_id"), implicit=False, outer=True) # CHAINED outer join
query.tables.append('"account.account"')
query.where_clause.append("product_category.expense_account_id = account_account.id") # additional implicit join
query.where_clause.append("product_category.expense_account_id = account_account.id") # additional implicit join
self.assertEquals(query.get_sql()[0].strip(),
""""product_product","product_template" JOIN "product_category" ON ("product_template"."categ_id" = "product_category"."id") LEFT JOIN "res_user" ON ("product_category"."user_id" = "res_user"."id"),"account.account" """.strip())
""""product_product","product_template" JOIN "product_category" as "product_template__categ_id" ON ("product_template"."categ_id" = "product_template__categ_id"."id") LEFT JOIN "res_user" as "product_template__categ_id__user_id" ON ("product_template__categ_id"."user_id" = "product_template__categ_id__user_id"."id"),"account.account" """.strip())
self.assertEquals(query.get_sql()[1].strip(), """product_product.template_id = product_template.id AND product_category.expense_account_id = account_account.id""".strip())
def test_raise_missing_lhs(self):
query = Query()
query.tables.append('"product_product"')
self.assertRaises(AssertionError, query.join, ("product_template", "product_category", "categ_id", "id"), outer=False)
self.assertRaises(AssertionError, query.add_join, ("product_template", "product_category", "categ_id", "id", "categ_id"), implicit=False, outer=False)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -57,9 +57,9 @@ def _convert_nnn_fr(val):
if rem > 0:
word = to_19_fr[rem] + ' Cent'
if mod > 0:
word = word + ' '
word += ' '
if mod > 0:
word = word + _convert_nn_fr(mod)
word += _convert_nn_fr(mod)
return word
def french_number(val):
@ -125,9 +125,9 @@ def _convert_nnn_nl(val):
if rem > 0:
word = to_19_nl[rem] + ' Honderd'
if mod > 0:
word = word + ' '
word += ' '
if mod > 0:
word = word + _convert_nn_nl(mod)
word += _convert_nn_nl(mod)
return word
def dutch_number(val):

View File

@ -60,9 +60,9 @@ def _convert_nnn(val):
if rem > 0:
word = to_19[rem] + ' Hundred'
if mod > 0:
word = word + ' '
word += ' '
if mod > 0:
word = word + _convert_nn(mod)
word += _convert_nn(mod)
return word
def english_number(val):

View File

@ -352,7 +352,7 @@ class configmanager(object):
# Check if the config file exists (-c used, but not -s)
die(not opt.save and opt.config and not os.path.exists(opt.config),
"The config file '%s' selected with -c/--config doesn't exist, "\
"use -s/--save if you want to generate it"%(opt.config))
"use -s/--save if you want to generate it"% opt.config)
# place/search the config file on Win32 near the server installation
# (../etc from the server)

View File

@ -662,7 +662,7 @@ form: module.record_id""" % (xml_id,)
if rec.get('action') and pid:
action = "ir.actions.%s,%d" % (a_type, a_id)
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
return ('ir.ui.menu', pid)
return 'ir.ui.menu', pid
def _assert_equals(self, f1, f2, prec=4):
return not round(f1 - f2, prec)

View File

@ -45,7 +45,7 @@ def frame_codeinfo(fframe, back=0):
try:
if not fframe:
return ("<unknown>", '')
return "<unknown>", ''
for i in range(back):
fframe = fframe.f_back
try:
@ -53,8 +53,8 @@ def frame_codeinfo(fframe, back=0):
except TypeError:
fname = '<builtin>'
lineno = fframe.f_lineno or ''
return (fname, lineno)
return fname, lineno
except Exception:
return ("<unknown>", '')
return "<unknown>", ''
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -51,7 +51,7 @@ class graph(object):
for link in self.links:
self.edge_wt[link] = self.result[link[1]]['x'] - self.result[link[0]]['x']
tot_node = self.partial_order.__len__()
tot_node = len(self.partial_order)
#do until all the nodes in the component are searched
while self.tight_tree()<tot_node:
list_node = []
@ -68,9 +68,9 @@ class graph(object):
slack = 100
for edge in list_edge:
if ((self.reachable_nodes.__contains__(edge[0]) and edge[1] not in self.reachable_nodes) or
(self.reachable_nodes.__contains__(edge[1]) and edge[0] not in self.reachable_nodes)):
if(slack>self.edge_wt[edge]-1):
if ((edge[0] in self.reachable_nodes and edge[1] not in self.reachable_nodes) or
(edge[1] in self.reachable_nodes and edge[0] not in self.reachable_nodes)):
if slack > self.edge_wt[edge]-1:
slack = self.edge_wt[edge]-1
new_edge = edge
@ -93,7 +93,7 @@ class graph(object):
self.reachable_nodes = []
self.tree_edges = []
self.reachable_node(self.start)
return self.reachable_nodes.__len__()
return len(self.reachable_nodes)
def reachable_node(self, node):
@ -117,13 +117,13 @@ class graph(object):
"""
self.cut_edges = {}
self.head_nodes = []
i=0;
i=0
for edge in self.tree_edges:
self.head_nodes = []
rest_edges = []
rest_edges += self.tree_edges
rest_edges.__delitem__(i)
del rest_edges[i]
self.head_component(self.start, rest_edges)
i+=1
positive = 0
@ -197,7 +197,7 @@ class graph(object):
des = link[1]
edge_len = self.partial_order[des]['level'] - self.partial_order[src]['level']
if edge_len < 0:
self.links.__delitem__(i)
del self.links[i]
self.links.insert(i, (des, src))
self.transitions[src].remove(des)
self.transitions.setdefault(des, []).append(src)
@ -210,10 +210,10 @@ class graph(object):
def exchange(self, e, f):
"""Exchange edges to make feasible-tree optimized
@param edge edge with negative cut-value
@param edge new edge with minimum slack-value
:param e: edge with negative cut-value
:param f: new edge with minimum slack-value
"""
self.tree_edges.__delitem__(self.tree_edges.index(e))
del self.tree_edges[self.tree_edges.index(e)]
self.tree_edges.append(f)
self.init_cutvalues()
@ -227,13 +227,13 @@ class graph(object):
self.head_nodes = []
rest_edges = []
rest_edges += self.tree_edges
rest_edges.__delitem__(rest_edges.index(edge))
del rest_edges[rest_edges.index(edge)]
self.head_component(self.start, rest_edges)
if self.head_nodes.__contains__(edge[1]):
if edge[1] in self.head_nodes:
l = []
for node in self.result:
if not self.head_nodes.__contains__(node):
if node not in self.head_nodes:
l.append(node)
self.head_nodes = l
@ -243,7 +243,7 @@ class graph(object):
if source_node in self.head_nodes:
for dest_node in self.transitions[source_node]:
if dest_node not in self.head_nodes:
if(slack>(self.edge_wt[edge]-1)):
if slack>(self.edge_wt[edge]-1):
slack = self.edge_wt[edge]-1
new_edge = (source_node, dest_node)
@ -276,7 +276,7 @@ class graph(object):
least_rank = min(map(lambda x: x['x'], self.result.values()))
if(least_rank!=0):
if least_rank!=0:
for node in self.result:
self.result[node]['x']-=least_rank
@ -310,7 +310,7 @@ class graph(object):
"""
if not self.result[node]['y']:
self.result[node]['y'] = self.order[level]
self.order[level] = self.order[level]+1
self.order[level] += 1
for sec_end in self.transitions.get(node, []):
if node!=sec_end:
@ -377,7 +377,7 @@ class graph(object):
if pre_level_nodes:
for src in pre_level_nodes:
if (self.transitions.get(src) and self.transitions[src].__contains__(node)):
if self.transitions.get(src) and node in self.transitions[src]:
adj_nodes.append(self.result[src]['y'])
return adj_nodes
@ -455,7 +455,7 @@ class graph(object):
mid_node = l[no/2]
self.result[mid_node]['y'] = mid_pos
if self.transitions.get((mid_node), False):
if self.transitions.get(mid_node, False):
if last:
self.result[mid_node]['y'] = last + len(self.transitions[mid_node])/2 + 1
if node!=mid_node:
@ -494,7 +494,7 @@ class graph(object):
if max_level%2:
self.result[self.start]['y'] = (max_level+1)/2 + self.max_order + (self.max_order and 1)
else:
self.result[self.start]['y'] = (max_level)/2 + self.max_order + (self.max_order and 1)
self.result[self.start]['y'] = max_level /2 + self.max_order + (self.max_order and 1)
self.graph_order()
@ -511,7 +511,7 @@ class graph(object):
for start in self.start_nodes[:index]:
same = True
for edge in self.tree_list[start][1:]:
if self.tree_list[self.start].__contains__(edge):
if edge in self.tree_list[self.start]:
continue
else:
same = False
@ -590,9 +590,9 @@ class graph(object):
for edge in largest_tree:
if rem_nodes.__contains__(edge[0]):
if edge[0] in rem_nodes:
rem_nodes.remove(edge[0])
if rem_nodes.__contains__(edge[1]):
if edge[1] in rem_nodes:
rem_nodes.remove(edge[1])
if not rem_nodes:
@ -601,8 +601,6 @@ class graph(object):
def rank(self):
"""Finds the optimized rank of the nodes using Network-simplex algorithm
@param start starting node of the component
"""
self.levels = {}
self.critical_edges = []
@ -641,8 +639,6 @@ class graph(object):
def order_in_rank(self):
"""Finds optimized order of the nodes within their ranks using median heuristic
@param start: starting node of the component
"""
self.make_chain()
@ -716,7 +712,7 @@ class graph(object):
#for flat edges ie. source an destination nodes are on the same rank
for src in self.transitions:
for des in self.transitions[src]:
if (self.result[des]['x'] - self.result[src]['x'] == 0):
if self.result[des]['x'] - self.result[src]['x'] == 0:
self.result[src]['x'] += 0.08
self.result[des]['x'] -= 0.08

View File

@ -23,7 +23,7 @@ import io
import StringIO
from PIL import Image
from PIL import ImageEnhance
from PIL import ImageEnhance, ImageOps
from random import random
# ----------------------------------------
@ -36,6 +36,7 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
filled with transparent background. The image will not be stretched if
smaller than the expected size.
Steps of the resizing:
- Compute width and height if not specified.
- if avoid_if_small: if both image sizes are smaller than the requested
sizes, the original image is returned. This is used to avoid adding
transparent content around images that we do not want to alter but
@ -46,14 +47,14 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
function. Aspect ratios are preserved when using it. Note that if the
source image is smaller than the expected size, it will not be
extended, but filled to match the size.
- create a transparent background that will hold the final
image.
- past the thumbnail on the transparent background and center
it.
- create a transparent background that will hold the final image.
- paste the thumbnail on the transparent background and center it.
:param base64_source: base64-encoded version of the source
image; if False, returns False
:param size: tuple(height, width)
:param size: 2-tuple(width, height). A None value for any of width or
height mean an automatically computed value based respectivelly
on height or width of the source image.
:param encoding: the output encoding
:param filetype: the output filetype
:param avoid_if_small: do not resize if image height and width
@ -61,22 +62,21 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
"""
if not base64_source:
return False
if size == (None, None):
return base64_source
image_stream = io.BytesIO(base64_source.decode(encoding))
image = Image.open(image_stream)
# check image size: do not create a thumbnail if avoiding smaller images
if avoid_if_small and image.size[0] <= size[0] and image.size[1] <= size[1]:
return base64_source
# create a thumbnail: will resize and keep ratios, then sharpen for better looking result
image.thumbnail(size, Image.ANTIALIAS)
sharpener = ImageEnhance.Sharpness(image.convert('RGBA'))
image = sharpener.enhance(2.0)
# create a transparent image for background
background = Image.new('RGBA', size, (255, 255, 255, 0))
# past the resized image on the background
background.paste(image, ((size[0] - image.size[0]) / 2, (size[1] - image.size[1]) / 2))
# return an encoded image
asked_width, asked_height = size
if asked_width is None:
asked_width = int(image.size[0] * (float(asked_height) / image.size[1]))
if asked_height is None:
asked_height = int(image.size[1] * (float(asked_width) / image.size[0]))
size = asked_width, asked_height
if image.size <> size:
image = ImageOps.fit(image, size, Image.ANTIALIAS)
background_stream = StringIO.StringIO()
background.save(background_stream, filetype)
image.save(background_stream, filetype)
return background_stream.getvalue().encode(encoding)
def image_resize_image_big(base64_source, size=(1204, 1204), encoding='base64', filetype='PNG', avoid_if_small=True):
@ -158,3 +158,13 @@ def image_get_resized_images(base64_source, return_big=False, return_medium=True
return_dict[small_name] = image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small)
return return_dict
if __name__=="__main__":
import sys
assert len(sys.argv)==3, 'Usage to Test: image.py SRC.png DEST.png'
img = file(sys.argv[1],'rb').read().encode('base64')
new = image_resize_image(img, (128,100))
file(sys.argv[2], 'wb').write(new.decode('base64'))

Some files were not shown because too many files have changed in this diff Show More