102 lines
5.0 KiB
Python
102 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models, fields, api, _
|
|
|
|
class GarmentFabricInspection(models.Model):
|
|
_name = 'garment.fabric.inspection'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_description = 'Fabric 4-Point System Quality Inspection'
|
|
_order = 'name desc'
|
|
|
|
name = fields.Char(string='Inspection Number', required=True, default=lambda self: _('New'), copy=False)
|
|
roll_id = fields.Many2one('garment.fabric.roll', string='Fabric Roll', required=True, tracking=True)
|
|
supplier_id = fields.Many2one('res.partner', string='Supplier', related='roll_id.supplier_id', readonly=True)
|
|
fabric_product_id = fields.Many2one('product.product', string='Fabric Product', related='roll_id.product_id', readonly=True)
|
|
shade_lot = fields.Char(string='Shade / Dyeing Lot', related='roll_id.shade_lot', readonly=True)
|
|
|
|
# Inspector & Date
|
|
inspector_id = fields.Many2one('res.users', string='Quality Inspector', default=lambda self: self.env.user, tracking=True)
|
|
date_inspected = fields.Date(string='Inspection Date', default=fields.Date.today, tracking=True)
|
|
|
|
# GSM & Width Verification
|
|
target_gsm = fields.Integer(string='Target GSM', default=180)
|
|
actual_gsm = fields.Integer(string='Actual GSM Measured', default=180)
|
|
target_width = fields.Float(string='Target Width (Inches)', default=30.0)
|
|
actual_width = fields.Float(string='Actual Width (Inches)', default=30.0)
|
|
|
|
# Shade Evaluation
|
|
shade_grade = fields.Selection([
|
|
('grade_a', 'Grade A - Exact Match with Master Swatch'),
|
|
('grade_b', 'Grade B - Slight Variation (Approved)'),
|
|
('grade_c', 'Grade C - Noticeable Variation (Group Separately)'),
|
|
('grade_d', 'Grade D - Severely Off-Shade (Rejected)'),
|
|
], string='Shade / Color Evaluation', default='grade_a', required=True, tracking=True)
|
|
|
|
# 4-Point Defect Scoring System
|
|
# Points 1 to 4 based on defect length:
|
|
# 1 pt: Defect up to 3 inches
|
|
# 2 pts: Defect over 3 up to 6 inches
|
|
# 3 pts: Defect over 6 up to 9 inches
|
|
# 4 pts: Defect over 9 inches or any hole
|
|
defects_1pt_count = fields.Integer(string='1-Point Defects (<=3")', default=0)
|
|
defects_2pt_count = fields.Integer(string='2-Point Defects (3"-6")', default=0)
|
|
defects_3pt_count = fields.Integer(string='3-Point Defects (6"-9")', default=0)
|
|
defects_4pt_count = fields.Integer(string='4-Point Defects (>9" or Holes)', default=0)
|
|
|
|
total_defect_points = fields.Integer(string='Total Defect Points', compute='_compute_points', store=True)
|
|
inspected_meters = fields.Float(string='Inspected Length (Meters)', default=20.0, required=True)
|
|
|
|
# 4-Point Formula: (Total Points * 100) / (Inspected Meters * Fabric Width in Meters)
|
|
score_per_100_sqm = fields.Float(string='Score / 100 Sq. Meters', compute='_compute_points', store=True)
|
|
max_allowed_score = fields.Float(string='AQL Max Points Threshold', default=28.0, help='Standard industry threshold: 28 points per 100 sq meters')
|
|
|
|
# Quantitative Results
|
|
passed_meters = fields.Float(string='Passed Quantity (Meters)')
|
|
rejected_meters = fields.Float(string='Rejected Quantity (Meters)')
|
|
|
|
# Status
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('inspected', 'Inspected'),
|
|
('passed', 'Quality Passed'),
|
|
('failed', 'Quality Failed / Rejected'),
|
|
], string='Inspection Verdict', default='draft', tracking=True, required=True)
|
|
remarks = fields.Text(string='Inspector Remarks / Observations')
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get('name', _('New')) == _('New'):
|
|
vals['name'] = self.env['ir.sequence'].next_by_code('garment.fabric.inspection') or _('FINSP/%s') % fields.Date.today().strftime('%Y%m%d')
|
|
return super().create(vals_list)
|
|
|
|
@api.depends('defects_1pt_count', 'defects_2pt_count', 'defects_3pt_count', 'defects_4pt_count', 'inspected_meters', 'actual_width')
|
|
def _compute_points(self):
|
|
for insp in self:
|
|
total_pts = (insp.defects_1pt_count * 1) + (insp.defects_2pt_count * 2) + (insp.defects_3pt_count * 3) + (insp.defects_4pt_count * 4)
|
|
insp.total_defect_points = total_pts
|
|
# Width in meters: width in inches * 0.0254
|
|
width_meters = (insp.actual_width or 30.0) * 0.0254
|
|
area_sqm = (insp.inspected_meters or 1.0) * width_meters
|
|
if area_sqm > 0:
|
|
insp.score_per_100_sqm = round((total_pts * 100.0) / area_sqm, 1)
|
|
else:
|
|
insp.score_per_100_sqm = 0.0
|
|
|
|
def action_pass(self):
|
|
self.ensure_one()
|
|
self.write({
|
|
'state': 'passed',
|
|
'passed_meters': self.roll_id.length_meters,
|
|
'rejected_meters': 0.0,
|
|
})
|
|
self.roll_id.write({'status': 'approved'})
|
|
|
|
def action_fail(self):
|
|
self.ensure_one()
|
|
self.write({
|
|
'state': 'failed',
|
|
'passed_meters': 0.0,
|
|
'rejected_meters': self.roll_id.length_meters,
|
|
})
|
|
self.roll_id.write({'status': 'rejected'})
|