merge upstream
bzr revid: chs@openerp.com-20121217172614-3z1pstu5th26wuuc
This commit is contained in:
commit
0c7f17c0ac
|
@ -19,6 +19,7 @@ Depends:
|
|||
python-docutils,
|
||||
python-feedparser,
|
||||
python-gdata,
|
||||
python-jinja2,
|
||||
python-ldap,
|
||||
python-libxslt1,
|
||||
python-lxml,
|
||||
|
|
|
@ -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
|
||||
----------
|
||||
|
||||
|
|
|
@ -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
|
||||
+++++++++++++++++++++++++
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
"OpenERP’s 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
|
||||
|
|
|
@ -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
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
|
@ -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
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -24,9 +24,6 @@ from osv import osv, fields
|
|||
from tools.translate import _
|
||||
|
||||
class ir_filters(osv.osv):
|
||||
'''
|
||||
Filters
|
||||
'''
|
||||
_name = 'ir.filters'
|
||||
_description = 'Filters'
|
||||
|
||||
|
|
|
@ -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)
|
||||
"""
|
||||
|
|
|
@ -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)])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
|
@ -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>
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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,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,
|
||||
]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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:
|
||||
|
|
|
@ -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()]
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 = '/'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 = '/'
|
||||
|
|
|
@ -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], )
|
||||
|
|
|
@ -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) + \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 +='''
|
||||
|
|
|
@ -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)])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"> </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):
|
||||
|
|
|
@ -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('&','&').replace('<', '<').replace('>', '>').replace('</br>',''), report_type)
|
||||
return html.replace('&','&').replace('<', '<').replace('>', '>').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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' \
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 """
|
||||
|
|
|
@ -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, [])
|
||||
|
||||
|
|
|
@ -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:
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue