- create new module hr_promote (depend: hr,approvals) \n - customize approval_type (WIP)
141 lines
5.9 KiB
Python
141 lines
5.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.fields import Datetime
|
|
from odoo.osv.expression import NEGATIVE_TERM_OPERATORS
|
|
|
|
|
|
class MarketingParticipant(models.Model):
|
|
_name = 'marketing.participant'
|
|
_description = 'Marketing Participant'
|
|
_order = 'id ASC'
|
|
_rec_name = 'resource_ref'
|
|
|
|
@api.model
|
|
def default_get(self, default_fields):
|
|
defaults = super(MarketingParticipant, self).default_get(default_fields)
|
|
if 'res_id' in default_fields and not defaults.get('res_id'):
|
|
model_name = defaults.get('model_name')
|
|
if not model_name and defaults.get('campaign_id'):
|
|
model_name = self.env['marketing.campaign'].browse(defaults['campaign_id']).model_name
|
|
if model_name and model_name in self.env:
|
|
resource = self.env[model_name].search([], limit=1)
|
|
defaults['res_id'] = resource.id
|
|
return defaults
|
|
|
|
@api.model
|
|
def _selection_target_model(self):
|
|
models = self.env['ir.model'].sudo().search([('is_mail_thread', '=', True)])
|
|
return [(model.model, model.name) for model in models]
|
|
|
|
def _search_resource_ref(self, operator, value):
|
|
ir_models = set([model['model_name'] for model in self.env['marketing.campaign'].search([]).read(['model_name'])])
|
|
ir_model_ids = []
|
|
for model in ir_models:
|
|
if model in self.env:
|
|
ir_model_ids += self.env['marketing.participant'].search(['&', ('model_name', '=', model), ('res_id', 'in', [name[0] for name in self.env[model].name_search(name=value)])]).ids
|
|
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
|
|
return [('id', operator, ir_model_ids)]
|
|
|
|
campaign_id = fields.Many2one(
|
|
'marketing.campaign', string='Campaign',
|
|
index=True, ondelete='cascade', required=True)
|
|
model_id = fields.Many2one(
|
|
'ir.model', string='Model', related='campaign_id.model_id',
|
|
index=True, readonly=True, store=True)
|
|
model_name = fields.Char(
|
|
string='Record model', related='campaign_id.model_id.model',
|
|
readonly=True, store=True)
|
|
res_id = fields.Integer(string='Record ID', index=True)
|
|
resource_ref = fields.Reference(
|
|
string='Record', selection='_selection_target_model',
|
|
compute='_compute_resource_ref', inverse='_set_resource_ref', search='_search_resource_ref')
|
|
trace_ids = fields.One2many('marketing.trace', 'participant_id', string='Actions')
|
|
state = fields.Selection([
|
|
('running', 'Running'),
|
|
('completed', 'Completed'),
|
|
('unlinked', 'Removed'),
|
|
], default='running', index=True, required=True,
|
|
help='Removed means the related record does not exist anymore.')
|
|
is_test = fields.Boolean('Test Record', default=False)
|
|
|
|
@api.depends('model_name', 'res_id')
|
|
def _compute_resource_ref(self):
|
|
for participant in self:
|
|
if participant.model_name and participant.model_name in self.env:
|
|
participant.resource_ref = '%s,%s' % (participant.model_name, participant.res_id or 0)
|
|
else:
|
|
participant.resource_ref = None
|
|
|
|
def _set_resource_ref(self):
|
|
for participant in self:
|
|
if participant.resource_ref:
|
|
participant.res_id = participant.resource_ref.id
|
|
|
|
def check_completed(self):
|
|
existing_traces = self.env['marketing.trace'].search([
|
|
('participant_id', 'in', self.ids),
|
|
('state', '=', 'scheduled'),
|
|
])
|
|
(self - existing_traces.mapped('participant_id')).write({'state': 'completed'})
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
participants = super().create(vals_list)
|
|
now = Datetime.now()
|
|
cron_trigger_dates = set()
|
|
for res in participants:
|
|
# prepare first traces related to begin activities
|
|
primary_activities = res.campaign_id.marketing_activity_ids.filtered(lambda act: act.trigger_type == 'begin')
|
|
trace_ids = [
|
|
(0, 0, {
|
|
'activity_id': activity.id,
|
|
'schedule_date': now + relativedelta(**{activity.interval_type: activity.interval_number}),
|
|
}) for activity in primary_activities]
|
|
res.write({'trace_ids': trace_ids})
|
|
|
|
cron_trigger_dates |= set([
|
|
now + relativedelta(**{activity.interval_type: activity.interval_number})
|
|
for activity in primary_activities
|
|
])
|
|
|
|
if cron_trigger_dates:
|
|
# based on activities with 'begin' trigger_type, we schedule CRON triggers
|
|
# that match the scheduled_dates of created marketing.traces
|
|
# we use a set to only trigger the CRON once per timeslot event if there are multiple
|
|
# marketing.participants
|
|
cron = self.env.ref('marketing_automation.ir_cron_campaign_execute_activities')
|
|
cron._trigger(cron_trigger_dates)
|
|
|
|
return participants
|
|
|
|
def action_set_completed(self):
|
|
''' Manually mark as a completed and cancel every scheduled trace '''
|
|
# TDE TODO: delegate set Canceled to trace record
|
|
self.write({'state': 'completed'})
|
|
self.env['marketing.trace'].search([
|
|
('participant_id', 'in', self.ids),
|
|
('state', '=', 'scheduled')
|
|
]).write({
|
|
'state': 'canceled',
|
|
'schedule_date': Datetime.now(),
|
|
'state_msg': _('Marked as completed')
|
|
})
|
|
|
|
def action_set_running(self):
|
|
self.write({'state': 'running'})
|
|
|
|
def action_set_unlink(self):
|
|
self.write({'state': 'unlinked'})
|
|
self.env['marketing.trace'].search([
|
|
('participant_id', 'in', self.ids),
|
|
('state', '=', 'scheduled')
|
|
]).write({
|
|
'state': 'canceled',
|
|
'state_msg': _('Record deleted'),
|
|
})
|
|
return True
|