2026-09-21 16:43:23 +05:30

96 lines
4.6 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class GarmentFabricRoll(models.Model):
_name = 'garment.fabric.roll'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Fabric Roll Inventory Tracking'
_order = 'name desc'
name = fields.Char(string='Roll Number', required=True, default=lambda self: _('New'), copy=False, tracking=True)
product_id = fields.Many2one('product.product', string='Fabric Product', required=True)
fabric_type_id = fields.Many2one('garment.fabric.type', string='Fabric Structure')
color_id = fields.Many2one('garment.color', string='Color / Shade')
shade_lot = fields.Char(string='Shade / Dyeing Lot Number', required=True, index=True, tracking=True)
barcode = fields.Char(string='Barcode / QR Code', index=True, copy=False)
# Technical Specifications
gsm = fields.Integer(string='GSM (Actual)', required=True, default=180)
width = fields.Float(string='Width (Inches)', required=True, default=30.0)
width_type = fields.Selection([('tube', 'Tubular'), ('open', 'Open Width')], string='Width Type', default='tube')
yarn_count = fields.Char(string='Yarn Count', default='30s Combed')
# Quantitative Weights (Kg)
gross_weight = fields.Float(string='Gross Weight (Kg)', required=True, default=25.0)
tare_weight = fields.Float(string='Tare / Core Weight (Kg)', default=0.8)
net_weight = fields.Float(string='Initial Net Weight (Kg)', compute='_compute_net_weight', store=True)
length_meters = fields.Float(string='Fabric Length (Meters)', default=75.0)
# Consumption & Balance
issued_weight = fields.Float(string='Issued Weight (Kg)', default=0.0)
scrap_weight = fields.Float(string='End-Bit Scrap (Kg)', default=0.0)
remaining_weight = fields.Float(string='Remaining Weight (Kg)', compute='_compute_remaining_weight', store=True)
# Origin & Storage
supplier_id = fields.Many2one('res.partner', string='Fabric Mill / Supplier', domain=[('supplier_rank', '>', 0)])
purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order Ref')
date_received = fields.Date(string='Date Received', default=fields.Date.today)
location_id = fields.Many2one('stock.location', string='Storage Warehouse Location')
# Workflow State
status = fields.Selection([
('received', 'Received / Uninspected'),
('inspected', 'Inspected'),
('approved', 'Quality Approved (Ready to Cut)'),
('issued', 'Partially Issued'),
('exhausted', 'Fully Exhausted'),
('rejected', 'Quality Rejected (Quarantine)'),
], string='Roll Status', default='received', tracking=True, required=True)
# Inspections
inspection_ids = fields.One2many('garment.fabric.inspection', 'roll_id', string='Fabric Inspections')
inspection_count = fields.Integer(string='Inspections', compute='_compute_inspection_count')
@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.roll') or _('ROLL-%s') % fields.Date.today().strftime('%Y%m%d')
if not vals.get('barcode'):
vals['barcode'] = vals['name']
return super().create(vals_list)
@api.depends('gross_weight', 'tare_weight')
def _compute_net_weight(self):
for roll in self:
roll.net_weight = max(0.0, roll.gross_weight - roll.tare_weight)
@api.depends('net_weight', 'issued_weight', 'scrap_weight')
def _compute_remaining_weight(self):
for roll in self:
rem = roll.net_weight - roll.issued_weight - roll.scrap_weight
roll.remaining_weight = max(0.0, round(rem, 2))
if roll.remaining_weight <= 0.2 and roll.status in ['approved', 'issued']:
roll.status = 'exhausted'
@api.depends('inspection_ids')
def _compute_inspection_count(self):
for roll in self:
roll.inspection_count = len(roll.inspection_ids)
def action_create_inspection(self):
self.ensure_one()
insp = self.env['garment.fabric.inspection'].create({
'roll_id': self.id,
'target_gsm': self.gsm,
'target_width': self.width,
'inspected_meters': min(20.0, self.length_meters),
})
return {
'name': _('Fabric 4-Point Inspection'),
'type': 'ir.actions.act_window',
'res_model': 'garment.fabric.inspection',
'res_id': insp.id,
'view_mode': 'form',
}