summaryrefslogtreecommitdiff
path: root/addons/sales_team/models
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/sales_team/models
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/sales_team/models')
-rw-r--r--addons/sales_team/models/__init__.py7
-rw-r--r--addons/sales_team/models/crm_tag.py21
-rw-r--r--addons/sales_team/models/crm_team.py240
-rw-r--r--addons/sales_team/models/res_partner.py12
-rw-r--r--addons/sales_team/models/res_users.py12
5 files changed, 292 insertions, 0 deletions
diff --git a/addons/sales_team/models/__init__.py b/addons/sales_team/models/__init__.py
new file mode 100644
index 00000000..2fa2d9bc
--- /dev/null
+++ b/addons/sales_team/models/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import crm_team
+from . import crm_tag
+from . import res_partner
+from . import res_users
diff --git a/addons/sales_team/models/crm_tag.py b/addons/sales_team/models/crm_tag.py
new file mode 100644
index 00000000..29d0c696
--- /dev/null
+++ b/addons/sales_team/models/crm_tag.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from random import randint
+
+from odoo import fields, models
+
+
+class Tag(models.Model):
+ _name = "crm.tag"
+ _description = "CRM Tag"
+
+ def _get_default_color(self):
+ return randint(1, 11)
+
+ name = fields.Char('Tag Name', required=True, translate=True)
+ color = fields.Integer('Color', default=_get_default_color)
+
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', "Tag name already exists !"),
+ ]
diff --git a/addons/sales_team/models/crm_team.py b/addons/sales_team/models/crm_team.py
new file mode 100644
index 00000000..104baaf1
--- /dev/null
+++ b/addons/sales_team/models/crm_team.py
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import json
+
+from babel.dates import format_date
+from datetime import date
+from dateutil.relativedelta import relativedelta
+
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+from odoo.release import version
+
+
+class CrmTeam(models.Model):
+ _name = "crm.team"
+ _inherit = ['mail.thread']
+ _description = "Sales Team"
+ _order = "sequence"
+ _check_company_auto = True
+
+ def _get_default_team_id(self, user_id=None, domain=None):
+ user_id = user_id or self.env.uid
+ user_salesteam_id = self.env['res.users'].browse(user_id).sale_team_id.id
+ # Avoid searching on member_ids (+1 query) when we may have the user salesteam already in cache.
+ team = self.env['crm.team'].search([
+ ('company_id', 'in', [False, self.env.company.id]),
+ '|', ('user_id', '=', user_id), ('id', '=', user_salesteam_id),
+ ], limit=1)
+ if not team and 'default_team_id' in self.env.context:
+ team = self.env['crm.team'].browse(self.env.context.get('default_team_id'))
+ return team or self.env['crm.team'].search(domain or [], limit=1)
+
+ def _get_default_favorite_user_ids(self):
+ return [(6, 0, [self.env.uid])]
+
+ name = fields.Char('Sales Team', required=True, translate=True)
+ sequence = fields.Integer('Sequence', default=10)
+ active = fields.Boolean(default=True, help="If the active field is set to false, it will allow you to hide the Sales Team without removing it.")
+ company_id = fields.Many2one(
+ 'res.company', string='Company', index=True,
+ default=lambda self: self.env.company)
+ currency_id = fields.Many2one(
+ "res.currency", string="Currency",
+ related='company_id.currency_id', readonly=True)
+ user_id = fields.Many2one('res.users', string='Team Leader', check_company=True)
+ # memberships
+ member_ids = fields.One2many(
+ 'res.users', 'sale_team_id', string='Channel Members',
+ check_company=True, domain=[('share', '=', False)],
+ help="Add members to automatically assign their documents to this sales team. You can only be member of one team.")
+ # UX options
+ color = fields.Integer(string='Color Index', help="The color of the channel")
+ favorite_user_ids = fields.Many2many(
+ 'res.users', 'team_favorite_user_rel', 'team_id', 'user_id',
+ string='Favorite Members', default=_get_default_favorite_user_ids)
+ is_favorite = fields.Boolean(
+ string='Show on dashboard', compute='_compute_is_favorite', inverse='_inverse_is_favorite',
+ help="Favorite teams to display them in the dashboard and access them easily.")
+ dashboard_button_name = fields.Char(string="Dashboard Button", compute='_compute_dashboard_button_name')
+ dashboard_graph_data = fields.Text(compute='_compute_dashboard_graph')
+
+ def _compute_is_favorite(self):
+ for team in self:
+ team.is_favorite = self.env.user in team.favorite_user_ids
+
+ def _inverse_is_favorite(self):
+ sudoed_self = self.sudo()
+ to_fav = sudoed_self.filtered(lambda team: self.env.user not in team.favorite_user_ids)
+ to_fav.write({'favorite_user_ids': [(4, self.env.uid)]})
+ (sudoed_self - to_fav).write({'favorite_user_ids': [(3, self.env.uid)]})
+ return True
+
+ def _compute_dashboard_button_name(self):
+ """ Sets the adequate dashboard button name depending on the Sales Team's options
+ """
+ for team in self:
+ team.dashboard_button_name = _("Big Pretty Button :)") # placeholder
+
+ def _compute_dashboard_graph(self):
+ for team in self:
+ team.dashboard_graph_data = json.dumps(team._get_dashboard_graph_data())
+
+ # ------------------------------------------------------------
+ # CRUD
+ # ------------------------------------------------------------
+
+ @api.model
+ def create(self, values):
+ team = super(CrmTeam, self.with_context(mail_create_nosubscribe=True)).create(values)
+ if values.get('member_ids'):
+ team._add_members_to_favorites()
+ return team
+
+ def write(self, values):
+ res = super(CrmTeam, self).write(values)
+ if values.get('member_ids'):
+ self._add_members_to_favorites()
+ return res
+
+ def unlink(self):
+ default_teams = [
+ self.env.ref('sales_team.salesteam_website_sales'),
+ self.env.ref('sales_team.pos_sales_team'),
+ self.env.ref('sales_team.ebay_sales_team')
+ ]
+ for team in self:
+ if team in default_teams:
+ raise UserError(_('Cannot delete default team "%s"', team.name))
+ return super(CrmTeam,self).unlink()
+
+ # ------------------------------------------------------------
+ # ACTIONS
+ # ------------------------------------------------------------
+
+ def action_primary_channel_button(self):
+ """ Skeleton function to be overloaded It will return the adequate action
+ depending on the Sales Team's options. """
+ return False
+
+ # ------------------------------------------------------------
+ # TOOLS
+ # ------------------------------------------------------------
+
+ def _add_members_to_favorites(self):
+ for team in self:
+ team.favorite_user_ids = [(4, member.id) for member in team.member_ids]
+
+ # ------------------------------------------------------------
+ # GRAPH
+ # ------------------------------------------------------------
+
+ def _graph_get_model(self):
+ """ skeleton function defined here because it'll be called by crm and/or sale
+ """
+ raise UserError(_('Undefined graph model for Sales Team: %s', self.name))
+
+ def _graph_get_dates(self, today):
+ """ return a coherent start and end date for the dashboard graph covering a month period grouped by week.
+ """
+ start_date = today - relativedelta(months=1)
+ # we take the start of the following week if we group by week
+ # (to avoid having twice the same week from different month)
+ start_date += relativedelta(days=8 - start_date.isocalendar()[2])
+ return [start_date, today]
+
+ def _graph_date_column(self):
+ return 'create_date'
+
+ def _graph_x_query(self):
+ return 'EXTRACT(WEEK FROM %s)' % self._graph_date_column()
+
+ def _graph_y_query(self):
+ raise UserError(_('Undefined graph model for Sales Team: %s', self.name))
+
+ def _extra_sql_conditions(self):
+ return ''
+
+ def _graph_title_and_key(self):
+ """ Returns an array containing the appropriate graph title and key respectively.
+
+ The key is for lineCharts, to have the on-hover label.
+ """
+ return ['', '']
+
+ def _graph_data(self, start_date, end_date):
+ """ return format should be an iterable of dicts that contain {'x_value': ..., 'y_value': ...}
+ x_values should be weeks.
+ y_values are floats.
+ """
+ query = """SELECT %(x_query)s as x_value, %(y_query)s as y_value
+ FROM %(table)s
+ WHERE team_id = %(team_id)s
+ AND DATE(%(date_column)s) >= %(start_date)s
+ AND DATE(%(date_column)s) <= %(end_date)s
+ %(extra_conditions)s
+ GROUP BY x_value;"""
+
+ # apply rules
+ dashboard_graph_model = self._graph_get_model()
+ GraphModel = self.env[dashboard_graph_model]
+ graph_table = GraphModel._table
+ extra_conditions = self._extra_sql_conditions()
+ where_query = GraphModel._where_calc([])
+ GraphModel._apply_ir_rules(where_query, 'read')
+ from_clause, where_clause, where_clause_params = where_query.get_sql()
+ if where_clause:
+ extra_conditions += " AND " + where_clause
+
+ query = query % {
+ 'x_query': self._graph_x_query(),
+ 'y_query': self._graph_y_query(),
+ 'table': graph_table,
+ 'team_id': "%s",
+ 'date_column': self._graph_date_column(),
+ 'start_date': "%s",
+ 'end_date': "%s",
+ 'extra_conditions': extra_conditions
+ }
+
+ self._cr.execute(query, [self.id, start_date, end_date] + where_clause_params)
+ return self.env.cr.dictfetchall()
+
+ def _get_dashboard_graph_data(self):
+ def get_week_name(start_date, locale):
+ """ Generates a week name (string) from a datetime according to the locale:
+ E.g.: locale start_date (datetime) return string
+ "en_US" November 16th "16-22 Nov"
+ "en_US" December 28th "28 Dec-3 Jan"
+ """
+ if (start_date + relativedelta(days=6)).month == start_date.month:
+ short_name_from = format_date(start_date, 'd', locale=locale)
+ else:
+ short_name_from = format_date(start_date, 'd MMM', locale=locale)
+ short_name_to = format_date(start_date + relativedelta(days=6), 'd MMM', locale=locale)
+ return short_name_from + '-' + short_name_to
+
+ self.ensure_one()
+ values = []
+ today = fields.Date.from_string(fields.Date.context_today(self))
+ start_date, end_date = self._graph_get_dates(today)
+ graph_data = self._graph_data(start_date, end_date)
+ x_field = 'label'
+ y_field = 'value'
+
+ # generate all required x_fields and update the y_values where we have data for them
+ locale = self._context.get('lang') or 'en_US'
+
+ weeks_in_start_year = int(date(start_date.year, 12, 28).isocalendar()[1]) # This date is always in the last week of ISO years
+ for week in range(0, (end_date.isocalendar()[1] - start_date.isocalendar()[1]) % weeks_in_start_year + 1):
+ short_name = get_week_name(start_date + relativedelta(days=7 * week), locale)
+ values.append({x_field: short_name, y_field: 0})
+
+ for data_item in graph_data:
+ index = int((data_item.get('x_value') - start_date.isocalendar()[1]) % weeks_in_start_year)
+ values[index][y_field] = data_item.get('y_value')
+
+ [graph_title, graph_key] = self._graph_title_and_key()
+ color = '#875A7B' if '+e' in version else '#7c7bad'
+ return [{'values': values, 'area': True, 'title': graph_title, 'key': graph_key, 'color': color}]
diff --git a/addons/sales_team/models/res_partner.py b/addons/sales_team/models/res_partner.py
new file mode 100644
index 00000000..d651f89d
--- /dev/null
+++ b/addons/sales_team/models/res_partner.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import fields, models
+
+
+class ResPartner(models.Model):
+ _inherit = 'res.partner'
+
+ team_id = fields.Many2one(
+ 'crm.team', 'Sales Team',
+ help='If set, this Sales Team will be used for sales and assignments related to this partner')
diff --git a/addons/sales_team/models/res_users.py b/addons/sales_team/models/res_users.py
new file mode 100644
index 00000000..f2fdd183
--- /dev/null
+++ b/addons/sales_team/models/res_users.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import fields, models
+
+
+class ResUsers(models.Model):
+ _inherit = 'res.users'
+
+ sale_team_id = fields.Many2one(
+ 'crm.team', "User's Sales Team",
+ help='Sales Team the user is member of. Used to compute the members of a Sales Team through the inverse one2many') \ No newline at end of file