diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 46db7021f41..f3243ecfafe 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -241,7 +241,7 @@ class AccountBankStatement(models.Model): for aml in st_line.journal_entry_ids: moves |= aml.move_id if moves: - moves.post() + moves.filtered(lambda m: m.state != 'posted').post() statement.message_post(body=_('Statement %s confirmed, journal items were created.') % (statement.name,)) statements.link_bank_to_partner() statements.write({'state': 'confirm', 'date_done': time.strftime("%Y-%m-%d %H:%M:%S")}) diff --git a/addons/account/wizard/wizard_tax_adjustments.py b/addons/account/wizard/wizard_tax_adjustments.py index 8c5002347c0..22d2235ef04 100644 --- a/addons/account/wizard/wizard_tax_adjustments.py +++ b/addons/account/wizard/wizard_tax_adjustments.py @@ -18,24 +18,26 @@ class TaxAdjustments(models.TransientModel): debit_account_id = fields.Many2one('account.account', string='Debit account', required=True, domain=[('deprecated', '=', False)]) credit_account_id = fields.Many2one('account.account', string='Credit account', required=True, domain=[('deprecated', '=', False)]) amount = fields.Monetary(currency_field='company_currency_id', required=True) + adjustment_type = fields.Selection([('debit', 'Adjustment in favor of the Estate'), ('credit', 'Adjustment in your favor')], string="Adjustment Type", store=False, required=True) company_currency_id = fields.Many2one('res.currency', readonly=True, default=lambda self: self.env.user.company_id.currency_id) tax_id = fields.Many2one('account.tax', string='Adjustment Tax', ondelete='restrict', domain=[('type_tax_use', '=', 'none'), ('tax_adjustment', '=', True)], required=True) @api.multi def _create_move(self): + adjustment_type = self.env.context.get('adjustment_type', (self.amount > 0.0 and 'debit' or 'credit')) debit_vals = { 'name': self.reason, - 'debit': self.amount, + 'debit': abs(self.amount), 'credit': 0.0, 'account_id': self.debit_account_id.id, - 'tax_line_id': self.tax_id.id, + 'tax_line_id': adjustment_type == 'debit' and self.tax_id.id or False, } credit_vals = { 'name': self.reason, 'debit': 0.0, - 'credit': self.amount, + 'credit': abs(self.amount), 'account_id': self.credit_account_id.id, - 'tax_line_id': self.tax_id.id, + 'tax_line_id': adjustment_type == 'credit' and self.tax_id.id or False, } vals = { 'journal_id': self.journal_id.id, @@ -48,6 +50,13 @@ class TaxAdjustments(models.TransientModel): return move.id @api.multi + def create_move_debit(self): + return self.with_context(adjustment_type='debit').create_move() + + @api.multi + def create_move_credit(self): + return self.with_context(adjustment_type='credit').create_move() + def create_move(self): #create the adjustment move move_id = self._create_move() diff --git a/addons/account/wizard/wizard_tax_adjustments_view.xml b/addons/account/wizard/wizard_tax_adjustments_view.xml index 3d4ed0a9e9a..dba164388b9 100644 --- a/addons/account/wizard/wizard_tax_adjustments_view.xml +++ b/addons/account/wizard/wizard_tax_adjustments_view.xml @@ -12,6 +12,7 @@ + @@ -26,8 +27,14 @@ diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py index 78cd786cda8..52d2c48a0d9 100644 --- a/addons/account_asset/models/account_asset.py +++ b/addons/account_asset/models/account_asset.py @@ -411,7 +411,7 @@ class AccountAssetAsset(models.Model): @api.model def create(self, vals): asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals) - asset.compute_depreciation_board() + asset.sudo().compute_depreciation_board() return asset @api.multi diff --git a/addons/hr_timesheet/report/report_timesheet_templates.xml b/addons/hr_timesheet/report/report_timesheet_templates.xml index 141eb0511e8..c706143dd93 100644 --- a/addons/hr_timesheet/report/report_timesheet_templates.xml +++ b/addons/hr_timesheet/report/report_timesheet_templates.xml @@ -36,7 +36,7 @@ - + @@ -72,4 +72,4 @@ name="hr_timesheet.report_timesheet" file="report_timesheet" /> - \ No newline at end of file + diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index 72c02fc5aed..515dd3bcd1c 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -109,7 +109,7 @@ class PaymentTransactionStripe(models.Model): @api.multi def stripe_s2s_do_transaction(self, **kwargs): self.ensure_one() - result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref) + result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref, email=self.partner_email) return self._stripe_s2s_validate_tree(result) @api.model diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 6e12dc8b114..25b31fd0b8f 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1152,7 +1152,8 @@ exports.Orderline = Backbone.Model.extend({ if (unit.rounding) { this.quantity = round_pr(quant, unit.rounding); var decimals = this.pos.dp['Product Unit of Measure']; - this.quantityStr = formats.format_value(round_di(this.quantity, decimals), { type: 'float', digits: [69, decimals]}); + this.quantity = round_di(this.quantity, decimals) + this.quantityStr = formats.format_value(this.quantity, { type: 'float', digits: [69, decimals]}); } else { this.quantity = round_pr(quant, 1); this.quantityStr = this.quantity.toFixed(0); diff --git a/addons/pos_mercury/data/pos_mercury_demo.xml b/addons/pos_mercury/data/pos_mercury_demo.xml index 5ff1a0d70e4..b242868f8df 100644 --- a/addons/pos_mercury/data/pos_mercury_demo.xml +++ b/addons/pos_mercury/data/pos_mercury_demo.xml @@ -5,8 +5,8 @@ Mercury Demo - 334160 - 81303DUR + 755847002 + xyz diff --git a/addons/pos_mercury/models/pos_mercury.py b/addons/pos_mercury/models/pos_mercury.py index 707f85692e0..6af9d437af9 100644 --- a/addons/pos_mercury/models/pos_mercury.py +++ b/addons/pos_mercury/models/pos_mercury.py @@ -4,6 +4,7 @@ import logging from odoo import models, fields, api, _ +from odoo.tools.float_utils import float_compare _logger = logging.getLogger(__name__) @@ -71,8 +72,9 @@ class PosOrder(models.Model): statement_id = super(PosOrder, self).add_payment(data) statement_lines = self.env['account.bank.statement.line'].search([('statement_id', '=', statement_id), ('pos_statement_id', '=', self.id), - ('journal_id', '=', data['journal']), - ('amount', '=', data['amount'])]) + ('journal_id', '=', data['journal'])]) + statement_lines = statement_lines.filtered(lambda line: float_compare(line.amount, data['amount'], + precision_rounding=line.journal_currency_id.rounding) == 0) # we can get multiple statement_lines when there are >1 credit # card payments with the same amount. In that case it doesn't diff --git a/addons/pos_mercury/models/pos_mercury_transaction.py b/addons/pos_mercury/models/pos_mercury_transaction.py index cca78872ac5..4d8da0b9a98 100644 --- a/addons/pos_mercury/models/pos_mercury_transaction.py +++ b/addons/pos_mercury/models/pos_mercury_transaction.py @@ -63,7 +63,11 @@ class MercuryTransaction(models.Model): 'SOAPAction': 'http://www.mercurypay.com/CreditTransaction', } - r = urllib2.Request('https://w1.mercurypay.com/ws/ws.asmx', data=xml_transaction, headers=headers) + url = 'https://w1.mercurypay.com/ws/ws.asmx' + if self.env['ir.config_parameter'].sudo().get_param('pos_mercury.enable_test_env'): + url = 'https://w1.mercurycert.net/ws/ws.asmx' + + r = urllib2.Request(url, data=xml_transaction, headers=headers) try: u = urllib2.urlopen(r, timeout=65) response = werkzeug.utils.unescape(u.read()) diff --git a/addons/sale/models/account_invoice.py b/addons/sale/models/account_invoice.py index 1ed8cda461b..a0b1a51cde1 100644 --- a/addons/sale/models/account_invoice.py +++ b/addons/sale/models/account_invoice.py @@ -39,6 +39,9 @@ class AccountInvoice(models.Model): def _onchange_delivery_address(self): addr = self.partner_id.address_get(['delivery']) self.partner_shipping_id = addr and addr.get('delivery') + if self.env.context.get('type', 'out_invoice') == 'out_invoice': + company = self.company_id or self.env.user.company_id + self.comment = company.with_context(lang=self.partner_id.lang).sale_note @api.multi def action_invoice_paid(self): diff --git a/addons/stock/wizard/make_procurement.py b/addons/stock/wizard/make_procurement.py index 3ae8f6d6bf8..3bed9047bd9 100644 --- a/addons/stock/wizard/make_procurement.py +++ b/addons/stock/wizard/make_procurement.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import datetime from odoo import api, fields, models - class MakeProcurement(models.TransientModel): _name = 'make.procurement' _description = 'Make Procurements' @@ -64,9 +64,14 @@ class MakeProcurement(models.TransientModel): """ Creates procurement order for selected product. """ ProcurementOrder = self.env['procurement.order'] for wizard in self: + # we set the time to noon to avoid the date to be changed because of timezone issues + date = fields.Datetime.from_string(wizard.date_planned) + date = date + datetime.timedelta(hours=12) + date = fields.Datetime.to_string(date) + procurement = ProcurementOrder.create({ 'name': 'INT: %s' % (self.env.user.login), - 'date_planned': wizard.date_planned, + 'date_planned': date, 'product_id': wizard.product_id.id, 'product_qty': wizard.qty, 'product_uom': wizard.uom_id.id, diff --git a/addons/stock_calendar/models/stock.py b/addons/stock_calendar/models/stock.py index 9ed605cda30..88121065d7e 100644 --- a/addons/stock_calendar/models/stock.py +++ b/addons/stock_calendar/models/stock.py @@ -54,7 +54,7 @@ class StockWarehouseOrderpoint(models.Model): date = interval[1] res_intervals += [(date, group), ] else: - return [(now_date, None)] + return [(False, None)] return res_intervals def _get_previous_dates(self, start_date=False): diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py index a1223d896c8..5e5c88031c7 100644 --- a/addons/stock_landed_costs/models/stock_landed_cost.py +++ b/addons/stock_landed_costs/models/stock_landed_cost.py @@ -85,11 +85,13 @@ class LandedCost(models.Model): raise UserError(_('Cost and adjustments lines do not match. You should maybe recompute the landed costs.')) for cost in self: - move = self.env['account.move'].create({ + move = self.env['account.move'] + move_vals = { 'journal_id': cost.account_journal_id.id, 'date': cost.date, - 'ref': cost.name - }) + 'ref': cost.name, + 'line_ids': [], + } for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id): per_unit = line.final_cost / line.quantity diff = per_unit - line.former_cost_per_unit @@ -134,8 +136,9 @@ class LandedCost(models.Model): for quant in line.move_id.quant_ids: if quant.location_id.usage != 'internal': qty_out += quant.qty - line._create_accounting_entries(move, qty_out) - move.assert_balanced() + move_vals['line_ids'] += line._create_accounting_entries(move, qty_out) + + move = move.create(move_vals) cost.write({'state': 'done', 'account_move_id': move.id}) move.post() return True @@ -336,11 +339,10 @@ class AdjustmentLines(models.Model): Generate the account.move.line values to track the landed cost. Afterwards, for the goods that are already out of stock, we should create the out moves """ - AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False, recompute=False) + AccountMoveLine = [] base_line = { 'name': self.name, - 'move_id': move.id, 'product_id': self.product_id.id, 'quantity': self.quantity, } @@ -354,8 +356,8 @@ class AdjustmentLines(models.Model): # negative cost, reverse the entry debit_line['credit'] = -diff credit_line['debit'] = -diff - AccountMoveLine.create(debit_line) - AccountMoveLine.create(credit_line) + AccountMoveLine.append([0, 0, debit_line]) + AccountMoveLine.append([0, 0, credit_line]) # Create account move lines for quants already out of stock if qty_out > 0: @@ -375,8 +377,8 @@ class AdjustmentLines(models.Model): # negative cost, reverse the entry debit_line['credit'] = -diff credit_line['debit'] = -diff - AccountMoveLine.create(debit_line) - AccountMoveLine.create(credit_line) + AccountMoveLine.append([0, 0, debit_line]) + AccountMoveLine.append([0, 0, credit_line]) # TDE FIXME: oh dear if self.env.user.company_id.anglo_saxon_accounting: @@ -396,7 +398,7 @@ class AdjustmentLines(models.Model): # negative cost, reverse the entry debit_line['credit'] = -diff credit_line['debit'] = -diff - AccountMoveLine.create(debit_line) - AccountMoveLine.create(credit_line) + AccountMoveLine.append([0, 0, debit_line]) + AccountMoveLine.append([0, 0, credit_line]) - return True + return AccountMoveLine diff --git a/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js b/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js index 8619c44a7d6..304845a0fee 100644 --- a/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js +++ b/addons/web/static/lib/bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js @@ -391,18 +391,14 @@ THE SOFTWARE. if (picker.options.calendarWeeks === true) { html.append('#'); } - if (moment().localeData()._week.dow === 0) { // starts on Sunday - for (i = 0; i < 7; i++) { - html.append('' + weekdaysMin[i] + ''); - } - } else { - for (i = 1; i < 8; i++) { - if (i === 7) { - html.append('' + weekdaysMin[0] + ''); - } else { - html.append('' + weekdaysMin[i] + ''); - } - } + // ODOO change so week starting not on sunday/monday have correct + // day name. This is solved in saas-15 by using new library version + var startDay = moment().localeData()._week.dow; + if (startDay === undefined) { + startDay = 1; + } + for (i = startDay; i < startDay + 7; i++) { + html.append('' + weekdaysMin[i % 7] + ''); } picker.widget.find('.datepicker-days thead').append(html); }, diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js index f5ed3b2e806..1ee3ea65ed1 100644 --- a/addons/web_calendar/static/src/js/web_calendar.js +++ b/addons/web_calendar/static/src/js/web_calendar.js @@ -920,9 +920,10 @@ var CalendarView = View.extend({ } } else { + var res_id = parseInt(id).toString() === id ? parseInt(id) : id; new form_common.FormViewDialog(this, { res_model: this.model, - res_id: parseInt(id).toString() === id ? parseInt(id) : id, + res_id: res_id, context: this.dataset.get_context(), title: title, view_id: +this.open_popup_action, @@ -934,7 +935,7 @@ var CalendarView = View.extend({ }}, {text: _t("Delete"), close: true, click: function() { - self.remove_event(id); + self.remove_event(res_id); }}, {text: _t("Close"), close: true} diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js index 2678ba955af..435c5d7fa78 100644 --- a/addons/web_editor/static/src/js/summernote.js +++ b/addons/web_editor/static/src/js/summernote.js @@ -1856,12 +1856,17 @@ $.summernote.pluginEvents.indent = function (event, editor, layoutInfo, outdent) var $dom = $(ancestor); if (!dom.isList(ancestor)) { + // to indent a selection, we indent the child nodes of the common + // ancestor that contains this selection $dom = $(dom.node(ancestor)).children(); } - if (!$dom.length) { - $dom = $(dom.ancestor(r.sc, dom.isList) || dom.ancestor(r.sc, dom.isCell)); + if (!$dom.not('br').length) { + // if selection is inside a list, we indent its list items + $dom = $(dom.ancestor(r.sc, dom.isList)); if (!$dom.length) { - $dom = $(r.sc).closest(options.styleTags.join(',')); + // if the selection is contained in a single HTML node, we indent + // the first ancestor 'content block' (P, H1, PRE, ...) or TD + $dom = $(r.sc).closest(options.styleTags.join(',')+',td'); } } diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index fd68fa704dc..3843638c8b0 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -110,7 +110,10 @@ class Website(Home): } # /page/website.XXX --> /page/XXX if page.startswith('website.'): - return request.redirect('/page/' + page[8:], code=301) + url = '/page/' + page[8:] + if request.httprequest.query_string: + url += '?' + request.httprequest.query_string + return request.redirect(url, code=301) elif '.' not in page: page = 'website.%s' % page 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 327afe03a56..d765351ed02 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 @@ -91,6 +91,7 @@ tour.register('event_buy_tickets', { { content: "Last step", trigger: '.oe_website_sale:contains("Thank you for your order")', + timeout: 30000, } ] ); diff --git a/addons/website_form/static/src/js/website_form.js b/addons/website_form/static/src/js/website_form.js index 2f91db94c9b..022156b99f7 100644 --- a/addons/website_form/static/src/js/website_form.js +++ b/addons/website_form/static/src/js/website_form.js @@ -13,7 +13,11 @@ odoo.define('website_form.animation', function (require) { snippet_animation.registry.form_builder_send = snippet_animation.Class.extend({ selector: '.s_website_form', - start: function() { + start: function(editable_mode) { + if (editable_mode) { + this.stop(); + return; + } var self = this; this.templates_loaded = ajax.loadXML('/website_form/static/src/xml/website_form.xml', qweb); this.$target.find('.o_website_form_send').on('click',function(e) {self.send(e);}); diff --git a/addons/website_sale/static/src/js/website_sale_tour_buy.js b/addons/website_sale/static/src/js/website_sale_tour_buy.js index 18db42a1270..268a4448570 100644 --- a/addons/website_sale/static/src/js/website_sale_tour_buy.js +++ b/addons/website_sale/static/src/js/website_sale_tour_buy.js @@ -76,6 +76,7 @@ tour.register('shop_buy_product', { { content: "finish", trigger: '.oe_website_sale:contains("Thank you for your order")', + timeout: 30000, } ] ); diff --git a/odoo/addons/base/module/module.py b/odoo/addons/base/module/module.py index 3e2eb4749cb..e499eb6550b 100644 --- a/odoo/addons/base/module/module.py +++ b/odoo/addons/base/module/module.py @@ -599,7 +599,7 @@ class Module(models.Model): res = [0, 0] # [update, add] default_version = modules.adapt_version('1.0') - known_mods = self.search([]) + known_mods = self.with_context(lang=None).search([]) known_mods_names = {mod.name: mod for mod in known_mods} # iterate through detected modules and update/create them in db diff --git a/odoo/addons/base/res/res_country_data.xml b/odoo/addons/base/res/res_country_data.xml index 8ff0caa1ef0..800e349bf56 100644 --- a/odoo/addons/base/res/res_country_data.xml +++ b/odoo/addons/base/res/res_country_data.xml @@ -1385,7 +1385,7 @@ Sudan sd - + diff --git a/odoo/addons/base/res/res_currency_data.xml b/odoo/addons/base/res/res_currency_data.xml index f986c0a08b8..dc864e1dc9a 100644 --- a/odoo/addons/base/res/res_currency_data.xml +++ b/odoo/addons/base/res/res_currency_data.xml @@ -1016,6 +1016,7 @@ + SDD £Sd @@ -1023,6 +1024,13 @@ + + SDG + ج.س. + 0.01 + + + LKR Rs diff --git a/odoo/addons/base/res/res_currency_demo.xml b/odoo/addons/base/res/res_currency_demo.xml index ba316d0a7db..e74fb16fda8 100644 --- a/odoo/addons/base/res/res_currency_demo.xml +++ b/odoo/addons/base/res/res_currency_demo.xml @@ -877,6 +877,12 @@ 544.44 + + + 2010-01-01 + 3.1999 + + 2010-01-01