[MERGE] forward port branch saas-11.2 up to 55a14f9ce8
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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'):
|
||||
|
||||
@@ -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 """
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.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()])
|
||||
|
||||
@@ -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:
|
||||
@@ -709,7 +716,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.
|
||||
@@ -749,7 +756,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):
|
||||
@@ -985,7 +992,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:
|
||||
@@ -995,7 +1002,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:
|
||||
@@ -1034,7 +1045,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
|
||||
@@ -1064,7 +1077,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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1474,6 +1474,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -632,7 +632,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 = [];
|
||||
|
||||
@@ -656,8 +657,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,
|
||||
@@ -665,7 +664,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,
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -176,7 +176,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">
|
||||
|
||||
@@ -422,6 +422,7 @@ class IrMailServer(models.Model):
|
||||
email_to = message['To']
|
||||
email_cc = message['Cc']
|
||||
email_bcc = message['Bcc']
|
||||
del message['Bcc']
|
||||
|
||||
smtp_to_list = [
|
||||
address
|
||||
|
||||
@@ -458,13 +458,18 @@ class IrTranslation(models.Model):
|
||||
continue
|
||||
|
||||
# remap existing translations on terms when possible
|
||||
trans_src = record_trans.mapped('src')
|
||||
for trans in record_trans:
|
||||
if trans.src == trans.value:
|
||||
discarded += trans
|
||||
elif trans.src not in terms:
|
||||
matches = get_close_matches(trans.src, terms, 1, 0.9)
|
||||
if matches:
|
||||
trans.write({'src': matches[0], 'state': trans.state})
|
||||
if matches[0] in trans_src:
|
||||
# there is already a translation for this term; discard this one
|
||||
discarded += trans
|
||||
else:
|
||||
trans.write({'src': matches[0], 'state': trans.state})
|
||||
else:
|
||||
outdated += trans
|
||||
|
||||
|
||||
Reference in New Issue
Block a user