Perubahan desain business category

This commit is contained in:
2026-03-29 21:18:49 +07:00
parent 95aa9da5fe
commit 458121a30a
39 changed files with 713 additions and 271 deletions
+2
View File
@@ -0,0 +1,2 @@
from . import models
from .hooks import post_init_hook
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
{
"name": "GRT Business Category Base",
"summary": "Shared business category master for cross-module references",
"description": """
Central business category master module.
This module provides the shared business category model, user access context,
and reusable mixins so CRM, Sales, Purchase, Expense, and Inventory can all
reference the same category definitions.
""",
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Tools",
"version": "14.0.1.1.0",
"depends": ["base", "analytic"],
"post_init_hook": "post_init_hook",
"data": [
"security/ir.model.access.csv",
"security/ir.rule.csv",
"views/crm_business_category_views.xml",
"views/res_users_business_category_views.xml"
],
"installable": True,
"application": False
}
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record id="crm_business_category_01" model="crm.business.category">
<field name="name">Business Category 1</field>
<field name="code">BC01</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="crm_business_category_02" model="crm.business.category">
<field name="name">Business Category 2</field>
<field name="code">BC02</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="crm_business_category_03" model="crm.business.category">
<field name="name">Business Category 3</field>
<field name="code">BC03</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="crm_business_category_04" model="crm.business.category">
<field name="name">Business Category 4</field>
<field name="code">BC04</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="crm_business_category_05" model="crm.business.category">
<field name="name">Business Category 5</field>
<field name="code">BC05</field>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="crm_business_category_06" model="crm.business.category">
<field name="name">Business Category 6</field>
<field name="code">BC06</field>
<field name="company_id" ref="base.main_company"/>
</record>
</odoo>
+162
View File
@@ -0,0 +1,162 @@
from odoo import SUPERUSER_ID, api
SEED_CATEGORIES = [
("crm_business_category_01", "Business Category 1", "BC01"),
("crm_business_category_02", "Business Category 2", "BC02"),
("crm_business_category_03", "Business Category 3", "BC03"),
("crm_business_category_04", "Business Category 4", "BC04"),
("crm_business_category_05", "Business Category 5", "BC05"),
("crm_business_category_06", "Business Category 6", "BC06"),
]
SHARED_XMLID_NAMES = [
"view_crm_business_category_tree",
"view_crm_business_category_form",
"action_crm_business_category",
"view_res_users_business_category_tree",
"view_res_users_business_category_form",
"action_res_users_business_category_access",
"action_sync_team_business_category_access_server",
"menu_crm_business_category",
"menu_res_users_business_category_access",
]
def _get_xmlid_map(env, module, names):
data = env["ir.model.data"].sudo().search(
[("module", "=", module), ("name", "in", names)]
)
return {record.name: record for record in data}
def _ensure_xmlid(env, module, name, model, res_id, noupdate=True):
xmlid = env["ir.model.data"].sudo().search(
[("module", "=", module), ("name", "=", name)], limit=1
)
values = {
"module": module,
"name": name,
"model": model,
"res_id": res_id,
"noupdate": noupdate,
}
if xmlid:
xmlid.write(values)
else:
env["ir.model.data"].sudo().create(values)
def _cleanup_duplicate_record(env, xmlid_record, keep_res_id):
if not xmlid_record or xmlid_record.res_id == keep_res_id:
return
model = env[xmlid_record.model].sudo()
duplicate = model.browse(xmlid_record.res_id)
if duplicate.exists():
duplicate.unlink()
def _migrate_seed_categories(env):
company = env.ref("base.main_company")
category_model = env["crm.business.category"].sudo()
base_xmlids = _get_xmlid_map(
env, "grt_business_category_base", [name for name, _, _ in SEED_CATEGORIES]
)
old_xmlids = _get_xmlid_map(
env, "grt_crm_business_category", [name for name, _, _ in SEED_CATEGORIES]
)
for xmlid_name, category_name, code in SEED_CATEGORIES:
chosen = False
old_xmlid = old_xmlids.get(xmlid_name)
base_xmlid = base_xmlids.get(xmlid_name)
if old_xmlid:
chosen = category_model.browse(old_xmlid.res_id)
elif base_xmlid:
chosen = category_model.browse(base_xmlid.res_id)
else:
chosen = category_model.search(
[("company_id", "=", company.id), "|", ("code", "=", code), ("name", "=", category_name)],
limit=1,
)
if not chosen:
chosen = category_model.create(
{
"name": category_name,
"code": code,
"company_id": company.id,
}
)
if not chosen.code:
chosen.code = code
_ensure_xmlid(
env, "grt_business_category_base", xmlid_name, "crm.business.category", chosen.id
)
_ensure_xmlid(
env, "grt_crm_business_category", xmlid_name, "crm.business.category", chosen.id
)
_cleanup_duplicate_record(env, base_xmlid, chosen.id)
def _migrate_shared_xmlids(env):
base_xmlids = _get_xmlid_map(env, "grt_business_category_base", SHARED_XMLID_NAMES)
old_xmlids = _get_xmlid_map(env, "grt_crm_business_category", SHARED_XMLID_NAMES)
for xmlid_name in SHARED_XMLID_NAMES:
old_xmlid = old_xmlids.get(xmlid_name)
base_xmlid = base_xmlids.get(xmlid_name)
canonical = old_xmlid or base_xmlid
if not canonical:
continue
_ensure_xmlid(
env,
"grt_business_category_base",
xmlid_name,
canonical.model,
canonical.res_id,
noupdate=canonical.noupdate,
)
_ensure_xmlid(
env,
"grt_crm_business_category",
xmlid_name,
canonical.model,
canonical.res_id,
noupdate=canonical.noupdate,
)
if old_xmlid and base_xmlid and old_xmlid.res_id != base_xmlid.res_id:
_cleanup_duplicate_record(env, base_xmlid, old_xmlid.res_id)
def _cleanup_obsolete_crm_security(env):
obsolete_names = [
"access_crm_business_category_user",
"access_crm_business_category_manager",
"crm_business_category_rule_user",
"crm_business_category_rule_manager",
]
obsolete = env["ir.model.data"].sudo().search(
[("module", "=", "grt_crm_business_category"), ("name", "in", obsolete_names)]
)
for record in obsolete:
target = env[record.model].sudo().browse(record.res_id)
if target.exists():
target.unlink()
obsolete.unlink()
def post_init_hook(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
_migrate_seed_categories(env)
_migrate_shared_xmlids(env)
_cleanup_obsolete_crm_security(env)
@@ -0,0 +1,3 @@
from . import business_category_mixin
from . import crm_business_category
from . import res_users
@@ -0,0 +1,46 @@
from odoo import api, fields, models
class BusinessCategoryMixin(models.AbstractModel):
_name = "business.category.mixin"
_description = "Business Category Mixin"
@api.model
def _default_business_category_id(self):
cr = self.env.cr
cr.execute(
"""
SELECT 1
FROM information_schema.columns
WHERE table_name = 'res_users' AND column_name = 'active_business_category_id'
"""
)
has_active = bool(cr.fetchone())
cr.execute(
"""
SELECT 1
FROM information_schema.columns
WHERE table_name = 'res_users' AND column_name = 'default_business_category_id'
"""
)
has_default = bool(cr.fetchone())
if not has_active and not has_default:
return False
user = self.env.user
if has_active and user.active_business_category_id.company_id == self.env.company:
return user.active_business_category_id.id
if has_default and user.default_business_category_id.company_id == self.env.company:
return user.default_business_category_id.id
return False
business_category_id = fields.Many2one(
"crm.business.category",
string="Business Category",
default=_default_business_category_id,
required=True,
ondelete="restrict",
index=True,
domain="[('company_id', '=', company_id)]",
)
@@ -0,0 +1,58 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class CrmBusinessCategory(models.Model):
_name = "crm.business.category"
_description = "Business Category"
_order = "name"
def init(self):
self._cr.execute(
"""
UPDATE crm_business_category
SET company_id = %s
WHERE company_id IS NULL
""",
[self.env.ref("base.main_company").id],
)
name = fields.Char(required=True)
code = fields.Char()
company_id = fields.Many2one(
"res.company",
string="Company",
required=True,
default=lambda self: self.env.company,
index=True,
)
active = fields.Boolean(default=True)
description = fields.Text()
analytic_account_id = fields.Many2one(
"account.analytic.account",
string="Analytic Account",
domain="[('company_id', '=', company_id)]",
ondelete="restrict",
help="Shared default analytic account used by modules that reference this business category.",
)
_sql_constraints = [
(
"crm_business_category_name_company_uniq",
"unique(name, company_id)",
"Business category name must be unique per company.",
),
]
@api.constrains("company_id", "analytic_account_id")
def _check_analytic_account_company(self):
for category in self:
if not category.analytic_account_id or not category.company_id:
continue
if category.analytic_account_id.company_id != category.company_id:
raise ValidationError(
_(
"Business Category '%s' must use an Analytic Account from company '%s'."
)
% (category.name, category.company_id.name)
)
@@ -0,0 +1,196 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class ResUsers(models.Model):
_inherit = "res.users"
allowed_business_category_ids = fields.Many2many(
"crm.business.category",
"res_users_crm_business_category_rel",
"user_id",
"business_category_id",
string="Allowed Business Categories",
domain="[('company_id', 'in', company_ids)]",
help="Users can only access records in these business categories.",
)
team_business_category_ids = fields.Many2many(
"crm.business.category",
string="Team Business Categories",
compute="_compute_effective_business_category_ids",
readonly=True,
help="Business categories inherited automatically from team membership.",
)
effective_business_category_ids = fields.Many2many(
"crm.business.category",
string="Effective Business Categories",
compute="_compute_effective_business_category_ids",
readonly=True,
help="Union of manual access and team-based access.",
)
default_business_category_id = fields.Many2one(
"crm.business.category",
string="Default Business Category",
domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]",
help="Default category for new records.",
)
active_business_category_id = fields.Many2one(
"crm.business.category",
string="Active Business Category",
domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]",
help="Current user context category, similar to active company.",
)
def _build_or_domain(self, domain_parts):
if not domain_parts:
return []
if len(domain_parts) == 1:
return domain_parts
return ["|"] * (len(domain_parts) - 1) + domain_parts
def _get_team_business_categories_from_model(self, model_name, domain_parts):
self.ensure_one()
if model_name not in self.env:
return self.env["crm.business.category"]
team_model = self.env[model_name].sudo()
user_id = self._origin.id or self.id
if not isinstance(user_id, int):
return self.env["crm.business.category"]
valid_domain_parts = [
domain_part
for domain_part in domain_parts
if isinstance(domain_part, (list, tuple))
and len(domain_part) >= 1
and domain_part[0] in team_model._fields
]
if not valid_domain_parts:
return self.env["crm.business.category"]
domain = self._build_or_domain(valid_domain_parts)
teams = team_model.search(domain + [("company_id", "in", self.company_ids.ids)])
return teams.mapped("business_category_id")
def _get_team_business_categories(self):
self.ensure_one()
categories = self.env["crm.business.category"]
categories |= self._get_team_business_categories_from_model(
"crm.team",
[
("user_id", "=", self.id),
("member_ids", "in", self.id),
("sale_team_leader_id", "=", self.id),
("team_members_ids", "in", self.id),
],
)
categories |= self._get_team_business_categories_from_model(
"purchase.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
categories |= self._get_team_business_categories_from_model(
"expense.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
categories |= self._get_team_business_categories_from_model(
"stock.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
return categories
def _filter_business_categories_by_company(self, categories):
self.ensure_one()
return categories.filtered(lambda category: category.company_id in self.company_ids)
@api.depends("allowed_business_category_ids", "company_ids")
def _compute_effective_business_category_ids(self):
for user in self:
team_categories = user._get_team_business_categories()
allowed_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
)
user.team_business_category_ids = team_categories
user.effective_business_category_ids = allowed_categories | team_categories
@api.onchange("allowed_business_category_ids", "company_ids")
def _onchange_allowed_business_category_ids(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
if user.default_business_category_id not in effective_categories:
user.default_business_category_id = False
if user.active_business_category_id not in effective_categories:
user.active_business_category_id = False
if effective_categories and not user.default_business_category_id:
user.default_business_category_id = effective_categories[0]
if effective_categories and not user.active_business_category_id:
user.active_business_category_id = user.default_business_category_id
@api.constrains(
"allowed_business_category_ids",
"default_business_category_id",
"active_business_category_id",
)
def _check_business_category_consistency(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
if (
user.default_business_category_id
and user.default_business_category_id not in effective_categories
):
raise ValidationError(
_("Default Business Category must be included in Effective Business Categories.")
)
if (
user.default_business_category_id
and user.default_business_category_id.company_id not in user.company_ids
):
raise ValidationError(
_("Default Business Category must belong to one of the user's allowed companies.")
)
if (
user.active_business_category_id
and user.active_business_category_id not in effective_categories
):
raise ValidationError(
_("Active Business Category must be included in Effective Business Categories.")
)
if (
user.active_business_category_id
and user.active_business_category_id.company_id not in user.company_ids
):
raise ValidationError(
_("Active Business Category must belong to one of the user's allowed companies.")
)
def action_sync_team_business_category_access(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
first_category = effective_categories[:1]
vals = {}
if user.default_business_category_id not in effective_categories:
vals["default_business_category_id"] = first_category.id if first_category else False
elif not user.default_business_category_id and first_category:
vals["default_business_category_id"] = first_category.id
default_id = vals.get("default_business_category_id") or user.default_business_category_id.id
if user.active_business_category_id not in effective_categories:
vals["active_business_category_id"] = default_id or (
first_category.id if first_category else False
)
elif not user.active_business_category_id:
vals["active_business_category_id"] = default_id or (
first_category.id if first_category else False
)
if vals:
user.write(vals)
return {"type": "ir.actions.client", "tag": "reload"}
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_crm_business_category_user,crm.business.category.user,model_crm_business_category,base.group_user,1,0,0,0
access_crm_business_category_manager,crm.business.category.manager,model_crm_business_category,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_crm_business_category_user crm.business.category.user model_crm_business_category base.group_user 1 0 0 0
3 access_crm_business_category_manager crm.business.category.manager model_crm_business_category base.group_system 1 1 1 1
@@ -0,0 +1,3 @@
id,name,model_id:id,domain_force,groups:id,perm_read,perm_write,perm_create,perm_unlink
crm_business_category_rule_user,Business Category by user effective list,model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",base.group_user,1,0,0,0
crm_business_category_rule_manager,Business Category full access for system admin,model_crm_business_category,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
2 crm_business_category_rule_user Business Category by user effective list model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] base.group_user 1 0 0 0
3 crm_business_category_rule_manager Business Category full access for system admin model_crm_business_category [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_crm_business_category_tree" model="ir.ui.view">
<field name="name">crm.business.category.tree</field>
<field name="model">crm.business.category</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="code"/>
<field name="company_id"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="view_crm_business_category_form" model="ir.ui.view">
<field name="name">crm.business.category.form</field>
<field name="model">crm.business.category</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
<field name="code"/>
<field name="company_id"/>
<field name="active"/>
</group>
<group string="Accounting">
<field name="analytic_account_id" domain="[('company_id', '=', company_id)]"/>
</group>
<group>
<field name="description"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_crm_business_category" model="ir.actions.act_window">
<field name="name">Business Categories</field>
<field name="res_model">crm.business.category</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_crm_business_category"
name="Business Categories"
parent="base.menu_administration"
action="action_crm_business_category"
sequence="85"
groups="base.group_system"/>
</odoo>
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_res_users_business_category_tree" model="ir.ui.view">
<field name="name">res.users.business.category.tree</field>
<field name="model">res.users</field>
<field name="arch" type="xml">
<tree>
<button name="action_sync_team_business_category_access" type="object" string="Sync" class="btn-link"/>
<field name="name"/>
<field name="login"/>
<field name="active"/>
<field name="company_id"/>
<field name="team_business_category_ids" widget="many2many_tags"/>
<field name="allowed_business_category_ids" widget="many2many_tags"/>
<field name="effective_business_category_ids" widget="many2many_tags"/>
<field name="default_business_category_id"/>
<field name="active_business_category_id"/>
</tree>
</field>
</record>
<record id="view_res_users_business_category_form" model="ir.ui.view">
<field name="name">res.users.business.category.form</field>
<field name="model">res.users</field>
<field name="arch" type="xml">
<form string="User Business Category Access">
<header>
<button
name="action_sync_team_business_category_access"
type="object"
string="Sync Team Access"
class="oe_highlight"
/>
</header>
<sheet>
<group>
<field name="name"/>
<field name="login"/>
<field name="active"/>
<field name="company_id"/>
<field name="company_ids" widget="many2many_tags"/>
</group>
<group string="Business Category Access">
<field name="team_business_category_ids" widget="many2many_tags" readonly="1"/>
<field name="allowed_business_category_ids" widget="many2many_tags" domain="[('company_id', 'in', company_ids)]"/>
<field name="effective_business_category_ids" widget="many2many_tags" readonly="1"/>
<field name="default_business_category_id" domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]"/>
<field name="active_business_category_id" domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_res_users_business_category_access" model="ir.actions.act_window">
<field name="name">User Business Category Access</field>
<field name="res_model">res.users</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('share', '=', False)]</field>
</record>
<record id="action_sync_team_business_category_access_server" model="ir.actions.server">
<field name="name">Sync Team Category Access</field>
<field name="model_id" ref="base.model_res_users"/>
<field name="binding_model_id" ref="base.model_res_users"/>
<field name="binding_view_types">list,form</field>
<field name="state">code</field>
<field name="code">records.action_sync_team_business_category_access()</field>
</record>
<menuitem id="menu_res_users_business_category_access"
name="User Category Access"
parent="base.menu_administration"
action="action_res_users_business_category_access"
sequence="86"
groups="base.group_system"/>
</odoo>
+3 -6
View File
@@ -9,23 +9,20 @@ This enables different staging flow per business category through team pipelines
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Sales/CRM",
"version": "14.0.2.10.1",
"depends": ["crm"],
"version": "14.0.2.11.0",
"depends": ["crm", "grt_business_category_base"],
"data": [
"security/ir.model.access.csv",
"security/ir.rule.csv",
"data/crm_business_category_data.xml",
"views/assets.xml",
"views/crm_activity_history_views.xml",
"views/crm_business_category_views.xml",
"views/crm_lead_views.xml",
"views/crm_pipeline_report_views.xml",
"views/crm_menu_views.xml",
"views/crm_stage_views.xml",
"views/crm_team_views.xml",
"views/crm_team_business_category_views.xml",
"views/mail_activity_views.xml",
"views/res_users_business_category_views.xml",
"views/mail_activity_views.xml"
],
"installable": True,
"application": False,
@@ -1,5 +1,3 @@
from . import crm_business_category
from . import business_category_mixin
from . import crm_team
from . import crm_stage
from . import crm_lead
+1 -174
View File
@@ -1,5 +1,4 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo import fields, models
class ResUsers(models.Model):
@@ -10,175 +9,3 @@ class ResUsers(models.Model):
last_gps_client_time = fields.Char(string="Last GPS Client Time", readonly=True)
last_gps_client_tz = fields.Char(string="Last GPS Client TZ", readonly=True)
last_gps_recorded_at = fields.Datetime(string="Last GPS Recorded At", readonly=True)
allowed_business_category_ids = fields.Many2many(
"crm.business.category",
"res_users_crm_business_category_rel",
"user_id",
"business_category_id",
string="Allowed Business Categories",
domain="[('company_id', 'in', company_ids)]",
help="Users can only access CRM data in these business categories.",
)
team_business_category_ids = fields.Many2many(
"crm.business.category",
string="Team Business Categories",
compute="_compute_effective_business_category_ids",
readonly=True,
help="Business categories inherited automatically from Sales Team membership.",
)
effective_business_category_ids = fields.Many2many(
"crm.business.category",
string="Effective Business Categories",
compute="_compute_effective_business_category_ids",
readonly=True,
help="Union of manual access and Sales Team-based access.",
)
default_business_category_id = fields.Many2one(
"crm.business.category",
string="Default Business Category",
domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]",
help="Default category for new records.",
)
active_business_category_id = fields.Many2one(
"crm.business.category",
string="Active Business Category",
domain="[('id', 'in', effective_business_category_ids), ('company_id', 'in', company_ids)]",
help="Current user context category, similar to active company.",
)
def _build_or_domain(self, domain_parts):
if not domain_parts:
return []
if len(domain_parts) == 1:
return domain_parts
return ["|"] * (len(domain_parts) - 1) + domain_parts
def _get_team_business_categories_from_model(self, model_name, domain_parts):
self.ensure_one()
if model_name not in self.env:
return self.env["crm.business.category"]
team_model = self.env[model_name].sudo()
user_id = self._origin.id or self.id
if not isinstance(user_id, int):
return self.env["crm.business.category"]
valid_domain_parts = [
domain_part
for domain_part in domain_parts
if isinstance(domain_part, (list, tuple))
and len(domain_part) >= 1
and domain_part[0] in team_model._fields
]
if not valid_domain_parts:
return self.env["crm.business.category"]
domain = self._build_or_domain(valid_domain_parts)
teams = team_model.search(domain + [("company_id", "in", self.company_ids.ids)])
return teams.mapped("business_category_id")
def _get_team_business_categories(self):
self.ensure_one()
categories = self.env["crm.business.category"]
categories |= self._get_team_business_categories_from_model(
"crm.team",
[
("user_id", "=", self.id),
("member_ids", "in", self.id),
("sale_team_leader_id", "=", self.id),
("team_members_ids", "in", self.id),
],
)
categories |= self._get_team_business_categories_from_model(
"purchase.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
categories |= self._get_team_business_categories_from_model(
"expense.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
categories |= self._get_team_business_categories_from_model(
"stock.team",
[("user_id", "=", self.id), ("member_ids", "in", self.id)],
)
return categories
def _filter_business_categories_by_company(self, categories):
self.ensure_one()
return categories.filtered(lambda category: category.company_id in self.company_ids)
@api.depends("allowed_business_category_ids", "company_ids")
def _compute_effective_business_category_ids(self):
for user in self:
team_categories = user._get_team_business_categories()
allowed_categories = user._filter_business_categories_by_company(user.allowed_business_category_ids)
user.team_business_category_ids = team_categories
user.effective_business_category_ids = allowed_categories | team_categories
@api.onchange("allowed_business_category_ids", "company_ids")
def _onchange_allowed_business_category_ids(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
if user.default_business_category_id not in effective_categories:
user.default_business_category_id = False
if user.active_business_category_id not in effective_categories:
user.active_business_category_id = False
if effective_categories and not user.default_business_category_id:
user.default_business_category_id = effective_categories[0]
if effective_categories and not user.active_business_category_id:
user.active_business_category_id = user.default_business_category_id
@api.constrains(
"allowed_business_category_ids",
"default_business_category_id",
"active_business_category_id",
)
def _check_business_category_consistency(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
if user.default_business_category_id and user.default_business_category_id not in effective_categories:
raise ValidationError(
_("Default Business Category must be included in Effective Business Categories.")
)
if user.default_business_category_id and user.default_business_category_id.company_id not in user.company_ids:
raise ValidationError(
_("Default Business Category must belong to one of the user's allowed companies.")
)
if user.active_business_category_id and user.active_business_category_id not in effective_categories:
raise ValidationError(
_("Active Business Category must be included in Effective Business Categories.")
)
if user.active_business_category_id and user.active_business_category_id.company_id not in user.company_ids:
raise ValidationError(
_("Active Business Category must belong to one of the user's allowed companies.")
)
def action_sync_team_business_category_access(self):
for user in self:
effective_categories = user._filter_business_categories_by_company(
user.allowed_business_category_ids
) | user._get_team_business_categories()
first_category = effective_categories[:1]
vals = {}
if user.default_business_category_id not in effective_categories:
vals["default_business_category_id"] = first_category.id if first_category else False
elif not user.default_business_category_id and first_category:
vals["default_business_category_id"] = first_category.id
default_id = vals.get("default_business_category_id") or user.default_business_category_id.id
if user.active_business_category_id not in effective_categories:
vals["active_business_category_id"] = default_id or (first_category.id if first_category else False)
elif not user.active_business_category_id:
vals["active_business_category_id"] = default_id or (first_category.id if first_category else False)
if vals:
user.write(vals)
return {"type": "ir.actions.client", "tag": "reload"}
@@ -1,6 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_crm_business_category_user,crm.business.category.user,model_crm_business_category,crm.group_use_lead,1,0,0,0
access_crm_business_category_manager,crm.business.category.manager,model_crm_business_category,sales_team.group_sale_manager,1,1,1,1
access_crm_activity_history_user,crm.activity.history.user,model_crm_activity_history,crm.group_use_lead,1,0,0,0
access_crm_activity_history_manager,crm.activity.history.manager,model_crm_activity_history,sales_team.group_sale_manager,1,1,1,1
access_crm_activity_history_sysadmin,crm.activity.history.sysadmin,model_crm_activity_history,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
access_crm_business_category_user crm.business.category.user model_crm_business_category crm.group_use_lead 1 0 0 0
access_crm_business_category_manager crm.business.category.manager model_crm_business_category sales_team.group_sale_manager 1 1 1 1
2 access_crm_activity_history_user crm.activity.history.user model_crm_activity_history crm.group_use_lead 1 0 0 0
3 access_crm_activity_history_manager crm.activity.history.manager model_crm_activity_history sales_team.group_sale_manager 1 1 1 1
4 access_crm_activity_history_sysadmin crm.activity.history.sysadmin model_crm_activity_history base.group_system 1 1 1 1
@@ -2,10 +2,8 @@ id,name,model_id:id,domain_force,groups:id,perm_read,perm_write,perm_create,perm
crm_lead_business_category_rule_user_read_create,CRM Lead read/create by effective business category,crm.model_crm_lead,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",crm.group_use_lead,1,0,1,0
crm_lead_business_category_rule_user_write_own,CRM Lead write own by effective business category,crm.model_crm_lead,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids),'|',('user_id','=',user.id),('create_uid','=',user.id)]",crm.group_use_lead,0,1,0,1
crm_team_business_category_rule_user,CRM Team read by effective business category,sales_team.model_crm_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",crm.group_use_lead,1,0,0,0
crm_business_category_rule_user,Business Category by user effective list,model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",crm.group_use_lead,1,0,0,0
crm_lead_business_category_rule_manager,CRM Lead full access for manager in effective business category,crm.model_crm_lead,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_team_business_category_rule_manager,CRM Team full access for manager in effective business category,sales_team.model_crm_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_business_category_rule_manager,Business Category access for manager in effective business category,model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_activity_history_rule_user,CRM Activity History by effective business category,model_crm_activity_history,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",crm.group_use_lead,1,0,0,0
crm_activity_history_rule_manager,CRM Activity History full access for manager in effective business category,model_crm_activity_history,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_team_business_category_rule_sysadmin,CRM Team full access for system admin,sales_team.model_crm_team,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
2 crm_lead_business_category_rule_user_read_create CRM Lead read/create by effective business category crm.model_crm_lead [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] crm.group_use_lead 1 0 1 0
3 crm_lead_business_category_rule_user_write_own CRM Lead write own by effective business category crm.model_crm_lead [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids),'|',('user_id','=',user.id),('create_uid','=',user.id)] crm.group_use_lead 0 1 0 1
4 crm_team_business_category_rule_user CRM Team read by effective business category sales_team.model_crm_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] crm.group_use_lead 1 0 0 0
crm_business_category_rule_user Business Category by user effective list model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] crm.group_use_lead 1 0 0 0
5 crm_lead_business_category_rule_manager CRM Lead full access for manager in effective business category crm.model_crm_lead [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
6 crm_team_business_category_rule_manager CRM Team full access for manager in effective business category sales_team.model_crm_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
crm_business_category_rule_manager Business Category access for manager in effective business category model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
7 crm_activity_history_rule_user CRM Activity History by effective business category model_crm_activity_history [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] crm.group_use_lead 1 0 0 0
8 crm_activity_history_rule_manager CRM Activity History full access for manager in effective business category model_crm_activity_history [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
9 crm_team_business_category_rule_sysadmin CRM Team full access for system admin sales_team.model_crm_team [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
@@ -10,16 +10,15 @@ for expense transactions and accounting entries.
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Human Resources/Expenses",
"version": "14.0.1.0.0",
"version": "14.0.1.1.0",
"depends": [
"hr_expense",
"account",
"grt_crm_business_category",
"grt_business_category_base",
],
"data": [
"security/ir.model.access.csv",
"security/ir.rule.csv",
"views/crm_business_category_views.xml",
"views/expense_team_views.xml",
"views/hr_expense_views.xml",
"views/expense_report_business_category_views.xml",
@@ -1,5 +1,4 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo import fields, models
class CrmBusinessCategory(models.Model):
@@ -8,20 +7,7 @@ class CrmBusinessCategory(models.Model):
expense_analytic_account_id = fields.Many2one(
"account.analytic.account",
string="Expense Analytic Account",
domain="[('company_id', '=', company_id)]",
ondelete="restrict",
help="Default analytic account used for expense transactions in this business category.",
related="analytic_account_id",
readonly=False,
help="Alias to the shared analytic account used for this business category.",
)
@api.constrains("company_id", "expense_analytic_account_id")
def _check_expense_analytic_account_company(self):
for category in self:
if not category.expense_analytic_account_id or not category.company_id:
continue
if category.expense_analytic_account_id.company_id != category.company_id:
raise ValidationError(
_(
"Business Category '%s' must use an Expense Analytic Account from company '%s'."
)
% (category.name, category.company_id.name)
)
@@ -9,9 +9,9 @@ hr_expense_sheet_business_category_rule_sysadmin,Expense Report full access for
expense_team_business_category_rule_user,Expense Team read by effective business category,model_expense_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_user,1,0,0,0
expense_team_business_category_rule_manager,Expense Team full access for expense manager in effective business category,model_expense_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_manager,1,1,1,1
expense_team_business_category_rule_sysadmin,Expense Team full access for system admin,model_expense_team,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
crm_business_category_rule_expense_user,Business Category by user effective list for expense user,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_user,1,0,0,0
crm_business_category_rule_expense_manager,Business Category access for expense manager in effective business category,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_manager,1,1,1,1
crm_business_category_rule_expense_sysadmin,Business Category full access for system admin,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
crm_business_category_rule_expense_user,Business Category by user effective list for expense user,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_user,1,0,0,0
crm_business_category_rule_expense_manager,Business Category access for expense manager in effective business category,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_manager,1,1,1,1
crm_business_category_rule_expense_sysadmin,Business Category full access for system admin,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
account_move_expense_business_category_rule_user,Journal Entry read by effective business category for expense user,account.model_account_move,"[('company_id','in',user.company_ids.ids),('expense_business_category_id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_user,1,0,0,0
account_move_expense_business_category_rule_manager,Journal Entry access for expense manager in effective business category,account.model_account_move,"[('company_id','in',user.company_ids.ids),('expense_business_category_id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_manager,1,1,1,1
account_move_line_expense_business_category_rule_user,Journal Item read by effective business category for expense user,account.model_account_move_line,"[('company_id','in',user.company_ids.ids),('move_id.expense_business_category_id','in',user.effective_business_category_ids.ids)]",hr_expense.group_hr_expense_user,1,0,0,0
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
9 expense_team_business_category_rule_user Expense Team read by effective business category model_expense_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_user 1 0 0 0
10 expense_team_business_category_rule_manager Expense Team full access for expense manager in effective business category model_expense_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_manager 1 1 1 1
11 expense_team_business_category_rule_sysadmin Expense Team full access for system admin model_expense_team [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
12 crm_business_category_rule_expense_user Business Category by user effective list for expense user grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_user 1 0 0 0
13 crm_business_category_rule_expense_manager Business Category access for expense manager in effective business category grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_manager 1 1 1 1
14 crm_business_category_rule_expense_sysadmin Business Category full access for system admin grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
15 account_move_expense_business_category_rule_user Journal Entry read by effective business category for expense user account.model_account_move [('company_id','in',user.company_ids.ids),('expense_business_category_id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_user 1 0 0 0
16 account_move_expense_business_category_rule_manager Journal Entry access for expense manager in effective business category account.model_account_move [('company_id','in',user.company_ids.ids),('expense_business_category_id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_manager 1 1 1 1
17 account_move_line_expense_business_category_rule_user Journal Item read by effective business category for expense user account.model_account_move_line [('company_id','in',user.company_ids.ids),('move_id.expense_business_category_id','in',user.effective_business_category_ids.ids)] hr_expense.group_hr_expense_user 1 0 0 0
@@ -3,7 +3,7 @@
<record id="view_crm_business_category_form_expense_analytic" model="ir.ui.view">
<field name="name">crm.business.category.form.expense.analytic</field>
<field name="model">crm.business.category</field>
<field name="inherit_id" ref="grt_crm_business_category.view_crm_business_category_form"/>
<field name="inherit_id" ref="grt_business_category_base.view_crm_business_category_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='description']/.." position="before">
<group string="Expenses">
@@ -11,6 +11,6 @@
name="Business Categories"
parent="hr_expense.menu_hr_expense_root"
sequence="46"
action="grt_crm_business_category.action_crm_business_category"
action="grt_business_category_base.action_crm_business_category"
groups="hr_expense.group_hr_expense_manager"/>
</odoo>
@@ -10,19 +10,18 @@ propagation for stock valuation journal entries.
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Inventory",
"version": "14.0.1.0.0",
"version": "14.0.1.1.1",
"depends": [
"stock_account",
"sale_stock",
"purchase_stock",
"grt_crm_business_category",
"grt_business_category_base",
"grt_sales_business_category",
"grt_purchase_business_category",
],
"data": [
"security/ir.model.access.csv",
"security/ir.rule.csv",
"views/crm_business_category_views.xml",
"views/stock_team_views.xml",
"views/stock_warehouse_views.xml",
"views/stock_picking_views.xml",
@@ -1,5 +1,4 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo import fields, models
class CrmBusinessCategory(models.Model):
@@ -8,20 +7,7 @@ class CrmBusinessCategory(models.Model):
inventory_analytic_account_id = fields.Many2one(
"account.analytic.account",
string="Inventory Analytic Account",
domain="[('company_id', '=', company_id)]",
ondelete="restrict",
help="Default analytic account used for stock valuation entries in this business category.",
related="analytic_account_id",
readonly=False,
help="Alias to the shared analytic account used for this business category.",
)
@api.constrains("company_id", "inventory_analytic_account_id")
def _check_inventory_analytic_account_company(self):
for category in self:
if not category.inventory_analytic_account_id or not category.company_id:
continue
if category.inventory_analytic_account_id.company_id != category.company_id:
raise ValidationError(
_(
"Business Category '%s' must use an Inventory Analytic Account from company '%s'."
)
% (category.name, category.company_id.name)
)
@@ -9,10 +9,10 @@ class ProductTemplate(models.Model):
"crm.business.category",
string="Business Category",
default=lambda self: self.env["business.category.mixin"]._default_business_category_id(),
required=True,
ondelete="restrict",
index=True,
domain="[('company_id', '=', company_id)]",
help="Shared business category for operational products. System-generated products may leave this empty.",
)
@api.onchange("business_category_id")
@@ -12,9 +12,9 @@ stock_warehouse_business_category_rule_sysadmin,Warehouse full access for system
stock_team_business_category_rule_user,Inventory Team read by effective business category,model_stock_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",stock.group_stock_user,1,0,0,0
stock_team_business_category_rule_manager,Inventory Team full access for inventory manager in effective business category,model_stock_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",stock.group_stock_manager,1,1,1,1
stock_team_business_category_rule_sysadmin,Inventory Team full access for system admin,model_stock_team,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
crm_business_category_rule_inventory_user,Business Category by user effective list for inventory user,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",stock.group_stock_user,1,0,0,0
crm_business_category_rule_inventory_manager,Business Category access for inventory manager in effective business category,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",stock.group_stock_manager,1,1,1,1
crm_business_category_rule_inventory_sysadmin,Business Category full access for system admin,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
crm_business_category_rule_inventory_user,Business Category by user effective list for inventory user,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",stock.group_stock_user,1,0,0,0
crm_business_category_rule_inventory_manager,Business Category access for inventory manager in effective business category,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",stock.group_stock_manager,1,1,1,1
crm_business_category_rule_inventory_sysadmin,Business Category full access for system admin,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
account_move_inventory_business_category_rule_user,Journal Entry read by effective business category for inventory user,account.model_account_move,"[('company_id','in',user.company_ids.ids),('inventory_business_category_id','in',user.effective_business_category_ids.ids)]",stock.group_stock_user,1,0,0,0
account_move_inventory_business_category_rule_manager,Journal Entry access for inventory manager in effective business category,account.model_account_move,"[('company_id','in',user.company_ids.ids),('inventory_business_category_id','in',user.effective_business_category_ids.ids)]",stock.group_stock_manager,1,1,1,1
account_move_line_inventory_business_category_rule_user,Journal Item read by effective business category for inventory user,account.model_account_move_line,"[('company_id','in',user.company_ids.ids),('move_id.inventory_business_category_id','in',user.effective_business_category_ids.ids)]",stock.group_stock_user,1,0,0,0
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
12 stock_team_business_category_rule_user Inventory Team read by effective business category model_stock_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] stock.group_stock_user 1 0 0 0
13 stock_team_business_category_rule_manager Inventory Team full access for inventory manager in effective business category model_stock_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] stock.group_stock_manager 1 1 1 1
14 stock_team_business_category_rule_sysadmin Inventory Team full access for system admin model_stock_team [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
15 crm_business_category_rule_inventory_user Business Category by user effective list for inventory user grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] stock.group_stock_user 1 0 0 0
16 crm_business_category_rule_inventory_manager Business Category access for inventory manager in effective business category grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] stock.group_stock_manager 1 1 1 1
17 crm_business_category_rule_inventory_sysadmin Business Category full access for system admin grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
18 account_move_inventory_business_category_rule_user Journal Entry read by effective business category for inventory user account.model_account_move [('company_id','in',user.company_ids.ids),('inventory_business_category_id','in',user.effective_business_category_ids.ids)] stock.group_stock_user 1 0 0 0
19 account_move_inventory_business_category_rule_manager Journal Entry access for inventory manager in effective business category account.model_account_move [('company_id','in',user.company_ids.ids),('inventory_business_category_id','in',user.effective_business_category_ids.ids)] stock.group_stock_manager 1 1 1 1
20 account_move_line_inventory_business_category_rule_user Journal Item read by effective business category for inventory user account.model_account_move_line [('company_id','in',user.company_ids.ids),('move_id.inventory_business_category_id','in',user.effective_business_category_ids.ids)] stock.group_stock_user 1 0 0 0
@@ -3,7 +3,7 @@
<record id="view_crm_business_category_form_inventory_analytic" model="ir.ui.view">
<field name="name">crm.business.category.form.inventory.analytic</field>
<field name="model">crm.business.category</field>
<field name="inherit_id" ref="grt_crm_business_category.view_crm_business_category_form"/>
<field name="inherit_id" ref="grt_business_category_base.view_crm_business_category_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='description']/.." position="before">
<group string="Inventory">
@@ -11,6 +11,6 @@
name="Business Categories"
parent="stock.menu_stock_root"
sequence="46"
action="grt_crm_business_category.action_crm_business_category"
action="grt_business_category_base.action_crm_business_category"
groups="stock.group_stock_manager"/>
</odoo>
@@ -10,16 +10,15 @@ for purchasing transactions.
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Purchases",
"version": "14.0.1.0.0",
"version": "14.0.1.1.0",
"depends": [
"purchase",
"account",
"grt_crm_business_category",
"grt_business_category_base",
],
"data": [
"security/ir.model.access.csv",
"security/ir.rule.csv",
"views/crm_business_category_views.xml",
"views/purchase_team_views.xml",
"views/purchase_order_views.xml",
"views/purchase_report_business_category_views.xml",
@@ -1,5 +1,4 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo import fields, models
class CrmBusinessCategory(models.Model):
@@ -8,20 +7,7 @@ class CrmBusinessCategory(models.Model):
purchase_analytic_account_id = fields.Many2one(
"account.analytic.account",
string="Purchase Analytic Account",
domain="[('company_id', '=', company_id)]",
ondelete="restrict",
help="Default analytic account used for purchasing transactions in this business category.",
related="analytic_account_id",
readonly=False,
help="Alias to the shared analytic account used for this business category.",
)
@api.constrains("company_id", "purchase_analytic_account_id")
def _check_purchase_analytic_account_company(self):
for category in self:
if not category.purchase_analytic_account_id or not category.company_id:
continue
if category.purchase_analytic_account_id.company_id != category.company_id:
raise ValidationError(
_(
"Business Category '%s' must use a Purchase Analytic Account from company '%s'."
)
% (category.name, category.company_id.name)
)
@@ -6,8 +6,8 @@ purchase_order_business_category_rule_sysadmin,Purchase Order full access for sy
purchase_team_business_category_rule_user,Purchase Team read by effective business category,model_purchase_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_user,1,0,0,0
purchase_team_business_category_rule_manager,Purchase Team full access for purchase manager in effective business category,model_purchase_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_manager,1,1,1,1
purchase_team_business_category_rule_sysadmin,Purchase Team full access for system admin,model_purchase_team,"[('company_id','in',user.company_ids.ids)]",base.group_system,1,1,1,1
crm_business_category_rule_purchase_user,Business Category by user effective list for purchase user,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_user,1,0,0,0
crm_business_category_rule_purchase_manager,Business Category access for purchase manager in effective business category,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_manager,1,1,1,1
crm_business_category_rule_purchase_user,Business Category by user effective list for purchase user,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_user,1,0,0,0
crm_business_category_rule_purchase_manager,Business Category access for purchase manager in effective business category,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_manager,1,1,1,1
account_move_purchase_business_category_rule_user,Vendor Bill read by effective business category for purchase user,account.model_account_move,"[('company_id','in',user.company_ids.ids),('purchase_business_category_id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_user,1,0,0,0
account_move_purchase_business_category_rule_manager,Vendor Bill access for purchase manager in effective business category,account.model_account_move,"[('company_id','in',user.company_ids.ids),('purchase_business_category_id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_manager,1,1,1,1
account_move_line_purchase_business_category_rule_user,Journal Item read by effective business category for purchase user,account.model_account_move_line,"[('company_id','in',user.company_ids.ids),('move_id.purchase_business_category_id','in',user.effective_business_category_ids.ids)]",purchase.group_purchase_user,1,0,0,0
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
6 purchase_team_business_category_rule_user Purchase Team read by effective business category model_purchase_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_user 1 0 0 0
7 purchase_team_business_category_rule_manager Purchase Team full access for purchase manager in effective business category model_purchase_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_manager 1 1 1 1
8 purchase_team_business_category_rule_sysadmin Purchase Team full access for system admin model_purchase_team [('company_id','in',user.company_ids.ids)] base.group_system 1 1 1 1
9 crm_business_category_rule_purchase_user Business Category by user effective list for purchase user grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_user 1 0 0 0
10 crm_business_category_rule_purchase_manager Business Category access for purchase manager in effective business category grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_manager 1 1 1 1
11 account_move_purchase_business_category_rule_user Vendor Bill read by effective business category for purchase user account.model_account_move [('company_id','in',user.company_ids.ids),('purchase_business_category_id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_user 1 0 0 0
12 account_move_purchase_business_category_rule_manager Vendor Bill access for purchase manager in effective business category account.model_account_move [('company_id','in',user.company_ids.ids),('purchase_business_category_id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_manager 1 1 1 1
13 account_move_line_purchase_business_category_rule_user Journal Item read by effective business category for purchase user account.model_account_move_line [('company_id','in',user.company_ids.ids),('move_id.purchase_business_category_id','in',user.effective_business_category_ids.ids)] purchase.group_purchase_user 1 0 0 0
@@ -3,7 +3,7 @@
<record id="view_crm_business_category_form_purchase_analytic" model="ir.ui.view">
<field name="name">crm.business.category.form.purchase.analytic</field>
<field name="model">crm.business.category</field>
<field name="inherit_id" ref="grt_crm_business_category.view_crm_business_category_form"/>
<field name="inherit_id" ref="grt_business_category_base.view_crm_business_category_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='description']/.." position="before">
<group string="Purchasing">
@@ -11,6 +11,6 @@
name="Business Categories"
parent="purchase.menu_purchase_root"
sequence="46"
action="grt_crm_business_category.action_crm_business_category"
action="grt_business_category_base.action_crm_business_category"
groups="purchase.group_purchase_manager"/>
</odoo>
+2 -2
View File
@@ -9,12 +9,13 @@ plus a two-step approval flow: Sales Team Leader then Accounting Manager.
"author": "PT Gagak Rimang Teknologi",
"website": "https://rimang.id",
"category": "Sales/Sales",
"version": "14.0.1.0.14",
"version": "14.0.1.1.0",
"depends": [
"sale_management",
"sale_crm",
"account",
"contacts",
"grt_business_category_base",
"grt_crm_business_category",
],
"post_init_hook": "post_init_hook",
@@ -23,7 +24,6 @@ plus a two-step approval flow: Sales Team Leader then Accounting Manager.
"security/security.xml",
"security/ir.model.access.csv",
"security/ir.rule.csv",
"views/crm_business_category_views.xml",
"views/customer_behavior_dashboard_views.xml",
"views/customer_behavior_recompute_wizard_views.xml",
"views/customer_behavior_segment_views.xml",
@@ -1,5 +1,4 @@
from . import crm_team
from . import crm_business_category
from . import customer_behavior_segment
from . import customer_behavior_config
from . import customer_behavior_analysis
@@ -5,8 +5,8 @@ sale_order_business_category_rule_manager,Sale Order full access for sales manag
sale_order_business_category_rule_sysadmin,Sale Order full access for system admin,sale.model_sale_order,"[(1,'=',1)]",base.group_system,1,1,1,1
crm_team_business_category_rule_sales_user,CRM Team read by effective business category for sales user,sales_team.model_crm_team,"[('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_salesman,1,0,0,0
crm_team_business_category_rule_sales_manager,CRM Team full access for sales manager in effective business category,sales_team.model_crm_team,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_business_category_rule_sales_user,Business Category by user effective list for sales user,grt_crm_business_category.model_crm_business_category,"[('id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_salesman,1,0,0,0
crm_business_category_rule_sales_manager,Business Category access for sales manager in effective business category,grt_crm_business_category.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
crm_business_category_rule_sales_user,Business Category by user effective list for sales user,grt_business_category_base.model_crm_business_category,"[('id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_salesman,1,0,0,0
crm_business_category_rule_sales_manager,Business Category access for sales manager in effective business category,grt_business_category_base.model_crm_business_category,"[('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
customer_behavior_analysis_rule_sales_user,Customer Behavior Analysis by effective business category,model_customer_behavior_analysis,"[('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_salesman,1,0,0,0
customer_behavior_analysis_rule_sales_manager,Customer Behavior Analysis full access for sales manager in effective business category,model_customer_behavior_analysis,"[('business_category_id.company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_manager,1,1,1,1
account_move_business_category_rule_sales_user,Invoice read by effective business category for sales user,account.model_account_move,"[('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)]",sales_team.group_sale_salesman,1,0,0,0
1 id name model_id:id domain_force groups:id perm_read perm_write perm_create perm_unlink
5 sale_order_business_category_rule_sysadmin Sale Order full access for system admin sale.model_sale_order [(1,'=',1)] base.group_system 1 1 1 1
6 crm_team_business_category_rule_sales_user CRM Team read by effective business category for sales user sales_team.model_crm_team [('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_salesman 1 0 0 0
7 crm_team_business_category_rule_sales_manager CRM Team full access for sales manager in effective business category sales_team.model_crm_team [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
8 crm_business_category_rule_sales_user Business Category by user effective list for sales user grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_salesman 1 0 0 0
9 crm_business_category_rule_sales_manager Business Category access for sales manager in effective business category grt_crm_business_category.model_crm_business_category grt_business_category_base.model_crm_business_category [('company_id','in',user.company_ids.ids),('id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
10 customer_behavior_analysis_rule_sales_user Customer Behavior Analysis by effective business category model_customer_behavior_analysis [('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_salesman 1 0 0 0
11 customer_behavior_analysis_rule_sales_manager Customer Behavior Analysis full access for sales manager in effective business category model_customer_behavior_analysis [('business_category_id.company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_manager 1 1 1 1
12 account_move_business_category_rule_sales_user Invoice read by effective business category for sales user account.model_account_move [('company_id','in',user.company_ids.ids),('business_category_id','in',user.effective_business_category_ids.ids)] sales_team.group_sale_salesman 1 0 0 0
@@ -3,7 +3,7 @@
<record id="view_crm_business_category_form_analytic" model="ir.ui.view">
<field name="name">crm.business.category.form.analytic</field>
<field name="model">crm.business.category</field>
<field name="inherit_id" ref="grt_crm_business_category.view_crm_business_category_form"/>
<field name="inherit_id" ref="grt_business_category_base.view_crm_business_category_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='description']/.." position="before">
<group string="Accounting">
@@ -17,7 +17,7 @@
name="Business Categories"
parent="sale.sale_order_menu"
sequence="36"
action="grt_crm_business_category.action_crm_business_category"
action="grt_business_category_base.action_crm_business_category"
groups="sales_team.group_sale_manager"/>
<menuitem id="menu_customer_behavior_analysis"
+11
View File
@@ -0,0 +1,11 @@
[options]
addons_path = C:\odoo14c\server\odoo\addons,C:\addon14
logfile = C:\addon14\log\odoo_upgrade_business_category.log
log_level = info
log_handler = :INFO
xmlrpc_port = 8071
db_host = localhost
db_port = 5432
db_user = openpg
db_password = openpgpwd
pg_path = C:\Odoo16\PostgreSQL\bin