Reference #11
This commit is contained in:
parent
ebdc1d3ca1
commit
ceb5e58e3e
|
|
@ -11,7 +11,7 @@
|
|||
'version': '17.0.1.0.0',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base','web','mail'],
|
||||
'depends': ['base','web','mail','one2many_search_widget'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
'security/record_rules.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/cron_jobs.xml',
|
||||
'views/pareto_chart_widget_view.xml',
|
||||
'views/sos_audit_log_view.xml',
|
||||
'views/menu.xml',
|
||||
'views/sos_quote_generation.xml',
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
'views/sos_fg_view.xml',
|
||||
'views/sos_sfg_view.xml',
|
||||
'views/sos_material_view.xml',
|
||||
'views/sos_budget_plan_view.xml',
|
||||
'views/sos_material_bom_view.xml',
|
||||
'views/sos_sfg_bom_view.xml',
|
||||
'views/sos_fg_bom_view.xml',
|
||||
|
|
@ -81,6 +83,8 @@
|
|||
'views/sos_service_call_log_report.xml',
|
||||
'views/sos_transfer_challan_return_from_customer_view.xml',
|
||||
'views/sos_shelflife_register_view.xml',
|
||||
'views/sos_prf_view.xml',
|
||||
|
||||
'wizard/sfg_bom_bulk_upload_view.xml',
|
||||
'wizard/mon_bulk_upload_view.xml',
|
||||
'wizard/missing_component_wizard.xml',
|
||||
|
|
@ -115,6 +119,7 @@
|
|||
'report/sos_boq_labels.xml',
|
||||
'report/shelflife_report.xml',
|
||||
'report/sos_boq_report.xml',
|
||||
'report/sos_budget_plan_summary.xml',
|
||||
'data/send_indent_plan_email_template.xml',
|
||||
'data/selection_item.xml'
|
||||
|
||||
|
|
@ -130,6 +135,8 @@
|
|||
'sos_inventory/static/src/components/**/*.js',
|
||||
'sos_inventory/static/src/components/**/*.xml',
|
||||
'sos_inventory/static/src/components/**/*.scss',
|
||||
'sos_inventory/static/src/js/pareto_chart_widget.js',
|
||||
'sos_inventory/static/src/xml/pareto_chart_template.xml',
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,7 +4,9 @@ import io
|
|||
import xlsxwriter
|
||||
|
||||
class MaterialBackupExportController(http.Controller):
|
||||
|
||||
@http.route('/supplier/form', auth='public')
|
||||
def index(self, **kw):
|
||||
return "Hello, world"
|
||||
@http.route(['/download/material/backup/<string:year>/<string:item_type>'], type='http', auth='user')
|
||||
def download_backup_by_year(self, year, item_type, **kwargs):
|
||||
# Safely map table names
|
||||
|
|
|
|||
|
|
@ -58,4 +58,6 @@ from . import sos_master_customer_property
|
|||
from . import sos_service_call_log_report
|
||||
from . import sos_inhouse_validation_reports_files
|
||||
from . import sos_transfer_challan_return_from_customer
|
||||
from . import sos_shelflife_register
|
||||
from . import sos_shelflife_register
|
||||
from . import sos_budget_plan
|
||||
from . import sos_prf
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,159 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import UserError
|
||||
from math import ceil
|
||||
|
||||
|
||||
class SOS_Budget_Plan(models.Model):
|
||||
_name = 'sos_budget_plan'
|
||||
_description = 'Budget Plan'
|
||||
|
||||
name= fields.Char(string="Plan Name")
|
||||
sfg_option = fields.Boolean('Semi-Finished Goods')
|
||||
fg_option = fields.Boolean('Finished Goods',default=True)
|
||||
fg_name = fields.Many2one('sos_fg', string='FG Name')
|
||||
sfg_name = fields.Many2one('sos_sfg', string="SFG Name")
|
||||
quantity = fields.Integer(string="Quantity",required=True)
|
||||
@api.onchange('sfg_option')
|
||||
def _onchange_sfg_option(self):
|
||||
if self.sfg_option:
|
||||
self.fg_option = False
|
||||
@api.onchange('fg_option')
|
||||
def _onchange_fg_option(self):
|
||||
if self.fg_option:
|
||||
self.sfg_option = False
|
||||
def create_budget_plan(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.quantity:
|
||||
raise UserError("Quantity must be greater than zero.")
|
||||
|
||||
if not (self.fg_option or getattr(self, 'sfg_option', False)):
|
||||
raise UserError("Select Finished Goods or SFG option.")
|
||||
|
||||
# --- Accumulator keyed by product/component id ---
|
||||
# { prod_id: {'name': str, 'needed': float, 'inhand': float, 'price': float} }
|
||||
agg = {}
|
||||
|
||||
def _accumulate(line, needed_qty):
|
||||
"""Accumulate needed qty for a line's primary component."""
|
||||
prod = line.primary_component_id
|
||||
if not prod:
|
||||
return
|
||||
pid = prod.id
|
||||
rec = agg.get(pid)
|
||||
if rec:
|
||||
rec['needed'] += float(needed_qty or 0.0)
|
||||
else:
|
||||
agg[pid] = {
|
||||
'name': prod.part_no or prod.name or '—',
|
||||
'needed': float(needed_qty or 0.0),
|
||||
'inhand': float(prod.inhand_stock_qty or 0.0), # take once per product
|
||||
'price': float(prod.unit_price or 0.0),
|
||||
'pack': float(getattr(prod, 'std_packing_qty', 0.0) or 0.0),
|
||||
}
|
||||
|
||||
label_name = "" # what we'll display in the report header
|
||||
|
||||
if self.fg_option:
|
||||
# -------- FG → explode SFGs + add direct materials --------
|
||||
product_bom = self.env['sos_fg_bom'].search([
|
||||
('fg_name', '=', self.fg_name.id),
|
||||
('is_primary', '=', True)
|
||||
], limit=1)
|
||||
if not product_bom:
|
||||
raise UserError("BOM for product is Missing")
|
||||
|
||||
label_name = self.fg_name.display_name
|
||||
|
||||
# 1) FG BOM lines that reference SFG BOMs
|
||||
fg_sfg_lines = self.env['sos_fg_bom_line'].search([('bom_id', '=', product_bom.id)])
|
||||
for sfg_line in fg_sfg_lines:
|
||||
sfg_bom = sfg_line.sfg_bom_id # Many2one to SFG BOM
|
||||
if not sfg_bom:
|
||||
continue
|
||||
|
||||
# Required SFG qty = (FG qty * SFG-per-FG) - SFG in-hand (clamped ≥ 0)
|
||||
inhand_sfg = float((sfg_bom.name and sfg_bom.name.inhand_stock_qty) or 0.0)
|
||||
requested = float(self.quantity or 0.0) * float(sfg_line.quantity or 0.0)
|
||||
required_sfg_qty = max(requested - inhand_sfg, 0.0)
|
||||
if not required_sfg_qty:
|
||||
continue
|
||||
|
||||
# Explode SFG BOM to components for the required SFG qty
|
||||
for comp in sfg_bom.sfg_bom_line_ids:
|
||||
needed_qty = float(comp.quantity or 0.0) * required_sfg_qty
|
||||
_accumulate(comp, needed_qty)
|
||||
|
||||
# 2) Direct materials under the FG BOM
|
||||
direct_material_lines = self.env['sos_sfg_bom_line'].search([('fg_bom_id', '=', product_bom.id)])
|
||||
for mat in direct_material_lines:
|
||||
needed_qty = float(mat.quantity or 0.0) * float(self.quantity or 0.0)
|
||||
_accumulate(mat, needed_qty)
|
||||
|
||||
else:
|
||||
# -------- SFG-only path --------
|
||||
if not getattr(self, 'sfg_option', False):
|
||||
raise UserError("SFG option must be selected.")
|
||||
|
||||
sfg_bom = self.env['sos_sfg_bom'].search([('name', '=', self.sfg_name.id)], limit=1)
|
||||
if not sfg_bom:
|
||||
raise UserError("SFG BOM is missing.")
|
||||
|
||||
label_name = self.sfg_name.display_name
|
||||
|
||||
# Required SFG qty = requested - in-hand (clamped ≥ 0)
|
||||
inhand_sfg = float((sfg_bom.name and sfg_bom.name.inhand_stock_qty) or 0.0)
|
||||
requested = float(self.quantity or 0.0)
|
||||
required_sfg_qty = max(requested - inhand_sfg, 0.0)
|
||||
|
||||
if required_sfg_qty:
|
||||
for comp in sfg_bom.sfg_bom_line_ids:
|
||||
needed_qty = float(comp.quantity or 0.0) * required_sfg_qty
|
||||
_accumulate(comp, needed_qty)
|
||||
|
||||
# ---- Build final list from aggregator (merge duplicates; consider inhand once) ----
|
||||
materials = []
|
||||
for rec in agg.values():
|
||||
raw_to_purchase = max(rec['needed'] - rec['inhand'], 0.0)
|
||||
if raw_to_purchase <= 0:
|
||||
continue
|
||||
pack = float(getattr(rec, 'pack', 0.0) or rec.get('pack') or 0.0)
|
||||
if pack > 0:
|
||||
pack_count = ceil(raw_to_purchase / pack)
|
||||
to_purchase = pack_count * pack
|
||||
else:
|
||||
pack_count = 0
|
||||
to_purchase = raw_to_purchase
|
||||
materials.append({
|
||||
'material_name': rec['name'],
|
||||
'needed_quantity': rec['needed'],
|
||||
'inhand_quantity': rec['inhand'],
|
||||
'actual_needed': raw_to_purchase,
|
||||
'std_packing_qty': pack,
|
||||
'packs_to_buy': pack_count,
|
||||
'to_purchase': to_purchase,
|
||||
'price': rec['price'],
|
||||
'cost': round(to_purchase * rec['price'], 2),
|
||||
})
|
||||
|
||||
if not materials:
|
||||
raise UserError("No materials need to be purchased.")
|
||||
|
||||
# Optional ordering: most to purchase first
|
||||
materials.sort(key=lambda r: (-r['to_purchase'], r['material_name']))
|
||||
|
||||
total_cost = sum(m['cost'] for m in materials)
|
||||
|
||||
action = self.env.ref('sos_inventory.action_material_budget_summary')
|
||||
return action.report_action(
|
||||
self,
|
||||
data={
|
||||
'fg_name': label_name, # shown as header label
|
||||
'total_quantity': self.quantity,
|
||||
'materials': materials,
|
||||
'total_cost': total_cost,
|
||||
'currency_symbol': self.env.company.currency_id.symbol or '',
|
||||
}
|
||||
)
|
||||
|
|
@ -41,7 +41,7 @@ class SOS_CCRF(models.Model):
|
|||
batch_release_date = fields.Date(string="Invoice Date")
|
||||
brcoa_no = fields.Char(string="BRCOA No")
|
||||
brcoa_date = fields.Date(string="BRCOA Date")
|
||||
other_complaints = fields.Text(string="Details of any other Complaints received from this Production run")
|
||||
other_complaints = fields.Text(string="Defective Details/Symptom")
|
||||
data_collected_by = fields.Many2one('res.users', string='Data Collected By')
|
||||
data_collected_image = fields.Image(related="data_collected_by.signature_image",string='Data Collected Sign',readonly=True)
|
||||
data_collected_on = fields.Datetime(string="Data Collected On")
|
||||
|
|
@ -56,12 +56,17 @@ class SOS_CCRF(models.Model):
|
|||
investigation_carriedout_image = fields.Image(related="investigation_carriedout_by.signature_image",string='Investigation Carried Out Sign',readonly=True)
|
||||
investigation_carriedout_on = fields.Datetime(string="Investigation Carried Out On")
|
||||
root_cause = fields.Html(string="Root Cause",
|
||||
default="<p>Why #1</p><p>Why #2</p><p>Why #3</p>")
|
||||
default="<p>Why #1 :</p><p>Why #2 :</p><p>Why #3 :</p><p>Why #4 :</p><p>Why #5 :</p>")
|
||||
#team_formation = fields.Html(string="Team Formation",
|
||||
#default="<p>Name :</p><br><p>Department :</p><br><p>Roles :</p>")
|
||||
#problem_description = fields.Html(string="Problem Description",
|
||||
#default="<p>Clear Statement :</p><br><p>Photo :</p><br><p>What :</p><br><p>Where :</p><br><p>When :</p><br><p>Why :</p><br><p>Who :</p><br><p>How :</p><br><p>How many :</p>")
|
||||
rootcause_carriedout_by = fields.Many2one('res.users', string='Root Cause Carried Out By')
|
||||
rootcause_carriedout_image = fields.Image(related="rootcause_carriedout_by.signature_image",string='Root Cause Carried Out Sign',readonly=True)
|
||||
rootcause_carriedout_on = fields.Datetime(string="Root Cause Carried Out On")
|
||||
corrective_action = fields.Html(string="Corrective Action")
|
||||
preventive_action = fields.Html(string="Preventive Action")
|
||||
corrective_action = fields.Html(string="D5:Permanent Corrective Action")
|
||||
implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions")
|
||||
preventive_action = fields.Html(string="D7:Preventive Recurrence")
|
||||
capa_status = fields.Selection([ ('open', 'OPEN'),('close', 'Close')], default='open' , string="Status")
|
||||
status_reviewed_by = fields.Many2one('res.users', string='Status Reviewed By')
|
||||
status_reviewed_image = fields.Image(related="status_reviewed_by.signature_image",string='Status Reviewed Out Sign',readonly=True)
|
||||
|
|
@ -76,6 +81,11 @@ class SOS_CCRF(models.Model):
|
|||
rootcause_verifiedout_image = fields.Image(related="rootcause_verifiedout_by.signature_image",string='Root Cause Verified By Sign',readonly=True)
|
||||
rootcause_verifiedout_on = fields.Datetime(string="Root Cause Verified On")
|
||||
helper_field = fields.Many2many('sos_fg', string="Helper Field")
|
||||
team_recognition = fields.Html(string="Team Recognition (Image)")
|
||||
capa_line_ids = fields.One2many('sos_ccrf_capa_line', 'ccrf_id', string="CAPA Line Ids",copy=True)
|
||||
team_formation_line_ids = fields.One2many('sos_ccrf_team_formation_line', 'ccrf_id', string="Team Formation Line Ids",copy=True)
|
||||
problem_description_line_ids = fields.One2many('sos_ccrf_problem_description_line', 'ccrf_id', string="Problem Description Line Ids",copy=True)
|
||||
|
||||
@api.onchange('fg_name')
|
||||
def _onchange_fg_name(self):
|
||||
if self.fg_name:
|
||||
|
|
@ -140,4 +150,38 @@ class SOS_CCRF(models.Model):
|
|||
'rootcause_verifiedout_by',
|
||||
'rootcause_verifiedout_on'
|
||||
)
|
||||
|
||||
|
||||
class CCRF_Model_CAPA_Line(models.Model):
|
||||
_name = 'sos_ccrf_capa_line'
|
||||
_description = 'CAPA Lines'
|
||||
|
||||
ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade")
|
||||
issue = fields.Char(string="Issue")
|
||||
corrective_action = fields.Html(string="D5:Permanent Corrective Action")
|
||||
implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions")
|
||||
preventive_action = fields.Html(string="D7:Preventive Recurrence")
|
||||
|
||||
class CCRF_Model_TEAM_FORMATION_Line(models.Model):
|
||||
_name = 'sos_ccrf_team_formation_line'
|
||||
_description = 'Team Formation Lines'
|
||||
|
||||
ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade")
|
||||
name = fields.Char(string="Name")
|
||||
department = fields.Char(string="Department")
|
||||
role = fields.Char(string="Role")
|
||||
|
||||
|
||||
class CCRF_Model_PROBLEM_DESCRIPTION_Line(models.Model):
|
||||
_name = 'sos_ccrf_problem_description_line'
|
||||
_description = 'Problem Description Lines'
|
||||
|
||||
ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade")
|
||||
clear_statement = fields.Text(string="Clear Statement")
|
||||
photos = fields.Html(string="Photos")
|
||||
what = fields.Text(string="What")
|
||||
where = fields.Text(string="Where")
|
||||
when = fields.Text(string="When")
|
||||
why = fields.Text(string="Why")
|
||||
who = fields.Text(string="Who")
|
||||
how = fields.Text(string="How")
|
||||
how_many = fields.Text(string="How many")
|
||||
|
|
@ -288,7 +288,7 @@ class Sequence_Generator(models.AbstractModel):
|
|||
reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)])
|
||||
email_to = reporting_user.login
|
||||
else:
|
||||
email_to = "ramachandran.r@sosaley.in"
|
||||
email_to = "ramachandran.r@sosaley.com"
|
||||
mail_values = {
|
||||
'subject': subject,
|
||||
'body_html': body_html,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ class sos__dc(models.Model):
|
|||
dept_in_charge_image = fields.Image(related="dept_in_charge_name.signature_image",string='Department In-Charge Sign',readonly=True)
|
||||
dept_in_charge_approved_on = fields.Datetime(string="Approved On")
|
||||
remarks = fields.Text(string="Remarks")
|
||||
|
||||
courier = fields.Char(string="Courier Name")
|
||||
lr_no = fields.Char(string="LR No")
|
||||
@api.onchange('dock_audit_no')
|
||||
def _onchange_dock_audit_no(self):
|
||||
if self.dock_audit_no:
|
||||
|
|
@ -220,7 +221,7 @@ class sos__dc(models.Model):
|
|||
"""
|
||||
subject = f"Delivery Challan Approval Request - {self.dc_no}"
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_dc",self.id,"ramachandran.r@sosaley.in",subject,body_html)
|
||||
send_email.send_direct_email(self.env,"sos_dc",self.id,"ramachandran.r@sosaley.com",subject,body_html)
|
||||
# Email part ends
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
sequence_util.action_assign_signature(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,12 @@ class SosTestingParameters(models.Model):
|
|||
communication_type = fields.Selection([
|
||||
('wired', 'Wired'),
|
||||
('wireless', 'Wireless')
|
||||
], string="Communication Type", default='wired')
|
||||
], string="Communication Type")
|
||||
slave_type = fields.Selection([
|
||||
('15S Individual Slave', '15S Individual Slave'),
|
||||
('90S Electrical Panel', '90S Electrical Panel'),
|
||||
('60S Electrical Panel', '60S Electrical Panel')
|
||||
], string="Slave Type")
|
||||
fg_ids = fields.One2many('sos_fg_deliverables', 'ref_id', string= 'FG Deliverables',copy=True)
|
||||
sfg_ids = fields.One2many('sos_sfg_deliverables', 'ref_id', string= 'SFG Deliverables',copy=True)
|
||||
material_ids = fields.One2many('sos_material_deliverables', 'ref_id', string='Material Deliverables',copy=True)
|
||||
|
|
@ -57,6 +62,7 @@ class SOS_SFG_Deliverables(models.Model):
|
|||
item_type = fields.Selection([
|
||||
('Master Panel', 'Master Panel'),
|
||||
('CT Module', 'CT Module'),
|
||||
('Battery Count', 'Battery Count'),
|
||||
('Slave Module', 'Slave Module'),
|
||||
('Internet Module', 'Internet Module')
|
||||
], string="Type",default="Master Panel")
|
||||
|
|
@ -82,6 +88,7 @@ class SOS_Material_Deliverables(models.Model):
|
|||
item_type = fields.Selection([
|
||||
('Master Panel', 'Master Panel'),
|
||||
('CT Module', 'CT Module'),
|
||||
('Battery Count', 'Battery Count'),
|
||||
('Slave Module', 'Slave Module'),
|
||||
('Internet Module', 'Internet Module')
|
||||
], string="Type",default="Master Panel")
|
||||
|
|
|
|||
|
|
@ -8,4 +8,34 @@ class sos_department(models.Model):
|
|||
|
||||
|
||||
name = fields.Char(string="Department Name")
|
||||
|
||||
short_form = fields.Char(string="Short Text")
|
||||
process_incharge = fields.Many2one('res.users', string='Process Incharge')
|
||||
users_line_ids = fields.One2many('sos_departments_user_lines','ref_id', string='Users')
|
||||
|
||||
_sql_constraints = [
|
||||
('uniq_department_name', 'unique(name)', 'Department name must be unique.'),
|
||||
]
|
||||
class sos_department_line(models.Model):
|
||||
_name = 'sos_departments_user_lines'
|
||||
_description = 'Users in department'
|
||||
|
||||
ref_id = fields.Many2one('sos_departments', string="Departments", ondelete="cascade")
|
||||
users = fields.Many2one('res.users', string='Users')
|
||||
# @api.onchange('users')
|
||||
# def _onchange_users(self):
|
||||
# if self.users:
|
||||
# domain = [('users', '=', self.users.id)]
|
||||
# if self.id and isinstance(self.id, int): # Only add if it's a real ID
|
||||
# domain.append(('id', '!=', self.id))
|
||||
|
||||
# existing_line = self.env['sos_departments_user_lines'].search(domain, limit=1)
|
||||
# if existing_line:
|
||||
# return {
|
||||
# 'warning': {
|
||||
# 'title': 'User Already Assigned',
|
||||
# 'message': f"This user is already assigned to {existing_line.ref_id.name}."
|
||||
# }
|
||||
# }
|
||||
|
||||
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ class sos_Disposal_Register(models.Model):
|
|||
<p>Below Item is waiting for your approval to Dispose</p>
|
||||
"""
|
||||
|
||||
sequence_util.send_direct_email(self.env,"sos_disposal_register",self.id,"ramachandran.r@sosaley.in","Disposal Approved",body_html)
|
||||
sequence_util.send_direct_email(self.env,"sos_disposal_register",self.id,"ramachandran.r@sosaley.com","Disposal Approved",body_html)
|
||||
# Email part ends
|
||||
return sequence_util.action_assign_signature(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ class SOS_Dock_Audit(models.Model):
|
|||
],
|
||||
string="Product Type",required=True)
|
||||
quantity = fields.Integer(string="Quantity")
|
||||
warranty = fields.Integer(string="Warranty(In Months)")
|
||||
invoice_no = fields.Char(string="Invoice No")
|
||||
invoice_date = fields.Date(string="Invoice Date")
|
||||
customer_name = fields.Char(string="Customer Name")
|
||||
lead_time = fields.Datetime(string="Lead Time")
|
||||
customer_po_no = fields.Char(string="PO No")
|
||||
|
|
@ -140,6 +142,18 @@ class SOS_Dock_Audit(models.Model):
|
|||
})
|
||||
|
||||
def action_acc_esign_btn(self):
|
||||
required_fields = ['payment_status', 'invoice_date','invoice_no', 'billing_address', 'gst_no', 'shipping_address']
|
||||
missing_fields = []
|
||||
|
||||
for field in required_fields:
|
||||
if not self[field]: # Check if field is empty/False
|
||||
missing_fields.append(field)
|
||||
|
||||
# If any fields are missing, show warning
|
||||
if missing_fields:
|
||||
warning_msg = "Please fill the following required fields before proceeding:\n"
|
||||
warning_msg += "\n".join([f"👉 {field.replace('_', ' ').title()}" for field in missing_fields])
|
||||
raise UserError(warning_msg)
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
sequence_util.action_assign_signature(
|
||||
self,
|
||||
|
|
@ -151,7 +165,7 @@ class SOS_Dock_Audit(models.Model):
|
|||
body_html = f"""
|
||||
<p>Below Dock Audit is waiting for your Approval</p>
|
||||
"""
|
||||
sequence_util.send_direct_email(self.env,"sos_dock_audit",self.id,"ramachandran.r@sosaley.in","Dock Audit Approval",body_html)
|
||||
sequence_util.send_direct_email(self.env,"sos_dock_audit",self.id,"ramachandran.r@sosaley.com","Dock Audit Approval",body_html)
|
||||
# Email part ends
|
||||
def action_auditor_esign_btn(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
|
|
@ -206,7 +220,7 @@ class SOS_Dock_Audit(models.Model):
|
|||
self.shipping_address = self.deliverables_boq_id.sales_id.shipping_address
|
||||
self.gst_no = self.deliverables_boq_id.sales_id.gst_no
|
||||
self.payment_status = self.deliverables_boq_id.sales_id.payment_status
|
||||
self.customer_name = self.deliverables_boq_id.sales_id.customer_name
|
||||
self.customer_name = self.deliverables_boq_id.sales_id.customer_name.customer_name
|
||||
self.fg_name = self.deliverables_boq_id.sales_id.fg_name
|
||||
self.quantity = self.deliverables_boq_id.sales_id.qty
|
||||
self.lead_time = self.deliverables_boq_id.sales_id.lead_time
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ class SOS_FG_Plan(models.Model):
|
|||
prepared_by = fields.Many2one('res.users', string='Planned By')
|
||||
prepared_image = fields.Image(related="prepared_by.signature_image",string='Prepared By Sign',readonly=True)
|
||||
prepared_on = fields.Datetime(string="Planned On")
|
||||
|
||||
accounts_approved_on = fields.Datetime(string="Accounts Approved On")
|
||||
accounts_approved_name = fields.Many2one('res.users', string='Accounts Sign')
|
||||
accounts_approved_by_image = fields.Image(related="accounts_approved_name.signature_image",string='Accounts Sign',readonly=True)
|
||||
|
||||
blowup = fields.Boolean(string="Blowup Done",default=False)
|
||||
target_date = fields.Date(string="Target Date",required=True)
|
||||
indent_start_date = fields.Date(string="Indent Start Date", default=lambda self: fields.Date.context_today(self))
|
||||
|
|
@ -116,29 +121,45 @@ class SOS_FG_Plan(models.Model):
|
|||
month = today.strftime('%m')
|
||||
base_sequence_prefix = f"SOS/{form_name}/{fy}/{month}/"
|
||||
|
||||
# Search for latest record for this fiscal year (not just this month)
|
||||
records = self.env[model_name].sudo().search(
|
||||
[(field_name, 'like', f"{base_sequence_prefix}%")],
|
||||
[(field_name, 'like', f"SOS/{form_name}/{fy}/%")],
|
||||
order=f"{field_name} desc",
|
||||
limit=1
|
||||
)
|
||||
|
||||
if records:
|
||||
last_sequence = records[0][field_name]
|
||||
last_suffix = last_sequence.split('/')[-1]
|
||||
if last_suffix.isdigit():
|
||||
new_suffix = f"{last_suffix}a"
|
||||
parts = last_sequence.split('/')
|
||||
last_month = parts[-2]
|
||||
last_suffix = parts[-1]
|
||||
|
||||
# Extract numeric part only (ignore trailing alphabet)
|
||||
numeric_part = ''.join(filter(str.isdigit, last_suffix))
|
||||
|
||||
if last_month != month:
|
||||
# New month: increment numeric part, no suffix
|
||||
new_number = int(numeric_part) + 1
|
||||
new_suffix = f"{new_number:03d}"
|
||||
else:
|
||||
base_num = last_suffix[:-1]
|
||||
last_alpha = last_suffix[-1]
|
||||
next_alpha = chr(ord(last_alpha) + 1) if last_alpha < 'z' else 'a'
|
||||
new_suffix = f"{base_num}{next_alpha}"
|
||||
# Same month: check for alphabet suffix
|
||||
alpha_part = ''.join(filter(str.isalpha, last_suffix))
|
||||
if alpha_part:
|
||||
next_alpha = chr(ord(alpha_part) + 1) if alpha_part < 'z' else 'a'
|
||||
new_suffix = f"{numeric_part}{next_alpha}"
|
||||
else:
|
||||
# First duplicate in same month
|
||||
new_suffix = f"{numeric_part}a"
|
||||
else:
|
||||
new_suffix = '016'
|
||||
# No previous records at all
|
||||
new_suffix = '001'
|
||||
|
||||
return f"{base_sequence_prefix}{new_suffix}"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _get_default_lines(self,model,column):
|
||||
products = self.env[model].search([])
|
||||
|
|
@ -170,9 +191,10 @@ class SOS_FG_Plan(models.Model):
|
|||
|
||||
|
||||
def send_indent_plan_email(self, email_ids):
|
||||
valid_emails = [email for email in email_ids if email]
|
||||
template = self.env.ref('sos_inventory.send_indent_plan_email_template')
|
||||
if template:
|
||||
template.email_to = ','.join(email_ids)
|
||||
template.email_to = ','.join(valid_emails)
|
||||
template.send_mail(self.id, force_send=True)
|
||||
def get_unique_emails(self):
|
||||
group_refs = [
|
||||
|
|
@ -290,7 +312,22 @@ class SOS_FG_Plan(models.Model):
|
|||
else:
|
||||
worksheet.write(row, 1, value)
|
||||
|
||||
|
||||
def action_acc_approver_esign_btn(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
body_html = f"""
|
||||
<p>Below <b>Indent Budget</b> is waiting for your Approval</p>
|
||||
"""
|
||||
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_fg_plan",self.id,"ramachandran.r@sosaley.com","Indent Budget Approval",body_html)
|
||||
result = sequence_util.action_assign_signature(
|
||||
self,
|
||||
'accounts_approved_name',
|
||||
'accounts_approved_on',
|
||||
'sos_inventory.sos_finance_user'
|
||||
)
|
||||
|
||||
|
||||
def action_top_approver_esign_btn(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
result = sequence_util.action_assign_signature(
|
||||
|
|
@ -334,11 +371,9 @@ class SOS_FG_Plan(models.Model):
|
|||
body_html = f"""
|
||||
<p>Below <b>Indent Budget</b> is waiting for your Approval</p>
|
||||
"""
|
||||
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_fg_plan",self.id,"ramachandran.r@sosaley.in","Indent Budget Approval",body_html)
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
result = sequence_util.action_assign_signature(
|
||||
send_email.send_group_email(self.env,'sos_fg_plan',self.id,"deenalaura.m@sosaley.in","Indent Budget Approval",body_html,'sos_inventory.sos_finance_user')
|
||||
result = send_email.action_assign_signature(
|
||||
self,
|
||||
'prepared_by',
|
||||
'prepared_on'
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ class FIR_BRR(models.Model):
|
|||
sos_record.target_date ,
|
||||
date.today()
|
||||
)
|
||||
week_number = min(week_number, 8)
|
||||
field_name = f'qc_week_{week_number}'
|
||||
fgplan_field_name = f'planned_week_{week_number}'
|
||||
# FG Plan update
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ class sos__grn(models.Model):
|
|||
print(f"Failed to find report action: {e}")
|
||||
|
||||
def action_report_esign_btn(self):
|
||||
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
sequence_util.action_assign_signature(
|
||||
self,
|
||||
|
|
@ -84,6 +85,7 @@ class sos__grn(models.Model):
|
|||
'stores_approval_on',
|
||||
'sos_inventory.sos_scg_group_user'
|
||||
)
|
||||
self.generate_supplier_service()
|
||||
if self.received_goods_type == "Materials":
|
||||
for item in self.line_ids:
|
||||
component = self.env['sos_material'].browse(item.component_id.id)
|
||||
|
|
@ -148,7 +150,180 @@ class sos__grn(models.Model):
|
|||
def _compute_sequence(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.generate_sequence('sos_grn','GRN', 'grn_no')
|
||||
def generate_supplier_service(self):
|
||||
|
||||
grn = self.env['sos_grn'].browse(self.id)
|
||||
|
||||
if self.received_goods_type == "Materials":
|
||||
# Check for existing register line
|
||||
already_created = self.env['sos_mat_outsourcing_vendor_register_lines'].search([
|
||||
('ref_id.supplier_name', '=', grn.supplier_name.id),
|
||||
('po_no', '=', grn.po_no.id)
|
||||
], limit=1)
|
||||
# Get or create the main register
|
||||
outsource = self.env['sos_mat_outsourcing_vendor_register'].search(
|
||||
[('supplier_name', '=', grn.supplier_name.id)], limit=1)
|
||||
if not outsource:
|
||||
outsource = self.env['sos_mat_outsourcing_vendor_register'].create({
|
||||
'supplier_name': grn.supplier_name.id,
|
||||
})
|
||||
ir_records = self.env['sos_ir'].search([('po_no', '=', grn.po_no.id)])
|
||||
iqi_records = self.env['sos_iqi'].search([('ir_id_unique_id', 'in', ir_records.ids)])
|
||||
grn_records = self.env['sos_grn'].search([('po_no', '=', grn.po_no.id)])
|
||||
grn_line_records = self.env['sos_grn_line'].search([('grn_id', 'in', grn_records.ids)])
|
||||
|
||||
# Prepare material_names list
|
||||
mat_record = [line.component_id.id for line in grn_line_records if line.component_id and line.component_id.part_no]
|
||||
material_names = [(6, 0, mat_record)]
|
||||
|
||||
# Sum all GRN line quantities including current
|
||||
total_received_qty = sum(grn_line_records.mapped('received_qty')) #+ new_received
|
||||
total_approved_qty = sum(grn_line_records.mapped('approved_qty')) #+ new_approved
|
||||
total_rejected_qty = sum(grn_line_records.mapped('rejected_qty')) #+ new_rejected
|
||||
|
||||
delivery_values = grn_records.mapped('delivery')
|
||||
delivery_numbers = [float(value) for value in delivery_values if value]
|
||||
existing_count = len(delivery_numbers)
|
||||
|
||||
responsive_values = grn_records.mapped('responsiveness')
|
||||
responsive_numbers = [float(value) for value in responsive_values if value]
|
||||
|
||||
reports_values = grn_records.mapped('reports')
|
||||
reports_numbers = [float(value) for value in reports_values if value]
|
||||
|
||||
avg_delivery_marks = sum(delivery_numbers) / (existing_count)
|
||||
delivery = (
|
||||
30 if 27.5 < avg_delivery_marks <= 30 else
|
||||
25 if 22.5 < avg_delivery_marks <= 27.5 else
|
||||
10 if avg_delivery_marks < 20 else
|
||||
0
|
||||
)
|
||||
|
||||
avg_report_marks = sum(reports_numbers) / (existing_count)
|
||||
report = (
|
||||
30 if 27.5 < avg_report_marks <= 30 else
|
||||
25 if 22.5 < avg_report_marks <= 27.5 else
|
||||
10 if avg_report_marks < 20 else
|
||||
0
|
||||
)
|
||||
|
||||
avg_responsiveness_marks = sum(responsive_numbers) / (existing_count)
|
||||
|
||||
responsiveness = (
|
||||
10 if 5 <= avg_responsiveness_marks <= 10 else
|
||||
5 if avg_responsiveness_marks < 5 else
|
||||
0
|
||||
)
|
||||
if already_created:
|
||||
updated_vals = {
|
||||
'received_qty': total_received_qty,
|
||||
'approved_qty': total_approved_qty,
|
||||
'rejected_qty': total_rejected_qty,
|
||||
'delivery_marks': delivery,
|
||||
'responsiveness_marks': responsiveness,
|
||||
'report_marks': report,
|
||||
'iqi_references': [(6, 0, iqi_records.ids)],
|
||||
'grn_references': [(6, 0, grn_records.ids)],
|
||||
'material_names': material_names,
|
||||
}
|
||||
already_created.write(updated_vals)
|
||||
else:
|
||||
self.env['sos_mat_outsourcing_vendor_register_lines'].create({
|
||||
'ref_id': outsource.id,
|
||||
'po_no': grn.po_no.id,
|
||||
'received_qty': total_received_qty,
|
||||
'approved_qty': total_approved_qty,
|
||||
'rejected_qty': total_rejected_qty,
|
||||
'iqi_references': [(6, 0, iqi_records.ids)],
|
||||
'grn_references': [(6, 0, grn_records.ids)],
|
||||
'material_names': material_names,
|
||||
'delivery_marks': delivery,
|
||||
'responsiveness_marks': responsiveness,
|
||||
'report_marks': report,
|
||||
})
|
||||
|
||||
elif self.received_goods_type == "SFG":
|
||||
|
||||
# Check for existing register line
|
||||
already_created = self.env['sos_outsourcing_vendor_monitoring_register_lines'].search([
|
||||
('ref_id.service_provider_name', '=', grn.service_provider_name.id),
|
||||
('wo_no', '=', grn.wo_no.id)
|
||||
], limit=1)
|
||||
|
||||
# Get or create the main register
|
||||
outsource = self.env['sos_outsourcing_vendor_monitoring_register'].search(
|
||||
[('service_provider_name', '=', grn.service_provider_name.id)], limit=1)
|
||||
if not outsource:
|
||||
outsource = self.env['sos_outsourcing_vendor_monitoring_register'].create({
|
||||
'service_provider_name': grn.service_provider_name.id,
|
||||
})
|
||||
# Related documents
|
||||
ir_records = self.env['sos_ir'].search([('wo_no', '=', grn.wo_no.id)])
|
||||
iqi_records = self.env['sos_iqi'].search([('ir_id_unique_id', 'in', ir_records.ids)])
|
||||
dc_records = self.env['sos_dc'].search([('wo_no', '=', grn.wo_no.id)])
|
||||
grn_records = self.env['sos_grn'].search([('wo_no', '=', grn.wo_no.id)])
|
||||
|
||||
grn_line_records = self.env['sos_grn_line_sfg'].search([('grn_id', 'in', grn_records.ids)])
|
||||
|
||||
# Prepare material_names list
|
||||
sfg_ids = [line.component_id.id for line in grn_line_records if line.component_id and line.component_id.name]
|
||||
|
||||
# Include current line component manually if not yet saved in DB
|
||||
current_component_id = self.line_ids.component_id
|
||||
if current_component_id and current_component_id not in sfg_ids:
|
||||
sfg_ids.append(current_component_id)
|
||||
|
||||
sfg_names = [(6, 0, sfg_ids)]
|
||||
|
||||
total_received_qty = sum(grn_line_records.mapped('received_qty'))
|
||||
total_approved_qty = sum(grn_line_records.mapped('approved_qty'))
|
||||
total_rejected_qty = sum(grn_line_records.mapped('rejected_qty'))
|
||||
|
||||
delivery_values = grn_line_records.mapped('delivery')
|
||||
delivery_numbers = [float(value) for value in delivery_values if value]
|
||||
existing_count = len(delivery_numbers)
|
||||
|
||||
responsive_values = grn_line_records.mapped('responsiveness')
|
||||
responsive_numbers = [float(value) for value in responsive_values if value]
|
||||
|
||||
reports_values = grn_line_records.mapped('reports')
|
||||
reports_numbers = [float(value) for value in reports_values if value]
|
||||
|
||||
avg_delivery_marks = sum(delivery_numbers) / (existing_count)
|
||||
avg_responsiveness_marks = sum(responsive_numbers) / (existing_count)
|
||||
avg_report_marks = sum(reports_numbers) / (existing_count)
|
||||
|
||||
if already_created:
|
||||
#print(f" sfg_names : if {sfg_names}")
|
||||
updated_vals = {
|
||||
'received_qty': total_received_qty,
|
||||
'approved_qty': total_approved_qty,
|
||||
'rejected_qty': total_rejected_qty,
|
||||
'delivery_marks': avg_delivery_marks,
|
||||
'responsiveness_marks': avg_responsiveness_marks,
|
||||
'report_marks': avg_report_marks,
|
||||
'iqi_references': [(6, 0, iqi_records.ids)],
|
||||
'dc_references': [(6, 0, dc_records.ids)],
|
||||
'grn_references': [(6, 0, grn_records.ids)],
|
||||
'sfg_names': sfg_names,
|
||||
}
|
||||
already_created.write(updated_vals)
|
||||
else:
|
||||
#print(f" sfg_names : else {sfg_names}")
|
||||
self.env['sos_outsourcing_vendor_monitoring_register_lines'].create({
|
||||
'ref_id': outsource.id,
|
||||
'iqi_references': [(6, 0, iqi_records.ids)],
|
||||
'dc_references': [(6, 0, dc_records.ids)],
|
||||
'grn_references': [(6, 0, grn_records.ids)],
|
||||
'sfg_names': sfg_names,
|
||||
'wo_no': grn.wo_no.id,
|
||||
'received_qty': total_received_qty,
|
||||
'approved_qty': total_approved_qty,
|
||||
'rejected_qty': total_rejected_qty,
|
||||
'delivery_marks': avg_delivery_marks,
|
||||
'responsiveness_marks': avg_responsiveness_marks,
|
||||
'report_marks': avg_report_marks,
|
||||
})
|
||||
class sos_grn_line(models.Model):
|
||||
_name = 'sos_grn_line'
|
||||
_description = 'GRN Material Lines'
|
||||
|
|
@ -169,14 +344,19 @@ class sos_grn_line(models.Model):
|
|||
@api.depends('received_qty', 'rejected_qty')
|
||||
def _compute_quality(self):
|
||||
for record in self:
|
||||
if record.rejected_qty != 0:
|
||||
record.quality_marks = (100 - ((record.rejected_qty / record.received_qty) * 100))
|
||||
if record.quality_marks >= 80 and record.quality_marks <=99:
|
||||
record.quality_marks = 25
|
||||
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||
|
||||
|
||||
def _calculate_quality_marks(self, received, rejected):
|
||||
if received != 0:
|
||||
q = 100 - ((rejected / received) * 100)
|
||||
if 91 <= q <= 100:
|
||||
return 30
|
||||
elif 80 <= q <= 90:
|
||||
return 25
|
||||
else:
|
||||
record.quality_marks = 10
|
||||
else:
|
||||
record.quality_marks = 100
|
||||
return 10
|
||||
return 0
|
||||
|
||||
@api.model
|
||||
def write(self, vals):
|
||||
|
|
@ -295,14 +475,20 @@ class sos_grn_line_sfg(models.Model):
|
|||
@api.depends('received_qty', 'rejected_qty')
|
||||
def _compute_sfgquality(self):
|
||||
for record in self:
|
||||
if record.rejected_qty != 0:
|
||||
record.quality_marks = (100 - ((record.rejected_qty / record.received_qty) * 100))
|
||||
if record.quality_marks >= 80 and record.quality_marks <=99:
|
||||
record.quality_marks = 25
|
||||
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||
|
||||
|
||||
|
||||
def _calculate_quality_marks(self, received, rejected):
|
||||
if received != 0:
|
||||
q = 100 - ((rejected / received) * 100)
|
||||
if 91 <= q <= 100:
|
||||
return 30
|
||||
elif 80 <= q <= 90:
|
||||
return 25
|
||||
else:
|
||||
record.quality_marks = 10
|
||||
else:
|
||||
record.quality_marks = 100
|
||||
return 10
|
||||
return 0
|
||||
|
||||
class sos_grn_line_fg(models.Model):
|
||||
_name = 'sos_grn_line_fg'
|
||||
|
|
|
|||
|
|
@ -276,25 +276,26 @@ class SOS_IR(models.Model):
|
|||
|
||||
|
||||
else:
|
||||
iqi_record = self.env['sos_iqi'].create({
|
||||
'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'),
|
||||
'material_option':True,
|
||||
'sfg_option':False,
|
||||
'supplier_name': self.supplier_name.id,
|
||||
'batch_no':item.batch_no,
|
||||
'received_qty':item.qty,
|
||||
'uom': item.component_id.uom,
|
||||
'material_name': item.component_id.id,
|
||||
'material_code': item.component_id.material_code,
|
||||
'in_tact':self.boxes_sealing,
|
||||
'invoice_no':self.dc_no_char,
|
||||
'invoice_date':self.dc_date,
|
||||
'ir_id_unique_id':self.id,
|
||||
'from_origin':"Vendor",
|
||||
'unit_price':item.unit_price
|
||||
|
||||
if item.qty > 0:
|
||||
iqi_record = self.env['sos_iqi'].create({
|
||||
'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'),
|
||||
'material_option':True,
|
||||
'sfg_option':False,
|
||||
'supplier_name': self.supplier_name.id,
|
||||
'batch_no':item.batch_no,
|
||||
'received_qty':item.qty,
|
||||
'uom': item.component_id.uom,
|
||||
'material_name': item.component_id.id,
|
||||
'material_code': item.component_id.material_code,
|
||||
'in_tact':self.boxes_sealing,
|
||||
'invoice_no':self.dc_no_char,
|
||||
'invoice_date':self.dc_date,
|
||||
'ir_id_unique_id':self.id,
|
||||
'from_origin':"Vendor",
|
||||
'unit_price':item.unit_price
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
# Email part
|
||||
body_html = f"""
|
||||
<p>Below <b>IQI</b> is waiting for your Approval</p>
|
||||
|
|
@ -383,7 +384,7 @@ class SOS_IR(models.Model):
|
|||
"""
|
||||
subject = f"Inward Approval Request - {self.ir_no}"
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_ir",self.id,"ramachandran.r@sosaley.in",subject,body_html)
|
||||
send_email.send_direct_email(self.env,"sos_ir",self.id,"ramachandran.r@sosaley.com",subject,body_html)
|
||||
# Email part ends
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.action_assign_signature(
|
||||
|
|
|
|||
|
|
@ -35,12 +35,26 @@ class SOS_Mat_Oursourcing_Monitor_Lines(models.Model):
|
|||
rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True)
|
||||
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
||||
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
||||
|
||||
quality_marks = fields.Float(string="Quality Marks")
|
||||
quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality")
|
||||
delivery_marks = fields.Float(string="Delivery Marks")
|
||||
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
||||
report_marks = fields.Float(string="Report Marks")
|
||||
def _calculate_quality_marks(self, received, rejected):
|
||||
if received != 0:
|
||||
q = 100 - ((rejected / received) * 100)
|
||||
if 91 <= q <= 100:
|
||||
return 30
|
||||
elif 80 <= q <= 90:
|
||||
return 25
|
||||
else:
|
||||
return 10
|
||||
return 0
|
||||
|
||||
@api.depends('received_qty', 'rejected_qty')
|
||||
def _compute_sfgquality(self):
|
||||
for record in self:
|
||||
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||
|
||||
@api.depends('rejection_percentage')
|
||||
def _compute_rejected_percentage_display(self):
|
||||
for record in self:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class sos__mon(models.Model):
|
|||
filled_by = fields.Many2one('res.users', string='Filled By', readonly=True,required=True,default=lambda self: self.env.user)
|
||||
logged_inuser_group=fields.Boolean(string='Group Name',compute='compute_user_grp',store=True)
|
||||
dept = fields.Many2one('sos_departments',string="Department")
|
||||
customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name")
|
||||
purpose = fields.Char(string="Purpose")
|
||||
product_name = fields.Many2one('sos_fg', string='Material/Product Name & No')
|
||||
indent_ref_no = fields.Many2one('sos_fg_plan',string="Indent Reference No")
|
||||
|
|
@ -33,7 +34,7 @@ class sos__mon(models.Model):
|
|||
top_management_name = fields.Many2one('res.users', string='Top Management Approver')
|
||||
top_management_approval_image = fields.Image(related="top_management_name.signature_image",string='Top Management Approval',readonly=True)
|
||||
top_management_approved_on = fields.Datetime(string="Approved On")
|
||||
|
||||
deliverables_boq_id = fields.Many2one('sos_deliverables_boq', string="Load From Deliverables/BOQ Id")
|
||||
stores_approved_by = fields.Many2one('res.users', string='Stores Approved By')
|
||||
stores_approved_image = fields.Image(related="stores_approved_by.signature_image",string='Stores Approval Sign',readonly=True)
|
||||
stores_approved_on = fields.Datetime(string="Approved On")
|
||||
|
|
@ -43,9 +44,9 @@ class sos__mon(models.Model):
|
|||
('fg', 'FG')
|
||||
], string='Auto Load Items' ,default=False)
|
||||
material_option = fields.Boolean('Materials', default=True)
|
||||
sfg_option = fields.Boolean('Semi-Finished Goods')
|
||||
fg_option = fields.Boolean('Finished Goods')
|
||||
order_type = fields.Char(string='order_type',copy=True)
|
||||
sfg_option = fields.Boolean('Semi-Finished Goods', default=False)
|
||||
fg_option = fields.Boolean('Finished Goods', default=False)
|
||||
order_type = fields.Char(string='order_type',copy=True,compute="_compute_order_type")
|
||||
line_ids_material = fields.One2many('sos_mon_line_material', 'mon_id', string="Materials",copy=True)
|
||||
line_ids_sfg = fields.One2many('sos_mon_line_sfg', 'mon_id', string="Semi-Finished Goods",copy=True)
|
||||
line_ids_fg = fields.One2many('sos_mon_line_fg', 'mon_id', string="Finished Goods",copy=True)
|
||||
|
|
@ -73,6 +74,74 @@ class sos__mon(models.Model):
|
|||
approx_value = fields.Monetary(compute='_compute_approx_value', string="Approximate Value", currency_field='currency_id', readonly=True,store=True)
|
||||
status = fields.Selection([ ('open', 'Open'),('close', 'Closed')], default='open' , string="Status")
|
||||
active = fields.Boolean(default=True)
|
||||
is_ce_user_created = fields.Boolean(
|
||||
compute='_compute_is_ce_user_created',
|
||||
store=True,
|
||||
string='Created by CE User'
|
||||
)
|
||||
@api.depends('create_uid')
|
||||
def _compute_is_ce_user_created(self):
|
||||
ce_groups = [
|
||||
self.env.ref('sos_inventory.sos_ce_user').id
|
||||
]
|
||||
for record in self:
|
||||
record.is_ce_user_created = any(
|
||||
gid in record.create_uid.groups_id.ids for gid in ce_groups
|
||||
)
|
||||
@api.depends('material_option', 'sfg_option', 'fg_option')
|
||||
def _compute_order_type(self):
|
||||
for rec in self:
|
||||
parts = []
|
||||
if rec.material_option:
|
||||
parts.append('Material')
|
||||
if rec.sfg_option:
|
||||
parts.append('SFG')
|
||||
if rec.fg_option:
|
||||
parts.append('FG')
|
||||
rec.order_type = ",".join(parts) if parts else False
|
||||
@api.onchange('deliverables_boq_id')
|
||||
def _onchange_deliverables_boq_id(self):
|
||||
self.material_option = True
|
||||
self.sfg_option = True
|
||||
self.fg_option = True
|
||||
if self.deliverables_boq_id:
|
||||
self.line_ids_material = [(5, 0, 0)] # Clear existing records
|
||||
self.line_ids_material = [
|
||||
(0, 0, {
|
||||
'component_id': line.component_id, # Replace 'field1' with the actual field names
|
||||
'uom': line.uom,
|
||||
'material_code': line.material_code,
|
||||
'quantity': line.quantity
|
||||
|
||||
# Add other fields to copy here
|
||||
}) for line in self.deliverables_boq_id.line_ids_installation_kit
|
||||
]
|
||||
self.line_ids_fg = [(5, 0, 0)] # Clear existing records
|
||||
self.line_ids_fg = [
|
||||
(0, 0, {
|
||||
'component_id': line.component_id, # Replace 'field1' with the actual field names
|
||||
'quantity': line.quantity
|
||||
}) for line in self.deliverables_boq_id.line_ids_fg
|
||||
]
|
||||
self.line_ids_sfg = [(5, 0, 0)] # Clear existing records
|
||||
self.line_ids_sfg = [
|
||||
(0, 0, {
|
||||
'component_id': line.component_id, # Replace 'field1' with the actual field names
|
||||
'quantity': line.quantity
|
||||
# Add other fields to copy here
|
||||
}) for line in self.deliverables_boq_id.line_ids_sfg
|
||||
]
|
||||
self.line_ids_material = [
|
||||
(0, 0, {
|
||||
'uom': line.uom,
|
||||
'material_code': line.material_code,
|
||||
'component_id': line.component_id,
|
||||
'quantity': line.quantity
|
||||
# Add other fields to copy here
|
||||
}) for line in self.deliverables_boq_id.line_ids_material
|
||||
]
|
||||
|
||||
|
||||
@api.constrains('indent_ref_no', 'auto_load_fg_items')
|
||||
def _check_duplicate_fg_items_per_indent(self):
|
||||
for record in self:
|
||||
|
|
@ -461,7 +530,7 @@ class Mon_Line_Material(models.Model):
|
|||
uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], string="Uom")
|
||||
specifications = fields.Char(string="Specifications")
|
||||
quantity = fields.Float(string="Quantity",required=True,default=1)
|
||||
location = fields.Char(string="Location")
|
||||
location = fields.Char(string="Location",related='component_id.location')
|
||||
company_id = fields.Many2one('res.company', store=True, copy=False,
|
||||
string="Company",
|
||||
default=lambda self: self.env.user.company_id.id)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,20 @@ class sos__mrn(models.Model):
|
|||
default=lambda
|
||||
self: self.env.user.company_id.currency_id.id)
|
||||
approx_value = fields.Monetary(compute='_compute_approx_value', string="Approximate Value", currency_field='currency_id', readonly=True)
|
||||
is_ce_user_created = fields.Boolean(
|
||||
compute='_compute_is_ce_user_created',
|
||||
store=True,
|
||||
string='Created by CE User'
|
||||
)
|
||||
@api.depends('create_uid')
|
||||
def _compute_is_ce_user_created(self):
|
||||
ce_groups = [
|
||||
self.env.ref('sos_inventory.sos_ce_user').id
|
||||
]
|
||||
for record in self:
|
||||
record.is_ce_user_created = any(
|
||||
gid in record.create_uid.groups_id.ids for gid in ce_groups
|
||||
)
|
||||
@api.onchange('min_no')
|
||||
def _onchange_min_no(self):
|
||||
if self.min_no:
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ class NCMR_Model(models.Model):
|
|||
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")
|
||||
root_cause_of_nc = fields.Html(string="Root Cause",
|
||||
default="<p>Why #1 :</p><p>Why #2 :</p><p>Why #3 :</p><p>Why #4 :</p><p>Why #5 :</p>")
|
||||
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")
|
||||
|
|
@ -104,6 +105,14 @@ class NCMR_Model(models.Model):
|
|||
rework_rd_approval_by = fields.Many2one('res.users',string='Rework - R&D In-Charge',readonly=True)
|
||||
rework_rd_approval_sign = fields.Image(related="rework_rd_approval_by.signature_image",string='Rework - R&D In-Charge',readonly=True)
|
||||
rework_rd_approval_on = fields.Datetime(string="Approved On")
|
||||
|
||||
responsible_department = fields.Many2one('sos_departments', string='Department')
|
||||
responsible_name = fields.Many2one('res.users',string='Responsible Person',domain="[('id', 'in', allowed_user_ids)]")
|
||||
allowed_user_ids = fields.Many2many('res.users', compute='_compute_allowed_users')
|
||||
rca_responsible_department = fields.Many2many('sos_departments', string='Department')
|
||||
rca_responsible_name = fields.Many2many('res.users',string='Responsible Person',relation='sos_ncmr_rca_responsible_name_rel',domain="[('id', 'in', rca_allowed_user_ids)]")
|
||||
rca_allowed_user_ids = fields.Many2many('res.users', compute='_rca_compute_allowed_users')
|
||||
|
||||
|
||||
combined_incoming_doc_ref = fields.Reference(
|
||||
selection=[
|
||||
|
|
@ -120,8 +129,155 @@ class NCMR_Model(models.Model):
|
|||
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")
|
||||
|
||||
problem_description_line_ids = fields.One2many('sos_ncmr_problem_description_line', 'ncmr_id', string="Problem Description Line Ids",copy=True)
|
||||
|
||||
@api.depends('responsible_department')
|
||||
def _compute_allowed_users(self):
|
||||
for rec in self:
|
||||
rec.allowed_user_ids = rec.responsible_department.users_line_ids.mapped('users')
|
||||
|
||||
@api.depends('rca_responsible_department')
|
||||
def _rca_compute_allowed_users(self):
|
||||
for rec in self:
|
||||
rec.rca_allowed_user_ids = rec.rca_responsible_department.users_line_ids.mapped('users')
|
||||
|
||||
@api.model
|
||||
def get_service_suppliers_by_goods_type(self,goods_type=False,startDate=False, endDate=False):
|
||||
|
||||
if goods_type == 'Material':
|
||||
|
||||
query = """
|
||||
SELECT id,supplier_name
|
||||
FROM sos_suppliers
|
||||
WHERE id IN (
|
||||
SELECT b.supplier_name
|
||||
FROM sos_ncmr a, sos_iqi b
|
||||
WHERE a.incoming_doc_ref = b.id
|
||||
AND a.material_option = 't'
|
||||
AND a.ncmr_date BETWEEN %s AND %s
|
||||
)
|
||||
"""
|
||||
elif goods_type == 'SFG':
|
||||
|
||||
query = """
|
||||
SELECT id,service_provider_name
|
||||
FROM sos_service_providers
|
||||
WHERE id IN (
|
||||
SELECT b.service_provider_name
|
||||
FROM sos_ncmr a, sos_iqi b
|
||||
WHERE a.incoming_doc_ref = b.id
|
||||
AND a.sfg_option = 't'
|
||||
AND a.ncmr_date BETWEEN %s AND %s
|
||||
)
|
||||
"""
|
||||
|
||||
self.env.cr.execute(query,(startDate, endDate))
|
||||
rows = self.env.cr.fetchall()
|
||||
result = [{'id': '', 'supplier_name': 'Select Supplier/Service'}]
|
||||
result += [{'id': row[0], 'supplier_name': row[1]} for row in rows]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@api.model
|
||||
def get_pareto_data(self, start_date=False, end_date=False, goodstype=False, categoryId=False, servicesupplier=False):
|
||||
|
||||
if not start_date or not end_date:
|
||||
raise ValueError("Start date and end date must be provided.")
|
||||
|
||||
base_where_clause = "a.ncmr_date BETWEEN %s AND %s"
|
||||
where_params = [start_date, end_date]
|
||||
base_groupby_clause = "d.name"
|
||||
|
||||
if goodstype == 'Material':
|
||||
join_clause = """
|
||||
JOIN sos_material_defective_line_sos_ncmr_line_rel c ON b.id = c.sos_ncmr_line_id
|
||||
JOIN sos_material_defective_line d ON c.sos_material_defective_line_id = d.id
|
||||
JOIN sos_material_configuration e ON a.material_category = e.id
|
||||
"""
|
||||
if categoryId and categoryId != 'Select Category':
|
||||
join_clause += " JOIN sos_material f ON a.material_name = f.id JOIN sos_material_types g ON f.material_type_id = g.id"
|
||||
base_where_clause += " AND g.name = %s"
|
||||
#base_groupby_clause += ",g.name"
|
||||
where_params.append(categoryId)
|
||||
|
||||
if servicesupplier and servicesupplier !='Select Supplier/Service' and servicesupplier !='undefined':
|
||||
join_clause += " LEFT JOIN sos_iqi h ON a.incoming_doc_ref = h.id LEFT JOIN sos_suppliers i ON h.supplier_name = i.id"
|
||||
base_where_clause += " AND h.supplier_name = %s"
|
||||
base_groupby_clause += ",h.supplier_name"
|
||||
where_params.append(servicesupplier)
|
||||
|
||||
elif goodstype == 'SFG':
|
||||
join_clause = """
|
||||
JOIN sos_ncmr_line_sos_sfg_defective_line_rel c ON b.id = c.sos_ncmr_line_id
|
||||
JOIN sos_sfg_defective_line d ON c.sos_sfg_defective_line_id = d.id
|
||||
JOIN sos_sfg_configuration e ON a.sfg_category = e.id
|
||||
"""
|
||||
if categoryId and categoryId != 'Select Category':
|
||||
join_clause += " JOIN sos_sfg f ON a.sfg_name = f.id"
|
||||
base_where_clause += " AND f.category = %s"
|
||||
base_groupby_clause += ",f.category"
|
||||
where_params.append(categoryId)
|
||||
|
||||
if servicesupplier and servicesupplier !='Select Supplier/Service' and servicesupplier !='undefined':
|
||||
join_clause += " LEFT JOIN sos_iqi g ON a.incoming_doc_ref = g.id LEFT JOIN sos_service_providers h ON g.service_provider_name = h.id"
|
||||
base_where_clause += " AND g.service_provider_name = %s"
|
||||
base_groupby_clause += ",g.service_provider_name"
|
||||
where_params.append(servicesupplier)
|
||||
|
||||
elif goodstype == 'FG':
|
||||
join_clause = """
|
||||
JOIN sos_defectives_sos_ncmr_line_rel c ON b.id = c.sos_ncmr_line_id
|
||||
JOIN sos_defectives d ON c.sos_defectives_id = d.id
|
||||
JOIN sos_testing_parameters f ON a.fg_category = f.id
|
||||
JOIN sos_fg e ON e.id = f.fg_name
|
||||
"""
|
||||
|
||||
if categoryId and categoryId != 'Select Category':
|
||||
base_where_clause += " AND e.fg_type = %s"
|
||||
base_groupby_clause += ",e.fg_type"
|
||||
where_params.append(categoryId)
|
||||
|
||||
# Build the full SQL query dynamically
|
||||
|
||||
query = f"""
|
||||
SELECT
|
||||
defect_name,
|
||||
count,
|
||||
ROUND(count * 100.0 / total, 2) AS individual_percent,
|
||||
ROUND(SUM(count) OVER (ORDER BY count DESC ROWS UNBOUNDED PRECEDING) * 100.0 / total, 2) AS cumulative_percent
|
||||
FROM (
|
||||
SELECT
|
||||
d.name AS defect_name,
|
||||
COUNT(*) AS count,
|
||||
SUM(COUNT(*)) OVER () AS total
|
||||
FROM
|
||||
sos_ncmr a
|
||||
JOIN sos_ncmr_line b ON a.id = b.ncmr_id
|
||||
{join_clause}
|
||||
WHERE
|
||||
{base_where_clause}
|
||||
GROUP BY
|
||||
{base_groupby_clause}
|
||||
) AS sub
|
||||
ORDER BY
|
||||
count DESC;
|
||||
"""
|
||||
|
||||
self.env.cr.execute(query, tuple(where_params))
|
||||
result = self.env.cr.fetchall()
|
||||
|
||||
data = []
|
||||
for row in result:
|
||||
data.append({
|
||||
'defect_name': row[0], # defect_name
|
||||
'count': row[1], # count
|
||||
'cumulative_percent': row[3], # cumulative_percent
|
||||
})
|
||||
|
||||
return data
|
||||
#Excel Write
|
||||
def action_ncmr_report_orm_btn(self, from_date, to_date,force_download=True):
|
||||
output = io.BytesIO()
|
||||
|
|
@ -559,17 +715,18 @@ class NCMR_Model(models.Model):
|
|||
'sos_inventory.sos_qa_user'
|
||||
)
|
||||
else:
|
||||
|
||||
if all_closed or record.aodr_no:
|
||||
self.status = 'closed'
|
||||
if self.rework_action == "inhouse":
|
||||
s_no_list = self.line_ids.mapped('s_no') # Collect all s_no values
|
||||
s_no_str = ', '.join(map(str, s_no_list))
|
||||
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_name': self.material_name.id,
|
||||
'material_code': self.material_name.material_code,
|
||||
'sfg_name': self.sfg_name.id,
|
||||
'sfg_code': self.sfg_name.sfg_code,
|
||||
|
|
@ -577,7 +734,9 @@ class NCMR_Model(models.Model):
|
|||
'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
|
||||
'in_tact':self.incoming_doc_ref.in_tact,
|
||||
'ncmr_ref':self.id,
|
||||
'serial_no':s_no_str
|
||||
# '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,
|
||||
|
|
@ -585,7 +744,7 @@ class NCMR_Model(models.Model):
|
|||
|
||||
|
||||
})
|
||||
|
||||
print(iqi_record)
|
||||
# Rework Iteration starts
|
||||
sos_record = self.env['sos_iqi'].search([('id', '=', self.incoming_doc_ref.id)], limit=1)
|
||||
if sos_record:
|
||||
|
|
@ -622,7 +781,27 @@ class NCMR_Model(models.Model):
|
|||
'sos_inventory.sos_scg_group_user'
|
||||
)
|
||||
if self.rework_action == "inhouse":
|
||||
# Email part
|
||||
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,
|
||||
'goods_type':'Materials',
|
||||
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||
'rework_type':'inhouse'
|
||||
})
|
||||
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,
|
||||
'sfg_name':self.incoming_doc_ref.sfg_name,
|
||||
'goods_type':'SFG',
|
||||
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||
'rework_type':'inhouse'
|
||||
})
|
||||
self.outsourcing_return_ref_no = orr_record.id
|
||||
body_html = f"""
|
||||
<p>Below <b>NCMR</b> is waiting for your Action</p>
|
||||
"""
|
||||
|
|
@ -636,7 +815,8 @@ class NCMR_Model(models.Model):
|
|||
'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
|
||||
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||
'rework_type':'outsourcing'
|
||||
})
|
||||
else:
|
||||
if self.material_option:
|
||||
|
|
@ -647,7 +827,8 @@ class NCMR_Model(models.Model):
|
|||
'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
|
||||
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||
'rework_type':'outsourcing'
|
||||
})
|
||||
else:
|
||||
orr_record = self.env['sos_sfg_outsourcing_return_register'].create({
|
||||
|
|
@ -657,7 +838,8 @@ class NCMR_Model(models.Model):
|
|||
'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
|
||||
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||
'rework_type':'outsourcing'
|
||||
})
|
||||
self.outsourcing_return_ref_no = orr_record.id
|
||||
|
||||
|
|
@ -685,6 +867,26 @@ class NCMR_Model(models.Model):
|
|||
)
|
||||
|
||||
def action_qa_esign_btn(self):
|
||||
if self.responsible_department:
|
||||
if self.material_option:
|
||||
material = self.material_name.part_no
|
||||
elif self.sfg_option:
|
||||
material = self.sfg_name.name
|
||||
else:
|
||||
material = self.fg_name.name
|
||||
result_col = f"NCMR Ref No :{getattr(self, 'ncmr_no', '')}"
|
||||
|
||||
new_action_record = self.env['sos_brm_action'].create({
|
||||
'cross_dept_action': 'cross_dept',
|
||||
'department': 3,
|
||||
'responsible_person': getattr(self.responsible_name, 'id', False),
|
||||
'assigned_by': getattr(self.qa_by, 'id', False),
|
||||
'assigned_from_dept': 3,
|
||||
'assigned_to_dept': getattr(self.responsible_department, 'id', False),
|
||||
'name': f"NCMR Assigned : {material}",
|
||||
'result': result_col
|
||||
})
|
||||
|
||||
if self.action_group:
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
sequence_util.action_assign_signature(
|
||||
|
|
@ -767,8 +969,9 @@ class NCMR_Model_CAPA_Line(models.Model):
|
|||
|
||||
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")
|
||||
corrective_action = fields.Html(string="D5: Permanent Corrective Action")
|
||||
implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions")
|
||||
preventive_action = fields.Html(string="D7:Preventive Recurrence")
|
||||
|
||||
class NCMR_Model_Line(models.Model):
|
||||
_name = 'sos_ncmr_line'
|
||||
|
|
@ -897,3 +1100,18 @@ class NCMR_Model_Line(models.Model):
|
|||
def _compute_fg_defective_count(self):
|
||||
for record in self:
|
||||
record.fg_defective_count = len(record.fg_defectives)
|
||||
|
||||
class NCMR_Model_PROBLEM_DESCRIPTION_Line(models.Model):
|
||||
_name = 'sos_ncmr_problem_description_line'
|
||||
_description = 'Problem Description Lines'
|
||||
|
||||
ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade")
|
||||
clear_statement = fields.Html(string="Clear Statement")
|
||||
photos = fields.Html(string="Photos")
|
||||
what = fields.Text(string="What")
|
||||
where = fields.Text(string="Where")
|
||||
when = fields.Text(string="When")
|
||||
why = fields.Text(string="Why")
|
||||
who = fields.Text(string="Who")
|
||||
how = fields.Text(string="How")
|
||||
how_many = fields.Text(string="How many")
|
||||
|
|
@ -182,7 +182,7 @@ class SOS_Order_Delivery_Plan(models.Model):
|
|||
<p>Below <b>Order Delivery Plan</b> is waiting for your Approval</p>
|
||||
"""
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_order_delivery_plan",self.id,"ramachandran.r@sosaley.in","Order Delivery Plan",body_html)
|
||||
send_email.send_direct_email(self.env,"sos_order_delivery_plan",self.id,"ramachandran.r@sosaley.com","Order Delivery Plan",body_html)
|
||||
# Email part ends
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.action_assign_signature(
|
||||
|
|
|
|||
|
|
@ -36,12 +36,25 @@ class SOS_Oursourcing_Monitor_Lines(models.Model):
|
|||
rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True)
|
||||
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
||||
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
||||
|
||||
quality_marks = fields.Float(string="Quality Marks")
|
||||
quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality")
|
||||
delivery_marks = fields.Float(string="Delivery Marks")
|
||||
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
||||
report_marks = fields.Float(string="Report Marks")
|
||||
def _calculate_quality_marks(self, received, rejected):
|
||||
if received != 0:
|
||||
q = 100 - ((rejected / received) * 100)
|
||||
if 91 <= q <= 100:
|
||||
return 30
|
||||
elif 80 <= q <= 90:
|
||||
return 25
|
||||
else:
|
||||
return 10
|
||||
return 0
|
||||
|
||||
@api.depends('received_qty', 'rejected_qty')
|
||||
def _compute_sfgquality(self):
|
||||
for record in self:
|
||||
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||
@api.depends('rejection_percentage')
|
||||
def _compute_rejected_percentage_display(self):
|
||||
for record in self:
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class sos__po(models.Model):
|
|||
"""
|
||||
subject = f"Purchase Order Approval Request - {self.po_no}"
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_po",self.id,"ramachandran.r@sosaley.in",subject,body_html)
|
||||
send_email.send_direct_email(self.env,"sos_po",self.id,"ramachandran.r@sosaley.com",subject,body_html)
|
||||
# Email part ends
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.action_assign_signature(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
from odoo import models, fields, api
|
||||
|
||||
class SOS_prf(models.Model):
|
||||
_name = 'sos_prf'
|
||||
_description = 'Purchase Requisition Form'
|
||||
_rec_name = 'prf_no'
|
||||
_order = 'id desc'
|
||||
|
||||
prf_no = fields.Char(string="PRF No", readonly= True, required= True, default=lambda self: self._generate_id())
|
||||
prf_date = fields.Date(string="PRF Date", required=True, default=fields.Date.today)
|
||||
line_ids = fields.One2many('sos_prf_lines', 'ref_id', string="PRF Lines",copy=True)
|
||||
requested_by_name = fields.Many2one('res.users', string='Requested by')
|
||||
requested_by_image = fields.Image(related="requested_by_name.signature_image",string='Requested by Sign',readonly=True)
|
||||
requested_on = fields.Datetime(string="Requested On")
|
||||
dept_in_charge_name = fields.Many2one('res.users', string='Department In-Charge')
|
||||
dept_in_charge_image = fields.Image(related="dept_in_charge_name.signature_image",string='Department In-Charge Sign',readonly=True)
|
||||
dept_in_charge_approved_on = fields.Datetime(string="Approved On")
|
||||
top_management_name = fields.Many2one('res.users', string='Top Management Approver')
|
||||
top_management_approval_image = fields.Image(related="top_management_name.signature_image",string='Top Management Approval',readonly=True)
|
||||
top_management_approved_on = fields.Datetime(string="Approved On")
|
||||
status = fields.Selection([('open', 'Open'),('close', 'Closed')], default='open' , string="Status")
|
||||
|
||||
def action_top_esign_btn(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
subject = f"PRF Approved - {self.prf_no}"
|
||||
body_html = f"""
|
||||
<p>Below <b>PRF</b> got approved</p>
|
||||
"""
|
||||
sequence_util.send_direct_email(self.env,"sos_prf",self.id,"praveenkumar.m@sosaley.com",subject,body_html)
|
||||
sequence_util.action_assign_signature(
|
||||
self,
|
||||
'top_management_name',
|
||||
'top_management_approved_on',
|
||||
'sos_inventory.sos_management_user'
|
||||
)
|
||||
def action_dept_esign_btn(self):
|
||||
# Email part
|
||||
body_html = f"""
|
||||
<p>Below <b>PRF</b> is waiting for your Approval</p>
|
||||
"""
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
subject = f"PRF Approval Request - {self.prf_no}"
|
||||
sequence_util.send_direct_email(self.env,"sos_prf",self.id,"ramachandran.r@sosaley.com",subject,body_html)
|
||||
# Email part ends
|
||||
sequence_util.action_assign_signature(
|
||||
self,
|
||||
'dept_in_charge_name',
|
||||
'dept_in_charge_approved_on',
|
||||
'sos_inventory.sos_scg_group_manager'
|
||||
)
|
||||
def action_stores_esign_btn(self):
|
||||
# Email part
|
||||
body_html = f"""
|
||||
<p>Below <b>PRF</b> is waiting for your Approval</p>
|
||||
"""
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
sequence_util.send_group_email(self.env,'sos_prf',self.id,"deenalaura.m@sosaley.in","PRF Approval Request",body_html,'sos_inventory.sos_scg_group_manager')
|
||||
# Email part ends
|
||||
sequence_util.action_assign_signature(
|
||||
self,
|
||||
'requested_by_name',
|
||||
'requested_on',
|
||||
'sos_inventory.sos_scg_group_user'
|
||||
)
|
||||
def _generate_id(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.generate_sequence('sos_prf','PRF', 'prf_no')
|
||||
|
||||
class SOS_prf_Lines(models.Model):
|
||||
_name = 'sos_prf_lines'
|
||||
_description = 'Purchase Requisition Form Lines'
|
||||
|
||||
ref_id = fields.Many2one('sos_prf', string="PRF", ondelete="cascade")
|
||||
com_type = fields.Selection([('exits', 'In-stock'),('new', 'New')], string="Availability", default='exits')
|
||||
component_id = fields.Many2one('sos_material', string="Material Name")
|
||||
new_component_id = fields.Char(string="New Part No")
|
||||
qty = fields.Integer(string="Required Qty")
|
||||
req_date = fields.Date(string="Required Date")
|
||||
mon_ref_no = fields.Many2one('sos_mon',string="MON Ref No")
|
||||
|
|
@ -68,35 +68,35 @@ class SOS_Quote_Generation(models.Model):
|
|||
|
||||
supplier_dict = {}
|
||||
for record in self.line_ids:
|
||||
if record.supplier1_name:
|
||||
supplier = record.supplier1_name
|
||||
if record.final_supplier1_name:
|
||||
supplier = record.final_supplier1_name
|
||||
if supplier not in supplier_dict:
|
||||
supplier_dict[supplier] = []
|
||||
supplier_dict[supplier].append({
|
||||
'name': record.material_name,
|
||||
'product_qty': record.supplier1_qty,
|
||||
'price_unit': record.supplier1_quoted_price
|
||||
'product_qty': record.final_supplier1_qty,
|
||||
'price_unit': record.final_supplier1_quoted_price
|
||||
})
|
||||
|
||||
if record.supplier2_name:
|
||||
supplier = record.supplier2_name
|
||||
if supplier not in supplier_dict:
|
||||
supplier_dict[supplier] = []
|
||||
supplier_dict[supplier].append({
|
||||
'name': record.material_name,
|
||||
'product_qty': record.supplier2_qty,
|
||||
'price_unit': record.supplier2_quoted_price
|
||||
})
|
||||
# if record.supplier2_name:
|
||||
# supplier = record.supplier2_name
|
||||
# if supplier not in supplier_dict:
|
||||
# supplier_dict[supplier] = []
|
||||
# supplier_dict[supplier].append({
|
||||
# 'name': record.material_name,
|
||||
# 'product_qty': record.supplier2_qty,
|
||||
# 'price_unit': record.supplier2_quoted_price
|
||||
# })
|
||||
|
||||
if record.supplier3_name:
|
||||
supplier = record.supplier3_name
|
||||
if supplier not in supplier_dict:
|
||||
supplier_dict[supplier] = []
|
||||
supplier_dict[supplier].append({
|
||||
'name': record.material_name,
|
||||
'product_qty': record.supplier3_qty,
|
||||
'price_unit': record.supplier3_quoted_price
|
||||
})
|
||||
# if record.supplier3_name:
|
||||
# supplier = record.supplier3_name
|
||||
# if supplier not in supplier_dict:
|
||||
# supplier_dict[supplier] = []
|
||||
# supplier_dict[supplier].append({
|
||||
# 'name': record.material_name,
|
||||
# 'product_qty': record.supplier3_qty,
|
||||
# 'price_unit': record.supplier3_quoted_price
|
||||
# })
|
||||
for x, y in supplier_dict.items():
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
po_no = sequence_util.generate_sequence('sos_po','PO', 'po_no')
|
||||
|
|
@ -111,6 +111,7 @@ class SOS_Quote_Generation(models.Model):
|
|||
'quantity': components['product_qty'],'unit_price': components['price_unit'], 'total_price': components['product_qty'] * components['price_unit']
|
||||
})
|
||||
message = 'Purchase Order(s) successfully generated.'
|
||||
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class SOS_SalesOrder(models.Model):
|
|||
string="Product Name",required=True)
|
||||
line_ids = fields.One2many('sos_sales_order_line', 'ref_id',copy=True)
|
||||
customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name")
|
||||
customer_location = fields.Char(string="Customer Location")
|
||||
lead_time = fields.Datetime(string="Lead Time")
|
||||
customer_po_no = fields.Char(string="PO No")
|
||||
customer_po_date = fields.Datetime(string="PO Date")
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class Sequence_Generator(models.AbstractModel):
|
|||
reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)])
|
||||
# email_to = reporting_user.login
|
||||
else:
|
||||
# email_to = "ramachandran.r@sosaley.in"
|
||||
# email_to = "ramachandran.r@sosaley.com"
|
||||
print("test")
|
||||
mail_values = {
|
||||
'subject': subject,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,17 @@ class SOS_Service_Call_Log_Report(models.Model):
|
|||
action_taken = fields.Text(string="Action taken or required action to be taken")
|
||||
Date_of_action_Completed = fields.Datetime(string="Date of action completed")
|
||||
status = fields.Selection([('open', 'Open'),('close', 'Closed')], default='open' , string="Status")
|
||||
|
||||
dock_audit_ref_no = fields.Many2one('sos_dock_audit',string="Dock Audit Ref No")
|
||||
warranty = fields.Integer(string="Warranty(In Months)")
|
||||
invoice_no = fields.Char(string="Invoice No")
|
||||
invoice_date = fields.Date(string="Invoice Date")
|
||||
|
||||
@api.onchange('dock_audit_ref_no')
|
||||
def _onchange_dock_audit_ref_no(self):
|
||||
if self.dock_audit_ref_no:
|
||||
self.warranty = self.dock_audit_ref_no.warranty
|
||||
self.invoice_no = self.dock_audit_ref_no.invoice_no
|
||||
self.invoice_date = self.dock_audit_ref_no.invoice_date
|
||||
def _generate_id(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.generate_sequence('sos_service_call_log_report','SCLR', 'ref_no')
|
||||
|
|
@ -111,6 +111,6 @@ class SOS_SFG_Line(models.Model):
|
|||
ir_no = fields.Many2one('sos_ir', string="Material Inward Ref No")
|
||||
min_no = fields.Many2one('sos_min', string="Material Issue Ref No")
|
||||
mrn_no = fields.Many2one('sos_mrn', string="Material Return Ref No")
|
||||
iqi_no = fields.Many2one('sos_iqi', string="In-house Inspection Ref No")
|
||||
iqi_no = fields.Many2one('sos_iqi', string="IQI Ref No")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ class sos_Outsourcing_Return(models.Model):
|
|||
material_name = fields.Many2one('sos_material',string="Material Name",related="iqi_no.material_name")
|
||||
returned_qty = fields.Integer(string="Returned Quantity",related="iqi_no.rejected_qty")
|
||||
remarks = fields.Text(string="Remarks")
|
||||
rework_type = fields.Selection([
|
||||
('outsourcing', 'Out-Sourcing'),
|
||||
('inhouse', 'In-House')
|
||||
], string='Rework Type',default="outsourcing",copy=True)
|
||||
def _generate_id(self):
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.generate_sequence('sos_sfg_outsourcing_return_register','ORR', 'orr_no')
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class sos__wo(models.Model):
|
|||
"""
|
||||
subject = f"Work Order Approval Request - {self.wo_no}"
|
||||
send_email = self.env['sos_common_scripts']
|
||||
send_email.send_direct_email(self.env,"sos_wo",self.id,"ramachandran.r@sosaley.in",subject,body_html)
|
||||
send_email.send_direct_email(self.env,"sos_wo",self.id,"ramachandran.r@sosaley.com",subject,body_html)
|
||||
# Email part ends
|
||||
sequence_util = self.env['sos_common_scripts']
|
||||
return sequence_util.action_assign_signature(
|
||||
|
|
|
|||
|
|
@ -9,269 +9,296 @@
|
|||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<template id="labels_print">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="web.basic_layout">
|
||||
<!-- Include Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"/>
|
||||
<template id="labels_print">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="web.basic_layout">
|
||||
|
||||
<style>
|
||||
/* Reset default margins and ensure full-page layout */
|
||||
.page {
|
||||
margin: 3mm; /* Reduced margins */
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden; /* Prevent content from overflowing */
|
||||
}
|
||||
<style type="text/css">
|
||||
|
||||
/* Container for each set of tables (FG, SFG, Materials) */
|
||||
.label-set {
|
||||
page-break-inside: avoid; /* Try to keep the entire set on one page */
|
||||
page-break-after: always; /* Force a page break after each set */
|
||||
}
|
||||
/* Avoid clipping; wkhtmltopdf + overflow hidden can break pagination */
|
||||
.page {
|
||||
margin: 3mm;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Ensure tables stay within their column */
|
||||
.table-container {
|
||||
width: 100%; /* Full width of the column */
|
||||
page-break-inside: avoid; /* Prevent table from splitting across pages */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* Keep each whole set on one page when possible */
|
||||
.label-set {
|
||||
page-break-inside: avoid !important;
|
||||
break-inside: avoid !important;
|
||||
page-break-after: always; /* one set per page; remove if not desired */
|
||||
}
|
||||
|
||||
/* Clearfix for the last table if odd number of tables */
|
||||
.label-set::after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
/* Pair wrapper: keep both columns together */
|
||||
.pair-block,
|
||||
.row,
|
||||
.col-6,
|
||||
.table-container,
|
||||
.label-table,
|
||||
.label-table tr,
|
||||
.label-table td {
|
||||
page-break-inside: avoid !important;
|
||||
break-inside: avoid !important;
|
||||
}
|
||||
|
||||
/* Compact table styling */
|
||||
.label-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
/* Replace Bootstrap flex with inline-block for PDF reliability */
|
||||
.row {
|
||||
display: block !important;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
.col-6 {
|
||||
display: inline-block !important;
|
||||
vertical-align: top;
|
||||
width: 49.8%;
|
||||
box-sizing: border-box;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.label-table td {
|
||||
font-size: 15px; /* Smaller font size for compactness */
|
||||
padding: 2mm; /* Reduced padding */
|
||||
border: 1px solid #000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* Table layout and text wrapping for long content */
|
||||
.table-container { width: 100%; box-sizing: border-box; }
|
||||
.label-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed; /* keep widths predictable */
|
||||
}
|
||||
.label-table td {
|
||||
font-size: 15px;
|
||||
padding: 2mm;
|
||||
border: 1px solid #000;
|
||||
box-sizing: border-box;
|
||||
white-space: normal; /* allow wrapping */
|
||||
word-wrap: break-word;
|
||||
word-break: break-word; /* break long tokens */
|
||||
}
|
||||
.label-table .column {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.label-table .column {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
width:20%
|
||||
}
|
||||
.empty-col { font-size: 10px; text-align: center; padding: 2mm; }
|
||||
|
||||
/* Adjust Bootstrap row margins for PDF */
|
||||
.row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom:40px;
|
||||
}
|
||||
/* Vendor-ish safety (wkhtmltopdf is WebKit) */
|
||||
@media print {
|
||||
.pair-block, .row, .col-6, .table-container, .label-table, .label-table tr, .label-table td {
|
||||
-webkit-region-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
/* Adjust Bootstrap column padding for PDF */
|
||||
[class*="col-"] {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
<div class="page">
|
||||
<t t-set="counter" t-value="0"/>
|
||||
<t t-foreach="range(o.master_quantity)" t-as="line_items">
|
||||
<t t-set="counter" t-value="counter + 1"/>
|
||||
|
||||
/* Style for empty column placeholder */
|
||||
.empty-col {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
padding: 2mm;
|
||||
}
|
||||
</style>
|
||||
<div class="label-set">
|
||||
|
||||
<div class="page">
|
||||
|
||||
<!-- Build a single list with: (category_id, record, index) -->
|
||||
<t t-set="all_tables" t-value="[]"/>
|
||||
|
||||
<t t-set="counter" t-value="0"/>
|
||||
<t t-foreach="range(o.master_quantity)" t-as="line_items">
|
||||
<t t-set="counter" t-value="counter + 1"/>
|
||||
<div class="label-set">
|
||||
<!-- Combine all tables into a single list -->
|
||||
<t t-set="all_tables" t-value="[]"/>
|
||||
<!-- Add FG tables -->
|
||||
<t t-set="fg_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_fg or []" t-as="fg_item">
|
||||
<t t-set="fg_counter" t-value="fg_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(1, fg_item, fg_counter)]"/>
|
||||
</t>
|
||||
<!-- Add SFG tables -->
|
||||
<t t-set="sfg_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_sfg or []" t-as="sfg_item">
|
||||
<t t-set="sfg_counter" t-value="sfg_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(2, sfg_item, sfg_counter)]"/>
|
||||
</t>
|
||||
<!-- Add Materials tables -->
|
||||
<t t-set="material_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_material or []" t-as="material_item">
|
||||
<t t-set="material_counter" t-value="material_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(3, material_item, material_counter)]"/>
|
||||
</t>
|
||||
<!-- Add Installation Kit tables -->
|
||||
<t t-set="installation_kit_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_installation_kit or []" t-as="installation_kit_item">
|
||||
<t t-set="installation_kit_counter" t-value="installation_kit_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(4, installation_kit_item, installation_kit_counter)]"/>
|
||||
</t>
|
||||
<!-- Add Miscelleneous tables -->
|
||||
<t t-set="miscellaneous_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_miscellaneous or []" t-as="miscellaneous_item">
|
||||
<t t-set="miscellaneous_counter" t-value="miscellaneous_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(5, miscellaneous_item, miscellaneous_counter)]"/>
|
||||
</t>
|
||||
<!-- FG -->
|
||||
<t t-set="fg_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_fg or []" t-as="fg_item">
|
||||
<t t-set="fg_counter" t-value="fg_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(1, fg_item, fg_counter)]"/>
|
||||
</t>
|
||||
|
||||
<!-- SFG -->
|
||||
<t t-set="sfg_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_sfg or []" t-as="sfg_item">
|
||||
<t t-set="sfg_counter" t-value="sfg_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(2, sfg_item, sfg_counter)]"/>
|
||||
</t>
|
||||
|
||||
|
||||
<!-- Materials -->
|
||||
<t t-set="material_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_material or []" t-as="material_item">
|
||||
<t t-set="material_counter" t-value="material_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(3, material_item, material_counter)]"/>
|
||||
</t>
|
||||
|
||||
<!-- Process all tables in pairs -->
|
||||
<t t-foreach="range(0, len(all_tables), 2)" t-as="pair_index">
|
||||
<div class="row">
|
||||
<!-- First table in the pair -->
|
||||
<!-- Installation Kit -->
|
||||
<t t-set="installation_kit_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_installation_kit or []" t-as="installation_kit_item">
|
||||
<t t-set="installation_kit_counter" t-value="installation_kit_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(4, installation_kit_item, installation_kit_counter)]"/>
|
||||
</t>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<t t-set="miscellaneous_counter" t-value="0"/>
|
||||
<t t-foreach="o.line_ids_miscellaneous or []" t-as="miscellaneous_item">
|
||||
<t t-set="miscellaneous_counter" t-value="miscellaneous_counter + 1"/>
|
||||
<t t-set="all_tables" t-value="all_tables + [(5, miscellaneous_item, miscellaneous_counter)]"/>
|
||||
</t>
|
||||
|
||||
<!-- Render in pairs -->
|
||||
<t t-foreach="range(0, len(all_tables), 2)" t-as="pair_index">
|
||||
<div class="pair-block">
|
||||
<div class="row">
|
||||
<!-- Left column -->
|
||||
<div class="col-6">
|
||||
<t t-set="table_info" t-value="all_tables[pair_index]"/>
|
||||
<t t-set="table_info" t-value="all_tables[pair_index]"/>
|
||||
<t t-set="category" t-value="table_info[0]"/>
|
||||
<t t-set="item" t-value="table_info[1]"/>
|
||||
<t t-set="index" t-value="table_info[2]"/>
|
||||
|
||||
<div class="table-container">
|
||||
<table class="label-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="column">Set No</td>
|
||||
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Battery</td>
|
||||
<td><t t-esc="o.batter_or_cells"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">No</td>
|
||||
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Name</td>
|
||||
<td>
|
||||
<t t-if="'component_id' in item._fields">
|
||||
<t t-esc="item.component_id.name or item.component_id.part_no or item.name or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.name or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">UOM</td>
|
||||
<td>
|
||||
<t t-if="'uom' in item._fields">
|
||||
<t t-esc="item.uom or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Qty</td>
|
||||
<td>
|
||||
<t t-if="category == 5">
|
||||
<t t-esc="(item.quantity or 0) // (o.master_quantity or 1)"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="'singet_set_qty' in item._fields">
|
||||
<t t-esc="item.singet_set_qty or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.quantity or 'N/A'"/>
|
||||
</t>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="column">S.No</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right column -->
|
||||
<div class="col-6">
|
||||
<t t-if="pair_index + 1 < len(all_tables)">
|
||||
<t t-set="table_info" t-value="all_tables[pair_index + 1]"/>
|
||||
<t t-set="category" t-value="table_info[0]"/>
|
||||
<t t-set="item" t-value="table_info[1]"/>
|
||||
<t t-set="index" t-value="table_info[2]"/>
|
||||
|
||||
<div class="table-container">
|
||||
<table class="label-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="column">Set No</td>
|
||||
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Battery</td>
|
||||
<td><t t-esc="o.batter_or_cells"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">No</td>
|
||||
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Name</td>
|
||||
<td>
|
||||
<t t-if="'component_id' in item">
|
||||
<t t-esc="item.component_id.name or item.component_id.part_no or item.name or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.name or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">UOM</td>
|
||||
<td>
|
||||
<t t-if="'uom' in item">
|
||||
<t t-esc="item.uom or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Qty</td>
|
||||
<td>
|
||||
<t t-if="'singet_set_qty' in item">
|
||||
<t t-esc="item.singet_set_qty or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.quantity or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="column">S.No</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second table in the pair (if exists) -->
|
||||
<div class="col-6">
|
||||
<t t-if="pair_index + 1 < len(all_tables)">
|
||||
<t t-set="table_info" t-value="all_tables[pair_index + 1]"/>
|
||||
<t t-set="category" t-value="table_info[0]"/>
|
||||
<t t-set="item" t-value="table_info[1]"/>
|
||||
<t t-set="index" t-value="table_info[2]"/>
|
||||
<div class="table-container">
|
||||
<table class="label-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="column">Set No</td>
|
||||
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Battery</td>
|
||||
<td><t t-esc="o.batter_or_cells"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">No</td>
|
||||
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Name</td>
|
||||
<td>
|
||||
<t t-if="'component_id' in item">
|
||||
<t t-esc="item.component_id.name or item.component_id.part_no or item.name or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.name or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">UOM</td>
|
||||
<td>
|
||||
<t t-if="'uom' in item">
|
||||
<t t-esc="item.uom or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Qty</td>
|
||||
<td>
|
||||
<t t-if="'singet_set_qty' in item">
|
||||
<t t-esc="item.singet_set_qty or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.quantity or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">S.No</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="empty-col"></div>
|
||||
</t>
|
||||
</div>
|
||||
</div> <!-- Close row -->
|
||||
</t>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="label-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="column">Set No</td>
|
||||
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Battery</td>
|
||||
<td><t t-esc="o.batter_or_cells"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">No</td>
|
||||
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Name</td>
|
||||
<td>
|
||||
<t t-if="'component_id' in item._fields">
|
||||
<t t-if="category in [3, 4]">
|
||||
<t t-esc="item.component_id.part_no or item.name or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.component_id.name or item.name or 'N/A'"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.name or 'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="column">UOM</td>
|
||||
<td>
|
||||
<t t-if="'uom' in item._fields">
|
||||
<t t-esc="item.uom or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="'N/A'"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="column">Qty</td>
|
||||
<td>
|
||||
<t t-if="category == 5">
|
||||
<t t-esc="(item.quantity or 0) // (o.master_quantity or 1)"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="'singet_set_qty' in item._fields">
|
||||
<t t-esc="item.singet_set_qty or 'N/A'"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="item.quantity or 'N/A'"/>
|
||||
</t>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="column">S.No</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="empty-col"></div>
|
||||
</t>
|
||||
</div>
|
||||
</div> <!-- /row -->
|
||||
</div> <!-- /pair-block -->
|
||||
</t>
|
||||
</div> <!-- /label-set -->
|
||||
</t>
|
||||
</div> <!-- /page -->
|
||||
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<odoo>
|
||||
<record id="action_material_budget_summary" model="ir.actions.report">
|
||||
<field name="name">Material Budget Summary</field>
|
||||
<field name="model">sos_budget_plan</field> <!-- Adjust model if needed -->
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">sos_inventory.report_material_budget_summary</field>
|
||||
<field name="print_report_name">Material_Budget_Summary</field>
|
||||
</record>
|
||||
<template id="report_material_budget_summary">
|
||||
<t t-call="web.basic_layout">
|
||||
<t t-call="web.html_container">
|
||||
<style>
|
||||
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; color: #1f2937; }
|
||||
.page { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
.header { border-bottom: 2px solid #e5e7eb; padding-bottom: 16px; margin-bottom: 24px; }
|
||||
.header h3 { font-size: 24px; font-weight: 700; margin: 0; color: #1e40af; }
|
||||
.header .info { font-size: 14px; color: #4b5563; margin-top: 8px; }
|
||||
.header .info strong { font-weight: 600; }
|
||||
.section-title { font-size: 18px; font-weight: 600; color: #1e40af; margin: 24px 0 12px; }
|
||||
.count { font-size: 14px; color: #4b5563; margin-bottom: 8px; }
|
||||
.table-custom { width: 100%; border-collapse: separate; border-spacing: 0; background-color: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 8px; overflow: hidden; }
|
||||
.table-custom th { background-color: #e4e0f9; color: #1e40af; font-weight: 600; padding: 12px; text-align: left; border-bottom: 1px solid #d1d5db; }
|
||||
.table-custom td { padding: 12px; border-bottom: 1px solid #e5e7eb; }
|
||||
.table-custom tr:last-child td { border-bottom: none; }
|
||||
.table-custom th.center, .table-custom td.center { text-align: center; }
|
||||
.no-data { text-align: center; color: #6b7280; padding: 16px; font-style: italic; }
|
||||
.total-cost{
|
||||
display:flex; justify-content:flex-end; align-items:center; gap:8px;
|
||||
padding:8px 10px; margin:10px 0 6px;
|
||||
background:#fff; border:1px solid #e5e7eb; border-radius:8px;
|
||||
font-size:14px;
|
||||
}
|
||||
.total-cost .label{ color:#4b5563; }
|
||||
.total-cost .amount{ font-weight:700; font-size:16px; }
|
||||
</style>
|
||||
<div class="page">
|
||||
<div class="header">
|
||||
<h3>Budget Summary</h3>
|
||||
<div class="info">
|
||||
<strong>Name:</strong> <t t-esc="fg_name or '—'"/>
|
||||
| <strong>Planned Quantity:</strong> <t t-esc="total_quantity or '—'"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Material Quantities Table -->
|
||||
<h4 class="section-title">Materials to Purchase</h4>
|
||||
<div class="count">Total Materials: <t t-esc="len(materials)"/></div>
|
||||
<div class="total-cost">
|
||||
<span class="label">Estimated Purchase Cost:</span>
|
||||
<span class="amount">
|
||||
<t t-esc="currency_symbol"/> <t t-esc="'{:,.2f}'.format(total_cost)"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<table class="table-custom">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Material Name</th>
|
||||
<th class="center">Needed Qty</th>
|
||||
<th class="center">In-Hand Qty</th>
|
||||
<th class="center">Actual Needed Qty</th>
|
||||
<th class="center">Standard Packing Qty</th>
|
||||
<th class="center">To Purchase</th>
|
||||
<th class="center">cost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-if="materials">
|
||||
<t t-foreach="materials" t-as="material">
|
||||
<tr>
|
||||
<td><t t-esc="material['material_name']"/></td>
|
||||
<td class="center"><t t-esc="material['needed_quantity']"/></td>
|
||||
<td class="center"><t t-esc="material['inhand_quantity']"/></td>
|
||||
<td class="center"><t t-esc="material['actual_needed']"/></td>
|
||||
<td class="center"><t t-esc="material['std_packing_qty']"/></td>
|
||||
<td class="center"><t t-esc="material['to_purchase']"/></td>
|
||||
<td class="center"><t t-esc="material['cost']"/></td>
|
||||
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="not materials or len(materials) == 0">
|
||||
<tr><td colspan="4" class="no-data">No materials need to be purchased.</td></tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
|
|
@ -72,14 +72,16 @@
|
|||
<table class="table table-bordered">
|
||||
<tbody>
|
||||
<t t-if="o.material_option == True">
|
||||
<tr style="background-color:#ccc"><td class="column" colspan="6">Materials</td></tr>
|
||||
<tr style="background-color:#ccc"><td class="column" colspan="7">Materials</td></tr>
|
||||
<tr class="column">
|
||||
<td>S.No</td>
|
||||
<td class="column">Material Code</td>
|
||||
<td class="column">Name</td>
|
||||
<td class="column">Location</td>
|
||||
<td class="column">In-Hand Quantity</td>
|
||||
<td class="column">Requested Quantity</td>
|
||||
<td class="column">Given Quantity</td>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
|
|
@ -95,6 +97,9 @@
|
|||
<td><t t-esc="line_items.new_component_id"/></td>
|
||||
</t>
|
||||
<t t-if="line_items.com_type == 'exits'">
|
||||
<td><t t-esc="line_items.location"/></td>
|
||||
</t>
|
||||
<t t-if="line_items.com_type == 'exits'">
|
||||
<td><t t-esc="line_items.inhand_stock_qty"/></td>
|
||||
</t>
|
||||
<t t-if="line_items.com_type == 'new'">
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ access_ir_act_window_healthcare_user,Access Action Window for Health Care Users,
|
|||
access_ir_act_window_sos_inside_sales_user,Access Action Window for Inside sales Users,base.model_ir_actions_act_window,sos_inventory.sos_inside_sales_user,1,0,0,0
|
||||
access_ir_act_window_hr_user,Access Action Window for Human Care Resources Users,base.model_ir_actions_act_window,sos_inventory.sos_hr_user,1,0,0,0
|
||||
access_ir_act_window_sos_marketing_user,Access Action Window for Marketing Users,base.model_ir_actions_act_window,sos_inventory.sos_marketing_user,1,0,0,0
|
||||
access_ir_act_window_sos_sales_reviewer,Access Action Window for Sales Reviewer,base.model_ir_actions_act_window,sos_inventory.sos_sales_reviewer,1,0,0,0
|
||||
access_ir_act_window_finance_head_user,Access Action Window for Finance Head,base.model_ir_actions_act_window,sos_inventory.sos_finance_head_user,1,0,0,0
|
||||
access_ir_act_window_sales_sapl_user,Access Action Window for Sales SAPL Users,base.model_ir_actions_act_window,sos_inventory.sos_sales_sapl_user,1,0,0,0
|
||||
access_sos_return_fir,sos_return_fir access,model_sos_return_fir,base.group_user,1,1,1,1
|
||||
access_sos_return_fir_line,sos_return_fir_line access,model_sos_return_fir_line,base.group_user,1,1,1,1
|
||||
access_sos_return_calibration_devices_fir,sos_return_calibration_devices_fir access,model_sos_return_calibration_devices_fir,base.group_user,1,1,1,1
|
||||
|
|
@ -182,6 +185,7 @@ access_sos_transfer_challan_specification_lines,sos_transfer_challan_specificati
|
|||
access_sos_fir_serial_no_lines,sos_fir_serial_no_lines access,model_sos_fir_serial_no_lines,base.group_user,1,1,1,1
|
||||
access_sos_miscellaneous_deliverables,sos_miscellaneous_deliverables access,model_sos_miscellaneous_deliverables,base.group_user,1,1,1,1
|
||||
access_sos_mat_outsourcing_vendor_register,sos_mat_outsourcing_vendor_register access,model_sos_mat_outsourcing_vendor_register,base.group_user,1,1,1,1
|
||||
access_sos_mat_outsourcing_vendor_register_lines,sos_mat_outsourcing_vendor_register_lines access,model_sos_mat_outsourcing_vendor_register_lines,base.group_user,1,1,1,1
|
||||
access_stock_movement_report_wizard,stock_movement_report_wizard access,model_stock_movement_report_wizard,base.group_user,1,1,1,1
|
||||
access_sos_inventory_customers,sos_inventory_customers access,model_sos_inventory_customers,base.group_user,1,1,1,1
|
||||
access_sos_master_list_customer,sos_master_list_customer access,model_sos_master_list_customer,base.group_user,1,1,1,1
|
||||
|
|
@ -197,5 +201,11 @@ access_sos_parameter_fir,sos_parameter_fir access,model_sos_parameter_fir,base.g
|
|||
access_sos_transfer_challan_return_from_customer_lines,sos_transfer_challan_return_from_customer_lines access,model_sos_transfer_challan_return_from_customer_lines,base.group_user,1,1,1,1
|
||||
access_sos_transfer_challan_return_from_customer,sos_transfer_challan_return_from_customer access,model_sos_transfer_challan_return_from_customer,base.group_user,1,1,1,1
|
||||
access_sos_shelflife_register,sos_shelflife_register access,model_sos_shelflife_register,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_sos_budget_plan,sos_budget_plan access,model_sos_budget_plan,base.group_user,1,1,1,1
|
||||
access_sos_prf,sos_prf access,model_sos_prf,base.group_user,1,1,1,1
|
||||
access_sos_prf_lines,sos_prf_lines access,model_sos_prf_lines,base.group_user,1,1,1,1
|
||||
access_sos_departments_user_lines,sos_departments_user_lines access,model_sos_departments_user_lines,base.group_user,1,1,1,1
|
||||
access_sos_ncmr_problem_description_line,access_sos_ncmr_problem_description_line access,model_sos_ncmr_problem_description_line,base.group_user,1,1,1,1
|
||||
access_sos_ccrf_capa_line,access_sos_ccrf_capa_line access,model_sos_ccrf_capa_line,base.group_user,1,1,1,1
|
||||
access_sos_ccrf_team_formation_line,access_sos_ccrf_team_formation_line access,model_sos_ccrf_team_formation_line,base.group_user,1,1,1,1
|
||||
access_sos_ccrf_problem_description_line,access_sos_ccrf_problem_description_line access,model_sos_ccrf_problem_description_line,base.group_user,1,1,1,1
|
||||
|
|
|
@ -152,5 +152,25 @@
|
|||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="sos_mon_ce_team_rule" model="ir.rule">
|
||||
<field name="name">MON: CE Team View CE Records</field>
|
||||
<field name="model_id" ref="model_sos_mon"/>
|
||||
<field name="domain_force">[('is_ce_user_created', '=', True)]</field>
|
||||
<field name="groups" eval="[(4, ref('sos_inventory.sos_ce_user'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
<record id="sos_mrn_ce_team_rule" model="ir.rule">
|
||||
<field name="name">MRN: CE Team View CE Records</field>
|
||||
<field name="model_id" ref="model_sos_mrn"/>
|
||||
<field name="domain_force">[('is_ce_user_created', '=', True)]</field>
|
||||
<field name="groups" eval="[(4, ref('sos_inventory.sos_ce_user'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@
|
|||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
<!-- Finance Head Group -->
|
||||
<record id="sos_finance_head_user" model="res.groups">
|
||||
<field name="name">Finance Head</field>
|
||||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
<!-- Logistics Group -->
|
||||
<record id="sos_logistics_user" model="res.groups">
|
||||
<field name="name">Logistics User</field>
|
||||
|
|
@ -97,7 +103,7 @@
|
|||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
<!-- Finance Group -->
|
||||
<!-- Haelthcare Group -->
|
||||
<record id="sos_healthcare_user" model="res.groups">
|
||||
<field name="name">Healthcare User</field>
|
||||
<field name="category_id"
|
||||
|
|
@ -121,6 +127,17 @@
|
|||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
|
||||
<!-- Sales/Inside Reviewer -->
|
||||
<record id="sos_sales_reviewer" model="res.groups">
|
||||
<field name="name">Sales Reviewer</field>
|
||||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
<!-- Sales/Inside Reviewer -->
|
||||
<record id="sos_sales_sapl_user" model="res.groups">
|
||||
<field name="name">Sales SAPL</field>
|
||||
<field name="category_id"
|
||||
ref="sos_inventory.module_category_sos_inventory"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@ body{
|
|||
font-size: 15px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.modal.o_technical_modal .modal-content .modal-header .modal-title {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #fff;
|
||||
}
|
||||
.btn-primary {
|
||||
color: #FFFFFF;
|
||||
background-color: #71639e !important;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,344 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Component, onWillStart, useRef, onMounted } from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
export class ParetoChartWidget extends Component {
|
||||
|
||||
static template = "sos_inventory.ParetoChartWidget";
|
||||
|
||||
setup() {
|
||||
this.orm = useService("orm");
|
||||
this.action = useService("action");
|
||||
this.chartRef = useRef("paretoChart");
|
||||
this.startDateRef = useRef("startDate");
|
||||
this.endDateRef = useRef("endDate");
|
||||
this.noDataMessageRef = useRef("endDate");
|
||||
this.goodsTypeRef = useRef("goodsType");
|
||||
this.categoryRef = useRef("category");
|
||||
this.servicesupplierRef = useRef("servicesupplier");
|
||||
|
||||
this.chartInstance = null; // Track chart instance
|
||||
|
||||
// 👉 Pre-fill start & end date when component is mounted
|
||||
onMounted(() => {
|
||||
|
||||
const today = new Date();
|
||||
// First and last day of the month
|
||||
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
this.startDateRef.el.value = formatDate(firstDay);
|
||||
this.endDateRef.el.value = formatDate(lastDay);
|
||||
|
||||
//this.onGoodsTypeChange();
|
||||
//this.onServiceSupplierChange();
|
||||
this.loadData();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async onServiceSupplierChange() {
|
||||
const goods_type = this.goodsTypeRef.el.value;
|
||||
const servicesupplierSelect = this.servicesupplierRef.el;
|
||||
const startDate = this.startDateRef.el.value || false;
|
||||
const endDate = this.endDateRef.el.value || false;
|
||||
//alert(selectedGoodsType+" FFFF :::: "+categorySelect);
|
||||
// Clear existing options
|
||||
servicesupplierSelect.innerHTML = '';//last 12.16 22/08/2025
|
||||
const defaultOption = document.createElement('option');
|
||||
defaultOption.text = 'Select Supplier/Service';
|
||||
defaultOption.disabled = true;
|
||||
defaultOption.selected = true;
|
||||
servicesupplierSelect.appendChild(defaultOption);
|
||||
//alert(" selectedGoodsType :::: "+selectedGoodsType);
|
||||
|
||||
if (goods_type != "FG"){
|
||||
try {
|
||||
// Call backend route to get categories by goodsType
|
||||
const categories = await this.orm.call('sos_ncmr', 'get_service_suppliers_by_goods_type', [goods_type, startDate, endDate]);
|
||||
if (!categories.length) {
|
||||
servicesupplierSelect.innerHTML = '';
|
||||
const option = document.createElement('option');
|
||||
option.text = 'No Data Found';
|
||||
option.disabled = true;
|
||||
servicesupplierSelect.appendChild(option);
|
||||
} else {
|
||||
servicesupplierSelect.innerHTML = '';
|
||||
categories.forEach(cat => {
|
||||
const option = document.createElement('option');
|
||||
option.text = cat.supplier_name;
|
||||
option.value = cat.id;
|
||||
servicesupplierSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch categories:', error);
|
||||
const option = document.createElement('option');
|
||||
option.text = 'Error loading categories';
|
||||
option.disabled = true;
|
||||
servicesupplierSelect.appendChild(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onGoodsTypeChange() {
|
||||
this.onServiceSupplierChange();
|
||||
const selectedGoodsType = this.goodsTypeRef.el.value;
|
||||
const categorySelect = this.categoryRef.el;
|
||||
categorySelect.innerHTML = '';
|
||||
const defaultOption = document.createElement('option');
|
||||
defaultOption.text = 'Select Category';
|
||||
defaultOption.disabled = true;
|
||||
defaultOption.selected = true;
|
||||
categorySelect.appendChild(defaultOption);
|
||||
|
||||
let categories = [];
|
||||
|
||||
if (selectedGoodsType == 'Material'){
|
||||
categories = [
|
||||
{'id': '', 'name': 'Select Category'},
|
||||
{'id': 'Active Components', 'name': 'Active Components'},
|
||||
{'id': 'Passive Components', 'name': 'Passive Components'},
|
||||
{'id': 'Fabrication', 'name': 'Fabrication'},
|
||||
{'id': 'Accessories', 'name': 'Accessories'},
|
||||
{'id': 'Cables & Connectors', 'name': 'Cables & Connectors'},
|
||||
{'id': 'Metal', 'name': 'Metal'},
|
||||
]
|
||||
}else if (selectedGoodsType == 'SFG'){
|
||||
categories = [
|
||||
{'id': '', 'name': 'Select Category'},
|
||||
{'id': 'pcba', 'name': 'PCB Board'},
|
||||
{'id': 'cables', 'name': 'Cables & Connectors'},
|
||||
{'id': 'others', 'name': 'Others'},
|
||||
]
|
||||
}else if (selectedGoodsType == 'FG'){
|
||||
categories = [
|
||||
{'id': '', 'name': 'Select Category'},
|
||||
{'id': 'Health Care', 'name': 'Health Care'},
|
||||
{'id': 'BHMS', 'name': 'BHMS'},
|
||||
{'id': 'LV-BMS', 'name': 'BMS-LV'},
|
||||
{'id': 'HV-BMS', 'name': 'BMS-HV'},
|
||||
{'id': 'SBMS', 'name': 'SBMS'},
|
||||
{'id': 'Motor Controller', 'name': 'Motor Controller'},
|
||||
]
|
||||
}
|
||||
|
||||
try {
|
||||
// Call backend route to get categories by goodsType
|
||||
if (!categories.length) {
|
||||
const option = document.createElement('option');
|
||||
option.text = 'No Categories Found';
|
||||
option.disabled = true;
|
||||
categorySelect.appendChild(option);
|
||||
} else {
|
||||
categorySelect.innerHTML = '';
|
||||
categories.forEach(cat => {
|
||||
const option = document.createElement('option');
|
||||
option.text = cat.name;
|
||||
option.value = cat.id;
|
||||
categorySelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch categories:', error);
|
||||
const option = document.createElement('option');
|
||||
option.text = 'Error loading categories';
|
||||
option.disabled = true;
|
||||
categorySelect.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
async onFilterClick() {
|
||||
await this.loadData();
|
||||
}
|
||||
|
||||
showNoDataMessage() {
|
||||
this.noDataMessageRef.el.style.display = "block";
|
||||
if (this.chartInstance) {
|
||||
this.chartInstance.destroy();
|
||||
this.chartInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
hideNoDataMessage() {
|
||||
this.noDataMessageRef.el.style.display = "none";
|
||||
}
|
||||
|
||||
async loadData() {
|
||||
|
||||
const startDate = this.startDateRef.el.value || false;
|
||||
const endDate = this.endDateRef.el.value || false;
|
||||
const goodstype = this.goodsTypeRef.el.value || false;
|
||||
const categoryId = this.categoryRef.el.value || false;
|
||||
const servicesupplier = this.servicesupplierRef.el.value || false;
|
||||
//alert(" categoryId :: "+categoryId);
|
||||
if (!startDate || !endDate) {
|
||||
// Optionally show a message or just return
|
||||
console.warn("Start and end date are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
const domain = [];
|
||||
if (startDate) domain.push(['date', '>=', startDate]);
|
||||
if (endDate) domain.push(['date', '<=', endDate]);
|
||||
|
||||
let records = [];
|
||||
|
||||
try {
|
||||
records = await this.orm.call("sos_ncmr", "get_pareto_data", [startDate, endDate, goodstype, categoryId, servicesupplier]); //, goodstype , categoryId
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch pareto data:", error);
|
||||
//this.showNoDataMessage();
|
||||
//return;
|
||||
}
|
||||
|
||||
// if (!records || records.length === 0) {
|
||||
// this.showNoDataMessage();
|
||||
// return;
|
||||
// }
|
||||
|
||||
//this.hideNoDataMessage();
|
||||
this.renderChart(records); // ✅ cleaner and reusable
|
||||
|
||||
// const records = await this.orm.searchRead("pareto.defect.report", [], [
|
||||
// "defect_name", "count", "individual_percent", "cumulative_percent"
|
||||
// ]);
|
||||
}
|
||||
|
||||
renderChart(records){
|
||||
|
||||
const labels = records.map(r => r.defect_name);
|
||||
const counts = records.map(r => r.count);
|
||||
const cumulative = records.map(r => r.cumulative_percent);
|
||||
|
||||
//const ctx = this.el.querySelector("#paretoChart").getContext("2d");
|
||||
|
||||
const threshold = 80;
|
||||
let thresholdLine = [];
|
||||
let thresholdReached = false;
|
||||
|
||||
for (let i = 0; i < cumulative.length; i++) {
|
||||
|
||||
if (!thresholdReached) {
|
||||
thresholdLine.push(threshold);
|
||||
|
||||
if (cumulative[i] >= threshold) {
|
||||
// Insert drop to bottom after this
|
||||
thresholdLine.push(0); // drop vertically
|
||||
thresholdLine.push(null); // stop the line
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ctx = this.chartRef.el.getContext("2d");
|
||||
|
||||
// Plugin to draw lines after bars
|
||||
const drawLinesLastPlugin = {
|
||||
id: 'drawLinesLast',
|
||||
afterDatasetsDraw(chart) {
|
||||
const ctx = chart.ctx;
|
||||
chart.data.datasets.forEach((dataset, index) => {
|
||||
if (dataset.type === 'line') {
|
||||
const meta = chart.getDatasetMeta(index);
|
||||
meta.controller.draw(ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ Destroy previous chart if exists
|
||||
if (this.chartInstance) {
|
||||
this.chartInstance.destroy();
|
||||
}
|
||||
|
||||
// ✅ Create new chart and store it
|
||||
this.chartInstance = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Defect Qty",
|
||||
data: counts,
|
||||
backgroundColor: "steelblue",
|
||||
yAxisID: 'y',
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
label: "Cumulative %",
|
||||
data: cumulative,
|
||||
type: "line",
|
||||
borderColor: "green",
|
||||
yAxisID: 'y1',
|
||||
tension: 0.4,
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
label: "80% Threshold",
|
||||
data: new Array(records.length).fill(80),
|
||||
//data: thresholdLine,
|
||||
type: "line",
|
||||
borderColor: "red",
|
||||
borderDash: [5, 5],
|
||||
pointRadius: 0,
|
||||
fill: false,
|
||||
yAxisID: 'y1',
|
||||
spanGaps: false,
|
||||
stepped: true,
|
||||
order: 3,
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: "bottom" },
|
||||
title: {
|
||||
display: true,
|
||||
text: "" //Pareto Chart - cables, Cables & Connectors
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
title: { display: true, text: 'Defect Count' },
|
||||
beginAtZero: true
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
position: 'right',
|
||||
title: { display: true, text: 'Percentage' },
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
max: 120,
|
||||
ticks: {
|
||||
callback: function (value) {
|
||||
return value + "%";
|
||||
}
|
||||
},
|
||||
grid: { drawOnChartArea: false }
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [drawLinesLastPlugin],
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//ParetoChartWidget.template = "sos_inventory.ParetoChartWidget";
|
||||
|
||||
registry.category("actions").add("pareto_chart_widget", ParetoChartWidget);
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates>
|
||||
<t t-name="sos_inventory.ParetoChartWidget">
|
||||
<!-- <div class="container mt-3">
|
||||
<canvas t-ref="paretoChart" id="paretoChart" width="100%" height="40"></canvas>
|
||||
</div> -->
|
||||
<div class="o_pareto_chart_container">
|
||||
<div class="o_date_filter_controls" style="margin-left:20px;">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label>Start Date:</label><br />
|
||||
<input type="date" t-ref="startDate" class="form-control" style="min-width: 150px;" />
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label>End Date:</label><br />
|
||||
<input type="date" t-ref="endDate" class="form-control" style="min-width: 150px;" />
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label>Goods Type:</label><br />
|
||||
<select t-ref="goodsType" t-on-change="onGoodsTypeChange" class="form-select" style="min-width: 150px;">
|
||||
<option selected="selected">Material</option>
|
||||
<option>SFG</option>
|
||||
<option>FG</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label>Category:</label><br />
|
||||
<select t-ref="category" class="form-select" style="min-width: 150px;">
|
||||
<option selected="selected" disabled="disabled">Select Category</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label>Supplier/Service:</label><br />
|
||||
<select t-ref="servicesupplier" class="form-select" style="min-width: 150px;">
|
||||
<option selected="selected" disabled="disabled">Select Supplier/Service</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-group" style="margin-top: 1.5rem;">
|
||||
<button t-on-click="onFilterClick" class="btn btn-primary">Graph</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Placeholder for No Data -->
|
||||
<div t-ref="noDataMessage" class="o_no_data_message" style="display: none; text-align: center; font-weight: bold; color: red; margin: 2rem;">
|
||||
No Data Available for Selected Dates
|
||||
</div>
|
||||
<!-- <button class="btn btn-primary o-default-button" style="display:none;">Ok</button> -->
|
||||
<canvas t-ref="paretoChart" id="paretoChart" width="1600" height="600"></canvas>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -46,10 +46,7 @@
|
|||
<menuitem id="mop_forms_menu_root"
|
||||
name="MOP FORMS"
|
||||
parent="forms_menu_root"/>
|
||||
<!-- CE Forms -->
|
||||
<menuitem id="ce_forms_menu_root"
|
||||
name="CE FORMS"
|
||||
parent="forms_menu_root"/>
|
||||
|
||||
<!-- End CE Forms -->
|
||||
<menuitem id="mme_forms_menu_root"
|
||||
name="MME FORMS"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<odoo>
|
||||
<record id="action_pareto_chart" model="ir.actions.client">
|
||||
<field name="name">Pareto Chart Analysis</field>
|
||||
<field name="tag">pareto_chart_widget</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="action_budget_plan_list" model="ir.actions.act_window">
|
||||
<field name="name">Budget Plan</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sos_budget_plan</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No Plan Found
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sos_budget_plan_view_tree" model="ir.ui.view">
|
||||
<field name="name">sos_budget_plan.view.tree</field>
|
||||
<field name="model">sos_budget_plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
|
||||
<field name="name"/>
|
||||
<field name="quantity"/>
|
||||
|
||||
<field name="write_uid" string="Last Edited By" optional="hide"/>
|
||||
<field name="write_date" string="Last Edited On" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="sos_budget_plan_form_view" model="ir.ui.view">
|
||||
<field name="name">Form</field>
|
||||
<field name="model">sos_budget_plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Budget Plan">
|
||||
<sheet>
|
||||
<h2 style="text-align: center;text-transform: uppercase;text-shadow: 1px 1p 1px #140718;color: #65407c;padding:5px;">Budget Plan</h2><hr></hr><br></br>
|
||||
<table class="table table" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;">
|
||||
<tr><td><group><field name="sfg_option"/></group></td>
|
||||
<td><group><field name="fg_option"/></group></td></tr>
|
||||
</table>
|
||||
<br></br>
|
||||
<group>
|
||||
<!-- Left Column -->
|
||||
<group>
|
||||
<field name="name"/>
|
||||
|
||||
<field name="quantity"/>
|
||||
</group>
|
||||
|
||||
<!-- Right Column -->
|
||||
<group>
|
||||
<field name="fg_name" invisible="sfg_option"/>
|
||||
<field name="sfg_name" invisible="fg_option"/>
|
||||
|
||||
</group>
|
||||
<button class="btn btn-primary" type="object" name="create_budget_plan" string="Execute"/>
|
||||
|
||||
</group>
|
||||
|
||||
|
||||
|
||||
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="budget_plan_menu"
|
||||
name="Budget Plan"
|
||||
parent="indent_menu_root"
|
||||
action = "action_budget_plan_list"/>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -59,22 +59,24 @@
|
|||
<field name="helper_field" invisible="1"/>
|
||||
<field name="sub_fg_name" domain="[('id', 'in', helper_field)]"/>
|
||||
<field name="batch_no"/>
|
||||
|
||||
<field name="invoice_no"/>
|
||||
<field name="batch_release_date"/>
|
||||
<field name="quantity_dispatched"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="Data Collection">
|
||||
<group>
|
||||
<page string="D0: Defective Details/Symptom">
|
||||
<group>
|
||||
<!-- <group>
|
||||
<field name="invoice_no"/>
|
||||
<field name="batch_release_date"/>
|
||||
<field name="quantity_dispatched"/>
|
||||
</group>
|
||||
</group> -->
|
||||
<group>
|
||||
<field name="brcoa_no"/>
|
||||
<field name="brcoa_date"/>
|
||||
<!-- <field name="brcoa_no"/>
|
||||
<field name="brcoa_date"/> -->
|
||||
<field name="other_complaints"/>
|
||||
</group>
|
||||
</group>
|
||||
|
|
@ -102,13 +104,13 @@
|
|||
</div>
|
||||
</templates>
|
||||
</page>
|
||||
<page string="Investigation Details">
|
||||
<page string="D0:Investigation Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="device_failed_to_meet_specification"/>
|
||||
<field name="labelling_error"/>
|
||||
<field name="ifu"/>
|
||||
<field name="interin_containment_actions"/>
|
||||
<!-- <field name="interin_containment_actions"/> -->
|
||||
</group>
|
||||
<group>
|
||||
<field name="packaging_details"/>
|
||||
|
|
@ -140,8 +142,59 @@
|
|||
</div>
|
||||
</templates>
|
||||
</page>
|
||||
<page string="Root Cause">
|
||||
<page string="D1:Team Formation & Document Reference">
|
||||
<!-- <field name="team_formation" /> -->
|
||||
|
||||
<field name="team_formation_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="department"/>
|
||||
<field name="role"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Form a cross-functional team with process knowledge and authority. Assign roles and responsibilities.</div>
|
||||
</div>
|
||||
</page>
|
||||
<page string="D2:Problem Description">
|
||||
<!-- <field name="problem_description"/> -->
|
||||
|
||||
<field name="problem_description_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="clear_statement"/>
|
||||
<field name="photos"/>
|
||||
<field name="what"/>
|
||||
<field name="where"/>
|
||||
<field name="when"/>
|
||||
<field name="why"/>
|
||||
<field name="who"/>
|
||||
<field name="how"/>
|
||||
<field name="how_many"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Clearly define the problem: What, Where, When, Why, Who, How,How Much.Use measurable facts(not assumptions).</div>
|
||||
</div>
|
||||
</page>
|
||||
|
||||
<page string="D3:Containment Actions">
|
||||
<group>
|
||||
<group>
|
||||
<field name="interin_containment_actions"/>
|
||||
</group>
|
||||
</group>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Temporary actions to isolate the problem and protect the customer.Example: Stop shipment,sort defective parts,replace or rework.</div>
|
||||
</div>
|
||||
</page>
|
||||
|
||||
<page string="D4:Root Cause Analysis">
|
||||
<field name="root_cause"/>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Identify the true root cause.Tools:5 Whys,Fishbone Diagram,Fault Tree Analysis,FMEA. </div>
|
||||
</div>
|
||||
<templates>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
|
|
@ -183,7 +236,35 @@
|
|||
</templates>
|
||||
</page>
|
||||
<page string="CAPA">
|
||||
<group>
|
||||
|
||||
<field name="capa_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="issue"/>
|
||||
<field name="corrective_action"/>
|
||||
<field name="implement_validate_corrective_action"/>
|
||||
<field name="preventive_action"/>
|
||||
</tree>
|
||||
</field>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong><div> Define and verify permanent corrective actions to eliminate the root cause.Validate effectiveness before full implementation.</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Apply the corrective actions,monitor effectiveness, and confirm the issue is resolved.</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Update processes, procedures, training, FMEA, control plans, Process Automation flows.Ensure similar issues don't happen elsewhere. </div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- <group>
|
||||
<group>
|
||||
<field name="corrective_action"/>
|
||||
</group>
|
||||
|
|
@ -193,7 +274,7 @@
|
|||
<group>
|
||||
<field name="capa_status"/>
|
||||
</group>
|
||||
</group>
|
||||
</group> -->
|
||||
<templates>
|
||||
<div class="row">
|
||||
<div class="col-6"></div>
|
||||
|
|
@ -217,7 +298,7 @@
|
|||
</div>
|
||||
</templates>
|
||||
</page>
|
||||
<page string="Response">
|
||||
<page string="D8: Team Recognition">
|
||||
<group>
|
||||
<group>
|
||||
<field name="response_sent_date"/>
|
||||
|
|
@ -228,7 +309,16 @@
|
|||
<group>
|
||||
<field name="qa_comments"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="capa_status"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="team_recognition" />
|
||||
</group>
|
||||
</group>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Appreciate and recognize the team's effort.Helps motivation and organizational learning. </div>
|
||||
</div>
|
||||
<templates>
|
||||
<div class="row">
|
||||
<div class="col-6"></div>
|
||||
|
|
@ -266,9 +356,5 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem id="ccrf_menu"
|
||||
name="Customer Complaint Registration Form(CCRF)"
|
||||
parent="ce_forms_menu_root" action="action_ccrf_list" groups="sos_inventory.sos_production_user,sos_inventory.sos_rd_user,sos_inventory.sos_healthcare_user,sos_inventory.sos_qa_user,sos_inventory.sos_qc_user,sos_inventory.sos_ce_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_management_user,sos_inventory.sos_sales_user"/>
|
||||
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
|
@ -84,7 +84,7 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
|||
|
||||
<notebook>
|
||||
<page string="Outsourcing" invisible="dc_type != 'out_souce_return' and dc_type != 'out_souce_noreturn'">
|
||||
<field name="line_ids" readonly="top_management_name">
|
||||
<field name="line_ids" widget="one2many_search" readonly="top_management_name">
|
||||
<tree editable="bottom">
|
||||
<field name="component_id"/>
|
||||
<field name="display_name"/>
|
||||
|
|
@ -97,7 +97,7 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
|||
</field>
|
||||
</page>
|
||||
<page string="Materials" invisible="dc_type == 'out_souce_return' or dc_type == 'out_souce_noreturn'">
|
||||
<field name="line_ids_materials" readonly="top_management_name">
|
||||
<field name="line_ids_materials" widget="one2many_search" readonly="top_management_name">
|
||||
<tree editable="bottom">
|
||||
<field name="component_id"/>
|
||||
<field name="display_name"/>
|
||||
|
|
@ -143,7 +143,10 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
|||
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<page string="Logistice Details">
|
||||
<field name="courier"/>
|
||||
<field name="lr_no"/>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
<br></br>
|
||||
|
|
@ -217,7 +220,7 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
|||
</record>
|
||||
<menuitem id="delivery_challan_menu"
|
||||
name="Delivery Challan (DC)"
|
||||
parent="scg_forms_menu_root" action="action_dc_form_list" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_manager,sos_inventory.sos_logistics_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_management_user,sos_inventory.sos_finance_user,sos_inventory.sos_sys_admin_user"/>
|
||||
parent="scg_forms_menu_root" action="action_dc_form_list" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_manager,sos_inventory.sos_logistics_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_management_user,sos_inventory.sos_finance_user,sos_inventory.sos_sys_admin_user,sos_inventory.sos_ce_user,sos_inventory.sos_sales_user"/>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@
|
|||
</record>
|
||||
<menuitem id="sos_deliverables_boq_menu"
|
||||
name="Deliverables List / BOQ"
|
||||
parent="sales_root_menu" action="action_sos_deliverables_boq_form_list" groups="sos_inventory.sos_scg_group_user,sos_inventory.sos_ce_user,sos_inventory.sos_finance_user,sos_inventory.sos_scg_group_manager,sos_inventory.sos_rd_user,sos_inventory.sos_production_user,sos_inventory.sos_qc_user,sos_inventory.sos_qa_user" />
|
||||
parent="sales_root_menu" action="action_sos_deliverables_boq_form_list" groups="sos_inventory.sos_scg_group_user,sos_inventory.sos_ce_user,sos_inventory.sos_finance_user,sos_inventory.sos_scg_group_manager,sos_inventory.sos_rd_user,sos_inventory.sos_production_user,sos_inventory.sos_qc_user,sos_inventory.sos_qa_user,sos_inventory.sos_logistics_user" />
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
<sheet>
|
||||
<group>
|
||||
<field name="fg_name"/>
|
||||
<field name="communication_type"/>
|
||||
<field name="communication_type" invisible="fg_name != 'BHMS 12V'"/>
|
||||
<field name="slave_type" invisible="fg_name != 'BHMS 1.2V'"/>
|
||||
<!-- <field name="customer_name"/>
|
||||
<field name="customer_location"/> -->
|
||||
</group>
|
||||
|
|
@ -91,6 +92,7 @@
|
|||
<tree string="Deliverables">
|
||||
<field name="fg_name"/>
|
||||
<field name="communication_type"/>
|
||||
<field name="slave_type"/>
|
||||
<field name="fg_ids"/>
|
||||
<field name="sfg_ids"/>
|
||||
<field name="material_ids"/>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<field name="model">sos_departments</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="short_form"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
|
@ -20,9 +21,18 @@
|
|||
<field name="model">sos_departments</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Model Form">
|
||||
<sheet>
|
||||
<group><field name="name"/></group>
|
||||
</sheet>
|
||||
<sheet>
|
||||
<group><field name="name"/></group>
|
||||
<group><field name="short_form"/></group>
|
||||
<group><field name="process_incharge"/></group>
|
||||
|
||||
<field name="users_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="users"/>
|
||||
</tree>
|
||||
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
|||
|
|
@ -216,13 +216,15 @@
|
|||
|
||||
<field name="payment_status"/>
|
||||
<field name="billing_address"/>
|
||||
<field name="shipping_address"/>
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<field name="invoice_no"/>
|
||||
<field name="invoice_date"/>
|
||||
<field name="warranty"/>
|
||||
<field name="gst_no"/>
|
||||
|
||||
<field name="shipping_address"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
decoration-warning="indent_status == 'hold'"
|
||||
decoration-danger="indent_status == 'open' or indent_status == 'cancel'"
|
||||
/>
|
||||
<field name="prepared_by" string="Prepared By" widget="many2one_avatar_user"/>
|
||||
|
||||
<field name="approved_by" string="Approved By" widget="many2one_avatar_user"/>
|
||||
|
||||
</tree>
|
||||
|
|
@ -184,7 +186,8 @@
|
|||
<templates>
|
||||
<div class="row" style="margin-top:100px">
|
||||
|
||||
<div class="col-4"> <table class="table_custom">
|
||||
<div class="col-4"> <table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
|
||||
<tr style="border-bottom: solid 1px #ccc;">
|
||||
<td style="padding: 8px;" class="column"><b>Prepared By Sign</b>
|
||||
<button string="Approve" invisible="prepared_image" class="btn-primary custom_btn" type="object" name="action_approve_esign_btn"></button>
|
||||
|
|
@ -200,9 +203,26 @@
|
|||
<td><field name="prepared_by" readonly="1"/></td>
|
||||
</tr>
|
||||
</table> </div>
|
||||
<div class="col-4"> </div>
|
||||
<div class="col-4"> <table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
|
||||
<tr style="border-bottom: solid 1px #ccc;">
|
||||
<td style="padding: 8px;" class="column"><b>Accounts Approval Sign</b>
|
||||
<button string="Approve" invisible="accounts_approved_by_image" class="btn-primary custom_btn" type="object" name="action_acc_approver_esign_btn"></button>
|
||||
</td>
|
||||
<td><field name="accounts_approved_by_image" widget="image"/></td>
|
||||
</tr>
|
||||
<tr invisible="accounts_approved_by_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved On</b></td>
|
||||
<td><field name="accounts_approved_on" readonly="1"/></td>
|
||||
</tr>
|
||||
<tr invisible="accounts_approved_by_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved By</b></td>
|
||||
<td><field name="accounts_approved_name" readonly="1"/></td>
|
||||
</tr>
|
||||
</table> </div>
|
||||
<div class="col-4">
|
||||
<table class="table_custom">
|
||||
<table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
|
||||
<tr style="border-bottom: solid 1px #ccc;">
|
||||
<td style="padding: 8px;" class="column"><b>Top Management Approval Sign</b>
|
||||
<button string="Approve" invisible="approval_image" class="btn-primary custom_btn" type="object" name="action_top_approver_esign_btn"></button>
|
||||
|
|
@ -233,5 +253,6 @@
|
|||
name="Indent Plan"
|
||||
parent="indent_menu_root"
|
||||
action = "action_fg_plan_list"/>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@
|
|||
<field name="fg_type" string="Type" icon="fa-list-ul" enable_counters="1"/>
|
||||
|
||||
</searchpanel>
|
||||
<field name="display_name" string="Display Name"/>
|
||||
<field name="name" string="Name"/>
|
||||
|
||||
|
||||
|
||||
</search>
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@
|
|||
</field>
|
||||
</record>
|
||||
<!-- Menuitem -->
|
||||
<menuitem id="menu_sos_fir" sequence="5" name="Final Inspection Report (FIR)" parent="mop_forms_menu_root" action="action_sos_fir" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user,sos_inventory.sos_ce_user"/>
|
||||
<menuitem id="menu_sos_fir" sequence="5" name="Final Inspection Report (FIR)" parent="mop_forms_menu_root" action="action_sos_fir" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user,sos_inventory.sos_ce_user,sos_inventory.sos_sales_user"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
</record>
|
||||
|
||||
<menuitem id="sos_master_list_customer_menu" name="Customer Property Master"
|
||||
parent="scg_forms_menu_root" action="action_sos_master_list_customer_form_list" />
|
||||
<!-- groups="sos_inventory.sos_sales_user,sos_inventory.sos_scg_group_manager,sos_inventory.sos_scg_group_user,sos_inventory.sos_ce_user,sos_inventory.sos_rd_user,sos_inventory.sos_production_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user,sos_inventory.sos_logistics_user,sos_inventory.sos_finance_user" -->
|
||||
parent="scg_forms_menu_root" action="action_sos_master_list_customer_form_list" groups="sos_inventory.sos_scg_group_manager,sos_inventory.sos_scg_group_user,sos_inventory.sos_ce_user,sos_inventory.sos_rd_user,sos_inventory.sos_production_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user"/>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
<field name="ref_no" optional="hide"/>
|
||||
<field name="stores_approval_name" string="Stores Approved By" widget="many2one_avatar_user"/>
|
||||
<field name="scg_manager_approval_name" string="SCG Manager Approved By" widget="many2one_avatar_user"/>
|
||||
<field name="receiver_approval_name" string="Received By" widget="many2one_avatar_user"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -105,7 +107,7 @@
|
|||
<span>Not Issued</span>
|
||||
</div>
|
||||
|
||||
<field name="line_ids_material">
|
||||
<field name="line_ids_material" widget="one2many_search">
|
||||
<tree editable="bottom" decoration-success="quantity <= issued_quantity and quantity != 0" decoration-warning="quantity > issued_quantity and issued_quantity != 0">
|
||||
|
||||
<field name="s_no"/>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
<field name="mon_date"/>
|
||||
<field name="min_no" string="Issue Note Ref No" />
|
||||
<field name="purpose"/>
|
||||
<field name="customer_name" groups="sos_inventory.sos_ce_user"/>
|
||||
<field name="approx_value" string="Order Value" optional="hide"/>
|
||||
<field name="prepared_by_name" string="Prepared By" widget="many2one_avatar_user"/>
|
||||
<field name="dept_in_charge_name" string="Department In-Charge" widget="many2one_avatar_user"/>
|
||||
|
|
@ -59,9 +60,9 @@
|
|||
|
||||
</header>
|
||||
<sheet>
|
||||
<widget name="web_ribbon" text="Open" bg_color="bg-danger" invisible="status == 'close'"/>
|
||||
<widget name="web_ribbon" text="Closed" bg_color="bg-success" invisible="status == 'open'"/>
|
||||
|
||||
<widget name="web_ribbon" text="Open" bg_color="bg-danger" invisible="status == 'close'"/>
|
||||
<widget name="web_ribbon" text="Closed" bg_color="bg-success" invisible="status == 'open'"/>
|
||||
|
||||
<h2 style="text-align: center;text-transform: uppercase;text-shadow: 1px 1p 1px #140718;color: #65407c;padding:5px;">Material / SFG / FG <br></br>Order Note</h2><hr></hr><br></br>
|
||||
|
||||
<table class="table table" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;">
|
||||
|
|
@ -88,6 +89,7 @@
|
|||
<field name="auto_load_fg_items" invisible="auto_load == 'sfg' or auto_load == False" />
|
||||
<field name="set_qty" invisible="auto_load == 'fg' or auto_load == False" />
|
||||
<field name="fg_set_qty" invisible="auto_load != 'fg'" />
|
||||
<field name="deliverables_boq_id" groups="sos_inventory.sos_management_user,sos_inventory.sos_scg_group_user" />
|
||||
|
||||
</group>
|
||||
<!-- Second Column -->
|
||||
|
|
@ -110,7 +112,7 @@
|
|||
<notebook>
|
||||
<page string="Materials" invisible="material_option == False">
|
||||
<div style="float:right;margin-bottom: 10px;"> <button string="Bulk Upload Materials" type="object" name="action_bulk_upload" class="oe_highlight"/></div>
|
||||
<field name="line_ids_material" readonly="dept_in_charge_name">
|
||||
<field name="line_ids_material" widget="one2many_search" readonly="dept_in_charge_name">
|
||||
<tree editable="bottom">
|
||||
<field name="s_no"/>
|
||||
<field name="com_type" decoration-info="com_type == 'new'"/>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
|
||||
<notebook>
|
||||
<page string="Materials" invisible="material_option == False">
|
||||
<field name="line_ids_material">
|
||||
<field name="line_ids_material" readonly="stores_approved_by">
|
||||
<tree editable="bottom">
|
||||
<field name="component_id" string="Material Name"/>
|
||||
<field name="approx_price"/>
|
||||
|
|
@ -104,10 +104,11 @@
|
|||
<field name="approx_value" widget="monetary" options="{'currency_field': 'currency_id'}" class="oe_inline"/>
|
||||
</div>
|
||||
</div>
|
||||
<br></br>
|
||||
<br></br> <br></br>
|
||||
|
||||
</page>
|
||||
<page string="Semi-Finished Goods" invisible="sfg_option == False">
|
||||
<field name="line_ids_sfg">
|
||||
<field name="line_ids_sfg" readonly="stores_approved_by">
|
||||
<tree editable="bottom">
|
||||
<field name="component_id"/>
|
||||
<field name="qp_no"/>
|
||||
|
|
@ -128,7 +129,7 @@
|
|||
|
||||
</page>
|
||||
<page string="Finished Goods" invisible="fg_option == False">
|
||||
<field name="line_ids_fg">
|
||||
<field name="line_ids_fg" readonly="stores_approved_by">
|
||||
<tree editable="bottom">
|
||||
<field name="component_id"/>
|
||||
<field name="batch_No"/>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
<tree>
|
||||
<header>
|
||||
<button name="%(action_ncmr_wizard)d" string="Report" type="action" class="oe_highlight" display="always"/>
|
||||
<button name="%(action_pareto_chart)d" string="Pareto" type="action" class="oe_highlight" display="always"/>
|
||||
</header>
|
||||
<field name="ncmr_no"/>
|
||||
<field name="ncmr_date"/>
|
||||
|
|
@ -59,17 +60,20 @@
|
|||
|
||||
</table>
|
||||
<br></br>
|
||||
|
||||
<!-- Topmost Group -->
|
||||
<group>
|
||||
<!-- First Column -->
|
||||
<group>
|
||||
<field name="rca_required" invisible="1"/>
|
||||
<field name="allowed_user_ids" invisible="1"/>
|
||||
<field name="rca_allowed_user_ids" invisible="1"/>
|
||||
<field name="status" invisible="1"/>
|
||||
<field name="department"/>
|
||||
<field name="ncmr_no"/>
|
||||
<field name="ncmr_type" invisible="1"/>
|
||||
<field name="ncmr_date"/>
|
||||
<field name="outsourcing_return_ref_no" invisible="rework_action == 'inhouse'"/>
|
||||
<field name="outsourcing_return_ref_no"/>
|
||||
</group>
|
||||
<!-- Second Column -->
|
||||
<group>
|
||||
|
|
@ -77,7 +81,7 @@
|
|||
|
||||
<field name="fg_name"/>
|
||||
<field name="fg_category" invisible="1"/>
|
||||
<field name="customer_name" invisible="customer_name == False"/>
|
||||
<!-- <field name="customer_name" invisible="customer_name == False"/> -->
|
||||
|
||||
<field name="batch_no"/>
|
||||
<field name="rejected_qty" invisible="fg_option != True"/>
|
||||
|
|
@ -109,7 +113,7 @@
|
|||
border-radius: 5px;margin-bottom: 20px;"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Defective Details" invisible="fg_option != True">
|
||||
<page string="D0: Defective Details/Symptom" invisible="fg_option != True">
|
||||
|
||||
<field name="line_ids">
|
||||
<tree editable="bottom">
|
||||
|
|
@ -126,7 +130,7 @@
|
|||
<label for="fg_unique_defect_count"/><field name="fg_unique_defect_count" nolabel="1" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Defective Details" invisible="sfg_option != True">
|
||||
<page string="D0: Defective Details/Symptom" invisible="sfg_option != True">
|
||||
|
||||
<field name="line_ids">
|
||||
<tree editable="bottom">
|
||||
|
|
@ -144,7 +148,7 @@
|
|||
<label for="unique_defect_count"/><field name="unique_defect_count" nolabel="1" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Defective Details" invisible="material_option != True">
|
||||
<page string="D0: Defective Details/Symptom" invisible="material_option != True">
|
||||
|
||||
<field name="line_ids">
|
||||
<tree editable="bottom">
|
||||
|
|
@ -161,7 +165,7 @@
|
|||
<label for="material_unique_defect_count"/><field name="material_unique_defect_count" nolabel="1" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Document Reference">
|
||||
<page string="D1: Team Formation & Document Reference">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -173,8 +177,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td class="column">In-Coming Material (RM/PM)</td><td><field name="incoming_doc_ref"/></td><td><field name="incoming_responsibility"/></td></tr>
|
||||
<tr><td class="column">Return In-Coming Material (RM/PM)</td><td><field name="return_incoming_doc_ref"/></td><td><field name="return_incoming_resposibility"/></td></tr>
|
||||
<tr><td class="column">In-Coming Material (RM/PM)</td><td><field name="incoming_doc_ref"/></td><td><group><field name="responsible_department" invisible="not incoming_doc_ref"/><field name="responsible_name" invisible="not incoming_doc_ref"/></group></td></tr>
|
||||
<tr><td class="column">Return In-Coming Material (RM/PM)</td><td><field name="return_incoming_doc_ref"/></td><td><group><field name="responsible_department" invisible="not return_incoming_doc_ref"/><field name="responsible_name" invisible="not return_incoming_doc_ref"/></group></td></tr>
|
||||
|
||||
<!--
|
||||
<tr><td class="column">Dispensed Material (RM/PM)</td><td><field name="dispensed_doc_ref"/></td><td><field name="dispensed_responsibility"/></td></tr>
|
||||
|
|
@ -183,61 +187,130 @@
|
|||
<tr><td class="column">Approved Stored Material (RM/PM)</td><td><field name="approved_doc_ref"/></td><td><field name="approved_responsibility"/></td></tr>
|
||||
<tr><td class="column">Customer Complaint</td><td><field name="customer_complaint_doc_ref"/></td><td><field name="customer_complaint_responsibility"/></td></tr>
|
||||
-->
|
||||
<tr><td class="column">Approved Finished Products</td><td><field name="fir_incoming_doc_ref"/></td><td><field name="approved_fg_responsibility"/></td></tr>
|
||||
<tr><td class="column">Returned Finished Products</td><td><field name="return_fg_incoming_doc_ref"/></td><td><field name="returned_fg_responsibility"/></td></tr>
|
||||
<tr><td class="column">Finished Products(Production Assy)</td><td><field name="fg_incoming_doc_ref"/></td><td><field name="finished_fg_assy_responsibility"/></td></tr>
|
||||
|
||||
<tr><td class="column">Approved Finished Products</td><td><field name="fir_incoming_doc_ref"/></td><td><group><field name="responsible_department" invisible="not fir_incoming_doc_ref"/><field name="responsible_name" invisible="not fir_incoming_doc_ref"/></group></td></tr>
|
||||
<tr><td class="column">Returned Finished Products</td><td><field name="return_fg_incoming_doc_ref"/></td><td><group><field name="responsible_department" invisible="not return_fg_incoming_doc_ref"/><field name="responsible_name" invisible="not return_fg_incoming_doc_ref"/></group></td></tr>
|
||||
<tr><td class="column">Finished Products(Production Assy)</td><td><field name="fg_incoming_doc_ref"/></td><td><group><field name="responsible_department" invisible="not fg_incoming_doc_ref"/><field name="responsible_name" invisible="not fg_incoming_doc_ref"/></group></td></tr>
|
||||
<tr><td class="column">RCA Committee</td><td></td><td><group><field name="rca_responsible_department" widget="many2many_tags"/><field name="rca_responsible_name" widget="many2many_tags"/></group></td></tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Form a cross-functional team with process knowledge and authority. Assign roles and responsibilities.</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</page>
|
||||
<page string="Description of NC">
|
||||
<field name="description_of_nc"/>
|
||||
<page string="D2:Problem Description">
|
||||
<!-- <field name="description_of_nc"/> -->
|
||||
<field name="problem_description_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="clear_statement"/>
|
||||
<field name="photos"/>
|
||||
<field name="what"/>
|
||||
<field name="where"/>
|
||||
<field name="when"/>
|
||||
<field name="why"/>
|
||||
<field name="who"/>
|
||||
<field name="how"/>
|
||||
<field name="how_many"/>
|
||||
</tree>
|
||||
</field>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Clearly define the problem: What, Where, When, Why, Who, How,How Much.Use measurable facts(not assumptions).</div>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Root Cause of NC" invisible="rca_required == 'no'">
|
||||
<field name="root_cause_of_nc"/>
|
||||
</page>
|
||||
<page string="Containment Action" invisible="rca_required == 'no'">
|
||||
|
||||
<page string="D3: Containment Action" >
|
||||
<field name="containment_action_of_nc"/>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Temporary actions to isolate the problem and protect the customer.Example: Stop shipment, sort defective parts,replace or rework.</div>
|
||||
</div>
|
||||
</page>
|
||||
|
||||
<page string="D4: Root Cause Analysis" invisible="rca_required == 'no'">
|
||||
<field name="root_cause_of_nc"/>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Identify the true root cause.Tools:5 Whys, Fishbone Diagram (Ishikawa),Fault Tree Analysis,FMEA. </div>
|
||||
</div>
|
||||
</page>
|
||||
|
||||
<page string="CAPA" invisible="rca_required == 'no'">
|
||||
<field name="capa_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="issue"/>
|
||||
<field name="corrective_action"/>
|
||||
<field name="implement_validate_corrective_action"/>
|
||||
<field name="preventive_action"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong><div> Define and verify permanent corrective actions to eliminate the root cause.Validate effectiveness before full implementation.</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Apply the corrective actions,monitor effectiveness, and confirm the issue is resolved.</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Update processes, procedures, training, FMEA, control plans, Process Automation flows.Ensure similar issues don't happen elsewhere. </div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</page>
|
||||
<page string="Comments on CAPA" invisible="rca_required == 'no'">
|
||||
<!-- <page string="Comments on CAPA" invisible="rca_required == 'no'">
|
||||
<field name="comments_on_capa"/>
|
||||
</page>
|
||||
<page string="Status" invisible="sfg_option != True">
|
||||
</page> -->
|
||||
<page string="D8: Team Recognition" invisible="sfg_option != True">
|
||||
<field name="defective_status_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<tree editable="bottom">
|
||||
<field name="defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
<field name="comments_on_capa" nolabel="0"/>
|
||||
</group>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Appreciate and recognize the team's effort.Helps motivation and organizational learning. </div>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Status" invisible="material_option != True">
|
||||
<page string="D8: Team Recognition" invisible="material_option != True">
|
||||
<field name="defective_status_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="material_defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<tree editable="bottom">
|
||||
<field name="material_defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
<field name="comments_on_capa" nolabel="0"/>
|
||||
</group>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Appreciate and recognize the team's effort.Helps motivation and organizational learning. </div>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Status" invisible="fg_option != True">
|
||||
<page string="D8: Team Recognition" invisible="fg_option != True">
|
||||
<field name="defective_status_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="fg_defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<tree editable="bottom">
|
||||
<field name="fg_defective_id"/>
|
||||
<field name="aodr_no"/>
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
<field name="comments_on_capa" nolabel="0"/>
|
||||
</group>
|
||||
<div class="oe_note">
|
||||
<strong>Note:</strong> <div>Appreciate and recognize the team's effort.Helps motivation and organizational learning. </div>
|
||||
</div>
|
||||
</page>
|
||||
|
||||
|
||||
|
|
@ -424,6 +497,8 @@
|
|||
</record>
|
||||
<menuitem id="ncmr_menu"
|
||||
name="Non-Conforming Material Report (NCMR)"
|
||||
parent="cnp_forms_menu_root" action="action_ncmr_form_list" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_qa_user,sos_inventory.sos_rd_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user,sos_inventory.sos_production_user"/>
|
||||
parent="cnp_forms_menu_root" action="action_ncmr_form_list"
|
||||
|
||||
/>
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="action_prf_list" model="ir.actions.act_window">
|
||||
<field name="name">PRF</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sos_prf</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No Plan Found
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sos_prf_view_tree" model="ir.ui.view">
|
||||
<field name="name">sos_prf.view.tree</field>
|
||||
<field name="model">sos_prf</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
|
||||
<field name="prf_no"/>
|
||||
<field name="prf_date"/>
|
||||
<field name="status" widget="badge" decoration-success="status == 'close'" decoration-danger="status == 'open'"/>
|
||||
|
||||
|
||||
<field name="write_uid" string="Last Edited By" optional="hide"/>
|
||||
<field name="write_date" string="Last Edited On" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="sos_prf_form_view" model="ir.ui.view">
|
||||
<field name="name">Form</field>
|
||||
<field name="model">sos_prf</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Purchase Requisition Form">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" text="Open" bg_color="bg-danger" invisible="status == 'close'"/>
|
||||
<widget name="web_ribbon" text="Closed" bg_color="bg-success" invisible="status != 'close'"/>
|
||||
<group>
|
||||
<!-- Left Column -->
|
||||
<group>
|
||||
<field name="prf_no"/>
|
||||
<field name="status"/>
|
||||
|
||||
</group>
|
||||
|
||||
<!-- Right Column -->
|
||||
<group>
|
||||
<field name="prf_date"/>
|
||||
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<br></br>
|
||||
|
||||
<field name="line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="com_type"/>
|
||||
<field name="component_id" required="com_type == 'exits'" readonly="com_type == 'new'"/>
|
||||
<field name="new_component_id" required="com_type == 'new'" readonly="com_type == 'exits'"/>
|
||||
|
||||
<field name="qty"/>
|
||||
<field name="req_date"/>
|
||||
<field name="mon_ref_no"/>
|
||||
</tree>
|
||||
</field>
|
||||
<br></br>
|
||||
<templates>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
<tr style="border-bottom: solid 1px #ccc;">
|
||||
<td style="padding: 8px;" class="column"><b>Stores Incharge</b>
|
||||
<button string="Approve" invisible="requested_by_image" class="btn-primary custom_btn" type="object" name="action_stores_esign_btn"></button>
|
||||
</td>
|
||||
<td><field name="requested_by_image" widget="image"/></td>
|
||||
</tr>
|
||||
<tr invisible="requested_by_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Requested On</b></td>
|
||||
<td><field name="requested_on" readonly="1"/></td>
|
||||
</tr>
|
||||
<tr invisible="requested_by_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Requested By</b></td>
|
||||
<td><field name="requested_by_name" readonly="1"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
|
||||
|
||||
<tr style="border-bottom: solid 1px #ccc;">
|
||||
<td style="padding: 8px;" class="column"><b>Dept-Incharge Sign</b>
|
||||
<button string="Approve" invisible="dept_in_charge_image" class="btn-primary custom_btn" type="object" name="action_dept_esign_btn"></button>
|
||||
</td>
|
||||
<td><field name="dept_in_charge_image" widget="image"/></td>
|
||||
</tr>
|
||||
<tr invisible="dept_in_charge_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved On</b></td>
|
||||
<td><field name="dept_in_charge_approved_on" readonly="1"/></td>
|
||||
</tr>
|
||||
<tr invisible="dept_in_charge_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved By</b></td>
|
||||
<td><field name="dept_in_charge_name" readonly="1"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
|
||||
|
||||
<tr>
|
||||
<td style="padding: 8px;" class="column"><b>Top Management</b>
|
||||
<button string="Approve" invisible="top_management_approval_image" class="btn-primary custom_btn" type="object" name="action_top_esign_btn"></button>
|
||||
</td>
|
||||
<td><field name="top_management_approval_image" widget="image"/></td>
|
||||
</tr>
|
||||
<tr invisible="top_management_approval_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved On</b></td>
|
||||
<td><field name="top_management_approved_on" readonly="1"/></td>
|
||||
</tr>
|
||||
<tr invisible="top_management_approval_image == False">
|
||||
<td style="padding: 8px;" class="column"><b>Approved By</b></td>
|
||||
<td><field name="top_management_name" readonly="1"/></td>
|
||||
</tr>
|
||||
</table></div>
|
||||
</div>
|
||||
|
||||
</templates>
|
||||
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="prf_menu"
|
||||
name="Purchase Requisition Form(PRF)"
|
||||
parent="scg_forms_menu_root"
|
||||
action = "action_prf_list" groups="sos_inventory.sos_scg_group_manager,sos_inventory.sos_scg_group_user" />
|
||||
|
||||
</odoo>
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
<field name="lead_time"/>
|
||||
<field name="customer_po_no"/>
|
||||
<field name="customer_po_date"/>
|
||||
<field name="customer_location"/>
|
||||
</group>
|
||||
<group>
|
||||
<!-- <field name="email_to" widget="many2many_tags"/> -->
|
||||
|
|
@ -29,6 +30,7 @@
|
|||
<page string="Commercial Details">
|
||||
<group>
|
||||
<group>
|
||||
|
||||
<field name="purpose_of_delivery"/>
|
||||
<field name="payment_status"/>
|
||||
<field name="payment_terms"/>
|
||||
|
|
@ -38,6 +40,8 @@
|
|||
|
||||
</group>
|
||||
<group>
|
||||
<field name="customer_name"/>
|
||||
<field name="customer_location"/>
|
||||
<field name="billing_address"/>
|
||||
<field name="shipping_address"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@
|
|||
<field name="ref_no"/>
|
||||
<field name="customer_name"/>
|
||||
<field name="contact_person"/>
|
||||
<field name="dock_audit_ref_no"/>
|
||||
<field name="invoice_no" invisible="dock_audit_ref_no == False"/>
|
||||
<field name="invoice_date" invisible="dock_audit_ref_no == False"/>
|
||||
<field name="warranty" invisible="dock_audit_ref_no == False"/>
|
||||
<field name="location"/>
|
||||
<field name="mobile_no"/>
|
||||
<field name="email"/>
|
||||
|
|
@ -74,9 +78,6 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem id="sos_service_call_log_report_menu"
|
||||
name="Service Call Log Report" parent="ce_forms_menu_root"
|
||||
action="action_sos_service_call_log_report_form_list" groups="sos_inventory.sos_ce_user,sos_inventory.sos_management_user"/>
|
||||
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
@ -46,15 +46,16 @@
|
|||
<group>
|
||||
<field name="orr_no"/>
|
||||
<field name="iqi_no"/>
|
||||
<field name="rework_type"/>
|
||||
<field name="goods_type"/>
|
||||
<field name="service_provider_name" invisible="goods_type != 'SFG'"/>
|
||||
<field name="supplier_name" invisible="goods_type != 'Materials'"/>
|
||||
<field name="service_provider_name" invisible="goods_type != 'SFG' or rework_type !='outsourcing'"/>
|
||||
<field name="supplier_name" invisible="goods_type != 'Materials' or rework_type !='outsourcing'"/>
|
||||
<field name="returned_qty"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="iqi_date"/>
|
||||
<field name="sfg_name" invisible="goods_type != 'SFG'"/>
|
||||
<field name="material_name" invisible="goods_type != 'Materials'"/>
|
||||
<field name="sfg_name" invisible="goods_type != 'SFG' or rework_type !='outsourcing'"/>
|
||||
<field name="material_name" invisible="goods_type != 'Materials' or rework_type !='outsourcing'"/>
|
||||
<field name="remarks"/>
|
||||
</group>
|
||||
</group>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<field name="res_model">sos_wo</field>
|
||||
<field name="view_mode">tree,form,kanban</field>
|
||||
</record>
|
||||
<record id="action_amend_server_action" model="ir.actions.server">
|
||||
<record id="action_amend_wo_server_action" model="ir.actions.server">
|
||||
<field name="name">📝 Amend</field>
|
||||
<field name="model_id" ref="model_sos_wo"/>
|
||||
<field name="binding_model_id" ref="model_sos_wo"/>
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
action = model.action_amend()
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sos_wo_view_panel" model="ir.ui.view">
|
||||
<field name="name">sos_wo.search</field>
|
||||
<field name="model">sos_wo</field>
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue