[IMP] *: Use the new API of _read_group for backend use
Part-of: odoo/odoo#110737
This commit is contained in:
@@ -26,13 +26,12 @@ class AccountAccount(models.Model):
|
||||
def _check_account_type_unique_current_year_earning(self):
|
||||
result = self._read_group(
|
||||
domain=[('account_type', '=', 'equity_unaffected')],
|
||||
fields=['company_id', 'ids:array_agg(id)'],
|
||||
groupby=['company_id'],
|
||||
aggregates=['id:recordset'],
|
||||
having=[('__count', '>', 1)],
|
||||
)
|
||||
for res in result:
|
||||
if res.get('company_id_count', 0) >= 2:
|
||||
account_unaffected_earnings = self.browse(res['ids'])
|
||||
raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)', [a.code for a in account_unaffected_earnings]))
|
||||
for _company, account_unaffected_earnings in result:
|
||||
raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)', [a.code for a in account_unaffected_earnings]))
|
||||
|
||||
name = fields.Char(string="Account Name", required=True, index='trigram', tracking=True, translate=True)
|
||||
currency_id = fields.Many2one('res.currency', string='Account Currency', tracking=True,
|
||||
@@ -354,11 +353,11 @@ class AccountAccount(models.Model):
|
||||
|
||||
def _compute_current_balance(self):
|
||||
balances = {
|
||||
read['account_id'][0]: read['balance']
|
||||
for read in self.env['account.move.line']._read_group(
|
||||
account.id: balance
|
||||
for account, balance in self.env['account.move.line']._read_group(
|
||||
domain=[('account_id', 'in', self.ids), ('parent_state', '=', 'posted')],
|
||||
fields=['balance', 'account_id'],
|
||||
groupby=['account_id'],
|
||||
aggregates=['balance:sum'],
|
||||
)
|
||||
}
|
||||
for record in self:
|
||||
|
||||
@@ -120,11 +120,11 @@ class account_journal(models.Model):
|
||||
|
||||
def _compute_entries_count(self):
|
||||
res = {
|
||||
r['journal_id'][0]: r['journal_id_count']
|
||||
for r in self.env['account.move']._read_group(
|
||||
journal.id: count
|
||||
for journal, count in self.env['account.move']._read_group(
|
||||
domain=[('journal_id', 'in', self.ids)],
|
||||
fields=['journal_id'],
|
||||
groupby=['journal_id'],
|
||||
aggregates=['__count'],
|
||||
)
|
||||
}
|
||||
for journal in self:
|
||||
@@ -310,11 +310,11 @@ class account_journal(models.Model):
|
||||
:type domain: list[tuple]
|
||||
"""
|
||||
res = {
|
||||
r['journal_id'][0]: r['journal_id_count']
|
||||
for r in self.env[model]._read_group(
|
||||
journal.id: count
|
||||
for journal, count in self.env[model]._read_group(
|
||||
domain=[('journal_id', 'in', self.ids)] + domain,
|
||||
fields=['journal_id'],
|
||||
groupby=['journal_id'],
|
||||
aggregates=['__count'],
|
||||
)
|
||||
}
|
||||
for journal in self:
|
||||
|
||||
@@ -285,8 +285,8 @@ class AccountReconcileModel(models.Model):
|
||||
return action
|
||||
|
||||
def _compute_number_entries(self):
|
||||
data = self.env['account.move.line']._read_group([('reconcile_model_id', 'in', self.ids)], ['reconcile_model_id'], 'reconcile_model_id')
|
||||
mapped_data = dict([(d['reconcile_model_id'][0], d['reconcile_model_id_count']) for d in data])
|
||||
data = self.env['account.move.line']._read_group([('reconcile_model_id', 'in', self.ids)], ['reconcile_model_id'], ['__count'])
|
||||
mapped_data = {reconcile_model.id: count for reconcile_model, count in data}
|
||||
for model in self:
|
||||
model.number_entries = mapped_data.get(model.id, 0)
|
||||
|
||||
|
||||
@@ -209,11 +209,11 @@ class ResCompany(models.Model):
|
||||
@api.depends('fiscal_position_ids.foreign_vat')
|
||||
def _compute_multi_vat_foreign_country(self):
|
||||
company_to_foreign_vat_country = {
|
||||
val['company_id'][0]: val['country_ids']
|
||||
for val in self.env['account.fiscal.position'].read_group(
|
||||
company.id: country_ids
|
||||
for company, country_ids in self.env['account.fiscal.position']._read_group(
|
||||
domain=[('company_id', 'in', self.ids), ('foreign_vat', '!=', False)],
|
||||
fields=['country_ids:array_agg(country_id)'],
|
||||
groupby='company_id',
|
||||
groupby=['company_id'],
|
||||
aggregates=['country_id:array_agg'],
|
||||
)
|
||||
}
|
||||
for company in self:
|
||||
|
||||
@@ -398,9 +398,9 @@ class ResPartner(models.Model):
|
||||
('state', 'not in', ['draft', 'cancel']),
|
||||
('move_type', 'in', ('out_invoice', 'out_refund')),
|
||||
]
|
||||
price_totals = self.env['account.invoice.report'].read_group(domain, ['price_subtotal'], ['partner_id'])
|
||||
price_totals = self.env['account.invoice.report']._read_group(domain, ['partner_id'], ['price_subtotal:sum'])
|
||||
for partner, child_ids in all_partners_and_children.items():
|
||||
partner.total_invoiced = sum(price['price_subtotal'] for price in price_totals if price['partner_id'][0] in child_ids)
|
||||
partner.total_invoiced = sum(price_subtotal_sum for partner, price_subtotal_sum in price_totals if partner.id in child_ids)
|
||||
|
||||
def _compute_journal_item_count(self):
|
||||
AccountMoveLine = self.env['account.move.line']
|
||||
@@ -526,8 +526,8 @@ class ResPartner(models.Model):
|
||||
)
|
||||
|
||||
def _compute_bank_count(self):
|
||||
bank_data = self.env['res.partner.bank']._read_group([('partner_id', 'in', self.ids)], ['partner_id'], ['partner_id'])
|
||||
mapped_data = dict([(bank['partner_id'][0], bank['partner_id_count']) for bank in bank_data])
|
||||
bank_data = self.env['res.partner.bank']._read_group([('partner_id', 'in', self.ids)], ['partner_id'], ['__count'])
|
||||
mapped_data = {partner.id: count for partner, count in bank_data}
|
||||
for partner in self:
|
||||
partner.bank_account_count = mapped_data.get(partner.id, 0)
|
||||
|
||||
|
||||
@@ -25,16 +25,15 @@ class AccountBankStatement(models.Model):
|
||||
"""
|
||||
rand = populate.Random('account_bank_statement+Populate')
|
||||
|
||||
read_group_res = self.env['account.bank.statement.line'].read_group(
|
||||
read_group_res = self.env['account.bank.statement.line']._read_group(
|
||||
[('statement_id', '=', False)],
|
||||
['ids:array_agg(id)'],
|
||||
['journal_id'],
|
||||
['id:array_agg'],
|
||||
)
|
||||
|
||||
bank_statement_vals_list = []
|
||||
for res in read_group_res:
|
||||
available_ids = res['ids']
|
||||
nb_ids = len(available_ids)
|
||||
for journal, ids in read_group_res:
|
||||
nb_ids = len(ids)
|
||||
while nb_ids > 0:
|
||||
batch_size = min(rand.randint(1, 19), nb_ids)
|
||||
nb_ids -= batch_size
|
||||
@@ -46,8 +45,8 @@ class AccountBankStatement(models.Model):
|
||||
|
||||
bank_statement_vals_list.append({
|
||||
'name': f"statement_{len(bank_statement_vals_list) + 1}",
|
||||
'journal_id': res['journal_id'][0],
|
||||
'line_ids': [Command.set(res['ids'])],
|
||||
'journal_id': journal.id,
|
||||
'line_ids': [Command.set(ids)],
|
||||
})
|
||||
|
||||
return self.env['account.bank.statement'].create(bank_statement_vals_list)
|
||||
|
||||
@@ -14,8 +14,8 @@ class AccountMove(models.Model):
|
||||
@api.depends('debit_note_ids')
|
||||
def _compute_debit_count(self):
|
||||
debit_data = self.env['account.move']._read_group([('debit_origin_id', 'in', self.ids)],
|
||||
['debit_origin_id'], ['debit_origin_id'])
|
||||
data_map = {datum['debit_origin_id'][0]: datum['debit_origin_id_count'] for datum in debit_data}
|
||||
['debit_origin_id'], ['__count'])
|
||||
data_map = {debit_origin.id: count for debit_origin, count in debit_data}
|
||||
for inv in self:
|
||||
inv.debit_note_count = data_map.get(inv.id, 0.0)
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ class FleetVehicle(models.Model):
|
||||
('parent_state', '!=', 'cancel'),
|
||||
('move_id.move_type', 'in', self.env['account.move'].get_purchase_types())
|
||||
],
|
||||
fields=['vehicle_id', 'move_id:array_agg'],
|
||||
groupby=['vehicle_id'],
|
||||
aggregates=['move_id:array_agg'],
|
||||
)
|
||||
vehicle_move_mapping = {move['vehicle_id'][0]: set(move['move_id']) for move in moves}
|
||||
vehicle_move_mapping = {vehicle.id: set(move_ids) for vehicle, move_ids in moves}
|
||||
for vehicle in self:
|
||||
vehicle.account_move_ids = [Command.set(vehicle_move_mapping.get(vehicle.id, []))]
|
||||
vehicle.bill_count = len(vehicle.account_move_ids)
|
||||
|
||||
@@ -86,10 +86,10 @@ class AccountPayment(models.Model):
|
||||
('source_payment_id', 'in', self.ids),
|
||||
('payment_transaction_id.operation', '=', 'refund')
|
||||
],
|
||||
fields=['source_payment_id'],
|
||||
groupby=['source_payment_id']
|
||||
groupby=['source_payment_id'],
|
||||
aggregates=['__count']
|
||||
)
|
||||
data = {x['source_payment_id'][0]: x['source_payment_id_count'] for x in rg_data}
|
||||
data = {source_payment.id: count for source_payment, count in rg_data}
|
||||
for payment in self:
|
||||
payment.refunds_count = data.get(payment.id, 0)
|
||||
|
||||
|
||||
@@ -150,7 +150,6 @@ class AccountAnalyticAccount(models.Model):
|
||||
|
||||
@api.depends('line_ids.amount')
|
||||
def _compute_debit_credit_balance(self):
|
||||
Curr = self.env['res.currency']
|
||||
analytic_line_obj = self.env['account.analytic.line']
|
||||
domain = [
|
||||
('account_id', 'in', self.ids),
|
||||
@@ -162,27 +161,25 @@ class AccountAnalyticAccount(models.Model):
|
||||
domain.append(('date', '<=', self._context['to_date']))
|
||||
|
||||
user_currency = self.env.company.currency_id
|
||||
credit_groups = analytic_line_obj.read_group(
|
||||
credit_groups = analytic_line_obj._read_group(
|
||||
domain=domain + [('amount', '>=', 0.0)],
|
||||
fields=['account_id', 'currency_id', 'amount'],
|
||||
groupby=['account_id', 'currency_id'],
|
||||
lazy=False,
|
||||
aggregates=['amount:sum'],
|
||||
)
|
||||
data_credit = defaultdict(float)
|
||||
for l in credit_groups:
|
||||
data_credit[l['account_id'][0]] += Curr.browse(l['currency_id'][0])._convert(
|
||||
l['amount'], user_currency, self.env.company, fields.Date.today())
|
||||
for account, currency, amount_sum in credit_groups:
|
||||
data_credit[account.id] += currency._convert(
|
||||
amount_sum, user_currency, self.env.company, fields.Date.today())
|
||||
|
||||
debit_groups = analytic_line_obj.read_group(
|
||||
debit_groups = analytic_line_obj._read_group(
|
||||
domain=domain + [('amount', '<', 0.0)],
|
||||
fields=['account_id', 'currency_id', 'amount'],
|
||||
groupby=['account_id', 'currency_id'],
|
||||
lazy=False,
|
||||
aggregates=['amount:sum'],
|
||||
)
|
||||
data_debit = defaultdict(float)
|
||||
for l in debit_groups:
|
||||
data_debit[l['account_id'][0]] += Curr.browse(l['currency_id'][0])._convert(
|
||||
l['amount'], user_currency, self.env.company, fields.Date.today())
|
||||
for account, currency, amount_sum in debit_groups:
|
||||
data_debit[account.id] += currency._convert(
|
||||
amount_sum, user_currency, self.env.company, fields.Date.today())
|
||||
|
||||
for account in self:
|
||||
account.debit = abs(data_debit.get(account.id, 0.0))
|
||||
|
||||
@@ -164,11 +164,8 @@ class RecurrenceRule(models.Model):
|
||||
|
||||
@api.depends('calendar_event_ids.start')
|
||||
def _compute_dtstart(self):
|
||||
groups = self.env['calendar.event'].read_group([('recurrence_id', 'in', self.ids)], ['start:min'], ['recurrence_id'])
|
||||
start_mapping = {
|
||||
group['recurrence_id'][0]: group['start']
|
||||
for group in groups
|
||||
}
|
||||
groups = self.env['calendar.event']._read_group([('recurrence_id', 'in', self.ids)], ['recurrence_id'], ['start:min'])
|
||||
start_mapping = {recurrence.id: start_min for recurrence, start_min in groups}
|
||||
for recurrence in self:
|
||||
recurrence.dtstart = start_mapping.get(recurrence.id)
|
||||
|
||||
|
||||
@@ -538,13 +538,10 @@ class Lead(models.Model):
|
||||
lead.recurring_revenue_prorated = (lead.recurring_revenue or 0.0) * (lead.probability or 0) / 100.0
|
||||
|
||||
def _compute_calendar_event_count(self):
|
||||
if self.ids:
|
||||
meeting_data = self.env['calendar.event'].sudo()._read_group([
|
||||
('opportunity_id', 'in', self.ids)
|
||||
], ['opportunity_id'], ['opportunity_id'])
|
||||
mapped_data = {m['opportunity_id'][0]: m['opportunity_id_count'] for m in meeting_data}
|
||||
else:
|
||||
mapped_data = dict()
|
||||
meeting_data = self.env['calendar.event'].sudo()._read_group([
|
||||
('opportunity_id', 'in', self.ids)
|
||||
], ['opportunity_id'], ['__count'])
|
||||
mapped_data = {opportunity.id: count for opportunity, count in meeting_data}
|
||||
for lead in self:
|
||||
lead.calendar_event_count = mapped_data.get(lead.id, 0)
|
||||
|
||||
@@ -826,11 +823,11 @@ class Lead(models.Model):
|
||||
activity_asc = any('my_activity_date_deadline asc' in item for item in order_items)
|
||||
my_lead_activities = self.env['mail.activity']._read_group(
|
||||
[('res_model', '=', self._name), ('user_id', '=', self.env.uid)],
|
||||
['res_id', 'date_deadline:min'],
|
||||
['res_id'],
|
||||
orderby='date_deadline ASC'
|
||||
['date_deadline:min'],
|
||||
order='date_deadline:min ASC, res_id',
|
||||
)
|
||||
my_lead_mapping = dict((item['res_id'], item['date_deadline']) for item in my_lead_activities)
|
||||
my_lead_mapping = dict(my_lead_activities)
|
||||
my_lead_ids = list(my_lead_mapping.keys())
|
||||
my_lead_domain = expression.AND([[('id', 'in', my_lead_ids)], domain])
|
||||
my_lead_order = ', '.join(item for item in order_items if 'my_activity_date_deadline' not in item)
|
||||
|
||||
@@ -16,9 +16,9 @@ class LostReason(models.Model):
|
||||
lead_data = self.env['crm.lead'].with_context(active_test=False)._read_group(
|
||||
[('lost_reason_id', 'in', self.ids)],
|
||||
['lost_reason_id'],
|
||||
['lost_reason_id']
|
||||
['__count'],
|
||||
)
|
||||
mapped_data = dict((data['lost_reason_id'][0], data['lost_reason_id_count']) for data in lead_data)
|
||||
mapped_data = {lost_reason.id: count for lost_reason, count in lead_data}
|
||||
for reason in self:
|
||||
reason.leads_count = mapped_data.get(reason.id, 0)
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ class Team(models.Model):
|
||||
('team_id', 'in', self.ids),
|
||||
('type', '=', 'lead'),
|
||||
('user_id', '=', False),
|
||||
], ['team_id'], ['team_id'])
|
||||
counts = {datum['team_id'][0]: datum['team_id_count'] for datum in leads_data}
|
||||
], ['team_id'], ['__count'])
|
||||
counts = {team.id: count for team, count in leads_data}
|
||||
for team in self:
|
||||
team.lead_unassigned_count = counts.get(team.id, 0)
|
||||
|
||||
@@ -92,12 +92,10 @@ class Team(models.Model):
|
||||
('team_id', 'in', self.ids),
|
||||
('probability', '<', 100),
|
||||
('type', '=', 'opportunity'),
|
||||
], ['expected_revenue:sum', 'team_id'], ['team_id'])
|
||||
counts = {datum['team_id'][0]: datum['team_id_count'] for datum in opportunity_data}
|
||||
amounts = {datum['team_id'][0]: datum['expected_revenue'] for datum in opportunity_data}
|
||||
], ['team_id'], ['__count', 'expected_revenue:sum'])
|
||||
counts_amounts = {team.id: (count, expected_revenue_sum) for team, count, expected_revenue_sum in opportunity_data}
|
||||
for team in self:
|
||||
team.opportunities_count = counts.get(team.id, 0)
|
||||
team.opportunities_amount = amounts.get(team.id, 0)
|
||||
team.opportunities_count, team.opportunities_amount = counts_amounts.get(team.id, (0, 0))
|
||||
|
||||
def _compute_opportunities_overdue_data(self):
|
||||
opportunity_data = self.env['crm.lead']._read_group([
|
||||
@@ -105,12 +103,10 @@ class Team(models.Model):
|
||||
('probability', '<', 100),
|
||||
('type', '=', 'opportunity'),
|
||||
('date_deadline', '<', fields.Date.to_string(fields.Datetime.now()))
|
||||
], ['expected_revenue', 'team_id'], ['team_id'])
|
||||
counts = {datum['team_id'][0]: datum['team_id_count'] for datum in opportunity_data}
|
||||
amounts = {datum['team_id'][0]: (datum['expected_revenue']) for datum in opportunity_data}
|
||||
], ['team_id'], ['__count', 'expected_revenue:sum'])
|
||||
counts_amounts = {team.id: (count, expected_revenue_sum) for team, count, expected_revenue_sum in opportunity_data}
|
||||
for team in self:
|
||||
team.opportunities_overdue_count = counts.get(team.id, 0)
|
||||
team.opportunities_overdue_amount = amounts.get(team.id, 0)
|
||||
team.opportunities_overdue_count, team.opportunities_overdue_amount = counts_amounts.get(team.id, (0, 0))
|
||||
|
||||
@api.onchange('use_leads', 'use_opportunities')
|
||||
def _onchange_use_leads_opportunities(self):
|
||||
|
||||
@@ -51,15 +51,15 @@ class Partner(models.Model):
|
||||
|
||||
opportunity_data = self.env['crm.lead'].with_context(active_test=False)._read_group(
|
||||
domain=[('partner_id', 'in', all_partners.ids)],
|
||||
fields=['partner_id'], groupby=['partner_id']
|
||||
groupby=['partner_id'], aggregates=['__count']
|
||||
)
|
||||
self_ids = set(self._ids)
|
||||
|
||||
self.opportunity_count = 0
|
||||
for group in opportunity_data:
|
||||
partner = self.browse(group['partner_id'][0])
|
||||
for partner, count in opportunity_data:
|
||||
while partner:
|
||||
if partner in self:
|
||||
partner.opportunity_count += group['partner_id_count']
|
||||
if partner.id in self_ids:
|
||||
partner.opportunity_count += count
|
||||
partner = partner.parent_id
|
||||
|
||||
def action_view_opportunity(self):
|
||||
|
||||
@@ -16,8 +16,8 @@ class UtmCampaign(models.Model):
|
||||
def _compute_crm_lead_count(self):
|
||||
lead_data = self.env['crm.lead'].with_context(active_test=False)._read_group([
|
||||
('campaign_id', 'in', self.ids)],
|
||||
['campaign_id'], ['campaign_id'])
|
||||
mapped_data = {datum['campaign_id'][0]: datum['campaign_id_count'] for datum in lead_data}
|
||||
['campaign_id'], ['__count'])
|
||||
mapped_data = {campaign.id: count for campaign, count in lead_data}
|
||||
for campaign in self:
|
||||
campaign.crm_lead_count = mapped_data.get(campaign.id, 0)
|
||||
|
||||
|
||||
@@ -98,15 +98,12 @@ class CRMLeadMiningRequest(models.Model):
|
||||
|
||||
@api.depends('lead_ids.lead_mining_request_id')
|
||||
def _compute_lead_count(self):
|
||||
if self.ids:
|
||||
leads_data = self.env['crm.lead']._read_group(
|
||||
[('lead_mining_request_id', 'in', self.ids)],
|
||||
['lead_mining_request_id'], ['lead_mining_request_id'])
|
||||
else:
|
||||
leads_data = []
|
||||
mapped_data = dict(
|
||||
(m['lead_mining_request_id'][0], m['lead_mining_request_id_count'])
|
||||
for m in leads_data)
|
||||
leads_data = self.env['crm.lead']._read_group(
|
||||
[('lead_mining_request_id', 'in', self.ids)],
|
||||
['lead_mining_request_id'], ['__count'])
|
||||
mapped_data = {
|
||||
lead_mining_request.id: count
|
||||
for lead_mining_request, count in leads_data}
|
||||
for request in self:
|
||||
request.lead_count = mapped_data.get(request.id, 0)
|
||||
|
||||
|
||||
@@ -11,12 +11,9 @@ class ChatbotScript(models.Model):
|
||||
string='Generated Lead Count', compute='_compute_lead_count')
|
||||
|
||||
def _compute_lead_count(self):
|
||||
mapped_leads = {}
|
||||
if self.ids:
|
||||
leads_data = self.env['crm.lead'].with_context(active_test=False).sudo()._read_group(
|
||||
[('source_id', 'in', self.mapped('source_id').ids)], ['source_id'], ['source_id'])
|
||||
mapped_leads = {lead['source_id'][0]: lead['source_id_count'] for lead in leads_data}
|
||||
|
||||
leads_data = self.env['crm.lead'].with_context(active_test=False).sudo()._read_group(
|
||||
[('source_id', 'in', self.mapped('source_id').ids)], ['source_id'], ['__count'])
|
||||
mapped_leads = {source.id: count for source, count in leads_data}
|
||||
for script in self:
|
||||
script.lead_count = mapped_leads.get(script.source_id.id, 0)
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ class DataRecycleModel(models.Model):
|
||||
count_data = self.env['data_recycle.record']._read_group(
|
||||
[('recycle_model_id', 'in', self.ids)],
|
||||
['recycle_model_id'],
|
||||
['recycle_model_id'])
|
||||
counts = {cd['recycle_model_id'][0]: cd['recycle_model_id_count'] for cd in count_data}
|
||||
['__count'])
|
||||
counts = {recycle_model.id: count for recycle_model, count in count_data}
|
||||
for model in self:
|
||||
model.records_to_recycle_count = counts[model.id] if model.id in counts else 0
|
||||
|
||||
|
||||
@@ -416,14 +416,11 @@ class Digest(models.Model):
|
||||
|
||||
values = self.env[model]._read_group(
|
||||
domain=base_domain,
|
||||
fields=[f'{sum_field}:sum'] if sum_field else None,
|
||||
groupby=['company_id'],
|
||||
aggregates=[f'{sum_field}:sum'] if sum_field else ['__count'],
|
||||
)
|
||||
|
||||
values_per_company = {
|
||||
value['company_id'][0]: value[sum_field] if sum_field else value['company_id_count']
|
||||
for value in values
|
||||
}
|
||||
values_per_company = {company.id: agg for company, agg in values}
|
||||
for digest in self:
|
||||
company = digest.company_id or self.env.company
|
||||
digest[digest_kpi_field] = values_per_company.get(company.id, 0)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import Command
|
||||
@@ -55,16 +56,14 @@ class Event(models.Model):
|
||||
def _get_booth_stat_count(self):
|
||||
elements = self.env['event.booth'].sudo()._read_group(
|
||||
[('event_id', 'in', self.ids)],
|
||||
['event_id', 'state'], ['event_id', 'state'], lazy=False
|
||||
['event_id', 'state'], ['__count']
|
||||
)
|
||||
elements_total_count = dict()
|
||||
elements_total_count = defaultdict(int)
|
||||
elements_available_count = dict()
|
||||
for element in elements:
|
||||
event_id = element['event_id'][0]
|
||||
if element['state'] == 'available':
|
||||
elements_available_count[event_id] = element['__count']
|
||||
elements_total_count.setdefault(event_id, 0)
|
||||
elements_total_count[event_id] += element['__count']
|
||||
for event, state, count in elements:
|
||||
if state == 'available':
|
||||
elements_available_count[event.id] = count
|
||||
elements_total_count[event.id] += count
|
||||
return elements_available_count, elements_total_count
|
||||
|
||||
@api.depends('event_booth_ids', 'event_booth_ids.state')
|
||||
|
||||
@@ -12,14 +12,11 @@ class SaleOrder(models.Model):
|
||||
|
||||
@api.depends('event_booth_ids')
|
||||
def _compute_event_booth_count(self):
|
||||
if self.ids:
|
||||
slot_data = self.env['event.booth']._read_group(
|
||||
[('sale_order_id', 'in', self.ids)],
|
||||
['sale_order_id'], ['sale_order_id']
|
||||
)
|
||||
slot_mapped = dict((data['sale_order_id'][0], data['sale_order_id_count']) for data in slot_data)
|
||||
else:
|
||||
slot_mapped = dict()
|
||||
slot_data = self.env['event.booth']._read_group(
|
||||
[('sale_order_id', 'in', self.ids)],
|
||||
['sale_order_id'], ['__count'],
|
||||
)
|
||||
slot_mapped = {sale_order.id: count for sale_order, count in slot_data}
|
||||
for so in self:
|
||||
so.event_booth_count = slot_mapped.get(so.id, 0)
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class EventEvent(models.Model):
|
||||
def _compute_lead_count(self):
|
||||
lead_data = self.env['crm.lead']._read_group(
|
||||
[('event_id', 'in', self.ids)],
|
||||
['event_id'], ['event_id']
|
||||
['event_id'], ['__count'],
|
||||
)
|
||||
mapped_data = {item['event_id'][0]: item['event_id_count'] for item in lead_data}
|
||||
mapped_data = {event.id: count for event, count in lead_data}
|
||||
for event in self:
|
||||
event.lead_count = mapped_data.get(event.id, 0)
|
||||
|
||||
@@ -31,50 +31,22 @@ class Event(models.Model):
|
||||
have to do one conversion per sale.order (and a sale.order is created every time
|
||||
we sell a single event ticket). """
|
||||
date_now = fields.Datetime.now()
|
||||
sale_price_by_event = {}
|
||||
if self.ids:
|
||||
event_subtotals = self.env['sale.order.line']._read_group(
|
||||
[('event_id', 'in', self.ids),
|
||||
('price_subtotal', '!=', 0)],
|
||||
['event_id', 'currency_id', 'price_subtotal:sum'],
|
||||
['event_id', 'currency_id'],
|
||||
lazy=False
|
||||
event_subtotals = self.env['sale.order.line']._read_group(
|
||||
[('event_id', 'in', self.ids),
|
||||
('price_subtotal', '!=', 0)],
|
||||
['event_id', 'currency_id'],
|
||||
['price_subtotal:sum'],
|
||||
)
|
||||
|
||||
self.sale_price_subtotal = 0
|
||||
for event, currency, sum_price_subtotal in event_subtotals:
|
||||
event.sale_price_subtotal += event.currency_id._convert(
|
||||
sum_price_subtotal,
|
||||
currency,
|
||||
event.company_id,
|
||||
date_now,
|
||||
)
|
||||
|
||||
company_by_event = {
|
||||
event._origin.id or event.id: event.company_id
|
||||
for event in self
|
||||
}
|
||||
|
||||
currency_by_event = {
|
||||
event._origin.id or event.id: event.currency_id
|
||||
for event in self
|
||||
}
|
||||
|
||||
currency_by_id = {
|
||||
currency.id: currency
|
||||
for currency in self.env['res.currency'].browse(
|
||||
[event_subtotal['currency_id'][0] for event_subtotal in event_subtotals]
|
||||
)
|
||||
}
|
||||
|
||||
for event_subtotal in event_subtotals:
|
||||
price_subtotal = event_subtotal['price_subtotal']
|
||||
event_id = event_subtotal['event_id'][0]
|
||||
currency_id = event_subtotal['currency_id'][0]
|
||||
sale_price = currency_by_event[event_id]._convert(
|
||||
price_subtotal,
|
||||
currency_by_id[currency_id],
|
||||
company_by_event[event_id],
|
||||
date_now)
|
||||
if event_id in sale_price_by_event:
|
||||
sale_price_by_event[event_id] += sale_price
|
||||
else:
|
||||
sale_price_by_event[event_id] = sale_price
|
||||
|
||||
for event in self:
|
||||
event.sale_price_subtotal = sale_price_by_event.get(event._origin.id or event.id, 0)
|
||||
|
||||
def action_view_linked_orders(self):
|
||||
""" Redirects to the orders linked to the current events """
|
||||
sale_order_action = self.env["ir.actions.actions"]._for_xml_id("sale.action_orders")
|
||||
|
||||
@@ -44,12 +44,10 @@ class SaleOrder(models.Model):
|
||||
sale_orders_data = self.env['event.registration']._read_group(
|
||||
[('sale_order_id', 'in', self.ids),
|
||||
('state', '!=', 'cancel')],
|
||||
['sale_order_id'], ['sale_order_id']
|
||||
['sale_order_id'], ['__count'],
|
||||
)
|
||||
attendee_count_data = {
|
||||
sale_order_data['sale_order_id'][0]:
|
||||
sale_order_data['sale_order_id_count']
|
||||
for sale_order_data in sale_orders_data
|
||||
sale_order.id: count for sale_order, count in sale_orders_data
|
||||
}
|
||||
for sale_order in self:
|
||||
sale_order.attendee_count = attendee_count_data.get(sale_order.id, 0)
|
||||
|
||||
@@ -167,24 +167,24 @@ class FleetVehicle(models.Model):
|
||||
LogService = self.env['fleet.vehicle.log.services'].with_context(active_test=False)
|
||||
LogContract = self.env['fleet.vehicle.log.contract'].with_context(active_test=False)
|
||||
History = self.env['fleet.vehicle.assignation.log']
|
||||
odometers_data = Odometer.read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id'], ['vehicle_id'])
|
||||
services_data = LogService.read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id', 'active'], ['vehicle_id', 'active'], lazy=False)
|
||||
logs_data = LogContract.read_group([('vehicle_id', 'in', self.ids), ('state', '!=', 'closed')], ['vehicle_id', 'active'], ['vehicle_id', 'active'], lazy=False)
|
||||
histories_data = History.read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id'], ['vehicle_id'])
|
||||
odometers_data = Odometer._read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id'], ['__count'])
|
||||
services_data = LogService._read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id', 'active'], ['__count'])
|
||||
logs_data = LogContract._read_group([('vehicle_id', 'in', self.ids), ('state', '!=', 'closed')], ['vehicle_id', 'active'], ['__count'])
|
||||
histories_data = History._read_group([('vehicle_id', 'in', self.ids)], ['vehicle_id'], ['__count'])
|
||||
|
||||
mapped_odometer_data = defaultdict(lambda: 0)
|
||||
mapped_service_data = defaultdict(lambda: defaultdict(lambda: 0))
|
||||
mapped_log_data = defaultdict(lambda: defaultdict(lambda: 0))
|
||||
mapped_history_data = defaultdict(lambda: 0)
|
||||
|
||||
for odometer_data in odometers_data:
|
||||
mapped_odometer_data[odometer_data['vehicle_id'][0]] = odometer_data['vehicle_id_count']
|
||||
for service_data in services_data:
|
||||
mapped_service_data[service_data['vehicle_id'][0]][service_data['active']] = service_data['__count']
|
||||
for log_data in logs_data:
|
||||
mapped_log_data[log_data['vehicle_id'][0]][log_data['active']] = log_data['__count']
|
||||
for history_data in histories_data:
|
||||
mapped_history_data[history_data['vehicle_id'][0]] = history_data['vehicle_id_count']
|
||||
for vehicle, count in odometers_data:
|
||||
mapped_odometer_data[vehicle.id] = count
|
||||
for vehicle, active, count in services_data:
|
||||
mapped_service_data[vehicle.id][active] = count
|
||||
for vehicle, active, count in logs_data:
|
||||
mapped_log_data[vehicle.id][active] = count
|
||||
for vehicle, count in histories_data:
|
||||
mapped_history_data[vehicle.id] = count
|
||||
|
||||
for vehicle in self:
|
||||
vehicle.odometer_count = mapped_odometer_data[vehicle.id]
|
||||
|
||||
@@ -64,9 +64,9 @@ class FleetVehicleModel(models.Model):
|
||||
|
||||
def _compute_vehicle_count(self):
|
||||
group = self.env['fleet.vehicle']._read_group(
|
||||
[('model_id', 'in', self.ids)], ['id', 'model_id'], groupby='model_id', lazy=False,
|
||||
[('model_id', 'in', self.ids)], ['model_id'], aggregates=['__count'],
|
||||
)
|
||||
count_by_model = {entry['model_id'][0]: entry['__count'] for entry in group}
|
||||
count_by_model = {model.id: count for model, count in group}
|
||||
for model in self:
|
||||
model.vehicle_count = count_by_model.get(model.id, 0)
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class FleetVehicleModelBrand(models.Model):
|
||||
def _compute_model_count(self):
|
||||
model_data = self.env['fleet.vehicle.model']._read_group([
|
||||
('brand_id', 'in', self.ids),
|
||||
], ['brand_id'], ['brand_id'])
|
||||
models_brand = {x['brand_id'][0]: x['brand_id_count'] for x in model_data}
|
||||
], ['brand_id'], ['__count'])
|
||||
models_brand = {brand.id: count for brand, count in model_data}
|
||||
|
||||
for record in self:
|
||||
record.model_count = models_brand.get(record.id, 0)
|
||||
|
||||
@@ -666,15 +666,14 @@ class Challenge(models.Model):
|
||||
challenge_ended = force or end_date == fields.Date.to_string(yesterday)
|
||||
if challenge.reward_id and (challenge_ended or challenge.reward_realtime):
|
||||
# not using start_date as intemportal goals have a start date but no end_date
|
||||
reached_goals = self.env['gamification.goal'].read_group([
|
||||
reached_goals = self.env['gamification.goal']._read_group([
|
||||
('challenge_id', '=', challenge.id),
|
||||
('end_date', '=', end_date),
|
||||
('state', '=', 'reached')
|
||||
], fields=['user_id'], groupby=['user_id'])
|
||||
for reach_goals_user in reached_goals:
|
||||
if reach_goals_user['user_id_count'] == len(challenge.line_ids):
|
||||
], groupby=['user_id'], aggregates=['__count'])
|
||||
for user, count in reached_goals:
|
||||
if count == len(challenge.line_ids):
|
||||
# the user has succeeded every assigned goal
|
||||
user = self.env['res.users'].browse(reach_goals_user['user_id'][0])
|
||||
if challenge.reward_realtime:
|
||||
badges = self.env['gamification.badge.user'].search_count([
|
||||
('challenge_id', '=', challenge.id),
|
||||
|
||||
@@ -185,30 +185,18 @@ class Goal(models.Model):
|
||||
subquery_domain.append((field_date_name, '<=', end_date))
|
||||
|
||||
if definition.computation_mode == 'count':
|
||||
value_field_name = field_name + '_count'
|
||||
if field_name == 'id':
|
||||
# grouping on id does not work and is similar to search anyway
|
||||
users = Obj.search(subquery_domain)
|
||||
user_values = [{'id': user.id, value_field_name: 1} for user in users]
|
||||
else:
|
||||
user_values = Obj.read_group(subquery_domain, fields=[field_name], groupby=[field_name])
|
||||
user_values = Obj._read_group(subquery_domain, groupby=[field_name], aggregates=['__count'])
|
||||
|
||||
else: # sum
|
||||
value_field_name = definition.field_id.name
|
||||
if field_name == 'id':
|
||||
user_values = Obj.search_read(subquery_domain, fields=['id', value_field_name])
|
||||
else:
|
||||
user_values = Obj.read_group(subquery_domain, fields=[field_name, "%s:sum" % value_field_name], groupby=[field_name])
|
||||
user_values = Obj._read_group(subquery_domain, groupby=[field_name], aggregates=[f'{value_field_name}:sum'])
|
||||
|
||||
# user_values has format of read_group: [{'partner_id': 42, 'partner_id_count': 3},...]
|
||||
# user_values has format of _read_group: [(<partner>, <aggregate>), ...]
|
||||
for goal in [g for g in goals if g.id in query_goals]:
|
||||
for user_value in user_values:
|
||||
queried_value = field_name in user_value and user_value[field_name] or False
|
||||
if isinstance(queried_value, tuple) and len(queried_value) == 2 and isinstance(queried_value[0], int):
|
||||
queried_value = queried_value[0]
|
||||
for field_value, aggregate in user_values:
|
||||
queried_value = field_value.id if isinstance(field_value, models.Model) else field_value
|
||||
if queried_value == query_goals[goal.id]:
|
||||
new_value = user_value.get(value_field_name, goal.current)
|
||||
goals_to_write.update(goal._get_write_values(new_value))
|
||||
goals_to_write.update(goal._get_write_values(aggregate))
|
||||
|
||||
else:
|
||||
for goal in goals:
|
||||
@@ -223,8 +211,8 @@ class Goal(models.Model):
|
||||
|
||||
if definition.computation_mode == 'sum':
|
||||
field_name = definition.field_id.name
|
||||
res = Obj.read_group(domain, [field_name], [])
|
||||
new_value = res and res[0][field_name] or 0.0
|
||||
res = Obj._read_group(domain, [], [field_name])
|
||||
new_value = res[0][0] or 0.0
|
||||
|
||||
else: # computation mode = count
|
||||
new_value = Obj.search_count(domain)
|
||||
|
||||
@@ -26,8 +26,8 @@ class KarmaRank(models.Model):
|
||||
|
||||
@api.depends('user_ids')
|
||||
def _compute_rank_users_count(self):
|
||||
requests_data = self.env['res.users']._read_group([('rank_id', '!=', False)], ['rank_id'], ['rank_id'])
|
||||
requests_mapped_data = dict((data['rank_id'][0], data['rank_id_count']) for data in requests_data)
|
||||
requests_data = self.env['res.users']._read_group([('rank_id', '!=', False)], ['rank_id'], ['__count'])
|
||||
requests_mapped_data = {rank.id: count for rank, count in requests_data}
|
||||
for rank in self:
|
||||
rank.rank_users_count = requests_mapped_data.get(rank.id, 0)
|
||||
|
||||
|
||||
@@ -54,14 +54,14 @@ class Department(models.Model):
|
||||
department.master_department_id = int(department.parent_path.split('/')[0])
|
||||
|
||||
def _compute_total_employee(self):
|
||||
emp_data = self.env['hr.employee']._read_group([('department_id', 'in', self.ids)], ['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in emp_data)
|
||||
emp_data = self.env['hr.employee']._read_group([('department_id', 'in', self.ids)], ['department_id'], ['__count'])
|
||||
result = {department.id: count for department, count in emp_data}
|
||||
for department in self:
|
||||
department.total_employee = result.get(department.id, 0)
|
||||
|
||||
def _compute_plan_count(self):
|
||||
plans_data = self.env['hr.plan']._read_group([('department_id', 'in', self.ids)], ['department_id'], ['department_id'])
|
||||
plans_count = {x['department_id'][0]: x['department_id_count'] for x in plans_data}
|
||||
plans_data = self.env['hr.plan']._read_group([('department_id', 'in', self.ids)], ['department_id'], ['__count'])
|
||||
plans_count = {department.id: count for department, count in plans_data}
|
||||
for department in self:
|
||||
department.plans_count = plans_count.get(department.id, 0)
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ class Job(models.Model):
|
||||
|
||||
@api.depends('no_of_recruitment', 'employee_ids.job_id', 'employee_ids.active')
|
||||
def _compute_employees(self):
|
||||
employee_data = self.env['hr.employee']._read_group([('job_id', 'in', self.ids)], ['job_id'], ['job_id'])
|
||||
result = dict((data['job_id'][0], data['job_id_count']) for data in employee_data)
|
||||
employee_data = self.env['hr.employee']._read_group([('job_id', 'in', self.ids)], ['job_id'], ['__count'])
|
||||
result = {job.id: count for job, count in employee_data}
|
||||
for job in self:
|
||||
job.no_of_employee = result.get(job.id, 0)
|
||||
job.expected_employees = result.get(job.id, 0) + job.no_of_recruitment
|
||||
|
||||
@@ -21,7 +21,7 @@ class HrPlan(models.Model):
|
||||
|
||||
@api.depends('plan_activity_type_ids')
|
||||
def _compute_steps_count(self):
|
||||
activity_type_data = self.env['hr.plan.activity.type']._read_group([('plan_id', 'in', self.ids)], ['plan_id'], ['plan_id'])
|
||||
steps_count = {x['plan_id'][0]: x['plan_id_count'] for x in activity_type_data}
|
||||
activity_type_data = self.env['hr.plan.activity.type']._read_group([('plan_id', 'in', self.ids)], ['plan_id'], ['__count'])
|
||||
steps_count = {plan.id: count for plan, count in activity_type_data}
|
||||
for plan in self:
|
||||
plan.steps_count = steps_count.get(plan.id, 0)
|
||||
|
||||
@@ -197,12 +197,6 @@ class HrEmployee(models.Model):
|
||||
'Your attendances have probably been modified manually by human resources.') % {'empl_name': self.sudo().name, })
|
||||
return attendance
|
||||
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
if 'pin' in groupby or 'pin' in self.env.context.get('group_by', '') or self.env.context.get('no_group_by'):
|
||||
raise exceptions.UserError(_('Such grouping is not allowed.'))
|
||||
return super(HrEmployee, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
def _compute_presence_icon(self):
|
||||
res = super()._compute_presence_icon()
|
||||
# All employee must chek in or check out. Everybody must have an icon
|
||||
|
||||
@@ -32,8 +32,8 @@ class ResourceCalendar(models.Model):
|
||||
count_data = self.env['hr.contract']._read_group(
|
||||
[('resource_calendar_id', 'in', self.ids)],
|
||||
['resource_calendar_id'],
|
||||
['resource_calendar_id'])
|
||||
mapped_counts = {cd['resource_calendar_id'][0]: cd['resource_calendar_id_count'] for cd in count_data}
|
||||
['__count'])
|
||||
mapped_counts = {resource_calendar.id: count for resource_calendar, count in count_data}
|
||||
for calendar in self:
|
||||
calendar.contracts_count = mapped_counts.get(calendar.id, 0)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class ResourceResource(models.Model):
|
||||
calendars_within_period_per_resource = defaultdict(lambda: defaultdict(Intervals)) # keys are [resource id:integer][calendar:self.env['resource.calendar']]
|
||||
# Employees that have ever had an active contract
|
||||
employee_ids_with_active_contracts = {
|
||||
contract['employee_id'][0] for contract in
|
||||
employee.id for [employee] in
|
||||
self.env['hr.contract']._read_group(
|
||||
domain=[
|
||||
('employee_id', 'in', self.employee_id.ids),
|
||||
@@ -25,7 +25,7 @@ class ResourceResource(models.Model):
|
||||
'|', ('state', '=', 'close'),
|
||||
'&', ('state', '=', 'draft'), ('kanban_state', '=', 'done')
|
||||
],
|
||||
fields=['employee_id'], groupby=['employee_id']
|
||||
groupby=['employee_id'],
|
||||
)
|
||||
}
|
||||
resource_without_contract = self.filtered(
|
||||
|
||||
@@ -8,8 +8,8 @@ class HrDepartment(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
def _compute_expense_sheets_to_approve(self):
|
||||
expense_sheet_data = self.env['hr.expense.sheet']._read_group([('department_id', 'in', self.ids), ('state', '=', 'submit')], ['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in expense_sheet_data)
|
||||
expense_sheet_data = self.env['hr.expense.sheet']._read_group([('department_id', 'in', self.ids), ('state', '=', 'submit')], ['department_id'], ['__count'])
|
||||
result = {department.id: count for department, count in expense_sheet_data}
|
||||
for department in self:
|
||||
department.expense_sheets_to_approve_count = result.get(department.id, 0)
|
||||
|
||||
|
||||
@@ -215,8 +215,8 @@ class HrExpense(models.Model):
|
||||
expense.label_convert_rate = rate_txt
|
||||
|
||||
def _compute_attachment_number(self):
|
||||
attachment_data = self.env['ir.attachment']._read_group([('res_model', '=', 'hr.expense'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id'])
|
||||
attachment = dict((data['res_id'], data['res_id_count']) for data in attachment_data)
|
||||
attachment_data = self.env['ir.attachment']._read_group([('res_model', '=', 'hr.expense'), ('res_id', 'in', self.ids)], ['res_id'], ['__count'])
|
||||
attachment = dict(attachment_data)
|
||||
for expense in self:
|
||||
expense.attachment_number = attachment.get(expense._origin.id, 0)
|
||||
|
||||
@@ -611,17 +611,16 @@ class HrExpense(models.Model):
|
||||
if not self.env.user.employee_ids:
|
||||
return expense_state
|
||||
target_currency = self.env.company.currency_id
|
||||
expenses = self.read_group(
|
||||
expenses = self._read_group(
|
||||
[
|
||||
('employee_id', 'in', self.env.user.employee_ids.ids),
|
||||
('payment_mode', '=', 'own_account'),
|
||||
('state', 'in', ['draft', 'reported', 'approved'])
|
||||
], ['total_amount', 'currency_id', 'state'], ['state', 'currency_id'], lazy=False)
|
||||
for expense in expenses:
|
||||
state = expense['state']
|
||||
currency = self.env['res.currency'].browse(expense['currency_id'][0]) if expense['currency_id'] else target_currency
|
||||
], ['state', 'currency_id'], ['total_amount:sum'])
|
||||
for state, currency, total_amount_sum in expenses:
|
||||
currency = currency or target_currency
|
||||
amount = currency._convert(
|
||||
expense['total_amount'], target_currency, self.env.company, fields.Date.today())
|
||||
total_amount_sum, target_currency, self.env.company, fields.Date.today())
|
||||
expense_state[state]['amount'] += amount
|
||||
return expense_state
|
||||
|
||||
@@ -975,8 +974,8 @@ class HrExpenseSheet(models.Model):
|
||||
|
||||
@api.depends('expense_line_ids')
|
||||
def _compute_expense_number(self):
|
||||
read_group_result = self.env['hr.expense']._read_group([('sheet_id', 'in', self.ids)], ['sheet_id'], ['sheet_id'])
|
||||
result = dict((data['sheet_id'][0], data['sheet_id_count']) for data in read_group_result)
|
||||
read_group_result = self.env['hr.expense']._read_group([('sheet_id', 'in', self.ids)], ['sheet_id'], ['__count'])
|
||||
result = {sheet.id: count for sheet, count in read_group_result}
|
||||
for sheet in self:
|
||||
sheet.expense_number = result.get(sheet.id, 0)
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class Employee(models.Model):
|
||||
def _compute_employee_cars_count(self):
|
||||
rg = self.env['fleet.vehicle.assignation.log']._read_group([
|
||||
('driver_employee_id', 'in', self.ids),
|
||||
], ['driver_employee_id'], ['driver_employee_id'])
|
||||
cars_count = {r['driver_employee_id'][0]: r['driver_employee_id_count'] for r in rg}
|
||||
], ['driver_employee_id'], ['__count'])
|
||||
cars_count = {driver_employee.id: count for driver_employee, count in rg}
|
||||
for employee in self:
|
||||
employee.employee_cars_count = cars_count.get(employee.id, 0)
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ class FleetVehicleAssignationLog(models.Model):
|
||||
def _compute_attachment_number(self):
|
||||
attachment_data = self.env['ir.attachment']._read_group([
|
||||
('res_model', '=', 'fleet.vehicle.assignation.log'),
|
||||
('res_id', 'in', self.ids)], ['res_id'], ['res_id'])
|
||||
attachment = dict((data['res_id'], data['res_id_count']) for data in attachment_data)
|
||||
('res_id', 'in', self.ids)], ['res_id'], ['__count'])
|
||||
attachment = dict(attachment_data)
|
||||
for doc in self:
|
||||
doc.attachment_number = attachment.get(doc.id, 0)
|
||||
|
||||
|
||||
@@ -28,19 +28,19 @@ class Department(models.Model):
|
||||
leave_data = Requests._read_group(
|
||||
[('department_id', 'in', self.ids),
|
||||
('state', '=', 'confirm')],
|
||||
['department_id'], ['department_id'])
|
||||
['department_id'], ['__count'])
|
||||
allocation_data = Allocations._read_group(
|
||||
[('department_id', 'in', self.ids),
|
||||
('state', '=', 'confirm')],
|
||||
['department_id'], ['department_id'])
|
||||
['department_id'], ['__count'])
|
||||
absence_data = Requests._read_group(
|
||||
[('department_id', 'in', self.ids), ('state', 'not in', ['cancel', 'refuse']),
|
||||
('date_from', '<=', today_end), ('date_to', '>=', today_start)],
|
||||
['department_id'], ['department_id'])
|
||||
['department_id'], ['__count'])
|
||||
|
||||
res_leave = dict((data['department_id'][0], data['department_id_count']) for data in leave_data)
|
||||
res_allocation = dict((data['department_id'][0], data['department_id_count']) for data in allocation_data)
|
||||
res_absence = dict((data['department_id'][0], data['department_id_count']) for data in absence_data)
|
||||
res_leave = {department.id: count for department, count in leave_data}
|
||||
res_allocation = {department.id: count for department, count in allocation_data}
|
||||
res_absence = {department.id: count for department, count in absence_data}
|
||||
|
||||
for department in self:
|
||||
department.leave_to_approve_count = res_leave.get(department.id, 0)
|
||||
|
||||
@@ -88,13 +88,13 @@ class HrEmployeeBase(models.AbstractModel):
|
||||
('state', '=', 'validate'),
|
||||
('date_from', '<=', current_date),
|
||||
('date_to', '>=', current_date),
|
||||
], ['number_of_days:sum', 'employee_id'], ['employee_id'])
|
||||
rg_results = dict((d['employee_id'][0], {"employee_id_count": d['employee_id_count'], "number_of_days": d['number_of_days']}) for d in data)
|
||||
], ['employee_id'], ['__count', 'number_of_days:sum'])
|
||||
rg_results = {employee.id: (count, days) for employee, count, days in data}
|
||||
for employee in self:
|
||||
result = rg_results.get(employee.id)
|
||||
employee.allocation_count = float_round(result['number_of_days'], precision_digits=2) if result else 0.0
|
||||
count, days = rg_results.get(employee.id, (0, 0))
|
||||
employee.allocation_count = float_round(days, precision_digits=2)
|
||||
employee.allocation_display = "%g" % employee.allocation_count
|
||||
employee.allocations_count = result['employee_id_count'] if result else 0.0
|
||||
employee.allocations_count = count
|
||||
|
||||
def _compute_allocation_remaining_display(self):
|
||||
allocations = self.env['hr.leave.allocation'].search([('employee_id', 'in', self.ids)])
|
||||
|
||||
@@ -1067,12 +1067,6 @@ class HolidaysRequest(models.Model):
|
||||
def _get_mail_redirect_suggested_company(self):
|
||||
return self.holiday_status_id.company_id
|
||||
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
if not self.user_has_groups('hr_holidays.group_hr_holidays_user') and 'private_name' in groupby:
|
||||
raise UserError(_('Such grouping is not allowed.'))
|
||||
return super(HolidaysRequest, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
####################################################
|
||||
# Business methods
|
||||
####################################################
|
||||
@@ -1705,13 +1699,12 @@ class HolidaysRequest(models.Model):
|
||||
('display_type', '=', False),
|
||||
('day_period', '!=', 'lunch'),
|
||||
]
|
||||
attendances = self.env['resource.calendar.attendance'].read_group(domain,
|
||||
['ids:array_agg(id)', 'hour_from:min(hour_from)', 'hour_to:max(hour_to)',
|
||||
'week_type', 'dayofweek', 'day_period'],
|
||||
['week_type', 'dayofweek', 'day_period'], lazy=False)
|
||||
attendances = self.env['resource.calendar.attendance']._read_group(domain,
|
||||
['week_type', 'dayofweek', 'day_period'],
|
||||
['hour_from:min', 'hour_to:max'])
|
||||
|
||||
# Must be sorted by dayofweek ASC and day_period DESC
|
||||
attendances = sorted([DummyAttendance(group['hour_from'], group['hour_to'], group['dayofweek'], group['day_period'], group['week_type']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != 'morning'))
|
||||
attendances = sorted([DummyAttendance(hour_from, hour_to, dayofweek, day_period, week_type) for week_type, dayofweek, day_period, hour_from, hour_to in attendances], key=lambda att: (att.dayofweek, att.day_period != 'morning'))
|
||||
|
||||
default_value = DummyAttendance(0, 0, 0, 'morning', False)
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ class AccrualPlan(models.Model):
|
||||
def _compute_level_count(self):
|
||||
level_read_group = self.env['hr.leave.accrual.level']._read_group(
|
||||
[('accrual_plan_id', 'in', self.ids)],
|
||||
fields=['accrual_plan_id'],
|
||||
groupby=['accrual_plan_id'],
|
||||
aggregates=['__count'],
|
||||
)
|
||||
mapped_count = {group['accrual_plan_id'][0]: group['accrual_plan_id_count'] for group in level_read_group}
|
||||
mapped_count = {accrual_plan.id: count for accrual_plan, count in level_read_group}
|
||||
for plan in self:
|
||||
plan.level_count = mapped_count.get(plan.id, 0)
|
||||
|
||||
@@ -50,10 +50,10 @@ class AccrualPlan(models.Model):
|
||||
def _compute_employee_count(self):
|
||||
allocations_read_group = self.env['hr.leave.allocation']._read_group(
|
||||
[('accrual_plan_id', 'in', self.ids)],
|
||||
['accrual_plan_id', 'employee_count:count_distinct(employee_id)'],
|
||||
['accrual_plan_id'],
|
||||
['employee_id:count_distinct'],
|
||||
)
|
||||
allocations_dict = {res['accrual_plan_id'][0]: res['employee_count'] for res in allocations_read_group}
|
||||
allocations_dict = {accrual_plan.id: count for accrual_plan, count in allocations_read_group}
|
||||
for plan in self:
|
||||
plan.employees_count = allocations_dict.get(plan.id, 0)
|
||||
|
||||
|
||||
@@ -313,14 +313,12 @@ class HolidaysAllocation(models.Model):
|
||||
@api.depends('holiday_status_id', 'allocation_type', 'number_of_hours_display', 'number_of_days_display', 'date_to')
|
||||
def _compute_from_holiday_status_id(self):
|
||||
accrual_allocations = self.filtered(lambda alloc: alloc.allocation_type == 'accrual' and not alloc.accrual_plan_id and alloc.holiday_status_id)
|
||||
accruals_dict = {}
|
||||
if accrual_allocations:
|
||||
accruals_read_group = self.env['hr.leave.accrual.plan'].read_group(
|
||||
[('time_off_type_id', 'in', accrual_allocations.holiday_status_id.ids)],
|
||||
['time_off_type_id', 'ids:array_agg(id)'],
|
||||
['time_off_type_id'],
|
||||
)
|
||||
accruals_dict = {res['time_off_type_id'][0]: res['ids'] for res in accruals_read_group}
|
||||
accruals_read_group = self.env['hr.leave.accrual.plan']._read_group(
|
||||
[('time_off_type_id', 'in', accrual_allocations.holiday_status_id.ids)],
|
||||
['time_off_type_id'],
|
||||
['id:array_agg'],
|
||||
)
|
||||
accruals_dict = {time_off_type.id: ids for time_off_type, ids in accruals_read_group}
|
||||
for allocation in self:
|
||||
allocation.number_of_days = allocation.number_of_days_display
|
||||
if allocation.type_request_unit == 'hour':
|
||||
|
||||
@@ -496,9 +496,9 @@ class HolidaysType(models.Model):
|
||||
grouped_res = self.env['hr.leave.allocation']._read_group(
|
||||
domain,
|
||||
['holiday_status_id'],
|
||||
['holiday_status_id'],
|
||||
['__count'],
|
||||
)
|
||||
grouped_dict = dict((data['holiday_status_id'][0], data['holiday_status_id_count']) for data in grouped_res)
|
||||
grouped_dict = {holiday_status.id: count for holiday_status, count in grouped_res}
|
||||
for allocation in self:
|
||||
allocation.allocation_count = grouped_dict.get(allocation.id, 0)
|
||||
|
||||
@@ -514,15 +514,15 @@ class HolidaysType(models.Model):
|
||||
grouped_res = self.env['hr.leave']._read_group(
|
||||
domain,
|
||||
['holiday_status_id'],
|
||||
['holiday_status_id'],
|
||||
['__count'],
|
||||
)
|
||||
grouped_dict = dict((data['holiday_status_id'][0], data['holiday_status_id_count']) for data in grouped_res)
|
||||
grouped_dict = {holiday_status.id: count for holiday_status, count in grouped_res}
|
||||
for allocation in self:
|
||||
allocation.group_days_leave = grouped_dict.get(allocation.id, 0)
|
||||
|
||||
def _compute_accrual_count(self):
|
||||
accrual_allocations = self.env['hr.leave.accrual.plan']._read_group([('time_off_type_id', 'in', self.ids)], ['time_off_type_id'], ['time_off_type_id'])
|
||||
mapped_data = dict((data['time_off_type_id'][0], data['time_off_type_id_count']) for data in accrual_allocations)
|
||||
accrual_allocations = self.env['hr.leave.accrual.plan']._read_group([('time_off_type_id', 'in', self.ids)], ['time_off_type_id'], ['__count'])
|
||||
mapped_data = {time_off_type.id: count for time_off_type, count in accrual_allocations}
|
||||
for leave_type in self:
|
||||
leave_type.accrual_count = mapped_data.get(leave_type.id, 0)
|
||||
|
||||
|
||||
@@ -66,11 +66,10 @@ class User(models.Model):
|
||||
if not any(u.has_group(approver_group) for u in self):
|
||||
return
|
||||
|
||||
res = self.env['hr.employee'].read_group(
|
||||
res = self.env['hr.employee']._read_group(
|
||||
[('leave_manager_id', 'in', self.ids)],
|
||||
['leave_manager_id'],
|
||||
['leave_manager_id'])
|
||||
responsibles_to_remove_ids = set(self.ids) - {x['leave_manager_id'][0] for x in res}
|
||||
responsibles_to_remove_ids = set(self.ids) - {leave_manager.id for [leave_manager] in res}
|
||||
if responsibles_to_remove_ids:
|
||||
self.browse(responsibles_to_remove_ids).write({
|
||||
'groups_id': [Command.unlink(self.env.ref(approver_group).id)],
|
||||
|
||||
@@ -108,12 +108,12 @@ class ResourceCalendar(models.Model):
|
||||
associated_leaves_count = fields.Integer("Time Off Count", compute='_compute_associated_leaves_count')
|
||||
|
||||
def _compute_associated_leaves_count(self):
|
||||
leaves_read_group = self.env['resource.calendar.leaves'].read_group(
|
||||
[('resource_id', '=', False)],
|
||||
leaves_read_group = self.env['resource.calendar.leaves']._read_group(
|
||||
[('resource_id', '=', False), ('calendar_id', 'in', [False, *self.ids])],
|
||||
['calendar_id'],
|
||||
['calendar_id']
|
||||
['__count'],
|
||||
)
|
||||
result = dict((data['calendar_id'][0] if data['calendar_id'] else 'global', data['calendar_id_count']) for data in leaves_read_group)
|
||||
result = {calendar.id if calendar else 'global': count for calendar, count in leaves_read_group}
|
||||
global_leave_count = result.get('global', 0)
|
||||
for calendar in self:
|
||||
calendar.associated_leaves_count = result.get(calendar.id, 0) + global_leave_count
|
||||
|
||||
@@ -205,8 +205,8 @@ class Applicant(models.Model):
|
||||
def _get_attachment_number(self):
|
||||
read_group_res = self.env['ir.attachment']._read_group(
|
||||
[('res_model', '=', 'hr.applicant'), ('res_id', 'in', self.ids)],
|
||||
['res_id'], ['res_id'])
|
||||
attach_data = dict((res['res_id'], res['res_id_count']) for res in read_group_res)
|
||||
['res_id'], ['__count'])
|
||||
attach_data = dict(read_group_res)
|
||||
for record in self:
|
||||
record.attachment_number = attach_data.get(record.id, 0)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class HrDepartment(models.Model):
|
||||
@@ -17,8 +17,8 @@ class HrDepartment(models.Model):
|
||||
if self.env.user.has_group('hr_recruitment.group_hr_recruitment_interviewer'):
|
||||
applicant_data = self.env['hr.applicant']._read_group(
|
||||
[('department_id', 'in', self.ids), ('stage_id.sequence', '<=', '1')],
|
||||
['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in applicant_data)
|
||||
['department_id'], ['__count'])
|
||||
result = {department.id: count for department, count in applicant_data}
|
||||
for department in self:
|
||||
department.new_applicant_count = result.get(department.id, 0)
|
||||
else:
|
||||
@@ -27,9 +27,9 @@ class HrDepartment(models.Model):
|
||||
def _compute_recruitment_stats(self):
|
||||
job_data = self.env['hr.job']._read_group(
|
||||
[('department_id', 'in', self.ids)],
|
||||
['no_of_hired_employee', 'no_of_recruitment', 'department_id'], ['department_id'])
|
||||
new_emp = dict((data['department_id'][0], data['no_of_hired_employee']) for data in job_data)
|
||||
expected_emp = dict((data['department_id'][0], data['no_of_recruitment']) for data in job_data)
|
||||
['department_id'], ['no_of_hired_employee:sum', 'no_of_recruitment:sum'])
|
||||
new_emp = {department.id: nb_employee for department, nb_employee, __ in job_data}
|
||||
expected_emp = {department.id: nb_recruitment for department, __, nb_recruitment in job_data}
|
||||
for department in self:
|
||||
department.new_hired_employee = new_emp.get(department.id, 0)
|
||||
department.expected_employee = expected_emp.get(department.id, 0)
|
||||
|
||||
@@ -134,14 +134,14 @@ class Job(models.Model):
|
||||
('active', '=', True),
|
||||
'&',
|
||||
('active', '=', False), ('refuse_reason_id', '!=', False),
|
||||
], ['job_id'], ['job_id'])
|
||||
result = dict((data['job_id'][0], data['job_id_count']) for data in read_group_result)
|
||||
], ['job_id'], ['__count'])
|
||||
result = {job.id: count for job, count in read_group_result}
|
||||
for job in self:
|
||||
job.all_application_count = result.get(job.id, 0)
|
||||
|
||||
def _compute_application_count(self):
|
||||
read_group_result = self.env['hr.applicant']._read_group([('job_id', 'in', self.ids)], ['job_id'], ['job_id'])
|
||||
result = dict((data['job_id'][0], data['job_id_count']) for data in read_group_result)
|
||||
read_group_result = self.env['hr.applicant']._read_group([('job_id', 'in', self.ids)], ['job_id'], ['__count'])
|
||||
result = {job.id: count for job, count in read_group_result}
|
||||
for job in self:
|
||||
job.application_count = result.get(job.id, 0)
|
||||
|
||||
@@ -189,8 +189,8 @@ class Job(models.Model):
|
||||
hired_data = self.env['hr.applicant']._read_group([
|
||||
('job_id', 'in', self.ids),
|
||||
('stage_id', 'in', hired_stages.ids),
|
||||
], ['job_id'], ['job_id'])
|
||||
job_hires = {data['job_id'][0]: data['job_id_count'] for data in hired_data}
|
||||
], ['job_id'], ['__count'])
|
||||
job_hires = {job.id: count for job, count in hired_data}
|
||||
for job in self:
|
||||
job.applicant_hired = job_hires.get(job.id, 0)
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ class RecruitmentStage(models.Model):
|
||||
|
||||
@api.depends('hired_stage')
|
||||
def _compute_is_warning_visible(self):
|
||||
applicant_data = self.env['hr.applicant']._read_group([('stage_id', 'in', self.ids)], ['stage_id'], 'stage_id')
|
||||
applicants = dict((data['stage_id'][0], data['stage_id_count']) for data in applicant_data)
|
||||
applicant_data = self.env['hr.applicant']._read_group([('stage_id', 'in', self.ids)], ['stage_id'], ['__count'])
|
||||
applicants = {stage.id: count for stage, count in applicant_data}
|
||||
for stage in self:
|
||||
if stage._origin.hired_stage and not stage.hired_stage and applicants.get(stage._origin.id):
|
||||
stage.is_warning_visible = True
|
||||
|
||||
@@ -23,11 +23,11 @@ class ResUsers(models.Model):
|
||||
interviewer_group = self.env.ref('hr_recruitment.group_hr_recruitment_interviewer')
|
||||
recruitment_group = self.env.ref('hr_recruitment.group_hr_recruitment_user')
|
||||
|
||||
job_interviewers = self.env['hr.job']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'], ['interviewer_ids'])
|
||||
user_ids = {j['interviewer_ids'][0] for j in job_interviewers}
|
||||
job_interviewers = self.env['hr.job']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'])
|
||||
user_ids = {interviewer.id for [interviewer] in job_interviewers}
|
||||
|
||||
application_interviewers = self.env['hr.applicant']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'], ['interviewer_ids'])
|
||||
user_ids |= {a['interviewer_ids'][0] for a in application_interviewers}
|
||||
application_interviewers = self.env['hr.applicant']._read_group([('interviewer_ids', 'in', self.ids)], ['interviewer_ids'])
|
||||
user_ids |= {interviewer.id for [interviewer] in application_interviewers}
|
||||
|
||||
# Remove users that are no longer interviewers on at least a job or an application
|
||||
users_to_remove = set(self.ids) - (user_ids | set(recruitment_group.users.ids))
|
||||
|
||||
@@ -137,14 +137,14 @@ class TimesheetCustomerPortal(CustomerPortal):
|
||||
timesheets = Timesheet_sudo.search(domain, order=orderby, limit=_items_per_page, offset=pager['offset'])
|
||||
if field:
|
||||
if groupby == 'date':
|
||||
raw_timesheets_group = Timesheet_sudo.read_group(
|
||||
domain, ["unit_amount:sum", "ids:array_agg(id)"], ["date:day"]
|
||||
raw_timesheets_group = Timesheet_sudo._read_group(
|
||||
domain, ['date:day'], ['unit_amount:sum', 'id:array_agg']
|
||||
)
|
||||
grouped_timesheets = [(Timesheet_sudo.browse(group["ids"]), group["unit_amount"]) for group in raw_timesheets_group]
|
||||
grouped_timesheets = [(records, unit_amount) for __, unit_amount, records in raw_timesheets_group]
|
||||
|
||||
else:
|
||||
time_data = Timesheet_sudo.read_group(domain, [field, 'unit_amount:sum'], [field])
|
||||
mapped_time = dict([(m[field][0] if m[field] else False, m['unit_amount']) for m in time_data])
|
||||
time_data = Timesheet_sudo._read_group(domain, [field], ['unit_amount:sum'])
|
||||
mapped_time = {field.id: unit_amount for field, unit_amount in time_data}
|
||||
grouped_timesheets = [(Timesheet_sudo.concat(*g), mapped_time[k.id]) for k, g in groupbyelem(timesheets, itemgetter(field))]
|
||||
return timesheets, grouped_timesheets
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ class HrEmployee(models.Model):
|
||||
|
||||
name_mapping = dict(res)
|
||||
employees_count_per_user = {
|
||||
res['user_id'][0]: res['user_id_count']
|
||||
for res in self.env['hr.employee'].sudo()._read_group(
|
||||
user.id: count
|
||||
for user, count in self.env['hr.employee'].sudo()._read_group(
|
||||
[('user_id', 'in', self.user_id.ids), ('company_id', 'in', allowed_company_ids)],
|
||||
['user_id'],
|
||||
['user_id'],
|
||||
['__count'],
|
||||
)
|
||||
}
|
||||
for employee in self:
|
||||
|
||||
@@ -79,10 +79,10 @@ class Project(models.Model):
|
||||
def _compute_remaining_hours(self):
|
||||
timesheets_read_group = self.env['account.analytic.line']._read_group(
|
||||
[('project_id', 'in', self.ids)],
|
||||
['project_id', 'unit_amount'],
|
||||
['project_id'],
|
||||
lazy=False)
|
||||
timesheet_time_dict = {res['project_id'][0]: res['unit_amount'] for res in timesheets_read_group}
|
||||
['unit_amount:sum'],
|
||||
)
|
||||
timesheet_time_dict = {project.id: unit_amount_sum for project, unit_amount_sum in timesheets_read_group}
|
||||
for project in self:
|
||||
project.remaining_hours = project.allocated_hours - timesheet_time_dict.get(project.id, 0)
|
||||
project.is_project_overtime = project.remaining_hours < 0
|
||||
@@ -120,28 +120,23 @@ class Project(models.Model):
|
||||
|
||||
@api.depends('timesheet_ids')
|
||||
def _compute_total_timesheet_time(self):
|
||||
timesheets_read_group = self.env['account.analytic.line'].read_group(
|
||||
timesheets_read_group = self.env['account.analytic.line']._read_group(
|
||||
[('project_id', 'in', self.ids)],
|
||||
['project_id', 'unit_amount', 'product_uom_id'],
|
||||
['project_id', 'product_uom_id'],
|
||||
lazy=False)
|
||||
['unit_amount:sum'],
|
||||
)
|
||||
|
||||
timesheet_time_dict = defaultdict(list)
|
||||
uom_ids = set(self.timesheet_encode_uom_id.ids)
|
||||
for project, product_uom, unit_amount_sum in timesheets_read_group:
|
||||
timesheet_time_dict[project.id].append((product_uom, unit_amount_sum))
|
||||
|
||||
for result in timesheets_read_group:
|
||||
uom_id = result['product_uom_id'] and result['product_uom_id'][0]
|
||||
if uom_id:
|
||||
uom_ids.add(uom_id)
|
||||
timesheet_time_dict[result['project_id'][0]].append((uom_id, result['unit_amount']))
|
||||
|
||||
uoms_dict = {uom.id: uom for uom in self.env['uom.uom'].browse(uom_ids)}
|
||||
for project in self:
|
||||
# Timesheets may be stored in a different unit of measure, so first
|
||||
# we convert all of them to the reference unit
|
||||
# if the timesheet has no product_uom_id then we take the one of the project
|
||||
total_time = 0.0
|
||||
for product_uom_id, unit_amount in timesheet_time_dict[project.id]:
|
||||
factor = uoms_dict.get(product_uom_id, project.timesheet_encode_uom_id).factor_inv
|
||||
for product_uom, unit_amount in timesheet_time_dict[project.id]:
|
||||
factor = (product_uom or project.timesheet_encode_uom_id).factor_inv
|
||||
total_time += unit_amount * (1.0 if project.encode_uom_in_days else factor)
|
||||
# Now convert to the proper unit of measure set in the settings
|
||||
total_time *= project.timesheet_encode_uom_id.factor
|
||||
|
||||
@@ -66,8 +66,8 @@ class Task(models.Model):
|
||||
for task in self:
|
||||
task.effective_hours = round(sum(task.timesheet_ids.mapped('unit_amount')), 2)
|
||||
return
|
||||
timesheet_read_group = self.env['account.analytic.line'].read_group([('task_id', 'in', self.ids)], ['unit_amount', 'task_id'], ['task_id'])
|
||||
timesheets_per_task = {res['task_id'][0]: res['unit_amount'] for res in timesheet_read_group}
|
||||
timesheet_read_group = self.env['account.analytic.line']._read_group([('task_id', 'in', self.ids)], ['task_id'], ['unit_amount:sum'])
|
||||
timesheets_per_task = {task.id: amount for task, amount in timesheet_read_group}
|
||||
for task in self:
|
||||
task.effective_hours = round(timesheets_per_task.get(task.id, 0.0), 2)
|
||||
|
||||
@@ -223,9 +223,8 @@ class Task(models.Model):
|
||||
timesheet_data = self.env['account.analytic.line'].sudo()._read_group(
|
||||
[('task_id', 'in', self.ids)],
|
||||
['task_id'],
|
||||
['task_id'],
|
||||
)
|
||||
task_with_timesheets_ids = [res['task_id'][0] for res in timesheet_data]
|
||||
task_with_timesheets_ids = [task.id for task in timesheet_data]
|
||||
if task_with_timesheets_ids:
|
||||
if len(task_with_timesheets_ids) > 1:
|
||||
warning_msg = _("These tasks have some timesheet entries referencing them. Before removing these tasks, you have to remove these timesheet entries.")
|
||||
|
||||
@@ -15,32 +15,32 @@ class AccountAnalyticLine(models.Model):
|
||||
def _populate_factories(self):
|
||||
projects_groups = self.env['project.project']._read_group(
|
||||
domain=[('id', 'in', self.env.registry.populated_models["project.project"])],
|
||||
fields=['company_id', 'ids:array_agg(id)'],
|
||||
groupby=['company_id'],
|
||||
aggregates=['id:array_agg'],
|
||||
)
|
||||
project_ids = []
|
||||
projects_per_company = defaultdict(list)
|
||||
for group in projects_groups:
|
||||
project_ids += group['ids']
|
||||
projects_per_company[group['company_id'][0]] = group['ids']
|
||||
for company, ids in projects_groups:
|
||||
project_ids += ids
|
||||
projects_per_company[company.id] = ids
|
||||
|
||||
tasks_per_project = {
|
||||
group['project_id'][0]: group['ids']
|
||||
for group in self.env['project.task']._read_group(
|
||||
project.id: ids
|
||||
for project, ids in self.env['project.task']._read_group(
|
||||
domain=[
|
||||
('id', 'in', self.env.registry.populated_models["project.task"]),
|
||||
('project_id', 'in', project_ids),
|
||||
],
|
||||
fields=['project_id', 'ids:array_agg(id)'],
|
||||
groupby=['project_id'],
|
||||
aggregates=['id:array_agg'],
|
||||
)
|
||||
}
|
||||
employees_per_company = {
|
||||
group['company_id'][0]: group['ids']
|
||||
for group in self.env['hr.employee']._read_group(
|
||||
company.id: ids
|
||||
for company, ids in self.env['hr.employee']._read_group(
|
||||
domain=[('id', 'in', self.env.registry.populated_models["hr.employee"])],
|
||||
fields=['company_id', 'ids:array_agg(id)'],
|
||||
groupby=['company_id'],
|
||||
aggregates=['id:array_agg'],
|
||||
)
|
||||
}
|
||||
# Companies with projects and employees only
|
||||
|
||||
@@ -16,9 +16,9 @@ class HrEmployeDeleteWizard(models.TransientModel):
|
||||
def _compute_has_timesheet(self):
|
||||
timesheet_read_group = self.env['account.analytic.line']._read_group([
|
||||
('employee_id', 'in', self.employee_ids.ids)],
|
||||
['employee_id'], ['employee_id'],
|
||||
['employee_id'],
|
||||
)
|
||||
timesheet_employee_map = set(employee_info['employee_id'][0] for employee_info in timesheet_read_group)
|
||||
timesheet_employee_map = {employee.id for [employee] in timesheet_read_group}
|
||||
for wizard in self:
|
||||
wizard.has_timesheet = timesheet_employee_map & set(wizard.employee_ids.ids)
|
||||
|
||||
|
||||
@@ -24,12 +24,11 @@ class TestTimesheetAttendance(TestCommonTimesheet):
|
||||
'unit_amount': 6.0,
|
||||
'date': datetime(2022, 2, 9),
|
||||
})
|
||||
report_data = self.env['hr.timesheet.attendance.report']._read_group(
|
||||
total_timesheet, total_attendance = self.env['hr.timesheet.attendance.report']._read_group(
|
||||
[('user_id', '=', self.user_employee.id),
|
||||
('date', '>=', datetime(2022, 2, 9, 8, 0)), ('date', '<=', datetime(2022, 2, 9, 16, 0))],
|
||||
['total_timesheet', 'total_attendance', 'total_difference'],
|
||||
['user_id'],
|
||||
aggregates=['total_timesheet:sum', 'total_attendance:sum'],
|
||||
)[0]
|
||||
self.assertEqual(report_data['total_timesheet'], 6.0, "Total timesheet in report should be 4.0")
|
||||
self.assertEqual(report_data['total_attendance'], 7.0, "Total attendance in report should be 8.0")
|
||||
self.assertEqual(report_data['total_attendance'] - report_data['total_timesheet'], 1)
|
||||
self.assertEqual(total_timesheet, 6.0, "Total timesheet in report should be 4.0")
|
||||
self.assertEqual(total_attendance, 7.0, "Total attendance in report should be 8.0")
|
||||
self.assertEqual(total_attendance - total_timesheet, 1)
|
||||
|
||||
@@ -135,11 +135,11 @@ Contracts:
|
||||
('date_start', '<', stop),
|
||||
('date_stop', '>', start),
|
||||
('employee_id', 'in', self.employee_id.ids),
|
||||
], ['work_entry_ids:array_agg(id)', 'employee_id'], ['employee_id', 'date_start', 'date_stop'], lazy=False)
|
||||
work_entries_by_employee = defaultdict(lambda: self.env['hr.work.entry'])
|
||||
for group in work_entry_groups:
|
||||
employee_id = group.get('employee_id')[0]
|
||||
work_entries_by_employee[employee_id] |= self.env['hr.work.entry'].browse(group.get('work_entry_ids'))
|
||||
], ['employee_id'], ['id:recordset'])
|
||||
work_entries_by_employee = {
|
||||
employee.id: work_entries
|
||||
for employee, work_entries in work_entry_groups
|
||||
}
|
||||
|
||||
# 3. Archive work entries included in leaves
|
||||
included = self.env['hr.work.entry']
|
||||
|
||||
@@ -28,9 +28,9 @@ class ChatbotScript(models.Model):
|
||||
], compute="_compute_first_step_warning")
|
||||
|
||||
def _compute_livechat_channel_count(self):
|
||||
channels_data = self.env['im_livechat.channel.rule'].read_group(
|
||||
[('chatbot_script_id', 'in', self.ids)], ['channel_id:count_distinct'], ['chatbot_script_id'])
|
||||
mapped_channels = {channel['chatbot_script_id'][0]: channel['channel_id'] for channel in channels_data}
|
||||
channels_data = self.env['im_livechat.channel.rule']._read_group(
|
||||
[('chatbot_script_id', 'in', self.ids)], ['chatbot_script_id'], ['channel_id:count_distinct'])
|
||||
mapped_channels = {chatbot_script.id: count_distinct for chatbot_script, count_distinct in channels_data}
|
||||
for script in self:
|
||||
script.livechat_channel_count = mapped_channels.get(script.id, 0)
|
||||
|
||||
|
||||
@@ -92,18 +92,15 @@ class ChatbotScriptStep(models.Model):
|
||||
step_values.append(vals)
|
||||
vals_by_chatbot_id[chatbot_id] = step_values
|
||||
|
||||
max_sequence_by_chatbot = {}
|
||||
if vals_by_chatbot_id:
|
||||
read_group_results = self.env['chatbot.script.step'].read_group(
|
||||
[('chatbot_script_id', 'in', list(vals_by_chatbot_id.keys()))],
|
||||
['sequence:max'],
|
||||
['chatbot_script_id']
|
||||
)
|
||||
|
||||
max_sequence_by_chatbot = {
|
||||
read_group_result['chatbot_script_id'][0]: read_group_result['sequence']
|
||||
for read_group_result in read_group_results
|
||||
}
|
||||
read_group_results = self.env['chatbot.script.step']._read_group(
|
||||
[('chatbot_script_id', 'in', list(vals_by_chatbot_id))],
|
||||
['chatbot_script_id'],
|
||||
['sequence:max'],
|
||||
)
|
||||
max_sequence_by_chatbot = {
|
||||
chatbot_script.id: sequence
|
||||
for chatbot_script, sequence in read_group_results
|
||||
}
|
||||
|
||||
for chatbot_id, step_vals in vals_by_chatbot_id.items():
|
||||
current_sequence = 0
|
||||
|
||||
@@ -39,8 +39,8 @@ class Digest(models.Model):
|
||||
response_time = self.env['im_livechat.report.channel'].sudo()._read_group([
|
||||
('start_date', '>=', start),
|
||||
('start_date', '<', end),
|
||||
], ['time_to_answer:avg'], [])
|
||||
self.kpi_livechat_response_value = response_time[0]['time_to_answer']
|
||||
], [], ['time_to_answer:avg'])
|
||||
self.kpi_livechat_response_value = response_time[0][0]
|
||||
|
||||
def _compute_kpis_actions(self, company, user):
|
||||
res = super(Digest, self)._compute_kpis_actions(company, user)
|
||||
|
||||
@@ -66,9 +66,9 @@ class ImLivechatChannel(models.Model):
|
||||
|
||||
@api.depends('rule_ids.chatbot_script_id')
|
||||
def _compute_chatbot_script_count(self):
|
||||
data = self.env['im_livechat.channel.rule'].read_group(
|
||||
[('channel_id', 'in', self.ids)], ['chatbot_script_id:count_distinct'], ['channel_id'])
|
||||
mapped_data = {rule['channel_id'][0]: rule['chatbot_script_id'] for rule in data}
|
||||
data = self.env['im_livechat.channel.rule']._read_group(
|
||||
[('channel_id', 'in', self.ids)], ['channel_id'], ['chatbot_script_id:count_distinct'])
|
||||
mapped_data = {channel.id: count_distinct for channel, count_distinct in data}
|
||||
for channel in self:
|
||||
channel.chatbot_script_count = mapped_data.get(channel.id, 0)
|
||||
|
||||
@@ -89,8 +89,8 @@ class ImLivechatChannel(models.Model):
|
||||
def _compute_nbr_channel(self):
|
||||
data = self.env['mail.channel']._read_group([
|
||||
('livechat_channel_id', 'in', self._ids),
|
||||
('has_message', '=', True)], ['__count'], ['livechat_channel_id'], lazy=False)
|
||||
channel_count = {x['livechat_channel_id'][0]: x['__count'] for x in data}
|
||||
('has_message', '=', True)], ['livechat_channel_id'], ['__count'])
|
||||
channel_count = {livechat_channel.id: count for livechat_channel, count in data}
|
||||
for record in self:
|
||||
record.nbr_channel = channel_count.get(record.id, 0)
|
||||
|
||||
|
||||
@@ -58,15 +58,12 @@ class LinkTracker(models.Model):
|
||||
|
||||
@api.depends('link_click_ids.link_id')
|
||||
def _compute_count(self):
|
||||
if self.ids:
|
||||
clicks_data = self.env['link.tracker.click']._read_group(
|
||||
[('link_id', 'in', self.ids)],
|
||||
['link_id'],
|
||||
['link_id']
|
||||
)
|
||||
mapped_data = {m['link_id'][0]: m['link_id_count'] for m in clicks_data}
|
||||
else:
|
||||
mapped_data = dict()
|
||||
clicks_data = self.env['link.tracker.click']._read_group(
|
||||
[('link_id', 'in', self.ids)],
|
||||
['link_id'],
|
||||
['__count'],
|
||||
)
|
||||
mapped_data = {link.id: count for link, count in clicks_data}
|
||||
for tracker in self:
|
||||
tracker.count = mapped_data.get(tracker.id, 0)
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ class UtmCampaign(models.Model):
|
||||
def _compute_clicks_count(self):
|
||||
click_data = self.env['link.tracker.click']._read_group(
|
||||
[('campaign_id', 'in', self.ids)],
|
||||
['campaign_id'], ['campaign_id'])
|
||||
['campaign_id'], ['__count'])
|
||||
|
||||
mapped_data = {datum['campaign_id'][0]: datum['campaign_id_count'] for datum in click_data}
|
||||
mapped_data = {campaign.id: count for campaign, count in click_data}
|
||||
|
||||
for campaign in self:
|
||||
campaign.click_count = mapped_data.get(campaign.id, 0)
|
||||
|
||||
@@ -139,8 +139,8 @@ class LoyaltyProgram(models.Model):
|
||||
|
||||
@api.depends('coupon_ids')
|
||||
def _compute_coupon_count(self):
|
||||
read_group_data = self.env['loyalty.card']._read_group([('program_id', 'in', self.ids)], ['program_id'], ['program_id'])
|
||||
count_per_program = {r['program_id'][0]: r['program_id_count'] for r in read_group_data}
|
||||
read_group_data = self.env['loyalty.card']._read_group([('program_id', 'in', self.ids)], ['program_id'], ['__count'])
|
||||
count_per_program = {program.id: count for program, count in read_group_data}
|
||||
for program in self:
|
||||
program.coupon_count = count_per_program.get(program.id, 0)
|
||||
|
||||
|
||||
@@ -19,18 +19,15 @@ class ResPartner(models.Model):
|
||||
('expiration_date', '>=', fields.Date().context_today(self)),
|
||||
('expiration_date', '=', False),
|
||||
],
|
||||
fields=['partner_id'],
|
||||
groupby=['partner_id'],
|
||||
aggregates=['__count'],
|
||||
)
|
||||
partners = self.browse()
|
||||
for group in loyalty_groups:
|
||||
partner = self.browse(group['partner_id'][0])
|
||||
self.loyalty_card_count = 0
|
||||
for partner, count in loyalty_groups:
|
||||
while partner:
|
||||
if partner in self:
|
||||
partner.loyalty_card_count += group['partner_id_count']
|
||||
partners |= partner
|
||||
partner.loyalty_card_count += count
|
||||
partner = partner.parent_id
|
||||
(self - partners).loyalty_card_count = 0
|
||||
|
||||
def action_view_loyalty_cards(self):
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('loyalty.loyalty_card_action')
|
||||
|
||||
@@ -27,8 +27,8 @@ class LunchProductCategory(models.Model):
|
||||
image_1920 = fields.Image(default=_default_image)
|
||||
|
||||
def _compute_product_count(self):
|
||||
product_data = self.env['lunch.product']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
|
||||
data = {product['category_id'][0]: product['category_id_count'] for product in product_data}
|
||||
product_data = self.env['lunch.product']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['__count'])
|
||||
data = {category.id: count for category, count in product_data}
|
||||
for category in self:
|
||||
category.product_count = data.get(category.id, 0)
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ class MailActivity(models.Model):
|
||||
return activities._as_query(order)
|
||||
|
||||
@api.model
|
||||
def _read_group_raw(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
def _read_group(self, domain, groupby=(), aggregates=(), having=(), offset=0, limit=None, order=None):
|
||||
""" The base _read_group_raw method implementation computes a where based on a given domain
|
||||
(_where_calc) and manually applies ir rules (_apply_ir_rules).
|
||||
|
||||
@@ -425,9 +425,9 @@ class MailActivity(models.Model):
|
||||
# force void result if no allowed ids found
|
||||
domain = expression.AND([domain, [(0, '=', 1)]])
|
||||
|
||||
return super(MailActivity, self)._read_group_raw(
|
||||
domain=domain, fields=fields, groupby=groupby, offset=offset,
|
||||
limit=limit, orderby=orderby, lazy=lazy,
|
||||
return super()._read_group(
|
||||
domain=domain, groupby=groupby, aggregates=aggregates,
|
||||
having=having, offset=offset, limit=limit, order=order,
|
||||
)
|
||||
|
||||
def name_get(self):
|
||||
@@ -608,28 +608,26 @@ class MailActivity(models.Model):
|
||||
if domain:
|
||||
res = self.env[res_model].search(domain)
|
||||
activity_domain.append(('res_id', 'in', res.ids))
|
||||
grouped_activities = self.env['mail.activity'].read_group(
|
||||
grouped_activities = self.env['mail.activity']._read_group(
|
||||
activity_domain,
|
||||
['res_id', 'activity_type_id', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'],
|
||||
['res_id', 'activity_type_id'],
|
||||
lazy=False)
|
||||
['id:array_agg', 'date_deadline:min', '__count'])
|
||||
# filter out unreadable records
|
||||
if not domain:
|
||||
res_ids = tuple(a['res_id'] for a in grouped_activities)
|
||||
res = self.env[res_model].search([('id', 'in', res_ids)])
|
||||
grouped_activities = [a for a in grouped_activities if a['res_id'] in res.ids]
|
||||
res_ids = tuple(res_id for res_id, *_ in grouped_activities)
|
||||
res_ids_set = set(self.env[res_model].search([('id', 'in', res_ids)])._ids)
|
||||
grouped_activities = [a for a in grouped_activities if a[0] in res_ids_set]
|
||||
res_id_to_deadline = {}
|
||||
activity_data = defaultdict(dict)
|
||||
for group in grouped_activities:
|
||||
res_id = group['res_id']
|
||||
activity_type_id = (group.get('activity_type_id') or (False, False))[0]
|
||||
res_id_to_deadline[res_id] = group['date_deadline'] if (res_id not in res_id_to_deadline or group['date_deadline'] < res_id_to_deadline[res_id]) else res_id_to_deadline[res_id]
|
||||
state = self._compute_state_from_date(group['date_deadline'], self.user_id.sudo().tz)
|
||||
for res_id, activity_type, ids, date_deadline, count in grouped_activities:
|
||||
activity_type_id = activity_type.id
|
||||
res_id_to_deadline[res_id] = date_deadline if (res_id not in res_id_to_deadline or date_deadline < res_id_to_deadline[res_id]) else res_id_to_deadline[res_id]
|
||||
state = self._compute_state_from_date(date_deadline, self.user_id.sudo().tz)
|
||||
activity_data[res_id][activity_type_id] = {
|
||||
'count': group['__count'],
|
||||
'ids': group['ids'],
|
||||
'count': count,
|
||||
'ids': ids,
|
||||
'state': state,
|
||||
'o_closest_deadline': group['date_deadline'],
|
||||
'o_closest_deadline': date_deadline,
|
||||
}
|
||||
activity_type_infos = []
|
||||
activity_type_ids = self.env['mail.activity.type'].search(
|
||||
|
||||
@@ -191,8 +191,8 @@ class Channel(models.Model):
|
||||
|
||||
@api.depends('channel_member_ids')
|
||||
def _compute_member_count(self):
|
||||
read_group_res = self.env['mail.channel.member']._read_group(domain=[('channel_id', 'in', self.ids)], fields=['channel_id'], groupby=['channel_id'])
|
||||
member_count_by_channel_id = {item['channel_id'][0]: item['channel_id_count'] for item in read_group_res}
|
||||
read_group_res = self.env['mail.channel.member']._read_group(domain=[('channel_id', 'in', self.ids)], groupby=['channel_id'], aggregates=['__count'])
|
||||
member_count_by_channel_id = {channel.id: count for channel, count in read_group_res}
|
||||
for channel in self:
|
||||
channel.member_count = member_count_by_channel_id.get(channel.id, 0)
|
||||
|
||||
|
||||
@@ -719,13 +719,13 @@ class Message(models.Model):
|
||||
return super(Message, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _read_group_raw(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
def _read_group(self, domain, groupby=(), aggregates=(), having=(), offset=0, limit=None, order=None):
|
||||
if not self.env.is_admin():
|
||||
raise AccessError(_("Only administrators are allowed to use grouped read on message model"))
|
||||
|
||||
return super(Message, self)._read_group_raw(
|
||||
domain=domain, fields=fields, groupby=groupby, offset=offset,
|
||||
limit=limit, orderby=orderby, lazy=lazy,
|
||||
return super()._read_group(
|
||||
domain=domain, groupby=groupby, aggregates=aggregates,
|
||||
having=having, offset=offset, limit=limit, order=order,
|
||||
)
|
||||
|
||||
def export_data(self, fields_to_export):
|
||||
|
||||
@@ -228,10 +228,10 @@ class MailThread(models.AbstractModel):
|
||||
|
||||
def _compute_message_attachment_count(self):
|
||||
read_group_var = self.env['ir.attachment']._read_group([('res_id', 'in', self.ids), ('res_model', '=', self._name)],
|
||||
fields=['res_id'],
|
||||
groupby=['res_id'])
|
||||
groupby=['res_id'],
|
||||
aggregates=['__count'])
|
||||
|
||||
attachment_count_dict = dict((d['res_id'], d['res_id_count']) for d in read_group_var)
|
||||
attachment_count_dict = dict(read_group_var)
|
||||
for record in self:
|
||||
record.message_attachment_count = attachment_count_dict.get(record.id, 0)
|
||||
|
||||
|
||||
@@ -100,12 +100,12 @@ class MailGroup(models.Model):
|
||||
('mail_group_id', 'in', self.ids),
|
||||
('create_date', '>=', fields.Datetime.to_string(month_date)),
|
||||
('moderation_status', '=', 'accepted'),
|
||||
], ['mail_group_id'], ['mail_group_id'])
|
||||
], ['mail_group_id'], ['__count'])
|
||||
|
||||
# { mail_discusison_id: number_of_mail_group_message_last_month_count }
|
||||
messages_data = {
|
||||
message['mail_group_id'][0]: message['mail_group_id_count']
|
||||
for message in messages_data
|
||||
mail_group.id: count
|
||||
for mail_group, count in messages_data
|
||||
}
|
||||
|
||||
for group in self:
|
||||
@@ -120,11 +120,11 @@ class MailGroup(models.Model):
|
||||
results = self.env['mail.group.message']._read_group(
|
||||
[('mail_group_id', 'in', self.ids)],
|
||||
['mail_group_id'],
|
||||
['mail_group_id'],
|
||||
['__count'],
|
||||
)
|
||||
result_per_group = {
|
||||
result['mail_group_id'][0]: result['mail_group_id_count']
|
||||
for result in results
|
||||
mail_group.id: count
|
||||
for mail_group, count in results
|
||||
}
|
||||
for group in self:
|
||||
group.mail_group_message_count = result_per_group.get(group.id, 0)
|
||||
@@ -134,11 +134,11 @@ class MailGroup(models.Model):
|
||||
results = self.env['mail.group.message']._read_group(
|
||||
[('mail_group_id', 'in', self.ids), ('moderation_status', '=', 'pending_moderation')],
|
||||
['mail_group_id'],
|
||||
['mail_group_id'],
|
||||
['__count'],
|
||||
)
|
||||
result_per_group = {
|
||||
result['mail_group_id'][0]: result['mail_group_id_count']
|
||||
for result in results
|
||||
mail_group.id: count
|
||||
for mail_group, count in results
|
||||
}
|
||||
|
||||
for group in self:
|
||||
@@ -486,12 +486,11 @@ class MailGroup(models.Model):
|
||||
_logger.warning('Template "mail_group.mail_group_notify_moderation" was not found. Cannot send reminder notifications.')
|
||||
return
|
||||
|
||||
results = self.env['mail.group.message'].read_group(
|
||||
results = self.env['mail.group.message']._read_group(
|
||||
[('mail_group_id', 'in', self.ids), ('moderation_status', '=', 'pending_moderation')],
|
||||
['mail_group_id'],
|
||||
['mail_group_id'],
|
||||
)
|
||||
groups = self.browse([result['mail_group_id'][0] for result in results])
|
||||
groups = self.browse([mail_group.id for [mail_group] in results])
|
||||
|
||||
for group in groups:
|
||||
moderators_to_notify = group.moderator_ids
|
||||
|
||||
@@ -54,14 +54,14 @@ class MaintenanceEquipmentCategory(models.Model):
|
||||
fold = fields.Boolean(string='Folded in Maintenance Pipe', compute='_compute_fold', store=True)
|
||||
|
||||
def _compute_equipment_count(self):
|
||||
equipment_data = self.env['maintenance.equipment']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
|
||||
mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])
|
||||
equipment_data = self.env['maintenance.equipment']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['__count'])
|
||||
mapped_data = {category.id: count for category, count in equipment_data}
|
||||
for category in self:
|
||||
category.equipment_count = mapped_data.get(category.id, 0)
|
||||
|
||||
def _compute_maintenance_count(self):
|
||||
maintenance_data = self.env['maintenance.request']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
|
||||
mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in maintenance_data])
|
||||
maintenance_data = self.env['maintenance.request']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['__count'])
|
||||
mapped_data = {category.id: count for category, count in maintenance_data}
|
||||
for category in self:
|
||||
category.maintenance_count = mapped_data.get(category.id, 0)
|
||||
|
||||
|
||||
@@ -385,8 +385,8 @@ class MassMailing(models.Model):
|
||||
def _compute_mailing_filter_count(self):
|
||||
filter_data = self.env['mailing.filter']._read_group([
|
||||
('mailing_model_id', 'in', self.mailing_model_id.ids)
|
||||
], ['mailing_model_id'], ['mailing_model_id'])
|
||||
mapped_data = {data['mailing_model_id'][0]: data['mailing_model_id_count'] for data in filter_data}
|
||||
], ['mailing_model_id'], ['__count'])
|
||||
mapped_data = {mailing_model.id: count for mailing_model, count in filter_data}
|
||||
for mailing in self:
|
||||
mailing.mailing_filter_count = mapped_data.get(mailing.mailing_model_id.id, 0)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
@@ -48,25 +49,20 @@ class UtmCampaign(models.Model):
|
||||
|
||||
@api.depends('mailing_mail_ids')
|
||||
def _compute_mailing_mail_count(self):
|
||||
if self.ids:
|
||||
mailing_data = self.env['mailing.mailing']._read_group(
|
||||
[('campaign_id', 'in', self.ids), ('mailing_type', '=', 'mail')],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
lazy=False,
|
||||
)
|
||||
ab_testing_mapped_data = {}
|
||||
mapped_data = {}
|
||||
for data in mailing_data:
|
||||
if data['ab_testing_enabled']:
|
||||
ab_testing_mapped_data.setdefault(data['campaign_id'][0], []).append(data['__count'])
|
||||
mapped_data.setdefault(data['campaign_id'][0], []).append(data['__count'])
|
||||
else:
|
||||
mapped_data = dict()
|
||||
ab_testing_mapped_data = dict()
|
||||
mailing_data = self.env['mailing.mailing']._read_group(
|
||||
[('campaign_id', 'in', self.ids), ('mailing_type', '=', 'mail')],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
['__count'],
|
||||
)
|
||||
ab_testing_mapped_data = defaultdict(list)
|
||||
mapped_data = defaultdict(list)
|
||||
for campaign, ab_testing_enabled, count in mailing_data:
|
||||
if ab_testing_enabled:
|
||||
ab_testing_mapped_data[campaign.id].append(count)
|
||||
mapped_data[campaign.id].append(count)
|
||||
for campaign in self:
|
||||
campaign.mailing_mail_count = sum(mapped_data.get(campaign._origin.id or campaign.id, []))
|
||||
campaign.ab_testing_mailings_count = sum(ab_testing_mapped_data.get(campaign._origin.id or campaign.id, []))
|
||||
campaign.mailing_mail_count = sum(mapped_data[campaign._origin.id or campaign.id])
|
||||
campaign.ab_testing_mailings_count = sum(ab_testing_mapped_data[campaign._origin.id or campaign.id])
|
||||
|
||||
def _compute_statistics(self):
|
||||
""" Compute statistics of the mass mailing campaign """
|
||||
|
||||
@@ -18,9 +18,9 @@ class MassMailing(models.Model):
|
||||
def _compute_crm_lead_count(self):
|
||||
lead_data = self.env['crm.lead'].with_context(active_test=False).sudo()._read_group(
|
||||
[('source_id', 'in', self.source_id.ids)],
|
||||
['source_id'], ['source_id'],
|
||||
['source_id'], ['__count'],
|
||||
)
|
||||
mapped_data = {datum['source_id'][0]: datum['source_id_count'] for datum in lead_data}
|
||||
mapped_data = {source.id: count for source, count in lead_data}
|
||||
for mass_mailing in self:
|
||||
mass_mailing.crm_lead_count = mapped_data.get(mass_mailing.source_id.id, 0)
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ class MassMailing(models.Model):
|
||||
def _compute_sale_quotation_count(self):
|
||||
quotation_data = self.env['sale.order'].sudo()._read_group(
|
||||
[('source_id', 'in', self.source_id.ids)],
|
||||
['source_id'], ['source_id'],
|
||||
['source_id'], ['__count'],
|
||||
)
|
||||
mapped_data = {datum['source_id'][0]: datum['source_id_count'] for datum in quotation_data}
|
||||
mapped_data = {source.id: count for source, count in quotation_data}
|
||||
for mass_mailing in self:
|
||||
mass_mailing.sale_quotation_count = mapped_data.get(mass_mailing.source_id.id, 0)
|
||||
|
||||
@@ -30,9 +30,9 @@ class MassMailing(models.Model):
|
||||
[('state', 'not in', ['draft', 'cancel'])]
|
||||
])
|
||||
moves_data = self.env['account.move'].sudo()._read_group(
|
||||
domain, ['source_id', 'amount_untaxed_signed'], ['source_id'],
|
||||
domain, ['source_id'], ['amount_untaxed_signed:sum'],
|
||||
)
|
||||
mapped_data = {datum['source_id'][0]: datum['amount_untaxed_signed'] for datum in moves_data}
|
||||
mapped_data = {source.id: amount_untaxed_signed for source, amount_untaxed_signed in moves_data}
|
||||
for mass_mailing in self:
|
||||
mass_mailing.sale_invoiced_amount = mapped_data.get(mass_mailing.source_id.id, 0)
|
||||
|
||||
|
||||
@@ -70,23 +70,18 @@ class Mailing(models.Model):
|
||||
|
||||
@api.depends('mailing_trace_ids.failure_type')
|
||||
def _compute_sms_has_iap_failure(self):
|
||||
failures = ['sms_acc', 'sms_credit']
|
||||
if not self.ids:
|
||||
self.sms_has_insufficient_credit = self.sms_has_unregistered_account = False
|
||||
else:
|
||||
traces = self.env['mailing.trace'].sudo().read_group([
|
||||
('mass_mailing_id', 'in', self.ids),
|
||||
('trace_type', '=', 'sms'),
|
||||
('failure_type', 'in', failures)
|
||||
], ['mass_mailing_id', 'failure_type'], ['mass_mailing_id', 'failure_type'], lazy=False)
|
||||
self.sms_has_insufficient_credit = self.sms_has_unregistered_account = False
|
||||
traces = self.env['mailing.trace'].sudo()._read_group([
|
||||
('mass_mailing_id', 'in', self.ids),
|
||||
('trace_type', '=', 'sms'),
|
||||
('failure_type', 'in', ['sms_acc', 'sms_credit'])
|
||||
], ['mass_mailing_id', 'failure_type'])
|
||||
|
||||
trace_dict = dict.fromkeys(self.ids, {key: False for key in failures})
|
||||
for t in traces:
|
||||
trace_dict[t['mass_mailing_id'][0]][t['failure_type']] = bool(t['__count'])
|
||||
|
||||
for mail in self:
|
||||
mail.sms_has_insufficient_credit = trace_dict[mail.id]['sms_credit']
|
||||
mail.sms_has_unregistered_account = trace_dict[mail.id]['sms_acc']
|
||||
for mass_mailing, failure_type in traces:
|
||||
if failure_type == 'sms_credit':
|
||||
mass_mailing.sms_has_insufficient_credit = True
|
||||
elif failure_type == 'sms_acc':
|
||||
mass_mailing.sms_has_unregistered_account = True
|
||||
|
||||
# --------------------------------------------------
|
||||
# ORM OVERRIDES
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
@@ -26,25 +27,21 @@ class UtmCampaign(models.Model):
|
||||
|
||||
@api.depends('mailing_sms_ids')
|
||||
def _compute_mailing_sms_count(self):
|
||||
if self.ids:
|
||||
mailing_sms_data = self.env['mailing.mailing'].read_group(
|
||||
[('campaign_id', 'in', self.ids), ('mailing_type', '=', 'sms')],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
lazy=False,
|
||||
)
|
||||
ab_testing_mapped_sms_data = {}
|
||||
mapped_sms_data = {}
|
||||
for data in mailing_sms_data:
|
||||
if data['ab_testing_enabled']:
|
||||
ab_testing_mapped_sms_data.setdefault(data['campaign_id'][0], []).append(data['__count'])
|
||||
mapped_sms_data.setdefault(data['campaign_id'][0], []).append(data['__count'])
|
||||
else:
|
||||
mapped_sms_data = dict()
|
||||
ab_testing_mapped_sms_data = dict()
|
||||
mailing_sms_data = self.env['mailing.mailing']._read_group(
|
||||
[('campaign_id', 'in', self.ids), ('mailing_type', '=', 'sms')],
|
||||
['campaign_id', 'ab_testing_enabled'],
|
||||
['__count'],
|
||||
)
|
||||
ab_testing_mapped_sms_data = defaultdict(list)
|
||||
mapped_sms_data = defaultdict(list)
|
||||
for campaign, ab_testing_enabled, count in mailing_sms_data:
|
||||
if ab_testing_enabled:
|
||||
ab_testing_mapped_sms_data[campaign.id].append(count)
|
||||
mapped_sms_data[campaign.id].append(count)
|
||||
|
||||
for campaign in self:
|
||||
campaign.mailing_sms_count = sum(mapped_sms_data.get(campaign._origin.id or campaign.id, []))
|
||||
campaign.ab_testing_mailings_sms_count = sum(ab_testing_mapped_sms_data.get(campaign._origin.id or campaign.id, []))
|
||||
campaign.mailing_sms_count = sum(mapped_sms_data[campaign.id])
|
||||
campaign.ab_testing_mailings_sms_count = sum(ab_testing_mapped_sms_data[campaign.id])
|
||||
|
||||
def action_create_mass_sms(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("mass_mailing.action_create_mass_mailings_from_campaign")
|
||||
|
||||
@@ -411,8 +411,8 @@ class MrpProduction(models.Model):
|
||||
|
||||
@api.depends('move_raw_ids.delay_alert_date')
|
||||
def _compute_delay_alert_date(self):
|
||||
delay_alert_date_data = self.env['stock.move']._read_group([('id', 'in', self.move_raw_ids.ids), ('delay_alert_date', '!=', False)], ['delay_alert_date:max'], 'raw_material_production_id')
|
||||
delay_alert_date_data = {data['raw_material_production_id'][0]: data['delay_alert_date'] for data in delay_alert_date_data}
|
||||
delay_alert_date_data = self.env['stock.move']._read_group([('id', 'in', self.move_raw_ids.ids), ('delay_alert_date', '!=', False)], ['raw_material_production_id'], ['delay_alert_date:max'])
|
||||
delay_alert_date_data = {raw_material_production.id: delay_alert_date_max for raw_material_production, delay_alert_date_max in delay_alert_date_data}
|
||||
for production in self:
|
||||
production.delay_alert_date = delay_alert_date_data.get(production.id, False)
|
||||
|
||||
@@ -442,14 +442,11 @@ class MrpProduction(models.Model):
|
||||
('production_id', 'in', self.ids),
|
||||
('raw_material_production_id', 'in', self.ids)
|
||||
]
|
||||
res = self.env['stock.move'].read_group(domain, ['state', 'production_id', 'raw_material_production_id'], ['production_id', 'raw_material_production_id'], lazy=False)
|
||||
productions_with_done_move = {}
|
||||
for rec in res:
|
||||
production_record = rec['production_id'] or rec['raw_material_production_id']
|
||||
if production_record:
|
||||
productions_with_done_move[production_record[0]] = True
|
||||
for production in self:
|
||||
production.confirm_cancel = productions_with_done_move.get(production.id, False)
|
||||
res = self.env['stock.move']._read_group(domain, ['production_id', 'raw_material_production_id'])
|
||||
self.confirm_cancel = False
|
||||
for production, raw_material_production in res:
|
||||
production_record = production or raw_material_production
|
||||
production_record.confirm_cancel = True
|
||||
|
||||
@api.depends('procurement_group_id', 'procurement_group_id.stock_move_ids.group_id')
|
||||
def _compute_picking_ids(self):
|
||||
@@ -474,8 +471,8 @@ class MrpProduction(models.Model):
|
||||
location_by_company = self.env['stock.location']._read_group([
|
||||
('company_id', 'in', self.company_id.ids),
|
||||
('usage', '=', 'production')
|
||||
], ['company_id', 'ids:array_agg(id)'], ['company_id'])
|
||||
location_by_company = {lbc['company_id'][0]: lbc['ids'] for lbc in location_by_company}
|
||||
], ['company_id'], ['id:array_agg'])
|
||||
location_by_company = {company.id: ids for company, ids in location_by_company}
|
||||
for production in self:
|
||||
if production.product_id:
|
||||
production.production_location_id = production.product_id.with_company(production.company_id).property_stock_production
|
||||
@@ -608,8 +605,8 @@ class MrpProduction(models.Model):
|
||||
return True
|
||||
|
||||
def _compute_scrap_move_count(self):
|
||||
data = self.env['stock.scrap']._read_group([('production_id', 'in', self.ids)], ['production_id'], ['production_id'])
|
||||
count_data = dict((item['production_id'][0], item['production_id_count']) for item in data)
|
||||
data = self.env['stock.scrap']._read_group([('production_id', 'in', self.ids)], ['production_id'], ['__count'])
|
||||
count_data = {production.id: count for production, count in data}
|
||||
for production in self:
|
||||
production.scrap_count = count_data.get(production.id, 0)
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ class MrpRoutingWorkcenter(models.Model):
|
||||
def _compute_workorder_count(self):
|
||||
data = self.env['mrp.workorder']._read_group([
|
||||
('operation_id', 'in', self.ids),
|
||||
('state', '=', 'done')], ['operation_id'], ['operation_id'])
|
||||
count_data = dict((item['operation_id'][0], item['operation_id_count']) for item in data)
|
||||
('state', '=', 'done')], ['operation_id'], ['__count'])
|
||||
count_data = {operation.id: count for operation, count in data}
|
||||
for operation in self:
|
||||
operation.workorder_count = count_data.get(operation.id, 0)
|
||||
|
||||
|
||||
@@ -90,17 +90,16 @@ class MrpWorkcenter(models.Model):
|
||||
# Count Late Workorder
|
||||
data = MrpWorkorder._read_group(
|
||||
[('workcenter_id', 'in', self.ids), ('state', 'in', ('pending', 'waiting', 'ready')), ('date_start', '<', datetime.now().strftime('%Y-%m-%d'))],
|
||||
['workcenter_id'], ['workcenter_id'])
|
||||
count_data = dict((item['workcenter_id'][0], item['workcenter_id_count']) for item in data)
|
||||
['workcenter_id'], ['__count'])
|
||||
count_data = {workcenter.id: count for workcenter, count in data}
|
||||
# Count All, Pending, Ready, Progress Workorder
|
||||
res = MrpWorkorder._read_group(
|
||||
[('workcenter_id', 'in', self.ids)],
|
||||
['workcenter_id', 'state', 'duration_expected'], ['workcenter_id', 'state'],
|
||||
lazy=False)
|
||||
for res_group in res:
|
||||
result[res_group['workcenter_id'][0]][res_group['state']] = res_group['__count']
|
||||
if res_group['state'] in ('pending', 'waiting', 'ready', 'progress'):
|
||||
result_duration_expected[res_group['workcenter_id'][0]] += res_group['duration_expected']
|
||||
['workcenter_id', 'state'], ['duration_expected:sum', '__count'])
|
||||
for workcenter, state, duration_sum, count in res:
|
||||
result[workcenter.id][state] = count
|
||||
if state in ('pending', 'waiting', 'ready', 'progress'):
|
||||
result_duration_expected[workcenter.id] += duration_sum
|
||||
for workcenter in self:
|
||||
workcenter.workorder_count = sum(count for state, count in result[workcenter.id].items() if state not in ('done', 'cancel'))
|
||||
workcenter.workorder_pending_count = result[workcenter.id].get('pending', 0)
|
||||
@@ -136,8 +135,8 @@ class MrpWorkcenter(models.Model):
|
||||
('workcenter_id', 'in', self.ids),
|
||||
('date_end', '!=', False),
|
||||
('loss_type', '!=', 'productive')],
|
||||
['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
|
||||
count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
|
||||
['workcenter_id'], ['duration:sum'])
|
||||
count_data = {workcenter.id: duration for workcenter, duration in data}
|
||||
for workcenter in self:
|
||||
workcenter.blocked_time = count_data.get(workcenter.id, 0.0) / 60.0
|
||||
|
||||
@@ -148,8 +147,8 @@ class MrpWorkcenter(models.Model):
|
||||
('workcenter_id', 'in', self.ids),
|
||||
('date_end', '!=', False),
|
||||
('loss_type', '=', 'productive')],
|
||||
['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
|
||||
count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
|
||||
['workcenter_id'], ['duration:sum'])
|
||||
count_data = {workcenter.id: duration for workcenter, duration in data}
|
||||
for workcenter in self:
|
||||
workcenter.productive_time = count_data.get(workcenter.id, 0.0) / 60.0
|
||||
|
||||
@@ -165,9 +164,9 @@ class MrpWorkcenter(models.Model):
|
||||
wo_data = self.env['mrp.workorder']._read_group([
|
||||
('date_start', '>=', fields.Datetime.to_string(datetime.now() - relativedelta.relativedelta(months=1))),
|
||||
('workcenter_id', 'in', self.ids),
|
||||
('state', '=', 'done')], ['duration_expected', 'workcenter_id', 'duration'], ['workcenter_id'], lazy=False)
|
||||
duration_expected = dict((data['workcenter_id'][0], data['duration_expected']) for data in wo_data)
|
||||
duration = dict((data['workcenter_id'][0], data['duration']) for data in wo_data)
|
||||
('state', '=', 'done')], ['workcenter_id'], ['duration_expected:sum', 'duration:sum'])
|
||||
duration_expected = {workcenter.id: expected for workcenter, expected, __ in wo_data}
|
||||
duration = {workcenter.id: duration for workcenter, __, duration in wo_data}
|
||||
for workcenter in self:
|
||||
if duration.get(workcenter.id):
|
||||
workcenter.performance = 100 * duration_expected.get(workcenter.id, 0.0) / duration[workcenter.id]
|
||||
@@ -437,8 +436,11 @@ class MrpWorkcenterProductivity(models.Model):
|
||||
@api.constrains('workorder_id')
|
||||
def _check_open_time_ids(self):
|
||||
for workorder in self.workorder_id:
|
||||
open_time_ids_by_user = self.env["mrp.workcenter.productivity"].read_group([("id", "in", workorder.time_ids.ids), ("date_end", "=", False)], ["user_id", "open_time_ids_count:count(id)"], ["user_id"])
|
||||
if any(data["open_time_ids_count"] > 1 for data in open_time_ids_by_user):
|
||||
open_time_ids_by_user = self.env["mrp.workcenter.productivity"]._read_group(
|
||||
[("id", "in", workorder.time_ids.ids), ("date_end", "=", False)],
|
||||
["user_id"], having=[("__count", ">", 1)],
|
||||
)
|
||||
if open_time_ids_by_user:
|
||||
raise ValidationError(_('The Workorder (%s) cannot be started twice!', workorder.display_name))
|
||||
|
||||
def button_block(self):
|
||||
|
||||
@@ -397,8 +397,8 @@ class MrpWorkorder(models.Model):
|
||||
order.is_user_working = False
|
||||
|
||||
def _compute_scrap_move_count(self):
|
||||
data = self.env['stock.scrap']._read_group([('workorder_id', 'in', self.ids)], ['workorder_id'], ['workorder_id'])
|
||||
count_data = dict((item['workorder_id'][0], item['workorder_id_count']) for item in data)
|
||||
data = self.env['stock.scrap']._read_group([('workorder_id', 'in', self.ids)], ['workorder_id'], ['__count'])
|
||||
count_data = {workorder.id: count for workorder, count in data}
|
||||
for workorder in self:
|
||||
workorder.scrap_count = count_data.get(workorder.id, 0)
|
||||
|
||||
|
||||
@@ -169,8 +169,8 @@ class ProductProduct(models.Model):
|
||||
date_from = fields.Datetime.to_string(fields.datetime.now() - timedelta(days=365))
|
||||
#TODO: state = done?
|
||||
domain = [('state', '=', 'done'), ('product_id', 'in', self.ids), ('date_start', '>', date_from)]
|
||||
read_group_res = self.env['mrp.production']._read_group(domain, ['product_id', 'product_uom_qty'], ['product_id'])
|
||||
mapped_data = dict([(data['product_id'][0], data['product_uom_qty']) for data in read_group_res])
|
||||
read_group_res = self.env['mrp.production']._read_group(domain, ['product_id'], ['product_uom_qty:sum'])
|
||||
mapped_data = {product.id: qty for product, qty in read_group_res}
|
||||
for product in self:
|
||||
if not product.id:
|
||||
product.mrp_product_qty = 0.0
|
||||
|
||||
@@ -103,15 +103,13 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
|
||||
bom_manufacture = self.env['mrp.bom']._bom_find(orderpoints_without_kit.product_id, bom_type='normal')
|
||||
bom_manufacture = self.env['mrp.bom'].concat(*bom_manufacture.values())
|
||||
productions_group = self.env['mrp.production'].read_group(
|
||||
productions_group = self.env['mrp.production']._read_group(
|
||||
[('bom_id', 'in', bom_manufacture.ids), ('state', '=', 'draft'), ('orderpoint_id', 'in', orderpoints_without_kit.ids)],
|
||||
['orderpoint_id', 'product_qty', 'product_uom_id'],
|
||||
['orderpoint_id', 'product_uom_id'], lazy=False)
|
||||
for p in productions_group:
|
||||
uom = self.env['uom.uom'].browse(p['product_uom_id'][0])
|
||||
orderpoint = self.env['stock.warehouse.orderpoint'].browse(p['orderpoint_id'][0])
|
||||
['orderpoint_id', 'product_uom_id'],
|
||||
['product_qty:sum'])
|
||||
for orderpoint, uom, product_qty_sum in productions_group:
|
||||
res[orderpoint.id] += uom._compute_quantity(
|
||||
p['product_qty'], orderpoint.product_uom, round=False)
|
||||
product_qty_sum, orderpoint.product_uom, round=False)
|
||||
return res
|
||||
|
||||
def _get_qty_multiple_to_order(self):
|
||||
|
||||
@@ -28,28 +28,20 @@ class StockPickingType(models.Model):
|
||||
|
||||
def _get_mo_count(self):
|
||||
mrp_picking_types = self.filtered(lambda picking: picking.code == 'mrp_operation')
|
||||
if not mrp_picking_types:
|
||||
self.count_mo_waiting = False
|
||||
self.count_mo_todo = False
|
||||
self.count_mo_late = False
|
||||
return
|
||||
remaining = (self - mrp_picking_types)
|
||||
remaining.count_mo_waiting = remaining.count_mo_todo = remaining.count_mo_late = False
|
||||
domains = {
|
||||
'count_mo_waiting': [('reservation_state', '=', 'waiting')],
|
||||
'count_mo_todo': ['|', ('state', 'in', ('confirmed', 'draft', 'progress', 'to_close')), ('is_planned', '=', True)],
|
||||
'count_mo_late': [('date_start', '<', fields.Date.today()), ('state', '=', 'confirmed')],
|
||||
}
|
||||
for field in domains:
|
||||
data = self.env['mrp.production']._read_group(domains[field] +
|
||||
[('state', 'not in', ('done', 'cancel')), ('picking_type_id', 'in', self.ids)],
|
||||
['picking_type_id'], ['picking_type_id'])
|
||||
count = {x['picking_type_id'] and x['picking_type_id'][0]: x['picking_type_id_count'] for x in data}
|
||||
for key, domain in domains.items():
|
||||
data = self.env['mrp.production']._read_group(domain +
|
||||
[('state', 'not in', ('done', 'cancel')), ('picking_type_id', 'in', mrp_picking_types.ids)],
|
||||
['picking_type_id'], ['__count'])
|
||||
count = {picking_type.id: count for picking_type, count in data}
|
||||
for record in mrp_picking_types:
|
||||
record[field] = count.get(record.id, 0)
|
||||
remaining = (self - mrp_picking_types)
|
||||
if remaining:
|
||||
remaining.count_mo_waiting = False
|
||||
remaining.count_mo_todo = False
|
||||
remaining.count_mo_late = False
|
||||
record[key] = count.get(record.id, 0)
|
||||
|
||||
def get_mrp_stock_picking_action_picking_type(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id('mrp.mrp_production_action_picking_deshboard')
|
||||
|
||||
@@ -555,9 +555,9 @@ class ReportBomStructure(models.AbstractModel):
|
||||
domain.append(('warehouse_id', '=', self.env.context.get('warehouse')))
|
||||
|
||||
# Seek the closest date in the forecast report where consummed quantity >= forecasted quantity
|
||||
closest_forecasted = self.env['report.stock.quantity']._read_group(domain, ['min_date:min(date)', 'product_id'], ['product_id'])
|
||||
if closest_forecasted:
|
||||
days_to_forecast = (closest_forecasted[0]['min_date'] - date_today).days
|
||||
[min_date] = self.env['report.stock.quantity']._read_group(domain, aggregates=['date:min'])[0]
|
||||
if min_date:
|
||||
days_to_forecast = (min_date - date_today).days
|
||||
return ('expected', days_to_forecast)
|
||||
return ('unavailable', False)
|
||||
|
||||
|
||||
@@ -44,16 +44,16 @@ class StockForecasted(models.AbstractModel):
|
||||
|
||||
# Pending incoming quantity.
|
||||
mo_domain = domain + [('location_dest_id', 'in', wh_location_ids)]
|
||||
grouped_mo = self.env['mrp.production'].read_group(mo_domain, ['product_qty:sum'], 'product_id')
|
||||
res['draft_production_qty']['in'] = sum(mo['product_qty'] for mo in grouped_mo)
|
||||
[product_qty] = self.env['mrp.production']._read_group(mo_domain, aggregates=['product_qty:sum'])[0]
|
||||
res['draft_production_qty']['in'] = product_qty or 0.0
|
||||
|
||||
# Pending outgoing quantity.
|
||||
move_domain = domain + [
|
||||
('raw_material_production_id', '!=', False),
|
||||
('location_id', 'in', wh_location_ids),
|
||||
]
|
||||
grouped_moves = self.env['stock.move'].read_group(move_domain, ['product_qty:sum'], 'product_id')
|
||||
res['draft_production_qty']['out'] = sum(move['product_qty'] for move in grouped_moves)
|
||||
[product_qty] = self.env['stock.move']._read_group(move_domain, aggregates=['product_qty:sum'])[0]
|
||||
res['draft_production_qty']['out'] = product_qty or 0.0
|
||||
res['qty']['in'] += res['draft_production_qty']['in']
|
||||
res['qty']['out'] += res['draft_production_qty']['out']
|
||||
|
||||
|
||||
@@ -18,30 +18,30 @@ class ResPartner(models.Model):
|
||||
picking_ids = fields.Many2many('stock.picking', compute='_compute_picking_ids', string="Stock Pickings for which the Partner is the subcontractor")
|
||||
|
||||
def _compute_bom_ids(self):
|
||||
results = self.env['mrp.bom'].read_group([('subcontractor_ids.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['ids:array_agg(id)', 'subcontractor_ids'], ['subcontractor_ids'])
|
||||
results = self.env['mrp.bom']._read_group([('subcontractor_ids.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['subcontractor_ids'], ['id:array_agg'])
|
||||
for partner in self:
|
||||
bom_ids = []
|
||||
for res in results:
|
||||
if partner.id == res['subcontractor_ids'][0] or res['subcontractor_ids'][0] in partner.child_ids.ids:
|
||||
bom_ids += res['ids']
|
||||
for subcontractor, ids in results:
|
||||
if partner.id == subcontractor.id or subcontractor.id in partner.child_ids.ids:
|
||||
bom_ids += ids
|
||||
partner.bom_ids = bom_ids
|
||||
|
||||
def _compute_production_ids(self):
|
||||
results = self.env['mrp.production'].read_group([('subcontractor_id.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['ids:array_agg(id)'], ['subcontractor_id'])
|
||||
results = self.env['mrp.production']._read_group([('subcontractor_id.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['subcontractor_id'], ['id:array_agg'])
|
||||
for partner in self:
|
||||
production_ids = []
|
||||
for res in results:
|
||||
if partner.id == res['subcontractor_id'][0] or res['subcontractor_id'][0] in partner.child_ids.ids:
|
||||
production_ids += res['ids']
|
||||
for subcontractor, ids in results:
|
||||
if partner.id == subcontractor.id or subcontractor.id in partner.child_ids.ids:
|
||||
production_ids += ids
|
||||
partner.production_ids = production_ids
|
||||
|
||||
def _compute_picking_ids(self):
|
||||
results = self.env['stock.picking'].read_group([('partner_id.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['ids:array_agg(id)'], ['partner_id'])
|
||||
results = self.env['stock.picking']._read_group([('partner_id.commercial_partner_id', 'in', self.commercial_partner_id.ids)], ['partner_id'], ['id:array_agg'])
|
||||
for partner in self:
|
||||
picking_ids = []
|
||||
for res in results:
|
||||
if partner.id == res['partner_id'][0] or res['partner_id'][0] in partner.child_ids.ids:
|
||||
picking_ids += res['ids']
|
||||
for partner_rg, ids in results:
|
||||
if partner_rg.id == partner.id or partner_rg.id in partner.child_ids.ids:
|
||||
picking_ids += ids
|
||||
partner.picking_ids = picking_ids
|
||||
|
||||
def _search_is_subcontractor(self, operator, value):
|
||||
|
||||
@@ -33,11 +33,11 @@ class OnboardingProgress(models.Model):
|
||||
|
||||
@api.depends('onboarding_id.step_ids', 'progress_step_ids', 'progress_step_ids.step_state')
|
||||
def _compute_onboarding_state(self):
|
||||
progress_steps_data = self.env['onboarding.progress.step'].read_group(
|
||||
progress_steps_data = self.env['onboarding.progress.step']._read_group(
|
||||
[('progress_id', 'in', self.ids), ('step_state', 'in', ['just_done', 'done'])],
|
||||
['progress_id'], ['progress_id']
|
||||
['progress_id'], ['__count']
|
||||
)
|
||||
result = dict((data['progress_id'][0], data['progress_id_count']) for data in progress_steps_data)
|
||||
result = {progress.id: count for progress, count in progress_steps_data}
|
||||
for progress in self:
|
||||
progress.onboarding_state = (
|
||||
'not_done' if result.get(progress.id, 0) != len(progress.onboarding_id.step_ids)
|
||||
|
||||
@@ -133,10 +133,10 @@ class PaymentTransaction(models.Model):
|
||||
def _compute_refunds_count(self):
|
||||
rg_data = self.env['payment.transaction']._read_group(
|
||||
domain=[('source_transaction_id', 'in', self.ids), ('operation', '=', 'refund')],
|
||||
fields=['source_transaction_id'],
|
||||
groupby=['source_transaction_id'],
|
||||
aggregates=['__count'],
|
||||
)
|
||||
data = {x['source_transaction_id'][0]: x['source_transaction_id_count'] for x in rg_data}
|
||||
data = {source_transaction.id: count for source_transaction, count in rg_data}
|
||||
for record in self:
|
||||
record.refunds_count = data.get(record.id, 0)
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ class ResPartner(models.Model):
|
||||
@api.depends('payment_token_ids')
|
||||
def _compute_payment_token_count(self):
|
||||
payments_data = self.env['payment.token']._read_group(
|
||||
[('partner_id', 'in', self.ids)], ['partner_id'], ['partner_id']
|
||||
[('partner_id', 'in', self.ids)], ['partner_id'], ['__count'],
|
||||
)
|
||||
partners_data = {payment_data['partner_id'][0]: payment_data['partner_id_count']
|
||||
for payment_data in payments_data}
|
||||
partners_data = {partner.id: count for partner, count in payments_data}
|
||||
for partner in self:
|
||||
partner.payment_token_count = partners_data.get(partner.id, 0)
|
||||
|
||||
@@ -389,13 +389,13 @@ class PosOrder(models.Model):
|
||||
Practical to be used for migrations
|
||||
"""
|
||||
amounts = {order_id: {'paid': 0, 'return': 0, 'taxed': 0, 'taxes': 0} for order_id in self.ids}
|
||||
for order in self.env['pos.payment'].read_group([('pos_order_id', 'in', self.ids)], ['pos_order_id', 'amount'], ['pos_order_id']):
|
||||
amounts[order['pos_order_id'][0]]['paid'] = order['amount']
|
||||
for order in self.env['pos.payment'].read_group(['&', ('pos_order_id', 'in', self.ids), ('amount', '<', 0)], ['pos_order_id', 'amount'], ['pos_order_id']):
|
||||
amounts[order['pos_order_id'][0]]['return'] = order['amount']
|
||||
for order in self.env['pos.order.line'].read_group([('order_id', 'in', self.ids)], ['order_id', 'price_subtotal', 'price_subtotal_incl'], ['order_id']):
|
||||
amounts[order['order_id'][0]]['taxed'] = order['price_subtotal_incl']
|
||||
amounts[order['order_id'][0]]['taxes'] = order['price_subtotal_incl'] - order['price_subtotal']
|
||||
for pos_order, amount in self.env['pos.payment']._read_group([('pos_order_id', 'in', self.ids)], ['pos_order_id'], ['amount:sum']):
|
||||
amounts[pos_order.id]['paid'] = amount
|
||||
for pos_order, amount in self.env['pos.payment']._read_group(['&', ('pos_order_id', 'in', self.ids), ('amount', '<', 0)], ['pos_order_id'], ['amount:sum']):
|
||||
amounts[pos_order.id]['return'] = amount
|
||||
for order, price_subtotal, price_subtotal_incl in self.env['pos.order.line']._read_group([('order_id', 'in', self.ids)], ['order_id'], ['price_subtotal:sum', 'price_subtotal_incl:sum']):
|
||||
amounts[order.id]['taxed'] = price_subtotal_incl
|
||||
amounts[order.id]['taxes'] = price_subtotal_incl - price_subtotal
|
||||
|
||||
for order in self:
|
||||
order.write({
|
||||
|
||||
@@ -111,9 +111,8 @@ class PosSession(models.Model):
|
||||
if cash_payment_method:
|
||||
total_cash_payment = 0.0
|
||||
last_session = session.search([('config_id', '=', session.config_id.id), ('id', '!=', session.id)], limit=1)
|
||||
result = self.env['pos.payment']._read_group([('session_id', '=', session.id), ('payment_method_id', '=', cash_payment_method.id)], ['amount'], ['session_id'])
|
||||
if result:
|
||||
total_cash_payment = result[0]['amount']
|
||||
result = self.env['pos.payment']._read_group([('payment_method_id', '=', cash_payment_method.id)], aggregates=['amount:sum'])
|
||||
total_cash_payment = result[0][0] or 0.0
|
||||
session.cash_register_total_entry_encoding = sum(session.statement_line_ids.mapped('amount')) + (
|
||||
0.0 if session.state == 'closed' else total_cash_payment
|
||||
)
|
||||
@@ -126,14 +125,14 @@ class PosSession(models.Model):
|
||||
|
||||
@api.depends('order_ids.payment_ids.amount')
|
||||
def _compute_total_payments_amount(self):
|
||||
result = self.env['pos.payment']._read_group([('session_id', 'in', self.ids)], ['amount'], ['session_id'])
|
||||
session_amount_map = dict((data['session_id'][0], data['amount']) for data in result)
|
||||
result = self.env['pos.payment']._read_group([('session_id', 'in', self.ids)], ['session_id'], ['amount:sum'])
|
||||
session_amount_map = {session.id: amount for session, amount in result}
|
||||
for session in self:
|
||||
session.total_payments_amount = session_amount_map.get(session.id) or 0
|
||||
|
||||
def _compute_order_count(self):
|
||||
orders_data = self.env['pos.order']._read_group([('session_id', 'in', self.ids)], ['session_id'], ['session_id'])
|
||||
sessions_data = {order_data['session_id'][0]: order_data['session_id_count'] for order_data in orders_data}
|
||||
orders_data = self.env['pos.order']._read_group([('session_id', 'in', self.ids)], ['session_id'], ['__count'])
|
||||
sessions_data = {session.id: count for session, count in orders_data}
|
||||
for session in self:
|
||||
session.order_count = sessions_data.get(session.id, 0)
|
||||
|
||||
@@ -1741,16 +1740,16 @@ class PosSession(models.Model):
|
||||
|
||||
# Add the 'sum_repartition_factor' as needed in the compute_all
|
||||
# Note that the factor = factor_percent/100
|
||||
groups = self.env['account.tax.repartition.line'].read_group(
|
||||
groups = self.env['account.tax.repartition.line']._read_group(
|
||||
domain=[
|
||||
('tax_id', 'in', tuple([t['id'] for t in taxes])),
|
||||
('document_type', '=', 'invoice'),
|
||||
('repartition_type', '=', 'tax'),
|
||||
],
|
||||
fields=["factor_percent:sum"],
|
||||
groupby=["tax_id"],
|
||||
aggregates=["factor_percent:sum"],
|
||||
)
|
||||
tax_id_to_factor_sum = {g['tax_id'][0]: g['factor_percent']/100 for g in groups}
|
||||
tax_id_to_factor_sum = {tax.id: factor_sum / 100 for tax, factor_sum in groups}
|
||||
for tax in taxes:
|
||||
tax['sum_repartition_factor'] = tax_id_to_factor_sum[tax['id']]
|
||||
|
||||
|
||||
@@ -22,15 +22,15 @@ class ResPartner(models.Model):
|
||||
)
|
||||
pos_order_data = self.env['pos.order']._read_group(
|
||||
domain=[('partner_id', 'in', all_partners.ids)],
|
||||
fields=['partner_id'], groupby=['partner_id']
|
||||
groupby=['partner_id'], aggregates=['__count']
|
||||
)
|
||||
self_ids = set(self._ids)
|
||||
|
||||
self.pos_order_count = 0
|
||||
for group in pos_order_data:
|
||||
partner = self.browse(group['partner_id'][0])
|
||||
for partner, count in pos_order_data:
|
||||
while partner:
|
||||
if partner in self:
|
||||
partner.pos_order_count += group['partner_id_count']
|
||||
if partner.id in self_ids:
|
||||
partner.pos_order_count += count
|
||||
partner = partner.parent_id
|
||||
|
||||
def action_view_pos_order(self):
|
||||
|
||||
@@ -27,7 +27,7 @@ class LoyaltyCard(models.Model):
|
||||
def _compute_use_count(self):
|
||||
super()._compute_use_count()
|
||||
read_group_res = self.env['pos.order.line']._read_group(
|
||||
[('coupon_id', 'in', self.ids)], ['id'], ['coupon_id'])
|
||||
count_per_coupon = {r['coupon_id'][0]: r['coupon_id_count'] for r in read_group_res}
|
||||
[('coupon_id', 'in', self.ids)], ['coupon_id'], ['__count'])
|
||||
count_per_coupon = {coupon.id: count for coupon, count in read_group_res}
|
||||
for card in self:
|
||||
card.use_count += count_per_coupon.get(card.id, 0)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user