diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 6e7c404df39..e0b18dd355a 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -100,18 +100,23 @@ class IrModule(models.Model): raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename) with tempdir() as module_dir: - z.extractall(module_dir) - dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] - for mod_name in dirs: - module_names.append(mod_name) - try: - # assert mod_name.startswith('theme_') - path = opj(module_dir, mod_name) - self.import_module(mod_name, path, force=force) - success.append(mod_name) - except Exception, e: - _logger.exception('Error while importing module') - errors[mod_name] = exception_to_unicode(e) + import odoo.modules as addons + try: + addons.module.ad_paths.append(module_dir) + z.extractall(module_dir) + dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] + for mod_name in dirs: + module_names.append(mod_name) + try: + # assert mod_name.startswith('theme_') + path = opj(module_dir, mod_name) + self.import_module(mod_name, path, force=force) + success.append(mod_name) + except Exception, e: + _logger.exception('Error while importing module') + errors[mod_name] = exception_to_unicode(e) + finally: + addons.module.ad_paths.remove(module_dir) r = ["Successfully imported module '%s'" % mod for mod in success] for mod, error in errors.items(): r.append("Error while importing module '%s': %r" % (mod, error)) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index f267c3b984e..de53a4fd7d9 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -557,15 +557,18 @@ class Meeting(models.Model): if not event_date: event_date = datetime.now() - # Convert the event date to saved timezone (or context tz) as it'll - # define the correct hour/day asked by the user to repeat for recurrence. - event_date = event_date.astimezone(timezone) # transform "+hh:mm" timezone - rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date, forceset=True) + if self.allday and self.rrule and 'Z' not in self.rrule: + rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date.replace(tzinfo=None), forceset=True, ignoretz=True) + else: + # Convert the event date to saved timezone (or context tz) as it'll + # define the correct hour/day asked by the user to repeat for recurrence. + event_date = event_date.astimezone(timezone) # transform "+hh:mm" timezone + rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date, forceset=True, tzinfos={}) recurring_meetings = self.search([('recurrent_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]) for meeting in recurring_meetings: rset1._exdate.append(todate(meeting.recurrent_id_date)) - return [d.astimezone(pytz.UTC) for d in rset1] + return [d.astimezone(pytz.UTC) if d.tzinfo else d for d in rset1] @api.multi def _get_recurrency_end_date(self): diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index d64daf876a3..06786354376 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -208,8 +208,11 @@ class MrpProduction(models.Model): @api.depends('move_raw_ids.quantity_done', 'move_finished_ids.quantity_done') def _compute_post_visible(self): for order in self: - order.post_visible = any(order.move_raw_ids.filtered(lambda x: (x.quantity_done) > 0 and (x.state not in ['done', 'cancel']))) or \ - any(order.move_finished_ids.filtered(lambda x: (x.quantity_done) > 0 and (x.state not in ['done', 'cancel']))) + if order.product_tmpl_id._is_cost_method_standard(): + order.post_visible = any((x.quantity_done > 0 and x.state not in ['done', 'cancel']) for x in order.move_raw_ids) or \ + any((x.quantity_done > 0 and x.state not in ['done' 'cancel']) for x in order.move_finished_ids) + else: + order.post_visible = any((x.quantity_done > 0 and x.state not in ['done' 'cancel']) for x in order.move_finished_ids) @api.multi @api.depends('workorder_ids.state', 'move_finished_ids') diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index c661b0c5151..df931c012c0 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -369,7 +369,7 @@ class ResourceCalendar(models.Model): resource_id=None, default_interval=None): hours = 0.0 for day in rrule.rrule(rrule.DAILY, dtstart=start_dt, - until=(end_dt + timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0), + until=end_dt.replace(hour=23, minute=59, second=59, microsecond=999999), byweekday=self.get_weekdays()): day_start_dt = day.replace(hour=0, minute=0, second=0, microsecond=0) if start_dt and day.date() == start_dt.date(): diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index c3386476adb..9191c1dc948 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -418,6 +418,9 @@ class ProductTemplate(models.Model): relation="stock.location.route", string="Category Routes", related='categ_id.total_route_ids') + def _is_cost_method_standard(self): + return True + def _compute_quantities(self): res = self._compute_quantities_dict() for template in self: diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py index 20de2d25775..8453a49b4e3 100644 --- a/addons/stock/models/stock_scrap.py +++ b/addons/stock/models/stock_scrap.py @@ -66,6 +66,12 @@ class StockScrap(models.Model): scrap.do_scrap() return scrap + @api.multi + def unlink(self): + if 'done' in self.mapped('state'): + raise UserError(_('You cannot delete a scrap which is done.')) + return super(StockScrap, self).unlink() + def _get_origin_moves(self): return self.picking_id and self.picking_id.move_lines.filtered(lambda x: x.product_id == self.product_id) diff --git a/addons/stock/security/ir.model.access.csv b/addons/stock/security/ir.model.access.csv index 17993221052..655a5549fa0 100644 --- a/addons/stock/security/ir.model.access.csv +++ b/addons/stock/security/ir.model.access.csv @@ -75,3 +75,7 @@ access_barcode_rule_stock_manager,barcode.rule.stock.manager,barcodes.model_barc access_stock_forecast_user,report.stock.forecast.user,model_report_stock_forecast,stock.group_stock_user,1,0,0,0 access_stock_forecast_manager,report.stock.forecast.manager,model_report_stock_forecast,stock.group_stock_manager,1,1,1,1 access_stock_scrap_user,stock.scrap.user,model_stock_scrap,stock.group_stock_user,1,1,1,0 +access_product_attribute_manager,product.attribute manager,product.model_product_attribute,stock.group_stock_manager,1,1,1,1 +access_product_attribute_value_manager,product.attribute manager value,product.model_product_attribute_value,stock.group_stock_manager,1,1,1,1 +access_product_attribute_price_manager,product.attribute manager price,product.model_product_attribute_price,stock.group_stock_manager,1,1,1,1 +access_product_attribute_line_manager,product.attribute manager line,product.model_product_attribute_line,stock.group_stock_manager,1,1,1,1 diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index 1e4ac7ffbe1..1b15d2aa066 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -51,6 +51,9 @@ class ProductTemplate(models.Model): def _compute_cost_method(self): self.cost_method = self.property_cost_method or self.categ_id.property_cost_method + def _is_cost_method_standard(self): + return self.property_cost_method == 'standard' + @api.one def _set_cost_method(self): return self.write({'property_cost_method': self.cost_method}) diff --git a/addons/website_event_sale/static/src/js/website.tour.event_sale.js b/addons/website_event_sale/static/src/js/website.tour.event_sale.js index de23a9b4b67..327afe03a56 100644 --- a/addons/website_event_sale/static/src/js/website.tour.event_sale.js +++ b/addons/website_event_sale/static/src/js/website.tour.event_sale.js @@ -75,7 +75,7 @@ tour.register('event_buy_tickets', { trigger: 'a[href="/shop/confirm_order"]:contains("Confirm")', }, { - content: "Check that the subtotal is 5,500.00", + content: "Check that the subtotal is 5,500.00 USD", // this test will fail if the currency of the main company is not USD trigger: '#order_total_untaxed .oe_currency_value:contains("5,500.00")', run: function () {}, // it's a check },