first commit
This commit is contained in:
259
modules/marketing_automation/marketing_automation_reporting.py
Normal file
259
modules/marketing_automation/marketing_automation_reporting.py
Normal file
@@ -0,0 +1,259 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from sql import Literal
|
||||
from sql.aggregate import Count, Min
|
||||
from sql.conditionals import NullIf
|
||||
from sql.functions import DateTrunc, Round
|
||||
|
||||
from trytond.model import ModelSQL, ModelView, fields
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class Context(ModelView):
|
||||
__name__ = 'marketing.automation.reporting.context'
|
||||
|
||||
from_date = fields.Date("From Date",
|
||||
domain=[
|
||||
If(Eval('to_date') & Eval('from_date'),
|
||||
('from_date', '<=', Eval('to_date')),
|
||||
()),
|
||||
])
|
||||
to_date = fields.Date("To Date",
|
||||
domain=[
|
||||
If(Eval('from_date') & Eval('to_date'),
|
||||
('to_date', '>=', Eval('from_date')),
|
||||
()),
|
||||
])
|
||||
period = fields.Selection([
|
||||
('year', "Year"),
|
||||
('month', "Month"),
|
||||
('day', "Day"),
|
||||
], "Period", required=True)
|
||||
|
||||
@classmethod
|
||||
def default_from_date(cls):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
context = Transaction().context
|
||||
if 'from_date' in context:
|
||||
return context['from_date']
|
||||
return Date.today() - relativedelta(years=1)
|
||||
|
||||
@classmethod
|
||||
def default_to_date(cls):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
context = Transaction().context
|
||||
if 'to_date' in context:
|
||||
return context['to_date']
|
||||
return Date.today()
|
||||
|
||||
@classmethod
|
||||
def default_period(cls):
|
||||
return Transaction().context.get('period', 'month')
|
||||
|
||||
|
||||
class Abstract(ModelSQL, ModelView):
|
||||
|
||||
date = fields.Date("Date")
|
||||
|
||||
@classmethod
|
||||
def table_query(cls):
|
||||
from_item, tables, withs = cls._joins()
|
||||
return from_item.select(*cls._columns(tables, withs),
|
||||
where=cls._where(tables, withs),
|
||||
group_by=cls._group_by(tables, withs),
|
||||
with_=withs.values())
|
||||
|
||||
@classmethod
|
||||
def _columns(cls, tables, withs):
|
||||
return [
|
||||
cls._column_id(tables, withs).as_('id'),
|
||||
cls._column_date(tables, withs).as_('date'),
|
||||
]
|
||||
|
||||
|
||||
class Scenario(Abstract):
|
||||
__name__ = 'marketing.automation.reporting.scenario'
|
||||
|
||||
scenario = fields.Many2One(
|
||||
'marketing.automation.scenario', "Scenario")
|
||||
record_count = fields.Integer("Records")
|
||||
record_count_blocked = fields.Integer("Records Blocked")
|
||||
block_rate = fields.Float("Block Rate")
|
||||
|
||||
@classmethod
|
||||
def _joins(cls):
|
||||
pool = Pool()
|
||||
Record = pool.get('marketing.automation.record')
|
||||
tables = {}
|
||||
tables['record'] = record = Record.__table__()
|
||||
withs = {}
|
||||
return record, tables, withs
|
||||
|
||||
@classmethod
|
||||
def _columns(cls, tables, withs):
|
||||
record = tables['record']
|
||||
|
||||
record_count = Count(Literal('*'))
|
||||
record_count_blocked = Count(Literal('*'), filter_=record.blocked)
|
||||
|
||||
return super()._columns(tables, withs) + [
|
||||
record.scenario.as_('scenario'),
|
||||
record_count.as_('record_count'),
|
||||
record_count_blocked.as_('record_count_blocked'),
|
||||
cls.block_rate.sql_cast(
|
||||
Round(record_count_blocked / NullIf(record_count, 0), 2)).as_(
|
||||
'block_rate'),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _column_id(cls, tables, withs):
|
||||
record = tables['record']
|
||||
return Min(record.id)
|
||||
|
||||
@classmethod
|
||||
def _column_date(cls, tables, withs):
|
||||
context = Transaction().context
|
||||
record = tables['record']
|
||||
|
||||
date = DateTrunc(context.get('period', 'month'), record.create_date)
|
||||
return cls.date.sql_cast(date)
|
||||
|
||||
@classmethod
|
||||
def _group_by(cls, tables, withs):
|
||||
record = tables['record']
|
||||
return [record.scenario, cls._column_date(tables, withs)]
|
||||
|
||||
@classmethod
|
||||
def _where(cls, tables, withs):
|
||||
context = Transaction().context
|
||||
record = tables['record']
|
||||
|
||||
where = Literal(True)
|
||||
from_date = context.get('from_date')
|
||||
if from_date:
|
||||
where &= record.create_date >= from_date
|
||||
to_date = context.get('to_date')
|
||||
if to_date:
|
||||
where &= record.create_date <= to_date
|
||||
return where
|
||||
|
||||
|
||||
class Activity(Abstract):
|
||||
__name__ = 'marketing.automation.reporting.activity'
|
||||
|
||||
activity = fields.Many2One(
|
||||
'marketing.automation.activity', "Activity")
|
||||
activity_action = fields.Function(
|
||||
fields.Selection('get_activity_actions', "Activity Action"),
|
||||
'on_change_with_activity_action')
|
||||
record_count = fields.Integer("Records")
|
||||
email_opened = fields.Integer(
|
||||
"Emails Opened",
|
||||
states={
|
||||
'invisible': Eval('activity_action') != 'send_email',
|
||||
})
|
||||
email_clicked = fields.Integer(
|
||||
"Emails Clicked",
|
||||
states={
|
||||
'invisible': Eval('activity_action') != 'send_email',
|
||||
})
|
||||
email_open_rate = fields.Float(
|
||||
"Email Open Rate",
|
||||
states={
|
||||
'invisible': Eval('activity_action') != 'send_email',
|
||||
})
|
||||
email_click_rate = fields.Float(
|
||||
"Email Click Rate",
|
||||
states={
|
||||
'invisible': Eval('activity_action') != 'send_email',
|
||||
})
|
||||
email_click_through_rate = fields.Float(
|
||||
"Email Click-Through Rate",
|
||||
states={
|
||||
'invisible': Eval('activity_action') != 'send_email',
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def get_activity_actions(cls):
|
||||
pool = Pool()
|
||||
Activity = pool.get('marketing.automation.activity')
|
||||
return Activity.fields_get(['action'])['action']['selection']
|
||||
|
||||
@fields.depends('activity')
|
||||
def on_change_with_activity_action(self, name=None):
|
||||
if self.activity:
|
||||
return self.activity.action
|
||||
|
||||
@classmethod
|
||||
def _joins(cls):
|
||||
pool = Pool()
|
||||
RecordActivity = pool.get('marketing.automation.record.activity')
|
||||
tables = {}
|
||||
tables['record_activity'] = record = RecordActivity.__table__()
|
||||
withs = {}
|
||||
return record, tables, withs
|
||||
|
||||
@classmethod
|
||||
def _columns(cls, tables, withs):
|
||||
record_activity = tables['record_activity']
|
||||
|
||||
record_count = Count(
|
||||
Literal('*'), filter_=record_activity.state == 'done')
|
||||
email_opened = Count(
|
||||
Literal('*'), filter_=record_activity.email_opened)
|
||||
email_clicked = Count(
|
||||
Literal('*'), filter_=record_activity.email_clicked)
|
||||
|
||||
return super()._columns(tables, withs) + [
|
||||
record_activity.activity.as_('activity'),
|
||||
record_count.as_('record_count'),
|
||||
email_opened.as_('email_opened'),
|
||||
email_clicked.as_('email_clicked'),
|
||||
cls.email_open_rate.sql_cast(
|
||||
Round(email_opened / NullIf(record_count, 0), 2)).as_(
|
||||
'email_open_rate'),
|
||||
cls.email_click_rate.sql_cast(
|
||||
Round(email_clicked / NullIf(record_count, 0), 2)).as_(
|
||||
'email_click_rate'),
|
||||
cls.email_click_through_rate.sql_cast(
|
||||
Round(email_clicked / NullIf(email_opened, 0), 2)).as_(
|
||||
'email_click_through_rate'),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _column_id(cls, tables, withs):
|
||||
record_activity = tables['record_activity']
|
||||
return Min(record_activity.id)
|
||||
|
||||
@classmethod
|
||||
def _column_date(cls, tables, withs):
|
||||
context = Transaction().context
|
||||
record_activity = tables['record_activity']
|
||||
|
||||
date = DateTrunc(context.get('period', 'month'), record_activity.at)
|
||||
return cls.date.sql_cast(date)
|
||||
|
||||
@classmethod
|
||||
def _group_by(cls, tables, withs):
|
||||
record_activity = tables['record_activity']
|
||||
return [record_activity.activity, cls._column_date(tables, withs)]
|
||||
|
||||
@classmethod
|
||||
def _where(cls, tables, withs):
|
||||
context = Transaction().context
|
||||
record_activity = tables['record_activity']
|
||||
|
||||
where = Literal(True)
|
||||
from_date = context.get('from_date')
|
||||
if from_date:
|
||||
where &= record_activity.at >= from_date
|
||||
to_date = context.get('to_date')
|
||||
if to_date:
|
||||
where &= record_activity.at <= to_date
|
||||
return where
|
||||
Reference in New Issue
Block a user