Skip to content
Snippets Groups Projects
Commit 43a6702a authored by OCA Git Bot's avatar OCA Git Bot
Browse files

Merge remote-tracking branch 'odoo/14.0' into 14.0

parents d0dd76e9 10c4091f
No related branches found
No related tags found
No related merge requests found
......@@ -168,7 +168,11 @@ You receive this email because you are:
@api.model
def run(self, autocommit=False):
schedulers = self.search([('done', '=', False), ('scheduled_date', '<=', datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT))])
schedulers = self.search([
('event_id.active', '=', True),
('done', '=', False),
('scheduled_date', '<=', datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT))
])
for scheduler in schedulers:
try:
with self.env.cr.savepoint():
......
......@@ -256,3 +256,68 @@ class TestMailSchedule(TestEventCommon, MockEmail):
fields_values={'subject': '%s: today' % test_event.name,
'email_from': self.user_eventmanager.company_id.email_formatted,
})
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
def test_archived_event_mail_schedule(self):
""" Test mail scheduling for archived events """
event_cron_id = self.env.ref('event.event_mail_scheduler')
# deactivate other schedulers to avoid messing with crons
self.env['event.mail'].search([]).unlink()
# freeze some datetimes, and ensure more than 1D+1H before event starts
# to ease time-based scheduler check
now = datetime(2023, 7, 24, 14, 30, 15)
event_date_begin = datetime(2023, 7, 26, 8, 0, 0)
event_date_end = datetime(2023, 7, 28, 18, 0, 0)
with freeze_time(now):
test_event = self.env['event.event'].with_user(self.user_eventmanager).create({
'name': 'TestEventMail',
'auto_confirm': True,
'date_begin': event_date_begin,
'date_end': event_date_end,
'event_mail_ids': [
(0, 0, { # right at subscription
'interval_unit': 'now',
'interval_type': 'after_sub',
'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}),
(0, 0, { # 3 hours before event
'interval_nbr': 3,
'interval_unit': 'hours',
'interval_type': 'before_event',
'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')})
]
})
# check event scheduler
scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id)])
self.assertEqual(len(scheduler), 2, 'event: wrong scheduler creation')
event_prev_scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id), ('interval_type', '=', 'before_event')])
with freeze_time(now), self.mock_mail_gateway():
self.env['event.registration'].with_user(self.user_eventuser).create({
'event_id': test_event.id,
'name': 'Reg1',
'email': 'reg1@example.com',
})
self.env['event.registration'].with_user(self.user_eventuser).create({
'event_id': test_event.id,
'name': 'Reg2',
'email': 'reg2@example.com',
})
# check emails effectively sent
self.assertEqual(len(self._new_mails), 2, 'event: should have 2 scheduled emails (1 / registration)')
# Archive the Event
test_event.action_archive()
# execute cron to run schedulers
now_start = event_date_begin + relativedelta(hours=-3)
with freeze_time(now_start), self.mock_mail_gateway():
event_cron_id.method_direct_trigger()
# check that scheduler is not executed
self.assertFalse(event_prev_scheduler.mail_sent, 'event: reminder scheduler should not run')
self.assertFalse(event_prev_scheduler.done, 'event: reminder scheduler should not run')
......@@ -117,29 +117,46 @@ GROUP BY channel_moderator.res_users_id""", [tuple(self.ids)])
@api.model
def systray_get_activities(self):
activities = self.env["mail.activity"].search([("user_id", "=", self.env.uid)])
activities_by_record_by_model_name = defaultdict(lambda: defaultdict(lambda: self.env["mail.activity"]))
for activity in activities:
record = self.env[activity.res_model].browse(activity.res_id)
activities_by_record_by_model_name[activity.res_model][record] += activity
model_ids = list({self.env["ir.model"]._get(name).id for name in activities_by_record_by_model_name.keys()})
query = """SELECT array_agg(res_id) as res_ids, m.id, count(*),
CASE
WHEN %(today)s::date - act.date_deadline::date = 0 Then 'today'
WHEN %(today)s::date - act.date_deadline::date > 0 Then 'overdue'
WHEN %(today)s::date - act.date_deadline::date < 0 Then 'planned'
END AS states
FROM mail_activity AS act
JOIN ir_model AS m ON act.res_model_id = m.id
WHERE user_id = %(user_id)s
GROUP BY m.id, states;
"""
self.env.cr.execute(query, {
'today': fields.Date.context_today(self),
'user_id': self.env.uid,
})
activity_data = self.env.cr.dictfetchall()
records_by_state_by_model = defaultdict(lambda: {"today": set(), "overdue": set(), "planned": set(), "all": set()})
for data in activity_data:
records_by_state_by_model[data["id"]][data["states"]] = set(data["res_ids"])
records_by_state_by_model[data["id"]]["all"] = records_by_state_by_model[data["id"]]["all"] | set(data["res_ids"])
user_activities = {}
for model_name, activities_by_record in activities_by_record_by_model_name.items():
domain = [("id", "in", list({r.id for r in activities_by_record.keys()}))]
allowed_records = self.env[model_name].search(domain)
for model_id in records_by_state_by_model:
model_dic = records_by_state_by_model[model_id]
model = self.env["ir.model"].browse(model_id).with_prefetch(tuple(records_by_state_by_model.keys()))
allowed_records = self.env[model.model].search([("id", "in", tuple(model_dic["all"]))])
if not allowed_records:
continue
module = self.env[model_name]._original_module
module = self.env[model.model]._original_module
icon = module and modules.module.get_module_icon(module)
user_activities[model_name] = {
"name": self.env["ir.model"]._get(model_name).with_prefetch(model_ids).name,
"model": model_name,
today = len(model_dic["today"] & set(allowed_records.ids))
overdue = len(model_dic["overdue"] & set(allowed_records.ids))
user_activities[model.model] = {
"name": model.name,
"model": model.model,
"type": "activity",
"icon": icon,
"total_count": 0,
"today_count": 0,
"overdue_count": 0,
"planned_count": 0,
"total_count": today + overdue,
"today_count": today,
"overdue_count": overdue,
"planned_count": len(model_dic["planned"] & set(allowed_records.ids)),
"actions": [
{
"icon": "fa-clock-o",
......@@ -147,13 +164,6 @@ GROUP BY channel_moderator.res_users_id""", [tuple(self.ids)])
}
],
}
for record, activities in activities_by_record.items():
if record not in allowed_records:
continue
for activity in activities:
user_activities[model_name]["%s_count" % activity.state] += 1
if activity.state in ("today", "overdue"):
user_activities[model_name]["total_count"] += 1
return list(user_activities.values())
......
......@@ -95,7 +95,7 @@ class StockProductionLot(models.Model):
for lot in alert_lots:
lot.activity_schedule(
'product_expiry.mail_activity_type_alert_date_reached',
user_id=lot.product_id.responsible_id.id or SUPERUSER_ID,
user_id=lot.product_id.with_company(lot.company_id).responsible_id.id or lot.product_id.responsible_id.id or SUPERUSER_ID,
note=_("The alert date has been reached for this lot/serial number")
)
alert_lots.write({
......
......@@ -21,7 +21,7 @@ class WebsiteVisitor(models.Model):
self.flush()
left_visitors = self.filtered(lambda visitor: not visitor.email or not visitor.mobile)
leads = left_visitors.mapped('lead_ids').sorted('create_date', reverse=True)
leads = left_visitors.sudo().mapped('lead_ids').sorted('create_date', reverse=True)
visitor_to_lead_ids = dict((visitor.id, visitor.lead_ids.ids) for visitor in left_visitors)
for visitor in left_visitors:
......
......@@ -21,7 +21,7 @@
<field name="arch" type="xml">
<xpath expr="//button[@id='w_visitor_visit_counter']" position="before">
<button name="%(website_crm.website_visitor_crm_lead_action)d" type="action" class="oe_stat_button" icon="fa-star"
attrs="{'invisible': [('lead_count', '=', 0)]}">
groups="sales_team.group_sale_salesman" attrs="{'invisible': [('lead_count', '=', 0)]}">
<field name="lead_count" widget="statinfo" string="Leads"/>
</button>
</xpath>
......
......@@ -18,13 +18,7 @@ def get_test_modules(module):
feed unittest.TestLoader.loadTestsFromModule() """
# Try to import the module
results = _get_tests_modules('odoo.addons', module)
try:
importlib.import_module('odoo.upgrade.%s' % module)
except ImportError:
pass
else:
results += list(_get_upgrade_test_modules(module))
results += list(_get_upgrade_test_modules(module))
return results
......@@ -53,16 +47,26 @@ def _get_tests_modules(path, module):
return result
def _get_upgrade_test_modules(module):
upg = importlib.import_module("odoo.upgrade")
for path in map(Path, upg.__path__):
for test in (path / module / "tests").glob("test_*.py"):
spec = importlib.util.spec_from_file_location(f"odoo.upgrade.{module}.tests.{test.stem}", test)
if not spec:
continue
pymod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = pymod
spec.loader.exec_module(pymod)
yield pymod
upgrade_modules = (
f"odoo.upgrade.{module}",
f"odoo.addons.{module}.migrations",
f"odoo.addons.{module}.upgrades",
)
for module_name in upgrade_modules:
try:
upg = importlib.import_module(module_name)
except ImportError:
continue
for path in map(Path, upg.__path__):
for test in path.glob("tests/test_*.py"):
spec = importlib.util.spec_from_file_location(f"{upg.__name__}.tests.{test.stem}", test)
if not spec:
continue
pymod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = pymod
spec.loader.exec_module(pymod)
yield pymod
def make_suite(module_names, position='at_install'):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment