merge upstream
bzr revid: chs@openerp.com-20121217172614-3z1pstu5th26wuuc
This commit is contained in:
Vendored
+1
@@ -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
|
||||
+11
-11
@@ -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
|
||||
|
||||
+284
-222
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
|
||||
|
||||
+155
-95
@@ -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
|
||||
|
||||
+896
-455
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1379
-172
File diff suppressed because it is too large
Load Diff
+708
-326
File diff suppressed because it is too large
Load Diff
+673
-332
File diff suppressed because it is too large
Load Diff
+118
-17
@@ -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
|
||||
|
||||
+300
-254
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
|
||||
|
||||
+3418
-318
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()
|
||||
|
||||
+676
-283
File diff suppressed because it is too large
Load Diff
+11
-5
@@ -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:
|
||||
|
||||
+141
-95
@@ -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()]
|
||||
|
||||
|
||||
+62
-26
@@ -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()
|
||||
|
||||
+32
-27
@@ -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
|
||||
|
||||
+12
-13
@@ -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
|
||||
|
||||
+17
-24
@@ -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)
|
||||
|
||||
|
||||
+5
-10
@@ -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:
|
||||
|
||||
+24
-28
@@ -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
|
||||
|
||||
|
||||
+29
-19
@@ -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
Reference in New Issue
Block a user