Garment_ERP/addons/garment_erp/models/fabric_inspection.py
2026-09-21 16:43:23 +05:30

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'})