Slink/sos_inventory/models/sos_fptc.py

325 lines
15 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
from odoo.exceptions import UserError
import re
class FptcModel(models.Model):
_name = 'sos_fptc'
_description = 'Finished Product Transfer Challan'
_rec_name="fptc_no"
_order = 'id desc'
plan_ref_no = fields.Many2one('sos_fg_plan',
string='Indent No'
)
fptc_no = fields.Char(string="FPTC No",default=lambda self: self._generate_id(),readonly= True, required= True)
fg_name = fields.Many2many('sos_fg', string='FG Name')
sfg_name = fields.Many2one('sos_sfg', string='SFG Name')
planned_qty = fields.Integer(string="Planned Qty")
line_ids = fields.One2many('sos_fptc_line', 'fptc_id', string="Finished Goods",copy=True, ondelete='cascade')
indent_start_date = fields.Date(string="Indent Started On")
indent_target_date = fields.Date(string="Indent Target On")
stores_to_production_lines= fields.One2many('sos_fptc_store_to_production', 'fptc_id',string="")
customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name")
deliverables_ref_no = fields.Many2one('sos_deliverables_boq',string="Deliverables/BOQ Reference")
production_witness_name = fields.Many2one('res.users')
production_witness_image = fields.Image(related="production_witness_name.signature_image",readonly=True)
production_witness_approved_on = fields.Datetime(string="Approved On")
qc_witness_name = fields.Many2one('res.users')
qc_witness_image = fields.Image(related="qc_witness_name.signature_image",readonly=True)
qc_witness_approved_on = fields.Datetime(string="Approved On")
stores_witness_name = fields.Many2one('res.users')
stores_witness_image = fields.Image(related="stores_witness_name.signature_image",readonly=True)
stores_witness_approved_on = fields.Datetime(string="Approved On")
def action_production_esign_btn(self):
sequence_util = self.env['sos_common_scripts']
sequence_util.action_assign_signature(
self,
'production_witness_name',
'production_witness_approved_on',
'sos_inventory.sos_production_user'
)
def action_stores_esign_btn(self):
sequence_util = self.env['sos_common_scripts']
sequence_util.action_assign_signature(
self,
'stores_witness_name',
'stores_witness_approved_on',
'sos_inventory.sos_scg_group_user'
)
def action_qc_esign_btn(self):
sequence_util = self.env['sos_common_scripts']
sequence_util.action_assign_signature(
self,
'qc_witness_name',
'qc_witness_approved_on',
'sos_inventory.sos_qc_user'
)
def _generate_id(self):
sequence_util = self.env['sos_common_scripts']
return sequence_util.generate_sequence('sos_fptc','FPTC', 'fptc_no')
def action_report_fptc_btn(self):
try:
action = self.env.ref("sos_inventory.action_report_fptc").report_action(self)
return action
except ValueError as e:
print(f"Failed to find report action: {e}")
class Stores_to_Production(models.Model):
_name = 'sos_fptc_store_to_production'
_description = 'Stores to Production Lines'
fptc_id = fields.Many2one('sos_fptc')
fg_name = fields.Many2one('sos_fg', string='FG Name')
batch_no = fields.Char(string="Batch No")
serial_no=fields.Text(string="Serial No")
from_dept = fields.Selection([('production', 'Production'),('stores', 'Stores')], string="From Department",default="stores")
stores_to_production_transfer_qty = fields.Integer(
string="Transfer Quantity", compute="_compute_transfer_qty", store=True, readonly=False
)
stores_to_production_transfer_on=fields.Date(string="Transfered On")
available_fg_names = fields.Many2many('sos_fg', compute="_compute_available_fg_names", store=False)
send_to_production_btn_display = fields.Boolean(default=True)
show_serial = fields.Boolean(default=True)
def toggle_serial(self):
for record in self:
record.show_serial = not record.show_serial
@api.model
def create(self, vals):
"""Expand serial number ranges before saving"""
if 'serial_no' in vals and vals['serial_no']:
vals['serial_no'] = self._expand_serial_numbers(vals['serial_no'])
return super(Stores_to_Production, self).create(vals)
def write(self, vals):
"""Expand serial number ranges on update"""
if 'serial_no' in vals and vals['serial_no']:
vals['serial_no'] = self._expand_serial_numbers(vals['serial_no'])
return super(Stores_to_Production, self).write(vals)
def _expand_serial_numbers(self, serial_text):
"""Convert serial number ranges into individual serial numbers only if 'to' is found"""
lines = serial_text.split("\n")
expanded_serials = []
for line in lines:
line = line.strip()
if "to" in line: # Process only if 'to' is present
match = re.match(r"^(.+?)-(\d+)\s+to\s+(.+?)-(\d+)$", line) # Match range format
if match:
prefix1, start_num, prefix2, end_num = match.groups()
if prefix1 == prefix2: # Ensure both prefixes are the same
start_num, end_num = int(start_num), int(end_num)
for num in range(start_num, end_num + 1):
expanded_serials.append(f"{prefix1}-{num:03d}") # Format with leading zeros
else:
expanded_serials.append(line) # Keep original if prefixes don't match
else:
expanded_serials.append(line) # Keep as is if not a valid range
else:
expanded_serials.append(line) # Keep original if 'to' is not present
return "\n".join(expanded_serials) # Return expanded serials as multiline text
@api.depends("serial_no")
def _compute_transfer_qty(self):
"""Compute Transfer Quantity based on number of serial numbers entered, but allow manual override"""
for record in self:
if record.serial_no:
serial_list = list(filter(None, map(str.strip, record.serial_no.split("\n")))) # Remove empty lines & spaces
record.stores_to_production_transfer_qty = len(serial_list) # Count valid serials
else:
record.stores_to_production_transfer_qty = 0 # If no serials, set to 0
@api.depends("fptc_id")
def _compute_available_fg_names(self):
for record in self:
if record.fptc_id:
fg_ids = record.fptc_id.fg_name.ids
record.available_fg_names = [(6, 0, fg_ids)]
# Auto-select FG name only if exactly one exists
if len(fg_ids) == 1:
record.fg_name = fg_ids[0]
# Don't reset if multiple exist; let user select
else:
record.available_fg_names = [(6, 0, [])]
record.fg_name = False # Clear selection only if no options exist
@api.onchange('fptc_id')
def _onchange_fptc_id(self):
if self.fptc_id and len(self.fptc_id.fg_name) == 1:
self.fg_name = self.fptc_id.fg_name.id
else:
self.fg_name = False
def send_to_production_btn(self):
new_record = self.fptc_id.line_ids
new_record.create({
'fptc_id': self.fptc_id.id,
'batch_no' : self.batch_no,
'serial_no' : self.serial_no,
'fg_name' : self.fg_name.id,
'production_to_qc_transfer_qty':self.stores_to_production_transfer_qty
})
self.send_to_production_btn_display = False
body_html = f"""
<p>Below <b>FPTC</b> is waiting for your response</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,"sos_fptc",self.id,"deenalaura.m@sosaley.in","Transfer Challan Received",body_html,'sos_inventory.sos_production_user')
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': "Moved to Production",
'type': 'success',
'sticky': False
}
}
class FptcModel_Line(models.Model):
_name = 'sos_fptc_line'
_description = 'FPTC Lines'
fptc_id = fields.Many2one('sos_fptc')
fg_name = fields.Many2one('sos_fg',string="FG Name")
specification = fields.Many2one('sos_specification', string='Specification Name')
specification_value = fields.Char(string="Value")
batch_no = fields.Char(string="Batch No")
serial_no=fields.Text(string="Serial No")
qc_report = fields.Many2one('sos_fir_brr')
fir_qc_report = fields.Many2one('sos_fir')
production_to_qc_transfer_qty=fields.Integer(string="Transfer Quantity")
production_to_qc_transfer_by = fields.Many2one('res.users',string='Production to QC By')
production_to_qc_transfer_on = fields.Date(string="Production to QC Transfered On")
qc_to_stores_transfer_qty=fields.Integer(string="Approved Quantity")
qc_to_stores_rejected_qty=fields.Integer(string="Rejected Quantity")
qc_to_stores_transfer_by = fields.Many2one('res.users',string='QC to Stores By')
qc_to_stores_transfer_on = fields.Date(string="QC to Stores Transfered On")
stores_received_by = fields.Many2one('res.users',string='Stores Received by')
stores_received_on = fields.Date(string="Stores Received On")
from_dept = fields.Selection([('production', 'Production'),('stores', 'Stores')], string="From Department",default="production")
sfg_qc_report = fields.Many2one('sos_iqi')
sfg_qc_to_stores_transfer_qty=fields.Integer(string="Approved Quantity",related="sfg_qc_report.approved_qty")
sfg_qc_to_stores_rejected_qty=fields.Integer(string="Rejected Quantity",related="sfg_qc_report.rejected_qty")
sfg_stores_received_by = fields.Many2one('res.users',string='Stores Received by',related="sfg_qc_report.stores_received_by")
sfg_stores_received_on = fields.Date(string="Stores Received On",related="sfg_qc_report.stores_received_on")
sfg_qc_to_stores_transfer_by = fields.Many2one('res.users',string='QC to Stores By',related="sfg_qc_report.qc_by_name")
sfg_qc_to_stores_transfer_on = fields.Date(string="QC to Stores Transfered On",related="sfg_qc_report.qc_tested_on")
available_fg_names = fields.Many2many('sos_fg', compute="_compute_available_fg_names", store=False)
show_serial = fields.Boolean(default=True)
def toggle_serial(self):
for record in self:
record.show_serial = not record.show_serial
# @api.model
# def create(self, vals):
# """Create multiple rows in `sos_serial_nos` for each serial number in the list"""
# res = super(FptcModel_Line, self).create(vals) # Create the main record first
# res._update_serial_numbers() # Call helper method to insert serials
# return res
# def write(self, vals):
# """Update related serial numbers in `sos_serial_nos` when this record is modified"""
# res = super(FptcModel_Line, self).write(vals) # Update the main record first
# if 'serial_no' in vals or 'batch_no' in vals or 'fg_name' in vals:
# self._update_serial_numbers() # Call helper method to update serials
# return res
# def unlink(self):
# """Delete associated serial numbers when this record is deleted"""
# for record in self:
# self.env['sos_serial_nos'].search([
# ('batch_no', '=', record.batch_no),
# ('fg_name', '=', record.fg_name.id)
# ]).unlink()
# return super(FptcModel_Line, self).unlink()
# def _update_serial_numbers(self):
# """Helper function to update serial numbers in `sos_serial_nos`"""
# for record in self:
# # Remove old serial numbers before inserting new ones
# self.env['sos_serial_nos'].search([
# ('batch_no', '=', record.batch_no),
# ('fg_name', '=', record.fg_name.id)
# ]).unlink()
# if record.serial_no:
# serial_numbers = record.serial_no.split('\n') # Split serial numbers into a list
# # Create separate rows in sos_serial_nos for each serial number
# for serial in filter(None, map(str.strip, serial_numbers)): # Removes empty lines & spaces
# self.env['sos_serial_nos'].create({
# 'customer_name': record.fptc_id.customer_name,
# 'fg_name': record.fg_name.id,
# 'serial_no': serial, # Each row gets a single serial number
# 'batch_no': record.batch_no
# })
@api.depends("fptc_id")
def _compute_available_fg_names(self):
for record in self:
if record.fptc_id:
fg_ids = record.fptc_id.fg_name.ids
record.available_fg_names = [(6, 0, fg_ids)]
# Auto-select FG name only if exactly one exists
if len(fg_ids) == 1:
record.fg_name = fg_ids[0]
else:
record.available_fg_names = [(6, 0, [])]
record.fg_name = False # Clear selection only if no options exist
def send_to_qc_btn(self):
self.production_to_qc_transfer_by = self.env.user.id
sequence_util = self.env['sos_common_scripts']
if self.fptc_id.plan_ref_no:
week_number = sequence_util.calculate_week_number(
self.fptc_id.indent_start_date,
self.fptc_id.indent_target_date,
date.today()
)
field_name = f'actual_week_{week_number}'
sos_record = self.env['sos_production_plan'].search([
('fg_name', '=', self.fg_name.id),
('plan_ref_no', '=', self.fptc_id.plan_ref_no)
], limit=1)
if sos_record:
current_value = getattr(sos_record, field_name, 0)
sos_record.write({field_name: current_value + self.production_to_qc_transfer_qty})
#end production status update
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': "Moved to QC For Inspection",
'type': 'success',
'sticky': False
}
}
class Fptc_Serial_lines(models.Model):
_name = 'sos_serial_nos'
_description = 'Batch & Serial Numbers'
fg_name = fields.Many2one('sos_fg',string="FG Name")
customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name")
serial_no = fields.Char(string="Serial No")
batch_no = fields.Char(string="Batch No")
delivery_date = fields.Date(string="Delivery Date")