import datetime as dt import pytz import json from dateutil import relativedelta import dateutil from datetime import datetime from collections import defaultdict import re import babel from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT, \ frozendict, lazy_classproperty, lazy_property, ormcache, \ Collector, LastOrderedSet, OrderedSet, pycompat from flectra import models, fields, api, _ from flectra.exceptions import ValidationError, AccessError, UserError from ast import literal_eval from flectra.tools.safe_eval import safe_eval from ..lib.ks_date_filter_selections import ks_get_date # TODO : Check all imports if needed aggregate_fun= { 'array_agg', 'count', 'count_distinct', 'bool_and', 'bool_or', 'max', 'min', 'avg', 'sum', } regex_field_agg = re.compile(r'(\w+)(?::(\w+)(?:\((\w+)\))?)?') read = fields.Many2one.read def ks_read(self, records): if self.name == 'ks_list_view_fields' or self.name == 'ks_list_view_group_fields': comodel = records.env[self.comodel_name] # String domains are supposed to be dynamic and evaluated on client-side # only (thus ignored here). domain = self.domain if isinstance(self.domain, list) else [] wquery = comodel._where_calc(domain) comodel._apply_ir_rules(wquery, 'read') from_c, where_c, where_params = wquery.get_sql() query = """ SELECT {rel}.{id1}, {rel}.{id2} FROM {rel}, {from_c} WHERE {where_c} AND {rel}.{id1} IN %s AND {rel}.{id2} = {tbl}.id """.format(rel=self.relation, id1=self.column1, id2=self.column2, tbl=comodel._table, from_c=from_c, where_c=where_c or '1=1', limit=(' LIMIT %d' % self.limit) if self.limit else '', ) where_params.append(tuple(records.ids)) # retrieve lines and group them by record group = defaultdict(list) records._cr.execute(query, where_params) rec_list = records._cr.fetchall() for row in rec_list: group[row[0]].append(row[1]) # store result in cache cache = records.env.cache for record in records: if self.name == 'ks_list_view_fields': field = 'ks_list_view_fields' else: field = 'ks_list_view_group_fields' order = False if record.ks_many2many_field_ordering: order = json.loads(record.ks_many2many_field_ordering).get(field, False) if order: group[record.id].sort(key=lambda x: order.index(x)) cache.set(record, self, tuple(group[record.id])) else: comodel = records.env[self.comodel_name] # String domains are supposed to be dynamic and evaluated on client-side # only (thus ignored here). domain = self.domain if isinstance(self.domain, list) else [] wquery = comodel._where_calc(domain) comodel._apply_ir_rules(wquery, 'read') order_by = comodel._generate_order_by(None, wquery) from_c, where_c, where_params = wquery.get_sql() query = """ SELECT {rel}.{id1}, {rel}.{id2} FROM {rel}, {from_c} WHERE {where_c} AND {rel}.{id1} IN %s AND {rel}.{id2} = {tbl}.id {order_by} {limit} OFFSET {offset} """.format(rel=self.relation, id1=self.column1, id2=self.column2, tbl=comodel._table, from_c=from_c, where_c=where_c or '1=1', limit=(' LIMIT %d' % self.limit) if self.limit else '', offset=0, order_by=order_by) where_params.append(tuple(records.ids)) # retrieve lines and group them by record group = defaultdict(list) records._cr.execute(query, where_params) for row in records._cr.fetchall(): group[row[0]].append(row[1]) # store result in cache cache = records.env.cache for record in records: cache.set(record, self, tuple(group[record.id])) fields.Many2many.read = ks_read read_group = models.BaseModel._read_group_process_groupby def ks_time_addition(self, gb, query): split = gb.split(':') field_type = self._fields[split[0]].type gb_function = split[1] if len(split) == 2 else None if gb_function == 'month_year': gb_function = 'month' temporal = field_type in ('date', 'datetime') tz_convert = field_type == 'datetime' and self._context.get('tz') in pytz.all_timezones qualified_field = self._inherits_join_calc(self._table, split[0], query) if temporal: display_formats = { # Careful with week/year formats: # - yyyy (lower) must always be used, *except* for week+year formats # - YYYY (upper) must always be used for week+year format # e.g. 2006-01-01 is W52 2005 in some locales (de_DE), # and W1 2006 for others # # Mixing both formats, e.g. 'MMM YYYY' would yield wrong results, # such as 2006-01-01 being formatted as "January 2005" in some locales. # Cfr: http://babel.pocoo.org/docs/dates/#date-fields 'minute': 'hh:mm dd MMM', 'hour': 'hh:00 dd MMM', 'day': 'dd MMM yyyy', # yyyy = normal year 'week': "'W'w YYYY", # w YYYY = ISO week-year 'month': 'MMMM yyyy', 'quarter': 'QQQ yyyy', 'year': 'yyyy', } time_intervals = { 'minute': dateutil.relativedelta.relativedelta(minutes=1), 'hour': dateutil.relativedelta.relativedelta(hours=1), 'day': dateutil.relativedelta.relativedelta(days=1), 'week': dt.timedelta(days=7), 'month': dateutil.relativedelta.relativedelta(months=1), 'month_year': dateutil.relativedelta.relativedelta(months=1), 'quarter': dateutil.relativedelta.relativedelta(months=3), 'year': dateutil.relativedelta.relativedelta(years=1) } if tz_convert: qualified_field = "timezone('%s', timezone('UTC',%s))" % (self._context.get('tz', 'UTC'), qualified_field) qualified_field = "date_trunc('%s', %s)" % (gb_function or 'month', qualified_field) if field_type == 'boolean': qualified_field = "coalesce(%s,false)" % qualified_field return { 'field': split[0], 'groupby': gb, 'type': field_type, 'display_format': display_formats[gb_function or 'month'] if temporal else None, 'interval': time_intervals[gb_function or 'month'] if temporal else None, 'tz_convert': tz_convert, 'qualified_field': qualified_field } def ks_read_group_raw(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): self.check_access_rights('read') query = self._where_calc(domain) fields = fields or [f.name for f in self._fields.values() if f.store] groupby = [groupby] if isinstance(groupby, pycompat.string_types) else list(OrderedSet(groupby)) groupby_list = groupby[:1] if lazy else groupby annotated_groupbys = [self._read_group_process_groupby(gb, query) for gb in groupby_list] groupby_fields = [g['field'] for g in annotated_groupbys] order = orderby or ','.join([g for g in groupby_list]) groupby_dict = {gb['groupby']: gb for gb in annotated_groupbys} self._apply_ir_rules(query, 'read') for gb in groupby_fields: assert gb in fields, "Fields in 'groupby' must appear in the list of fields to read (perhaps it's missing in the list view?)" assert gb in self._fields, "Unknown field %r in 'groupby'" % gb gb_field = self._fields[gb].base_field assert gb_field.store and gb_field.column_type, "Fields in 'groupby' must be regular database-persisted fields (no function or related fields), or function fields with store=True" aggregated_fields = [] select_terms = [] for field in fields: if field == 'sequence': continue match = regex_field_agg.match(field) if not match: raise UserError(_("Invalid field specification %r.") % field) name, func, fname = match.groups() if func: fname = fname or name field = self._fields[fname] if not (field.base_field.store and field.base_field.column_type): raise UserError(_("Cannot aggregate field %r.") % fname) if func not in aggregate_fun: raise UserError(_("Invalid aggregation function %r.") % func) else: field = self._fields.get(name) if not (field and field.base_field.store and field.base_field.column_type and field.group_operator): continue func, fname = field.group_operator, name if fname in groupby_fields: continue if name in aggregated_fields: raise UserError(_("Output name %r is used twice.") % name) aggregated_fields.append(name) expr = self._inherits_join_calc(self._table, fname, query) if func.lower() == 'count_distinct': term = 'COUNT(DISTINCT %s) AS "%s"' % (expr, name) else: term = '%s(%s) AS "%s"' % (func, expr, name) select_terms.append(term) for gb in annotated_groupbys: select_terms.append('%s as "%s" ' % (gb['qualified_field'], gb['groupby'])) for gb in annotated_groupbys: select_terms.append('%s as "%s" ' % (gb['qualified_field'], gb['groupby'])) groupby_terms, orderby_terms = self._read_group_prepare(order, aggregated_fields, annotated_groupbys, query) from_clause, where_clause, where_clause_params = query.get_sql() if lazy and (len(groupby_fields) >= 2 or not self._context.get('group_by_no_leaf')): count_field = groupby_fields[0] if len(groupby_fields) >= 1 else '_' else: count_field = '_' count_field += '_count' prefix_terms = lambda prefix, terms: (prefix + " " + ",".join(terms)) if terms else '' prefix_term = lambda prefix, term: ('%s %s' % (prefix, term)) if term else '' query = """ SELECT min("%(table)s".id) AS id, count("%(table)s".id) AS "%(count_field)s" %(extra_fields)s FROM %(from)s %(where)s %(groupby)s %(orderby)s %(limit)s %(offset)s """ % { 'table': self._table, 'count_field': count_field, 'extra_fields': prefix_terms(',', select_terms), 'from': from_clause, 'where': prefix_term('WHERE', where_clause), 'groupby': prefix_terms('GROUP BY', groupby_terms), 'orderby': prefix_terms('ORDER BY', orderby_terms), 'limit': prefix_term('LIMIT', int(limit) if limit else None), 'offset': prefix_term('OFFSET', int(offset) if limit else None), } self._cr.execute(query, where_clause_params) fetched_data = self._cr.dictfetchall() if not groupby_fields: return fetched_data self._read_group_resolve_many2one_fields(fetched_data, annotated_groupbys) data = ({k: self._read_group_prepare_data(k,v, groupby_dict) for k,v in r.items()} for r in fetched_data) result = [self._read_group_format_result(d, annotated_groupbys, groupby, domain) for d in data] if lazy: result = self._read_group_fill_results( domain, groupby_fields[0], groupby[len(annotated_groupbys):], aggregated_fields, count_field, result, read_group_order=order, ) return result models.BaseModel._read_group_process_groupby = ks_time_addition models.BaseModel._read_group_raw = ks_read_group_raw class KsDashboardNinjaItems(models.Model): _name = 'ks_dashboard_ninja.item' _description = 'Dashboard Ninja items' name = fields.Char(string="Name", size=256) ks_model_id = fields.Many2one('ir.model', string='Model', required=True, domain="[('access_ids','!=',False),('transient','=',False)," "('model','not ilike','base_import%'),'|',('model','not ilike','ir.%'),('model','=ilike','_%ir.%')," "('model','not ilike','web_editor.%'),('model','not ilike','web_tour.%')," "('model','!=','mail.thread'),('model','not ilike','ks_dash%')]") ks_domain = fields.Char(string="Domain") ks_model_id_2 = fields.Many2one('ir.model', string='Kpi Model', domain="[('access_ids','!=',False),('transient','=',False)," "('model','not ilike','base_import%'),'|',('model','not ilike','ir.%'),('model','=ilike','_%ir.%')," "('model','not ilike','web_editor.%'),('model','not ilike','web_tour.%')," "('model','!=','mail.thread'),('model','not ilike','ks_dash%')]") ks_model_name_2 = fields.Char(related='ks_model_id_2.model', readonly=True) ks_record_field_2 = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id_2),('name','!=','id'),('name','!=','sequence'),('store','='," "True),'|','|',('ttype','=','integer'),('ttype','=','float'),('ttype'," "'=','monetary')]", string="Record Field") ks_record_count_type_2 = fields.Selection([('count', 'Count'), ('sum', 'Sum'), ('average', 'Average')], string="Record Type", default="count") ks_domain_2_temp = fields.Char(string="KPI Domain Substitute") ks_domain_temp = fields.Char(string="Domain Substitute") ks_background_color = fields.Char(default="#337ab7,0.99", string="Background Color") ks_icon = fields.Binary(string="Icon", attachment=True) ks_default_icon = fields.Char(string="Icon", default="bar-chart") ks_default_icon_color = fields.Char(default="#ffffff,0.99", string="Icon Color") ks_icon_select = fields.Char(string="Icon Option", default="Default") ks_font_color = fields.Char(default="#ffffff,0.99", string="Font Color") ks_dashboard_item_theme = fields.Char(default="white", string="Theme") ks_layout = fields.Selection([('layout1', 'Layout 1'), ('layout2', 'Layout 2'), ('layout3', 'Layout 3'), ('layout4', 'Layout 4'), ('layout5', 'Layout 5'), ('layout6', 'Layout 6'), ], default=('layout1'), required=True, string="Layout") ks_preview = fields.Integer(default=1, string="Preview") ks_model_name = fields.Char(related='ks_model_id.model', readonly=True) ks_many2many_field_ordering = fields.Char() ks_record_count_type = fields.Selection([('count', 'Count'), ('sum', 'Sum'), ('average', 'Average')], string="Record Count Type", default="count") ks_record_count = fields.Float(string="Record Count", compute='ks_get_record_count', readonly=True) ks_record_field = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," "'|','|',('ttype','=','integer'),('ttype','=','float'),('ttype','='," "'monetary')]", string="Record Field") ks_date_filter_selection = fields.Selection([ ('l_none', 'None'), ('l_day', 'Today'), ('t_week', 'This Week'), ('t_month', 'This Month'), ('t_quarter', 'This Quarter'), ('t_year', 'This Year'), ('n_day', 'Next Day'), ('n_week', 'Next Week'), ('n_month', 'Next Month'), ('n_quarter', 'Next Quarter'), ('n_year', 'Next Year'), ('ls_day', 'Last Day'), ('ls_week', 'Last Week'), ('ls_month', 'Last Month'), ('ls_quarter', 'Last Quarter'), ('ls_year', 'Last Year'), ('l_week', 'Last 7 days'), ('l_month', 'Last 30 days'), ('l_quarter', 'Last 90 days'), ('l_year', 'Last 365 days'), ('ls_past_until_now', 'Past Till Now'), ('ls_pastwithout_now', ' Past Excluding Today'), ('n_future_starting_now', 'Future Starting Now'), ('n_futurestarting_tomorrow', 'Future Starting Tomorrow'), ('l_custom', 'Custom Filter'), ], string="Date Filter Selection", default="l_none", required=True) ks_date_filter_field = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('store','=',True),'|',('ttype','=','date')," "('ttype','=','datetime')]", string="Date Filter Field") ks_item_start_date = fields.Datetime(string="Start Date") ks_item_end_date = fields.Datetime(string="End Date") ks_date_filter_field_2 = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id_2),('store','=',True),'|',('ttype','=','date')," "('ttype','=','datetime')]", string="Date Filter Field") ks_item_start_date_2 = fields.Datetime(string="Start Date") ks_item_end_date_2 = fields.Datetime(string="End Date") ks_domain_2 = fields.Char(string="Domain") ks_date_filter_selection_2 = fields.Selection([ ('l_none', "None"), ('l_day', 'Today'), ('t_week', 'This Week'), ('t_month', 'This Month'), ('t_quarter', 'This Quarter'), ('t_year', 'This Year'), ('n_day', 'Next Day'), ('n_week', 'Next Week'), ('n_month', 'Next Month'), ('n_quarter', 'Next Quarter'), ('n_year', 'Next Year'), ('ls_day', 'Last Day'), ('ls_week', 'Last Week'), ('ls_month', 'Last Month'), ('ls_quarter', 'Last Quarter'), ('ls_year', 'Last Year'), ('l_week', 'Last 7 days'), ('l_month', 'Last 30 days'), ('l_quarter', 'Last 90 days'), ('l_year', 'Last 365 days'), ('ls_past_until_now', 'Past Till Now'), ('ls_pastwithout_now', ' Past Excluding Today'), ('n_future_starting_now', 'Future Starting Now'), ('n_futurestarting_tomorrow', 'Future Starting Tomorrow'), ('l_custom', 'Custom Filter'), ], string="Date Filter Selection", required=True, default='l_none') ks_previous_period = fields.Boolean(string="Previous Period") # Pro Fields ks_dashboard_ninja_board_id = fields.Many2one('ks_dashboard_ninja.board', default=lambda self: self._context[ 'ks_dashboard_id'] if 'ks_dashboard_id' in self._context else False) # Chart related fields ks_dashboard_item_type = fields.Selection([('ks_tile', 'Tile'), ('ks_bar_chart', 'Bar Chart'), ('ks_horizontalBar_chart', 'Horizontal Bar Chart'), ('ks_line_chart', 'Line Chart'), ('ks_area_chart', 'Area Chart'), ('ks_pie_chart', 'Pie Chart'), ('ks_doughnut_chart', 'Doughnut Chart'), ('ks_polarArea_chart', 'Polar Area Chart'), ('ks_list_view', 'List View'), ('ks_kpi', 'KPI'), ], default=lambda self: self._context.get('ks_dashboard_item_type', 'ks_tile'), required=True, string="Dashboard Item Type") ks_chart_groupby_type = fields.Char(compute='get_chart_groupby_type') ks_chart_relation_groupby = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," "('ttype','!=','binary'),('ttype','!=','many2many'), ('ttype','!=','one2many')]", string="Group By") ks_chart_relation_sub_groupby = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," "('ttype','!=','binary'),('ttype','!=','many2many'), ('ttype','!=','one2many')]", string=" Sub Group By") ks_chart_date_sub_groupby = fields.Selection([('minute', 'Minute'), ('hour', 'Hour'), ('day', 'Day'), ('week', 'Week'), ('month', 'Month'), ('quarter', 'Quarter'), ('year', 'Year'), ], string="Sub Group By Date") ks_chart_date_groupby = fields.Selection([('minute', 'Minute'), ('hour', 'Hour'), ('day', 'Day'), ('week', 'Week'), ('month', 'Month'), ('quarter', 'Quarter'), ('year', 'Year'), ('month_year', 'Month-Year'), ], string=" Group By Date") ks_graph_preview = fields.Char(string="Preview", default="Graph Preview") ks_chart_data = fields.Char(string="Chart Data in string form", compute='ks_get_chart_data') ks_chart_data_count_type = fields.Selection([('count', 'Count'), ('sum', 'Sum'), ('average', 'Average')], string="Data Type", default="sum") ks_chart_sub_groupby_type = fields.Char(compute='get_chart_sub_groupby_type') ks_chart_measure_field = fields.Many2many('ir.model.fields', 'ks_dn_measure_field_rel', 'measure_field_id', 'field_id', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','='," "True),'|','|', " "('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", string="Measures") ks_chart_measure_field_2 = fields.Many2many('ir.model.fields', 'ks_dn_measure_field_rel_2', 'measure_field_id_2', 'field_id', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store'," "'=',True),'|','|', " "('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", string="Line Measure") ks_bar_chart_stacked = fields.Boolean(string="Stacked Bar Chart") ks_sort_by_field = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," "('ttype','!=','one2many'),('ttype','!=','binary')]", string="Sort By Field") ks_sort_by_order = fields.Selection([('ASC', 'Ascending'), ('DESC', 'Descending')], string="Sort Order") ks_record_data_limit = fields.Integer(string="Record Limit") ks_list_view_preview = fields.Char(string="List View Preview", default="List View Preview") ks_kpi_preview = fields.Char(string="Preview", default="KPI Preview") ks_kpi_type = fields.Selection([ ('layout_1', 'KPI With Target'), ('layout_2', 'Data Comparison'), ], string="Layout", default="layout_1") ks_target_view = fields.Char(string="View", default="Number") ks_data_comparison = fields.Char(string="Data Type", default="None") ks_kpi_data = fields.Char(string="KPI Data", compute="ks_get_kpi_data") ks_chart_item_color = fields.Selection( [('default', 'Default'), ('cool', 'Cool'), ('warm', 'Warm'), ('neon', 'Neon')], string="Chart Color Palette", default="default") # ------------------------ List View Fields ------------------------------ ks_list_view_type = fields.Selection([('ungrouped', 'Un-Grouped'), ('grouped', 'Grouped')], default="ungrouped", string="List View Type", required=True) ks_list_view_fields = fields.Many2many('ir.model.fields', 'ks_dn_list_field_rel', 'list_field_id', 'field_id', domain="[('model_id','=',ks_model_id),('store','=',True)," "('ttype','!=','one2many'),('ttype','!=','many2many'),('ttype'," "'!=','binary')]", string="Fields to show in list") ks_list_view_group_fields = fields.Many2many('ir.model.fields', 'ks_dn_list_group_field_rel', 'list_field_id', 'field_id', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store'," "'=',True),'|','|', " "('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", string="List View Grouped Fields") ks_list_view_data = fields.Char(string="List View Data in JSon", compute='ks_get_list_view_data') # -------------------- Multi Company Feature --------------------- ks_company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id) ks_semi_circle_chart = fields.Boolean(string='Semi Circle Chart') # -------------------- Target Company Feature --------------------- ks_goal_enable = fields.Boolean(string="Enable Target") ks_goal_bar_line = fields.Boolean(string="Show Target As Line") ks_standard_goal_value = fields.Float(string="Standard Target") ks_goal_lines = fields.One2many('ks_dashboard_ninja.item_goal', 'ks_dashboard_item', string="Target Lines") ks_list_target_deviation_field = fields.Many2one('ir.model.fields', 'list_field_id', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," "('store','=',True),'|','|'," "('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", ) ks_compare_period = fields.Integer(string="Include Period") ks_year_period = fields.Integer(string="Same Period Previous Years") ks_compare_period_2 = fields.Integer(string="KPI Include Period") ks_year_period_2 = fields.Integer(string="KPI Same Period Previous Years") # ------------------------------------ Chart display props. TODO : Merge all these fields into one and show a widget to get output for these fields from JS ks_show_data_value = fields.Boolean(string="Show Data Value") ks_action_lines = fields.One2many('ks_dashboard_ninja.item_action', 'ks_dashboard_item_id', string="Action Lines") ks_actions = fields.Many2one('ir.actions.act_window', domain="[('res_model','=',ks_model_name)]", string="Actions") ks_record_count_2 = fields.Float(string="KPI Record Count", readonly=True) # Adding refresh per item override global update interval ks_update_items_data = fields.Selection([ (15000, '15 Seconds'), (30000, '30 Seconds'), (45000, '45 Seconds'), (60000, '1 minute'), (120000, '2 minute'), (300000, '5 minute'), (600000, '10 minute'), ], string="Set Update Interval", default=lambda self: self._context.get('ks_set_interval', False)) @api.multi def copy_data(self, default=None): if default is None: default = {} if 'ks_action_lines' not in default: default['ks_action_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_action_lines] if 'ks_goal_lines' not in default: default['ks_goal_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_goal_lines] return super(KsDashboardNinjaItems, self).copy_data(default) @api.model def create(self, values): """ Override to save list view fields ordering """ if values.get('ks_list_view_fields', False) and values.get('ks_list_view_group_fields', False): ks_many2many_field_ordering = { 'ks_list_view_fields': values['ks_list_view_fields'][0][2], 'ks_list_view_group_fields': values['ks_list_view_group_fields'][0][2], } values['ks_many2many_field_ordering'] = json.dumps(ks_many2many_field_ordering) return super(KsDashboardNinjaItems, self).create( values) # User can select custom units for measure ks_unit = fields.Boolean(string="Show Custom Unit", default=False) ks_unit_selection = fields.Selection([ ('monetary', 'Monetary'), ('custom', 'Custom'), ], string="Select Unit Type") ks_chart_unit = fields.Char(string="Enter Unit", size=5, default="", help="Maximum limit 5 characters, for ex: km, m") # User can stop propagation of the tile item ks_show_records = fields.Boolean(string="Show Records", default=True, help="""This field Enable the click on Dashboard Items to view the Flectra default view of records""") # Domain Extension field ks_domain_extension = fields.Char('Domain Extension') ks_domain_extension_2 = fields.Char('KPI Domain Extension') # hide legend ks_hide_legend = fields.Boolean('Show Legend', help="Hide all legend from the chart item", default=True) @api.multi def copy_data(self, default=None): if default is None: default = {} if 'ks_action_lines' not in default: default['ks_action_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_action_lines] if 'ks_goal_lines' not in default: default['ks_goal_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_goal_lines] return super(KsDashboardNinjaItems, self).copy_data(default) @api.model def create(self, values): """ Override to save list view fields ordering """ if values.get('ks_list_view_fields', False) and values.get('ks_list_view_group_fields', False): ks_many2many_field_ordering = { 'ks_list_view_fields': values['ks_list_view_fields'][0][2], 'ks_list_view_group_fields': values['ks_list_view_group_fields'][0][2], } values['ks_many2many_field_ordering'] = json.dumps(ks_many2many_field_ordering) return super(KsDashboardNinjaItems, self).create( values) @api.multi def write(self, values): for rec in self: if rec['ks_many2many_field_ordering']: ks_many2many_field_ordering = json.loads(rec['ks_many2many_field_ordering']) else: ks_many2many_field_ordering = {} if values.get('ks_list_view_fields', False): ks_many2many_field_ordering['ks_list_view_fields'] = values['ks_list_view_fields'][0][2] if values.get('ks_list_view_group_fields', False): ks_many2many_field_ordering['ks_list_view_group_fields'] = values['ks_list_view_group_fields'][0][2] values['ks_many2many_field_ordering'] = json.dumps(ks_many2many_field_ordering) return super(KsDashboardNinjaItems, self).write( values) @api.multi def write(self, values): for rec in self: if rec['ks_many2many_field_ordering']: ks_many2many_field_ordering = json.loads(rec['ks_many2many_field_ordering']) else: ks_many2many_field_ordering = {} if values.get('ks_list_view_fields', False): ks_many2many_field_ordering['ks_list_view_fields'] = values['ks_list_view_fields'][0][2] if values.get('ks_list_view_group_fields', False): ks_many2many_field_ordering['ks_list_view_group_fields'] = values['ks_list_view_group_fields'][0][2] values['ks_many2many_field_ordering'] = json.dumps(ks_many2many_field_ordering) return super(KsDashboardNinjaItems, self).write( values) @api.multi @api.onchange('ks_goal_lines') def ks_date_target_line(self): for rec in self: if rec.ks_chart_date_groupby in ('minute', 'hour') or rec.ks_chart_date_sub_groupby in ('minute', 'hour'): rec.ks_goal_lines = False return {'warning': { 'title': _('Groupby Field aggregation'), 'message': _('Cannot create target lines when Group By Date field is set to have aggregation in ' 'Minute and Hour case.') }} @api.multi @api.onchange('ks_chart_date_groupby', 'ks_chart_date_sub_groupby') def ks_date_target(self): for rec in self: if (rec.ks_chart_date_groupby in ('minute', 'hour') or rec.ks_chart_date_sub_groupby in ('minute', 'hour')) \ and rec.ks_goal_enable and rec.ks_goal_lines: raise ValidationError(_("Cannot set aggregation having Date time (Hour, Minute) when target lines are " "being used. " " To proceed this, first delete target lines")) @api.multi def name_get(self): res = [] for rec in self: name = rec.name if not name: name = rec.ks_model_id.name res.append((rec.id, name)) return res @api.onchange('ks_layout') def layout_four_font_change(self): if self.ks_dashboard_item_theme != "white": if self.ks_layout == 'layout4': self.ks_font_color = self.ks_background_color self.ks_default_icon_color = "#ffffff,0.99" elif self.ks_layout == 'layout6': self.ks_font_color = "#ffffff,0.99" self.ks_default_icon_color = self.ks_get_dark_color(self.ks_background_color.split(',')[0], self.ks_background_color.split(',')[1]) else: self.ks_default_icon_color = "#ffffff,0.99" self.ks_font_color = "#ffffff,0.99" else: if self.ks_layout == 'layout4': self.ks_background_color = "#00000,0.99" self.ks_font_color = self.ks_background_color self.ks_default_icon_color = "#ffffff,0.99" else: self.ks_background_color = "#ffffff,0.99" self.ks_font_color = "#00000,0.99" self.ks_default_icon_color = "#00000,0.99" # To convert color into 10% darker. Percentage amount is hardcoded. Change amt if want to change percentage. def ks_get_dark_color(self, color, opacity): num = int(color[1:], 16) amt = -25 R = (num >> 16) + amt R = (255 if R > 255 else 0 if R < 0 else R) * 0x10000 G = (num >> 8 & 0x00FF) + amt G = (255 if G > 255 else 0 if G < 0 else G) * 0x100 B = (num & 0x0000FF) + amt B = (255 if B > 255 else 0 if B < 0 else B) return "#" + hex(0x1000000 + R + G + B).split('x')[1][1:] + "," + opacity @api.onchange('ks_model_id') def make_record_field_empty(self): for rec in self: rec.ks_record_field = False rec.ks_domain = False rec.ks_date_filter_field = False # To show "created on" by default on date filter field on model select. if rec.ks_model_id: datetime_field_list = rec.ks_date_filter_field.search( [('model_id', '=', rec.ks_model_id.id), '|', ('ttype', '=', 'date'), ('ttype', '=', 'datetime')]).read(['id', 'name']) for field in datetime_field_list: if field['name'] == 'create_date': rec.ks_date_filter_field = field['id'] else: rec.ks_date_filter_field = False # Pro rec.ks_record_field = False rec.ks_chart_measure_field = False rec.ks_chart_measure_field_2 = False rec.ks_chart_relation_sub_groupby = False rec.ks_chart_relation_groupby = False rec.ks_chart_date_sub_groupby = False rec.ks_chart_date_groupby = False rec.ks_sort_by_field = False rec.ks_sort_by_order = False rec.ks_record_data_limit = False rec.ks_list_view_fields = False rec.ks_list_view_group_fields = False rec.ks_action_lines = False rec.ks_actions = False rec.ks_domain_extension = False @api.onchange('ks_record_count', 'ks_layout', 'name', 'ks_model_id', 'ks_domain', 'ks_icon_select', 'ks_default_icon', 'ks_icon', 'ks_background_color', 'ks_font_color', 'ks_default_icon_color') def ks_preview_update(self): self.ks_preview += 1 @api.onchange('ks_dashboard_item_theme') def change_dashboard_item_theme(self): if self.ks_dashboard_item_theme == "red": self.ks_background_color = "#d9534f,0.99" self.ks_default_icon_color = "#ffffff,0.99" self.ks_font_color = "#ffffff,0.99" elif self.ks_dashboard_item_theme == "blue": self.ks_background_color = "#337ab7,0.99" self.ks_default_icon_color = "#ffffff,0.99" self.ks_font_color = "#ffffff,0.99" elif self.ks_dashboard_item_theme == "yellow": self.ks_background_color = "#f0ad4e,0.99" self.ks_default_icon_color = "#ffffff,0.99" self.ks_font_color = "#ffffff,0.99" elif self.ks_dashboard_item_theme == "green": self.ks_background_color = "#5cb85c,0.99" self.ks_default_icon_color = "#ffffff,0.99" self.ks_font_color = "#ffffff,0.99" elif self.ks_dashboard_item_theme == "white": if self.ks_layout == 'layout4': self.ks_background_color = "#00000,0.99" self.ks_default_icon_color = "#ffffff,0.99" else: self.ks_background_color = "#ffffff,0.99" self.ks_default_icon_color = "#000000,0.99" self.ks_font_color = "#000000,0.99" if self.ks_layout == 'layout4': self.ks_font_color = self.ks_background_color elif self.ks_layout == 'layout6': self.ks_default_icon_color = self.ks_get_dark_color(self.ks_background_color.split(',')[0], self.ks_background_color.split(',')[1]) if self.ks_dashboard_item_theme == "white": self.ks_default_icon_color = "#000000,0.99" @api.multi @api.depends('ks_record_count_type', 'ks_model_id', 'ks_domain', 'ks_record_field', 'ks_date_filter_field', 'ks_item_end_date', 'ks_item_start_date', 'ks_compare_period', 'ks_year_period', 'ks_dashboard_item_type', 'ks_domain_extension', 'ks_record_data_limit') def ks_get_record_count(self): for rec in self: if rec.ks_record_count_type == 'count' or rec.ks_dashboard_item_type == 'ks_list_view': rec.ks_record_count = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'search_count', rec) elif rec.ks_record_count_type in ['sum', 'average'] and \ rec.ks_record_field and rec.ks_dashboard_item_type != 'ks_list_view': ks_records_grouped_data = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'read_group', rec) if ks_records_grouped_data and len(ks_records_grouped_data) > 0: ks_records_grouped_data = ks_records_grouped_data[0] if rec.ks_record_count_type == 'sum' and ks_records_grouped_data.get('__count', False) and ( ks_records_grouped_data.get(rec.ks_record_field.name)): rec.ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, 0) elif rec.ks_record_count_type == 'average' and ks_records_grouped_data.get( '__count', False) and (ks_records_grouped_data.get(rec.ks_record_field.name)): rec.ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, 0) / ks_records_grouped_data.get('__count', 1) else: rec.ks_record_count = 0 else: rec.ks_record_count = 0 else: rec.ks_record_count = 0 # Writing separate function to fetch dashboard item data def ks_fetch_model_data(self, ks_model_name, ks_domain, ks_func, rec): data = 0 try: if ks_domain and ks_domain != '[]' and ks_model_name: proper_domain = self.ks_convert_into_proper_domain(ks_domain, rec) if ks_func == 'search_count': if rec.ks_dashboard_item_type == "ks_list_view" and rec.ks_record_data_limit: data = self.env[ks_model_name].search_count(proper_domain, limit=rec.ks_record_data_limit) else: data = self.env[ks_model_name].search_count(proper_domain) elif ks_func == 'read_group': data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], []) elif ks_model_name: # Have to put extra if condition here because on load,model giving False value proper_domain = self.ks_convert_into_proper_domain(False, rec) if ks_func == 'search_count': if rec.ks_dashboard_item_type == "ks_list_view" and rec.ks_record_data_limit: data = self.env[ks_model_name].search_count(proper_domain, limit=rec.ks_record_data_limit) else: data = self.env[ks_model_name].search_count(proper_domain) elif ks_func == 'read_group': data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], []) else: return [] except Exception as e: return [] return data def ks_convert_into_proper_domain(self, ks_domain, rec): if ks_domain and "%UID" in ks_domain: ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) if ks_domain and "%MYCOMPANY" in ks_domain: ks_domain = ks_domain.replace('"%MYCOMPANY"', str(self.env.user.company_id.id)) ks_date_domain = False if rec.ks_date_filter_field: if not rec.ks_date_filter_selection or rec.ks_date_filter_selection == "l_none": selected_start_date = self._context.get('ksDateFilterStartDate', False) selected_end_date = self._context.get('ksDateFilterEndDate', False) if selected_end_date and not selected_start_date: ks_date_domain = [ (rec.ks_date_filter_field.name, "<=", selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] elif selected_start_date and not selected_end_date: ks_date_domain = [ (rec.ks_date_filter_field.name, ">=", selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] else: if selected_end_date and selected_start_date: ks_date_domain = [ (rec.ks_date_filter_field.name, ">=", selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), (rec.ks_date_filter_field.name, "<=", selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] else: if rec.ks_date_filter_selection and rec.ks_date_filter_selection != 'l_custom': ks_date_data = ks_get_date(rec.ks_date_filter_selection, self) selected_start_date = ks_date_data["selected_start_date"] selected_end_date = ks_date_data["selected_end_date"] else: selected_start_date = rec.ks_item_start_date selected_end_date = rec.ks_item_end_date if selected_start_date and selected_end_date: if rec.ks_compare_period: selected_start_date = fields.datetime.strptime(rec.ks_item_start_date, DEFAULT_SERVER_DATETIME_FORMAT) selected_end_date = fields.datetime.strptime(rec.ks_item_end_date, DEFAULT_SERVER_DATETIME_FORMAT) ks_compare_period = abs(rec.ks_compare_period) if ks_compare_period > 100: ks_compare_period = 100 if rec.ks_compare_period > 0: selected_end_date = selected_end_date + ( selected_end_date - selected_start_date) * ks_compare_period elif rec.ks_compare_period < 0: selected_start_date = selected_start_date - ( selected_end_date - selected_start_date) * ks_compare_period if rec.ks_year_period and rec.ks_year_period != 0 and rec.ks_dashboard_item_type: abs_year_period = abs(rec.ks_year_period) sign_yp = rec.ks_year_period / abs_year_period if abs_year_period > 100: abs_year_period = 100 date_field_name = rec.ks_date_filter_field.name ks_date_domain = ['&', (date_field_name, ">=", fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT)), (date_field_name, "<=", fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT))] for p in range(1, abs_year_period + 1): ks_date_domain.insert(0, '|') ks_date_domain.extend(['&', (date_field_name, ">=", fields.datetime.strftime( selected_start_date - relativedelta.relativedelta(years=p) * sign_yp, DEFAULT_SERVER_DATETIME_FORMAT)), (date_field_name, "<=", fields.datetime.strftime( selected_end_date - relativedelta.relativedelta(years=p) * sign_yp, DEFAULT_SERVER_DATETIME_FORMAT))]) else: selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) if \ type(selected_start_date).__name__ == 'datetime' else selected_start_date selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) \ if type(selected_end_date).__name__ == 'datetime' else selected_end_date ks_date_domain = [(rec.ks_date_filter_field.name, ">=", selected_start_date), (rec.ks_date_filter_field.name, "<=", selected_end_date)] elif selected_start_date and not selected_end_date: selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) \ if type(selected_start_date).__name__ == 'datetime' else selected_start_date ks_date_domain = [(rec.ks_date_filter_field.name, ">=", selected_start_date)] elif selected_end_date and not selected_start_date: selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) \ if type(selected_end_date).__name__ == 'datetime' else selected_end_date ks_date_domain = [(rec.ks_date_filter_field.name, "<=", selected_end_date)] else: ks_date_domain = [] proper_domain = safe_eval(ks_domain) if ks_domain else [] if ks_date_domain: proper_domain.extend(ks_date_domain) if rec.ks_domain_extension: ks_domain_extension = rec.ks_convert_domain_extension(rec.ks_domain_extension, rec) proper_domain.extend(ks_domain_extension) return proper_domain def ks_convert_domain_extension(self, ks_extensiom_domain, rec): if ks_extensiom_domain and "%UID" in ks_extensiom_domain: ks_extensiom_domain = ks_extensiom_domain.replace("%UID", str(self.env.user.id)) if ks_extensiom_domain and "%MYCOMPANY" in ks_extensiom_domain: ks_extensiom_domain = ks_extensiom_domain.replace("%MYCOMPANY", str(self.env.user.company_id.id)) ks_domain = safe_eval(ks_extensiom_domain) return ks_domain @api.onchange('ks_domain_extension') def ks_onchange_domain_extension(self): if self.ks_domain_extension: proper_domain = [] try: ks_domain_extension = self.ks_domain_extension if "%UID" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) if "%MYCOMPANY" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%MYCOMPANY", str(self.env.user.company_id.id)) self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) except Exception: raise ValidationError( "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," "'']]") @api.constrains('ks_domain_extension') def ks_check_domain_extension(self): if self.ks_domain_extension: proper_domain = [] try: ks_domain_extension = self.ks_domain_extension if "%UID" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) if "%MYCOMPANY" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%MYCOMPANY", str(self.env.user.company_id.id)) self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) except Exception: raise ValidationError( "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," "'']]") @api.onchange('ks_domain_extension_2') def ks_onchange_domain_extension_2(self): if self.ks_domain_extension_2: proper_domain = [] try: ks_domain_extension = self.ks_domain_extension_2 if "%UID" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) if "%MYCOMPANY" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%MYCOMPANY", str(self.env.user.company_id.id)) self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) except Exception: raise ValidationError( "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," "'']]") @api.constrains('ks_domain_extension_2') def ks_check_domain_extension_2(self): if self.ks_domain_extension: proper_domain = [] try: ks_domain_extension = self.ks_domain_extension if "%UID" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) if "%MYCOMPANY" in ks_domain_extension: ks_domain_extension = ks_domain_extension.replace("%MYCOMPANY", str(self.env.user.company_id.id)) self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) except Exception: raise ValidationError( "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," "'']]") @api.onchange('ks_list_view_fields') def ks_set_list_view_fields_order(self): for rec in self: order = [res.id for res in rec.ks_list_view_fields] if rec.ks_many2many_field_ordering: ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) else: ks_many2many_field_ordering = {} ks_many2many_field_ordering['ks_list_view_fields'] = order rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) @api.onchange('ks_list_view_group_fields') def ks_set_list_view_group_fields_order(self): for rec in self: order = [res.id for res in rec.ks_list_view_group_fields] if rec.ks_many2many_field_ordering: ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) else: ks_many2many_field_ordering = {} ks_many2many_field_ordering['ks_list_view_group_fields'] = order rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) @api.multi @api.onchange('ks_chart_relation_groupby') def get_chart_groupby_type(self): for rec in self: if rec.ks_chart_relation_groupby.ttype == 'datetime' or rec.ks_chart_relation_groupby.ttype == 'date': rec.ks_chart_groupby_type = 'date_type' elif rec.ks_chart_relation_groupby.ttype == 'many2one': rec.ks_chart_groupby_type = 'relational_type' rec.ks_chart_date_groupby = False elif rec.ks_chart_relation_groupby.ttype == 'selection': rec.ks_chart_groupby_type = 'selection' rec.ks_chart_date_groupby = False else: rec.ks_chart_groupby_type = 'other' @api.onchange('ks_chart_relation_groupby') def ks_empty_sub_group_by(self): for rec in self: if not rec.ks_chart_relation_groupby or rec.ks_chart_groupby_type == "date_type" \ and not rec.ks_chart_date_groupby: rec.ks_chart_relation_sub_groupby = False rec.ks_chart_date_sub_groupby = False @api.depends('ks_chart_relation_sub_groupby') def get_chart_sub_groupby_type(self): for rec in self: if rec.ks_chart_relation_sub_groupby.ttype == 'datetime' or \ rec.ks_chart_relation_sub_groupby.ttype == 'date': rec.ks_chart_sub_groupby_type = 'date_type' elif rec.ks_chart_relation_sub_groupby.ttype == 'many2one': rec.ks_chart_sub_groupby_type = 'relational_type' elif rec.ks_chart_relation_sub_groupby.ttype == 'selection': rec.ks_chart_sub_groupby_type = 'selection' else: rec.ks_chart_sub_groupby_type = 'other' # Using this function just to let js call rpc to load some data later @api.model def ks_chart_load(self): return True @api.multi @api.depends('ks_chart_measure_field', 'ks_chart_relation_groupby', 'ks_chart_date_groupby', 'ks_domain', 'ks_dashboard_item_type', 'ks_model_id', 'ks_sort_by_field', 'ks_sort_by_order', 'ks_record_data_limit', 'ks_chart_data_count_type', 'ks_chart_measure_field_2', 'ks_goal_enable', 'ks_standard_goal_value', 'ks_goal_bar_line', 'ks_chart_relation_sub_groupby', 'ks_chart_date_sub_groupby', 'ks_date_filter_field', 'ks_item_start_date', 'ks_item_end_date', 'ks_compare_period', 'ks_year_period', 'ks_unit', 'ks_unit_selection', 'ks_chart_unit', 'ks_domain_extension') def ks_get_chart_data(self): for rec in self: if rec.ks_dashboard_item_type and rec.ks_dashboard_item_type != 'ks_tile' and \ rec.ks_dashboard_item_type != 'ks_list_view' and rec.ks_model_id and rec.ks_chart_data_count_type: ks_chart_data = {'labels': [], 'datasets': [], 'ks_currency': 0, 'ks_field': "", 'ks_selection': "", 'ks_show_second_y_scale': False, 'domains': [], } ks_chart_measure_field = [] ks_chart_measure_field_with_type = [] ks_chart_measure_field_ids = [] ks_chart_measure_field_2 = [] ks_chart_measure_field_with_type_2 = [] ks_chart_measure_field_2_ids = [] if rec.ks_unit and rec.ks_unit_selection == 'monetary': ks_chart_data['ks_selection'] += rec.ks_unit_selection ks_chart_data['ks_currency'] += rec.env.user.company_id.currency_id.id elif rec.ks_unit and rec.ks_unit_selection == 'custom': ks_chart_data['ks_selection'] += rec.ks_unit_selection if rec.ks_chart_unit: ks_chart_data['ks_field'] += rec.ks_chart_unit # If count chart data type: if rec.ks_chart_data_count_type == "count": rec.ks_chart_measure_field = False rec.ks_chart_measure_field_2 = False ks_chart_measure_field_with_type.append('count:count(id)') ks_chart_data['datasets'].append({'data': [], 'label': "Count"}) else: if rec.ks_dashboard_item_type == 'ks_bar_chart': if rec.ks_chart_measure_field_2: ks_chart_data['ks_show_second_y_scale'] = True for res in rec.ks_chart_measure_field_2: if rec.ks_chart_data_count_type == 'sum': ks_data_count_type = 'sum' elif rec.ks_chart_data_count_type == 'average': ks_data_count_type = 'avg' else: raise ValidationError(_('Please chose any Data Type!')) ks_chart_measure_field_2.append(res.name) ks_chart_measure_field_with_type_2.append(res.name + ':' + ks_data_count_type) ks_chart_measure_field_2_ids.append(res.id) ks_chart_data['datasets'].append( {'data': [], 'label': res.field_description, 'type': 'line', 'yAxisID': 'y-axis-1'}) for res in rec.ks_chart_measure_field: if rec.ks_chart_data_count_type == 'sum': ks_data_count_type = 'sum' elif rec.ks_chart_data_count_type == 'average': ks_data_count_type = 'avg' else: raise ValidationError(_('Please chose any Data Type!')) ks_chart_measure_field_with_type.append(res.name + ':' + ks_data_count_type) ks_chart_measure_field.append(res.name) ks_chart_measure_field_ids.append(res.id) ks_chart_data['datasets'].append({'data': [], 'label': res.field_description}) # ks_chart_measure_field = [res.name for res in rec.ks_chart_measure_field] ks_chart_groupby_relation_field = rec.ks_chart_relation_groupby.name ks_chart_domain = self.ks_convert_into_proper_domain(rec.ks_domain, rec) ks_chart_data['previous_domain'] = ks_chart_domain if rec.ks_chart_data_count_type == "count": orderby = 'count' else: orderby = rec.ks_sort_by_field.name if rec.ks_sort_by_field else "id" if rec.ks_sort_by_order: orderby = orderby + " " + rec.ks_sort_by_order limit = rec.ks_record_data_limit if rec.ks_record_data_limit and rec.ks_record_data_limit > 0 else False if ((rec.ks_chart_data_count_type != "count" and ks_chart_measure_field) or ( rec.ks_chart_data_count_type == "count" and not ks_chart_measure_field)) and \ not rec.ks_chart_relation_sub_groupby: if rec.ks_chart_relation_groupby.ttype == 'date' and rec.ks_chart_date_groupby in ( 'minute', 'hour'): raise ValidationError(_('Groupby field: {} cannot be aggregated by {}').format( rec.ks_chart_relation_groupby.display_name, rec.ks_chart_date_groupby)) ks_chart_date_groupby = 'day' # when date_type doesn't have time else: if rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' else: ks_chart_date_groupby = rec.ks_chart_date_groupby if (rec.ks_chart_groupby_type == 'date_type' and rec.ks_chart_date_groupby) or\ rec.ks_chart_groupby_type != 'date_type': ks_chart_data = rec.ks_fetch_chart_data(rec.ks_model_name, ks_chart_domain, ks_chart_measure_field_with_type, ks_chart_measure_field_with_type_2, ks_chart_measure_field, ks_chart_measure_field_2, ks_chart_groupby_relation_field, ks_chart_date_groupby, rec.ks_chart_groupby_type, orderby, limit, rec.ks_chart_data_count_type, ks_chart_measure_field_ids, ks_chart_measure_field_2_ids, rec.ks_chart_relation_groupby.id, ks_chart_data) if rec.ks_chart_groupby_type == 'date_type' and rec.ks_goal_enable and rec.ks_dashboard_item_type in [ 'ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart'] and rec.ks_chart_groupby_type == "date_type": ks_goal_labels = [] ks_goal_dataset = [] goal_dataset = [] if rec.ks_goal_lines and len(rec.ks_goal_lines) != 0: if rec._context.get('current_id', False): ks_item_id = rec._context['current_id'] else: ks_item_id = rec.id if rec.ks_date_filter_selection == "l_none": selected_start_date = rec._context.get('ksDateFilterStartDate', False) selected_end_date = rec._context.get('ksDateFilterEndDate', False) else: if rec.ks_date_filter_selection == "l_custom": selected_start_date = rec.ks_item_start_date selected_end_date = rec.ks_item_start_date else: ks_date_data = ks_get_date(rec.ks_date_filter_selection, self) selected_start_date = ks_date_data["selected_start_date"] selected_end_date = ks_date_data["selected_end_date"] if selected_start_date and selected_end_date: selected_start_date = selected_start_date.strftime('%Y-%m-%d') selected_end_date = selected_end_date.strftime('%Y-%m-%d') ks_goal_domain = [('ks_dashboard_item', '=', ks_item_id)] if selected_start_date and selected_end_date: ks_goal_domain.extend([('ks_goal_date', '>=', str(selected_start_date).split(" ")[0]), ('ks_goal_date', '<=', str(selected_end_date).split(" ")[0])]) ks_date_data = rec.ks_get_start_end_date(rec.ks_model_name, ks_chart_groupby_relation_field, rec.ks_chart_relation_groupby.ttype, ks_chart_domain, ks_goal_domain) labels = [] if rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' else: ks_chart_date_groupby = rec.ks_chart_date_groupby if ks_date_data['start_date'] and ks_date_data['end_date']: labels = self.generate_timeserise(ks_date_data['start_date'], ks_date_data['end_date'], ks_chart_date_groupby) ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group( ks_goal_domain, ['ks_goal_value', 'ks_goal_date'], ['ks_goal_date' + ":" + ks_chart_date_groupby]) ks_goal_domains = {} for res in ks_goal_records: if res['ks_goal_date' + ":" + ks_chart_date_groupby]: label = res['ks_goal_date' + ":" + ks_chart_date_groupby] ks_goal_labels.append(label) ks_goal_dataset.append(res['ks_goal_value']) ks_goal_domains[label] = res['__domain'] for goal_domain in ks_goal_domains.keys(): ks_goal_doamins = [] for item in ks_goal_domains[goal_domain]: if 'ks_goal_date' in item: domain = list(item) domain[0] = ks_chart_groupby_relation_field domain = tuple(domain) ks_goal_doamins.append(domain) ks_goal_doamins.insert(0, '&') ks_goal_domains[goal_domain] = ks_goal_doamins domains = {} counter = 0 for label in ks_chart_data['labels']: domains[label] = ks_chart_data['domains'][counter] counter += 1 ks_chart_records_dates = ks_chart_data['labels'] + list( set(ks_goal_labels) - set(ks_chart_data['labels'])) ks_chart_records = [] for label in labels: if label in ks_chart_records_dates: ks_chart_records.append(label) ks_chart_data['domains'].clear() datasets = [] for dataset in ks_chart_data['datasets']: datasets.append(dataset['data'].copy()) for dataset in ks_chart_data['datasets']: dataset['data'].clear() for label in ks_chart_records: counterr = 0 domain = domains.get(label, False) if domain: ks_chart_data['domains'].append(domain) else: ks_chart_data['domains'].append(ks_goal_domains.get(label, [])) if label in ks_chart_data['labels']: index = ks_chart_data['labels'].index(label) for dataset in ks_chart_data['datasets']: dataset['data'].append(datasets[counterr][index]) counterr += 1 else: for dataset in ks_chart_data['datasets']: dataset['data'].append(0.00) if label in ks_goal_labels: index = ks_goal_labels.index(label) goal_dataset.append(ks_goal_dataset[index]) else: goal_dataset.append(0.00) ks_chart_data['labels'] = ks_chart_records else: if rec.ks_standard_goal_value: length = len(ks_chart_data['datasets'][0]['data']) for i in range(length): goal_dataset.append(rec.ks_standard_goal_value) ks_goal_datasets = { 'label': 'Target', 'data': goal_dataset, } if rec.ks_goal_bar_line: ks_goal_datasets['type'] = 'line' ks_chart_data['datasets'].insert(0, ks_goal_datasets) else: ks_chart_data['datasets'].append(ks_goal_datasets) elif rec.ks_chart_relation_sub_groupby and ((rec.ks_chart_sub_groupby_type == 'relational_type') or (rec.ks_chart_sub_groupby_type == 'selection') or (rec.ks_chart_sub_groupby_type == 'date_type' and rec.ks_chart_date_sub_groupby) or (rec.ks_chart_sub_groupby_type == 'other')): if rec.ks_chart_relation_sub_groupby.ttype == 'date': if rec.ks_chart_date_sub_groupby in ('minute', 'hour'): raise ValidationError(_('Sub Groupby field: {} cannot be aggregated by {}').format( rec.ks_chart_relation_sub_groupby.display_name, rec.ks_chart_date_sub_groupby)) if rec.ks_chart_date_groupby in ('minute', 'hour'): raise ValidationError(_('Groupby field: {} cannot be aggregated by {}').format( rec.ks_chart_relation_sub_groupby.display_name, rec.ks_chart_date_groupby)) # doesn't have time in date ks_chart_date_sub_groupby = rec.ks_chart_date_sub_groupby ks_chart_date_groupby = rec.ks_chart_date_groupby else: ks_chart_date_sub_groupby = rec.ks_chart_date_sub_groupby if rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' else: ks_chart_date_groupby = rec.ks_chart_date_groupby if len(ks_chart_measure_field) != 0 or rec.ks_chart_data_count_type == 'count': if rec.ks_chart_groupby_type == 'date_type' and ks_chart_date_groupby: ks_chart_group = rec.ks_chart_relation_groupby.name + ":" + ks_chart_date_groupby else: ks_chart_group = rec.ks_chart_relation_groupby.name if rec.ks_chart_sub_groupby_type == 'date_type' and rec.ks_chart_date_sub_groupby: ks_chart_sub_groupby_field = rec.ks_chart_relation_sub_groupby.name + ":" + \ ks_chart_date_sub_groupby else: ks_chart_sub_groupby_field = rec.ks_chart_relation_sub_groupby.name ks_chart_groupby_relation_fields = [ks_chart_group, ks_chart_sub_groupby_field] ks_chart_record = False try: ks_chart_record = self.env[rec.ks_model_name].read_group(ks_chart_domain, list(set(ks_chart_measure_field_with_type + ks_chart_measure_field_with_type_2 + [ks_chart_groupby_relation_field, rec.ks_chart_relation_sub_groupby.name ])), ks_chart_groupby_relation_fields, orderby=orderby, limit=limit, lazy=False) except Exception: ks_chart_record = {} chart_data = [] chart_sub_data = [] for res in ks_chart_record: domain = res.get('__domain', []) if all(measure_field in res for measure_field in ks_chart_measure_field) and all( measure_field in res for measure_field in ks_chart_measure_field_2): if res[ks_chart_groupby_relation_fields[0]] is not False: if rec.ks_chart_groupby_type == 'date_type': # x-axis modification if rec.ks_chart_date_groupby == "day" and rec.ks_chart_date_sub_groupby in [ \ "quarter", "year"]: label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:2]) elif rec.ks_chart_date_groupby in ["minute", "hour"] and rec.ks_chart_date_sub_groupby in \ ["month", "week", "quarter", "year"]: label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:3]) elif rec.ks_chart_date_groupby == 'month_year': label = res[ks_chart_groupby_relation_fields[0]] else: label = res[ks_chart_groupby_relation_fields[0]].split(" ")[0] elif rec.ks_chart_groupby_type == 'selection': selection = res[ks_chart_groupby_relation_fields[0]] label = dict(self.env[rec.ks_model_name].fields_get( allfields=[ks_chart_groupby_relation_fields[0]]) [ks_chart_groupby_relation_fields[0]]['selection'])[selection] elif rec.ks_chart_groupby_type == 'relational_type': label = res[ks_chart_groupby_relation_fields[0]][1] else: label = res[ks_chart_groupby_relation_fields[0]] labels = [] value = [] value_2 = [] labels_2 = [] if rec.ks_chart_data_count_type != 'count': for ress in rec.ks_chart_measure_field: if rec.ks_chart_sub_groupby_type == 'date_type': # Labels Name modification if res[ks_chart_groupby_relation_fields[1]] is not False: labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[ 0] + " " + ress.field_description) else: labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + " " + ress.field_description) elif rec.ks_chart_sub_groupby_type == 'selection': if res[ks_chart_groupby_relation_fields[1]] is not False: selection = res[ks_chart_groupby_relation_fields[1]] labels.append(dict(self.env[rec.ks_model_name].fields_get( allfields=[ks_chart_groupby_relation_fields[1]]) [ks_chart_groupby_relation_fields[1]][ 'selection'])[ selection] + " " + ress.field_description) else: labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) elif rec.ks_chart_sub_groupby_type == 'relational_type': if res[ks_chart_groupby_relation_fields[1]] is not False: labels.append(res[ks_chart_groupby_relation_fields[1]][1] + " " + ress.field_description) else: labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) else: if res[ks_chart_groupby_relation_fields[1]]: labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + "\'s " + ress.field_description) else: labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) value.append(res.get( ress.name) if rec.ks_chart_data_count_type == 'sum' else res.get( ress.name) / res.get('__count')) if rec.ks_chart_measure_field_2 and rec.ks_dashboard_item_type == 'ks_bar_chart': for ress in rec.ks_chart_measure_field_2: if rec.ks_chart_sub_groupby_type == 'date_type': # line in bar chart case if res[ks_chart_groupby_relation_fields[1]] is not False: labels_2.append( res[ks_chart_groupby_relation_fields[1]].split(" ")[0] + " " + ress.field_description) else: labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) elif rec.ks_chart_sub_groupby_type == 'selection': if res[ks_chart_groupby_relation_fields[1]] is not False: selection = res[ks_chart_groupby_relation_fields[1]] labels_2.append(dict(self.env[rec.ks_model_name].fields_get( allfields=[ks_chart_groupby_relation_fields[1]]) [ks_chart_groupby_relation_fields[1]][ 'selection'])[ selection] + " " + ress.field_description) else: labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + '' + ress.field_description) elif rec.ks_chart_sub_groupby_type == 'relational_type': if res[ks_chart_groupby_relation_fields[1]] is not False: labels_2.append( res[ks_chart_groupby_relation_fields[1]][1] + " " + ress.field_description) else: labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) else: if res[ks_chart_groupby_relation_fields[1]] is not False: labels_2.append(str( res[ks_chart_groupby_relation_fields[1]]) + " " + ress.field_description) else: labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + ' ' + ress.field_description) value_2.append(res.get( ress.name) if rec.ks_chart_data_count_type == 'sum' else res.get( ress.name) / res.get('__count')) chart_sub_data.append({ 'value': value_2, 'labels': label, 'series': labels_2, 'domain': domain, }) else: if res[ks_chart_groupby_relation_fields[1]] and rec.ks_chart_sub_groupby_type == \ 'date_type': # Labels labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[0]) elif res[ks_chart_groupby_relation_fields[1]] and rec.ks_chart_sub_groupby_type == 'selection': selection = res[ks_chart_groupby_relation_fields[1]] labels.append(dict(self.env[rec.ks_model_name].fields_get( allfields=[ks_chart_groupby_relation_fields[1]]) [ks_chart_groupby_relation_fields[1]]['selection'])[ selection]) elif res[ks_chart_groupby_relation_fields[1]] and rec.ks_chart_sub_groupby_type == 'relational_type': labels.append(res[ks_chart_groupby_relation_fields[1]][1]) else: labels.append(res[ks_chart_groupby_relation_fields[1]]) value.append(res['__count']) chart_data.append({ 'value': value, 'labels': label, 'series': labels, 'domain': domain, }) xlabels = [] series = [] values = {} domains = {} for data in chart_data: label = data['labels'] serie = data['series'] domain = data['domain'] if (len(xlabels) == 0) or (label not in xlabels): xlabels.append(label) if (label not in domains): domains[label] = domain else: domains[label].insert(0, '|') domains[label] = domains[label] + domain series = series + serie value = data['value'] counter = 0 for seri in serie: if seri not in values: values[seri] = {} if label in values[seri]: values[seri][label] = values[seri][label] + value[counter] else: values[seri][label] = value[counter] counter += 1 final_datasets = [] for serie in series: if serie not in final_datasets: final_datasets.append(serie) ks_data = [] for dataset in final_datasets: ks_dataset = { 'value': [], 'key': dataset } for label in xlabels: ks_dataset['value'].append({ 'domain': domains[label], 'x': label, 'y': values[dataset][label] if label in values[dataset] else 0 }) ks_data.append(ks_dataset) if rec.ks_chart_relation_sub_groupby.name == rec.ks_chart_relation_groupby.name == rec.ks_sort_by_field.name: ks_data = rec.ks_sort_sub_group_by_records(ks_data, rec.ks_chart_groupby_type, rec.ks_chart_date_groupby, rec.ks_sort_by_order, rec.ks_chart_date_sub_groupby) ks_chart_data = { 'labels': [], 'datasets': [], 'domains': [], 'ks_selection': "", 'ks_currency': 0, 'ks_field': "", 'previous_domain': ks_chart_domain } if rec.ks_unit and rec.ks_unit_selection == 'monetary': ks_chart_data['ks_selection'] += rec.ks_unit_selection ks_chart_data['ks_currency'] += rec.env.user.company_id.currency_id.id elif rec.ks_unit and rec.ks_unit_selection == 'custom': ks_chart_data['ks_selection'] += rec.ks_unit_selection if rec.ks_chart_unit: ks_chart_data['ks_field'] += rec.ks_chart_unit if len(ks_data) != 0: for res in ks_data[0]['value']: ks_chart_data['labels'].append(res['x']) ks_chart_data['domains'].append(res['domain']) if rec.ks_chart_measure_field_2 and rec.ks_dashboard_item_type == 'ks_bar_chart': ks_chart_data['ks_show_second_y_scale'] = True values_2 = {} series_2 = [] for data in chart_sub_data: label = data['labels'] serie = data['series'] series_2 = series_2 + serie value = data['value'] counter = 0 for seri in serie: if seri not in values_2: values_2[seri] = {} if label in values_2[seri]: values_2[seri][label] = values_2[seri][label] + value[counter] else: values_2[seri][label] = value[counter] counter += 1 final_datasets_2 = [] for serie in series_2: if serie not in final_datasets_2: final_datasets_2.append(serie) ks_data_2 = [] for dataset in final_datasets_2: ks_dataset = { 'value': [], 'key': dataset } for label in xlabels: ks_dataset['value'].append({ 'x': label, 'y': values_2[dataset][label] if label in values_2[dataset] else 0 }) ks_data_2.append(ks_dataset) for ks_dat in ks_data_2: dataset = { 'label': ks_dat['key'], 'data': [], 'type': 'line', 'yAxisID': 'y-axis-1', } for res in ks_dat['value']: dataset['data'].append(res['y']) ks_chart_data['datasets'].append(dataset) for ks_dat in ks_data: dataset = { 'label': ks_dat['key'], 'data': [] } for res in ks_dat['value']: dataset['data'].append(res['y']) ks_chart_data['datasets'].append(dataset) if rec.ks_goal_enable and rec.ks_standard_goal_value and rec.ks_dashboard_item_type in [ 'ks_bar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_horizontalBar_chart']: goal_dataset = [] length = len(ks_chart_data['datasets'][0]['data']) for i in range(length): goal_dataset.append(rec.ks_standard_goal_value) ks_goal_datasets = { 'label': 'Target', 'data': goal_dataset, } if rec.ks_goal_bar_line and rec.ks_dashboard_item_type != 'ks_horizontalBar_chart': ks_goal_datasets['type'] = 'line' ks_chart_data['datasets'].insert(0, ks_goal_datasets) else: ks_chart_data['datasets'].append(ks_goal_datasets) else: ks_chart_data = False rec.ks_chart_data = json.dumps(ks_chart_data) elif not rec.ks_dashboard_item_type or rec.ks_dashboard_item_type == 'ks_tile': rec.ks_chart_measure_field = False rec.ks_chart_measure_field_2 = False rec.ks_chart_relation_groupby = False @api.multi @api.depends('ks_domain', 'ks_dashboard_item_type', 'ks_model_id', 'ks_sort_by_field', 'ks_sort_by_order', 'ks_record_data_limit', 'ks_list_view_fields', 'ks_list_view_type', 'ks_list_view_group_fields', 'ks_chart_groupby_type', 'ks_chart_date_groupby', 'ks_date_filter_field', 'ks_item_end_date', 'ks_item_start_date', 'ks_compare_period', 'ks_year_period', 'ks_list_target_deviation_field', 'ks_goal_enable', 'ks_standard_goal_value', 'ks_goal_lines', 'ks_domain_extension') def ks_get_list_view_data(self): for rec in self: if rec.ks_list_view_type and rec.ks_dashboard_item_type and rec.ks_dashboard_item_type == 'ks_list_view' and \ rec.ks_model_id: ks_list_view_data = {'label': [], 'data_rows': [], 'model': rec.ks_model_name, 'fields_type': []} ks_chart_domain = self.ks_convert_into_proper_domain(rec.ks_domain, rec) orderby = rec.ks_sort_by_field.name if rec.ks_sort_by_field else "id" if rec.ks_sort_by_order: orderby = orderby + " " + rec.ks_sort_by_order limit = rec.ks_record_data_limit if rec.ks_record_data_limit and rec.ks_record_data_limit > 0 else False if rec.ks_list_view_type == "ungrouped": if rec.ks_list_view_fields: ks_list_view_data = rec.ks_fetch_list_view_data(rec) elif rec.ks_list_view_type == "grouped" and rec.ks_list_view_group_fields and rec.ks_chart_relation_groupby: ks_list_fields = [] if rec.ks_chart_groupby_type == 'relational_type': ks_list_view_data['list_view_type'] = 'relational_type' ks_list_view_data['groupby'] = rec.ks_chart_relation_groupby.name ks_list_fields.append(rec.ks_chart_relation_groupby.name) ks_list_view_data['label'].append(rec.ks_chart_relation_groupby.field_description) ks_list_view_data['fields_type'].append(self.ks_chart_relation_groupby.ttype) for res in rec.ks_list_view_group_fields: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_data['fields_type'].append(res.ttype) ks_list_view_records = self.env[rec.ks_model_name].read_group(ks_chart_domain, ks_list_fields, [ rec.ks_chart_relation_groupby.name], orderby=orderby, limit=limit) for res in ks_list_view_records: if all(list_fields in res for list_fields in ks_list_fields) and res[ rec.ks_chart_relation_groupby.name]: counter = 0 data_row = {'id': res[rec.ks_chart_relation_groupby.name][0], 'data': [], 'domain': json.dumps(res['__domain'])} for field_rec in ks_list_fields: if counter == 0: data_row['data'].append(res[field_rec][1]) else: data_row['data'].append(res[field_rec]) counter += 1 ks_list_view_data['data_rows'].append(data_row) elif rec.ks_chart_groupby_type == 'date_type' and rec.ks_chart_date_groupby: ks_chart_date_groupby = rec.ks_chart_date_groupby if rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' ks_list_view_data['list_view_type'] = 'date_type' ks_list_field = [] ks_list_view_data[ 'groupby'] = rec.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby ks_list_field.append(rec.ks_chart_relation_groupby.name) ks_list_fields.append(rec.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby) ks_list_view_data['label'].append( rec.ks_chart_relation_groupby.field_description + ' : ' + ks_chart_date_groupby.capitalize()) ks_list_view_data['fields_type'].append(self.ks_chart_relation_groupby.ttype) for res in rec.ks_list_view_group_fields: ks_list_fields.append(res.name) ks_list_field.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_data['fields_type'].append(res.ttype) list_target_deviation_field = [] if rec.ks_goal_enable and rec.ks_list_target_deviation_field: list_target_deviation_field.append(rec.ks_list_target_deviation_field.name) if rec.ks_list_target_deviation_field.name in ks_list_field: ks_list_field.remove(rec.ks_list_target_deviation_field.name) ks_list_fields.remove(rec.ks_list_target_deviation_field.name) ks_list_view_data['label'].remove(rec.ks_list_target_deviation_field.field_description) ks_list_view_records = self.env[rec.ks_model_name].read_group(ks_chart_domain, ks_list_field + list_target_deviation_field, [ rec.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby], orderby=orderby, limit=limit) if all(list_fields in res for res in ks_list_view_records for list_fields in ks_list_fields + list_target_deviation_field): for res in ks_list_view_records: counter = 0 data_row = {'id': 0, 'data': []} for field_rec in ks_list_fields: data_row['data'].append(res[field_rec]) ks_list_view_data['data_rows'].append(data_row) if rec.ks_goal_enable: ks_list_labels = [] ks_list_view_data['label'].append("Target") if rec.ks_list_target_deviation_field: ks_list_view_data['label'].append( rec.ks_list_target_deviation_field.field_description) ks_list_view_data['label'].append("Achievement") ks_list_view_data['label'].append("Deviation") for res in ks_list_view_records: ks_list_labels.append(res[ks_list_view_data['groupby']]) ks_list_view_data2 = rec.get_target_list_view_data(ks_list_view_records, rec, ks_list_fields, ks_list_view_data['groupby'], list_target_deviation_field, ks_chart_domain) ks_list_view_data['data_rows'] = ks_list_view_data2['data_rows'] elif rec.ks_chart_groupby_type == 'selection': ks_list_view_data['list_view_type'] = 'selection' ks_list_view_data['groupby'] = rec.ks_chart_relation_groupby.name ks_selection_field = rec.ks_chart_relation_groupby.name ks_list_fields.append(rec.ks_chart_relation_groupby.name) ks_list_view_data['label'].append(rec.ks_chart_relation_groupby.field_description) ks_list_view_data['fields_type'].append(self.ks_chart_relation_groupby.ttype) for res in rec.ks_list_view_group_fields: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_data['fields_type'].append(res.ttype) ks_list_view_records = self.env[rec.ks_model_name].read_group(ks_chart_domain, ks_list_fields, [ rec.ks_chart_relation_groupby.name], orderby=orderby, limit=limit) for res in ks_list_view_records: if all(list_fields in res for list_fields in ks_list_fields): counter = 0 data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain'])} if res[ks_selection_field]: data_row['data'].append(dict( self.env[rec.ks_model_name].fields_get(allfields=ks_selection_field) [ks_selection_field]['selection'])[res[ks_selection_field]]) else: data_row['data'].append(" ") for field_rec in ks_list_fields: data_row['data'].append(res[field_rec]) ks_list_view_data['data_rows'].append(data_row) elif rec.ks_chart_groupby_type == 'other': ks_list_view_data['list_view_type'] = 'other' ks_list_view_data['groupby'] = rec.ks_chart_relation_groupby.name ks_list_fields.append(rec.ks_chart_relation_groupby.name) ks_list_view_data['label'].append(rec.ks_chart_relation_groupby.field_description) ks_list_view_data['fields_type'].append(self.ks_chart_relation_groupby.ttype) for res in rec.ks_list_view_group_fields: if rec.ks_chart_relation_groupby.name != res.name: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_data['fields_type'].append(res.ttype) ks_list_view_records = self.env[rec.ks_model_name].read_group(ks_chart_domain, ks_list_fields, [ rec.ks_chart_relation_groupby.name], orderby=orderby, limit=limit) for res in ks_list_view_records: if all(list_fields in res for list_fields in ks_list_fields): counter = 0 data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain'])} for field_rec in ks_list_fields: if counter == 0: data_row['data'].append(res[field_rec]) else: if rec.ks_chart_relation_groupby.name == field_rec: data_row['data'].append(res[field_rec] * res[field_rec + '_count']) else: data_row['data'].append(res[field_rec]) counter += 1 ks_list_view_data['data_rows'].append(data_row) rec.ks_list_view_data = json.dumps(ks_list_view_data) else: rec.ks_list_view_data = False def get_target_list_view_data(self, ks_list_view_records, rec, ks_list_fields, ks_group_by, target_deviation_field, ks_chart_domain): ks_list_view_data = {} ks_list_labels = [] ks_list_records = {} ks_domains = {} for res in ks_list_view_records: ks_list_labels.append(res[ks_group_by]) ks_domains[res[ks_group_by]] = res['__domain'] ks_list_records[res[ks_group_by]] = {'measure_field': [], 'deviation_value': 0.0} ks_list_records[res[ks_group_by]]['measure_field'] = [] for fields in ks_list_fields[1:]: ks_list_records[res[ks_group_by]]['measure_field'].append(res[fields]) for field in target_deviation_field: ks_list_records[res[ks_group_by]]['deviation'] = res[field] if rec._context.get('current_id', False): ks_item_id = rec._context['current_id'] else: ks_item_id = rec.id if rec.ks_date_filter_selection_2 == "l_none": selected_start_date = rec._context.get('ksDateFilterStartDate', False) selected_end_date = rec._context.get('ksDateFilterEndDate', False) else: selected_start_date = rec.ks_item_start_date selected_end_date = rec.ks_item_end_date ks_goal_domain = [('ks_dashboard_item', '=', ks_item_id)] if selected_start_date and selected_end_date: ks_goal_domain.extend([('ks_goal_date', '>=', selected_start_date.strftime("%Y-%m-%d")), ('ks_goal_date', '<=', selected_end_date.strftime("%Y-%m-%d"))]) ks_date_data = rec.ks_get_start_end_date(rec.ks_model_name, rec.ks_chart_relation_groupby.name, rec.ks_chart_relation_groupby.ttype, ks_chart_domain, ks_goal_domain) labels = [] ks_chart_date_groupby = rec.ks_chart_date_groupby if rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' if ks_date_data['start_date'] and ks_date_data['end_date'] and rec.ks_goal_lines: labels = self.generate_timeserise(ks_date_data['start_date'], ks_date_data['end_date'], ks_chart_date_groupby) ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group( ks_goal_domain, ['ks_goal_value', 'ks_goal_date'], ['ks_goal_date' + ":" + ks_chart_date_groupby], ) ks_goal_labels = [] ks_goal_dataset = {} ks_list_view_data['data_rows'] = [] if rec.ks_goal_lines and len(rec.ks_goal_lines) != 0: ks_goal_domains = {} for res in ks_goal_records: if res['ks_goal_date' + ":" + ks_chart_date_groupby]: ks_goal_labels.append(res['ks_goal_date' + ":" + ks_chart_date_groupby]) ks_goal_dataset[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res['ks_goal_value'] ks_goal_domains[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res.get('__domain') for goal_domain in ks_goal_domains.keys(): ks_goal_doamins = [] for item in ks_goal_domains[goal_domain]: if 'ks_goal_date' in item: domain = list(item) domain[0] = ks_group_by.split(":")[0] domain = tuple(domain) ks_goal_doamins.append(domain) ks_goal_doamins.insert(0, '&') ks_goal_domains[goal_domain] = ks_goal_doamins ks_chart_records_dates = ks_list_labels + list( set(ks_goal_labels) - set(ks_list_labels)) ks_list_labels_dates = [] for label in labels: if label in ks_chart_records_dates: ks_list_labels_dates.append(label) for label in ks_list_labels_dates: data_rows = {'data': [label]} data = ks_list_records.get(label, False) if data: data_rows['data'] = data_rows['data'] + data['measure_field'] data_rows['domain'] = json.dumps(ks_domains[label]) else: for fields in ks_list_fields[1:]: data_rows['data'].append(0.0) data_rows['domain'] = json.dumps(ks_goal_domains[label]) target_value = (ks_goal_dataset.get(label, 0.0)) data_rows['data'].append(target_value) for field in target_deviation_field: if data: data_rows['data'].append(data['deviation']) value = data['deviation'] else: data_rows['data'].append(0.0) value = 0 if target_value: acheivement = round(((value) / target_value) * 100) acheivement = str(acheivement) + "%" else: acheivement = "" deviation = (value - target_value) data_rows['data'].append(acheivement) data_rows['data'].append(deviation) ks_list_view_data['data_rows'].append(data_rows) else: for res in ks_list_view_records: if all(list_fields in res for list_fields in ks_list_fields): counter = 0 data_row = {'id': 0, 'data': [], } for field_rec in ks_list_fields: data_row['data'].append(res[field_rec]) data_row['data'].append(rec.ks_standard_goal_value) data_row['domain'] = json.dumps(res['__domain']) for field in target_deviation_field: value = res[field] data_row['data'].append(res[field]) target_value = rec.ks_standard_goal_value if target_value: acheivement = round(((value) / target_value) * 100) acheivement = str(acheivement) + "%" else: acheivement = "" deviation = (value - target_value) data_row['data'].append(acheivement) data_row['data'].append(deviation) ks_list_view_data['data_rows'].append(data_row) return ks_list_view_data @api.model def ks_fetch_list_view_data(self, rec, limit=15, offset=0): ks_list_view_data = {'label': [], 'data_rows': [], 'model': rec.ks_model_name, 'fields_type': []} ks_chart_domain = rec.ks_convert_into_proper_domain(rec.ks_domain, rec) orderby = rec.ks_sort_by_field.name if rec.ks_sort_by_field else "id" if rec.ks_sort_by_order: orderby = orderby + " " + rec.ks_sort_by_order ks_limit = rec.ks_record_data_limit if rec.ks_record_data_limit and rec.ks_record_data_limit > 0 else False if ks_limit: ks_limit = ks_limit - offset if ks_limit < 15: limit = ks_limit else: limit = 15 if rec.ks_list_view_fields: ks_list_view_data['list_view_type'] = 'other' ks_list_view_data['groupby'] = False ks_list_view_data['label'] = [] ks_list_view_data['date_index'] = [] for res in rec.ks_list_view_fields: if (res.ttype == "datetime" or res.ttype == "date"): index = len(ks_list_view_data['label']) ks_list_view_data['label'].append(res.field_description) ks_list_view_data['date_index'].append(index) ks_list_view_data['fields_type'].append(res.ttype) else: ks_list_view_data['label'].append(res.field_description) ks_list_view_data['fields_type'].append(res.ttype) ks_list_view_fields = [res.name for res in rec.ks_list_view_fields] ks_list_view_field_type = [res.ttype for res in rec.ks_list_view_fields] try: ks_list_view_records = self.env[rec.ks_model_name].search_read(ks_chart_domain, ks_list_view_fields, order=orderby, limit=limit, offset=offset) except Exception as e: ks_list_view_data = False return ks_list_view_data for res in ks_list_view_records: counter = 0 data_row = {'id': res['id'], 'data': []} for field_rec in ks_list_view_fields: if type(res[field_rec]) == fields.datetime or type(res[field_rec]) == fields.date: res[field_rec] = res[field_rec].strftime("%D %T") elif ks_list_view_field_type[counter] == "many2one": if res[field_rec]: res[field_rec] = res[field_rec][1] data_row['data'].append(res[field_rec]) counter += 1 ks_list_view_data['data_rows'].append(data_row) return ks_list_view_data @api.onchange('ks_dashboard_item_type') def set_color_palette(self): for rec in self: if rec.ks_dashboard_item_type == "ks_bar_chart" or rec.ks_dashboard_item_type == "ks_horizontalBar_chart" or rec.ks_dashboard_item_type == "ks_line_chart" or rec.ks_dashboard_item_type == "ks_area_chart": rec.ks_chart_item_color = "cool" else: rec.ks_chart_item_color = "default" # Time Filter Calculation @api.multi @api.onchange('ks_date_filter_selection') def ks_set_date_filter(self): for rec in self: if (not rec.ks_date_filter_selection) or rec.ks_date_filter_selection == "l_none": rec.ks_item_start_date = rec.ks_item_end_date = False elif rec.ks_date_filter_selection != 'l_custom': ks_date_data = ks_get_date(rec.ks_date_filter_selection, self) rec.ks_item_start_date = ks_date_data["selected_start_date"] rec.ks_item_end_date = ks_date_data["selected_end_date"] @api.multi @api.depends('ks_dashboard_item_type', 'ks_model_id', 'ks_model_id_2', 'ks_record_field', 'ks_goal_enable', 'ks_standard_goal_value', 'ks_record_field_2', 'ks_record_count_type_2', 'ks_domain', 'ks_domain_2', 'ks_date_filter_selection', 'ks_item_start_date', 'ks_record_count_type', 'ks_date_filter_selection_2', 'ks_item_end_date', 'ks_previous_period', 'ks_item_start_date_2', 'ks_item_end_date', 'ks_compare_period', 'ks_year_period', 'ks_date_filter_field', 'ks_date_filter_field_2', 'ks_compare_period_2', 'ks_year_period_2', 'ks_domain_extension_2') def ks_get_kpi_data(self): for rec in self: if rec.ks_dashboard_item_type and rec.ks_dashboard_item_type == 'ks_kpi' and rec.ks_model_id: ks_kpi_data = [] ks_record_count = 0.0 ks_kpi_data_model_1 = {} if rec.ks_record_count_type == 'count': ks_record_count = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'search_count', rec) elif rec.ks_record_count_type in ['sum', 'average'] and rec.ks_record_field: ks_records_grouped_data = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'read_group', rec) if len(ks_records_grouped_data) > 0: ks_records_grouped_data = ks_records_grouped_data[0] if rec.ks_record_count_type == 'sum' and ks_records_grouped_data.get('__count', False) and ( ks_records_grouped_data.get(rec.ks_record_field.name)): ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, 0) elif rec.ks_record_count_type == 'average' and ks_records_grouped_data.get( '__count', False) and (ks_records_grouped_data.get(rec.ks_record_field.name)): ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, 0) / ks_records_grouped_data.get( '__count', 1) else: ks_record_count = 0 else: ks_record_count = 0 else: ks_record_count = 0 ks_kpi_data_model_1['model'] = rec.ks_model_name ks_kpi_data_model_1['record_field'] = rec.ks_record_field.field_description ks_kpi_data_model_1['record_data'] = ks_record_count if rec.ks_goal_enable: ks_kpi_data_model_1['target'] = rec.ks_standard_goal_value ks_kpi_data.append(ks_kpi_data_model_1) if rec.ks_previous_period: ks_previous_period_data = rec.ks_get_previous_period_data(rec) ks_kpi_data_model_1['previous_period'] = ks_previous_period_data if rec.ks_model_id_2 and rec.ks_record_count_type_2: ks_kpi_data_model_2 = rec.ks_get_model_2_data(rec.ks_model_name_2, rec.ks_record_count_type_2, rec.ks_record_field_2, rec.ks_domain_2, rec) ks_kpi_data.append(ks_kpi_data_model_2) rec.ks_kpi_data = json.dumps(ks_kpi_data) def ks_get_model_2_data(self, ks_model_name_2, ks_record_count_type_2, ks_record_field_2, ks_domain, rec): if rec.ks_record_count_type_2 == 'count': ks_record_count = rec.ks_fetch_model_data_2(ks_model_name_2, ks_domain, 'search_count', rec) elif rec.ks_record_count_type_2 in ['sum', 'average'] and ks_record_field_2: ks_records_grouped_data = rec.ks_fetch_model_data_2(ks_model_name_2, ks_domain, 'read_group', rec) if len(ks_records_grouped_data) > 0: ks_records_grouped_data = ks_records_grouped_data[0] if rec.ks_record_count_type_2 == 'sum' and ks_records_grouped_data.get('__count', False) and ( ks_records_grouped_data.get(ks_record_field_2.name)): ks_record_count = ks_records_grouped_data.get(ks_record_field_2.name, 0) elif rec.ks_record_count_type_2 == 'average' and ks_records_grouped_data.get( '__count', False) and (ks_records_grouped_data.get(ks_record_field_2.name)): ks_record_count = ks_records_grouped_data.get(ks_record_field_2.name, 0) / ks_records_grouped_data.get('__count', 1) else: ks_record_count = 0 else: ks_record_count = 0 else: ks_record_count = 0 rec.ks_record_count_2 = ks_record_count ks_kpi_data_model_2 = {} ks_kpi_data_model_2['model'] = rec.ks_model_name_2 ks_kpi_data_model_2[ 'record_field'] = 'count' if ks_record_count_type_2 == 'count' else ks_record_field_2.field_description ks_kpi_data_model_2['record_data'] = ks_record_count return ks_kpi_data_model_2 # writing separate function for fetching previous period data def ks_get_previous_period_data(self, rec): switcher = { 'l_day': 'ls_day', 't_week': 'ls_week', 't_month': 'ls_month', 't_quarter': 'ls_quarter', 't_year': 'ls_year', } ks_previous_period = False ks_date_data = False if rec.ks_date_filter_selection == "l_none": date_filter_selection = rec.ks_dashboard_ninja_board_id.ks_date_filter_selection else: date_filter_selection = rec.ks_date_filter_selection ks_previous_period = switcher.get(date_filter_selection, False) if ks_previous_period: ks_date_data = ks_get_date(ks_previous_period, self) if (ks_date_data): previous_period_start_date = ks_date_data["selected_start_date"] previous_period_end_date = ks_date_data["selected_end_date"] proper_domain = rec.ks_get_previous_period_domain(rec.ks_domain, previous_period_start_date, previous_period_end_date, rec.ks_date_filter_field) ks_record_count = 0.0 if rec.ks_record_count_type == 'count': try: ks_record_count = self.env[rec.ks_model_name].search_count(proper_domain) except Exception as e: ks_record_count = 0.0 return ks_record_count elif rec.ks_record_field: try: data = self.env[rec.ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], [])[0] except Exception as e: data = {} pass if rec.ks_record_count_type == 'sum': return data.get(rec.ks_record_field.name, 0) if data.get('__count', False) and ( data.get(rec.ks_record_field.name)) else 0 else: return data.get(rec.ks_record_field.name, 0) / data.get('__count', 1) if data.get('__count', False) and ( data.get( rec.ks_record_field.name)) else 0 else: return False else: return False def ks_get_previous_period_domain(self, ks_domain, ks_start_date, ks_end_date, date_filter_field): if ks_domain and "%UID" in ks_domain: ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) if ks_domain: # try: proper_domain = safe_eval(ks_domain) if ks_start_date and ks_end_date and date_filter_field: proper_domain.extend([(date_filter_field.name, ">=", str(ks_start_date)), (date_filter_field.name, "<=", str(ks_end_date))]) else: if ks_start_date and ks_end_date and date_filter_field: proper_domain = ([(date_filter_field.name, ">=", str(ks_start_date)), (date_filter_field.name, "<=", str(ks_end_date))]) else: proper_domain = [] return proper_domain @api.depends('ks_domain_2', 'ks_model_id_2', 'ks_record_field_2', 'ks_record_count_type_2', 'ks_item_start_date_2', 'ks_date_filter_selection_2', 'ks_record_count_type_2', 'ks_compare_period_2', 'ks_year_period_2') def ks_get_record_count_2(self): for rec in self: if rec.ks_record_count_type_2 == 'count': ks_record_count = rec.ks_fetch_model_data_2(rec.ks_model_name_2, rec.ks_domain_2, 'search_count', rec) elif rec.ks_record_count_type_2 in ['sum', 'average'] and rec.ks_record_field_2: ks_records_grouped_data = rec.ks_fetch_model_data_2(rec.ks_model_name_2, rec.ks_domain_2, 'read_group', rec) if ks_records_grouped_data and len(ks_records_grouped_data) > 0: ks_records_grouped_data = ks_records_grouped_data[0] if rec.ks_record_count_type_2 == 'sum' and ks_records_grouped_data.get('__count', False) and ( ks_records_grouped_data.get(rec.ks_record_field_2.name)): ks_record_count = ks_records_grouped_data.get(rec.ks_record_field_2.name, 0) elif rec.ks_record_count_type_2 == 'average' and ks_records_grouped_data.get( '__count', False) and (ks_records_grouped_data.get(rec.ks_record_field_2.name)): ks_record_count = ks_records_grouped_data.get(rec.ks_record_field_2.name, 0) / ks_records_grouped_data.get('__count', 1) else: ks_record_count = 0 else: ks_record_count = 0 else: ks_record_count = False rec.ks_record_count_2 = ks_record_count @api.onchange('ks_model_id_2') def make_record_field_empty_2(self): for rec in self: rec.ks_record_field_2 = False rec.ks_domain_2 = False rec.ks_date_filter_field_2 = False # To show "created on" by default on date filter field on model select. if rec.ks_model_id: datetime_field_list = rec.ks_date_filter_field_2.search( [('model_id', '=', rec.ks_model_id.id), '|', ('ttype', '=', 'date'), ('ttype', '=', 'datetime')]).read(['id', 'name']) for field in datetime_field_list: if field['name'] == 'create_date': rec.ks_date_filter_field_2 = field['id'] else: rec.ks_date_filter_field_2 = False # Writing separate function to fetch dashboard item data def ks_fetch_model_data_2(self, ks_model_name, ks_domain, ks_func, rec): data = 0 try: if ks_domain and ks_domain != '[]' and ks_model_name: proper_domain = self.ks_convert_into_proper_domain_2(ks_domain, rec) if ks_func == 'search_count': data = self.env[ks_model_name].search_count(proper_domain) elif ks_func == 'read_group': data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field_2.name], []) elif ks_model_name: # Have to put extra if condition here because on load,model giving False value proper_domain = self.ks_convert_into_proper_domain_2(False, rec) if ks_func == 'search_count': data = self.env[ks_model_name].search_count(proper_domain) elif ks_func == 'read_group': data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field_2.name], []) else: return [] except Exception as e: return [] return data @api.multi @api.onchange('ks_date_filter_selection_2') def ks_set_date_filter_2(self): for rec in self: if (not rec.ks_date_filter_selection_2) or rec.ks_date_filter_selection_2 == "l_none": rec.ks_item_start_date_2 = rec.ks_item_end_date = False elif rec.ks_date_filter_selection_2 != 'l_custom': ks_date_data = ks_get_date(rec.ks_date_filter_selection_2, self) rec.ks_item_start_date_2 = ks_date_data["selected_start_date"] rec.ks_item_end_date_2 = ks_date_data["selected_end_date"] def ks_convert_into_proper_domain_2(self, ks_domain_2, rec): if ks_domain_2 and "%UID" in ks_domain_2: ks_domain_2 = ks_domain_2.replace("%UID", str(self.env.user.id)) if ks_domain_2 and "%MYCOMPANY" in ks_domain_2: ks_domain_2 = str(safe_eval(ks_domain_2)).replace("'%MYCOMPANY'", str(self.env.user.company_id.id)) ks_date_domain = False if not rec.ks_date_filter_selection_2 or rec.ks_date_filter_selection_2 == "l_none": selected_start_date = self._context.get('ksDateFilterStartDate', False) selected_end_date = self._context.get('ksDateFilterEndDate', False) if selected_end_date and not selected_start_date: ks_date_domain = [ (rec.ks_date_filter_field.name, "<=", selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] elif selected_start_date and not selected_end_date: ks_date_domain = [ (rec.ks_date_filter_field.name, ">=", selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] else: if selected_end_date and selected_start_date: ks_date_domain = [ (rec.ks_date_filter_field.name, ">=", selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), (rec.ks_date_filter_field.name, "<=", selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] else: if rec.ks_date_filter_selection_2 and rec.ks_date_filter_selection_2 != 'l_custom': ks_date_data = ks_get_date(rec.ks_date_filter_selection_2, self) selected_start_date = ks_date_data["selected_start_date"] selected_end_date = ks_date_data["selected_end_date"] else: if rec.ks_item_start_date_2 and rec.ks_item_end_date_2: selected_start_date = fields.datetime.strptime(rec.ks_item_start_date_2, DEFAULT_SERVER_DATETIME_FORMAT) selected_end_date = fields.datetime.strptime(rec.ks_item_end_date_2, DEFAULT_SERVER_DATETIME_FORMAT) else: selected_start_date = False selected_end_date = False if selected_start_date and selected_end_date: if rec.ks_compare_period_2: ks_compare_period_2 = abs(rec.ks_compare_period_2) if ks_compare_period_2 > 100: ks_compare_period_2 = 100 if rec.ks_compare_period_2 > 0: selected_end_date = selected_end_date + ( selected_end_date - selected_start_date) * ks_compare_period_2 elif rec.ks_compare_period_2 < 0: selected_start_date = selected_start_date - ( selected_end_date - selected_start_date) * ks_compare_period_2 if rec.ks_year_period_2 and rec.ks_year_period_2 != 0: abs_year_period_2 = abs(rec.ks_year_period_2) sign_yp = rec.ks_year_period / abs_year_period_2 if abs_year_period_2 > 100: abs_year_period_2 = 100 date_field_name = rec.ks_date_filter_field_2.name ks_date_domain = ['&', (date_field_name, ">=", fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT)), (date_field_name, "<=", fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT))] for p in range(1, abs_year_period_2 + 1): ks_date_domain.insert(0, '|') ks_date_domain.extend(['&', (date_field_name, ">=", fields.datetime.strftime( selected_start_date - dateutil.relativedelta.relativedelta(years=p) * sign_yp, DEFAULT_SERVER_DATETIME_FORMAT)), (date_field_name, "<=", fields.datetime.strftime( selected_end_date - dateutil.relativedelta.relativedelta( years=p) * sign_yp, DEFAULT_SERVER_DATETIME_FORMAT))]) else: if rec.ks_date_filter_field_2: selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) ks_date_domain = [(rec.ks_date_filter_field_2.name, ">=", selected_start_date), (rec.ks_date_filter_field_2.name, "<=", selected_end_date)] else: ks_date_domain = [] elif selected_start_date and rec.ks_date_filter_field_2: selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) ks_date_domain = [(rec.ks_date_filter_field_2.name, ">=", selected_start_date)] elif selected_end_date and rec.ks_date_filter_field_2: selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) ks_date_domain = [(rec.ks_date_filter_field_2.name, "<=", selected_end_date)] proper_domain = safe_eval(ks_domain_2) if ks_domain_2 else [] if ks_date_domain: proper_domain.extend(ks_date_domain) if rec.ks_domain_extension_2: ks_domain_extension = rec.ks_convert_domain_extension(rec.ks_domain_extension_2, rec) proper_domain.extend(ks_domain_extension) return proper_domain def ks_fetch_chart_data(self, ks_model_name, ks_chart_domain,ks_chart_measure_field_with_type, ks_chart_measure_field_with_type_2, ks_chart_measure_field, ks_chart_measure_field_2, ks_chart_groupby_relation_field, ks_chart_date_groupby, ks_chart_groupby_type, orderby, limit, chart_count, ks_chart_measure_field_ids, ks_chart_measure_field_2_ids, ks_chart_groupby_relation_field_id, ks_chart_data): if ks_chart_groupby_type == "date_type": ks_chart_groupby_field = ks_chart_groupby_relation_field + ":" + ks_chart_date_groupby else: ks_chart_groupby_field = ks_chart_groupby_relation_field try: ks_chart_records = self.env[ks_model_name].read_group(ks_chart_domain, set( ks_chart_measure_field_with_type + ks_chart_measure_field_with_type_2 + [ks_chart_groupby_relation_field]), [ks_chart_groupby_field], orderby=orderby, limit=limit) except Exception as e: ks_chart_records = [] pass if ks_chart_groupby_type == "relational_type": ks_chart_data['groupByIds'] = [] for res in ks_chart_records: if all(measure_field in res for measure_field in ks_chart_measure_field): if ks_chart_groupby_type == "relational_type": label = res.get(ks_chart_groupby_field) if label: ks_chart_data['labels'].append(label[1]) ks_chart_data['groupByIds'].append(res[ks_chart_groupby_field][0]) else: ks_chart_data['labels'].append(label) elif ks_chart_groupby_type == "selection": selection = res[ks_chart_groupby_field] if selection: ks_chart_data['labels'].append( dict(self.env[ks_model_name].fields_get(allfields=[ks_chart_groupby_field]) [ks_chart_groupby_field]['selection'])[selection]) else: ks_chart_data['labels'].append(selection) else: ks_chart_data['labels'].append(res[ks_chart_groupby_field]) ks_chart_data['domains'].append(res.get('__domain', [])) counter = 0 if ks_chart_measure_field: if ks_chart_measure_field_2: index = 0 for field_rec in ks_chart_measure_field_2: ks_groupby_equal_measures = res[ks_chart_groupby_relation_field + "_count"] \ if ks_chart_measure_field_2_ids[index] == ks_chart_groupby_relation_field_id \ else 1 data = res[field_rec] * ks_groupby_equal_measures ks_chart_data['datasets'][counter]['data'].append(data) counter += 1 index += 1 index = 0 for field_rec in ks_chart_measure_field: ks_groupby_equal_measures = res[ks_chart_groupby_relation_field + "_count"] \ if ks_chart_measure_field_ids[index] == ks_chart_groupby_relation_field_id \ else 1 data = res[field_rec] * ks_groupby_equal_measures ks_chart_data['datasets'][counter]['data'].append(data) counter += 1 index += 1 else: data = res[ks_chart_groupby_relation_field + "_count"] ks_chart_data['datasets'][0]['data'].append(data) return ks_chart_data @api.model def ks_fetch_drill_down_data(self, item_id, domain, sequence): record = self.browse(int(item_id)) ks_chart_data = {'labels': [], 'datasets': [], 'ks_show_second_y_scale': False, 'domains': [], 'previous_domain': domain, 'ks_currency': 0, 'ks_field': "", 'ks_selection': ""} if record.ks_unit and record.ks_unit_selection == 'monetary': ks_chart_data['ks_selection'] += record.ks_unit_selection ks_chart_data['ks_currency'] += record.env.user.company_id.currency_id.id elif record.ks_unit and record.ks_unit_selection == 'custom': ks_chart_data['ks_selection'] += record.ks_unit_selection if record.ks_chart_unit: ks_chart_data['ks_field'] += record.ks_chart_unit # If count chart data type: action_lines = record.ks_action_lines.sorted(key=lambda r: r.sequence) action_line = action_lines[sequence] ks_chart_type = action_line.ks_chart_type if action_line.ks_chart_type else record.ks_dashboard_item_type ks_list_view_data = {'label': [], 'data_rows': [], 'model': record.ks_model_name, 'previous_domain': domain, } if action_line.ks_chart_type == 'ks_list_view': if record.ks_dashboard_item_type == 'ks_list_view': ks_chart_list_measure = record.ks_list_view_group_fields else: ks_chart_list_measure = record.ks_chart_measure_field ks_list_fields = [] orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else "id" if action_line.ks_sort_by_order: orderby = orderby + " " + action_line.ks_sort_by_order limit = action_line.ks_record_limit if action_line.ks_record_limit \ and action_line.ks_record_limit > 0 else False ks_count = 0 for ks in record.ks_action_lines: ks_count += 1 if action_line.ks_item_action_field.ttype == 'many2one': ks_list_view_data['groupby'] = action_line.ks_item_action_field.name ks_list_fields.append(action_line.ks_item_action_field.name) ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) for res in ks_chart_list_measure: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_records = self.env[record.ks_model_name].read_group(domain, ks_list_fields, [ action_line.ks_item_action_field.name], orderby=orderby, limit=limit) for res in ks_list_view_records: counter = 0 data_row = {'id': res[action_line.ks_item_action_field.name][0], 'data': [], 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, 'last_seq': ks_count} for field_rec in ks_list_fields: if counter == 0: data_row['data'].append(res[field_rec][1]) else: data_row['data'].append(res[field_rec]) counter += 1 ks_list_view_data['data_rows'].append(data_row) elif action_line.ks_item_action_field.ttype == 'date' or \ action_line.ks_item_action_field.ttype == 'datetime': ks_list_view_data['list_view_type'] = 'date_type' ks_list_field = [] ks_list_view_data['groupby'] = action_line.ks_item_action_field.name ks_list_field.append( action_line.ks_item_action_field.name + ':' + action_line.ks_item_action_date_groupby) ks_list_fields.append(action_line.ks_item_action_field.name) ks_list_view_data['label'].append( action_line.ks_item_action_field.field_description) for res in ks_chart_list_measure: ks_list_fields.append(res.name) ks_list_field.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_records = self.env[record.ks_model_name].read_group(domain, ks_list_fields, [action_line.ks_item_action_field.name + ':' + action_line.ks_item_action_date_groupby], orderby=orderby, limit=limit) for res in ks_list_view_records: counter = 0 data_row = {'data': [], 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, 'last_seq': ks_count} for field_rec in ks_list_field: data_row['data'].append(res[field_rec]) ks_list_view_data['data_rows'].append(data_row) elif action_line.ks_item_action_field.ttype == 'selection': ks_list_view_data['list_view_type'] = 'selection' ks_list_view_data['groupby'] = action_line.ks_item_action_field.name ks_list_fields.append(action_line.ks_item_action_field.name) ks_selection_field = action_line.ks_item_action_field.name ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) for res in ks_chart_list_measure: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_records = self.env[record.ks_model_name].read_group(domain, ks_list_fields, [ action_line.ks_item_action_field.name], orderby=orderby, limit=limit) for res in ks_list_view_records: counter = 0 data_row = {'data': [], 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, 'last_seq': ks_count} if res[ks_selection_field]: data_row['data'].append(dict( self.env[record.ks_model_name].fields_get(allfields=ks_selection_field) [ks_selection_field]['selection'])[res[ks_selection_field]]) else: data_row['data'].append(" ") for field_rec in ks_list_fields: data_row['data'].append(res[field_rec]) ks_list_view_data['data_rows'].append(data_row) else: ks_list_view_data['list_view_type'] = 'other' ks_list_view_data['groupby'] = action_line.ks_item_action_field.name ks_list_fields.append(action_line.ks_item_action_field.name) ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) for res in ks_chart_list_measure: ks_list_fields.append(res.name) ks_list_view_data['label'].append(res.field_description) ks_list_view_records = self.env[record.ks_model_name].read_group(domain, ks_list_fields, [ action_line.ks_item_action_field.name], orderby=orderby, limit=limit) for res in ks_list_view_records: if all(list_fields in res for list_fields in ks_list_fields): counter = 0 data_row = {'id': action_line.ks_item_action_field.name, 'data': [], 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, 'last_seq': ks_count} for field_rec in ks_list_fields: if counter == 0: data_row['data'].append(res[field_rec]) else: if action_line.ks_item_action_field.name == field_rec: data_row['data'].append(res[field_rec] * res[field_rec + '_count']) else: data_row['data'].append(res[field_rec]) counter += 1 ks_list_view_data['data_rows'].append(data_row) return {"ks_list_view_data": json.dumps(ks_list_view_data), "ks_list_view_type": "grouped", 'sequence': sequence + 1, } else: ks_chart_measure_field = [] ks_chart_measure_field_with_type = [] ks_chart_measure_field_ids = [] ks_chart_measure_field_2 = [] ks_chart_measure_field_with_type_2 = [] ks_chart_measure_field_2_ids = [] if record.ks_chart_data_count_type == "count": ks_chart_measure_field_with_type.append('count:count(id)') ks_chart_data['datasets'].append({'data': [], 'label': "Count"}) else: if ks_chart_type == 'ks_bar_chart': if record.ks_chart_measure_field_2: ks_chart_data['ks_show_second_y_scale'] = True for res in record.ks_chart_measure_field_2: if record.ks_chart_data_count_type == 'sum': ks_data_count_type = 'sum' elif record.ks_chart_data_count_type == 'average': ks_data_count_type = 'avg' else: raise ValidationError(_('Please chose any Data Type!')) ks_chart_measure_field_2.append(res.name) ks_chart_measure_field_with_type_2.append(res.name + ':' + ks_data_count_type) ks_chart_measure_field_2_ids.append(res.id) ks_chart_data['datasets'].append( {'data': [], 'label': res.field_description, 'type': 'line', 'yAxisID': 'y-axis-1'}) if record.ks_dashboard_item_type == 'ks_list_view': for res in record.ks_list_view_group_fields: ks_chart_measure_field.append(res.name) ks_chart_measure_field_with_type.append(res.name + ':' + 'sum') ks_chart_measure_field_ids.append(res.id) ks_chart_data['datasets'].append({'data': [], 'label': res.field_description}) else: for res in record.ks_chart_measure_field: if record.ks_chart_data_count_type == 'sum': ks_data_count_type = 'sum' elif record.ks_chart_data_count_type == 'average': ks_data_count_type = 'avg' else: raise ValidationError(_('Please chose any Data Type!')) ks_chart_measure_field.append(res.name) ks_chart_measure_field_with_type.append(res.name + ':' + ks_data_count_type) ks_chart_measure_field_ids.append(res.id) ks_chart_data['datasets'].append({'data': [], 'label': res.field_description}) ks_chart_groupby_relation_field = action_line.ks_item_action_field.name ks_chart_relation_type = action_line.ks_item_action_field_type ks_chart_date_group_by = action_line.ks_item_action_date_groupby ks_chart_groupby_relation_field_id = action_line.ks_item_action_field.id orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else "id" if record.ks_chart_data_count_type == "count": orderby = 'count' if action_line.ks_sort_by_order: orderby = orderby + " " + action_line.ks_sort_by_order limit = action_line.ks_record_limit if action_line.ks_record_limit and action_line.ks_record_limit > 0 else False if ks_chart_type != "ks_bar_chart": ks_chart_measure_field_2 = [] ks_chart_measure_field_2_ids = [] ks_chart_data = record.ks_fetch_chart_data(record.ks_model_name, domain, ks_chart_measure_field_with_type, ks_chart_measure_field_with_type_2, ks_chart_measure_field, ks_chart_measure_field_2, ks_chart_groupby_relation_field, ks_chart_date_group_by, ks_chart_relation_type, orderby, limit, record.ks_chart_data_count_type, ks_chart_measure_field_ids, ks_chart_measure_field_2_ids, ks_chart_groupby_relation_field_id, ks_chart_data) return { 'ks_chart_data': json.dumps(ks_chart_data), 'ks_chart_type': ks_chart_type, 'sequence': sequence + 1, } def ks_sort_sub_group_by_records(self, ks_data, field_type, ks_chart_date_groupby, ks_sort_by_order, ks_chart_date_sub_groupby): if ks_data: reverse = False if ks_sort_by_order == 'DESC': reverse = True for data in ks_data: if field_type == 'date_type': if ks_chart_date_groupby in ['minute', 'hour']: if ks_chart_date_sub_groupby in ["month", "week", "quarter", "year"]: ks_sorted_months = self.get_sorted_month("MMM") data['value'].sort(key=lambda x: int( str(ks_sorted_months.index(x['x'].split(" ")[2]) + 1) + x['x'].split(" ")[1] + x['x'].split(" ")[0].replace(":", "")), reverse=reverse) else: data['value'].sort(key=lambda x: int(x['x'].replace(":", "")), reverse=reverse) elif ks_chart_date_groupby == 'day' and ks_chart_date_sub_groupby in ["quarter", "year"]: ks_sorted_days = self.generate_timeserise("2020-01-01 00:00:00", "2020-12-31 00:00:00", 'day', "date") b = [" ".join(x.split(" ")[0:2]) for x in ks_sorted_days] data['value'].sort(key=lambda x: b.index(x['x']), reverse=reverse) elif ks_chart_date_groupby == 'day' and ks_chart_date_sub_groupby not in ["quarter", "year"]: data['value'].sort(key=lambda i: int(i['x']), reverse=reverse) elif ks_chart_date_groupby == 'week': data['value'].sort(key=lambda i: int(i['x'][1:]), reverse=reverse) elif ks_chart_date_groupby == 'month': ks_sorted_months = self.generate_timeserise("2020-01-01 00:00:00", "2020-12-31 00:00:00", 'month', "date") b = [" ".join(x.split(" ")[0:1]) for x in ks_sorted_months] data['value'].sort(key=lambda x: b.index(x['x']), reverse=reverse) elif ks_chart_date_groupby == 'quarter': data['value'].sort(key=lambda i: int(i['x'][1:]), reverse=reverse) elif ks_chart_date_groupby == 'year': data['value'].sort(key=lambda i: int(i['x']), reverse=reverse) else: data['value'].sort(key=lambda i: i['x'], reverse=reverse) return ks_data @api.model def ks_get_next_offset(self, ks_item_id, offset): record = self.browse(ks_item_id) ks_offset = offset['offset'] ks_list_view_data = self.ks_fetch_list_view_data(record, offset=int(ks_offset)) return { 'ks_list_view_data': json.dumps(ks_list_view_data), 'offset': int(ks_offset) + 1, 'next_offset': int(ks_offset) + len(ks_list_view_data['data_rows']), 'limit': record.ks_record_data_limit if record.ks_record_data_limit else 0, } @api.model def get_sorted_month(self, display_format, ftype='date'): query = """ with d as (SELECT date_trunc(%(aggr)s, generate_series) AS timestamp FROM generate_series(%(timestamp_begin)s::TIMESTAMP , %(timestamp_end)s::TIMESTAMP , %(aggr1)s::interval )) select timestamp from d group by timestamp order by timestamp """ self.env.cr.execute(query, { 'timestamp_begin': "2020-01-01 00:00:00", 'timestamp_end': "2020-12-31 00:00:00", 'aggr': 'month', 'aggr1': '1 month' }) dates = self.env.cr.fetchall() locale = self._context.get('lang') or 'en_US' tz_convert = self._context.get('tz') return [self.format_label(d[0], ftype, display_format, tz_convert, locale) for d in dates] @api.model def generate_timeserise(self, date_begin, date_end, aggr, ftype='date'): query = """ with d as (SELECT date_trunc(%(aggr)s, generate_series) AS timestamp FROM generate_series(%(timestamp_begin)s::TIMESTAMP , %(timestamp_end)s::TIMESTAMP , '1 hour'::interval )) select timestamp from d group by timestamp order by timestamp """ self.env.cr.execute(query, { 'timestamp_begin': date_begin, 'timestamp_end': date_end, 'aggr': aggr }) dates = self.env.cr.fetchall() display_formats = { # Careful with week/year formats: # - yyyy (lower) must always be used, except for week+year formats # - YYYY (upper) must always be used for week+year format # e.g. 2006-01-01 is W52 2005 in some locales (de_DE), # and W1 2006 for others # # Mixing both formats, e.g. 'MMM YYYY' would yield wrong results, # such as 2006-01-01 being formatted as "January 2005" in some locales. # Cfr: http://babel.pocoo.org/en/latest/dates.html#date-fields 'minute': 'hh:mm dd MMM', 'hour': 'hh:00 dd MMM', 'day': 'dd MMM yyyy', # yyyy = normal year 'week': "'W'w YYYY", # w YYYY = ISO week-year 'month': 'MMMM yyyy', 'quarter': 'QQQ yyyy', 'year': 'yyyy', } display_format = display_formats[aggr] locale = self._context.get('lang') or 'en_US' tz_convert = self._context.get('tz') return [self.format_label(d[0], ftype, display_format, tz_convert, locale) for d in dates] @api.model def format_label(self, value, ftype, display_format, tz_convert, locale): dt_format = '%Y-%m-%d %H:%M:%S' tzinfo = None if ftype == 'datetime': value = fields.datetime.strptime(value, dt_format) if tz_convert: value = pytz.timezone(self._context['tz']).localize(value) tzinfo = value.tzinfo return babel.dates.format_datetime(value, format=display_format, tzinfo=tzinfo, locale=locale) else: value = fields.datetime.strptime(value, dt_format) if tz_convert: value = pytz.timezone(self._context['tz']).localize(value) tzinfo = value.tzinfo return babel.dates.format_date(value, format=display_format, locale=locale) @api.model def ks_get_start_end_date(self, model_name, ks_chart_groupby_relation_field, ttype, ks_chart_domain, ks_goal_domain): ks_start_end_date = {} try: model_field_start_date = \ self.env[model_name].search(ks_chart_domain + [(ks_chart_groupby_relation_field, '!=', False)], limit=1, order=ks_chart_groupby_relation_field + " ASC")[ ks_chart_groupby_relation_field] model_field_end_date = \ self.env[model_name].search(ks_chart_domain + [(ks_chart_groupby_relation_field, '!=', False)], limit=1, order=ks_chart_groupby_relation_field + " DESC")[ ks_chart_groupby_relation_field] except Exception as e: model_field_start_date = model_field_end_date = False pass goal_model_start_date = \ self.env['ks_dashboard_ninja.item_goal'].search(ks_goal_domain, limit=1, order='ks_goal_date ASC')['ks_goal_date'] goal_model_end_date = \ self.env['ks_dashboard_ninja.item_goal'].search(ks_goal_domain, limit=1, order='ks_goal_date DESC')['ks_goal_date'] if model_field_start_date and ttype == "date": model_field_end_date = model_field_end_date + " 23:59:59" model_field_start_date = model_field_start_date + " 00:00:00" if model_field_start_date and goal_model_start_date: goal_model_start_date = goal_model_start_date + " 00:00:00" goal_model_end_date = goal_model_end_date + " 23:59:59" if fields.datetime.strptime(model_field_start_date, '%Y-%m-%d %H:%M:%S') < fields.datetime.strptime( goal_model_start_date, '%Y-%m-%d %H:%M:%S'): ks_start_end_date['start_date'] = model_field_start_date else: ks_start_end_date['start_date'] = goal_model_start_date if fields.datetime.strptime(model_field_end_date, '%Y-%m-%d %H:%M:%S') > fields.datetime.strptime( goal_model_end_date, '%Y-%m-%d %H:%M:%S'): ks_start_end_date['end_date'] = model_field_end_date else: ks_start_end_date['end_date'] = goal_model_end_date elif model_field_start_date and not goal_model_start_date: ks_start_end_date['start_date'] = model_field_start_date ks_start_end_date['end_date'] = model_field_end_date elif goal_model_start_date and not model_field_start_date: ks_start_end_date['start_date'] = goal_model_start_date ks_start_end_date['end_date'] = goal_model_start_date else: ks_start_end_date['start_date'] = False ks_start_end_date['end_date'] = False return ks_start_end_date class KsDashboardItemsGoal(models.Model): _name = 'ks_dashboard_ninja.item_goal' _description = 'Dashboard Ninja Items Goal Lines' ks_goal_date = fields.Date(string="Date") ks_goal_value = fields.Float(string="Value") ks_dashboard_item = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") class KsDashboardItemsActions(models.Model): _name = 'ks_dashboard_ninja.item_action' _description = 'Dashboard Ninja Items Action Lines' ks_item_action_field = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('store','=',True)," "('ttype','!=','binary'),('ttype','!=','many2many'), ('ttype','!=','one2many')]", string="Action Group By") ks_item_action_field_type = fields.Char(compute="ks_get_item_action_type") ks_item_action_date_groupby = fields.Selection([('minute', 'Minute'), ('hour', 'Hour'), ('day', 'Day'), ('week', 'Week'), ('month', 'Month'), ('quarter', 'Quarter'), ('year', 'Year'), ], string="Group By Date") ks_chart_type = fields.Selection([('ks_bar_chart', 'Bar Chart'), ('ks_horizontalBar_chart', 'Horizontal Bar Chart'), ('ks_line_chart', 'Line Chart'), ('ks_area_chart', 'Area Chart'), ('ks_pie_chart', 'Pie Chart'), ('ks_doughnut_chart', 'Doughnut Chart'), ('ks_polarArea_chart', 'Polar Area Chart'), ('ks_list_view', 'List View')], string="Item Type") ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") ks_model_id = fields.Many2one('ir.model', related='ks_dashboard_item_id.ks_model_id') sequence = fields.Integer(string="Sequence") # For sorting and record limit ks_record_limit = fields.Integer(string="Record Limit") ks_sort_by_field = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('store','=',True)," "('ttype','!=','one2many'),('ttype','!=','binary')]", string="Sort By Field") ks_sort_by_order = fields.Selection([('ASC', 'Ascending'), ('DESC', 'Descending')], string="Sort Order") @api.depends('ks_item_action_field') def ks_get_item_action_type(self): for rec in self: if rec.ks_item_action_field.ttype == 'datetime' or rec.ks_item_action_field.ttype == 'date': rec.ks_item_action_field_type = 'date_type' elif rec.ks_item_action_field.ttype == 'many2one': rec.ks_item_action_field_type = 'relational_type' rec.ks_item_action_date_groupby = False elif rec.ks_item_action_field.ttype == 'selection': rec.ks_item_action_field_type = 'selection' rec.ks_item_action_date_groupby = False else: rec.ks_item_action_field_type = 'none' rec.ks_item_action_date_groupby = False @api.onchange('ks_item_action_date_groupby') def ks_check_date_group_by(self): for rec in self: if rec.ks_item_action_field.ttype == 'date' and rec.ks_item_action_date_groupby in ['hour', 'minute']: raise ValidationError(_('Action field: {} cannot be aggregated by {}').format( rec.ks_item_action_field.display_name, rec.ks_item_action_date_groupby)) @api.onchange('ks_item_action_field') def ks_onchange_item_action(self): for rec in self: if not (rec.ks_item_action_field.ttype == 'datetime' or rec.ks_item_action_field.ttype == 'date'): rec.ks_item_action_date_groupby = False