diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py
index d48ef6e8cd9..da87d2edc0f 100644
--- a/addons/crm/models/crm_lead.py
+++ b/addons/crm/models/crm_lead.py
@@ -928,7 +928,7 @@ class Lead(models.Model):
result['activity']['today'] += 1
if date.today() <= date_deadline <= date.today() + timedelta(days=7):
result['activity']['next_7_days'] += 1
- if date_deadline < date.today():
+ if date_deadline < date.today() and not opp.date_closed:
result['activity']['overdue'] += 1
# Won in Opportunities
if opp.date_closed and opp.stage_id.probability == 100:
diff --git a/addons/hr_attendance/models/hr_attendance.py b/addons/hr_attendance/models/hr_attendance.py
index c373bbe23f4..76d442a4b67 100644
--- a/addons/hr_attendance/models/hr_attendance.py
+++ b/addons/hr_attendance/models/hr_attendance.py
@@ -68,7 +68,7 @@ class HrAttendance(models.Model):
('check_in', '<=', attendance.check_in),
('id', '!=', attendance.id),
], order='check_in desc', limit=1)
- if last_attendance_before_check_in and last_attendance_before_check_in.check_out and last_attendance_before_check_in.check_out >= attendance.check_in:
+ if last_attendance_before_check_in and last_attendance_before_check_in.check_out and last_attendance_before_check_in.check_out > attendance.check_in:
raise exceptions.ValidationError(_("Cannot create new attendance record for %(empl_name)s, the employee was already checked in on %(datetime)s") % {
'empl_name': attendance.employee_id.name,
'datetime': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(attendance.check_in))),
diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py
index f2f1545a82e..e87be516e21 100644
--- a/addons/hr_expense/models/hr_expense.py
+++ b/addons/hr_expense/models/hr_expense.py
@@ -299,6 +299,13 @@ class HrExpense(models.Model):
})
return account_move
+ @api.multi
+ def unlink(self):
+ for expense in self:
+ if expense.state in ['done']:
+ raise UserError(_('You cannot delete a posted expense.'))
+ super(HrExpense, self).unlink()
+
@api.multi
def action_get_attachment_view(self):
self.ensure_one()
@@ -441,8 +448,8 @@ class HrExpenseSheet(models.Model):
@api.multi
def unlink(self):
for expense in self:
- if expense.state == "post":
- raise UserError(_("You cannot delete a posted expense."))
+ if expense.state in ['post', 'done']:
+ raise UserError(_('You cannot delete a posted or paid expense.'))
super(HrExpenseSheet, self).unlink()
@api.multi
diff --git a/addons/hr_expense/security/ir_rule.xml b/addons/hr_expense/security/ir_rule.xml
index e86d91211d8..61aba78d7ed 100644
--- a/addons/hr_expense/security/ir_rule.xml
+++ b/addons/hr_expense/security/ir_rule.xml
@@ -26,26 +26,6 @@
['|',('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]
-
- Expense Report Prevent Delete Employee
-
- [('state', '=', 'submit')]
-
-
-
-
-
-
-
- Expense Report Authorize Delete Officer
-
- [(1, '=', 1)]
-
-
-
-
-
-
diff --git a/addons/l10n_fr/migrations/9.0.1.1/post-migrate_tags_on_taxes.py b/addons/l10n_fr/migrations/9.0.1.1/post-migrate_tags_on_taxes.py
new file mode 100644
index 00000000000..6f933404f1d
--- /dev/null
+++ b/addons/l10n_fr/migrations/9.0.1.1/post-migrate_tags_on_taxes.py
@@ -0,0 +1,7 @@
+from openerp.modules.registry import RegistryManager
+
+def migrate(cr, version):
+ registry = RegistryManager.get(cr.dbname)
+ from openerp.addons.account.models.chart_template import migrate_tags_on_taxes
+ migrate_tags_on_taxes(cr, registry)
+
diff --git a/addons/l10n_fr/migrations/9.0.1.1/pre-set_tags_and_taxes_updatable.py b/addons/l10n_fr/migrations/9.0.1.1/pre-set_tags_and_taxes_updatable.py
new file mode 100644
index 00000000000..586ae984b8c
--- /dev/null
+++ b/addons/l10n_fr/migrations/9.0.1.1/pre-set_tags_and_taxes_updatable.py
@@ -0,0 +1,7 @@
+from openerp.modules.registry import RegistryManager
+
+def migrate(cr, version):
+ registry = RegistryManager.get(cr.dbname)
+ from openerp.addons.account.models.chart_template import migrate_set_tags_and_taxes_updatable
+ migrate_set_tags_and_taxes_updatable(cr, registry, 'l10n_fr')
+
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index 1f59087a2c2..bfc48ef2072 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -340,6 +340,7 @@ class MrpProduction(models.Model):
source_location = self.location_src_id
original_quantity = self.product_qty - self.qty_produced
data = {
+ 'sequence': bom_line.sequence,
'name': self.name,
'date': self.date_planned_start,
'date_expected': self.date_planned_start,
diff --git a/addons/stock/models/stock_pack_operation.py b/addons/stock/models/stock_pack_operation.py
index edeba5e2c7b..a9116730e5c 100644
--- a/addons/stock/models/stock_pack_operation.py
+++ b/addons/stock/models/stock_pack_operation.py
@@ -34,6 +34,9 @@ class PackOperation(models.Model):
product_qty = fields.Float('To Do', default=0.0, digits=dp.get_precision('Product Unit of Measure'), required=True)
ordered_qty = fields.Float('Ordered Quantity', digits=dp.get_precision('Product Unit of Measure'))
qty_done = fields.Float('Done', default=0.0, digits=dp.get_precision('Product Unit of Measure'))
+ qty_done_uom_ordered = fields.Float(
+ 'Quantity Done', digits=dp.get_precision('Product Unit of Measure'), compute='_compute_qty_done_uom_ordered',
+ help='Quantity done in UOM ordered')
is_done = fields.Boolean(compute='_compute_is_done', string='Done', readonly=False, oldname='processed_boolean')
package_id = fields.Many2one('stock.quant.package', 'Source Package')
pack_lot_ids = fields.One2many('stock.pack.operation.lot', 'operation_id', 'Lots/Serial Numbers Used')
@@ -126,6 +129,14 @@ class PackOperation(models.Model):
else:
self.lots_visible = self.product_id.tracking != 'none'
+ @api.multi
+ def _compute_qty_done_uom_ordered(self):
+ for pack in self:
+ if pack.product_uom_id and pack.linked_move_operation_ids:
+ pack.qty_done_uom_ordered = pack.product_uom_id._compute_quantity(pack.qty_done, pack.linked_move_operation_ids[0].move_id.product_uom)
+ else:
+ pack.qty_done_uom_ordered = pack.qty_done
+
@api.onchange('pack_lot_ids')
def _onchange_packlots(self):
self.qty_done = sum([x.qty for x in self.pack_lot_ids])
diff --git a/addons/stock/report/report_deliveryslip.xml b/addons/stock/report/report_deliveryslip.xml
index 305bea7b34b..79814492932 100644
--- a/addons/stock/report/report_deliveryslip.xml
+++ b/addons/stock/report/report_deliveryslip.xml
@@ -125,11 +125,16 @@
-
+
-
-
+
+
+
+
+
+
+
|
diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml
index a7692d25b61..a1d7cf41f0a 100644
--- a/addons/website_sale/views/templates.xml
+++ b/addons/website_sale/views/templates.xml
@@ -201,7 +201,7 @@
-
+
No product defined.
Click 'New' in the top-right corner to create your first product.
@@ -413,8 +413,8 @@
-
-
+
+
@@ -434,10 +434,10 @@
-
-
+
-
-
+
-
diff --git a/addons/website_sale_delivery/static/src/js/website_sale_delivery.js b/addons/website_sale_delivery/static/src/js/website_sale_delivery.js
index 46caab18e0e..0775b7657cc 100644
--- a/addons/website_sale_delivery/static/src/js/website_sale_delivery.js
+++ b/addons/website_sale_delivery/static/src/js/website_sale_delivery.js
@@ -1,8 +1,14 @@
$(document).ready(function () {
- // When choosing an delivery carrier, update the quotation and the acquirers
+ var $pay_button = $('.oe_sale_acquirer_button button');
+ $pay_button.prop('disabled', false);
+
+ // When choosing an delivery carrier, update the quotation and the acquirers. Disable the 'Pay
+ // Now' button to avoid being redirected to payment acquier if the delivery carrier update is
+ // not over.
var $carrier = $("#delivery_carrier");
$carrier.find("input[name='delivery_type']").click(function (ev) {
+ $pay_button.prop('disabled', true);
var carrier_id = $(ev.currentTarget).val();
window.location.href = '/shop/payment?carrier_id=' + carrier_id;
});
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index a71e76a8033..0ec5dbb9764 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -1532,7 +1532,9 @@ class IrModelData(models.Model):
if model == 'ir.model.fields':
# Don't remove the LOG_ACCESS_COLUMNS unless _log_access
# has been turned off on the model.
- field = self.env[model].browse(res_id)
+ field = self.env[model].browse(res_id).with_context(
+ prefetch_fields=False,
+ )
if not field.exists():
_logger.info('Deleting orphan external_ids %s', external_ids)
external_ids.unlink()
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index ff45b8d8978..77d27b67868 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -383,11 +383,12 @@ try:
# TODO when xlsxwriter bump to 0.9.8, add worksheet_class=None parameter instead of kw
def add_worksheet(self, name=None, **kw):
- # invalid Excel character: []:*?/\
- name = re.sub(r'[\[\]:*?/\\]', '', name)
+ if name:
+ # invalid Excel character: []:*?/\
+ name = re.sub(r'[\[\]:*?/\\]', '', name)
- # maximum size is 31 characters
- name = name[:31]
+ # maximum size is 31 characters
+ name = name[:31]
return super(PatchedXlsxWorkbook, self).add_worksheet(name, **kw)
xlsxwriter.Workbook = PatchedXlsxWorkbook
diff --git a/odoo/tools/sql.py b/odoo/tools/sql.py
index 563ed08c679..239cee73fd1 100644
--- a/odoo/tools/sql.py
+++ b/odoo/tools/sql.py
@@ -23,7 +23,7 @@ _CONFDELTYPES = {
def table_exists(cr, tablename):
""" Return whether the given table exists. """
- query = "SELECT 1 FROM information_schema.tables WHERE table_name=%s"
+ query = "SELECT 1 FROM pg_class WHERE relkind IN ('r', 'v', 'm') AND relname=%s"
cr.execute(query, (tablename,))
return cr.rowcount