Revert "chore(plating): retire fusion_plating_culture — not a priority"
This reverts commit 95310c459d.
This commit is contained in:
53
fusion_plating/fusion_plating_culture/README.md
Normal file
53
fusion_plating/fusion_plating_culture/README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Fusion Plating — Culture & Values
|
||||||
|
|
||||||
|
Part of the Fusion Plating product family by Nexa Systems Inc.
|
||||||
|
|
||||||
|
A configurable culture / values / fundamentals framework for plating and
|
||||||
|
metal finishing shops. Each shop loads its own values — this module ships
|
||||||
|
with no client-specific seed data.
|
||||||
|
|
||||||
|
## What it gives you
|
||||||
|
|
||||||
|
- **Value Sets** — a named collection of a shop's values (e.g. "Our Way",
|
||||||
|
"The 24 Fundamentals", "Core Behaviours"). A company can have several
|
||||||
|
sets, but usually one is marked as primary.
|
||||||
|
- **Values** — individual fundamentals, core behaviours, or beliefs, each
|
||||||
|
with a short title, long-form description, stories/examples, icon, and
|
||||||
|
display number.
|
||||||
|
- **Rotations** — a schedule that surfaces a "Fundamental of the
|
||||||
|
Day/Week/Month". The shop admin decides whether to enable an ir.cron
|
||||||
|
(none ships in this module) to advance rotations automatically.
|
||||||
|
- **Recognitions** — peer shout-outs tied to a specific value. "I saw
|
||||||
|
Sarah living Value #3 today when she stayed late to finish a customer
|
||||||
|
order." Recognitions flow into an employee's Culture tab on their HR
|
||||||
|
record.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Install `fusion_plating` (core) and `hr` first.
|
||||||
|
2. Install `fusion_plating_culture`.
|
||||||
|
3. Go to **Plating → Culture → Configuration → Value Sets** and create
|
||||||
|
your shop's set.
|
||||||
|
4. Add values to that set.
|
||||||
|
5. (Optional) Create a rotation schedule if you want a
|
||||||
|
fundamental-of-the-week rotation.
|
||||||
|
|
||||||
|
## Design notes
|
||||||
|
|
||||||
|
- **Not client-specific.** Nothing ships with Entech, Westin, or any
|
||||||
|
particular shop's language baked in. Each shop loads its own.
|
||||||
|
- **Reuses core groups.** No new security groups — operator reads,
|
||||||
|
supervisor creates recognitions, manager configures value sets.
|
||||||
|
- **Theme-aware.** SCSS uses Bootstrap CSS variables so kanban tiles and
|
||||||
|
recognition cards render cleanly in both light and dark mode.
|
||||||
|
- **hr.employee extension uses `x_fc_` prefix** per the Fusion Central
|
||||||
|
field-naming convention for base Odoo model extensions.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- `fusion_plating` — core
|
||||||
|
- `hr` — for employee extension and recognition targeting
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
OPL-1 (Odoo Proprietary License v1.0) — Copyright 2026 Nexa Systems Inc.
|
||||||
6
fusion_plating/fusion_plating_culture/__init__.py
Normal file
6
fusion_plating/fusion_plating_culture/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from . import models
|
||||||
74
fusion_plating/fusion_plating_culture/__manifest__.py
Normal file
74
fusion_plating/fusion_plating_culture/__manifest__.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
{
|
||||||
|
'name': 'Fusion Plating — Culture & Values',
|
||||||
|
'version': '19.0.1.0.0',
|
||||||
|
'category': 'Manufacturing/Plating',
|
||||||
|
'summary': 'Configurable culture framework for plating shops: values, fundamentals, peer recognitions, rotation schedules. Each shop loads its own values.',
|
||||||
|
'description': """
|
||||||
|
Fusion Plating — Culture & Values
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Part of the Fusion Plating product family by Nexa Systems Inc.
|
||||||
|
|
||||||
|
A configurable culture / values / fundamentals framework for plating and
|
||||||
|
metal finishing shops. Every shop has a different way of talking about how
|
||||||
|
they expect their people to behave — this module gives each shop a place to
|
||||||
|
capture that language and put it to work in the daily flow of the plant.
|
||||||
|
|
||||||
|
The module is intentionally generic. It ships with NO client-specific data.
|
||||||
|
Each shop loads its own value set: one shop may adopt the Entech "24
|
||||||
|
Fundamentals", another may use a 10-value "Our Way" set, and another may
|
||||||
|
skip the module entirely.
|
||||||
|
|
||||||
|
Concepts
|
||||||
|
--------
|
||||||
|
* Value Set — a named collection of values owned by a company
|
||||||
|
* Value — an individual fundamental, behaviour, or belief
|
||||||
|
* Rotation — a schedule that surfaces a value-of-the-day/week/month
|
||||||
|
* Recognition — a peer shout-out tied to a specific value
|
||||||
|
|
||||||
|
Extensions
|
||||||
|
----------
|
||||||
|
* hr.employee gains a recognition count and a Culture tab showing the
|
||||||
|
employee's recognition history.
|
||||||
|
|
||||||
|
Copyright (c) 2026 Nexa Systems Inc. All rights reserved.
|
||||||
|
""",
|
||||||
|
'author': 'Nexa Systems Inc.',
|
||||||
|
'website': 'https://www.nexasystems.ca',
|
||||||
|
'maintainer': 'Nexa Systems Inc.',
|
||||||
|
'support': 'support@nexasystems.ca',
|
||||||
|
'license': 'OPL-1',
|
||||||
|
'price': 0.00,
|
||||||
|
'currency': 'CAD',
|
||||||
|
'depends': [
|
||||||
|
'fusion_plating',
|
||||||
|
'hr',
|
||||||
|
],
|
||||||
|
'data': [
|
||||||
|
'security/fp_culture_security.xml',
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'data/fp_sequence_data.xml',
|
||||||
|
'views/fp_value_set_views.xml',
|
||||||
|
'views/fp_value_views.xml',
|
||||||
|
'views/fp_value_rotation_views.xml',
|
||||||
|
'views/fp_value_recognition_views.xml',
|
||||||
|
'views/hr_employee_views.xml',
|
||||||
|
'views/fp_menu.xml',
|
||||||
|
],
|
||||||
|
'demo': [
|
||||||
|
'data/fp_demo_culture_data.xml',
|
||||||
|
],
|
||||||
|
'assets': {
|
||||||
|
'web.assets_backend': [
|
||||||
|
'fusion_plating_culture/static/src/scss/fusion_plating_culture.scss',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'auto_install': False,
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc. — DEMO DATA (temporary)
|
||||||
|
Remove this file and its manifest entry before production release.
|
||||||
|
-->
|
||||||
|
<odoo noupdate="1">
|
||||||
|
|
||||||
|
<!-- ========== VALUE SET ========== -->
|
||||||
|
<record id="demo_value_set_core" model="fusion.plating.value.set">
|
||||||
|
<field name="name">Core Values</field>
|
||||||
|
<field name="code">CORE</field>
|
||||||
|
<field name="is_primary" eval="True"/>
|
||||||
|
<field name="description" type="html"><p>The five core values that guide how we work, treat each other, and serve our customers every day on the shop floor.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ========== VALUES ========== -->
|
||||||
|
<record id="demo_value_safety" model="fusion.plating.value">
|
||||||
|
<field name="name">Safety First</field>
|
||||||
|
<field name="number">1</field>
|
||||||
|
<field name="sequence">10</field>
|
||||||
|
<field name="set_id" ref="demo_value_set_core"/>
|
||||||
|
<field name="icon">fa-shield</field>
|
||||||
|
<field name="color">1</field>
|
||||||
|
<field name="description" type="html"><p>Nothing we do is worth getting hurt over. Every person goes home safe, every day. We stop work when something is unsafe and speak up without hesitation.</p></field>
|
||||||
|
<field name="examples" type="html"><p>A plater notices a leaking hose on the chrome line and immediately tags it out, even though it means pausing production for the shift.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="demo_value_quality" model="fusion.plating.value">
|
||||||
|
<field name="name">Quality Excellence</field>
|
||||||
|
<field name="number">2</field>
|
||||||
|
<field name="sequence">20</field>
|
||||||
|
<field name="set_id" ref="demo_value_set_core"/>
|
||||||
|
<field name="icon">fa-star</field>
|
||||||
|
<field name="color">2</field>
|
||||||
|
<field name="description" type="html"><p>We take pride in doing it right the first time. Our coatings protect critical parts — there is no room for "good enough." We own the spec, own the process, and own the result.</p></field>
|
||||||
|
<field name="examples" type="html"><p>An operator catches a thickness reading at the low end of spec and voluntarily re-plates the part rather than shipping borderline work.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="demo_value_teamwork" model="fusion.plating.value">
|
||||||
|
<field name="name">Teamwork</field>
|
||||||
|
<field name="number">3</field>
|
||||||
|
<field name="sequence">30</field>
|
||||||
|
<field name="set_id" ref="demo_value_set_core"/>
|
||||||
|
<field name="icon">fa-users</field>
|
||||||
|
<field name="color">3</field>
|
||||||
|
<field name="description" type="html"><p>We win together or not at all. No one succeeds alone on a plating line — every station depends on the one before it. We help each other, share knowledge, and celebrate wins as a team.</p></field>
|
||||||
|
<field name="examples" type="html"><p>The prep team stays late to help the EN line clear a rush order, even though it was not their line's work.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="demo_value_improvement" model="fusion.plating.value">
|
||||||
|
<field name="name">Continuous Improvement</field>
|
||||||
|
<field name="number">4</field>
|
||||||
|
<field name="sequence">40</field>
|
||||||
|
<field name="set_id" ref="demo_value_set_core"/>
|
||||||
|
<field name="icon">fa-line-chart</field>
|
||||||
|
<field name="color">4</field>
|
||||||
|
<field name="description" type="html"><p>Good enough today is not good enough tomorrow. We look for small, practical improvements every day — in our processes, our tools, and ourselves.</p></field>
|
||||||
|
<field name="examples" type="html"><p>A shift lead redesigns the rack loading sequence and cuts cycle time by 12% without any capital spend.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="demo_value_customer" model="fusion.plating.value">
|
||||||
|
<field name="name">Customer Focus</field>
|
||||||
|
<field name="number">5</field>
|
||||||
|
<field name="sequence">50</field>
|
||||||
|
<field name="set_id" ref="demo_value_set_core"/>
|
||||||
|
<field name="icon">fa-handshake-o</field>
|
||||||
|
<field name="color">5</field>
|
||||||
|
<field name="description" type="html"><p>Our customers trust us with their most critical parts. We honour that trust by delivering on time, communicating proactively, and treating every job like it matters — because it does.</p></field>
|
||||||
|
<field name="examples" type="html"><p>The shipping coordinator calls a customer two days before the due date to confirm the delivery window, preventing a costly production delay on their end.</p></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo noupdate="1">
|
||||||
|
|
||||||
|
<record id="seq_fp_value_recognition" model="ir.sequence">
|
||||||
|
<field name="name">Fusion Plating: Recognition</field>
|
||||||
|
<field name="code">fusion.plating.value.recognition</field>
|
||||||
|
<field name="prefix">REC/%(year)s/</field>
|
||||||
|
<field name="padding">5</field>
|
||||||
|
<field name="company_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</odoo>
|
||||||
10
fusion_plating/fusion_plating_culture/models/__init__.py
Normal file
10
fusion_plating/fusion_plating_culture/models/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from . import fp_value_set
|
||||||
|
from . import fp_value
|
||||||
|
from . import fp_value_rotation
|
||||||
|
from . import fp_value_recognition
|
||||||
|
from . import hr_employee
|
||||||
100
fusion_plating/fusion_plating_culture/models/fp_value.py
Normal file
100
fusion_plating/fusion_plating_culture/models/fp_value.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class FpValue(models.Model):
|
||||||
|
"""A single value, fundamental, core behaviour, or belief.
|
||||||
|
|
||||||
|
Values are grouped under a fusion.plating.value.set. Each value has a
|
||||||
|
short title, an optional display number (e.g. "Fundamental #3"), a
|
||||||
|
long-form description, stories / examples of living the value, and an
|
||||||
|
icon for display in kanban tiles.
|
||||||
|
"""
|
||||||
|
_name = 'fusion.plating.value'
|
||||||
|
_description = 'Fusion Plating — Value'
|
||||||
|
_order = 'set_id, sequence, number, name'
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
string='Title',
|
||||||
|
required=True,
|
||||||
|
help='Short, memorable title for the value, e.g. '
|
||||||
|
'"Do What\'s Best for the Customer".',
|
||||||
|
)
|
||||||
|
sequence = fields.Integer(
|
||||||
|
string='Sequence',
|
||||||
|
default=10,
|
||||||
|
help='Display order within the set.',
|
||||||
|
)
|
||||||
|
number = fields.Integer(
|
||||||
|
string='Number',
|
||||||
|
help='Optional display number (e.g. 1, 2, 3). Shows on kanban '
|
||||||
|
'tiles and in rotation schedules.',
|
||||||
|
)
|
||||||
|
set_id = fields.Many2one(
|
||||||
|
'fusion.plating.value.set',
|
||||||
|
string='Value Set',
|
||||||
|
required=True,
|
||||||
|
ondelete='cascade',
|
||||||
|
index=True,
|
||||||
|
)
|
||||||
|
company_id = fields.Many2one(
|
||||||
|
'res.company',
|
||||||
|
string='Company',
|
||||||
|
related='set_id.company_id',
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
description = fields.Html(
|
||||||
|
string='Description',
|
||||||
|
help='Long-form explanation of what this value means and how it '
|
||||||
|
'shows up in daily work.',
|
||||||
|
)
|
||||||
|
examples = fields.Html(
|
||||||
|
string='Stories & Examples',
|
||||||
|
help='Stories, anecdotes, and concrete examples of people living '
|
||||||
|
'this value.',
|
||||||
|
)
|
||||||
|
icon = fields.Char(
|
||||||
|
string='Icon',
|
||||||
|
default='fa-star',
|
||||||
|
help='Font Awesome icon class (without the "fa " prefix), '
|
||||||
|
'e.g. "fa-heart", "fa-bolt".',
|
||||||
|
)
|
||||||
|
color = fields.Integer(
|
||||||
|
string='Color Index',
|
||||||
|
default=0,
|
||||||
|
help='Kanban colour index (0-11).',
|
||||||
|
)
|
||||||
|
active = fields.Boolean(
|
||||||
|
string='Active',
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
recognition_ids = fields.One2many(
|
||||||
|
'fusion.plating.value.recognition',
|
||||||
|
'value_id',
|
||||||
|
string='Recognitions',
|
||||||
|
)
|
||||||
|
recognition_count = fields.Integer(
|
||||||
|
string='Recognition Count',
|
||||||
|
compute='_compute_recognition_count',
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends('recognition_ids', 'recognition_ids.state')
|
||||||
|
def _compute_recognition_count(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.recognition_count = len(rec.recognition_ids.filtered(
|
||||||
|
lambda r: r.state == 'published'
|
||||||
|
))
|
||||||
|
|
||||||
|
def name_get(self):
|
||||||
|
result = []
|
||||||
|
for rec in self:
|
||||||
|
if rec.number:
|
||||||
|
result.append((rec.id, f'#{rec.number} — {rec.name}'))
|
||||||
|
else:
|
||||||
|
result.append((rec.id, rec.name))
|
||||||
|
return result
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from odoo import _, api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class FpValueRecognition(models.Model):
|
||||||
|
"""A peer recognition tied to a specific value.
|
||||||
|
|
||||||
|
Example: "I saw Sarah living Value #3 yesterday when she stayed late
|
||||||
|
to re-mask a customer part after first-article inspection flagged a
|
||||||
|
nick."
|
||||||
|
|
||||||
|
Recognitions start in draft, move to published, and can be archived
|
||||||
|
when they roll off a stand-up wall or a newsletter.
|
||||||
|
"""
|
||||||
|
_name = 'fusion.plating.value.recognition'
|
||||||
|
_description = 'Fusion Plating — Value Recognition'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
_order = 'nomination_date desc, id desc'
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
string='Title',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
help='Short headline for the recognition, e.g. '
|
||||||
|
'"Sarah stayed late for the customer".',
|
||||||
|
default=lambda self: _('New Recognition'),
|
||||||
|
)
|
||||||
|
reference = fields.Char(
|
||||||
|
string='Reference',
|
||||||
|
readonly=True,
|
||||||
|
copy=False,
|
||||||
|
default=lambda self: _('New'),
|
||||||
|
)
|
||||||
|
value_id = fields.Many2one(
|
||||||
|
'fusion.plating.value',
|
||||||
|
string='Value',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
ondelete='restrict',
|
||||||
|
)
|
||||||
|
set_id = fields.Many2one(
|
||||||
|
'fusion.plating.value.set',
|
||||||
|
string='Value Set',
|
||||||
|
related='value_id.set_id',
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
recognized_employee_id = fields.Many2one(
|
||||||
|
'hr.employee',
|
||||||
|
string='Recognized',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
help='The person being recognized.',
|
||||||
|
)
|
||||||
|
nominated_by_id = fields.Many2one(
|
||||||
|
'res.users',
|
||||||
|
string='Nominated By',
|
||||||
|
default=lambda self: self.env.user,
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
nomination_date = fields.Datetime(
|
||||||
|
string='Nominated On',
|
||||||
|
default=fields.Datetime.now,
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
story = fields.Html(
|
||||||
|
string='Story',
|
||||||
|
help='What happened? Describe the moment you saw the value being '
|
||||||
|
'lived.',
|
||||||
|
)
|
||||||
|
state = fields.Selection(
|
||||||
|
[
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('published', 'Published'),
|
||||||
|
('archived', 'Archived'),
|
||||||
|
],
|
||||||
|
string='Status',
|
||||||
|
default='draft',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
company_id = fields.Many2one(
|
||||||
|
'res.company',
|
||||||
|
string='Company',
|
||||||
|
default=lambda self: self.env.company,
|
||||||
|
)
|
||||||
|
color = fields.Integer(
|
||||||
|
string='Color Index',
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
for vals in vals_list:
|
||||||
|
if not vals.get('reference') or vals['reference'] == _('New'):
|
||||||
|
vals['reference'] = self.env['ir.sequence'].next_by_code(
|
||||||
|
'fusion.plating.value.recognition'
|
||||||
|
) or _('New')
|
||||||
|
return super().create(vals_list)
|
||||||
|
|
||||||
|
def action_publish(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.state = 'published'
|
||||||
|
rec.message_post(body=_('Recognition published.'))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def action_archive_recognition(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.state = 'archived'
|
||||||
|
rec.message_post(body=_('Recognition archived.'))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def action_reset_to_draft(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.state = 'draft'
|
||||||
|
return True
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from odoo import _, api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class FpValueRotation(models.Model):
|
||||||
|
"""A schedule that rotates a value to the front of the shop's attention.
|
||||||
|
|
||||||
|
Used to drive "Fundamental of the Day/Week/Month" programs. The admin
|
||||||
|
creates a rotation, picks a set and a period, and enables it. This
|
||||||
|
module does NOT ship an ir.cron — the shop admin wires a cron to call
|
||||||
|
`_cron_advance_rotation` if they want automatic advancement. Many
|
||||||
|
shops prefer to advance the rotation manually at a weekly stand-up.
|
||||||
|
"""
|
||||||
|
_name = 'fusion.plating.value.rotation'
|
||||||
|
_description = 'Fusion Plating — Value Rotation Schedule'
|
||||||
|
_inherit = ['mail.thread']
|
||||||
|
_order = 'name'
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
string='Name',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
help='Display name of the rotation, e.g. "Weekly Fundamental".',
|
||||||
|
)
|
||||||
|
set_id = fields.Many2one(
|
||||||
|
'fusion.plating.value.set',
|
||||||
|
string='Value Set',
|
||||||
|
required=True,
|
||||||
|
ondelete='cascade',
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
rotation_period = fields.Selection(
|
||||||
|
[
|
||||||
|
('daily', 'Daily'),
|
||||||
|
('weekly', 'Weekly'),
|
||||||
|
('monthly', 'Monthly'),
|
||||||
|
],
|
||||||
|
string='Rotation Period',
|
||||||
|
required=True,
|
||||||
|
default='weekly',
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
current_value_id = fields.Many2one(
|
||||||
|
'fusion.plating.value',
|
||||||
|
string='Current Value',
|
||||||
|
readonly=True,
|
||||||
|
tracking=True,
|
||||||
|
help='The value currently surfaced by this rotation. Updated by '
|
||||||
|
'_cron_advance_rotation.',
|
||||||
|
domain="[('set_id', '=', set_id)]",
|
||||||
|
)
|
||||||
|
last_rotation_date = fields.Date(
|
||||||
|
string='Last Rotated On',
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
next_rotation_date = fields.Date(
|
||||||
|
string='Next Rotation',
|
||||||
|
compute='_compute_next_rotation_date',
|
||||||
|
)
|
||||||
|
company_id = fields.Many2one(
|
||||||
|
'res.company',
|
||||||
|
string='Company',
|
||||||
|
related='set_id.company_id',
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
active = fields.Boolean(
|
||||||
|
string='Active',
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends('last_rotation_date', 'rotation_period')
|
||||||
|
def _compute_next_rotation_date(self):
|
||||||
|
for rec in self:
|
||||||
|
if not rec.last_rotation_date:
|
||||||
|
rec.next_rotation_date = fields.Date.context_today(rec)
|
||||||
|
continue
|
||||||
|
delta_days = {
|
||||||
|
'daily': 1,
|
||||||
|
'weekly': 7,
|
||||||
|
'monthly': 30,
|
||||||
|
}.get(rec.rotation_period, 7)
|
||||||
|
rec.next_rotation_date = rec.last_rotation_date + timedelta(
|
||||||
|
days=delta_days
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_advance(self):
|
||||||
|
"""Manually advance the rotation to the next value.
|
||||||
|
|
||||||
|
Wired to a form button so a shop that doesn't want cron-driven
|
||||||
|
rotation can move the fundamental forward at a stand-up meeting.
|
||||||
|
"""
|
||||||
|
for rec in self:
|
||||||
|
rec._advance_one()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _advance_one(self):
|
||||||
|
"""Move this rotation to the next value in the set, wrapping."""
|
||||||
|
self.ensure_one()
|
||||||
|
values = self.set_id.value_ids.filtered('active').sorted(
|
||||||
|
key=lambda v: (v.sequence, v.number, v.id)
|
||||||
|
)
|
||||||
|
if not values:
|
||||||
|
return False
|
||||||
|
if not self.current_value_id:
|
||||||
|
next_value = values[0]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
idx = list(values).index(self.current_value_id)
|
||||||
|
next_idx = (idx + 1) % len(values)
|
||||||
|
next_value = values[next_idx]
|
||||||
|
except ValueError:
|
||||||
|
next_value = values[0]
|
||||||
|
self.write({
|
||||||
|
'current_value_id': next_value.id,
|
||||||
|
'last_rotation_date': fields.Date.context_today(self),
|
||||||
|
})
|
||||||
|
self.message_post(
|
||||||
|
body=_('Rotation advanced to %(value)s.') % {
|
||||||
|
'value': next_value.display_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _cron_advance_rotation(self):
|
||||||
|
"""Cron entry point.
|
||||||
|
|
||||||
|
A shop admin can wire an ir.cron to this method. The module
|
||||||
|
intentionally does not ship one — different shops want different
|
||||||
|
cadences. Only advances rotations whose next_rotation_date is
|
||||||
|
today or earlier.
|
||||||
|
"""
|
||||||
|
today = fields.Date.context_today(self)
|
||||||
|
rotations = self.search([('active', '=', True)])
|
||||||
|
for rotation in rotations:
|
||||||
|
if (
|
||||||
|
not rotation.last_rotation_date
|
||||||
|
or rotation.next_rotation_date
|
||||||
|
and rotation.next_rotation_date <= today
|
||||||
|
):
|
||||||
|
rotation._advance_one()
|
||||||
|
return True
|
||||||
111
fusion_plating/fusion_plating_culture/models/fp_value_set.py
Normal file
111
fusion_plating/fusion_plating_culture/models/fp_value_set.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class FpValueSet(models.Model):
|
||||||
|
"""A named collection of values owned by a company.
|
||||||
|
|
||||||
|
Each shop loads its own set. One shop might call theirs
|
||||||
|
"Entech Fundamentals" with 24 items, another "Our Way" with 10. A shop
|
||||||
|
may have several sets (historical, draft, archived) but usually only
|
||||||
|
one is marked primary.
|
||||||
|
|
||||||
|
The module ships NO seed data — this is a generic framework.
|
||||||
|
"""
|
||||||
|
_name = 'fusion.plating.value.set'
|
||||||
|
_description = 'Fusion Plating — Value Set'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
_order = 'is_primary desc, name'
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
string='Name',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
help='Display name of the set, e.g. "Entech Fundamentals", "Our Way".',
|
||||||
|
)
|
||||||
|
code = fields.Char(
|
||||||
|
string='Code',
|
||||||
|
required=True,
|
||||||
|
tracking=True,
|
||||||
|
help='Unique slug identifier, e.g. "entech_fundamentals".',
|
||||||
|
)
|
||||||
|
description = fields.Html(
|
||||||
|
string='Description',
|
||||||
|
help='Long-form description of what this set represents and how '
|
||||||
|
'the shop uses it.',
|
||||||
|
)
|
||||||
|
company_id = fields.Many2one(
|
||||||
|
'res.company',
|
||||||
|
string='Company',
|
||||||
|
required=True,
|
||||||
|
default=lambda self: self.env.company,
|
||||||
|
tracking=True,
|
||||||
|
)
|
||||||
|
value_ids = fields.One2many(
|
||||||
|
'fusion.plating.value',
|
||||||
|
'set_id',
|
||||||
|
string='Values',
|
||||||
|
)
|
||||||
|
value_count = fields.Integer(
|
||||||
|
string='Value Count',
|
||||||
|
compute='_compute_value_count',
|
||||||
|
)
|
||||||
|
is_primary = fields.Boolean(
|
||||||
|
string='Primary Set',
|
||||||
|
default=False,
|
||||||
|
tracking=True,
|
||||||
|
help='Marks this as the shop\'s primary culture set. Only one set '
|
||||||
|
'per company should be primary at a time.',
|
||||||
|
)
|
||||||
|
active = fields.Boolean(
|
||||||
|
string='Active',
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_sql_constraints = [
|
||||||
|
(
|
||||||
|
'fp_value_set_code_company_uniq',
|
||||||
|
'unique(code, company_id)',
|
||||||
|
'Value set code must be unique within a company.',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
@api.depends('value_ids')
|
||||||
|
def _compute_value_count(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.value_count = len(rec.value_ids)
|
||||||
|
|
||||||
|
def write(self, vals):
|
||||||
|
"""When flipping a set to primary, demote any other primary set in
|
||||||
|
the same company so there is only one primary per company.
|
||||||
|
"""
|
||||||
|
res = super().write(vals)
|
||||||
|
if vals.get('is_primary'):
|
||||||
|
for rec in self:
|
||||||
|
if rec.is_primary:
|
||||||
|
others = self.search([
|
||||||
|
('id', '!=', rec.id),
|
||||||
|
('company_id', '=', rec.company_id.id),
|
||||||
|
('is_primary', '=', True),
|
||||||
|
])
|
||||||
|
if others:
|
||||||
|
others.write({'is_primary': False})
|
||||||
|
return res
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
recs = super().create(vals_list)
|
||||||
|
for rec in recs:
|
||||||
|
if rec.is_primary:
|
||||||
|
others = self.search([
|
||||||
|
('id', '!=', rec.id),
|
||||||
|
('company_id', '=', rec.company_id.id),
|
||||||
|
('is_primary', '=', True),
|
||||||
|
])
|
||||||
|
if others:
|
||||||
|
others.write({'is_primary': False})
|
||||||
|
return recs
|
||||||
47
fusion_plating/fusion_plating_culture/models/hr_employee.py
Normal file
47
fusion_plating/fusion_plating_culture/models/hr_employee.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class HrEmployee(models.Model):
|
||||||
|
"""Extend hr.employee with culture recognition totals.
|
||||||
|
|
||||||
|
Uses the x_fc_ prefix per the Fusion Central field-naming convention
|
||||||
|
for base Odoo model extensions.
|
||||||
|
"""
|
||||||
|
_inherit = 'hr.employee'
|
||||||
|
|
||||||
|
x_fc_recognition_ids = fields.One2many(
|
||||||
|
'fusion.plating.value.recognition',
|
||||||
|
'recognized_employee_id',
|
||||||
|
string='Recognitions',
|
||||||
|
)
|
||||||
|
x_fc_recognition_count = fields.Integer(
|
||||||
|
string='Recognition Count',
|
||||||
|
compute='_compute_x_fc_recognition_stats',
|
||||||
|
)
|
||||||
|
x_fc_last_recognized_date = fields.Datetime(
|
||||||
|
string='Last Recognized',
|
||||||
|
compute='_compute_x_fc_recognition_stats',
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends(
|
||||||
|
'x_fc_recognition_ids',
|
||||||
|
'x_fc_recognition_ids.state',
|
||||||
|
'x_fc_recognition_ids.nomination_date',
|
||||||
|
)
|
||||||
|
def _compute_x_fc_recognition_stats(self):
|
||||||
|
for rec in self:
|
||||||
|
published = rec.x_fc_recognition_ids.filtered(
|
||||||
|
lambda r: r.state == 'published'
|
||||||
|
)
|
||||||
|
rec.x_fc_recognition_count = len(published)
|
||||||
|
if published:
|
||||||
|
rec.x_fc_last_recognized_date = max(
|
||||||
|
published.mapped('nomination_date')
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rec.x_fc_last_recognized_date = False
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<!-- The Culture module reuses the core Fusion Plating groups: -->
|
||||||
|
<!-- group_fusion_plating_operator — read values and rotations -->
|
||||||
|
<!-- group_fusion_plating_supervisor — create recognitions -->
|
||||||
|
<!-- group_fusion_plating_manager — full CRUD on sets and values -->
|
||||||
|
<!-- No new groups are introduced here. ACLs live in -->
|
||||||
|
<!-- security/ir.model.access.csv. Record rules for multi-company -->
|
||||||
|
<!-- isolation live below. -->
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
|
||||||
|
<record id="fp_value_set_company_rule" model="ir.rule">
|
||||||
|
<field name="name">Fusion Plating: Value Set — multi-company</field>
|
||||||
|
<field name="model_id" ref="model_fusion_plating_value_set"/>
|
||||||
|
<field name="global" eval="True"/>
|
||||||
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="fp_value_company_rule" model="ir.rule">
|
||||||
|
<field name="name">Fusion Plating: Value — multi-company</field>
|
||||||
|
<field name="model_id" ref="model_fusion_plating_value"/>
|
||||||
|
<field name="global" eval="True"/>
|
||||||
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="fp_value_rotation_company_rule" model="ir.rule">
|
||||||
|
<field name="name">Fusion Plating: Value Rotation — multi-company</field>
|
||||||
|
<field name="model_id" ref="model_fusion_plating_value_rotation"/>
|
||||||
|
<field name="global" eval="True"/>
|
||||||
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="fp_value_recognition_company_rule" model="ir.rule">
|
||||||
|
<field name="name">Fusion Plating: Recognition — multi-company</field>
|
||||||
|
<field name="model_id" ref="model_fusion_plating_value_recognition"/>
|
||||||
|
<field name="global" eval="True"/>
|
||||||
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_fp_value_set_operator,fp.value.set.operator,model_fusion_plating_value_set,fusion_plating.group_fusion_plating_operator,1,0,0,0
|
||||||
|
access_fp_value_set_supervisor,fp.value.set.supervisor,model_fusion_plating_value_set,fusion_plating.group_fusion_plating_supervisor,1,0,0,0
|
||||||
|
access_fp_value_set_manager,fp.value.set.manager,model_fusion_plating_value_set,fusion_plating.group_fusion_plating_manager,1,1,1,1
|
||||||
|
access_fp_value_operator,fp.value.operator,model_fusion_plating_value,fusion_plating.group_fusion_plating_operator,1,0,0,0
|
||||||
|
access_fp_value_supervisor,fp.value.supervisor,model_fusion_plating_value,fusion_plating.group_fusion_plating_supervisor,1,0,0,0
|
||||||
|
access_fp_value_manager,fp.value.manager,model_fusion_plating_value,fusion_plating.group_fusion_plating_manager,1,1,1,1
|
||||||
|
access_fp_value_rotation_operator,fp.value.rotation.operator,model_fusion_plating_value_rotation,fusion_plating.group_fusion_plating_operator,1,0,0,0
|
||||||
|
access_fp_value_rotation_supervisor,fp.value.rotation.supervisor,model_fusion_plating_value_rotation,fusion_plating.group_fusion_plating_supervisor,1,1,0,0
|
||||||
|
access_fp_value_rotation_manager,fp.value.rotation.manager,model_fusion_plating_value_rotation,fusion_plating.group_fusion_plating_manager,1,1,1,1
|
||||||
|
access_fp_value_recognition_operator,fp.value.recognition.operator,model_fusion_plating_value_recognition,fusion_plating.group_fusion_plating_operator,1,0,0,0
|
||||||
|
access_fp_value_recognition_supervisor,fp.value.recognition.supervisor,model_fusion_plating_value_recognition,fusion_plating.group_fusion_plating_supervisor,1,1,1,0
|
||||||
|
access_fp_value_recognition_manager,fp.value.recognition.manager,model_fusion_plating_value_recognition,fusion_plating.group_fusion_plating_manager,1,1,1,1
|
||||||
|
@@ -0,0 +1,128 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Fusion Plating — Culture & Values — backend styles
|
||||||
|
// Copyright 2026 Nexa Systems Inc.
|
||||||
|
// License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
//
|
||||||
|
// THEME AWARENESS
|
||||||
|
// ---------------
|
||||||
|
// Like the core fusion_plating SCSS, this file uses ONLY Bootstrap /
|
||||||
|
// Odoo CSS custom properties so every surface adapts to light and dark
|
||||||
|
// mode automatically. No hardcoded hex colors anywhere.
|
||||||
|
//
|
||||||
|
// background: var(--bs-body-bg)
|
||||||
|
// surface: var(--o-view-background-color)
|
||||||
|
// foreground: var(--bs-body-color)
|
||||||
|
// muted text: var(--bs-secondary-color)
|
||||||
|
// border: var(--bs-border-color)
|
||||||
|
// primary: var(--o-action)
|
||||||
|
//
|
||||||
|
// Semantic tints use color-mix() so a green badge darkens on light mode
|
||||||
|
// and brightens on dark mode automatically.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Value kanban tile — a colourful card showing number + name + icon
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
.o_fp_value_card {
|
||||||
|
background-color: var(--o-view-background-color, var(--bs-body-bg));
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
border: 1px solid var(--bs-border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
min-height: 140px;
|
||||||
|
transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: color-mix(in srgb, var(--o-action) 50%, var(--bs-border-color));
|
||||||
|
box-shadow: 0 4px 14px color-mix(in srgb, var(--bs-body-color) 10%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_fp_value_number {
|
||||||
|
font-size: 2.4rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--o-action);
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_fp_value_icon {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_fp_value_name {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_fp_value_meta {
|
||||||
|
color: var(--bs-secondary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Recognition kanban card — badge-style card grouped by state
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
.o_fp_recognition_card {
|
||||||
|
background-color: var(--o-view-background-color, var(--bs-body-bg));
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
border: 1px solid var(--bs-border-color);
|
||||||
|
border-left-width: 4px;
|
||||||
|
border-left-color: color-mix(in srgb, var(--o-action) 70%, var(--bs-border-color));
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
transition: border-color 120ms ease, box-shadow 120ms ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: color-mix(in srgb, var(--o-action) 50%, var(--bs-border-color));
|
||||||
|
box-shadow: 0 2px 8px color-mix(in srgb, var(--bs-body-color) 8%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-muted {
|
||||||
|
color: var(--bs-secondary-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Recognition kanban — state-based accent on the left border
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
.o_fp_recognition_kanban {
|
||||||
|
|
||||||
|
// Draft — subtle muted accent
|
||||||
|
.o_kanban_group[data-id$="draft"] .o_fp_recognition_card {
|
||||||
|
border-left-color: var(--bs-secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Published — success accent
|
||||||
|
.o_kanban_group[data-id$="published"] .o_fp_recognition_card {
|
||||||
|
border-left-color: var(--bs-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Archived — dimmed
|
||||||
|
.o_kanban_group[data-id$="archived"] .o_fp_recognition_card {
|
||||||
|
border-left-color: color-mix(in srgb, var(--bs-secondary-color) 60%, transparent);
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Value kanban — spacing for the grouped kanban columns
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
.o_fp_value_kanban {
|
||||||
|
|
||||||
|
.o_kanban_record {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
fusion_plating/fusion_plating_culture/views/fp_menu.xml
Normal file
43
fusion_plating/fusion_plating_culture/views/fp_menu.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ===== CULTURE (top-level under Plating app) ===== -->
|
||||||
|
<menuitem id="menu_fp_culture_root"
|
||||||
|
name="Culture"
|
||||||
|
parent="fusion_plating.menu_fp_root"
|
||||||
|
sequence="80"
|
||||||
|
groups="fusion_plating.group_fusion_plating_operator"/>
|
||||||
|
|
||||||
|
<menuitem id="menu_fp_values"
|
||||||
|
name="Values"
|
||||||
|
parent="menu_fp_culture_root"
|
||||||
|
action="action_fp_value"
|
||||||
|
sequence="10"/>
|
||||||
|
|
||||||
|
<menuitem id="menu_fp_recognitions"
|
||||||
|
name="Recognitions"
|
||||||
|
parent="menu_fp_culture_root"
|
||||||
|
action="action_fp_value_recognition"
|
||||||
|
sequence="20"/>
|
||||||
|
|
||||||
|
<!-- ===== CULTURE CONFIGURATION (under core Configuration menu) ===== -->
|
||||||
|
<menuitem id="menu_fp_value_sets"
|
||||||
|
name="Value Sets"
|
||||||
|
parent="fusion_plating.menu_fp_config"
|
||||||
|
action="action_fp_value_set"
|
||||||
|
sequence="100"
|
||||||
|
groups="fusion_plating.group_fusion_plating_manager"/>
|
||||||
|
|
||||||
|
<menuitem id="menu_fp_value_rotations"
|
||||||
|
name="Value Rotations"
|
||||||
|
parent="fusion_plating.menu_fp_config"
|
||||||
|
action="action_fp_value_rotation"
|
||||||
|
sequence="110"
|
||||||
|
groups="fusion_plating.group_fusion_plating_manager"/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_fp_value_recognition_list" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.recognition.list</field>
|
||||||
|
<field name="model">fusion.plating.value.recognition</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Recognitions">
|
||||||
|
<field name="reference"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="recognized_employee_id"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
<field name="nominated_by_id"/>
|
||||||
|
<field name="nomination_date"/>
|
||||||
|
<field name="state" widget="badge"
|
||||||
|
decoration-info="state == 'draft'"
|
||||||
|
decoration-success="state == 'published'"
|
||||||
|
decoration-muted="state == 'archived'"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_recognition_form" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.recognition.form</field>
|
||||||
|
<field name="model">fusion.plating.value.recognition</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Recognition">
|
||||||
|
<header>
|
||||||
|
<button name="action_publish"
|
||||||
|
type="object"
|
||||||
|
string="Publish"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="state != 'draft'"/>
|
||||||
|
<button name="action_archive_recognition"
|
||||||
|
type="object"
|
||||||
|
string="Archive"
|
||||||
|
invisible="state != 'published'"/>
|
||||||
|
<button name="action_reset_to_draft"
|
||||||
|
type="object"
|
||||||
|
string="Reset to Draft"
|
||||||
|
invisible="state == 'draft'"/>
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,published,archived"/>
|
||||||
|
</header>
|
||||||
|
<sheet>
|
||||||
|
<div class="oe_title">
|
||||||
|
<label for="name"/>
|
||||||
|
<h1><field name="name" placeholder="e.g. Sarah stayed late for the customer"/></h1>
|
||||||
|
<div class="text-muted">
|
||||||
|
<field name="reference"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="recognized_employee_id"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
<field name="set_id"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="nominated_by_id"/>
|
||||||
|
<field name="nomination_date"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="Story">
|
||||||
|
<field name="story" placeholder="What happened? Describe the moment you saw the value being lived."/>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
</sheet>
|
||||||
|
<chatter/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_recognition_kanban" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.recognition.kanban</field>
|
||||||
|
<field name="model">fusion.plating.value.recognition</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<kanban default_group_by="state" class="o_fp_recognition_kanban">
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="reference"/>
|
||||||
|
<field name="recognized_employee_id"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
<field name="nomination_date"/>
|
||||||
|
<field name="state"/>
|
||||||
|
<field name="color"/>
|
||||||
|
<templates>
|
||||||
|
<t t-name="card">
|
||||||
|
<div t-attf-class="o_fp_recognition_card oe_kanban_color_#{record.color.raw_value}">
|
||||||
|
<div class="d-flex align-items-start justify-content-between">
|
||||||
|
<strong><field name="name"/></strong>
|
||||||
|
<i class="fa fa-thumbs-up text-muted" aria-hidden="true"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 small text-muted">
|
||||||
|
<i class="fa fa-user me-1" aria-hidden="true"/>
|
||||||
|
<field name="recognized_employee_id"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 small text-muted">
|
||||||
|
<i class="fa fa-star me-1" aria-hidden="true"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 small text-muted">
|
||||||
|
<field name="nomination_date"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
|
</kanban>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_recognition_search" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.recognition.search</field>
|
||||||
|
<field name="model">fusion.plating.value.recognition</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search string="Recognitions">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="recognized_employee_id"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
<field name="nominated_by_id"/>
|
||||||
|
<filter string="Draft" name="draft" domain="[('state', '=', 'draft')]"/>
|
||||||
|
<filter string="Published" name="published" domain="[('state', '=', 'published')]"/>
|
||||||
|
<filter string="Archived" name="archived_state" domain="[('state', '=', 'archived')]"/>
|
||||||
|
<separator/>
|
||||||
|
<filter string="My Nominations" name="my_nominations"
|
||||||
|
domain="[('nominated_by_id', '=', uid)]"/>
|
||||||
|
<group>
|
||||||
|
<filter string="Employee" name="group_employee" context="{'group_by': 'recognized_employee_id'}"/>
|
||||||
|
<filter string="Value" name="group_value" context="{'group_by': 'value_id'}"/>
|
||||||
|
<filter string="Status" name="group_state" context="{'group_by': 'state'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_fp_value_recognition" model="ir.actions.act_window">
|
||||||
|
<field name="name">Recognitions</field>
|
||||||
|
<field name="res_model">fusion.plating.value.recognition</field>
|
||||||
|
<field name="view_mode">kanban,list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Recognize a teammate
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Record peer recognitions tied to a specific value — a
|
||||||
|
shout-out for someone living the fundamentals in their
|
||||||
|
daily work.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_fp_value_rotation_list" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.rotation.list</field>
|
||||||
|
<field name="model">fusion.plating.value.rotation</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Rotations">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="rotation_period"/>
|
||||||
|
<field name="current_value_id"/>
|
||||||
|
<field name="last_rotation_date"/>
|
||||||
|
<field name="next_rotation_date"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_rotation_form" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.rotation.form</field>
|
||||||
|
<field name="model">fusion.plating.value.rotation</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Rotation">
|
||||||
|
<header>
|
||||||
|
<button name="action_advance"
|
||||||
|
type="object"
|
||||||
|
string="Advance Now"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="not active"/>
|
||||||
|
</header>
|
||||||
|
<sheet>
|
||||||
|
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
||||||
|
<div class="oe_title">
|
||||||
|
<label for="name"/>
|
||||||
|
<h1><field name="name" placeholder="e.g. Weekly Fundamental"/></h1>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="rotation_period"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="current_value_id"/>
|
||||||
|
<field name="last_rotation_date"/>
|
||||||
|
<field name="next_rotation_date"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<p class="text-muted mt-3">
|
||||||
|
This module does not ship an ir.cron — wire one to
|
||||||
|
<code>fusion.plating.value.rotation._cron_advance_rotation</code>
|
||||||
|
if you want automatic advancement, or click
|
||||||
|
<em>Advance Now</em> manually at a stand-up.
|
||||||
|
</p>
|
||||||
|
</sheet>
|
||||||
|
<chatter/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_fp_value_rotation" model="ir.actions.act_window">
|
||||||
|
<field name="name">Rotations</field>
|
||||||
|
<field name="res_model">fusion.plating.value.rotation</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Set up a rotation schedule
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A rotation surfaces a "Fundamental of the Day/Week/Month"
|
||||||
|
from one of your value sets.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_fp_value_set_list" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.set.list</field>
|
||||||
|
<field name="model">fusion.plating.value.set</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Value Sets">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="code"/>
|
||||||
|
<field name="value_count"/>
|
||||||
|
<field name="is_primary" widget="boolean_toggle"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_set_form" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.set.form</field>
|
||||||
|
<field name="model">fusion.plating.value.set</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Value Set">
|
||||||
|
<header/>
|
||||||
|
<sheet>
|
||||||
|
<widget name="web_ribbon" title="Primary" bg_color="text-bg-success" invisible="not is_primary"/>
|
||||||
|
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
||||||
|
<div class="oe_title">
|
||||||
|
<label for="name"/>
|
||||||
|
<h1><field name="name" placeholder="e.g. Our Way, Core Fundamentals"/></h1>
|
||||||
|
<div class="text-muted">
|
||||||
|
<field name="code" placeholder="our_way"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<field name="is_primary"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="value_count"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="Description">
|
||||||
|
<field name="description" placeholder="What does this set represent? How does the shop use it?"/>
|
||||||
|
</page>
|
||||||
|
<page string="Values">
|
||||||
|
<field name="value_ids" context="{'default_set_id': id}">
|
||||||
|
<list editable="bottom">
|
||||||
|
<field name="sequence" widget="handle"/>
|
||||||
|
<field name="number"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="icon"/>
|
||||||
|
<field name="color" widget="color_picker" optional="show"/>
|
||||||
|
<field name="recognition_count" optional="hide"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
</sheet>
|
||||||
|
<chatter/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_set_search" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.set.search</field>
|
||||||
|
<field name="model">fusion.plating.value.set</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search string="Value Sets">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="code"/>
|
||||||
|
<filter string="Primary" name="primary" domain="[('is_primary', '=', True)]"/>
|
||||||
|
<filter string="Archived" name="archived" domain="[('active', '=', False)]"/>
|
||||||
|
<group>
|
||||||
|
<filter string="Company" name="group_company" context="{'group_by': 'company_id'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_fp_value_set" model="ir.actions.act_window">
|
||||||
|
<field name="name">Value Sets</field>
|
||||||
|
<field name="res_model">fusion.plating.value.set</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Create your shop's first value set
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A value set is your shop's named collection of fundamentals,
|
||||||
|
core behaviours, or beliefs. Nothing ships pre-loaded — each
|
||||||
|
shop defines its own.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
134
fusion_plating/fusion_plating_culture/views/fp_value_views.xml
Normal file
134
fusion_plating/fusion_plating_culture/views/fp_value_views.xml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_fp_value_list" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.list</field>
|
||||||
|
<field name="model">fusion.plating.value</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Values">
|
||||||
|
<field name="sequence" widget="handle"/>
|
||||||
|
<field name="number"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="recognition_count"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_form" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.form</field>
|
||||||
|
<field name="model">fusion.plating.value</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Value">
|
||||||
|
<header/>
|
||||||
|
<sheet>
|
||||||
|
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
||||||
|
<div class="oe_title">
|
||||||
|
<label for="name"/>
|
||||||
|
<h1><field name="name" placeholder="e.g. Do What's Best for the Customer"/></h1>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="number"/>
|
||||||
|
<field name="sequence"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="icon" placeholder="fa-star"/>
|
||||||
|
<field name="color" widget="color_picker"/>
|
||||||
|
<field name="recognition_count"/>
|
||||||
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="Description">
|
||||||
|
<field name="description" placeholder="What does this value mean? How does it show up in daily work?"/>
|
||||||
|
</page>
|
||||||
|
<page string="Stories & Examples">
|
||||||
|
<field name="examples" placeholder="Stories of people living this value."/>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_kanban" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.kanban</field>
|
||||||
|
<field name="model">fusion.plating.value</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<kanban default_group_by="set_id" class="o_fp_value_kanban">
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="number"/>
|
||||||
|
<field name="icon"/>
|
||||||
|
<field name="color"/>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="recognition_count"/>
|
||||||
|
<templates>
|
||||||
|
<t t-name="card">
|
||||||
|
<div t-attf-class="o_fp_value_card oe_kanban_color_#{record.color.raw_value}">
|
||||||
|
<div class="d-flex align-items-start justify-content-between">
|
||||||
|
<div class="o_fp_value_number">
|
||||||
|
<t t-if="record.number.raw_value">
|
||||||
|
#<field name="number"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<i t-attf-class="fa #{record.icon.raw_value or 'fa-star'}" aria-hidden="true"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<i t-attf-class="fa #{record.icon.raw_value or 'fa-star'} o_fp_value_icon text-muted" aria-hidden="true"/>
|
||||||
|
</div>
|
||||||
|
<div class="o_fp_value_name mt-2">
|
||||||
|
<strong><field name="name"/></strong>
|
||||||
|
</div>
|
||||||
|
<div class="o_fp_value_meta mt-2 small text-muted">
|
||||||
|
<i class="fa fa-thumbs-up me-1" aria-hidden="true"/>
|
||||||
|
<field name="recognition_count"/> recognitions
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
|
</kanban>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_fp_value_search" model="ir.ui.view">
|
||||||
|
<field name="name">fp.value.search</field>
|
||||||
|
<field name="model">fusion.plating.value</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search string="Values">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="set_id"/>
|
||||||
|
<field name="number"/>
|
||||||
|
<filter string="Archived" name="archived" domain="[('active', '=', False)]"/>
|
||||||
|
<group>
|
||||||
|
<filter string="Set" name="group_set" context="{'group_by': 'set_id'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_fp_value" model="ir.actions.act_window">
|
||||||
|
<field name="name">Values</field>
|
||||||
|
<field name="res_model">fusion.plating.value</field>
|
||||||
|
<field name="view_mode">kanban,list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Add a value to your shop's set
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Values are your shop's fundamentals — short, memorable
|
||||||
|
statements of how people are expected to behave. Create a
|
||||||
|
Value Set first, then add values to it.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_hr_employee_form_fp_culture" model="ir.ui.view">
|
||||||
|
<field name="name">hr.employee.form.fp.culture</field>
|
||||||
|
<field name="model">hr.employee</field>
|
||||||
|
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//notebook" position="inside">
|
||||||
|
<page string="Culture" name="fp_culture">
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="x_fc_recognition_count"/>
|
||||||
|
<field name="x_fc_last_recognized_date"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<field name="x_fc_recognition_ids" readonly="1">
|
||||||
|
<list>
|
||||||
|
<field name="reference"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="value_id"/>
|
||||||
|
<field name="nominated_by_id"/>
|
||||||
|
<field name="nomination_date"/>
|
||||||
|
<field name="state" widget="badge"
|
||||||
|
decoration-info="state == 'draft'"
|
||||||
|
decoration-success="state == 'published'"
|
||||||
|
decoration-muted="state == 'archived'"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user