Files
enterprise-addons/sale_commission_subscription/report/achievement_report.py
T

209 lines
8.1 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from odoo import api, fields, models
class SaleCommissionAchievementReport(models.Model):
_inherit = "sale.commission.achievement.report"
@api.model
def _get_subscription_currency_rates(self):
""" Get a query to be able to convert the MRR log amount (in SO currency) to the currency of the current company.
This method uses the same logic than sale.order.log.report.
"""
conversion_date = fields.Date.today()
# In case we want to replay data at previous date
if self.env.context.get('conversion_date'):
conversion_date = datetime.strptime(self.env.context['conversion_date'], '%Y-%m-%d')
query = f"""
default_rate AS (
SELECT
{self.env.company.currency_id.id} AS currency_id,
'{self.env.company.currency_id.name}' AS name,
{self.env.company.id} AS company_id,
'{conversion_date}'::DATE AS date,
1 AS rate
),
sub_rate AS (
SELECT
rc.id AS currency_id,
rc.name,
rcr.company_id,
(array_agg(rcr.name order by rcr.name desc))[1] as date,
(array_agg(rcr.rate order by rcr.name desc))[1] as rate
FROM res_currency rc
JOIN res_currency_rate rcr
ON rcr.currency_id = rc.id
WHERE rc.active
AND rcr.name <= '{conversion_date}'
GROUP BY rc.id, rc.name, rcr.company_id
),
sub_rate_query AS (
SELECT *
FROM sub_rate
UNION ALL
SELECT *
FROM default_rate
WHERE NOT EXISTS (
SELECT 1 FROM sub_rate
)
),
"""
return query
@api.model
def _get_filtered_order_log_cte(self, users=None, teams=None):
date_from, date_to = self._get_achievement_default_dates()
today = fields.Date.today().strftime('%Y-%m-%d')
query = f"""
filtered_order_logs AS (
SELECT
l.id::bigint,
l.order_id,
l.plan_id,
l.amount_signed,
l.team_id,
l.company_id,
l.user_id,
l.currency_id,
l.event_date,
l.effective_date
FROM sale_order_log l
WHERE 1=1
{'AND l.user_id in (%s)' % ','.join(str(i) for i in users.ids) if users else ''}
{'AND l.team_id in (%s)' % ','.join(str(i) for i in teams.ids) if teams else ''}
{"AND l.event_date >= '%s' " % datetime.strftime(date_from, "%Y-%m-%d") if date_from else ''}
AND l.event_date <= '{datetime.strftime(date_to, "%Y-%m-%d") if date_to else today}'
),
"""
return query
@api.model
def _get_sale_order_log_rates(self):
return ['mrr']
@api.model
def _get_sale_order_log_product(self):
# TODO BIG CURRENCY CHANGES 0_0
return """
rules.mrr_rate * log.amount_signed::double precision / log_rate.rate::double precision
"""
@api.model
def _select_rules(self):
res = super()._select_rules()
res += """
,scpa.recurring_plan_id
"""
return res
@api.model
def _join_invoices(self, join_type=None):
res = super()._join_invoices(join_type=join_type)
res += """
LEFT JOIN sale_order sub ON sub.id=aml.subscription_id
"""
return res
@api.model
def _where_invoices(self):
res = super()._where_invoices()
# When the rules has no recurring plan, all invoices match, otherwise only the plan of the subscription
res += """
AND ((rules.recurring_plan_id IS NULL) OR (rules.recurring_plan_id=sub.plan_id))
"""
return res
def _subscription_lines(self, users=None, teams=None):
return f"""
{self._get_subscription_currency_rates()}
{self._get_filtered_order_log_cte(users=users, teams=teams)}
subscription_rules AS (
SELECT
(scpa.id::bigint << 20) | scpu.id::bigint as id,
COALESCE(scpu.date_from, scp.date_from) AS date_from,
COALESCE(scpu.date_to, scp.date_to) AS date_to,
scpu.user_id AS user_id,
scp.team_id AS team_id,
scp.id AS plan_id,
scpa.recurring_plan_id,
scp.company_id,
scp.currency_id AS currency_to,
scp.user_type::text = 'team'::text AS team_rule,
{self._rate_to_case(self._get_sale_order_log_rates())}
FROM sale_commission_plan_achievement scpa
JOIN sale_commission_plan scp ON scp.id = scpa.plan_id
JOIN sale_commission_plan_user scpu ON scpa.plan_id = scpu.plan_id
WHERE scp.state::text = 'approved'::text
AND scp.active
AND scpa.type::text IN ({','.join("'%s'::text" % r for r in self._get_sale_order_log_rates())})
{'AND scpu.user_id in (%s)' % ','.join(str(i) for i in users.ids) if users else ''}
), subscription_commission_lines_team AS (
SELECT
((max(rules.id) << 23) | (log.id << 3) | 0::bigint) *10+5 as id,
rules.user_id,
MAX(log.team_id) AS team_id,
rules.plan_id,
SUM({self._get_sale_order_log_product()}) AS achieved,
log.currency_id AS currency_id,
MAX(log.event_date) AS date,
MAX(rules.company_id) AS plan_company_id,
MAX(log.company_id) AS achievement_company_id,
MAX(log.order_id) AS related_res_id,
MAX(so.partner_id) AS partner_id
FROM subscription_rules rules
JOIN filtered_order_logs log ON log.team_id=rules.team_id
JOIN sale_order so ON so.id = log.order_id
JOIN sub_rate_query log_rate ON log_rate.currency_id=log.currency_id AND log_rate.company_id=log.company_id
WHERE rules.team_rule
AND (rules.recurring_plan_id IS NULL OR log.plan_id = rules.recurring_plan_id)
AND log.team_id = rules.team_id
{'AND log.team_id in (%s)' % ','.join(str(i) for i in teams.ids) if teams else ''}
AND log.event_date BETWEEN rules.date_from AND rules.date_to
AND log.effective_date IS NOT NULL
GROUP BY
log.id,
rules.plan_id,
rules.user_id,
log.currency_id
), subscription_commission_lines_user AS (
SELECT
((max(rules.id) << 23) | (log.id << 3) | 1::bigint) *10+6 as id,
rules.user_id,
MAX(log.team_id) AS team_id,
rules.plan_id,
SUM({self._get_sale_order_log_product()}) AS achieved,
log.currency_id AS currency_id,
MAX(log.event_date) AS date,
MAX(rules.company_id) AS plan_company_id,
MAX(log.company_id) AS achievement_company_id,
MAX(log.order_id) AS related_res_id,
MAX(so.partner_id) AS partner_id
FROM subscription_rules rules
JOIN filtered_order_logs log ON log.user_id=rules.user_id
JOIN sale_order so ON so.id = log.order_id
JOIN sub_rate_query log_rate ON log_rate.currency_id=log.currency_id AND log_rate.company_id=log.company_id
WHERE NOT rules.team_rule
AND (rules.recurring_plan_id IS NULL OR log.plan_id = rules.recurring_plan_id)
AND log.user_id = rules.user_id
{'AND log.user_id in (%s)' % ','.join(str(i) for i in users.ids) if users else ''}
AND log.event_date::DATE BETWEEN rules.date_from::DATE AND rules.date_to::DATE
AND log.effective_date IS NOT NULL
GROUP BY
log.id,
rules.plan_id,
rules.user_id,
log.currency_id
), subscription_commission_lines AS (
(SELECT *, 'sale.order' AS related_res_model FROM subscription_commission_lines_team)
UNION ALL
(SELECT *, 'sale.order' AS related_res_model FROM subscription_commission_lines_user)
)""", 'subscription_commission_lines'
def _commission_lines_cte(self, users=None, teams=None):
return super()._commission_lines_cte(users, teams) + [self._subscription_lines(users, teams)]