diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6dcf73892e5..12f9449c5f2 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -57,7 +57,8 @@ class AccountMove(models.Model): total_amount += amount for partial_line in (line.matched_debit_ids + line.matched_credit_ids): total_reconciled += partial_line.amount - if float_is_zero(total_amount, precision_rounding=move.currency_id.rounding): + precision_currency = move.currency_id or move.company_id.currency_id + if float_is_zero(total_amount, precision_rounding=precision_currency.rounding): move.matched_percentage = 1.0 else: move.matched_percentage = total_reconciled / total_amount diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py index aeff7ce574a..bbf1177a02d 100644 --- a/addons/stock/models/stock_warehouse.py +++ b/addons/stock/models/stock_warehouse.py @@ -151,11 +151,14 @@ class Warehouse(models.Model): # If another partner assigned if vals.get('partner_id'): warehouses._update_partner_data(vals['partner_id'], vals.get('company_id')) + res = super(Warehouse, self).write(vals) # check if we need to delete and recreate route if vals.get('reception_steps') or vals.get('delivery_steps'): - warehouses._update_routes() + route_vals = warehouses._update_routes() + if route_vals: + self.write(route_vals) if vals.get('resupply_wh_ids') and not vals.get('resupply_route_ids'): for warehouse in warehouses: @@ -560,12 +563,19 @@ class Warehouse(models.Model): # change the default source and destination location and (de)activate picking types self._update_picking_type() # update delivery route and rules: unlink the existing rules of the warehouse delivery route and recreate it - self._create_or_update_delivery_route(routes_data) + delivery_route = self._create_or_update_delivery_route(routes_data) # update receipt route and rules: unlink the existing rules of the warehouse receipt route and recreate it - self._create_or_update_reception_route(routes_data) - self._create_or_update_crossdock_route(routes_data) - self._create_or_update_mto_pull(routes_data) - return True + reception_route = self._create_or_update_reception_route(routes_data) + crossdock_route = self._create_or_update_crossdock_route(routes_data) + mto_pull = self._create_or_update_mto_pull(routes_data) + + return { + 'route_ids': [(4, route.id) for route in reception_route | delivery_route | crossdock_route], + 'mto_pull_id': mto_pull.id, + 'reception_route_id': reception_route.id, + 'delivery_route_id': delivery_route.id, + 'crossdock_route_id': crossdock_route.id, + } @api.one def _update_picking_type(self): diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js index 3c80e5c08e3..06f1ee0a4cb 100644 --- a/addons/web/static/src/js/views/form_widgets.js +++ b/addons/web/static/src/js/views/form_widgets.js @@ -1258,9 +1258,40 @@ var FieldBinaryFile = FieldBinary.extend({ }); } }, + /** + * Render the value of the binary file field + * + * The value depends on the mode (readonly/edit) and the attribute filename + * in the xml node of the field: + * + * + * with filename without filename + * [------------------|-----------------------] + * readonly: | saved filename | binary size | + * edit: | current filename | base64 representation | + * [------------------|-----------------------] + * + * + * This is how the filename is retrieved: + * + * - Suppose that the binary field is named 'data' + * - The xml node of this field is as follow: + * + * `` + * + * - 'fdata' is another field whose value is the filename + * - On the following record: + * + * `{data: "Cg==1das02fa01", fdata: 'my-file.txt'}` + * + * - The content of the file is the value of 'data': Cg==1das02fa01 + * - The filename is the value of 'fdata': my-file.txt + */ render_value: function() { - var filename = this.view.datarecord[this.node.attrs.filename]; + var filename; if (this.get("effective_readonly")) { + // Filename from saved state (might render from a discard operation) + filename = this.view.datarecord[this.node.attrs.filename]; // do not forward-port >= 11.0 this.do_toggle(!!this.get('value')); if (this.get('value')) { this.$el.empty().append($("").addClass('fa fa-download')); @@ -1274,6 +1305,9 @@ var FieldBinaryFile = FieldBinary.extend({ } } } else { + // Filename at the moment (might be unsaved state) + var filenameField = this.field_manager.fields[this.node.attrs.filename]; // do not forward-port >= 11.0 + filename = filenameField ? filenameField.get('value') : ''; if(this.get('value')) { this.$el.children().removeClass('o_hidden'); this.$('.o_select_file_button').first().addClass('o_hidden'); diff --git a/odoo/netsvc.py b/odoo/netsvc.py index ee961529c70..0c64ebe51aa 100644 --- a/odoo/netsvc.py +++ b/odoo/netsvc.py @@ -139,6 +139,13 @@ def init_logger(): if dirname and not os.path.isdir(dirname): os.makedirs(dirname) if tools.config['logrotate'] is not False: + if tools.config['workers'] > 1: + # TODO: fallback to regular file logging in master for safe(r) defaults? + # + # Doing so here would be a good idea but also might break + # situations were people do log-shipping of rotated data? + _logger.warn("WARNING: built-in log rotation is not reliable in multi-worker scenarios and may incur significant data loss. " + "It is strongly recommended to use an external log rotation utility or use system loggers (--syslog) instead.") handler = logging.handlers.TimedRotatingFileHandler(filename=logf, when='D', interval=1, backupCount=30) elif os.name == 'posix': handler = logging.handlers.WatchedFileHandler(logf)