This commit is contained in:
gsinghpal
2026-04-13 02:35:35 -04:00
parent 1176ba68ae
commit 0ff8c0b93f
116 changed files with 14227 additions and 2406 deletions

View File

@@ -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

View File

@@ -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.'),
]

View File

@@ -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)

View File

@@ -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},
}

View File

@@ -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',
)

View File

@@ -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,
)