# -*- coding: utf-8 -*- from odoo import models, fields, api, _ class GarmentDefectType(models.Model): _name = 'garment.defect.type' _description = 'Garment Quality Defect Category' _order = 'category, name' name = fields.Char(string='Defect Name', required=True) code = fields.Char(string='Defect Code', required=True) category = fields.Selection([ ('stitching', 'Stitching / Sewing Defect'), ('fabric', 'Fabric / Yarn Flaw'), ('measurement', 'Measurement / Spec Variance'), ('print_embroidery', 'Print / Embroidery Defect'), ('finishing_packing', 'Finishing / Staining / Packing'), ], string='Category', default='stitching', required=True) severity = fields.Selection([ ('minor', 'Minor Defect'), ('major', 'Major Defect'), ('critical', 'Critical (Must Reject)'), ], string='Defect Severity', default='major') active = fields.Boolean(default=True) class GarmentQualityInspection(models.Model): _name = 'garment.quality.inspection' _inherit = ['mail.thread', 'mail.activity.mixin'] _description = 'Garment Quality Control Inspection' _order = 'name desc' name = fields.Char(string='Inspection Number', required=True, default=lambda self: _('New'), copy=False, tracking=True) inspection_stage = fields.Selection([ ('fabric', '1. Fabric Inspection'), ('cutting', '2. Cutting Section QC'), ('sewing_inline', '3. Sewing Inline Roaming QC'), ('sewing_endline', '4. Sewing Endline 100% Checking'), ('jobwork', '5. Job Work Inward QC'), ('final_aql', '6. Final AQL 2.5 Pre-Shipment Audit'), ], string='Inspection Stage', default='sewing_endline', required=True, tracking=True) production_plan_id = fields.Many2one('garment.production.plan', string='Production Order', tracking=True) style_id = fields.Many2one('garment.style', string='Garment Style', tracking=True) color_id = fields.Many2one('garment.color', string='Color') size_id = fields.Many2one('garment.size', string='Size') bundle_id = fields.Many2one('garment.bundle', string='Bundle Ref') sewing_line_id = fields.Many2one('garment.sewing.line', string='Sewing Line') inspector_id = fields.Many2one('res.users', string='QA Inspector', default=lambda self: self.env.user, tracking=True) date_inspected = fields.Date(string='Inspection Date', default=fields.Date.today, tracking=True) # Quantities & AQL total_lot_qty = fields.Integer(string='Lot / Batch Quantity', default=100) sample_size = fields.Integer(string='Sample Quantity Checked', default=20, required=True) passed_qty = fields.Integer(string='Passed Quantity', default=0, tracking=True) failed_qty = fields.Integer(string='Defective Quantity', default=0, tracking=True) rework_qty = fields.Integer(string='Sent for Rework', default=0) scrapped_qty = fields.Integer(string='Permanently Scrapped', default=0) defect_line_ids = fields.One2many('garment.quality.defect.line', 'inspection_id', string='Defect Details') verdict = fields.Selection([ ('passed', 'Quality Approved (Pass)'), ('rework_needed', 'Rework Required'), ('rejected', 'Completely Rejected / Scrapped'), ], string='Final Verdict', default='passed', tracking=True, required=True) rework_order_ids = fields.One2many('garment.rework.order', 'inspection_id', string='Linked Rework Orders') rework_count = fields.Integer(string='Rework Orders', compute='_compute_rework_count') remarks = fields.Text(string='Inspector Notes') @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.quality.inspection') or _('QC/%s') % fields.Date.today().strftime('%Y%m%d') return super(GarmentQualityInspection, self).create(vals_list) @api.depends('rework_order_ids') def _compute_rework_count(self): for rec in self: rec.rework_count = len(rec.rework_order_ids) def action_pass(self): self.write({'verdict': 'passed'}) def action_trigger_rework(self): """Creates an automatic Rework Order for failed pieces""" self.ensure_one() rework_qty = self.rework_qty or self.failed_qty or 1 rework = self.env['garment.rework.order'].create({ 'inspection_id': self.id, 'production_plan_id': self.production_plan_id.id if self.production_plan_id else False, 'style_id': self.style_id.id if self.style_id else False, 'color_id': self.color_id.id if self.color_id else False, 'size_id': self.size_id.id if self.size_id else False, 'bundle_id': self.bundle_id.id if self.bundle_id else False, 'rework_qty': rework_qty, 'defect_description': self.remarks or 'Defects identified during quality inspection', 'assigned_dept': 'sewing', }) self.write({'verdict': 'rework_needed', 'rework_qty': rework_qty}) return { 'name': _('Rework Order'), 'type': 'ir.actions.act_window', 'res_model': 'garment.rework.order', 'res_id': rework.id, 'view_mode': 'form', } class GarmentQualityDefectLine(models.Model): _name = 'garment.quality.defect.line' _description = 'Quality Defect Occurrence Line' inspection_id = fields.Many2one('garment.quality.inspection', string='Inspection', required=True, ondelete='cascade') defect_type_id = fields.Many2one('garment.defect.type', string='Defect Type', required=True) category = fields.Selection(related='defect_type_id.category', readonly=True) defect_count = fields.Integer(string='Defect Count', default=1, required=True) action_type = fields.Selection([ ('rework', 'Alteration / Rework'), ('scrap', 'Permanent Rejection / Scrap'), ], string='Action Required', default='rework') notes = fields.Char(string='Defect Location / Remarks')