diff --git a/addons/account/static/src/js/account_reconciliation_widgets.js b/addons/account/static/src/js/account_reconciliation_widgets.js
index 54ff55fcdcc..01e1ebeb901 100644
--- a/addons/account/static/src/js/account_reconciliation_widgets.js
+++ b/addons/account/static/src/js/account_reconciliation_widgets.js
@@ -763,7 +763,9 @@ var abstractReconciliationLine = Widget.extend({
else if (preset_line.amount_type === "percentage") {
self.amount_field.set_value(0);
self.updateBalance();
- self.amount_field.set_value(-1 * self.get("balance") * preset_line.amount / 100);
+ var currency_dict = session.get_currency(self.get("currency_id"));
+ var preset_amount = utils.round_currency(currency_dict, -1 * self.get("balance") * preset_line.amount / 100);
+ self.amount_field.set_value(preset_amount);
}
}
},
diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py
index b2cee19bb1b..5aa384f3ae3 100644
--- a/addons/crm/models/crm_lead.py
+++ b/addons/crm/models/crm_lead.py
@@ -921,7 +921,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 b2cee749965..4230cee751e 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_related,
'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 39bcffd1c82..cab8df147a6 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 b9a37b99f5b..4cd0730c9ab 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/web/static/src/js/framework/utils.js b/addons/web/static/src/js/framework/utils.js
index e19246823c5..0dc66c6817f 100644
--- a/addons/web/static/src/js/framework/utils.js
+++ b/addons/web/static/src/js/framework/utils.js
@@ -350,6 +350,15 @@ function round_decimals (value, decimals) {
return round_precision(value, Math.pow(10,-decimals));
}
+/* Rounds a value according to a currency's digits
+ * @param {dict} The dict containing the currency's info, usually retrieved with session.get_currency
+ * @param {Number} The value to be rounded
+ */
+function round_currency(currency_dict, value) {
+ var digits = currency_dict && currency_dict.digits[1] || 4;
+ return round_decimals(value, digits);
+}
+
function float_is_zero (value, decimals) {
var epsilon = Math.pow(10, -decimals);
return Math.abs(round_precision(value, epsilon)) < epsilon;
@@ -516,6 +525,7 @@ return {
human_number: human_number,
round_precision: round_precision,
round_decimals: round_decimals,
+ round_currency: round_currency,
float_is_zero: float_is_zero,
confine: confine,
assert: assert,
diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml
index d7e94fc8736..8a04d392590 100644
--- a/addons/website_sale/views/templates.xml
+++ b/addons/website_sale/views/templates.xml
@@ -199,7 +199,7 @@
-
+
No product defined.
Click 'New' in the top-right corner to create your first product.
@@ -411,8 +411,8 @@
-
-
+
+
@@ -432,10 +432,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 b958fc9eb25..d2a53042751 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -1307,7 +1307,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/models.py b/odoo/models.py
index c459d2675c1..db807f9abb3 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -2601,7 +2601,7 @@ class BaseModel(object):
@api.model_cr
def _table_exist(self):
- query = "SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s"
+ query = "SELECT relname FROM pg_class WHERE relkind IN ('r','v','m') AND relname=%s"
self._cr.execute(query, (self._table,))
return self._cr.rowcount
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index 19470b07b00..ca20ab3278b 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -372,11 +372,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