diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-03-27 18:22:18 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-03-27 18:22:18 +0200 |
| commit | 87a0f4dc4cac8dba95081269f1859861e1f7b0b9 (patch) | |
| tree | 09567fc0b60a5bde467478fcb1eb1cadbe243328 /addons | |
| parent | 07843bd4c95b27ffccb196b3516421006c03b131 (diff) | |
| parent | b33d5af4a74e3f4ca515826d4683065e32005e85 (diff) | |
[MERGE] forward port branch 11.0 up to b33d5af4a74
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/account/models/account_journal_dashboard.py | 8 | ||||
| -rw-r--r-- | addons/account_bank_statement_import/account_bank_statement_import.py | 5 | ||||
| -rw-r--r-- | addons/mrp/models/mrp_production.py | 11 | ||||
| -rw-r--r-- | addons/mrp/models/stock_move.py | 4 | ||||
| -rw-r--r-- | addons/payment_authorize/models/authorize_request.py | 4 | ||||
| -rw-r--r-- | addons/sale_timesheet/models/account_invoice.py | 9 | ||||
| -rw-r--r-- | addons/stock/models/stock_move.py | 31 | ||||
| -rw-r--r-- | addons/stock/models/stock_move_line.py | 19 | ||||
| -rw-r--r-- | addons/stock/models/stock_picking.py | 5 | ||||
| -rw-r--r-- | addons/stock/models/stock_traceability.py | 8 | ||||
| -rw-r--r-- | addons/stock/tests/test_move.py | 37 | ||||
| -rw-r--r-- | addons/stock/tests/test_move2.py | 44 | ||||
| -rw-r--r-- | addons/stock/views/stock_picking_views.xml | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/calendar/calendar_model.js | 7 | ||||
| -rw-r--r-- | addons/web/static/tests/views/calendar_tests.js | 9 | ||||
| -rw-r--r-- | addons/website/models/ir_http.py | 10 | ||||
| -rw-r--r-- | addons/website/models/website.py | 5 | ||||
| -rw-r--r-- | addons/website_sale/views/templates.xml | 2 |
18 files changed, 183 insertions, 38 deletions
diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index a769a3f8d17..d9cf58720ea 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -219,7 +219,7 @@ class account_journal(models.Model): data as its first element, and the arguments dictionary to use to run it as its second. """ - return ("""SELECT state, residual_signed as amount_total, currency_id AS currency + return ("""SELECT state, residual_signed as amount_total, currency_id AS currency, type FROM account_invoice WHERE journal_id = %(journal_id)s AND state = 'open';""", {'journal_id':self.id}) @@ -229,7 +229,7 @@ class account_journal(models.Model): gather the bills in draft state data, and the arguments dictionary to use to run it as its second. """ - return ("""SELECT state, amount_total, currency_id AS currency + return ("""SELECT state, amount_total, currency_id AS currency, type FROM account_invoice WHERE journal_id = %(journal_id)s AND state = 'draft';""", {'journal_id':self.id}) @@ -242,7 +242,9 @@ class account_journal(models.Model): for result in results_dict: cur = self.env['res.currency'].browse(result.get('currency')) rslt_count += 1 - rslt_sum += cur.compute(result.get('amount_total'), target_currency) + + type_factor = result.get('type') in ('in_refund', 'out_refund') and -1 or 1 + rslt_sum += type_factor * cur.compute(result.get('amount_total'), target_currency) return (rslt_count, rslt_sum) @api.multi diff --git a/addons/account_bank_statement_import/account_bank_statement_import.py b/addons/account_bank_statement_import/account_bank_statement_import.py index 5fd022681aa..99fd0467418 100644 --- a/addons/account_bank_statement_import/account_bank_statement_import.py +++ b/addons/account_bank_statement_import/account_bank_statement_import.py @@ -195,7 +195,10 @@ class AccountBankStatementImport(models.TransientModel): bank_account_id = partner_bank.id partner_id = partner_bank.partner_id.id else: - bank_account_id = self.env['res.partner.bank'].create({'acc_number': line_vals['account_number']}).id + bank_account_id = self.env['res.partner.bank'].create({ + 'acc_number': line_vals['account_number'], + 'partner_id': False, + }).id line_vals['partner_id'] = partner_id line_vals['bank_account_id'] = bank_account_id diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index ae6e40ddbcd..7af68237e77 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -299,6 +299,17 @@ class MrpProduction(models.Model): self.location_src_id = self.picking_type_id.default_location_src_id.id or location.id self.location_dest_id = self.picking_type_id.default_location_dest_id.id or location.id + @api.multi + def write (self, vals): + res = super(MrpProduction, self).write(vals) + if 'date_planned_start' in vals: + moves = (self.mapped('move_raw_ids') + self.mapped('move_finished_ids')).filtered( + lambda r: r.state not in ['done', 'cancel']) + moves.write({ + 'date_expected': vals['date_planned_start'], + }) + return res + @api.model def create(self, values): if not values.get('name', False) or values['name'] == _('New'): diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index 64c2bcd22cb..1099d8b549e 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -137,12 +137,12 @@ class StockMove(models.Model): If you want to cancel this MO, please change the consumed quantities to 0.')) return super(StockMove, self)._action_cancel() - def _action_confirm(self, merge=True): + def _action_confirm(self, merge=True, merge_into=False): moves = self.env['stock.move'] for move in self: moves |= move.action_explode() # we go further with the list of ids potentially changed by action_explode - return super(StockMove, moves)._action_confirm(merge=merge) + return super(StockMove, moves)._action_confirm(merge=merge, merge_into=merge_into) def action_explode(self): """ Explodes pickings """ diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py index af710b280ba..138c270e35d 100644 --- a/addons/payment_authorize/models/authorize_request.py +++ b/addons/payment_authorize/models/authorize_request.py @@ -155,13 +155,13 @@ class AuthorizeAPI(): billTo = etree.SubElement(payment_profile, "billTo") etree.SubElement(billTo, "address").text = (partner.street or '' + (partner.street2 if partner.street2 else '')) or None - missing_fields = [partner._fields[field].string for field in ['city', 'country_id', 'zip'] if not partner[field]] + missing_fields = [partner._fields[field].string for field in ['city', 'country_id'] if not partner[field]] if missing_fields: raise ValidationError({'missing_fields': missing_fields}) etree.SubElement(billTo, "city").text = partner.city etree.SubElement(billTo, "state").text = partner.state_id.name or None - etree.SubElement(billTo, "zip").text = partner.zip + etree.SubElement(billTo, "zip").text = partner.zip or '' etree.SubElement(billTo, "country").text = partner.country_id.name or None payment = etree.SubElement(payment_profile, "payment") creditCard = etree.SubElement(payment, "creditCard") diff --git a/addons/sale_timesheet/models/account_invoice.py b/addons/sale_timesheet/models/account_invoice.py index 3c1b3b78ae0..a3f55c7b633 100644 --- a/addons/sale_timesheet/models/account_invoice.py +++ b/addons/sale_timesheet/models/account_invoice.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models, _ -from odoo.tools.float_utils import float_round +from odoo.tools.float_utils import float_round, float_is_zero class AccountInvoice(models.Model): @@ -95,8 +95,11 @@ class AccountInvoice(models.Model): if index+1 != len(no_zero_timesheet_revenue): price_subtotal_inv = invoice_line.currency_id.compute(invoice_line.price_subtotal, timesheet_line.currency_id) price_subtotal_sol = timesheet_line.so_line.currency_id.compute(timesheet_line.so_line.price_subtotal, timesheet_line.currency_id) - line_revenue = timesheet_line.timesheet_revenue * price_subtotal_inv / price_subtotal_sol - total_revenue_per_currency[timesheet_line.currency_id.id] += line_revenue + if not float_is_zero(price_subtotal_sol, precision_rounding=timesheet_line.company_currency_id.rounding): + line_revenue = timesheet_line.timesheet_revenue * price_subtotal_inv / price_subtotal_sol + total_revenue_per_currency[timesheet_line.currency_id.id] += line_revenue + else: + total_revenue_per_currency[timesheet_line.currency_id.id] += timesheet_line.timesheet_revenue else: # last line: add the difference to avoid rounding problem last_price_subtotal_inv = invoice_line.currency_id.compute(invoice_line.price_subtotal, timesheet_line.currency_id) total_revenue = sum([self.env['res.currency'].browse(currency_id).compute(amount, timesheet_line.currency_id) for currency_id, amount in total_revenue_per_currency.items()]) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 1bf167d5731..d5eecb49827 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -542,7 +542,7 @@ class StockMove(models.Model): move.product_uom.id, move.restrict_partner_id.id, move.scrapped, move.origin_returned_move_id.id ] - def _merge_moves(self): + def _merge_moves(self, merge_into=False): """ This method will, for each move in `self`, go up in their linked picking and try to find in their existing moves a candidate into which we can merge the move. :return: Recordset of moves passed to this method. If some of the passed moves were merged @@ -550,12 +550,19 @@ class StockMove(models.Model): """ distinct_fields = self._prepare_merge_moves_distinct_fields() + candidate_moves_list = [] + if not merge_into: + for picking in self.mapped('picking_id'): + candidate_moves_list.append(picking.move_lines) + else: + candidate_moves_list.append(merge_into | self) + # Move removed after merge moves_to_unlink = self.env['stock.move'] moves_to_merge = [] - for picking in self.mapped('picking_id'): + for candidate_moves in candidate_moves_list: # First step find move to merge. - for k, g in groupby(sorted(picking.move_lines, key=self._prepare_merge_move_sort_method), key=itemgetter(*distinct_fields)): + for k, g in groupby(sorted(candidate_moves, key=self._prepare_merge_move_sort_method), key=itemgetter(*distinct_fields)): moves = self.env['stock.move'].concat(*g).filtered(lambda m: m.state not in ('done', 'cancel', 'draft')) # If we have multiple records we will merge then in a single one. if len(moves) > 1: @@ -704,7 +711,7 @@ class StockMove(models.Model): 'location_dest_id': self.location_dest_id.id, } - def _action_confirm(self, merge=True): + def _action_confirm(self, merge=True, merge_into=False): """ Confirms stock move or put it in waiting if it's linked to another move. :param: merge: According to this boolean, a newly confirmed move will be merged in another move of the same picking sharing its characteristics. @@ -744,7 +751,7 @@ class StockMove(models.Model): moves._assign_picking() self._push_apply() if merge: - return self._merge_moves() + return self._merge_moves(merge_into=merge_into) return self def _prepare_procurement_values(self): @@ -980,7 +987,7 @@ class StockMove(models.Model): The rationale for the creation of an extra move is the application of a potential push rule that will handle the extra quantities. """ - extra_move = self.env['stock.move'] + extra_move = self rounding = self.product_uom.rounding # moves created after the picking is assigned do not have `product_uom_qty`, but we shouldn't create extra moves for them if float_compare(self.quantity_done, self.product_uom_qty, precision_rounding=rounding) > 0: @@ -990,7 +997,11 @@ class StockMove(models.Model): precision_rounding=self.product_uom.rounding, rounding_method ='UP') extra_move_vals = self._prepare_extra_move_vals(extra_move_quantity) - extra_move = self.copy(default=extra_move_vals)._action_confirm() + extra_move = self.copy(default=extra_move_vals) + if extra_move.picking_id: + extra_move = extra_move._action_confirm(merge_into=self) + else: + extra_move = extra_move._action_confirm() # link it to some move lines. We don't need to do it for move since they should be merged. if self.exists() and not self.picking_id: @@ -1029,7 +1040,9 @@ class StockMove(models.Model): for move in moves: if move.state == 'cancel' or move.quantity_done <= 0: continue - moves_todo |= move + # extra move will not be merged in mrp + if not move.picking_id: + moves_todo |= move moves_todo |= move._create_extra_move() # Split moves where necessary and move quants @@ -1059,7 +1072,7 @@ class StockMove(models.Model): .filtered(lambda p: p.quant_ids and len(p.quant_ids) > 1): if len(result_package.quant_ids.mapped('location_id')) > 1: raise UserError(_('You should not put the contents of a package in different locations.')) - picking = self and self[0].picking_id or False + picking = moves_todo and moves_todo[0].picking_id or False moves_todo.write({'state': 'done', 'date': fields.Datetime.now()}) moves_todo.mapped('move_dest_ids')._action_assign() diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index d485a08131f..2ff3586a943 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -403,6 +403,7 @@ class StockMoveLine(models.Model): ml_to_delete.unlink() # Now, we can actually move the quant. + done_ml = self.env['stock.move.line'] for ml in self - ml_to_delete: if ml.product_id.type == 'product': Quant = self.env['stock.quant'] @@ -411,7 +412,7 @@ class StockMoveLine(models.Model): # if this move line is force assigned, unreserve elsewhere if needed if not ml.location_id.should_bypass_reservation() and float_compare(ml.qty_done, ml.product_qty, precision_rounding=rounding) > 0: extra_qty = ml.qty_done - ml.product_qty - ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, ml_to_ignore=done_ml) # unreserve what's been reserved if not ml.location_id.should_bypass_reservation() and ml.product_id.type == 'product' and ml.product_qty: try: @@ -430,8 +431,12 @@ class StockMoveLine(models.Model): Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date) + done_ml |= ml # Reset the reserved quantity as we just moved it to the destination location. - (self - ml_to_delete).with_context(bypass_reservation_update=True).write({'product_uom_qty': 0.00}) + (self - ml_to_delete).with_context(bypass_reservation_update=True).write({ + 'product_uom_qty': 0.00, + 'date': fields.Datetime.now(), + }) def _log_message(self, record, move, template, vals): data = vals.copy() @@ -449,13 +454,19 @@ class StockMoveLine(models.Model): data['owner_name'] = self.env['res.partner'].browse(vals.get('owner_id')).name record.message_post_with_view(template, values={'move': move, 'vals': dict(vals, **data)}, subtype_id=self.env.ref('mail.mt_note').id) - def _free_reservation(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None): + def _free_reservation(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, ml_to_ignore=None): """ When editing a done move line or validating one with some forced quantities, it is possible to impact quants that were not reserved. It is therefore necessary to edit or unlink the move lines that reserved a quantity now unavailable. + + :param ml_to_ignore: recordset of `stock.move.line` that should NOT be unreserved """ self.ensure_one() + if ml_to_ignore is None: + ml_to_ignore = self.env['stock.move.line'] + ml_to_ignore |= self + # Check the available quantity, with the `strict` kw set to `True`. If the available # quantity is greather than the quantity now unavailable, there is nothing to do. available_quantity = self.env['stock.quant']._get_available_quantity( @@ -472,7 +483,7 @@ class StockMoveLine(models.Model): ('owner_id', '=', owner_id.id if owner_id else False), ('package_id', '=', package_id.id if package_id else False), ('product_qty', '>', 0.0), - ('id', '!=', self.id), + ('id', 'not in', ml_to_ignore.ids), ] oudated_candidates = self.env['stock.move.line'].search(oudated_move_lines_domain) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index f09d9ca1160..e4bab6ddbe1 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -300,11 +300,16 @@ class Picking(models.Model): product_id = fields.Many2one('product.product', 'Product', related='move_lines.product_id') show_operations = fields.Boolean(compute='_compute_show_operations') show_lots_text = fields.Boolean(compute='_compute_show_lots_text') + has_tracking = fields.Boolean(compute='_compute_has_tracking') _sql_constraints = [ ('name_uniq', 'unique(name, company_id)', 'Reference must be unique per company!'), ] + def _compute_has_tracking(self): + for picking in self: + picking.has_tracking = any(m.has_tracking != 'none' for m in picking.move_lines) + @api.depends('picking_type_id.show_operations') def _compute_show_operations(self): for picking in self: diff --git a/addons/stock/models/stock_traceability.py b/addons/stock/models/stock_traceability.py index 3b683002c05..633fb1b785e 100644 --- a/addons/stock/models/stock_traceability.py +++ b/addons/stock/models/stock_traceability.py @@ -90,6 +90,12 @@ class MrpStockReport(models.TransientModel): ref = move_line.move_id.scrap_ids[0].name return res_model, res_id, ref + @api.model + def _quantity_to_str(self, from_uom, to_uom, qty): + """ workaround to apply the float rounding logic of t-esc on data prepared server side """ + qty = from_uom._compute_quantity(qty, to_uom, rounding_method='HALF-UP') + return self.env['ir.qweb.field.float'].value_to_html(qty, {'decimal_precision': 'Product Unit of Measure'}) + def _get_usage(self, move_line): usage = '' if (move_line.location_id.usage == 'internal') and (move_line.location_dest_id.usage == 'internal'): @@ -114,9 +120,9 @@ class MrpStockReport(models.TransientModel): 'model_id': move_line.id, 'model': 'stock.move.line', 'product_id': move_line.product_id.display_name, + 'product_qty_uom': "%s %s" % (self._quantity_to_str(move_line.product_uom_id, move_line.product_id.uom_id, move_line.qty_done), move_line.product_id.uom_id.name), 'lot_name': move_line.lot_id.name, 'lot_id': move_line.lot_id.id, - 'product_qty_uom': str(move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id, rounding_method='HALF-UP')) + ' ' + move_line.product_id.uom_id.name, 'location_source': move_line.location_id.name if not unfoldable or level == 1 else False, 'location_destination': move_line.location_dest_id.name if not unfoldable or level == 1 else False, 'reference_id': ref, diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 609bf0aa334..032260d44b0 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -478,7 +478,7 @@ class StockMove(TransactionCase): 'product_id': self.product2.id, }) - move1.with_context(debug=True).move_line_ids[1].lot_id = lot3 + move1.move_line_ids[1].lot_id = lot3 self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=True), 0.0) @@ -1473,6 +1473,41 @@ class StockMove(TransactionCase): self.assertEqual(move1.state, 'confirmed') self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot1), 0.0) + def test_use_unreserved_move_line_3(self): + """ Test the behavior of `_free_reservation` when ran on a recordset of move lines where + some are assigned and some are force assigned. `_free_reservation` should not use an + already processed move line when looking for a move line candidate to unreserve. + """ + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0) + + move1 = self.env['stock.move'].create({ + 'name': 'test_use_unreserved_move_line_3', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 3.0, + }) + move1._action_confirm() + move1._action_assign() + move1.quantity_done = 1 + + # add a forced move line in `move1` + move1.write({'move_line_ids': [(0, 0, { + 'product_id': self.product1.id, + 'product_uom_id': self.uom_unit.id, + 'qty_done': 2, + 'product_uom_qty': 0, + 'lot_id': False, + 'package_id': False, + 'result_package_id': False, + 'location_id': move1.location_id.id, + 'location_dest_id': move1.location_dest_id.id, + })]}) + move1._action_done() + + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 3.0) + def test_edit_reserved_move_line_1(self): """ Test that editing a stock move line linked to an untracked product correctly and directly adapts the reservation. In this case, we edit the sublocation where we take the diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index d7bbc745703..5d253b46f1d 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -1015,6 +1015,50 @@ class TestSinglePicking(TestStockCommon): self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 2.0) self.assertEqual(move1.state, 'done') + def test_extra_move_4(self): + """ Create a picking with similar moves (created after + confirmation). Action done should propagate all the extra + quantity and only merge extra moves in their original moves. + """ + delivery = self.env['stock.picking'].create({ + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + 'partner_id': self.partner_delta_id, + 'picking_type_id': self.picking_type_out, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 5, + 'quantity_done': 10, + 'product_uom': self.productA.uom_id.id, + 'picking_id': delivery.id, + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + }) + stock_location = self.env['stock.location'].browse(self.stock_location) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 5) + delivery.action_confirm() + delivery.action_assign() + + delivery.write({ + 'move_lines': [(0, 0, { + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 0, + 'quantity_done': 10, + 'state': 'assigned', + 'product_uom': self.productA.uom_id.id, + 'picking_id': delivery.id, + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + })] + }) + delivery.action_done() + self.assertEqual(len(delivery.move_lines), 2, 'Move should not be merged together') + for move in delivery.move_lines: + self.assertEqual(move.quantity_done, move.product_uom_qty, 'Initial demand should be equals to quantity done') + def test_recheck_availability_1(self): """ Check the good behavior of check availability. I create a DO for 2 unit with only one in stock. After the first check availability, I should have 1 reserved diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index bda4b4decc8..00d47d77dbf 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -225,13 +225,14 @@ <sheet> <div class="oe_button_box" name="button_box"> <field name="has_scrap_move" invisible="True"/> + <field name="has_tracking" invisible="True"/> <button name="action_see_move_scrap" string="Scraps" type="object" class="oe_stat_button" icon="fa-arrows-v" attrs="{'invisible': [('has_scrap_move', '=', False)]}"/> <button name="action_see_packages" string="Packages" type="object" class="oe_stat_button" icon="fa-cubes" attrs="{'invisible': [('has_packages', '=', False)]}"/> - <button name="%(action_stock_report)d" icon="fa-arrow-up" class="oe_stat_button" string="Traceability Report" type="action" states="done" groups="stock.group_production_lot"/> + <button name="%(action_stock_report)d" icon="fa-arrow-up" class="oe_stat_button" string="Traceability Report" type="action" attrs="{'invisible': ['|', ('state', '!=', 'done'), ('has_tracking', '=', False)]}" groups="stock.group_production_lot"/> </div> <h1 class="hidden-xs"> <field name="name" attrs="{'invisible': [('name','=','/')]}" readonly="1"/> diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index 39f83e2a4f6..6467e4695c6 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -611,7 +611,8 @@ return AbstractModel.extend({ var date_start; var date_stop; var date_delay = evt[this.mapping.date_delay] || 1.0, - all_day = this.mapping.all_day ? evt[this.mapping.all_day] : false, + all_day = this.fields[this.mapping.date_start].type === 'date' || + this.mapping.all_day && evt[this.mapping.all_day] || false, the_title = '', attendees = []; @@ -635,8 +636,6 @@ return AbstractModel.extend({ if (this.mapping.all_day && evt[this.mapping.all_day]) { date_stop.add(1, 'days'); } - var isAllDay = this.fields[this.mapping.date_start].type === 'date' || - this.mapping.all_day && evt[this.mapping.all_day] || false; var r = { 'record': evt, 'start': date_start, @@ -644,7 +643,7 @@ return AbstractModel.extend({ 'r_start': date_start, 'r_end': date_stop, 'title': the_title, - 'allDay': isAllDay, + 'allDay': all_day, 'id': evt.id, 'attendees':attendees, }; diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index daba6f4cc70..b073bc988dd 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -1595,7 +1595,7 @@ QUnit.module('Views', { }); QUnit.test('set event as all day when field is date', function (assert) { - assert.expect(1); + assert.expect(2); this.data.event.records[0].start_date = "2016-12-14"; @@ -1619,9 +1619,16 @@ QUnit.module('Views', { viewOptions: { initialDate: initialDate, }, + session: { + getTZOffset: function () { + return -480; + } + }, }); assert.strictEqual(calendar.$('.fc-day-grid .fc-event-container').length, 1, "should be one event in the all day row"); + assert.strictEqual(calendar.model.data.data[0].r_start.date(), 14, + "the date should be 14"); calendar.destroy(); }); diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index c87d7226893..f25a38ca456 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -70,15 +70,15 @@ class Http(models.AbstractModel): @classmethod def _add_dispatch_parameters(cls, func): - context = dict(request.context) - if not context.get('tz'): + context = {} + if not request.context.get('tz'): context['tz'] = request.session.get('geoip', {}).get('time_zone') request.website = request.env['website'].get_current_website() # can use `request.env` since auth methods are called context['website_id'] = request.website.id - # bind modified context - request.context = context + # modify bound context + request.context = dict(request.context, **context) super(Http, cls)._add_dispatch_parameters(func) @@ -116,7 +116,7 @@ class Http(models.AbstractModel): mypage = pages[0] if pages else False _, ext = os.path.splitext(req_page) if mypage: - return request.render(mypage.view_id.id, { + return request.render(mypage.get_view_identifier(), { # 'path': req_page[1:], 'deletable': True, 'main_object': mypage, diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 56249153c1f..1a18cae3ca6 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -658,6 +658,11 @@ class Page(models.Model): item = self.search_read(domain, fields=['id', 'name', 'url', 'website_published', 'website_indexed', 'date_publish', 'menu_ids', 'is_homepage'], limit=1) return item + @api.multi + def get_view_identifier(self): + """ Get identifier of this page view that may be used to render it """ + return self.view_id.id + @api.model def save_page_info(self, website_id, data): website = self.env['website'].browse(website_id) diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 1fc7f86b1cf..e9f22845bda 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -173,7 +173,7 @@ <t t-set="additional_title">Shop</t> <div id="wrap" class="js_sale"> <div class="oe_structure" /> - <div t-attf-class="container oe_website_sale #{'oe_website_sale_search' if search else None}"> + <div class="container oe_website_sale"> <div class="products_pager"> <div class="row" style="width: 100%;"> <t t-call="website_sale.search"> |
