feat(configurator): fp.part.catalog — customer part library with views

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-12 18:24:54 -04:00
parent 73b7325b46
commit 87325e2caf
4 changed files with 213 additions and 1 deletions

View File

@@ -4,3 +4,5 @@
# Part of the Fusion Plating product family.
from . import fp_treatment
from . import fp_part_catalog
from . import fp_coating_config

View File

@@ -0,0 +1,65 @@
# -*- 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 FpPartCatalog(models.Model):
"""Customer part library.
Stores geometry, material, and complexity data for parts that
customers send repeatedly. New orders reference existing catalog
entries for instant re-quoting; one-off parts create new entries.
"""
_name = 'fp.part.catalog'
_description = 'Fusion Plating — Part Catalog'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'partner_id, part_number, name'
name = fields.Char(string='Part Name', required=True, tracking=True)
partner_id = fields.Many2one(
'res.partner', string='Customer', required=True, ondelete='cascade',
tracking=True, domain="[('customer_rank', '>', 0)]",
)
part_number = fields.Char(string='Part Number', tracking=True, help="Customer's part number (e.g. VS-R392007E01).")
revision = fields.Char(string='Revision', help='Revision letter or number (e.g. Rev: 1B).')
substrate_material = fields.Selection(
[('aluminium', 'Aluminium'), ('steel', 'Steel'), ('stainless', 'Stainless Steel'),
('copper', 'Copper'), ('titanium', 'Titanium'), ('other', 'Other')],
string='Substrate Material', default='steel',
)
geometry_source = fields.Selection(
[('3d_model', '3D Model'), ('manual', 'Manual Measurements'), ('pdf_drawing', 'PDF Drawing')],
string='Geometry Source', default='manual',
)
model_attachment_id = fields.Many2one('ir.attachment', string='3D Model File', help='STEP, STL, or IGES file.')
drawing_attachment_ids = fields.Many2many(
'ir.attachment', 'fp_part_catalog_drawing_rel', 'part_catalog_id', 'attachment_id', string='PDF Drawings',
)
surface_area = fields.Float(string='Surface Area', digits=(12, 4))
surface_area_uom = fields.Selection(
[('sq_in', 'sq in'), ('sq_ft', 'sq ft'), ('sq_cm', 'sq cm'), ('sq_m', 'sq m')],
string='Surface Area UoM', default='sq_in',
)
weight = fields.Float(string='Weight (kg)', digits=(12, 4))
dimensions_length = fields.Float(string='Length', digits=(12, 4))
dimensions_width = fields.Float(string='Width', digits=(12, 4))
dimensions_height = fields.Float(string='Height', digits=(12, 4))
complexity = fields.Selection(
[('simple', 'Simple'), ('moderate', 'Moderate'), ('complex', 'Complex'), ('very_complex', 'Very Complex')],
string='Complexity', default='simple',
)
masking_zones = fields.Integer(string='Masking Zones', help='Number of areas requiring masking.')
masking_description = fields.Text(string='Masking Description', help='e.g. "Mask threaded holes, mask bore ID"')
has_blind_holes = fields.Boolean(string='Has Blind Holes')
has_recesses = fields.Boolean(string='Has Recesses')
has_threads = fields.Boolean(string='Has Threads')
notes = fields.Html(string='Notes')
active = fields.Boolean(string='Active', default=True)
_sql_constraints = [
('fp_part_catalog_partner_partnum_uniq', 'unique(partner_id, part_number)',
'Part number must be unique per customer.'),
]