163 lines
7.2 KiB
Python
163 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
from typing import Dict, List
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
|
|
class QuickboardItem(models.Model):
|
|
_name = "quickboard.item"
|
|
_description = "Quickboard Item"
|
|
|
|
name = fields.Char(string="Name")
|
|
model_id = fields.Many2one('ir.model', string='Model')
|
|
model_name = fields.Char(related='model_id.model', string="Model Name")
|
|
icon = fields.Char(string="Icon")
|
|
type = fields.Selection(
|
|
selection=[("basic", "Basic"), ("chart", "Chart"), ("list", "List")],
|
|
string="Item Type",
|
|
default="basic")
|
|
chart_type = fields.Selection(
|
|
selection=[("bar", "Bar"), ('horizontal-bar', 'Horizontal Bar'), ('doughnut', "Doughnut"), ("line", "Line"), ("pie", "Pie"), ("polar", "Polar Area")],
|
|
string="Chart Type")
|
|
|
|
value_field_id = fields.Many2many("ir.model.fields", string="Value Field")
|
|
aggregate_function = fields.Selection(
|
|
selection=[("avg","Average"), ("count", "Count"), ('max', "Max"), ('min', "Min"), ("sum","Sum")],
|
|
string="Aggregate Function",
|
|
default="count",
|
|
depends=['value_field_id'])
|
|
|
|
dimension_field_id = fields.Many2one("ir.model.fields", string="Dimension Field")
|
|
group_field_id = fields.Many2one("ir.model.fields", string="Group Field")
|
|
datetime_granularity = fields.Selection(
|
|
selection=[("year", "Year"), ("month", "Month"), ("day", "Day")],
|
|
string="Date/Time Granularity",
|
|
default="day",
|
|
depends=['dimension_field_id'])
|
|
|
|
list_row_limit = fields.Integer(string="Row limit", default=10)
|
|
|
|
domain_filter = fields.Char(string="Filter")
|
|
|
|
# basic item color
|
|
text_color = fields.Integer("Text Color")
|
|
background_color = fields.Integer("Background Color")
|
|
|
|
# layout
|
|
x_pos = fields.Integer(string="X Pos")
|
|
y_pos = fields.Integer(string="Y Pos")
|
|
height = fields.Integer(string="Height")
|
|
width = fields.Integer(string="Width")
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for val in vals_list:
|
|
if not self.env.context.get("ai_generation", False):
|
|
if 'type' in val:
|
|
if val["type"] == "basic":
|
|
val["width"] = 2
|
|
val["height"] = 1
|
|
else:
|
|
val["width"] = 4
|
|
val["height"] = 2
|
|
|
|
sql = f"""WITH item_dim AS (
|
|
SELECT y_pos, CASE WHEN height = 0 THEN 1 ELSE height END AS height
|
|
FROM quickboard_item sdi WHERE create_uid = {self.env.uid}
|
|
)
|
|
SELECT max(y_pos + height) as max_y_pos FROM item_dim WHERE y_pos = (SELECT max(y_pos) FROM item_dim);
|
|
"""
|
|
self.env.cr.execute(sql)
|
|
res = self.env.cr.dictfetchall()
|
|
max_y_pos = res[0].get("max_y_pos")
|
|
val["y_pos"] = max_y_pos
|
|
val["x_pos"] = 0
|
|
res = super().create(vals_list)
|
|
return res
|
|
|
|
@api.onchange("type")
|
|
def clear_values(self):
|
|
for rec in self:
|
|
if rec.type:
|
|
if rec.type == 'basic':
|
|
rec.group_field_id = False
|
|
rec.dimension_field_id = False
|
|
elif rec.type == 'list':
|
|
rec.group_field_id = False
|
|
|
|
@api.constrains("aggregate_function", "value_field_id")
|
|
def _validate_aggregate_function(self):
|
|
for rec in self:
|
|
if rec.type != 'chart' and len(rec.value_field_id) > 1:
|
|
raise ValidationError(f"Basic and list items can only have one value field.")
|
|
if rec.type == 'chart':
|
|
for vf in rec.value_field_id:
|
|
if vf.ttype not in ['float', 'integer', 'monetary'] and rec.aggregate_function != "count":
|
|
raise ValidationError(f"Other fields than float, integer and monetary can only use count as aggregation.")
|
|
else:
|
|
if rec.value_field_id.ttype not in ['float', 'integer', 'monetary'] and rec.aggregate_function != "count":
|
|
raise ValidationError(f"Other fields than float, integer and monetary can only use count as aggregation.")
|
|
|
|
@api.constrains("value_field_id", "dimension_field_id")
|
|
def _validate_value_field_01(self):
|
|
for rec in self:
|
|
if rec.value_field_id and rec.dimension_field_id and rec.value_field_id == rec.dimension_field_id:
|
|
raise ValidationError("Value field must not be the same with dimension field.")
|
|
|
|
|
|
@api.constrains("dimension_field_id", "type")
|
|
def _validate_dimension_field_01(self):
|
|
for rec in self:
|
|
if rec.type in ["chart", "list"] and not rec.dimension_field_id:
|
|
raise ValidationError("Dimension field is required for charts.")
|
|
|
|
@api.constrains("list_row_limit", "type")
|
|
def _validate_dimension_field_02(self):
|
|
for rec in self:
|
|
if rec.type == "list" and not rec.list_row_limit:
|
|
raise ValidationError("Row limit is required for lists.")
|
|
|
|
@api.constrains("dimension_field_id", "datetime_granularity")
|
|
def _validate_dimension_field_03(self):
|
|
for rec in self:
|
|
if rec.dimension_field_id.ttype in ["date", "datetime"] and not rec.datetime_granularity:
|
|
raise ValidationError("Granularity for date or datetime field is required for charts.")
|
|
|
|
@api.constrains("dimension_field_id", "group_field_id")
|
|
def _validate_dimension_field_04(self):
|
|
for rec in self:
|
|
if not rec.dimension_field_id and rec.group_field_id:
|
|
raise ValidationError("Dimension field is required for grouping data.")
|
|
if rec.dimension_field_id and rec.group_field_id and rec.dimension_field_id == rec.group_field_id:
|
|
raise ValidationError("Dimension field must not be the same with grouping field.")
|
|
|
|
@api.constrains("group_field_id", "type")
|
|
def _validate_group_field_01(self):
|
|
for rec in self:
|
|
if rec.type != "chart" and rec.group_field_id:
|
|
raise ValidationError("Grouping only supported for charts.")
|
|
|
|
@api.constrains("group_field_id")
|
|
def _validate_group_field_02(self):
|
|
for rec in self:
|
|
if rec.group_field_id and rec.group_field_id.ttype in ["many2many", "one2many"]:
|
|
raise ValidationError("Grouping is not supported for x2many fields.")
|
|
|
|
@api.constrains("value_field_id", "group_field_id")
|
|
def _validate_group_field_03(self):
|
|
for rec in self:
|
|
if rec.group_field_id and len(rec.value_field_id) > 1:
|
|
raise ValidationError("Grouping is not supported when using multiple value fields.")
|
|
|
|
def web_save(self, vals, specification: Dict[str, Dict], next_id=None) -> List[Dict]:
|
|
res = super(QuickboardItem, self).web_save(vals, specification=specification, next_id=next_id)
|
|
if self.env.context.get("quick_edit", False):
|
|
self.env["bus.bus"]._sendone(
|
|
"quickboard",
|
|
"quickboard_item_updated",
|
|
{
|
|
"id": self.id,
|
|
}
|
|
)
|
|
return res
|