folder rename

This commit is contained in:
gsinghpal
2026-04-16 20:53:53 -04:00
parent 3f3ddcbab4
commit 7c7ef06057
634 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# -*- 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_n299_level
from . import fp_nuclear_program
from . import fp_nuclear_itp
from . import fp_10cfr21_report
from . import fp_nuclear_pedigree
from . import fp_cnsc_licence
from . import fp_customer_spec
from . import fp_ncr
from . import res_company

View File

@@ -0,0 +1,166 @@
# -*- 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 Fp10CFR21Report(models.Model):
"""10 CFR Part 21 — Reporting of Defects and Noncompliance.
10 CFR Part 21 is the US Nuclear Regulatory Commission regulation
that requires suppliers of basic components to nuclear facilities
to evaluate potential defects and noncompliances, and to report
reportable ones to the NRC within 60 days of discovery.
The typical workflow is:
1. discovery — something is observed that might be a defect
2. evaluation — determine whether it rises to the level of a
"substantial safety hazard" (reportable)
3. reportable — yes, it's reportable → file with NRC
or
not_reportable — evaluation closes with a documented basis
4. reported — notice filed with NRC and affected customers
5. closed — corrective action verified, record sealed
The record has a due date that is 60 days after discovery, driven by
the `days_since_discovery` computed field.
"""
_name = 'fusion.plating.10cfr21.report'
_description = 'Fusion Plating — 10 CFR Part 21 Defect Report'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'discovery_date desc, id desc'
name = fields.Char(
string='Reference',
required=True,
copy=False,
readonly=True,
default=lambda self: self._default_name(),
tracking=True,
)
discovery_date = fields.Date(
string='Discovery Date',
required=True,
default=lambda self: fields.Date.context_today(self),
tracking=True,
)
report_date = fields.Date(
string='Report Date',
tracking=True,
help='Date the notification was filed. 10 CFR 21 requires reporting '
'within 60 days of discovery for reportable defects.',
)
days_since_discovery = fields.Integer(
string='Days Since Discovery',
compute='_compute_days_since_discovery',
search='_search_days_since_discovery',
)
part_description = fields.Html(
string='Part / Component',
)
defect_description = fields.Html(
string='Defect Description',
)
customer_ids = fields.Many2many(
'res.partner',
'fp_10cfr21_customer_rel',
'report_id',
'partner_id',
string='Affected Customers',
)
ncr_id = fields.Many2one(
'fusion.plating.ncr',
string='Source NCR',
help='The non-conformance report that triggered the 10 CFR 21 '
'evaluation.',
)
reportable = fields.Boolean(
string='Reportable',
tracking=True,
help='Set after evaluation. True means the defect rises to the '
'level of a substantial safety hazard and must be reported.',
)
corrective_action = fields.Html(
string='Corrective Action',
)
state = fields.Selection(
[
('discovery', 'Discovery'),
('evaluation', 'Evaluation'),
('reportable', 'Reportable'),
('reported', 'Reported'),
('not_reportable', 'Not Reportable'),
('closed', 'Closed'),
],
string='Status',
default='discovery',
required=True,
tracking=True,
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
active = fields.Boolean(default=True)
@api.model
def _default_name(self):
seq = self.env['ir.sequence'].next_by_code(
'fusion.plating.10cfr21.report'
)
return seq or '/'
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get('name') or vals.get('name') == '/':
vals['name'] = self._default_name()
return super().create(vals_list)
@api.depends('discovery_date')
def _compute_days_since_discovery(self):
today = fields.Date.context_today(self)
for rec in self:
if rec.discovery_date:
rec.days_since_discovery = (today - rec.discovery_date).days
else:
rec.days_since_discovery = 0
def _search_days_since_discovery(self, operator, value):
today = fields.Date.context_today(self)
from datetime import timedelta
target = today - timedelta(days=value)
if operator in ('>=', '>'):
date_op = '<=' if operator == '>=' else '<'
return [('discovery_date', date_op, target)]
if operator in ('<=', '<'):
date_op = '>=' if operator == '<=' else '>'
return [('discovery_date', date_op, target)]
if operator == '=':
return [('discovery_date', '=', target)]
return [('discovery_date', '!=', target)]
def action_start_evaluation(self):
self.write({'state': 'evaluation'})
def action_mark_reportable(self):
self.write({'state': 'reportable', 'reportable': True})
def action_mark_not_reportable(self):
self.write({'state': 'not_reportable', 'reportable': False})
def action_file_report(self):
self.write({
'state': 'reported',
'report_date': fields.Date.context_today(self),
})
def action_close(self):
self.write({'state': 'closed'})
def action_reset_to_discovery(self):
self.write({'state': 'discovery'})

View File

@@ -0,0 +1,99 @@
# -*- 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 fields, models
class FpCnscLicence(models.Model):
"""CNSC Licence record.
The Canadian Nuclear Safety Commission (CNSC) regulates all nuclear
activities in Canada. A plating / finishing supplier that works on
nuclear items may hold — or be listed under — one or more CNSC
licences:
* Class II nuclear facility licence (on-site sources,
irradiators, handling of nuclear substances)
* Transport licence for nuclear substances
* Export licence for controlled nuclear items
This record tracks the licence number, issue and expiry dates, and
any key conditions so the facility can manage renewals and
compliance awareness.
"""
_name = 'fusion.plating.cnsc.licence'
_description = 'Fusion Plating — CNSC Licence'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'expiry_date, name'
name = fields.Char(
string='Title',
required=True,
tracking=True,
)
licence_number = fields.Char(
string='Licence Number',
required=True,
tracking=True,
)
facility_id = fields.Many2one(
'fusion.plating.facility',
string='Facility',
tracking=True,
)
company_id = fields.Many2one(
'res.company',
related='facility_id.company_id',
store=True,
readonly=True,
)
licence_type = fields.Selection(
[
('class_ii_nuclear_facility', 'Class II Nuclear Facility'),
('transport', 'Transport of Nuclear Substances'),
('export', 'Export of Controlled Nuclear Items'),
('other', 'Other'),
],
string='Licence Type',
default='class_ii_nuclear_facility',
required=True,
tracking=True,
)
issue_date = fields.Date(
string='Issue Date',
tracking=True,
)
expiry_date = fields.Date(
string='Expiry Date',
tracking=True,
)
conditions = fields.Html(
string='Licence Conditions',
)
state = fields.Selection(
[
('active', 'Active'),
('expiring', 'Expiring Soon'),
('expired', 'Expired'),
('revoked', 'Revoked'),
],
string='Status',
default='active',
required=True,
tracking=True,
)
attachment_id = fields.Many2one(
'ir.attachment',
string='Licence Document',
)
active = fields.Boolean(default=True)
_sql_constraints = [
(
'fp_cnsc_licence_number_uniq',
'unique(licence_number, company_id)',
'CNSC licence number must be unique per company.',
),
]

View File

@@ -0,0 +1,52 @@
# -*- 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 fields, models
class FpCustomerSpec(models.Model):
"""Extend the quality customer-spec library with nuclear flags.
When a customer spec is flagged `x_fc_is_nuclear`, the system will
surface the N299 level, NQA-1 applicability and nuclear customer
type so that jobs referencing the spec can inherit the correct
retention and traceability rules.
"""
_inherit = 'fusion.plating.customer.spec'
x_fc_is_nuclear = fields.Boolean(
string='Nuclear Spec',
tracking=True,
help='Tick when this specification applies to nuclear work.',
)
x_fc_n299_level_id = fields.Many2one(
'fusion.plating.n299.level',
string='CSA N299 Level',
tracking=True,
)
x_fc_nqa1_applicable = fields.Boolean(
string='NQA-1 Applicable',
tracking=True,
help='Tick when this specification covers work subject to ASME NQA-1.',
)
x_fc_extended_retention_years = fields.Integer(
string='Extended Retention (Years)',
help='Override the default document-retention period for records '
'tied to this specification. Leave 0 to inherit the N299 level '
'default or the company default.',
)
x_fc_nuclear_customer_type = fields.Selection(
[
('opg', 'OPG — Ontario Power Generation'),
('bruce_power', 'Bruce Power'),
('aecl', 'AECL / CNL'),
('cameco', 'Cameco'),
('candu_energy', 'Candu Energy'),
('us_utility', 'US Nuclear Utility'),
('other', 'Other'),
],
string='Nuclear Customer Type',
tracking=True,
)

View File

@@ -0,0 +1,81 @@
# -*- 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 fields, models
class FpN299Level(models.Model):
"""CSA N299 Quality Assurance Level.
CSA N299 is the Canadian Standards Association standard covering
quality assurance program requirements for items and services
supplied to nuclear power plants. It defines four levels of quality
programs keyed to the safety classification of the supplied item:
Level 1 — Safety-critical items (highest)
Level 2 — Safety-related items
Level 3 — Items important to safety
Level 4 — Commercial grade (lowest)
The level drives how long nuclear quality records must be retained
(life-of-plant on the highest levels, commercial norms on the lowest)
and how rigorous the supplier's quality program must be.
"""
_name = 'fusion.plating.n299.level'
_description = 'Fusion Plating — CSA N299 Quality Level'
_order = 'level_number, code'
name = fields.Char(
string='Level',
required=True,
translate=True,
)
code = fields.Char(
string='Code',
required=True,
help='Short identifier, e.g. N299_L1.',
)
level_number = fields.Integer(
string='Level Number',
required=True,
help='1 (highest, safety-critical) to 4 (commercial grade).',
)
description = fields.Text(
string='Description',
translate=True,
)
retention_years = fields.Integer(
string='Retention (Years)',
required=True,
default=40,
help='Default records-retention period for this level. Canadian nuclear '
'quality records are typically retained for 40 years or longer at '
'the highest levels — often "life of plant".',
)
safety_classification = fields.Selection(
[
('safety_critical', 'Safety-critical'),
('safety_related', 'Safety-related'),
('important_to_safety', 'Important to safety'),
('commercial_grade', 'Commercial grade'),
],
string='Safety Classification',
required=True,
default='safety_critical',
)
active = fields.Boolean(default=True)
_sql_constraints = [
(
'fp_n299_level_code_uniq',
'unique(code)',
'N299 level code must be unique.',
),
(
'fp_n299_level_number_uniq',
'unique(level_number)',
'N299 level number must be unique.',
),
]

View File

@@ -0,0 +1,61 @@
# -*- 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 fields, models
class FpNcr(models.Model):
"""Extend the quality NCR with nuclear flags and 10 CFR 21 hook.
When an NCR is opened against a nuclear job, quality needs to
decide within the 10 CFR Part 21 evaluation clock whether the
non-conformance rises to the level of a substantial safety hazard.
The `x_fc_cfr21_report_id` link lets an NCR spawn a 10 CFR 21
record and track the outcome without duplicating the narrative.
"""
_inherit = 'fusion.plating.ncr'
x_fc_is_nuclear = fields.Boolean(
string='Nuclear Job',
tracking=True,
help='Tick when the non-conformance occurred on a nuclear job. '
'This flags the NCR for 10 CFR Part 21 evaluation.',
)
x_fc_n299_level_id = fields.Many2one(
'fusion.plating.n299.level',
string='CSA N299 Level',
tracking=True,
)
x_fc_cfr21_evaluated = fields.Boolean(
string='10 CFR 21 Evaluated',
tracking=True,
)
x_fc_cfr21_report_id = fields.Many2one(
'fusion.plating.10cfr21.report',
string='10 CFR 21 Report',
tracking=True,
)
def action_open_cfr21_report(self):
"""Create or open the linked 10 CFR Part 21 evaluation record."""
self.ensure_one()
if not self.x_fc_cfr21_report_id:
report = self.env['fusion.plating.10cfr21.report'].create({
'discovery_date': fields.Date.context_today(self),
'part_description': self.part_ref or '',
'defect_description': self.description or '',
'ncr_id': self.id,
})
self.write({
'x_fc_cfr21_report_id': report.id,
'x_fc_cfr21_evaluated': True,
})
return {
'name': '10 CFR 21 Report',
'type': 'ir.actions.act_window',
'res_model': 'fusion.plating.10cfr21.report',
'view_mode': 'form',
'res_id': self.x_fc_cfr21_report_id.id,
}

View File

@@ -0,0 +1,126 @@
# -*- 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 FpNuclearItp(models.Model):
"""Inspection and Test Plan (ITP).
For nuclear work, every critical part typically has an approved
Inspection and Test Plan that lists:
* Hold points (customer has to be present before work continues)
* Witness points (customer may be present)
* Review points (customer reviews records after the fact)
* Test methods and acceptance criteria
The ITP is usually prepared by the supplier, reviewed by the
customer, and formally approved before work can start. Once
approved, any deviation needs a change record.
"""
_name = 'fusion.plating.nuclear.itp'
_description = 'Fusion Plating — Nuclear Inspection and Test Plan'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'name desc'
name = fields.Char(
string='Reference',
required=True,
copy=False,
readonly=True,
default=lambda self: self._default_name(),
tracking=True,
)
customer_id = fields.Many2one(
'res.partner',
string='Customer',
required=True,
tracking=True,
)
part_number = fields.Char(
string='Part Number',
tracking=True,
)
drawing_ref = fields.Char(
string='Drawing Ref',
tracking=True,
)
n299_level_id = fields.Many2one(
'fusion.plating.n299.level',
string='CSA N299 Level',
tracking=True,
)
hold_points = fields.Html(
string='Hold / Witness / Review Points',
help='Document the hold, witness and review points the customer has '
'specified for this part.',
)
test_methods = fields.Html(
string='Test Methods',
)
acceptance_criteria = fields.Html(
string='Acceptance Criteria',
)
document_ids = fields.Many2many(
'ir.attachment',
'fp_nuclear_itp_attachment_rel',
'itp_id',
'attachment_id',
string='Attached Documents',
)
state = fields.Selection(
[
('draft', 'Draft'),
('customer_review', 'Customer Review'),
('approved', 'Approved'),
('in_use', 'In Use'),
('superseded', 'Superseded'),
],
string='Status',
default='draft',
required=True,
tracking=True,
)
customer_approval_date = fields.Date(
string='Customer Approval',
tracking=True,
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
active = fields.Boolean(default=True)
@api.model
def _default_name(self):
seq = self.env['ir.sequence'].next_by_code('fusion.plating.nuclear.itp')
return seq or '/'
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get('name') or vals.get('name') == '/':
vals['name'] = self._default_name()
return super().create(vals_list)
def action_submit_for_review(self):
self.write({'state': 'customer_review'})
def action_approve(self):
self.write({
'state': 'approved',
'customer_approval_date': fields.Date.context_today(self),
})
def action_put_in_use(self):
self.write({'state': 'in_use'})
def action_supersede(self):
self.write({'state': 'superseded'})
def action_reset_to_draft(self):
self.write({'state': 'draft'})

View File

@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
class FpNuclearPedigree(models.Model):
"""Nuclear Pedigree Traceability Record.
Nuclear pedigree is the unbroken chain of traceability from the raw
material a plated part was made from, through every processing
step, to the finished and shipped component. Nuclear operators use
pedigree records decades after shipment — long after the original
work order has aged out of normal systems — which is why the
retention clock is driven by the N299 level rather than a generic
document-retention rule.
Once the record is locked (typically at ship), the fields above the
chatter are read-only and all downstream edits should go through
the normal change-control process.
"""
_name = 'fusion.plating.nuclear.pedigree'
_description = 'Fusion Plating — Nuclear Pedigree Record'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'ship_date desc, id desc'
name = fields.Char(
string='Job / Lot Ref',
required=True,
tracking=True,
)
part_number = fields.Char(
string='Part Number',
tracking=True,
)
lot_serial = fields.Char(
string='Lot / Serial',
tracking=True,
)
customer_id = fields.Many2one(
'res.partner',
string='Customer',
required=True,
tracking=True,
)
n299_level_id = fields.Many2one(
'fusion.plating.n299.level',
string='CSA N299 Level',
tracking=True,
)
raw_material_cert_refs = fields.Char(
string='Raw Material Cert Refs',
help='Mill test report, CMTR, or material certificate reference(s).',
)
raw_material_heat_no = fields.Char(
string='Raw Material Heat No',
)
process_steps_json = fields.Text(
string='Process Steps',
help='Structured trail of each processing step the part went '
'through (station, operator, timestamp, parameters).',
)
operators_log = fields.Text(
string='Operators Log',
)
chemistry_cert_refs = fields.Char(
string='Chemistry Cert Refs',
)
test_results = fields.Html(
string='Test Results',
)
ship_date = fields.Date(
string='Ship Date',
tracking=True,
)
retention_until_date = fields.Date(
string='Retain Until',
compute='_compute_retention_until_date',
store=True,
help='Ship date plus the retention period of the assigned N299 level.',
)
attachment_ids = fields.Many2many(
'ir.attachment',
'fp_nuclear_pedigree_attachment_rel',
'pedigree_id',
'attachment_id',
string='Supporting Documents',
)
locked = fields.Boolean(
string='Locked',
default=False,
tracking=True,
help='Once the part has shipped, lock the pedigree to prevent '
'modification. Further changes must go through formal '
'change control.',
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
active = fields.Boolean(default=True)
@api.depends('ship_date', 'n299_level_id.retention_years')
def _compute_retention_until_date(self):
for rec in self:
if rec.ship_date and rec.n299_level_id and rec.n299_level_id.retention_years:
rec.retention_until_date = rec.ship_date + relativedelta(
years=rec.n299_level_id.retention_years
)
else:
rec.retention_until_date = False
def action_lock(self):
self.write({'locked': True})
def action_unlock(self):
self.write({'locked': False})

View 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 fields, models
class FpNuclearProgram(models.Model):
"""Nuclear Quality Program per facility.
A facility that supplies the nuclear industry typically runs a
documented quality program aligned to CSA N299 (Canada) and/or
NQA-1 (US), and is listed on one or more nuclear operators'
approved supplier lists. This record tracks the program manual
revision, the target N299 level, supplier certification status, and
the audit cadence (internal, customer, CNSC awareness).
A facility can have more than one nuclear program — e.g. a Level 3
program for OPG work and a separate NQA-1 program for a US utility.
"""
_name = 'fusion.plating.nuclear.program'
_description = 'Fusion Plating — Nuclear Quality Program'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'facility_id, name'
name = fields.Char(
string='Program',
required=True,
tracking=True,
)
facility_id = fields.Many2one(
'fusion.plating.facility',
string='Facility',
required=True,
tracking=True,
)
company_id = fields.Many2one(
'res.company',
related='facility_id.company_id',
store=True,
readonly=True,
)
n299_level_id = fields.Many2one(
'fusion.plating.n299.level',
string='CSA N299 Level',
tracking=True,
)
nqa1_applicable = fields.Boolean(
string='NQA-1 Applicable',
tracking=True,
help='Tick when this program covers work for US nuclear facilities '
'subject to ASME NQA-1.',
)
cnsc_licensed_supplier = fields.Boolean(
string='CNSC Licensed Supplier',
tracking=True,
help='Tick when the facility holds or is listed under a CNSC '
'licence or a CNSC licensee\'s approved supplier programme.',
)
program_manual_rev = fields.Char(
string='Program Manual Rev',
tracking=True,
)
last_audit_date = fields.Date(
string='Last Audit',
tracking=True,
)
next_audit_date = fields.Date(
string='Next Audit',
tracking=True,
)
state = fields.Selection(
[
('draft', 'Draft'),
('active', 'Active'),
('suspended', 'Suspended'),
('withdrawn', 'Withdrawn'),
],
string='Status',
default='draft',
required=True,
tracking=True,
)
notes = fields.Html(
string='Notes',
)
active = fields.Boolean(default=True)
def action_activate(self):
self.write({'state': 'active'})
def action_suspend(self):
self.write({'state': 'suspended'})
def action_withdraw(self):
self.write({'state': 'withdrawn'})
def action_reset_to_draft(self):
self.write({'state': 'draft'})

View File

@@ -0,0 +1,26 @@
# -*- 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 fields, models
class ResCompany(models.Model):
"""Extend company with a default nuclear records retention policy.
Nuclear quality records typically have to be retained for 40 years
or longer — far beyond the standard document-retention rule of a
commercial shop. This field sets the company-wide default used
when a pedigree record has no N299 level linked or when a higher
authority needs to be applied.
"""
_inherit = 'res.company'
x_fc_nuclear_retention_years = fields.Integer(
string='Nuclear Retention (Years)',
default=40,
help='Default records-retention period for nuclear quality records, '
'applied when no N299 level or spec override is set. Typical '
'Canadian nuclear practice is 40 years or life-of-plant.',
)