diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml
index 5acb2ffcb9f..018f95380ff 100644
--- a/addons/account/views/report_invoice.xml
+++ b/addons/account/views/report_invoice.xml
@@ -112,6 +112,12 @@
+
+
+
+
on
@@ -122,12 +128,6 @@
-
-
-
-
|
partner.membership_stop:
res[partner.id] = 'free' if partner.free_member else 'old'
continue
+ if partner.associate_member:
+ res_state = partner.associate_member._membership_state()
+ res[partner.id] = res_state[partner.associate_member.id]
+ continue
s = 4
if partner.member_lines:
for mline in partner.member_lines:
if (mline.date_to or '0000-00-00') >= today and (mline.date_from or '0000-00-00') <= today:
- if mline.account_invoice_line.invoice_id:
+ if mline.account_invoice_line.invoice_id.partner_id == partner:
mstate = mline.account_invoice_line.invoice_id.state
if mstate == 'paid':
s = 0
inv = mline.account_invoice_line.invoice_id
- for payment in inv.payment_ids:
- if any(payment.invoice_ids.filtered(lambda inv: inv.type == 'out_refund')):
+ for ml in inv.payment_move_line_ids:
+ if any(ml.invoice_id.filtered(lambda inv: inv.type == 'out_refund')):
s = 2
break
elif mstate == 'open' and s != 0:
@@ -144,9 +150,6 @@ class Partner(models.Model):
res[partner.id] = 'none'
if partner.free_member and s != 0:
res[partner.id] = 'free'
- if partner.associate_member:
- res_state = partner.associate_member._membership_state()
- res[partner.id] = res_state[partner.associate_member.id]
return res
@api.one
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index 2972e9f7e2c..5e04c88c6a7 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -180,7 +180,7 @@ class PosOrder(models.Model):
}
@api.model
- def _get_account_move_line_group_data_type_key(self, data_type, values):
+ def _get_account_move_line_group_data_type_key(self, data_type, values, options={}):
"""
Return a tuple which will be used as a key for grouping account
move lines in _create_account_move_line method.
@@ -195,10 +195,16 @@ class PosOrder(models.Model):
values['analytic_account_id'],
values['debit'] > 0)
elif data_type == 'tax':
- return ('tax',
- values['partner_id'],
- values['tax_line_id'],
- values['debit'] > 0)
+ order_id = values.pop('order_id', False)
+ tax_key = ('tax',
+ values['partner_id'],
+ values['tax_line_id'],
+ values['debit'] > 0)
+ if options.get('rounding_method') == 'round_globally':
+ tax_key = ('tax',
+ values['tax_line_id'],
+ order_id)
+ return tax_key
elif data_type == 'counter_part':
return ('counter_part',
values['partner_id'],
@@ -308,7 +314,7 @@ class PosOrder(models.Model):
'move_id': move.id,
})
- key = self._get_account_move_line_group_data_type_key(data_type, values)
+ key = self._get_account_move_line_group_data_type_key(data_type, values, {'rounding_method': rounding_method})
if not key:
return
@@ -322,6 +328,14 @@ class PosOrder(models.Model):
current_value['quantity'] = current_value.get('quantity', 0.0) + values.get('quantity', 0.0)
current_value['credit'] = current_value.get('credit', 0.0) + values.get('credit', 0.0)
current_value['debit'] = current_value.get('debit', 0.0) + values.get('debit', 0.0)
+ if key[0] == 'tax' and rounding_method == 'round_globally':
+ if current_value['debit'] - current_value['credit'] > 0:
+ current_value['debit'] = current_value['debit'] - current_value['credit']
+ current_value['credit'] = 0
+ else:
+ current_value['credit'] = current_value['credit'] - current_value['debit']
+ current_value['debit'] = 0
+
else:
grouped_data[key].append(values)
@@ -381,7 +395,8 @@ class PosOrder(models.Model):
'credit': ((tax['amount'] > 0) and tax['amount']) or 0.0,
'debit': ((tax['amount'] < 0) and -tax['amount']) or 0.0,
'tax_line_id': tax['id'],
- 'partner_id': partner_id
+ 'partner_id': partner_id,
+ 'order_id': order.id
})
# round tax lines per order
diff --git a/addons/project/models/project.py b/addons/project/models/project.py
index 08a473a4c5e..2f334db50e6 100644
--- a/addons/project/models/project.py
+++ b/addons/project/models/project.py
@@ -862,14 +862,19 @@ class Task(models.Model):
groups = super(Task, self)._notify_get_groups(message, groups)
self.ensure_one()
+
+ new_group = (
+ 'group_project_user',
+ lambda partner: bool(partner.user_ids) and any(user.has_group('project.group_project_user') for user in partner.user_ids),
+ {},
+ )
+
if not self.user_id and not self.stage_id.fold:
take_action = self._notify_get_action_link('assign')
project_actions = [{'url': take_action, 'title': _('I take it')}]
- new_group = (
- 'group_project_user', lambda partner: bool(partner.user_ids) and any(user.has_group('project.group_project_user') for user in partner.user_ids), {
- 'actions': project_actions,
- })
- groups = [new_group] + groups
+ new_group[2]['actions'] = project_actions
+
+ groups = [new_group] + groups
for group_name, group_method, group_data in groups:
if group_name == 'customer':
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 111bda3cce7..51e32a48ff5 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -350,7 +350,7 @@ class PurchaseOrder(models.Model):
'sequence': max(line.product_id.seller_ids.mapped('sequence')) + 1 if line.product_id.seller_ids else 1,
'product_uom': line.product_uom.id,
'min_qty': 0.0,
- 'price': self.currency_id._convert(line.price_unit, currency, line.company_id, line.date_order or fields.Date.today()),
+ 'price': self.currency_id._convert(line.price_unit, currency, line.company_id, line.date_order or fields.Date.today(), round=False),
'currency_id': currency.id,
'delay': 0,
}
diff --git a/addons/sale_stock/models/stock.py b/addons/sale_stock/models/stock.py
index eee0424021c..2a7f9e5560e 100644
--- a/addons/sale_stock/models/stock.py
+++ b/addons/sale_stock/models/stock.py
@@ -36,6 +36,15 @@ class StockMove(models.Model):
#rslt += invoices.mapped('refund_invoice_ids')
return rslt
+ def _assign_picking_post_process(self, new=False):
+ super(StockMove, self)._assign_picking_post_process(new=new)
+ if new and self.sale_line_id and self.sale_line_id.order_id:
+ self.picking_id.message_post_with_view(
+ 'mail.message_origin_link',
+ values={'self': self.picking_id, 'origin': self.sale_line_id.order_id},
+ subtype_id=self.env.ref('mail.mt_note').id)
+
+
class ProcurementGroup(models.Model):
_inherit = 'procurement.group'
diff --git a/addons/sale_timesheet/controllers/main.py b/addons/sale_timesheet/controllers/main.py
index f37aacac96b..f07edcd0728 100644
--- a/addons/sale_timesheet/controllers/main.py
+++ b/addons/sale_timesheet/controllers/main.py
@@ -3,6 +3,7 @@
from ast import literal_eval
import babel
from dateutil.relativedelta import relativedelta
+import itertools
import json
from odoo import http, fields, _
@@ -88,7 +89,12 @@ class SaleTimesheetController(http.Controller):
#
# Time Repartition (per employee per billable types)
#
- employees = projects.mapped('tasks.user_id.employee_ids') | request.env['account.analytic.line'].search([('project_id', 'in', projects.ids)]).mapped('employee_id')
+ user_ids = request.env['project.task'].sudo().search_read([('project_id', 'in', projects.ids), ('user_id', '!=', False)], ['user_id'])
+ user_ids = [user_id['user_id'][0] for user_id in user_ids]
+ employee_ids = request.env['res.users'].sudo().search_read([('id', 'in', user_ids)], ['employee_ids'])
+ # flatten the list of list
+ employee_ids = list(itertools.chain.from_iterable([employee_id['employee_ids'] for employee_id in employee_ids]))
+ employees = request.env['hr.employee'].sudo().browse(employee_ids) | request.env['account.analytic.line'].search([('project_id', 'in', projects.ids)]).mapped('employee_id')
repartition_domain = [('project_id', 'in', projects.ids), ('employee_id', '!=', False), ('timesheet_invoice_type', '!=', False)] # force billable type
repartition_data = request.env['account.analytic.line'].read_group(repartition_domain, ['employee_id', 'timesheet_invoice_type', 'unit_amount'], ['employee_id', 'timesheet_invoice_type'], lazy=False)
diff --git a/addons/sales_team/models/crm_team.py b/addons/sales_team/models/crm_team.py
index f3708fc5b10..180e2879cdd 100644
--- a/addons/sales_team/models/crm_team.py
+++ b/addons/sales_team/models/crm_team.py
@@ -8,7 +8,7 @@ from dateutil.relativedelta import relativedelta
import json
from odoo import api, fields, models, _
-from odoo.exceptions import UserError
+from odoo.exceptions import AccessError, UserError
from odoo.release import version
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
@@ -33,8 +33,13 @@ class CrmTeam(models.Model):
team_id = self.env['crm.team'].browse(self.env.context.get('default_team_id'))
if not team_id:
default_team_id = self.env.ref('sales_team.team_sales_department', raise_if_not_found=False)
- if default_team_id and (self.env.context.get('default_type') != 'lead' or default_team_id.use_leads):
- team_id = default_team_id
+ if default_team_id:
+ try:
+ default_team_id.check_access_rule('read')
+ except AccessError:
+ return self.env['crm.team']
+ if self.env.context.get('default_type') != 'lead' or default_team_id.use_leads and default_team_id.active:
+ team_id = default_team_id
return team_id
def _get_default_favorite_user_ids(self):
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index 43d9785d1a1..a303ce1c480 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -720,7 +720,7 @@ class StockMove(models.Model):
recompute = True
picking = Picking.create(move._get_new_picking_values())
move.write({'picking_id': picking.id})
-
+ move._assign_picking_post_process(new=recompute)
# If this method is called in batch by a write on a one2many and
# at some point had to create a picking, some next iterations could
# try to find back the created picking. As we look for it by searching
@@ -730,6 +730,9 @@ class StockMove(models.Model):
move.recompute()
return True
+ def _assign_picking_post_process(self, new=False):
+ pass
+
def _get_new_picking_values(self):
""" Prepares a new picking for this move as it could not be assigned to
another picking. This method is designed to be inherited. """
diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py
index bb985547ede..80fc6e0eabb 100644
--- a/addons/stock/models/stock_scrap.py
+++ b/addons/stock/models/stock_scrap.py
@@ -121,6 +121,8 @@ class StockScrap(models.Model):
def action_validate(self):
self.ensure_one()
+ if self.product_id.type != 'product':
+ return self.do_scrap()
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
available_qty = sum(self.env['stock.quant']._gather(self.product_id,
self.location_id,
diff --git a/addons/stock/report/report_deliveryslip.xml b/addons/stock/report/report_deliveryslip.xml
index 50289bee840..a5a9d7d0fe5 100644
--- a/addons/stock/report/report_deliveryslip.xml
+++ b/addons/stock/report/report_deliveryslip.xml
@@ -11,11 +11,11 @@
Customer Address:
-
+
+ |