diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py index 996b91b0349..6c4b1904e64 100644 --- a/addons/base_import/models/base_import.py +++ b/addons/base_import/models/base_import.py @@ -615,7 +615,7 @@ class Import(models.TransientModel): for num, line in enumerate(data): if line[index]: try: - line[index] = dt.strftime(dt.strptime(ustr(line[index]).encode('utf-8'), user_format), server_format) + line[index] = dt.strftime(dt.strptime(ustr(line[index].strip()).encode('utf-8'), user_format), server_format) except ValueError as e: raise ValueError(_("Column %s contains incorrect values. Error in line %d: %s") % (name, num + 1, ustr(e.message))) except Exception as e: diff --git a/addons/l10n_fr_certification/models/account.py b/addons/l10n_fr_certification/models/account.py index bef0880d7ca..07d5fc04e41 100644 --- a/addons/l10n_fr_certification/models/account.py +++ b/addons/l10n_fr_certification/models/account.py @@ -10,7 +10,7 @@ ERR_MSG = _("According to the french law, you cannot modify a %s in order for it #forbidden fields MOVE_FIELDS = ['date', 'journal_id', 'company_id'] -LINE_FIELDS = ['debit', 'credit', 'account_id', 'move_id', 'partner_id'] +LINE_FIELDS = ['debit', 'credit', 'account_id', 'partner_id'] class AccountMove(models.Model): @@ -55,7 +55,8 @@ class AccountMove(models.Model): for line in move.line_ids: for field in LINE_FIELDS: - values[field] = _getattrstring(line, field) + k = 'line_%d_%s' % (line.id, field) + values[k] = _getattrstring(line, field) #make the json serialization canonical # (https://tools.ietf.org/html/draft-staykov-hu-json-canonical-form-00) move.l10n_fr_string_to_hash = dumps(values, sort_keys=True, encoding="utf-8", diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index e86138d82b9..be91eb3fd01 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -559,7 +559,7 @@ class MassMailing(models.Model): def retry_failed_mail(self): failed_mails = self.env['mail.mail'].search([('mailing_id', 'in', self.ids), ('state', '=', 'exception')]) failed_mails.mapped('statistics_ids').unlink() - failed_mails.unlink() + failed_mails.sudo().unlink() self.write({'state': 'in_queue'}) #------------------------------------------------------ diff --git a/addons/mrp/models/mrp_workcenter.py b/addons/mrp/models/mrp_workcenter.py index 0dc9cdc96af..cc12ec0060b 100644 --- a/addons/mrp/models/mrp_workcenter.py +++ b/addons/mrp/models/mrp_workcenter.py @@ -15,7 +15,7 @@ class MrpWorkcenter(models.Model): # resource name = fields.Char(related='resource_id.name', store=True) - time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', store=True) + time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', default=100, store=True) active = fields.Boolean('Active', related='resource_id.active', default=True, store=True) code = fields.Char('Code', copy=False) diff --git a/addons/point_of_sale/i18n/point_of_sale.pot b/addons/point_of_sale/i18n/point_of_sale.pot index 77c4a996ec8..0d7ea224acf 100644 --- a/addons/point_of_sale/i18n/point_of_sale.pot +++ b/addons/point_of_sale/i18n/point_of_sale.pot @@ -3512,6 +3512,18 @@ msgid "You have to select a pricelist in the sale form !\n" "Please set one before choosing a product." msgstr "" +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_details.py:48 +#, python-format +msgid "You have to set a logo for your company." +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_details.py:50 +#, python-format +msgid "You have to set your reports's header and footer layout." +msgstr "" + #. module: point_of_sale #: code:addons/point_of_sale/models/pos_session.py:24 #, python-format diff --git a/addons/point_of_sale/wizard/pos_details.py b/addons/point_of_sale/wizard/pos_details.py index 0a599aefd86..fa363798dfc 100644 --- a/addons/point_of_sale/wizard/pos_details.py +++ b/addons/point_of_sale/wizard/pos_details.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import api, fields, models, _ from odoo.exceptions import UserError @@ -44,6 +44,10 @@ class PosDetails(models.TransientModel): @api.multi def generate_report(self): + if (not self.env.user.company_id.logo): + raise UserError(_("You have to set a logo or a layout for your company.")) + elif (not self.env.user.company_id.external_report_layout): + raise UserError(_("You have to set your reports's header and footer layout.")) data = {'date_start': self.start_date, 'date_stop': self.end_date, 'config_ids': self.pos_config_ids.ids} return self.env['report'].get_action( [], 'point_of_sale.report_saledetails', data=data) diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index abe09f05fd6..e6c402bc95a 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -106,7 +106,7 @@ class Pricelist(models.Model): """ self.ensure_one() if not date: - date = self._context.get('date', fields.Date.today()) + date = self._context.get('date') or fields.Date.today() if not uom_id and self._context.get('uom'): uom_id = self._context['uom'] if uom_id: diff --git a/addons/resource/i18n/resource.pot b/addons/resource/i18n/resource.pot index 30b510ade92..aa093e5292e 100644 --- a/addons/resource/i18n/resource.pot +++ b/addons/resource/i18n/resource.pot @@ -441,6 +441,12 @@ msgstr "" msgid "This field is used to calculate the the expected duration of a work order at this work center. For example, if a work order takes one hour and the efficiency factor is 100%, then the expected duration will be one hour. If the efficiency factor is 200%, however the expected duration will be 30 minutes." msgstr "" +#. module: resource +#: code:addons/resource/models/resource.py:667 +#, python-format +msgid "The efficiency factor cannot be equal to 0." +msgstr "" + #. module: resource #: selection:resource.calendar.attendance,dayofweek:0 msgid "Thursday" diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index c464fada7a1..6f0353be2a4 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -669,6 +669,13 @@ class ResourceResource(models.Model): required=True, help="Define the schedule of resource") + @api.multi + @api.constrains('time_efficiency') + def _check_time_efficiency(self): + for record in self: + if record.time_efficiency == 0: + raise ValidationError(_('The efficiency factor cannot be equal to 0.')) + @api.model def create(self, values): if values.get('company_id') and not values.get('calendar_id'): diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index be7fea3d465..cb84495073d 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -889,6 +889,21 @@ class SaleOrderLine(models.Model): uom=self.product_uom.id ) + result = {'domain': domain} + + title = False + message = False + warning = {} + if product.sale_line_warn != 'no-message': + title = _("Warning for %s") % product.name + message = product.sale_line_warn_msg + warning['title'] = title + warning['message'] = message + result = {'warning': warning} + if product.sale_line_warn == 'block': + self.product_id = False + return result + name = product.name_get()[0][1] if product.description_sale: name += '\n' + product.description_sale @@ -900,22 +915,11 @@ class SaleOrderLine(models.Model): vals['price_unit'] = self.env['account.tax']._fix_tax_included_price(self._get_display_price(product), product.taxes_id, self.tax_id) self.update(vals) - title = False - message = False - warning = {} - if product.sale_line_warn != 'no-message': - title = _("Warning for %s") % product.name - message = product.sale_line_warn_msg - warning['title'] = title - warning['message'] = message - if product.sale_line_warn == 'block': - self.product_id = False - return {'warning': warning} - return {'domain': domain} + return result @api.onchange('product_uom', 'product_uom_qty') def product_uom_change(self): - if not self.product_uom: + if not self.product_uom or not self.product_id: self.price_unit = 0.0 return if self.order_id.pricelist_id and self.order_id.partner_id: diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index ca8e2e840dc..f68ed53d14e 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -318,8 +318,8 @@ class StockMove(models.Model): 'product_uom_id': self.product_id.uom_id.id, 'ref': self.picking_id.name, 'partner_id': partner_id, - 'debit': debit_value, - 'credit': 0, + 'debit': debit_value if debit_value > 0 else 0, + 'credit': -debit_value if debit_value < 0 else 0, 'account_id': debit_account_id, } credit_line_vals = { @@ -329,8 +329,8 @@ class StockMove(models.Model): 'product_uom_id': self.product_id.uom_id.id, 'ref': self.picking_id.name, 'partner_id': partner_id, - 'credit': credit_value, - 'debit': 0, + 'credit': credit_value if credit_value > 0 else 0, + 'debit': -credit_value if credit_value < 0 else 0, 'account_id': credit_account_id, } res = [(0, 0, debit_line_vals), (0, 0, credit_line_vals)] diff --git a/addons/website/static/src/js/website.backendDashboard.js b/addons/website/static/src/js/website.backendDashboard.js index 9c6416da4ac..345110eaf12 100644 --- a/addons/website/static/src/js/website.backendDashboard.js +++ b/addons/website/static/src/js/website.backendDashboard.js @@ -59,8 +59,8 @@ var Dashboard = Widget.extend(ControlPanelMixin, { fetch_data: function() { var self = this; return ajax.jsonRpc('/website/fetch_dashboard_data', 'call', { - 'date_from': this.date_from.format('YYYY-MM-DD'), - 'date_to': this.date_to.format('YYYY-MM-DD'), + 'date_from': this.date_from.year()+'-'+(this.date_from.month()+1)+'-'+this.date_from.date(), + 'date_to': this.date_to.year()+'-'+(this.date_to.month()+1)+'-'+this.date_to.date(), }).done(function(result) { self.data = result; self.dashboards_data = result.dashboards; diff --git a/addons/website_crm_partner_assign/report/crm_lead_report.py b/addons/website_crm_partner_assign/report/crm_lead_report.py index e72a1b3dedf..07676117473 100644 --- a/addons/website_crm_partner_assign/report/crm_lead_report.py +++ b/addons/website_crm_partner_assign/report/crm_lead_report.py @@ -67,7 +67,7 @@ class CrmLeadReportAssign(models.Model): p.grade_id, p.date as partner_date, c.planned_revenue*(c.probability/100) as probable_revenue, - 1 as nbr, + 1 as nbr_cases, c.create_date as create_date, extract('epoch' from (c.write_date-c.create_date))/(3600*24) as delay_close, extract('epoch' from (c.date_deadline - c.date_closed))/(3600*24) as delay_expected, diff --git a/addons/website_quote/models/sale_quote.py b/addons/website_quote/models/sale_quote.py index e65f6ed905f..79743fdc814 100644 --- a/addons/website_quote/models/sale_quote.py +++ b/addons/website_quote/models/sale_quote.py @@ -23,7 +23,8 @@ class SaleQuoteTemplate(models.Model): (2, 'Immediate after website order validation and save a token'), ], 'Payment', help="Require immediate payment by the customer when validating the order from the website quote") mail_template_id = fields.Many2one('mail.template', 'Confirmation Mail', - help="This e-mail template will be sent on confirmation. Leave empty to send nothing.") + help="This e-mail template will be sent on confirmation. Leave empty to send nothing.", + domain=[('model', '=', 'sale.quote.template')]) @api.multi def open_template(self): diff --git a/doc/howtos/backend/exercise-dashboard b/doc/howtos/backend/exercise-dashboard index 91bc239dd7a..affbc7bdc8f 100644 --- a/doc/howtos/backend/exercise-dashboard +++ b/doc/howtos/backend/exercise-dashboard @@ -9,12 +9,13 @@ Index: addons/openacademy/__manifest__.py 'version': '0.1', # any module necessary for this one to work correctly -- 'depends': ['base'], -+ 'depends': ['base', 'board'], +- 'depends': ['base', 'report'], ++ 'depends': ['base', 'report', 'board'], # always loaded 'data': [ -@@ -31,6 +31,7 @@ +@@ -30,6 +30,7 @@ + 'templates.xml', 'views/openacademy.xml', 'views/partner.xml', + 'views/session_board.xml', diff --git a/doc/howtos/backend/exercise-report b/doc/howtos/backend/exercise-report index 351d34a92b2..08ac677b5c0 100644 --- a/doc/howtos/backend/exercise-report +++ b/doc/howtos/backend/exercise-report @@ -1,11 +1,24 @@ # HG changeset patch # Parent c140f0a861a08881d8737bca0ffb83904a2059a3 +Index: addons/openacademy/__manifest__.py +=================================================================== +--- addons.orig/openacademy/__manifest__.py 2014-08-26 17:26:21.535783052 +0200 ++++ addons/openacademy/__manifest__.py 2014-08-26 17:26:21.531783052 +0200 +@@ -21,7 +21,7 @@ + 'version': '0.1', + + # any module necessary for this one to work correctly +- 'depends': ['base'], ++ 'depends': ['base', 'report'], + + # always loaded + 'data': [ Index: addons/openacademy/__manifest__.py =================================================================== --- addons.orig/openacademy/__manifest__.py 2014-08-29 08:39:43.975536806 +0200 +++ addons/openacademy/__manifest__.py 2014-08-29 08:39:52.000000000 +0200 -@@ -31,6 +31,7 @@ +@@ -30,6 +30,7 @@ 'templates.xml', 'views/openacademy.xml', 'views/partner.xml', diff --git a/doc/howtos/backend/exercise-state-basic b/doc/howtos/backend/exercise-state-basic deleted file mode 100644 index f70a41b4dae..00000000000 --- a/doc/howtos/backend/exercise-state-basic +++ /dev/null @@ -1,55 +0,0 @@ -# HG changeset patch -# Parent 8c721171aa16a41e94059f53d6780c67b5ef2dfc -# Parent 8d2ca42b5be2031ea9624896df53f09f7ca131be - -diff --git a/openacademy/models.py b/openacademy/models.py ---- a/openacademy/models.py -+++ b/openacademy/models.py -@@ -66,6 +66,24 @@ class Session(models.Model): - attendees_count = fields.Integer( - string="Attendees count", compute='_get_attendees_count', store=True) - -+ state = fields.Selection([ -+ ('draft', "Draft"), -+ ('confirmed', "Confirmed"), -+ ('done', "Done"), -+ ], default='draft') -+ -+ @api.multi -+ def action_draft(self): -+ self.state = 'draft' -+ -+ @api.multi -+ def action_confirm(self): -+ self.state = 'confirmed' -+ -+ @api.multi -+ def action_done(self): -+ self.state = 'done' -+ - @api.depends('seats', 'attendee_ids') - def _taken_seats(self): - for r in self: -diff --git a/openacademy/views/openacademy.xml b/openacademy/views/openacademy.xml ---- a/openacademy/views/openacademy.xml -+++ b/openacademy/views/openacademy.xml -@@ -96,6 +96,19 @@ - openacademy.session - -
-+
-+
-+ - - - diff --git a/doc/howtos/backend/exercise-translations b/doc/howtos/backend/exercise-translations index 8ade655253d..e7dfe53ebb7 100644 --- a/doc/howtos/backend/exercise-translations +++ b/doc/howtos/backend/exercise-translations @@ -28,7 +28,7 @@ diff --git a/openacademy/models.py b/openacademy/models.py default['name'] = new_name return super(Course, self).copy(default) -@@ -97,15 +97,15 @@ class Session(models.Model): +@@ -79,15 +79,15 @@ class Session(models.Model): if self.seats < 0: return { 'warning': { @@ -48,7 +48,7 @@ diff --git a/openacademy/models.py b/openacademy/models.py }, } -@@ -151,4 +151,4 @@ class Session(models.Model): +@@ -133,4 +133,4 @@ class Session(models.Model): def _check_instructor_not_in_attendees(self): for r in self: if r.instructor_id and r.instructor_id in r.attendee_ids: diff --git a/doc/howtos/backend/exercise-wizard-action b/doc/howtos/backend/exercise-wizard-action index 3bc20624ee9..23d6a0f2667 100644 --- a/doc/howtos/backend/exercise-wizard-action +++ b/doc/howtos/backend/exercise-wizard-action @@ -2,7 +2,7 @@ Index: addons/openacademy/views/openacademy.xml =================================================================== --- addons.orig/openacademy/views/openacademy.xml 2014-08-28 14:34:19.255004611 +0200 +++ addons/openacademy/views/openacademy.xml 2014-08-28 14:34:19.251004612 +0200 -@@ -248,6 +248,12 @@ +@@ -234,6 +234,12 @@ diff --git a/doc/howtos/backend/exercise-wizard-launch b/doc/howtos/backend/exercise-wizard-launch index d864eef3f87..340545ededa 100644 --- a/doc/howtos/backend/exercise-wizard-launch +++ b/doc/howtos/backend/exercise-wizard-launch @@ -17,7 +17,7 @@ Index: addons/openacademy/views/openacademy.xml =================================================================== --- addons.orig/openacademy/views/openacademy.xml 2014-08-28 14:34:07.879004780 +0200 +++ addons/openacademy/views/openacademy.xml 2014-08-28 14:34:07.871004780 +0200 -@@ -237,5 +237,26 @@ +@@ -224,5 +224,26 @@ diff --git a/doc/howtos/backend/exercise-wizard-multi b/doc/howtos/backend/exercise-wizard-multi index dc99dba2e31..f8ece675090 100644 --- a/doc/howtos/backend/exercise-wizard-multi +++ b/doc/howtos/backend/exercise-wizard-multi @@ -2,7 +2,7 @@ Index: addons/openacademy/views/openacademy.xml =================================================================== --- addons.orig/openacademy/views/openacademy.xml 2014-08-28 14:34:28.583004473 +0200 +++ addons/openacademy/views/openacademy.xml 2014-08-28 14:34:28.579004473 +0200 -@@ -245,7 +245,7 @@ +@@ -231,7 +231,7 @@ diff --git a/doc/howtos/backend/series b/doc/howtos/backend/series index 36627e4eadd..e48d05914e9 100644 --- a/doc/howtos/backend/series +++ b/doc/howtos/backend/series @@ -24,7 +24,6 @@ exercise-searchview exercise-gantt exercise-graph exercise-kanban -exercise-state-basic exercise-access-rights exercise-access-rules exercise-wizard diff --git a/doc/index.rst b/doc/index.rst index dcdd6ab752b..21231b7ce3f 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -17,7 +17,6 @@ Index api_integration setup reference - business .. ifconfig:: todo_include_todos diff --git a/doc/setup/install.rst b/doc/setup/install.rst index de21d6c53ab..aae7d03b8ba 100644 --- a/doc/setup/install.rst +++ b/doc/setup/install.rst @@ -546,7 +546,7 @@ default db to serve on localhost:8069 http://www.enterprisedb.com/products-services-training/pgdownload .. _Quilt: http://en.wikipedia.org/wiki/Quilt_(software) .. _saas: https://www.odoo.com/page/start -.. _the wkhtmltopdf download page: http://wkhtmltopdf.org/downloads.html +.. _the wkhtmltopdf download page: https://github.com/wkhtmltopdf/wkhtmltopdf/releases/tag/0.12.1 .. _UAC: http://en.wikipedia.org/wiki/User_Account_Control .. _wkhtmltopdf: http://wkhtmltopdf.org .. _pip: https://pip.pypa.io