changes
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from . import fp_maintenance_plan
|
||||
from . import fp_maintenance_node
|
||||
from . import fp_maintenance_label
|
||||
from . import maintenance_request
|
||||
from . import maintenance_equipment
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class FpMaintenanceLabel(models.Model):
|
||||
"""Simple tag model for equipment labels."""
|
||||
_name = 'fp.maintenance.label'
|
||||
_description = 'Fusion Plating — Equipment Label'
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(string='Name', required=True)
|
||||
color = fields.Integer(string='Colour')
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique(name)', 'Label name must be unique.'),
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class FpMaintenanceNode(models.Model):
|
||||
"""Maintenance checklist item.
|
||||
|
||||
Individual task or check within a maintenance plan.
|
||||
Auto-numbered on creation.
|
||||
"""
|
||||
_name = 'fp.maintenance.node'
|
||||
_description = 'Fusion Plating — Maintenance Node'
|
||||
_order = 'number desc'
|
||||
|
||||
name = fields.Char(
|
||||
string='Name',
|
||||
required=True,
|
||||
)
|
||||
number = fields.Integer(
|
||||
string='Number',
|
||||
readonly=True,
|
||||
copy=False,
|
||||
)
|
||||
plan_id = fields.Many2one(
|
||||
'fp.maintenance.plan',
|
||||
string='Plan',
|
||||
ondelete='set null',
|
||||
)
|
||||
active = fields.Boolean(default=True)
|
||||
company_id = fields.Many2one(
|
||||
'res.company',
|
||||
string='Company',
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if not vals.get('number'):
|
||||
last = self.sudo().search([], order='number desc', limit=1)
|
||||
vals['number'] = (last.number if last else 0) + 1
|
||||
return super().create(vals_list)
|
||||
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class FpMaintenancePlan(models.Model):
|
||||
"""Maintenance plan template.
|
||||
|
||||
Groups checklist nodes and links to an equipment category.
|
||||
Plans are selected when creating maintenance events.
|
||||
"""
|
||||
_name = 'fp.maintenance.plan'
|
||||
_description = 'Fusion Plating — Maintenance Plan'
|
||||
_inherit = ['mail.thread']
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(
|
||||
string='Name',
|
||||
required=True,
|
||||
tracking=True,
|
||||
help='e.g. "Tank A-10 Nickel Nichem HP 1170 - Daily Titration"',
|
||||
)
|
||||
equipment_category_id = fields.Many2one(
|
||||
'maintenance.equipment.category',
|
||||
string='Equipment Type',
|
||||
ondelete='set null',
|
||||
tracking=True,
|
||||
)
|
||||
description = fields.Html(string='Description')
|
||||
default_assignee_id = fields.Many2one(
|
||||
'res.users',
|
||||
string='Default Assignee',
|
||||
)
|
||||
node_ids = fields.One2many(
|
||||
'fp.maintenance.node',
|
||||
'plan_id',
|
||||
string='Checklist Items',
|
||||
)
|
||||
node_count = fields.Integer(
|
||||
string='Items',
|
||||
compute='_compute_node_count',
|
||||
)
|
||||
active = fields.Boolean(default=True)
|
||||
company_id = fields.Many2one(
|
||||
'res.company',
|
||||
string='Company',
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
|
||||
def _compute_node_count(self):
|
||||
for plan in self:
|
||||
plan.node_count = len(plan.node_ids)
|
||||
|
||||
def action_view_nodes(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': f'Items — {self.name}',
|
||||
'res_model': 'fp.maintenance.node',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('plan_id', '=', self.id)],
|
||||
'context': {'default_plan_id': self.id},
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class MaintenanceEquipment(models.Model):
|
||||
"""Extend standard maintenance.equipment with plating links."""
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
x_fc_tank_id = fields.Many2one(
|
||||
'fusion.plating.tank',
|
||||
string='Plating Tank',
|
||||
help='Link this equipment to a Fusion Plating tank.',
|
||||
)
|
||||
x_fc_facility_id = fields.Many2one(
|
||||
'fusion.plating.facility',
|
||||
string='Facility',
|
||||
)
|
||||
x_fc_location_name = fields.Char(
|
||||
string='Sub-Location',
|
||||
help='e.g. "PLANT1.BoilerRoom", "PLANT1.TankLine"',
|
||||
)
|
||||
x_fc_label_ids = fields.Many2many(
|
||||
'fp.maintenance.label',
|
||||
'fp_maintenance_equipment_label_rel',
|
||||
'equipment_id',
|
||||
'label_id',
|
||||
string='Labels',
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MaintenanceRequest(models.Model):
|
||||
"""Extend standard maintenance.request with plating-specific fields."""
|
||||
_inherit = 'maintenance.request'
|
||||
|
||||
x_fc_plan_id = fields.Many2one(
|
||||
'fp.maintenance.plan',
|
||||
string='Plan',
|
||||
)
|
||||
x_fc_node_id = fields.Many2one(
|
||||
'fp.maintenance.node',
|
||||
string='Checklist Item',
|
||||
)
|
||||
x_fc_labour_cost = fields.Monetary(
|
||||
string='Labour Cost',
|
||||
currency_field='x_fc_currency_id',
|
||||
)
|
||||
x_fc_currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
string='Currency',
|
||||
default=lambda self: self.env.company.currency_id,
|
||||
)
|
||||
x_fc_completed_at = fields.Datetime(
|
||||
string='Completed At',
|
||||
readonly=True,
|
||||
)
|
||||
x_fc_from_last = fields.Boolean(
|
||||
string='From Last Maintenance',
|
||||
help='When checked, the next recurrence is scheduled relative to '
|
||||
'completion date instead of a fixed calendar interval.',
|
||||
)
|
||||
x_fc_recurrence_days = fields.Integer(
|
||||
string='Recurrence Days',
|
||||
help='Number of days after completion to schedule the next event '
|
||||
'(only used with "From Last Maintenance").',
|
||||
)
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
if 'stage_id' in vals:
|
||||
for request in self:
|
||||
if request.stage_id.done and not request.x_fc_completed_at:
|
||||
request.x_fc_completed_at = fields.Datetime.now()
|
||||
self._maybe_schedule_from_last(request)
|
||||
elif not request.stage_id.done:
|
||||
request.x_fc_completed_at = False
|
||||
return res
|
||||
|
||||
def _maybe_schedule_from_last(self, request):
|
||||
"""Schedule next maintenance from completion date."""
|
||||
if not request.x_fc_from_last or not request.x_fc_recurrence_days:
|
||||
return
|
||||
next_date = fields.Datetime.now() + timedelta(
|
||||
days=request.x_fc_recurrence_days,
|
||||
)
|
||||
request.copy({
|
||||
'schedule_date': next_date,
|
||||
'x_fc_completed_at': False,
|
||||
'stage_id': self.env['maintenance.stage'].search(
|
||||
[('done', '=', False)], order='sequence', limit=1,
|
||||
).id,
|
||||
})
|
||||
_logger.info(
|
||||
'Scheduled next from-last maintenance for %s on %s',
|
||||
request.name, next_date,
|
||||
)
|
||||
Reference in New Issue
Block a user