diff options
24 files changed, 170 insertions, 49 deletions
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6d11d14aa8b..825cbb37025 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -531,7 +531,7 @@ class AccountMoveLine(models.Model): else: date = partial_line.credit_move_id.date if partial_line.debit_move_id == line else partial_line.debit_move_id.date rate = line.currency_id.with_context(date=date).rate - amount_residual_currency += sign_partial_line * line.currency_id.round(partial_line.amount * rate) + amount_residual_currency += sign_partial_line * partial_line.amount * rate #computing the `reconciled` field. reconciled = False diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml index 3387473a9e4..07230902ee8 100644 --- a/addons/account/views/account_payment_view.xml +++ b/addons/account/views/account_payment_view.xml @@ -106,7 +106,8 @@ <filter string="Payment Method" name="paymentmethod" domain="[]" context="{'group_by': 'payment_method_id'}"/> <filter string="State" name="state" domain="[]" context="{'group_by': 'state'}"/> <filter string="Currency" name="currency" domain="[]" context="{'group_by': 'currency_id'}" groups="base.group_multi_currency"/> - <filter string="Company" name="company" domain="[]" context="{'group_by': 'company_id'}" groups="base.group_multi_company"/> + <!-- company_id is not stored (cdca5d4751a979f6b694f02d88160843f81a77f5). But we can't break structure--> + <filter string="Company" name="company" domain="[]" context="{'group_by': 'company_id'}" groups="base.group_multi_company" invisible="1" /> </search> </field> </record> diff --git a/addons/hw_escpos/escpos/escpos.py b/addons/hw_escpos/escpos/escpos.py index 0369aa2a0a4..3105b38850f 100644 --- a/addons/hw_escpos/escpos/escpos.py +++ b/addons/hw_escpos/escpos/escpos.py @@ -894,14 +894,23 @@ class Escpos: self._raw(PAPER_FULL_CUT) - def cashdraw(self, pin): - """ Send pulse to kick the cash drawer """ - if pin == 2: - self._raw(CD_KICK_2) - elif pin == 5: - self._raw(CD_KICK_5) - else: - raise CashDrawerError() + def cashdraw(self, pin, tries=5): + """ Send pulse to kick the cash drawer + + With some printers the drawer will not open after one pulse, for this reason we will check + the drawer status up to 'tries' times and send a new pulse if the drawer is still closed. If the + drawer status is open, we will stop sending pulses. + """ + for i in range(tries): + if pin == 2: + self._raw(CD_KICK_2) + elif pin == 5: + self._raw(CD_KICK_5) + else: + raise CashDrawerError() + + if i != tries - 1 and not self.get_printer_status()['printer']['drawer_pin_high']: + break def hw(self, hw): diff --git a/addons/l10n_be_hr_payroll_fleet/__manifest__.py b/addons/l10n_be_hr_payroll_fleet/__manifest__.py index d31865d69b5..3f840a44b74 100644 --- a/addons/l10n_be_hr_payroll_fleet/__manifest__.py +++ b/addons/l10n_be_hr_payroll_fleet/__manifest__.py @@ -11,6 +11,7 @@ 'views/fleet_views.xml', 'views/res_config_settings_views.xml', 'views/hr_contract_views.xml', + 'security/security.xml', ], 'auto_install': True, } diff --git a/addons/l10n_be_hr_payroll_fleet/security/security.xml b/addons/l10n_be_hr_payroll_fleet/security/security.xml new file mode 100644 index 00000000000..3fc21715a4c --- /dev/null +++ b/addons/l10n_be_hr_payroll_fleet/security/security.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <!-- Note for later versions, the group Employee Manager should become contract manager --> + <record id="hr.group_hr_manager" model="res.groups"> + <field name="implied_ids" eval="[(4, ref('fleet.fleet_group_manager'))]"/> + </record> +</odoo> diff --git a/addons/l10n_mx/data/account_tag_data.xml b/addons/l10n_mx/data/account_tag_data.xml index 244c9b65ff3..1e8b23dacda 100644 --- a/addons/l10n_mx/data/account_tag_data.xml +++ b/addons/l10n_mx/data/account_tag_data.xml @@ -479,25 +479,25 @@ <field name='name'>119.01 IVA pendiente de pago</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_119_02' model='account.account.tag'> <field name='name'>119.02 IVA de importación pendiente de pago</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_119_03' model='account.account.tag'> <field name='name'>119.03 IEPS pendiente de pago</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_119_04' model='account.account.tag'> <field name='name'>119.04 IEPS pendiente de pago en importación</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_120_01' model='account.account.tag'> <field name='name'>120.01 Anticipo a proveedores nacional</field> @@ -917,7 +917,7 @@ <field name='name'>180.01 Crédito mercantil</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_181_01' model='account.account.tag'> <field name='name'>181.01 Gastos de instalación</field> @@ -2423,7 +2423,7 @@ <field name='name'>503 Devoluciones, descuentos o bonificaciones sobre compras</field> <field name='color'>1</field> <field name='applicability'>accounts</field> - <field name='nature'>D</field> + <field name='nature'>A</field> </record> <record id='account_tag_503_01' model='account.account.tag'> <field name='name'>503.01 Devoluciones, descuentos o bonificaciones sobre compras</field> @@ -2585,13 +2585,13 @@ <field name='name'>505.01 Costo por venta de activo fijo</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_505_02' model='account.account.tag'> <field name='name'>505.02 Costo por baja de activo fijo</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_601_01' model='account.account.tag'> <field name='name'>601.01 Sueldos y salarios</field> @@ -4781,7 +4781,7 @@ <field name='name'>607.01 Participación de los trabajadores en las utilidades</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_608_01' model='account.account.tag'> <field name='name'>608.01 Participación en resultados de subsidiarias</field> @@ -4799,7 +4799,7 @@ <field name='name'>610.01 Participación de los trabajadores en las utilidades diferida</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_611_01' model='account.account.tag'> <field name='name'>611.01 Impuesto Sobre la renta</field> @@ -4817,7 +4817,7 @@ <field name='name'>612.01 Gastos no deducibles para CUFIN</field> <field name='color'>4</field> <field name='applicability'>accounts</field> - <field name='nature'>A</field> + <field name='nature'>D</field> </record> <record id='account_tag_613_01' model='account.account.tag'> <field name='name'>613.01 Depreciación de edificios</field> diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index 982d67b21c7..c9957bfc1a2 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -146,7 +146,7 @@ class MailActivity(models.Model): ('today', 'Today'), ('planned', 'Planned')], 'State', compute='_compute_state') - recommended_activity_type_id = fields.Many2one('mail.activity.type', string="Recommended Activity Type", readonly=True) + recommended_activity_type_id = fields.Many2one('mail.activity.type', string="Recommended Activity Type") previous_activity_type_id = fields.Many2one('mail.activity.type', string='Previous Activity Type', readonly=True) has_recommended_activities = fields.Boolean( 'Next activities available', diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index f92e23c6cc1..dcaf346e139 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -376,6 +376,7 @@ class MailComposer(models.TransientModel): - normal mode: return rendered values /!\ for x2many field, this onchange return command instead of ids """ + attachment_ids = [] if template_id and composition_mode == 'mass_mail': template = self.env['mail.template'].browse(template_id) fields = ['subject', 'body_html', 'email_from', 'reply_to', 'mail_server_id'] @@ -401,7 +402,7 @@ class MailComposer(models.TransientModel): 'res_id': 0, 'type': 'binary', # override default_type from context, possibly meant for another model! } - values.setdefault('attachment_ids', list()).append(Attachment.create(data_attach).id) + attachment_ids.append(Attachment.create(data_attach).id) else: default_values = self.with_context(default_composition_mode=composition_mode, default_model=model, default_res_id=res_id).default_get(['composition_mode', 'model', 'res_id', 'parent_id', 'partner_ids', 'subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id']) values = dict((key, default_values[key]) for key in ['subject', 'body', 'partner_ids', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'] if key in default_values) @@ -414,6 +415,8 @@ class MailComposer(models.TransientModel): # this force the complete replacement of x2many field with # command and is compatible with onchange api.v7 values = self._convert_to_write(values) + if attachment_ids: + values.update(attachment_ids=[(6, 0, attachment_ids)]) return {'value': values} diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index b5cff2f233a..0d8c67bc3d9 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -458,7 +458,7 @@ var Gui = core.Class.extend({ } } else if (input === '-') { if (options.firstinput) { - newbuf = '-'; + newbuf = '-0'; } else if ( newbuf[0] === '-' ) { newbuf = newbuf.substring(1,newbuf.length); } else { @@ -473,6 +473,9 @@ var Gui = core.Class.extend({ newbuf += input; } } + if (newbuf === "-") { + newbuf = ""; + } // End of input buffer at 12 characters. if (newbuf.length > buffer.length && newbuf.length > 12) { diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index cc06fbddf41..e8954205d2e 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -1284,7 +1284,7 @@ class SaleOrderLine(models.Model): result.setdefault(so_line_id, 0.0) uom = product_uom_map.get(item['product_uom_id'][0]) if so_line.product_uom.category_id == uom.category_id: - qty = uom._compute_quantity(item['unit_amount'], so_line.product_uom) + qty = uom._compute_quantity(item['unit_amount'], so_line.product_uom, rounding_method='HALF-UP') else: qty = item['unit_amount'] result[so_line_id] += qty diff --git a/addons/website/static/src/js/content/snippets.animation.js b/addons/website/static/src/js/content/snippets.animation.js index c6a186c8a0c..0616ad311c1 100644 --- a/addons/website/static/src/js/content/snippets.animation.js +++ b/addons/website/static/src/js/content/snippets.animation.js @@ -930,6 +930,10 @@ registry.gallerySlider = Animation.extend({ destroy: function () { this._super.apply(this, arguments); + if (!this.$indicator) { + return; + } + this.$prev.prependTo(this.$indicator); this.$next.appendTo(this.$indicator); this.$carousel.off('.gallery_slider'); diff --git a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml index e8863b571e3..b1e0e863959 100644 --- a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml +++ b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml @@ -164,13 +164,9 @@ <t t-if="any([p.website_published for p in partner.implemented_partner_ids])"> <h3 id="references">References</h3> <div t-foreach="partner.implemented_partner_ids" t-if="reference.website_published" t-as="reference" class="media mt-3"> - <a t-attf-href="/customers/#{slug(reference)}"> - <span t-field="reference.image_medium" t-options='{"widget": "image", "class": "d-block mr-3"}'/> - </a> + <span t-field="reference.image_medium" t-options='{"widget": "image", "class": "d-block mr-3"}'/> <div class="media-body" style="min-height: 64px;"> - <a t-attf-href="/customers/#{slug(reference)}"> - <span t-field="reference.self"/> - </a> + <span t-field="reference.self"/> <div t-field='reference.website_short_description'/> </div> </div> diff --git a/addons/website_customer/views/website_customer_templates.xml b/addons/website_customer/views/website_customer_templates.xml index da6e9aa8a33..9cd668d901d 100644 --- a/addons/website_customer/views/website_customer_templates.xml +++ b/addons/website_customer/views/website_customer_templates.xml @@ -234,4 +234,13 @@ </t> </template> +<template id="references_block_href" inherit_id="website_crm_partner_assign.references_block" name="Partner References Block"> + <xpath expr="//div/span" position="replace"> + <a t-attf-href="/customers/#{slug(reference)}">$0</a> + </xpath> + <xpath expr="//div[hasclass('media-body')]/span" position="replace"> + <a t-attf-href="/customers/#{slug(reference)}">$0</a> + </xpath> +</template> + </odoo> diff --git a/doc/cla/corporate/ecoservice.md b/doc/cla/corporate/ecoservice.md new file mode 100644 index 00000000000..b1b1cbe8ff0 --- /dev/null +++ b/doc/cla/corporate/ecoservice.md @@ -0,0 +1,21 @@ +Germany, 2019-05-14 + +ecoservice GbR agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Falk Neubert neubert@ecoservice.de https://github.com/FNeu75 + +List of contributors: + +* Christian Engelhardt c.engelhardt@ecoservice.de https://github.com/c-engelhardt-ecoservice +* Christian Schöttke c.schoettke@ecoservice.de https://github.com/cschoettke +* Falk Neubert neubert@ecoservice.de https://github.com/FNeu75 +* Gülhan Celik g.celik@ecoservice.de https://github.com/guelhancelik +* Jan Brodersen 4rmitxes@gmail.com https://github.com/Armitxes +* Kamal Prajapati k.prajapati@ecoservice.de https://github.com/kamalprajapati +* Marcel Much m.much@ecoservice.de https://github.com/mmuch diff --git a/doc/cla/corporate/savoirfairelinux.md b/doc/cla/corporate/savoirfairelinux.md index 913e317cb07..04f4563d4b7 100644 --- a/doc/cla/corporate/savoirfairelinux.md +++ b/doc/cla/corporate/savoirfairelinux.md @@ -12,17 +12,24 @@ João Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joa List of contributors: -Agathe Mollé agathe.molle@savoirfairelinux.com https://github.com/Ehtaga -Bruno Joliveau bruno.joliveau@savoirfairelinux.com https://github.com/bjoliveau -David Dufresne david.dufresne@savoirfairelinux.com https://github.com/dufresnedavid -Istvan SZALAÏ istvan.szalai@savoirfairelinux.com https://github.com/ventilooo -João Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joaoalf -Julien Jezequel-Breard julien.jezequel-breard@savoirfairelinux.com https://github.com/jjbreard -Quentin Lavallée-Bourdeau quentin.lavallee@savoirfairelinux.com https://github.com/qtiplb + Rim Ben Dhaou rim.bendhaou@savoirfairelinux.com https://github.com/rimbendhaou -Yasmine El Mrini yasmine.elmrini@savoirfairelinux.com https://github.com/yasmineelmrini Luis Garcia Ruiz luis.garcia@savoirfairelinux.com https://github.com/eilst Dimitar Apostolov dimitar.apostolov@savoirfairelinux.com https://github.com/dapostolov-sfl +Pierre Gault pierre.gault@savoirfairelinux.com https://github.com/gaultp +Maroua Romdhane maroua.romdhane@savoirfairelinux.com https://github.com/mromdhane +Jean-François Bolduc jean-francois.bolduc@savoirfairelinux.com https://github.com/fjdrake +Blaise Frison blaise.frison@savoirfairelinux.com https://github.com/bfrison-sfl +Larbi Gharib larbi.gharib@savoirfairelinux.com https://github.com/lgharib +Jananjoy Rajkumar jananjoy.rajkumar@savoirfairelinux.com https://github.com/jananjoy +Yasmine El Mrini yasmine.elmrini@savoirfairelinux.com https://github.com/yasmineelmrini (up to 2019-05-13) +Agathe Mollé agathe.molle@savoirfairelinux.com https://github.com/Ehtaga (up to 2019-05-13) +Bruno Joliveau bruno.joliveau@savoirfairelinux.com https://github.com/bjoliveau (up to 2019-05-13) +David Dufresne david.dufresne@savoirfairelinux.com https://github.com/dufresnedavid (up to 2019-05-13) +Istvan SZALAÏ istvan.szalai@savoirfairelinux.com https://github.com/ventilooo (up to 2019-05-13) +João Alfredo Gama Batista joao.gama@savoirfairelinux.com https://github.com/joaoalf (up to 2019-05-13) +Julien Jezequel-Breard julien.jezequel-breard@savoirfairelinux.com https://github.com/jjbreard (up to 2019-05-13) +Quentin Lavallée-Bourdeau quentin.lavallee@savoirfairelinux.com https://github.com/qtiplb (up to 2019-05-13) Jérome Boisvert-Chouinard jerome.boisvertchouinard@savoirfairelinux.com https://github.com/jbchouinard (up to 2017-10-17) Julie Moussu julie.mousse@savoirfairelinux.com https://github.com/JulieSFL (up to 2017-10-17) Pierre Lamarche pierre.lamarche@savoirfairelinux.com https://github.com/plamarche (up to 2017-10-17) @@ -34,6 +41,5 @@ Jordi Riera jordi.riera@savoirfairelinux.com https://github.com/foutoucour (up t Julien Roux julien.roux@savoirfairelinux.com https://github.com/jrouxsfl (up to 2017-05-12) Loïc Faure-Lacroix loic.lacroix@savoirfairelinux.com https://github.com/llacroix (up to 2017-05-12) Maxime Chambreuil maxime.chambreuil@savoirfairelinux.com https://github.com/max3903 (up to 2017-05-12) -Pierre Gault pierre.gault@savoirfairelinux.com https://github.com/gaultp (up to 2017-05-12) Sandy Carter sandy.carter@savoirfairelinux.com https://github.com/bwrsandman (up to 2017-05-12) Vincent Vinet vincent.vinet@savoirfairelinux.com https://github.com/veloutin (up to 2017-05-12) diff --git a/doc/cla/individual/gjanssens.md b/doc/cla/individual/gjanssens.md new file mode 100644 index 00000000000..d3cda29d978 --- /dev/null +++ b/doc/cla/individual/gjanssens.md @@ -0,0 +1,11 @@ +Belgium, 2019-05-09 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Geert Janssens geert@kobaltwit.be https://github.com/gjanssens diff --git a/odoo/addons/base/models/ir_mail_server.py b/odoo/addons/base/models/ir_mail_server.py index 285bc88822a..58eb2afe5a5 100644 --- a/odoo/addons/base/models/ir_mail_server.py +++ b/odoo/addons/base/models/ir_mail_server.py @@ -119,10 +119,18 @@ def encode_rfc2822_address_header(header_text): # Header as a string, using an unlimited line length.", the old one # was "A synonym for Header.encode()." so call encode() directly? name = Header(pycompat.to_text(name)).encode() - return formataddr((name, email)) + # if the from does not follow the (name <addr>),* convention, we might + # try to encode meaningless strings as address, as getaddresses is naive + # note it would also fail on real addresses with non-ascii characters + try: + return formataddr((name, email)) + except UnicodeEncodeError: + _logger.warning(_('Failed to encode the address %s\n' + 'from mail header:\n%s') % addr, header_text) + return "" addresses = getaddresses([pycompat.to_native(ustr(header_text))]) - return COMMASPACE.join(encode_addr(a) for a in addresses) + return COMMASPACE.join(a for a in (encode_addr(addr) for addr in addresses) if a) class IrMailServer(models.Model): diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index ea80fa7dbb2..69d923763d8 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -1113,9 +1113,9 @@ class UsersView(models.Model): group_multi_company = self.env.ref('base.group_multi_company', False) if group_multi_company and 'company_ids' in values: if len(user.company_ids) <= 1 and user.id in group_multi_company.users.ids: - group_multi_company.write({'users': [(3, user.id)]}) + user.write({'groups_id': [(3, group_multi_company.id)]}) elif len(user.company_ids) > 1 and user.id not in group_multi_company.users.ids: - group_multi_company.write({'users': [(4, user.id)]}) + user.write({'groups_id': [(4, group_multi_company.id)]}) return user @api.multi @@ -1126,9 +1126,9 @@ class UsersView(models.Model): if group_multi_company and 'company_ids' in values: for user in self: if len(user.company_ids) <= 1 and user.id in group_multi_company.users.ids: - group_multi_company.write({'users': [(3, user.id)]}) + user.write({'groups_id': [(3, group_multi_company.id)]}) elif len(user.company_ids) > 1 and user.id not in group_multi_company.users.ids: - group_multi_company.write({'users': [(4, user.id)]}) + user.write({'groups_id': [(4, group_multi_company.id)]}) return res def _remove_reified_groups(self, values): diff --git a/odoo/addons/test_convert/__init__.py b/odoo/addons/test_convert/__init__.py index e69de29bb2d..0650744f6bc 100644 --- a/odoo/addons/test_convert/__init__.py +++ b/odoo/addons/test_convert/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/odoo/addons/test_convert/__manifest__.py b/odoo/addons/test_convert/__manifest__.py index af6cd1af6e4..a9c67447615 100644 --- a/odoo/addons/test_convert/__manifest__.py +++ b/odoo/addons/test_convert/__manifest__.py @@ -5,4 +5,5 @@ 'name': 'test_convert', 'description': "Data for xml conversion tests", 'version': '0.0.1', + 'data': ['ir.model.access.csv'], } diff --git a/odoo/addons/test_convert/ir.model.access.csv b/odoo/addons/test_convert/ir.model.access.csv new file mode 100644 index 00000000000..014e4d1c827 --- /dev/null +++ b/odoo/addons/test_convert/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_test_convert_test_model,access_test_convert_test_model,model_test_convert_test_model,,1,1,1,1
\ No newline at end of file diff --git a/odoo/addons/test_convert/models.py b/odoo/addons/test_convert/models.py new file mode 100644 index 00000000000..0f059e56e86 --- /dev/null +++ b/odoo/addons/test_convert/models.py @@ -0,0 +1,16 @@ +from odoo import api, models + +class TestModel(models.Model): + _name = 'test_convert.test_model' + + @api.model + def action_test_date(self, today_date): + return True + + @api.model + def action_test_time(self, cur_time): + return True + + @api.model + def action_test_timezone(self, timezone): + return True diff --git a/odoo/addons/test_convert/tests/test_convert.py b/odoo/addons/test_convert/tests/test_convert.py index e81526dd43c..1bb79619c21 100644 --- a/odoo/addons/test_convert/tests/test_convert.py +++ b/odoo/addons/test_convert/tests/test_convert.py @@ -4,8 +4,10 @@ import collections import unittest +from lxml import etree as ET from lxml.builder import E +import odoo from odoo.tests import common from odoo.tools.convert import _eval_xml @@ -16,6 +18,25 @@ class TestEvalXML(common.TransactionCase): def eval_xml(self, node, obj=None): return _eval_xml(obj, node, self.env) + def test_function_eval(self): + def id_get(): pass + Obj = collections.namedtuple('Obj', ['module', 'idref', 'id_get']) + obj = Obj('test_convert', {}, id_get) + + try: + test_datetime = ET.XML("<function name='action_test_date' model='test_convert.test_model' eval='[datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")]'/>") + self.eval_xml(node=test_datetime, obj=obj) + test_time = ET.XML("<function name='action_test_time' model='test_convert.test_model' eval='[time.strftime(\"%Y-%m-%d %H:%M:%S\")]'/>") + self.eval_xml(node=test_time, obj=obj) + test_timedelta = ET.XML("<function name='action_test_date' model='test_convert.test_model' eval='[(datetime.today()-timedelta(days=365)).strftime(\"%Y-%m-%d %H:%M:%S\")]'/>") + self.eval_xml(node=test_timedelta, obj=obj) + test_relativedelta = ET.XML("<function name='action_test_date' model='test_convert.test_model' eval='[(datetime.today()+relativedelta(months=3)).strftime(\"%Y-%m-%d %H:%M:%S\")]'/>") + self.eval_xml(node=test_relativedelta, obj=obj) + test_timezone = ET.XML("<function name='action_test_timezone' model='test_convert.test_model' eval='[pytz.timezone(\"Asia/Calcutta\")]'/>") + self.eval_xml(node=test_timezone, obj=obj) + except ValueError as e: + self.fail(e.message) + def test_char(self): self.assertEqual( self.eval_xml(Field("foo")), diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index b98e586a62e..3c873597ae0 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -179,15 +179,16 @@ def _eval_xml(self, node, env): elif node.tag == "function": args = [] a_eval = node.get('eval') + model_str = node.get('model') # FIXME: should probably be exclusive if a_eval: - self.idref['ref'] = self.id_get - args = safe_eval(a_eval, self.idref) + idref2 = _get_idref(self, env, model_str, self.idref) + args = safe_eval(a_eval, idref2) for n in node: return_val = _eval_xml(self, n, env) if return_val is not None: args.append(return_val) - model = env[node.get('model')] + model = env[model_str] method = node.get('name') # this one still depends on the old API return odoo.api.call_kw(model, method, args, {}) |
