Slink/sos_inventory/models/sos_ncmr.py

871 lines
43 KiB
Python
Executable File

from odoo import models, fields, api
from odoo.exceptions import UserError
from datetime import date,datetime
from odoo.exceptions import ValidationError
import base64
import io
import xlsxwriter
class NCMR_Model(models.Model):
_name = 'sos_ncmr'
_description = 'Non-Conforming Material Report'
_rec_name="ncmr_no"
_order = 'id desc'
ncmr_no = fields.Char(string="NCMR No",default=lambda self: self._generate_id(),readonly= True, required= True)
ncmr_date = fields.Date(string="NCMR Date",default=lambda self: fields.Date.today())
fg_name = fields.Many2one('sos_fg', string='FG Name')
fg_category = fields.Many2one('sos_testing_parameters',string="FG Category", compute="_compute_fg_category", store=True)
batch_no = fields.Char(string="Batch No")
department = fields.Char(string="Department")
status = fields.Selection([ ('open', 'Open'),('closed', 'Closed')], default='open' , string="Status")
material_name = fields.Many2one('sos_material', string="Material Name")
material_code = fields.Char(string="Material Code")
material_category = fields.Many2one('sos_material_configuration',string="Material Category")
rca_required = fields.Selection([('yes', 'Yes'),('no', 'No')], string="RCA Required",default="yes")
rca_notes_text=fields.Text(string="Notes")
sfg_name = fields.Many2one('sos_sfg', string="SFG Name")
sfg_code = fields.Char(string="SFG Code",related="sfg_name.sfg_code")
sfg_category = fields.Many2one('sos_sfg_configuration',string="SFG Category")
rejected_qty = fields.Integer(string="Rejected Quantity")
material_option = fields.Boolean('Materials', default=True)
sfg_option = fields.Boolean('Semi-Finished Goods')
fg_option = fields.Boolean('Finished Goods')
ncmr_type = fields.Selection([ ('new', 'New'),('return', 'Return')], default='new' , string="NCMR Type")
incoming_doc_ref = fields.Many2one('sos_iqi',string="IQI Ref No",readonly=True)
return_incoming_doc_ref = fields.Many2one('sos_return_iqi',string="IQI Ref No",readonly=True)
fir_incoming_doc_ref = fields.Many2one('sos_fir',string="FIR ref",readonly=True)
fg_incoming_doc_ref = fields.Many2one('sos_fir_brr',string="FIR ref",readonly=True)
return_fg_incoming_doc_ref = fields.Many2one('sos_return_fir',string="Return FIR ref",readonly=True)
incoming_responsibility = fields.Text(string="Incoming Responsibility")
qa_action = fields.Selection([ ('scrap', 'Scrap'),('rework', 'Rework')], string="Action")
dispensed_doc_ref = fields.Char(string="Dispensed Doc Ref")
dispensed_responsibility = fields.Text(string="Dispensed Responsibility")
approved_doc_ref = fields.Char(string="Approved Doc Ref")
approved_responsibility = fields.Text(string="Approved Responsibility")
customer_complaint_doc_ref = fields.Char(string="Customer Complaint Doc Ref")
customer_complaint_responsibility = fields.Text(string="Customer Complaint Responsibility")
approved_fg_doc_ref = fields.Char(string="Approved FG Doc Ref")
approved_fg_responsibility = fields.Text(string="Approved FG Responsibility")
returned_fg_doc_ref = fields.Char(string="Approved FG Doc Ref")
returned_fg_responsibility = fields.Text(string="Approved FG Responsibility")
finished_fg_assy = fields.Char()
finished_fg_assy_responsibility = fields.Text(string="Production Assy FG Responsibility")
description_of_nc = fields.Html(string="Description of Non-Conformities")
root_cause_of_nc = fields.Html(string="Root Cause of Non-Conformities")
containment_action_of_nc = fields.Html(string="Containment Action to close the Non-Conformities")
comments_on_capa = fields.Html(string="Comments on Corrective / Preventive Action ")
qa_comments=fields.Text(string="QA Comments")
qa_done_on = fields.Date(string="Verified On")
rd_user = fields.Many2many('res.users',string='R&D User', relation='sos_ncmr_rd_user_rel')
qa_by = fields.Many2one('res.users',string='QC In-Charge',readonly=True)
qa_sign = fields.Image(related="qa_by.signature_image",string='QC In-Charge',readonly=True)
qa_tested_on = fields.Datetime(string="Approved On")
line_ids = fields.One2many('sos_ncmr_line', 'ncmr_id', string="Line Ids",copy=True)
capa_line_ids = fields.One2many('sos_ncmr_capa_line', 'ncmr_id', string="CAPA Line Ids",copy=True)
line_count = fields.Integer(string='Number of Defects', compute='_compute_line_count', store=True)
unique_defect_count = fields.Integer(string='Required NCMR', compute='_compute_line_count', store=True)
material_line_count = fields.Integer(string='Number of Defects', compute='_compute_material_line_count', store=True)
fg_line_count = fields.Integer(string='Number of Defects', compute='_compute_fg_line_count', store=True)
material_unique_defect_count = fields.Integer(string='Required NCMR', compute='_compute_material_line_count', store=True)
fg_unique_defect_count = fields.Integer(string='Required NCMR', compute='_compute_fg_line_count', store=True)
defective_status_ids = fields.One2many('sos_ncmr_defective_status', 'ncmr_id', string='Defectives with Status')
opened_issues = fields.Integer(string="Issues Open", compute="_calculate_status")
closed_issues = fields.Integer(string="Issues Closed", compute="_calculate_status")
action_group = fields.Selection(
[('production', 'Production Team'), ('scg', 'SCG Team'), ('rd', 'R&D Team')],
string="Action By",
default="scg"
)
forward_on = fields.Datetime(string="Forwarded On")
forward_by = fields.Many2one('res.users',string='Forward By',readonly=True)
forward_sign = fields.Image(related="forward_by.signature_image",string='Sign',readonly=True)
forward_to = fields.Many2many('res.users', string='Forward To')
comments=fields.Text(string="Comments")
scg_approval_by = fields.Many2one('res.users',string='SCG Approved By',readonly=True)
scg_approval_sign = fields.Image(related="scg_approval_by.signature_image",string='SCG In-Charge',readonly=True)
scg_approval_on = fields.Datetime(string="Approved On")
scg_comments=fields.Text(string="Comments")
production_approval_by = fields.Many2one('res.users',string='Production In-Charge',readonly=True)
production_approval_sign = fields.Image(related="production_approval_by.signature_image",string='Production In-Charge',readonly=True)
production_approval_on = fields.Datetime(string="Approved On")
production_comments=fields.Text(string="Comments")
rework_action = fields.Selection(
[('inhouse', 'In-House'), ('outsourcing_vendor', 'Outsourcing Vendor'), ('supplier_replacement', 'Supplier Replacement')],
string="Rework Action",
default="inhouse"
)
rd_comments=fields.Text(string="Comments")
rd_approval_by = fields.Many2one('res.users',string='R&D In-Charge',readonly=True)
rd_approval_sign = fields.Image(related="rd_approval_by.signature_image",string='R&D In-Charge',readonly=True)
rd_approval_on = fields.Datetime(string="Approved On")
combined_incoming_doc_ref = fields.Reference(
selection=[
('sos_iqi', 'IQI Ref No'),
('sos_return_iqi', 'Return IQI Ref No'),
('sos_fir_brr', 'BRR Ref'),
('sos_return_fir', 'Return BRR FIR Ref'),
('sos_fir', 'FIR Ref')
],
string="Incoming Document Reference",
compute="_compute_combined_incoming_doc_ref",
store=False
)
supplier_name = fields.Many2one('sos_suppliers',string="Supplier Name",compute="_get_supplier_name")
service_provider_name = fields.Many2one('sos_service_providers',string="Service Provider Name",compute="_get_service_provider_name")
customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name",compute="_get_customer_name")
outsourcing_return_ref_no = fields.Many2one('sos_sfg_outsourcing_return_register',string="Outsourcing Return Ref No")
#Excel Write
def action_ncmr_report_orm_btn(self, from_date, to_date,force_download=True):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
headers = {
'S No':'S No',
'NCMRNo' : 'NCMR No',
'Product': 'Product',
'Date': 'Date',
'Issue Location': 'Issue Location',
'Customer Name/Supplier Name/Service Provider Name': 'Customer Name/Supplier Name/Service Provider Name',
'Customer/Supplier/Service':'Customer/Supplier/Service',
'Category':'Category',
'Defective': 'Problem Definition',
'Defect Qty': 'Defect Qty',
'Required NCMR': 'Required NCMR',
'Closed Complaint': 'Closed Complaint',
'Pending Complaint': 'Pending Complaint',
'Closure Rate %': 'Closure Rate (%)',
'PPM':'PPM',
'Status':'Status',
'Reason for delay': 'Reason for delay',
'Responsible': 'Responsible',
}
if from_date and to_date:
ncmr_lines = self.env['sos_ncmr'].search([
('ncmr_date', '>=', from_date),
('ncmr_date', '<=', to_date)
])
result = []
for line in ncmr_lines:
ncmrid = line.id
ncmr_no = line.ncmr_no
mat_name = line.material_category.material_name if line.material_category.material_name else None
sfg_name = line.sfg_category.sfg_name if line.sfg_category.sfg_name else None
fg_name = line.fg_name.display_name if line.fg_name.display_name else None
product = mat_name or sfg_name or fg_name
if line.incoming_responsibility:
parts = line.incoming_responsibility.split(",")
incom_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
incom_resp_dep = ''
if line.dispensed_responsibility:
parts = line.dispensed_responsibility.split(",")
dispe_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
dispe_resp_dep = ''
if line.approved_responsibility:
parts = line.approved_responsibility.split(",")
appvd_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
appvd_resp_dep = ''
if line.customer_complaint_responsibility:
parts = line.customer_complaint_responsibility.split(",")
cusmr_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
cusmr_resp_dep = ''
if line.approved_fg_responsibility:
parts = line.approved_fg_responsibility.split(",")
appfg_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
appfg_resp_dep = ''
if line.returned_fg_responsibility:
parts = line.returned_fg_responsibility.split(",")
rtnfg_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
rtnfg_resp_dep = ''
if line.finished_fg_assy_responsibility:
parts = line.finished_fg_assy_responsibility.split(",")
ffgas_resp_dep = parts[0].strip() + "-" + parts[2].strip() if len(parts) > 2 else ''
else:
ffgas_resp_dep = ''
responsibility = incom_resp_dep or dispe_resp_dep or appvd_resp_dep or cusmr_resp_dep or appfg_resp_dep or rtnfg_resp_dep or ffgas_resp_dep
custmer_name = None
suppler_name = None
serprdr_name = None
customer = None
supplier = None
serviceprovider = None
if line.customer_name and line.customer_name.customer_name:
custmer_name = line.customer_name.customer_name
customer = 'Customer'
if line.supplier_name and line.supplier_name.supplier_name:
suppler_name = line.supplier_name.supplier_name
supplier = 'Supplier'
if line.service_provider_name.service_provider_name:
serprdr_name = line.service_provider_name.service_provider_name
serviceprovider = 'Vendor'
cust_supp_serprdr_name = custmer_name or suppler_name or serprdr_name
cust_supp_serprdr = customer or supplier or serviceprovider
mat_type = line.material_name.material_type_id.name if line.material_name.material_type_id.name else None
fg_type = line.fg_name.fg_type if line.fg_name.fg_type else None
sfg_catgry = line.sfg_name.category if line.sfg_name.category else None
category = mat_type or fg_type or sfg_catgry
defect_qty = line.rejected_qty
status = line.status if line.status else 'Open'
required_ncmr = (
line.unique_defect_count if line.unique_defect_count not in (None, 0)
else line.fg_unique_defect_count if line.fg_unique_defect_count not in (None, 0)
else line.material_unique_defect_count if line.material_unique_defect_count not in (None, 0)
else 0
)
open_count = sum(1 for rec in line.defective_status_ids if rec.status == 'open')
closed_count = sum(1 for rec in line.defective_status_ids if rec.status == 'closed')
closure_rate = ((closed_count/required_ncmr)*100)
ppm = None
recevd_qty = line.combined_incoming_doc_ref
if not recevd_qty:
ppm = None
else:
received_qty = None
rejected_qty = None
if recevd_qty and hasattr(recevd_qty,'received_qty'):
received_qty = recevd_qty.received_qty
elif recevd_qty and hasattr(recevd_qty,'batch_size'):
received_qty = recevd_qty.batch_size
if recevd_qty and hasattr(recevd_qty,'rejected_qty'):
rejected_qty = recevd_qty.rejected_qty
if received_qty and rejected_qty is not None:
ppm = (rejected_qty / received_qty) * 10**6 #issue at PPM bcoz of diff name
else:
ppm = None
issue_location = ''
if line.incoming_doc_ref:
issue_location = 'IQI'
elif line.return_incoming_doc_ref:
issue_location = 'Return-IQI'
elif line.fir_incoming_doc_ref:
issue_location = 'FIR'
elif line.fg_incoming_doc_ref:
issue_location = 'FIR BRR'
elif line.return_fg_incoming_doc_ref:
issue_location = 'Return BRR'
if line.defective_status_ids:
defective_names = []
for fgname in line.defective_status_ids:
if fgname.defective_id:
defective_names.append(fgname.defective_id.name)
if fgname.material_defective_id:
defective_names.append(fgname.material_defective_id.name)
if fgname.fg_defective_id:
defective_names.append(fgname.fg_defective_id.name)
defective_names = list(set(defective_names))
else:
query = """
SELECT
sfg_defect.name AS Problem
FROM
sos_ncmr_line nl
JOIN
sos_ncmr n ON nl.ncmr_id = n.id
LEFT JOIN sos_ncmr_defective_status ds ON ds.ncmr_id = nl.ncmr_id
LEFT JOIN sos_ncmr_line_sos_sfg_defective_line_rel sfg_rel ON nl.id = sfg_rel.sos_ncmr_line_id
LEFT JOIN sos_sfg_defective_line sfg_defect ON sfg_rel.sos_sfg_defective_line_id = sfg_defect.id
WHERE
n.id = %s ;
"""
self.env.cr.execute(query,(ncmrid,))
record_list = self.env.cr.fetchall()
defective_names = [r[0] for r in record_list if r[0]]
result.append({
'S No':'',
'NCMRNo': line.ncmr_no,
'Product': product,
'Date': line.ncmr_date.strftime('%Y-%m-%d'),
'Issue Location': issue_location,
'Customer Name/Supplier Name/Service Provider Name':cust_supp_serprdr_name,
'Customer/Supplier/Service':cust_supp_serprdr,
'Category':category,
'Defective': defective_names,
'Defect Qty': defect_qty,
'Required NCMR': required_ncmr,
'Closed Complaint':closed_count,
'Pending Complaint':open_count,
'Closure Rate %':closure_rate,
'PPM':ppm,
'Status': status,
'Reason for delay':'',
'Responsible':responsibility
})
self._write_sheet(workbook, 'NMCR', result, headers)
workbook.close()
output.seek(0)
excel_data = output.read()
attachment = self.env['ir.attachment'].create({
'name': f'NCMR_Export.xlsx',
'type': 'binary',
'datas': base64.b64encode(excel_data),
'res_model': self._name,
'res_id': self.id,
'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
return {
'type': 'ir.actions.act_url',
'url': f'/web/content/{attachment.id}?download=true',
'target': 'self',
}
def _write_sheet(self, workbook, sheet_name, result, headers):
"""Write data to each sheet based on specified fields and custom headers."""
worksheet = workbook.add_worksheet(sheet_name)
for col, header in enumerate(headers.values()):
worksheet.write(0, col, header)
# Write data rows
for row_num, row in enumerate(result, start=1):
worksheet.write(row_num, 0, row_num)
for col_num, key in enumerate(headers.keys()):
value = row.get(key, '')
if isinstance(value, list):
value = ', '.join(str(v) for v in value)
worksheet.write(row_num, col_num, str(value))
@api.depends('incoming_doc_ref', 'return_incoming_doc_ref', 'fg_incoming_doc_ref','return_fg_incoming_doc_ref','fir_incoming_doc_ref')
def _compute_combined_incoming_doc_ref(self):
for record in self:
if record.incoming_doc_ref:
record.combined_incoming_doc_ref = f'sos_iqi,{record.incoming_doc_ref.id}'
elif record.return_incoming_doc_ref:
record.combined_incoming_doc_ref = f'sos_return_iqi,{record.return_incoming_doc_ref.id}'
elif record.fg_incoming_doc_ref:
record.combined_incoming_doc_ref = f'sos_fir_brr,{record.fg_incoming_doc_ref.id}'
elif record.return_fg_incoming_doc_ref:
record.combined_incoming_doc_ref = f'sos_return_fir,{record.return_fg_incoming_doc_ref.id}'
elif record.fir_incoming_doc_ref:
record.combined_incoming_doc_ref = f'sos_fir,{record.fir_incoming_doc_ref.id}'
else:
record.combined_incoming_doc_ref = False
@api.depends('combined_incoming_doc_ref')
def _get_supplier_name(self):
for record in self:
supplier = record.combined_incoming_doc_ref
if supplier and hasattr(supplier, 'supplier_name'):
record.supplier_name = supplier.supplier_name
else:
record.supplier_name = False # or '' if it's a Char field
@api.depends('combined_incoming_doc_ref')
def _get_service_provider_name(self):
for record in self:
service_provider = record.combined_incoming_doc_ref
if service_provider and hasattr(service_provider, 'service_provider_name'):
record.service_provider_name = service_provider.service_provider_name
else:
record.service_provider_name = False # or '' if it's a Char field
@api.depends('combined_incoming_doc_ref')
def _get_customer_name(self):
for record in self:
customer = record.combined_incoming_doc_ref
if customer and hasattr(customer, 'customer_name'):
record.customer_name = customer.customer_name
else:
record.customer_name = False # or '' if it's a Char field
@api.depends('fg_name')
def _compute_fg_category(self):
for record in self:
if record.fg_name:
record.fg_category = self.env['sos_testing_parameters'].search([('fg_name', '=', record.fg_name.id)], limit=1)
else:
record.fg_category = False
@api.onchange('material_option')
def _onchange_material_option(self):
if self.material_option:
self.sfg_option = False
self.fg_option = False
@api.onchange('sfg_option')
def _onchange_sfg_option(self):
if self.sfg_option:
self.material_option = False
self.fg_option = False
@api.onchange('fg_option')
def _onchange_fg_option(self):
if self.fg_option:
self.material_option = False
self.sfg_option = False
@api.depends('defective_status_ids.status')
def _calculate_status(self):
for record in self:
if record.sfg_option:
opened_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('defective_id','!=',False),
('status', '=', 'open')
])
# Count the number of closed issues
closed_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('defective_id','!=',False),
('status', '=', 'closed')
])
elif record.material_option:
opened_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('material_defective_id','!=',False),
('status', '=', 'open')
])
# Count the number of closed issues
closed_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('material_defective_id','!=',False),
('status', '=', 'closed')
])
else:
opened_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('fg_defective_id','!=',False),
('status', '=', 'open')
])
# Count the number of closed issues
closed_issues_count = self.env['sos_ncmr_defective_status'].search_count([
('ncmr_id', '=', record.id),
('fg_defective_id','!=',False),
('status', '=', 'closed')
])
if opened_issues_count == 0 and closed_issues_count > 0:
record.status = "closed"
record.opened_issues = opened_issues_count
record.closed_issues = closed_issues_count
@api.depends('line_ids', 'line_ids.defectives')
def _compute_line_count(self):
for record in self:
record.line_count = len(record.line_ids)
unique_defects = set()
for line in record.line_ids:
unique_defects.update(line.defectives.ids)
record.unique_defect_count = len(unique_defects)
@api.depends('line_ids', 'line_ids.material_defectives')
def _compute_material_line_count(self):
for record in self:
record.material_line_count = len(record.line_ids)
material_unique_defects = set()
for line in record.line_ids:
material_unique_defects.update(line.material_defectives.ids)
record.material_unique_defect_count = len(material_unique_defects)
@api.depends('line_ids', 'line_ids.fg_defectives')
def _compute_fg_line_count(self):
for record in self:
record.fg_line_count = len(record.line_ids)
fg_unique_defects = set()
for line in record.line_ids:
fg_unique_defects.update(line.fg_defectives.ids)
record.fg_unique_defect_count = len(fg_unique_defects)
def _generate_id(self):
self.qa_done_on = date.today()
sequence_util = self.env['sos_common_scripts']
return sequence_util.generate_sequence('sos_ncmr','NCMR', 'ncmr_no')
def action_forward_esign_btn(self):
send_email = self.env['sos_common_scripts']
all_closed = True
for record in self.defective_status_ids:
if record.status != 'closed':
all_closed = False
if not record.aodr_no:
raise UserError("All Status Should Be Closed")
return
if self.qa_action == "scrap":
if self.material_option:
material_type = "material"
column = "material_name"
elif self.sfg_option:
material_type = "sfg"
column = "sfg_name"
else:
material_type = "fg"
column = "fg_name"
# Creating the disposal register record
disposal_register = self.env['sos_disposal_register'].create({
'dr_no': send_email.generate_sequence('sos_disposal_register', 'DR', 'dr_no'),
'ncmr_no': self.id,
'goods_type': material_type,
column: getattr(self, column).id if getattr(self, column) else False # Dynamically assign value based on column name
})
return send_email.action_assign_signature(
self,
'forward_by',
'forward_on',
'sos_inventory.sos_qa_user'
)
else:
if all_closed or record.aodr_no:
self.status = 'closed'
if self.rework_action == "inhouse":
iqi_record = self.env['sos_iqi'].create({
'iqi_no': send_email.generate_sequence('sos_iqi', 'R-IQI', 'iqi_no'),
'material_option':self.material_option,
'sfg_option':self.sfg_option,
'received_qty': self.rejected_qty,
'iqi_type':'rework',
'material_name': self.material_name,
'material_code': self.material_name.material_code,
'sfg_name': self.sfg_name.id,
'sfg_code': self.sfg_name.sfg_code,
'supplier_name':self.incoming_doc_ref.supplier_name.id,
'service_provider_name':self.incoming_doc_ref.service_provider_name.id,
'old_iqi_ref': self.incoming_doc_ref.id,
'ir_id_unique_id':self.incoming_doc_ref.ir_id_unique_id.id,
'in_tact':self.incoming_doc_ref.in_tact
# 'test_report':self.incoming_doc_ref.test_report,
# 'test_report_no':self.incoming_doc_ref.test_report_no,
# 'test_report_doc':self.incoming_doc_ref.test_report_doc,
# 'test_report_filename':self.incoming_doc_ref.test_report_filename
})
# Rework Iteration starts
sos_record = self.env['sos_iqi'].search([('id', '=', self.incoming_doc_ref.id)], limit=1)
if sos_record:
rework_iteration = sos_record.reworked_count + 1
sos_record.write({
'reworked_count':rework_iteration
})
# Rework Iteration ends
return send_email.action_assign_signature(
self,
'forward_by',
'forward_on',
'sos_inventory.sos_qa_user'
)
else:
raise UserError("All Status Should Be Closed")
def action_report_ncmr_btn(self):
try:
action = self.env.ref("sos_inventory.action_report_ncmr").report_action(self)
return action
except ValueError as e:
print(f"Failed to find report action: {e}")
def action_scg_esign_btn(self):
sequence_util = self.env['sos_common_scripts']
orr_no = sequence_util.generate_sequence('sos_sfg_outsourcing_return_register','ORR', 'orr_no')
send_email = self.env['sos_common_scripts']
send_email.action_assign_signature(
self,
'scg_approval_by',
'scg_approval_on',
'sos_inventory.sos_scg_group_user'
)
if self.rework_action == "inhouse":
# Email part
body_html = f"""
<p>Below <b>NCMR</b> is waiting for your Action</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,'sos_ncmr',self.id,"deenalaura.m@sosaley.in","NCMR Action Request",body_html,"sos_inventory.sos_production_user")
elif self.rework_action == "supplier_replacement":
orr_record = self.env['sos_sfg_outsourcing_return_register'].create({
'orr_no': orr_no,
'iqi_no':self.incoming_doc_ref.id,
'iqi_date':self.incoming_doc_ref.iqi_date,
'material_name':self.incoming_doc_ref.material_name,
'supplier_name':self.incoming_doc_ref.supplier_name.id,
'goods_type':'Materials',
'returned_qty':self.incoming_doc_ref.rejected_qty
})
else:
if self.material_option:
orr_record = self.env['sos_sfg_outsourcing_return_register'].create({
'orr_no': orr_no,
'iqi_no':self.incoming_doc_ref.id,
'iqi_date':self.incoming_doc_ref.iqi_date,
'material_name':self.incoming_doc_ref.material_name,
'supplier_name':self.incoming_doc_ref.supplier_name.id,
'goods_type':'Materials',
'returned_qty':self.incoming_doc_ref.rejected_qty
})
else:
orr_record = self.env['sos_sfg_outsourcing_return_register'].create({
'orr_no': orr_no,
'iqi_no':self.incoming_doc_ref.id,
'iqi_date':self.incoming_doc_ref.iqi_date,
'service_provider_name':self.incoming_doc_ref.service_provider_name,
'sfg_name':self.incoming_doc_ref.sfg_name,
'goods_type':'SFG',
'returned_qty':self.incoming_doc_ref.rejected_qty
})
self.outsourcing_return_ref_no = orr_record.id
def action_production_esign_btn(self):
send_email = self.env['sos_common_scripts']
send_email.action_assign_signature(
self,
'production_approval_by',
'production_approval_on',
'sos_inventory.sos_production_user'
)
def action_rd_esign_btn(self):
send_email = self.env['sos_common_scripts']
send_email.action_assign_signature(
self,
'rd_approval_by',
'rd_approval_on'
)
def action_qa_esign_btn(self):
if self.action_group:
sequence_util = self.env['sos_common_scripts']
sequence_util.action_assign_signature(
self,
'qa_by',
'qa_tested_on',
'sos_inventory.sos_qc_user'
)
if self.action_group == "rd":
# Email part
body_html = f"""
<p>Below <b>NCMR</b> is waiting for your Action</p>
"""
send_email = self.env['sos_common_scripts']
for user in self.rd_user:
if user.login:
send_email.send_direct_email(
self.env,
"sos_ncmr",
self.id,
user.login,
"NCMR Action Request",
body_html
)
else:
if self.action_group == "production":
group="sos_inventory.sos_production_user"
else:
group="sos_inventory.sos_scg_group_user"
# Email part
body_html = f"""
<p>Below <b>NCMR</b> is waiting for your Action</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,'sos_ncmr',self.id,"deenalaura.m@sosaley.in","NCMR Action Request",body_html,group)
# Email part ends
else:
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': "Select Action to be taken by",
'type': 'danger',
'sticky': False
}
}
class NCMR_Defective_Status(models.Model):
_name = 'sos_ncmr_defective_status'
_description = 'NCMR Defective Status'
ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade")
defective_id = fields.Many2one('sos_sfg_defective_line', string="Defective")
material_defective_id = fields.Many2one('sos_material_defective_line', string="Defective")
fg_defective_id = fields.Many2one('sos_defectives', string="Defective")
aodr_no = fields.Many2one('sos_aodr',string="AODR No(If Any)")
status = fields.Selection([('open', 'Open'), ('closed', 'Closed')], string="Status", required=True, default='open')
_sql_constraints = [
('ncmr_defective_unique', 'unique(ncmr_id, defective_id)', 'Each defective can only have one status per NCMR.')
]
class NCMR_Model_CAPA_Line(models.Model):
_name = 'sos_ncmr_capa_line'
_description = 'CAPA Lines'
ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade")
issue = fields.Char(string="Issue")
corrective_action = fields.Html(string="Corrective Action")
preventive_action = fields.Html(string="Preventive Action")
class NCMR_Model_Line(models.Model):
_name = 'sos_ncmr_line'
_description = 'Non-Conforming Material Report Defectives'
s_no = fields.Char(string="Serial No")
ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade")
fg_name = fields.Many2one(related='ncmr_id.fg_name', string="FG Name", readonly=True, store=True)
remarks=fields.Char(string="Specific Remarks")
sfg_category = fields.Many2one(related='ncmr_id.sfg_category', string="SFG Category", readonly=True)
defective_count = fields.Integer(string='Number of Defectives', compute='_compute_defective_count', store=True)
defectives = fields.Many2many('sos_sfg_defective_line', string='Defectives')
defectives_domain = fields.Many2many('sos_sfg_defective_line', compute='_compute_defective_domain')
material_category = fields.Many2one(related='ncmr_id.material_category', string="Material Category", readonly=True)
material_defectives = fields.Many2many('sos_material_defective_line', string='Defectives')
material_defectives_domain = fields.Many2many('sos_material_defective_line', compute='_compute_material_defective_domain')
material_defective_count = fields.Integer(string='Number of Defectives', compute='_compute_material_defective_count', store=True)
fg_category = fields.Many2one(related='ncmr_id.fg_category', string="FG Category", readonly=True)
fg_defective_count = fields.Integer(string='Number of Defectives', compute='_compute_fg_defective_count', store=True)
fg_defectives = fields.Many2many('sos_defectives', string='Defectives')
fg_defectives_domain = fields.Many2many('sos_defectives', compute='_compute_fg_defective_domain')
@api.depends('ncmr_id', 'ncmr_id.fg_category')
def _compute_fg_defective_domain(self):
for record in self:
if record.fg_category:
sos_defectives_records = self.env['sos_defectives'].search([('defective_id', '=', record.fg_category.id)])
defective_names = sos_defectives_records.mapped('id')
matching_config_ids = self.env['sos_defectives'].search([
('id', 'in', defective_names)
]).ids
if matching_config_ids:
record.fg_defectives_domain = matching_config_ids if matching_config_ids else [] # Use [0] to prevent errors
else:
record.fg_defectives_domain = []
else:
record.fg_defectives_domain = []
@api.depends('ncmr_id', 'ncmr_id.material_category')
def _compute_material_defective_domain(self):
for record in self:
if record.material_category:
defective_names = record.material_category.defective_ids.mapped('id')
matching_config_ids = self.env['sos_material_defective_line'].search([
('id', 'in', defective_names)
]).ids
if matching_config_ids:
record.material_defectives_domain = matching_config_ids if matching_config_ids else [] # Use [0] to prevent errors
else:
record.material_defectives_domain = []
else:
record.material_defectives_domain = []
@api.depends('ncmr_id', 'ncmr_id.sfg_category')
def _compute_defective_domain(self):
for record in self:
if record.sfg_category:
defective_names = record.sfg_category.defective_ids.mapped('id')
matching_config_ids = self.env['sos_sfg_defective_line'].search([
('id', 'in', defective_names)
]).ids
if matching_config_ids:
record.defectives_domain = matching_config_ids if matching_config_ids else [] # Use [0] to prevent errors
else:
record.defectives_domain = []
else:
record.defectives_domain = []
@api.model
def create(self, vals):
record = super(NCMR_Model_Line, self).create(vals)
record._update_defective_status_ids()
return record
def write(self, vals):
result = super(NCMR_Model_Line, self).write(vals)
self._update_defective_status_ids()
return result
def _update_defective_status_ids(self):
for record in self:
if record.ncmr_id:
if record.ncmr_id.sfg_option:
existing_defective_ids = record.ncmr_id.defective_status_ids.mapped('defective_id.id')
new_lines = []
for defective in record.defectives:
if defective.id not in existing_defective_ids:
new_lines.append((0, 0, {
'defective_id': defective.id,
'ncmr_id': record.ncmr_id.id,
}))
elif record.ncmr_id.material_option:
existing_defective_ids = record.ncmr_id.defective_status_ids.mapped('material_defective_id.id')
new_lines = []
for defective in record.material_defectives:
if defective.id not in existing_defective_ids:
new_lines.append((0, 0, {
'material_defective_id': defective.id,
'ncmr_id': record.ncmr_id.id,
}))
else:
existing_defective_ids = record.ncmr_id.defective_status_ids.mapped('fg_defective_id.id')
new_lines = []
for defective in record.fg_defectives:
if defective.id not in existing_defective_ids:
new_lines.append((0, 0, {
'fg_defective_id': defective.id,
'ncmr_id': record.ncmr_id.id,
}))
if new_lines:
record.ncmr_id.write({
'defective_status_ids': new_lines
})
@api.depends('defectives')
def _compute_defective_count(self):
for record in self:
record.defective_count = len(record.defectives)
@api.depends('material_defectives')
def _compute_material_defective_count(self):
for record in self:
record.material_defective_count = len(record.material_defectives)
@api.depends('fg_defectives')
def _compute_fg_defective_count(self):
for record in self:
record.fg_defective_count = len(record.fg_defectives)