diff --git a/task_manager/__init__.py b/task_manager/__init__.py
new file mode 100644
index 00000000000..1793d20a10e
--- /dev/null
+++ b/task_manager/__init__.py
@@ -0,0 +1,46 @@
+from . import models
+
+from odoo import Command
+
+
+def add_tags(env):
+ tags = []
+ for i in range(10):
+ tags.append(
+ {
+ "name": f"tag_{i + 1}",
+ "color": i,
+ }
+ )
+
+ env["task.manager.tags"].create(tags)
+
+
+def _pre_init_hook(env):
+ query = """
+ DO $$
+ DECLARE
+ i INT;
+ new_partner_id INT;
+ BEGIN
+ FOR i IN 0..9 LOOP
+ INSERT INTO res_partner (name, phone, company_id, active, type)
+ VALUES ('user_' || i, '0987654321', 1, true, 'contact')
+ RETURNING id INTO new_partner_id;
+
+ INSERT INTO res_users (login, partner_id, company_id, active, notification_type)
+ VALUES ('user_' || i || '@example.com', new_partner_id, 1, true, 'email');
+ END LOOP;
+ END $$;
+ """
+ env.cr.execute(query)
+
+
+def remove_users_with_mobile_number(env):
+ target_logins = [f"user_{i}@example.com" for i in range(10)]
+ users_to_remove = env["res.users"].search([("login", "in", target_logins)])
+
+ if users_to_remove:
+ partner_records = users_to_remove.partner_id
+ users_to_remove.unlink()
+ partner_records.unlink()
diff --git a/task_manager/__manifest__.py b/task_manager/__manifest__.py
new file mode 100644
index 00000000000..344ec6d5bdf
--- /dev/null
+++ b/task_manager/__manifest__.py
@@ -0,0 +1,18 @@
+{
+ "name": "Task Manager",
+ "application": True,
+ "installable": True,
+ "author": "sngoh",
+ "depends": ["mail"],
+ "license": "LGPL-3",
+ "data": [
+ "security/ir.access.csv",
+ "data/ir_cron_data.xml",
+ "views/task_manager_tags_view.xml",
+ "views/task_manager_view.xml",
+ "views/task_manager_menus.xml",
+ ],
+ "pre_init_hook": "_pre_init_hook",
+ "post_init_hook": "add_tags",
+ "uninstall_hook": "remove_users_with_mobile_number",
+}
diff --git a/task_manager/data/ir_cron_data.xml b/task_manager/data/ir_cron_data.xml
new file mode 100644
index 00000000000..f56eb37fa09
--- /dev/null
+++ b/task_manager/data/ir_cron_data.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Auto Archive Task After 7pm
+
+ code
+ model._auto_archive()
+ 1
+ days
+
+
+
+
+
+
+
+
diff --git a/task_manager/models/__init__.py b/task_manager/models/__init__.py
new file mode 100644
index 00000000000..21ceadcea5e
--- /dev/null
+++ b/task_manager/models/__init__.py
@@ -0,0 +1,2 @@
+from . import task_manager
+from . import task_manager_tags
diff --git a/task_manager/models/task_manager.py b/task_manager/models/task_manager.py
new file mode 100644
index 00000000000..6877d280f90
--- /dev/null
+++ b/task_manager/models/task_manager.py
@@ -0,0 +1,134 @@
+from odoo import api, Command, fields, models
+from odoo.exceptions import UserError
+
+
+class TaskManagerTask(models.Model):
+ _name = "task.manager"
+ _inherit = ["mail.thread"]
+ _description = "Task Manager"
+
+ def _get_default_deadline(self):
+ return fields.Datetime.add(fields.Datetime.today(), days=3)
+
+ name = fields.Char(tracking=True, required=True)
+ active = fields.Boolean(default=True)
+ assigned_user = fields.Many2one("res.users", tracking=True)
+ deadline = fields.Datetime(
+ tracking=True,
+ required=True,
+ default=lambda self: self._get_default_deadline(),
+ )
+ status = fields.Selection(
+ string="Status",
+ selection=[
+ ("new", "New"),
+ ("in_progress", "In Progress"),
+ ("done", "Done"),
+ ],
+ default="new",
+ tracking=True,
+ )
+ tag_ids = fields.Many2many(
+ "task.manager.tags",
+ compute="_compute_assigned_user",
+ store=True,
+ )
+ days_remaining = fields.Integer(compute="_compute_days_remaining")
+ count_of_assignes = fields.Integer(compute="_compute_count_of_assignes")
+
+ @api.depends("deadline")
+ def _compute_days_remaining(self):
+ for task in self:
+ task.days_remaining = (task.deadline - fields.Datetime.today()).days
+
+ @api.depends("assigned_user")
+ def _compute_count_of_assignes(self):
+ for task in self:
+ task.count_of_assignes = len(task.assigned_user)
+
+ @api.depends("assigned_user")
+ def _compute_assigned_user(self):
+ tag_name = "assigned"
+ tag = self.env["task.manager.tags"].search([("name", "=", tag_name)], limit=1)
+ if not tag:
+ tag = self.env["task.manager.tags"].create({"name": tag_name})
+
+ unlink_ids = []
+ link_ids = []
+
+ for task in self:
+ if not task.assigned_user and tag in task.tag_ids:
+ unlink_ids.append(task.id)
+ elif task.assigned_user and tag not in task.tag_ids:
+ link_ids.append(task.id)
+
+ if unlink_ids:
+ self.browse(unlink_ids).tag_ids = [Command.unlink(tag.id)]
+ if link_ids:
+ self.browse(link_ids).tag_ids = [Command.link(tag.id)]
+
+ def write(self, vals):
+ is_archiving = "active" in vals
+ for task in self:
+ if task.status == "done" and not is_archiving:
+ raise UserError("Cannot update task's details in the Done state.")
+
+ return super().write(vals)
+
+ def quick_archive(self):
+ if self:
+ tasks = self.filtered(lambda t: t.status == "done" and t.active)
+ else:
+ tasks = self.env["task.manager"].search(
+ [
+ ("status", "=", "done"),
+ ("active", "=", True),
+ ],
+ )
+ if tasks:
+ tasks.action_archive()
+
+ def print_task_count(self):
+ task_count = self.env["task.manager"].search_count([])
+ return {
+ "effect": {
+ "fadeout": "slow",
+ "message": f"{task_count} Tasks are there.",
+ "img_url": "/web/static/img/smile.svg",
+ "type": "rainbow_man",
+ }
+ }
+
+ def generate_multiple_tasks(self):
+ tasks = [
+ {"name": "Generated Task 1", "deadline": fields.Datetime.today()},
+ {"name": "Generated Task 2", "deadline": fields.Datetime.today()},
+ ]
+ self.env["task.manager"].create(tasks)
+
+ def _auto_archive(self):
+ done_tasks = self.env["task.manager"].search(
+ [
+ ("status", "=", "done"),
+ ("active", "=", True),
+ ],
+ )
+ done_tasks.action_archive()
+
+ @api.autovacuum
+ def _gc_delete_archive_task(self):
+ old_archived_tasks = self.env["task.manager"].search(
+ [
+ ("active", "=", False),
+ (
+ "create_date",
+ "<",
+ fields.Datetime.subtract(
+ fields.Datetime.today(),
+ days=31,
+ ),
+ ),
+ ],
+ )
+ # breakpoint()
+ old_archived_tasks.unlink()
diff --git a/task_manager/models/task_manager_tags.py b/task_manager/models/task_manager_tags.py
new file mode 100644
index 00000000000..814fa75c462
--- /dev/null
+++ b/task_manager/models/task_manager_tags.py
@@ -0,0 +1,15 @@
+from odoo import fields, models
+
+
+class TaskManagerTags(models.Model):
+ _name = "task.manager.tags"
+ _description = "Tags for Tasks"
+ _order = "name"
+
+ name = fields.Char(required=True)
+ color = fields.Integer()
+
+ _check_unique_tag = models.Constraint(
+ "UNIQUE(name)",
+ "A property tag name must be unique",
+ )
diff --git a/task_manager/security/ir.access.csv b/task_manager/security/ir.access.csv
new file mode 100644
index 00000000000..542acada176
--- /dev/null
+++ b/task_manager/security/ir.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id,group_id/id,operation,domain
+access_task_manager,access_task_manager,task.manager,base.group_user,crud,
+access_task_manager_tags,access_task_manager_tags,task.manager.tags,base.group_user,crud,
diff --git a/task_manager/views/task_manager_menus.xml b/task_manager/views/task_manager_menus.xml
new file mode 100644
index 00000000000..545f8a7b31b
--- /dev/null
+++ b/task_manager/views/task_manager_menus.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/task_manager/views/task_manager_tags_view.xml b/task_manager/views/task_manager_tags_view.xml
new file mode 100644
index 00000000000..f4162f560bc
--- /dev/null
+++ b/task_manager/views/task_manager_tags_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+ task.manager.tags.view.list
+ task.manager.tags
+
+
+
+
+
+
+
+
+
+ task.manager.tags.view.form
+ task.manager.tags
+
+
+
+
+
+
+ Task Tags
+ task.manager.tags
+ list,form
+
+
+
diff --git a/task_manager/views/task_manager_view.xml b/task_manager/views/task_manager_view.xml
new file mode 100644
index 00000000000..d3f2d92d731
--- /dev/null
+++ b/task_manager/views/task_manager_view.xml
@@ -0,0 +1,85 @@
+
+
+
+
+ task.manager.list
+ task.manager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ task.manager.form
+ task.manager
+
+
+
+
+
+
+ task.manager.view.kanban
+ task.manager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tasks
+ task.manager
+ list,form,kanban
+
+
+