Reference #11
This commit is contained in:
parent
ebdc1d3ca1
commit
ceb5e58e3e
|
|
@ -11,7 +11,7 @@
|
||||||
'version': '17.0.1.0.0',
|
'version': '17.0.1.0.0',
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
# any module necessary for this one to work correctly
|
||||||
'depends': ['base','web','mail'],
|
'depends': ['base','web','mail','one2many_search_widget'],
|
||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
'security/record_rules.xml',
|
'security/record_rules.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'data/cron_jobs.xml',
|
'data/cron_jobs.xml',
|
||||||
|
'views/pareto_chart_widget_view.xml',
|
||||||
'views/sos_audit_log_view.xml',
|
'views/sos_audit_log_view.xml',
|
||||||
'views/menu.xml',
|
'views/menu.xml',
|
||||||
'views/sos_quote_generation.xml',
|
'views/sos_quote_generation.xml',
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
'views/sos_fg_view.xml',
|
'views/sos_fg_view.xml',
|
||||||
'views/sos_sfg_view.xml',
|
'views/sos_sfg_view.xml',
|
||||||
'views/sos_material_view.xml',
|
'views/sos_material_view.xml',
|
||||||
|
'views/sos_budget_plan_view.xml',
|
||||||
'views/sos_material_bom_view.xml',
|
'views/sos_material_bom_view.xml',
|
||||||
'views/sos_sfg_bom_view.xml',
|
'views/sos_sfg_bom_view.xml',
|
||||||
'views/sos_fg_bom_view.xml',
|
'views/sos_fg_bom_view.xml',
|
||||||
|
|
@ -81,6 +83,8 @@
|
||||||
'views/sos_service_call_log_report.xml',
|
'views/sos_service_call_log_report.xml',
|
||||||
'views/sos_transfer_challan_return_from_customer_view.xml',
|
'views/sos_transfer_challan_return_from_customer_view.xml',
|
||||||
'views/sos_shelflife_register_view.xml',
|
'views/sos_shelflife_register_view.xml',
|
||||||
|
'views/sos_prf_view.xml',
|
||||||
|
|
||||||
'wizard/sfg_bom_bulk_upload_view.xml',
|
'wizard/sfg_bom_bulk_upload_view.xml',
|
||||||
'wizard/mon_bulk_upload_view.xml',
|
'wizard/mon_bulk_upload_view.xml',
|
||||||
'wizard/missing_component_wizard.xml',
|
'wizard/missing_component_wizard.xml',
|
||||||
|
|
@ -115,6 +119,7 @@
|
||||||
'report/sos_boq_labels.xml',
|
'report/sos_boq_labels.xml',
|
||||||
'report/shelflife_report.xml',
|
'report/shelflife_report.xml',
|
||||||
'report/sos_boq_report.xml',
|
'report/sos_boq_report.xml',
|
||||||
|
'report/sos_budget_plan_summary.xml',
|
||||||
'data/send_indent_plan_email_template.xml',
|
'data/send_indent_plan_email_template.xml',
|
||||||
'data/selection_item.xml'
|
'data/selection_item.xml'
|
||||||
|
|
||||||
|
|
@ -130,6 +135,8 @@
|
||||||
'sos_inventory/static/src/components/**/*.js',
|
'sos_inventory/static/src/components/**/*.js',
|
||||||
'sos_inventory/static/src/components/**/*.xml',
|
'sos_inventory/static/src/components/**/*.xml',
|
||||||
'sos_inventory/static/src/components/**/*.scss',
|
'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
|
import xlsxwriter
|
||||||
|
|
||||||
class MaterialBackupExportController(http.Controller):
|
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')
|
@http.route(['/download/material/backup/<string:year>/<string:item_type>'], type='http', auth='user')
|
||||||
def download_backup_by_year(self, year, item_type, **kwargs):
|
def download_backup_by_year(self, year, item_type, **kwargs):
|
||||||
# Safely map table names
|
# Safely map table names
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,6 @@ from . import sos_master_customer_property
|
||||||
from . import sos_service_call_log_report
|
from . import sos_service_call_log_report
|
||||||
from . import sos_inhouse_validation_reports_files
|
from . import sos_inhouse_validation_reports_files
|
||||||
from . import sos_transfer_challan_return_from_customer
|
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")
|
batch_release_date = fields.Date(string="Invoice Date")
|
||||||
brcoa_no = fields.Char(string="BRCOA No")
|
brcoa_no = fields.Char(string="BRCOA No")
|
||||||
brcoa_date = fields.Date(string="BRCOA Date")
|
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_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_image = fields.Image(related="data_collected_by.signature_image",string='Data Collected Sign',readonly=True)
|
||||||
data_collected_on = fields.Datetime(string="Data Collected On")
|
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_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")
|
investigation_carriedout_on = fields.Datetime(string="Investigation Carried Out On")
|
||||||
root_cause = fields.Html(string="Root Cause",
|
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_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_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")
|
rootcause_carriedout_on = fields.Datetime(string="Root Cause Carried Out On")
|
||||||
corrective_action = fields.Html(string="Corrective Action")
|
corrective_action = fields.Html(string="D5:Permanent Corrective Action")
|
||||||
preventive_action = fields.Html(string="Preventive 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")
|
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_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)
|
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_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")
|
rootcause_verifiedout_on = fields.Datetime(string="Root Cause Verified On")
|
||||||
helper_field = fields.Many2many('sos_fg', string="Helper Field")
|
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')
|
@api.onchange('fg_name')
|
||||||
def _onchange_fg_name(self):
|
def _onchange_fg_name(self):
|
||||||
if self.fg_name:
|
if self.fg_name:
|
||||||
|
|
@ -140,4 +150,38 @@ class SOS_CCRF(models.Model):
|
||||||
'rootcause_verifiedout_by',
|
'rootcause_verifiedout_by',
|
||||||
'rootcause_verifiedout_on'
|
'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)])
|
reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)])
|
||||||
email_to = reporting_user.login
|
email_to = reporting_user.login
|
||||||
else:
|
else:
|
||||||
email_to = "ramachandran.r@sosaley.in"
|
email_to = "ramachandran.r@sosaley.com"
|
||||||
mail_values = {
|
mail_values = {
|
||||||
'subject': subject,
|
'subject': subject,
|
||||||
'body_html': body_html,
|
'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_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")
|
dept_in_charge_approved_on = fields.Datetime(string="Approved On")
|
||||||
remarks = fields.Text(string="Remarks")
|
remarks = fields.Text(string="Remarks")
|
||||||
|
courier = fields.Char(string="Courier Name")
|
||||||
|
lr_no = fields.Char(string="LR No")
|
||||||
@api.onchange('dock_audit_no')
|
@api.onchange('dock_audit_no')
|
||||||
def _onchange_dock_audit_no(self):
|
def _onchange_dock_audit_no(self):
|
||||||
if self.dock_audit_no:
|
if self.dock_audit_no:
|
||||||
|
|
@ -220,7 +221,7 @@ class sos__dc(models.Model):
|
||||||
"""
|
"""
|
||||||
subject = f"Delivery Challan Approval Request - {self.dc_no}"
|
subject = f"Delivery Challan Approval Request - {self.dc_no}"
|
||||||
send_email = self.env['sos_common_scripts']
|
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
|
# Email part ends
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
sequence_util.action_assign_signature(
|
sequence_util.action_assign_signature(
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,12 @@ class SosTestingParameters(models.Model):
|
||||||
communication_type = fields.Selection([
|
communication_type = fields.Selection([
|
||||||
('wired', 'Wired'),
|
('wired', 'Wired'),
|
||||||
('wireless', 'Wireless')
|
('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)
|
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)
|
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)
|
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([
|
item_type = fields.Selection([
|
||||||
('Master Panel', 'Master Panel'),
|
('Master Panel', 'Master Panel'),
|
||||||
('CT Module', 'CT Module'),
|
('CT Module', 'CT Module'),
|
||||||
|
('Battery Count', 'Battery Count'),
|
||||||
('Slave Module', 'Slave Module'),
|
('Slave Module', 'Slave Module'),
|
||||||
('Internet Module', 'Internet Module')
|
('Internet Module', 'Internet Module')
|
||||||
], string="Type",default="Master Panel")
|
], string="Type",default="Master Panel")
|
||||||
|
|
@ -82,6 +88,7 @@ class SOS_Material_Deliverables(models.Model):
|
||||||
item_type = fields.Selection([
|
item_type = fields.Selection([
|
||||||
('Master Panel', 'Master Panel'),
|
('Master Panel', 'Master Panel'),
|
||||||
('CT Module', 'CT Module'),
|
('CT Module', 'CT Module'),
|
||||||
|
('Battery Count', 'Battery Count'),
|
||||||
('Slave Module', 'Slave Module'),
|
('Slave Module', 'Slave Module'),
|
||||||
('Internet Module', 'Internet Module')
|
('Internet Module', 'Internet Module')
|
||||||
], string="Type",default="Master Panel")
|
], string="Type",default="Master Panel")
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,34 @@ class sos_department(models.Model):
|
||||||
|
|
||||||
|
|
||||||
name = fields.Char(string="Department Name")
|
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>
|
<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
|
# Email part ends
|
||||||
return sequence_util.action_assign_signature(
|
return sequence_util.action_assign_signature(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ class SOS_Dock_Audit(models.Model):
|
||||||
],
|
],
|
||||||
string="Product Type",required=True)
|
string="Product Type",required=True)
|
||||||
quantity = fields.Integer(string="Quantity")
|
quantity = fields.Integer(string="Quantity")
|
||||||
|
warranty = fields.Integer(string="Warranty(In Months)")
|
||||||
invoice_no = fields.Char(string="Invoice No")
|
invoice_no = fields.Char(string="Invoice No")
|
||||||
|
invoice_date = fields.Date(string="Invoice Date")
|
||||||
customer_name = fields.Char(string="Customer Name")
|
customer_name = fields.Char(string="Customer Name")
|
||||||
lead_time = fields.Datetime(string="Lead Time")
|
lead_time = fields.Datetime(string="Lead Time")
|
||||||
customer_po_no = fields.Char(string="PO No")
|
customer_po_no = fields.Char(string="PO No")
|
||||||
|
|
@ -140,6 +142,18 @@ class SOS_Dock_Audit(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
def action_acc_esign_btn(self):
|
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 = self.env['sos_common_scripts']
|
||||||
sequence_util.action_assign_signature(
|
sequence_util.action_assign_signature(
|
||||||
self,
|
self,
|
||||||
|
|
@ -151,7 +165,7 @@ class SOS_Dock_Audit(models.Model):
|
||||||
body_html = f"""
|
body_html = f"""
|
||||||
<p>Below Dock Audit is waiting for your Approval</p>
|
<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
|
# Email part ends
|
||||||
def action_auditor_esign_btn(self):
|
def action_auditor_esign_btn(self):
|
||||||
sequence_util = self.env['sos_common_scripts']
|
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.shipping_address = self.deliverables_boq_id.sales_id.shipping_address
|
||||||
self.gst_no = self.deliverables_boq_id.sales_id.gst_no
|
self.gst_no = self.deliverables_boq_id.sales_id.gst_no
|
||||||
self.payment_status = self.deliverables_boq_id.sales_id.payment_status
|
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.fg_name = self.deliverables_boq_id.sales_id.fg_name
|
||||||
self.quantity = self.deliverables_boq_id.sales_id.qty
|
self.quantity = self.deliverables_boq_id.sales_id.qty
|
||||||
self.lead_time = self.deliverables_boq_id.sales_id.lead_time
|
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_by = fields.Many2one('res.users', string='Planned By')
|
||||||
prepared_image = fields.Image(related="prepared_by.signature_image",string='Prepared By Sign',readonly=True)
|
prepared_image = fields.Image(related="prepared_by.signature_image",string='Prepared By Sign',readonly=True)
|
||||||
prepared_on = fields.Datetime(string="Planned On")
|
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)
|
blowup = fields.Boolean(string="Blowup Done",default=False)
|
||||||
target_date = fields.Date(string="Target Date",required=True)
|
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))
|
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')
|
month = today.strftime('%m')
|
||||||
base_sequence_prefix = f"SOS/{form_name}/{fy}/{month}/"
|
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(
|
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",
|
order=f"{field_name} desc",
|
||||||
limit=1
|
limit=1
|
||||||
)
|
)
|
||||||
|
|
||||||
if records:
|
if records:
|
||||||
last_sequence = records[0][field_name]
|
last_sequence = records[0][field_name]
|
||||||
last_suffix = last_sequence.split('/')[-1]
|
parts = last_sequence.split('/')
|
||||||
if last_suffix.isdigit():
|
last_month = parts[-2]
|
||||||
new_suffix = f"{last_suffix}a"
|
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:
|
else:
|
||||||
base_num = last_suffix[:-1]
|
# Same month: check for alphabet suffix
|
||||||
last_alpha = last_suffix[-1]
|
alpha_part = ''.join(filter(str.isalpha, last_suffix))
|
||||||
next_alpha = chr(ord(last_alpha) + 1) if last_alpha < 'z' else 'a'
|
if alpha_part:
|
||||||
new_suffix = f"{base_num}{next_alpha}"
|
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:
|
else:
|
||||||
new_suffix = '016'
|
# No previous records at all
|
||||||
|
new_suffix = '001'
|
||||||
|
|
||||||
return f"{base_sequence_prefix}{new_suffix}"
|
return f"{base_sequence_prefix}{new_suffix}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _get_default_lines(self,model,column):
|
def _get_default_lines(self,model,column):
|
||||||
products = self.env[model].search([])
|
products = self.env[model].search([])
|
||||||
|
|
@ -170,9 +191,10 @@ class SOS_FG_Plan(models.Model):
|
||||||
|
|
||||||
|
|
||||||
def send_indent_plan_email(self, email_ids):
|
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')
|
template = self.env.ref('sos_inventory.send_indent_plan_email_template')
|
||||||
if template:
|
if template:
|
||||||
template.email_to = ','.join(email_ids)
|
template.email_to = ','.join(valid_emails)
|
||||||
template.send_mail(self.id, force_send=True)
|
template.send_mail(self.id, force_send=True)
|
||||||
def get_unique_emails(self):
|
def get_unique_emails(self):
|
||||||
group_refs = [
|
group_refs = [
|
||||||
|
|
@ -290,7 +312,22 @@ class SOS_FG_Plan(models.Model):
|
||||||
else:
|
else:
|
||||||
worksheet.write(row, 1, value)
|
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):
|
def action_top_approver_esign_btn(self):
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
result = sequence_util.action_assign_signature(
|
result = sequence_util.action_assign_signature(
|
||||||
|
|
@ -334,11 +371,9 @@ class SOS_FG_Plan(models.Model):
|
||||||
body_html = f"""
|
body_html = f"""
|
||||||
<p>Below <b>Indent Budget</b> is waiting for your Approval</p>
|
<p>Below <b>Indent Budget</b> is waiting for your Approval</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
send_email = self.env['sos_common_scripts']
|
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)
|
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')
|
||||||
sequence_util = self.env['sos_common_scripts']
|
result = send_email.action_assign_signature(
|
||||||
result = sequence_util.action_assign_signature(
|
|
||||||
self,
|
self,
|
||||||
'prepared_by',
|
'prepared_by',
|
||||||
'prepared_on'
|
'prepared_on'
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ class FIR_BRR(models.Model):
|
||||||
sos_record.target_date ,
|
sos_record.target_date ,
|
||||||
date.today()
|
date.today()
|
||||||
)
|
)
|
||||||
|
week_number = min(week_number, 8)
|
||||||
field_name = f'qc_week_{week_number}'
|
field_name = f'qc_week_{week_number}'
|
||||||
fgplan_field_name = f'planned_week_{week_number}'
|
fgplan_field_name = f'planned_week_{week_number}'
|
||||||
# FG Plan update
|
# FG Plan update
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ class sos__grn(models.Model):
|
||||||
print(f"Failed to find report action: {e}")
|
print(f"Failed to find report action: {e}")
|
||||||
|
|
||||||
def action_report_esign_btn(self):
|
def action_report_esign_btn(self):
|
||||||
|
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
sequence_util.action_assign_signature(
|
sequence_util.action_assign_signature(
|
||||||
self,
|
self,
|
||||||
|
|
@ -84,6 +85,7 @@ class sos__grn(models.Model):
|
||||||
'stores_approval_on',
|
'stores_approval_on',
|
||||||
'sos_inventory.sos_scg_group_user'
|
'sos_inventory.sos_scg_group_user'
|
||||||
)
|
)
|
||||||
|
self.generate_supplier_service()
|
||||||
if self.received_goods_type == "Materials":
|
if self.received_goods_type == "Materials":
|
||||||
for item in self.line_ids:
|
for item in self.line_ids:
|
||||||
component = self.env['sos_material'].browse(item.component_id.id)
|
component = self.env['sos_material'].browse(item.component_id.id)
|
||||||
|
|
@ -148,7 +150,180 @@ class sos__grn(models.Model):
|
||||||
def _compute_sequence(self):
|
def _compute_sequence(self):
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.generate_sequence('sos_grn','GRN', 'grn_no')
|
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):
|
class sos_grn_line(models.Model):
|
||||||
_name = 'sos_grn_line'
|
_name = 'sos_grn_line'
|
||||||
_description = 'GRN Material Lines'
|
_description = 'GRN Material Lines'
|
||||||
|
|
@ -169,14 +344,19 @@ class sos_grn_line(models.Model):
|
||||||
@api.depends('received_qty', 'rejected_qty')
|
@api.depends('received_qty', 'rejected_qty')
|
||||||
def _compute_quality(self):
|
def _compute_quality(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.rejected_qty != 0:
|
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||||
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
|
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:
|
else:
|
||||||
record.quality_marks = 10
|
return 10
|
||||||
else:
|
return 0
|
||||||
record.quality_marks = 100
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
|
|
@ -295,14 +475,20 @@ class sos_grn_line_sfg(models.Model):
|
||||||
@api.depends('received_qty', 'rejected_qty')
|
@api.depends('received_qty', 'rejected_qty')
|
||||||
def _compute_sfgquality(self):
|
def _compute_sfgquality(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.rejected_qty != 0:
|
record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty)
|
||||||
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
|
|
||||||
|
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:
|
else:
|
||||||
record.quality_marks = 10
|
return 10
|
||||||
else:
|
return 0
|
||||||
record.quality_marks = 100
|
|
||||||
|
|
||||||
class sos_grn_line_fg(models.Model):
|
class sos_grn_line_fg(models.Model):
|
||||||
_name = 'sos_grn_line_fg'
|
_name = 'sos_grn_line_fg'
|
||||||
|
|
|
||||||
|
|
@ -276,25 +276,26 @@ class SOS_IR(models.Model):
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
iqi_record = self.env['sos_iqi'].create({
|
if item.qty > 0:
|
||||||
'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'),
|
iqi_record = self.env['sos_iqi'].create({
|
||||||
'material_option':True,
|
'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'),
|
||||||
'sfg_option':False,
|
'material_option':True,
|
||||||
'supplier_name': self.supplier_name.id,
|
'sfg_option':False,
|
||||||
'batch_no':item.batch_no,
|
'supplier_name': self.supplier_name.id,
|
||||||
'received_qty':item.qty,
|
'batch_no':item.batch_no,
|
||||||
'uom': item.component_id.uom,
|
'received_qty':item.qty,
|
||||||
'material_name': item.component_id.id,
|
'uom': item.component_id.uom,
|
||||||
'material_code': item.component_id.material_code,
|
'material_name': item.component_id.id,
|
||||||
'in_tact':self.boxes_sealing,
|
'material_code': item.component_id.material_code,
|
||||||
'invoice_no':self.dc_no_char,
|
'in_tact':self.boxes_sealing,
|
||||||
'invoice_date':self.dc_date,
|
'invoice_no':self.dc_no_char,
|
||||||
'ir_id_unique_id':self.id,
|
'invoice_date':self.dc_date,
|
||||||
'from_origin':"Vendor",
|
'ir_id_unique_id':self.id,
|
||||||
'unit_price':item.unit_price
|
'from_origin':"Vendor",
|
||||||
|
'unit_price':item.unit_price
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
# Email part
|
# Email part
|
||||||
body_html = f"""
|
body_html = f"""
|
||||||
<p>Below <b>IQI</b> is waiting for your Approval</p>
|
<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}"
|
subject = f"Inward Approval Request - {self.ir_no}"
|
||||||
send_email = self.env['sos_common_scripts']
|
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
|
# Email part ends
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.action_assign_signature(
|
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 = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True)
|
||||||
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
||||||
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
||||||
|
quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality")
|
||||||
quality_marks = fields.Float(string="Quality Marks")
|
|
||||||
delivery_marks = fields.Float(string="Delivery Marks")
|
delivery_marks = fields.Float(string="Delivery Marks")
|
||||||
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
||||||
report_marks = fields.Float(string="Report 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')
|
@api.depends('rejection_percentage')
|
||||||
def _compute_rejected_percentage_display(self):
|
def _compute_rejected_percentage_display(self):
|
||||||
for record in 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)
|
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)
|
logged_inuser_group=fields.Boolean(string='Group Name',compute='compute_user_grp',store=True)
|
||||||
dept = fields.Many2one('sos_departments',string="Department")
|
dept = fields.Many2one('sos_departments',string="Department")
|
||||||
|
customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name")
|
||||||
purpose = fields.Char(string="Purpose")
|
purpose = fields.Char(string="Purpose")
|
||||||
product_name = fields.Many2one('sos_fg', string='Material/Product Name & No')
|
product_name = fields.Many2one('sos_fg', string='Material/Product Name & No')
|
||||||
indent_ref_no = fields.Many2one('sos_fg_plan',string="Indent Reference 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_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_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")
|
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_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_image = fields.Image(related="stores_approved_by.signature_image",string='Stores Approval Sign',readonly=True)
|
||||||
stores_approved_on = fields.Datetime(string="Approved On")
|
stores_approved_on = fields.Datetime(string="Approved On")
|
||||||
|
|
@ -43,9 +44,9 @@ class sos__mon(models.Model):
|
||||||
('fg', 'FG')
|
('fg', 'FG')
|
||||||
], string='Auto Load Items' ,default=False)
|
], string='Auto Load Items' ,default=False)
|
||||||
material_option = fields.Boolean('Materials', default=True)
|
material_option = fields.Boolean('Materials', default=True)
|
||||||
sfg_option = fields.Boolean('Semi-Finished Goods')
|
sfg_option = fields.Boolean('Semi-Finished Goods', default=False)
|
||||||
fg_option = fields.Boolean('Finished Goods')
|
fg_option = fields.Boolean('Finished Goods', default=False)
|
||||||
order_type = fields.Char(string='order_type',copy=True)
|
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_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_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)
|
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)
|
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")
|
status = fields.Selection([ ('open', 'Open'),('close', 'Closed')], default='open' , string="Status")
|
||||||
active = fields.Boolean(default=True)
|
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')
|
@api.constrains('indent_ref_no', 'auto_load_fg_items')
|
||||||
def _check_duplicate_fg_items_per_indent(self):
|
def _check_duplicate_fg_items_per_indent(self):
|
||||||
for record in 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")
|
uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], string="Uom")
|
||||||
specifications = fields.Char(string="Specifications")
|
specifications = fields.Char(string="Specifications")
|
||||||
quantity = fields.Float(string="Quantity",required=True,default=1)
|
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,
|
company_id = fields.Many2one('res.company', store=True, copy=False,
|
||||||
string="Company",
|
string="Company",
|
||||||
default=lambda self: self.env.user.company_id.id)
|
default=lambda self: self.env.user.company_id.id)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,20 @@ class sos__mrn(models.Model):
|
||||||
default=lambda
|
default=lambda
|
||||||
self: self.env.user.company_id.currency_id.id)
|
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)
|
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')
|
@api.onchange('min_no')
|
||||||
def _onchange_min_no(self):
|
def _onchange_min_no(self):
|
||||||
if self.min_no:
|
if self.min_no:
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ class NCMR_Model(models.Model):
|
||||||
finished_fg_assy = fields.Char()
|
finished_fg_assy = fields.Char()
|
||||||
finished_fg_assy_responsibility = fields.Text(string="Production Assy FG Responsibility")
|
finished_fg_assy_responsibility = fields.Text(string="Production Assy FG Responsibility")
|
||||||
description_of_nc = fields.Html(string="Description of Non-Conformities")
|
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")
|
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 ")
|
comments_on_capa = fields.Html(string="Comments on Corrective / Preventive Action ")
|
||||||
qa_comments=fields.Text(string="QA Comments")
|
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_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_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")
|
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(
|
combined_incoming_doc_ref = fields.Reference(
|
||||||
selection=[
|
selection=[
|
||||||
|
|
@ -120,8 +129,155 @@ class NCMR_Model(models.Model):
|
||||||
supplier_name = fields.Many2one('sos_suppliers',string="Supplier Name",compute="_get_supplier_name")
|
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")
|
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")
|
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")
|
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
|
#Excel Write
|
||||||
def action_ncmr_report_orm_btn(self, from_date, to_date,force_download=True):
|
def action_ncmr_report_orm_btn(self, from_date, to_date,force_download=True):
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
|
|
@ -559,17 +715,18 @@ class NCMR_Model(models.Model):
|
||||||
'sos_inventory.sos_qa_user'
|
'sos_inventory.sos_qa_user'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if all_closed or record.aodr_no:
|
if all_closed or record.aodr_no:
|
||||||
self.status = 'closed'
|
self.status = 'closed'
|
||||||
if self.rework_action == "inhouse":
|
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_record = self.env['sos_iqi'].create({
|
||||||
'iqi_no': send_email.generate_sequence('sos_iqi', 'R-IQI', 'iqi_no'),
|
'iqi_no': send_email.generate_sequence('sos_iqi', 'R-IQI', 'iqi_no'),
|
||||||
'material_option':self.material_option,
|
'material_option':self.material_option,
|
||||||
'sfg_option':self.sfg_option,
|
'sfg_option':self.sfg_option,
|
||||||
'received_qty': self.rejected_qty,
|
'received_qty': self.rejected_qty,
|
||||||
'iqi_type':'rework',
|
'iqi_type':'rework',
|
||||||
'material_name': self.material_name,
|
'material_name': self.material_name.id,
|
||||||
'material_code': self.material_name.material_code,
|
'material_code': self.material_name.material_code,
|
||||||
'sfg_name': self.sfg_name.id,
|
'sfg_name': self.sfg_name.id,
|
||||||
'sfg_code': self.sfg_name.sfg_code,
|
'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,
|
'service_provider_name':self.incoming_doc_ref.service_provider_name.id,
|
||||||
'old_iqi_ref': self.incoming_doc_ref.id,
|
'old_iqi_ref': self.incoming_doc_ref.id,
|
||||||
'ir_id_unique_id':self.incoming_doc_ref.ir_id_unique_id.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':self.incoming_doc_ref.test_report,
|
||||||
# 'test_report_no':self.incoming_doc_ref.test_report_no,
|
# 'test_report_no':self.incoming_doc_ref.test_report_no,
|
||||||
# 'test_report_doc':self.incoming_doc_ref.test_report_doc,
|
# '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
|
# Rework Iteration starts
|
||||||
sos_record = self.env['sos_iqi'].search([('id', '=', self.incoming_doc_ref.id)], limit=1)
|
sos_record = self.env['sos_iqi'].search([('id', '=', self.incoming_doc_ref.id)], limit=1)
|
||||||
if sos_record:
|
if sos_record:
|
||||||
|
|
@ -622,7 +781,27 @@ class NCMR_Model(models.Model):
|
||||||
'sos_inventory.sos_scg_group_user'
|
'sos_inventory.sos_scg_group_user'
|
||||||
)
|
)
|
||||||
if self.rework_action == "inhouse":
|
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"""
|
body_html = f"""
|
||||||
<p>Below <b>NCMR</b> is waiting for your Action</p>
|
<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,
|
'material_name':self.incoming_doc_ref.material_name,
|
||||||
'supplier_name':self.incoming_doc_ref.supplier_name.id,
|
'supplier_name':self.incoming_doc_ref.supplier_name.id,
|
||||||
'goods_type':'Materials',
|
'goods_type':'Materials',
|
||||||
'returned_qty':self.incoming_doc_ref.rejected_qty
|
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||||
|
'rework_type':'outsourcing'
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
if self.material_option:
|
if self.material_option:
|
||||||
|
|
@ -647,7 +827,8 @@ class NCMR_Model(models.Model):
|
||||||
'material_name':self.incoming_doc_ref.material_name,
|
'material_name':self.incoming_doc_ref.material_name,
|
||||||
'supplier_name':self.incoming_doc_ref.supplier_name.id,
|
'supplier_name':self.incoming_doc_ref.supplier_name.id,
|
||||||
'goods_type':'Materials',
|
'goods_type':'Materials',
|
||||||
'returned_qty':self.incoming_doc_ref.rejected_qty
|
'returned_qty':self.incoming_doc_ref.rejected_qty,
|
||||||
|
'rework_type':'outsourcing'
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
orr_record = self.env['sos_sfg_outsourcing_return_register'].create({
|
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,
|
'service_provider_name':self.incoming_doc_ref.service_provider_name,
|
||||||
'sfg_name':self.incoming_doc_ref.sfg_name,
|
'sfg_name':self.incoming_doc_ref.sfg_name,
|
||||||
'goods_type':'SFG',
|
'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
|
self.outsourcing_return_ref_no = orr_record.id
|
||||||
|
|
||||||
|
|
@ -685,6 +867,26 @@ class NCMR_Model(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
def action_qa_esign_btn(self):
|
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:
|
if self.action_group:
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
sequence_util.action_assign_signature(
|
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")
|
ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade")
|
||||||
issue = fields.Char(string="Issue")
|
issue = fields.Char(string="Issue")
|
||||||
corrective_action = fields.Html(string="Corrective Action")
|
corrective_action = fields.Html(string="D5: Permanent Corrective Action")
|
||||||
preventive_action = fields.Html(string="Preventive 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):
|
class NCMR_Model_Line(models.Model):
|
||||||
_name = 'sos_ncmr_line'
|
_name = 'sos_ncmr_line'
|
||||||
|
|
@ -897,3 +1100,18 @@ class NCMR_Model_Line(models.Model):
|
||||||
def _compute_fg_defective_count(self):
|
def _compute_fg_defective_count(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
record.fg_defective_count = len(record.fg_defectives)
|
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>
|
<p>Below <b>Order Delivery Plan</b> is waiting for your Approval</p>
|
||||||
"""
|
"""
|
||||||
send_email = self.env['sos_common_scripts']
|
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
|
# Email part ends
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.action_assign_signature(
|
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 = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True)
|
||||||
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
||||||
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
||||||
|
quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality")
|
||||||
quality_marks = fields.Float(string="Quality Marks")
|
|
||||||
delivery_marks = fields.Float(string="Delivery Marks")
|
delivery_marks = fields.Float(string="Delivery Marks")
|
||||||
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
responsiveness_marks = fields.Float(string="Responsiveness Marks")
|
||||||
report_marks = fields.Float(string="Report 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')
|
@api.depends('rejection_percentage')
|
||||||
def _compute_rejected_percentage_display(self):
|
def _compute_rejected_percentage_display(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ class sos__po(models.Model):
|
||||||
"""
|
"""
|
||||||
subject = f"Purchase Order Approval Request - {self.po_no}"
|
subject = f"Purchase Order Approval Request - {self.po_no}"
|
||||||
send_email = self.env['sos_common_scripts']
|
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
|
# Email part ends
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.action_assign_signature(
|
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 = {}
|
supplier_dict = {}
|
||||||
for record in self.line_ids:
|
for record in self.line_ids:
|
||||||
if record.supplier1_name:
|
if record.final_supplier1_name:
|
||||||
supplier = record.supplier1_name
|
supplier = record.final_supplier1_name
|
||||||
if supplier not in supplier_dict:
|
if supplier not in supplier_dict:
|
||||||
supplier_dict[supplier] = []
|
supplier_dict[supplier] = []
|
||||||
supplier_dict[supplier].append({
|
supplier_dict[supplier].append({
|
||||||
'name': record.material_name,
|
'name': record.material_name,
|
||||||
'product_qty': record.supplier1_qty,
|
'product_qty': record.final_supplier1_qty,
|
||||||
'price_unit': record.supplier1_quoted_price
|
'price_unit': record.final_supplier1_quoted_price
|
||||||
})
|
})
|
||||||
|
|
||||||
if record.supplier2_name:
|
# if record.supplier2_name:
|
||||||
supplier = record.supplier2_name
|
# supplier = record.supplier2_name
|
||||||
if supplier not in supplier_dict:
|
# if supplier not in supplier_dict:
|
||||||
supplier_dict[supplier] = []
|
# supplier_dict[supplier] = []
|
||||||
supplier_dict[supplier].append({
|
# supplier_dict[supplier].append({
|
||||||
'name': record.material_name,
|
# 'name': record.material_name,
|
||||||
'product_qty': record.supplier2_qty,
|
# 'product_qty': record.supplier2_qty,
|
||||||
'price_unit': record.supplier2_quoted_price
|
# 'price_unit': record.supplier2_quoted_price
|
||||||
})
|
# })
|
||||||
|
|
||||||
if record.supplier3_name:
|
# if record.supplier3_name:
|
||||||
supplier = record.supplier3_name
|
# supplier = record.supplier3_name
|
||||||
if supplier not in supplier_dict:
|
# if supplier not in supplier_dict:
|
||||||
supplier_dict[supplier] = []
|
# supplier_dict[supplier] = []
|
||||||
supplier_dict[supplier].append({
|
# supplier_dict[supplier].append({
|
||||||
'name': record.material_name,
|
# 'name': record.material_name,
|
||||||
'product_qty': record.supplier3_qty,
|
# 'product_qty': record.supplier3_qty,
|
||||||
'price_unit': record.supplier3_quoted_price
|
# 'price_unit': record.supplier3_quoted_price
|
||||||
})
|
# })
|
||||||
for x, y in supplier_dict.items():
|
for x, y in supplier_dict.items():
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
po_no = sequence_util.generate_sequence('sos_po','PO', 'po_no')
|
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']
|
'quantity': components['product_qty'],'unit_price': components['price_unit'], 'total_price': components['product_qty'] * components['price_unit']
|
||||||
})
|
})
|
||||||
message = 'Purchase Order(s) successfully generated.'
|
message = 'Purchase Order(s) successfully generated.'
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.client',
|
'type': 'ir.actions.client',
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ class SOS_SalesOrder(models.Model):
|
||||||
string="Product Name",required=True)
|
string="Product Name",required=True)
|
||||||
line_ids = fields.One2many('sos_sales_order_line', 'ref_id',copy=True)
|
line_ids = fields.One2many('sos_sales_order_line', 'ref_id',copy=True)
|
||||||
customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name")
|
customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name")
|
||||||
|
customer_location = fields.Char(string="Customer Location")
|
||||||
lead_time = fields.Datetime(string="Lead Time")
|
lead_time = fields.Datetime(string="Lead Time")
|
||||||
customer_po_no = fields.Char(string="PO No")
|
customer_po_no = fields.Char(string="PO No")
|
||||||
customer_po_date = fields.Datetime(string="PO Date")
|
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)])
|
reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)])
|
||||||
# email_to = reporting_user.login
|
# email_to = reporting_user.login
|
||||||
else:
|
else:
|
||||||
# email_to = "ramachandran.r@sosaley.in"
|
# email_to = "ramachandran.r@sosaley.com"
|
||||||
print("test")
|
print("test")
|
||||||
mail_values = {
|
mail_values = {
|
||||||
'subject': subject,
|
'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")
|
action_taken = fields.Text(string="Action taken or required action to be taken")
|
||||||
Date_of_action_Completed = fields.Datetime(string="Date of action completed")
|
Date_of_action_Completed = fields.Datetime(string="Date of action completed")
|
||||||
status = fields.Selection([('open', 'Open'),('close', 'Closed')], default='open' , string="Status")
|
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):
|
def _generate_id(self):
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.generate_sequence('sos_service_call_log_report','SCLR', 'ref_no')
|
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")
|
ir_no = fields.Many2one('sos_ir', string="Material Inward Ref No")
|
||||||
min_no = fields.Many2one('sos_min', string="Material Issue Ref No")
|
min_no = fields.Many2one('sos_min', string="Material Issue Ref No")
|
||||||
mrn_no = fields.Many2one('sos_mrn', string="Material Return 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")
|
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")
|
returned_qty = fields.Integer(string="Returned Quantity",related="iqi_no.rejected_qty")
|
||||||
remarks = fields.Text(string="Remarks")
|
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):
|
def _generate_id(self):
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.generate_sequence('sos_sfg_outsourcing_return_register','ORR', 'orr_no')
|
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}"
|
subject = f"Work Order Approval Request - {self.wo_no}"
|
||||||
send_email = self.env['sos_common_scripts']
|
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
|
# Email part ends
|
||||||
sequence_util = self.env['sos_common_scripts']
|
sequence_util = self.env['sos_common_scripts']
|
||||||
return sequence_util.action_assign_signature(
|
return sequence_util.action_assign_signature(
|
||||||
|
|
|
||||||
|
|
@ -9,269 +9,296 @@
|
||||||
<field name="binding_type">report</field>
|
<field name="binding_type">report</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<template id="labels_print">
|
<template id="labels_print">
|
||||||
<t t-call="web.html_container">
|
<t t-call="web.html_container">
|
||||||
<t t-foreach="docs" t-as="o">
|
<t t-foreach="docs" t-as="o">
|
||||||
<t t-call="web.basic_layout">
|
<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"/>
|
|
||||||
|
|
||||||
<style>
|
<style type="text/css">
|
||||||
/* 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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Container for each set of tables (FG, SFG, Materials) */
|
/* Avoid clipping; wkhtmltopdf + overflow hidden can break pagination */
|
||||||
.label-set {
|
.page {
|
||||||
page-break-inside: avoid; /* Try to keep the entire set on one page */
|
margin: 3mm;
|
||||||
page-break-after: always; /* Force a page break after each set */
|
padding: 0;
|
||||||
}
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure tables stay within their column */
|
/* Keep each whole set on one page when possible */
|
||||||
.table-container {
|
.label-set {
|
||||||
width: 100%; /* Full width of the column */
|
page-break-inside: avoid !important;
|
||||||
page-break-inside: avoid; /* Prevent table from splitting across pages */
|
break-inside: avoid !important;
|
||||||
box-sizing: border-box;
|
page-break-after: always; /* one set per page; remove if not desired */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clearfix for the last table if odd number of tables */
|
/* Pair wrapper: keep both columns together */
|
||||||
.label-set::after {
|
.pair-block,
|
||||||
content: "";
|
.row,
|
||||||
display: block;
|
.col-6,
|
||||||
clear: both;
|
.table-container,
|
||||||
}
|
.label-table,
|
||||||
|
.label-table tr,
|
||||||
|
.label-table td {
|
||||||
|
page-break-inside: avoid !important;
|
||||||
|
break-inside: avoid !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compact table styling */
|
/* Replace Bootstrap flex with inline-block for PDF reliability */
|
||||||
.label-table {
|
.row {
|
||||||
width: 100%;
|
display: block !important;
|
||||||
border-collapse: collapse;
|
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 {
|
/* Table layout and text wrapping for long content */
|
||||||
font-size: 15px; /* Smaller font size for compactness */
|
.table-container { width: 100%; box-sizing: border-box; }
|
||||||
padding: 2mm; /* Reduced padding */
|
.label-table {
|
||||||
border: 1px solid #000;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
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 {
|
.empty-col { font-size: 10px; text-align: center; padding: 2mm; }
|
||||||
font-weight: bold;
|
|
||||||
font-size: 14px;
|
|
||||||
width:20%
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust Bootstrap row margins for PDF */
|
/* Vendor-ish safety (wkhtmltopdf is WebKit) */
|
||||||
.row {
|
@media print {
|
||||||
margin-left: 0;
|
.pair-block, .row, .col-6, .table-container, .label-table, .label-table tr, .label-table td {
|
||||||
margin-right: 0;
|
-webkit-region-break-inside: avoid;
|
||||||
margin-bottom:40px;
|
}
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
/* Adjust Bootstrap column padding for PDF */
|
<div class="page">
|
||||||
[class*="col-"] {
|
<t t-set="counter" t-value="0"/>
|
||||||
padding-left: 5px;
|
<t t-foreach="range(o.master_quantity)" t-as="line_items">
|
||||||
padding-right: 5px;
|
<t t-set="counter" t-value="counter + 1"/>
|
||||||
}
|
|
||||||
|
|
||||||
/* Style for empty column placeholder */
|
<div class="label-set">
|
||||||
.empty-col {
|
|
||||||
font-size: 10px;
|
|
||||||
text-align: center;
|
|
||||||
padding: 2mm;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<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"/>
|
<!-- FG -->
|
||||||
<t t-foreach="range(o.master_quantity)" t-as="line_items">
|
<t t-set="fg_counter" t-value="0"/>
|
||||||
<t t-set="counter" t-value="counter + 1"/>
|
<t t-foreach="o.line_ids_fg or []" t-as="fg_item">
|
||||||
<div class="label-set">
|
<t t-set="fg_counter" t-value="fg_counter + 1"/>
|
||||||
<!-- Combine all tables into a single list -->
|
<t t-set="all_tables" t-value="all_tables + [(1, fg_item, fg_counter)]"/>
|
||||||
<t t-set="all_tables" t-value="[]"/>
|
</t>
|
||||||
<!-- 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>
|
|
||||||
|
|
||||||
|
<!-- 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 -->
|
<!-- Installation Kit -->
|
||||||
<t t-foreach="range(0, len(all_tables), 2)" t-as="pair_index">
|
<t t-set="installation_kit_counter" t-value="0"/>
|
||||||
<div class="row">
|
<t t-foreach="o.line_ids_installation_kit or []" t-as="installation_kit_item">
|
||||||
<!-- First table in the pair -->
|
<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">
|
<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="category" t-value="table_info[0]"/>
|
||||||
<t t-set="item" t-value="table_info[1]"/>
|
<t t-set="item" t-value="table_info[1]"/>
|
||||||
<t t-set="index" t-value="table_info[2]"/>
|
<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="table-container">
|
||||||
<div class="col-6">
|
<table class="label-table">
|
||||||
<t t-if="pair_index + 1 < len(all_tables)">
|
<tbody>
|
||||||
<t t-set="table_info" t-value="all_tables[pair_index + 1]"/>
|
<tr>
|
||||||
<t t-set="category" t-value="table_info[0]"/>
|
<td class="column">Set No</td>
|
||||||
<t t-set="item" t-value="table_info[1]"/>
|
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
||||||
<t t-set="index" t-value="table_info[2]"/>
|
</tr>
|
||||||
<div class="table-container">
|
<tr>
|
||||||
<table class="label-table">
|
<td class="column">Battery</td>
|
||||||
<tbody>
|
<td><t t-esc="o.batter_or_cells"/></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td class="column">Set No</td>
|
<tr>
|
||||||
<td>#<t t-esc="counter"/>/<t t-esc="o.master_quantity"/></td>
|
<td class="column">No</td>
|
||||||
</tr>
|
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td class="column">Battery</td>
|
<tr>
|
||||||
<td><t t-esc="o.batter_or_cells"/></td>
|
<td class="column">Name</td>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<t t-if="'component_id' in item._fields">
|
||||||
<td class="column">No</td>
|
<t t-if="category in [3, 4]">
|
||||||
<td><t t-esc="category"/>.<t t-esc="index"/></td>
|
<t t-esc="item.component_id.part_no or item.name or 'N/A'"/>
|
||||||
</tr>
|
</t>
|
||||||
<tr>
|
<t t-else="">
|
||||||
<td class="column">Name</td>
|
<t t-esc="item.component_id.name or item.name or 'N/A'"/>
|
||||||
<td>
|
</t>
|
||||||
<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>
|
|
||||||
</t>
|
</t>
|
||||||
</div>
|
<t t-else="">
|
||||||
</t>
|
<t t-esc="item.name or 'N/A'"/>
|
||||||
</t>
|
</t>
|
||||||
</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>
|
</template>
|
||||||
|
|
||||||
</odoo>
|
</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">
|
<table class="table table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<t t-if="o.material_option == True">
|
<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">
|
<tr class="column">
|
||||||
<td>S.No</td>
|
<td>S.No</td>
|
||||||
<td class="column">Material Code</td>
|
<td class="column">Material Code</td>
|
||||||
<td class="column">Name</td>
|
<td class="column">Name</td>
|
||||||
|
<td class="column">Location</td>
|
||||||
<td class="column">In-Hand Quantity</td>
|
<td class="column">In-Hand Quantity</td>
|
||||||
<td class="column">Requested Quantity</td>
|
<td class="column">Requested Quantity</td>
|
||||||
<td class="column">Given Quantity</td>
|
<td class="column">Given Quantity</td>
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
@ -95,6 +97,9 @@
|
||||||
<td><t t-esc="line_items.new_component_id"/></td>
|
<td><t t-esc="line_items.new_component_id"/></td>
|
||||||
</t>
|
</t>
|
||||||
<t t-if="line_items.com_type == 'exits'">
|
<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>
|
<td><t t-esc="line_items.inhand_stock_qty"/></td>
|
||||||
</t>
|
</t>
|
||||||
<t t-if="line_items.com_type == 'new'">
|
<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_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_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_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,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_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
|
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_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_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,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_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_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
|
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_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_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_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"/>
|
<field name="perm_unlink" eval="0"/>
|
||||||
</record>
|
</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>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,12 @@
|
||||||
<field name="category_id"
|
<field name="category_id"
|
||||||
ref="sos_inventory.module_category_sos_inventory"/>
|
ref="sos_inventory.module_category_sos_inventory"/>
|
||||||
</record>
|
</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 -->
|
<!-- Logistics Group -->
|
||||||
<record id="sos_logistics_user" model="res.groups">
|
<record id="sos_logistics_user" model="res.groups">
|
||||||
<field name="name">Logistics User</field>
|
<field name="name">Logistics User</field>
|
||||||
|
|
@ -97,7 +103,7 @@
|
||||||
<field name="category_id"
|
<field name="category_id"
|
||||||
ref="sos_inventory.module_category_sos_inventory"/>
|
ref="sos_inventory.module_category_sos_inventory"/>
|
||||||
</record>
|
</record>
|
||||||
<!-- Finance Group -->
|
<!-- Haelthcare Group -->
|
||||||
<record id="sos_healthcare_user" model="res.groups">
|
<record id="sos_healthcare_user" model="res.groups">
|
||||||
<field name="name">Healthcare User</field>
|
<field name="name">Healthcare User</field>
|
||||||
<field name="category_id"
|
<field name="category_id"
|
||||||
|
|
@ -121,6 +127,17 @@
|
||||||
<field name="category_id"
|
<field name="category_id"
|
||||||
ref="sos_inventory.module_category_sos_inventory"/>
|
ref="sos_inventory.module_category_sos_inventory"/>
|
||||||
</record>
|
</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>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,13 @@ body{
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-family: sans-serif;
|
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 {
|
.btn-primary {
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
background-color: #71639e !important;
|
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"
|
<menuitem id="mop_forms_menu_root"
|
||||||
name="MOP FORMS"
|
name="MOP FORMS"
|
||||||
parent="forms_menu_root"/>
|
parent="forms_menu_root"/>
|
||||||
<!-- CE Forms -->
|
|
||||||
<menuitem id="ce_forms_menu_root"
|
|
||||||
name="CE FORMS"
|
|
||||||
parent="forms_menu_root"/>
|
|
||||||
<!-- End CE Forms -->
|
<!-- End CE Forms -->
|
||||||
<menuitem id="mme_forms_menu_root"
|
<menuitem id="mme_forms_menu_root"
|
||||||
name="MME FORMS"
|
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="helper_field" invisible="1"/>
|
||||||
<field name="sub_fg_name" domain="[('id', 'in', helper_field)]"/>
|
<field name="sub_fg_name" domain="[('id', 'in', helper_field)]"/>
|
||||||
<field name="batch_no"/>
|
<field name="batch_no"/>
|
||||||
|
<field name="invoice_no"/>
|
||||||
|
<field name="batch_release_date"/>
|
||||||
|
<field name="quantity_dispatched"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Data Collection">
|
<page string="D0: Defective Details/Symptom">
|
||||||
<group>
|
|
||||||
<group>
|
<group>
|
||||||
|
<!-- <group>
|
||||||
<field name="invoice_no"/>
|
<field name="invoice_no"/>
|
||||||
<field name="batch_release_date"/>
|
<field name="batch_release_date"/>
|
||||||
<field name="quantity_dispatched"/>
|
<field name="quantity_dispatched"/>
|
||||||
</group>
|
</group> -->
|
||||||
<group>
|
<group>
|
||||||
<field name="brcoa_no"/>
|
<!-- <field name="brcoa_no"/>
|
||||||
<field name="brcoa_date"/>
|
<field name="brcoa_date"/> -->
|
||||||
<field name="other_complaints"/>
|
<field name="other_complaints"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
@ -102,13 +104,13 @@
|
||||||
</div>
|
</div>
|
||||||
</templates>
|
</templates>
|
||||||
</page>
|
</page>
|
||||||
<page string="Investigation Details">
|
<page string="D0:Investigation Details">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="device_failed_to_meet_specification"/>
|
<field name="device_failed_to_meet_specification"/>
|
||||||
<field name="labelling_error"/>
|
<field name="labelling_error"/>
|
||||||
<field name="ifu"/>
|
<field name="ifu"/>
|
||||||
<field name="interin_containment_actions"/>
|
<!-- <field name="interin_containment_actions"/> -->
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="packaging_details"/>
|
<field name="packaging_details"/>
|
||||||
|
|
@ -140,8 +142,59 @@
|
||||||
</div>
|
</div>
|
||||||
</templates>
|
</templates>
|
||||||
</page>
|
</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"/>
|
<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>
|
<templates>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
|
|
@ -183,7 +236,35 @@
|
||||||
</templates>
|
</templates>
|
||||||
</page>
|
</page>
|
||||||
<page string="CAPA">
|
<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>
|
<group>
|
||||||
<field name="corrective_action"/>
|
<field name="corrective_action"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
@ -193,7 +274,7 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="capa_status"/>
|
<field name="capa_status"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group> -->
|
||||||
<templates>
|
<templates>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6"></div>
|
<div class="col-6"></div>
|
||||||
|
|
@ -217,7 +298,7 @@
|
||||||
</div>
|
</div>
|
||||||
</templates>
|
</templates>
|
||||||
</page>
|
</page>
|
||||||
<page string="Response">
|
<page string="D8: Team Recognition">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="response_sent_date"/>
|
<field name="response_sent_date"/>
|
||||||
|
|
@ -228,7 +309,16 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="qa_comments"/>
|
<field name="qa_comments"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="capa_status"/>
|
||||||
</group>
|
</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>
|
<templates>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6"></div>
|
<div class="col-6"></div>
|
||||||
|
|
@ -266,9 +356,5 @@
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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>
|
<notebook>
|
||||||
<page string="Outsourcing" invisible="dc_type != 'out_souce_return' and dc_type != 'out_souce_noreturn'">
|
<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">
|
<tree editable="bottom">
|
||||||
<field name="component_id"/>
|
<field name="component_id"/>
|
||||||
<field name="display_name"/>
|
<field name="display_name"/>
|
||||||
|
|
@ -97,7 +97,7 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
<page string="Materials" invisible="dc_type == 'out_souce_return' or dc_type == 'out_souce_noreturn'">
|
<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">
|
<tree editable="bottom">
|
||||||
<field name="component_id"/>
|
<field name="component_id"/>
|
||||||
<field name="display_name"/>
|
<field name="display_name"/>
|
||||||
|
|
@ -143,7 +143,10 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
||||||
|
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
|
<page string="Logistice Details">
|
||||||
|
<field name="courier"/>
|
||||||
|
<field name="lr_no"/>
|
||||||
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
|
|
||||||
<br></br>
|
<br></br>
|
||||||
|
|
@ -217,7 +220,7 @@ name="action_report_dc_btn"><i class="fa fa-print"></i> Print</button>
|
||||||
</record>
|
</record>
|
||||||
<menuitem id="delivery_challan_menu"
|
<menuitem id="delivery_challan_menu"
|
||||||
name="Delivery Challan (DC)"
|
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>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,7 @@
|
||||||
</record>
|
</record>
|
||||||
<menuitem id="sos_deliverables_boq_menu"
|
<menuitem id="sos_deliverables_boq_menu"
|
||||||
name="Deliverables List / BOQ"
|
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>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
<sheet>
|
<sheet>
|
||||||
<group>
|
<group>
|
||||||
<field name="fg_name"/>
|
<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_name"/>
|
||||||
<field name="customer_location"/> -->
|
<field name="customer_location"/> -->
|
||||||
</group>
|
</group>
|
||||||
|
|
@ -91,6 +92,7 @@
|
||||||
<tree string="Deliverables">
|
<tree string="Deliverables">
|
||||||
<field name="fg_name"/>
|
<field name="fg_name"/>
|
||||||
<field name="communication_type"/>
|
<field name="communication_type"/>
|
||||||
|
<field name="slave_type"/>
|
||||||
<field name="fg_ids"/>
|
<field name="fg_ids"/>
|
||||||
<field name="sfg_ids"/>
|
<field name="sfg_ids"/>
|
||||||
<field name="material_ids"/>
|
<field name="material_ids"/>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
<field name="model">sos_departments</field>
|
<field name="model">sos_departments</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree>
|
<tree>
|
||||||
|
<field name="short_form"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
|
|
@ -20,9 +21,18 @@
|
||||||
<field name="model">sos_departments</field>
|
<field name="model">sos_departments</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Model Form">
|
<form string="Model Form">
|
||||||
<sheet>
|
<sheet>
|
||||||
<group><field name="name"/></group>
|
<group><field name="name"/></group>
|
||||||
</sheet>
|
<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>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
||||||
|
|
@ -216,13 +216,15 @@
|
||||||
|
|
||||||
<field name="payment_status"/>
|
<field name="payment_status"/>
|
||||||
<field name="billing_address"/>
|
<field name="billing_address"/>
|
||||||
|
<field name="shipping_address"/>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="invoice_no"/>
|
<field name="invoice_no"/>
|
||||||
|
<field name="invoice_date"/>
|
||||||
|
<field name="warranty"/>
|
||||||
<field name="gst_no"/>
|
<field name="gst_no"/>
|
||||||
|
|
||||||
<field name="shipping_address"/>
|
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
decoration-warning="indent_status == 'hold'"
|
decoration-warning="indent_status == 'hold'"
|
||||||
decoration-danger="indent_status == 'open' or indent_status == 'cancel'"
|
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"/>
|
<field name="approved_by" string="Approved By" widget="many2one_avatar_user"/>
|
||||||
|
|
||||||
</tree>
|
</tree>
|
||||||
|
|
@ -184,7 +186,8 @@
|
||||||
<templates>
|
<templates>
|
||||||
<div class="row" style="margin-top:100px">
|
<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;">
|
<tr style="border-bottom: solid 1px #ccc;">
|
||||||
<td style="padding: 8px;" class="column"><b>Prepared By Sign</b>
|
<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>
|
<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>
|
<td><field name="prepared_by" readonly="1"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table> </div>
|
</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">
|
<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;">
|
<tr style="border-bottom: solid 1px #ccc;">
|
||||||
<td style="padding: 8px;" class="column"><b>Top Management Approval Sign</b>
|
<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>
|
<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"
|
name="Indent Plan"
|
||||||
parent="indent_menu_root"
|
parent="indent_menu_root"
|
||||||
action = "action_fg_plan_list"/>
|
action = "action_fg_plan_list"/>
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@
|
||||||
<field name="fg_type" string="Type" icon="fa-list-ul" enable_counters="1"/>
|
<field name="fg_type" string="Type" icon="fa-list-ul" enable_counters="1"/>
|
||||||
|
|
||||||
</searchpanel>
|
</searchpanel>
|
||||||
|
<field name="display_name" string="Display Name"/>
|
||||||
<field name="name" string="Name"/>
|
<field name="name" string="Name"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
<!-- Menuitem -->
|
<!-- 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>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem id="sos_master_list_customer_menu" name="Customer Property Master"
|
<menuitem id="sos_master_list_customer_menu" name="Customer Property Master"
|
||||||
parent="scg_forms_menu_root" action="action_sos_master_list_customer_form_list" />
|
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"/>
|
||||||
<!-- 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" -->
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
<field name="ref_no" optional="hide"/>
|
<field name="ref_no" optional="hide"/>
|
||||||
<field name="stores_approval_name" string="Stores Approved By" widget="many2one_avatar_user"/>
|
<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="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>
|
<span>Not Issued</span>
|
||||||
</div>
|
</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">
|
<tree editable="bottom" decoration-success="quantity <= issued_quantity and quantity != 0" decoration-warning="quantity > issued_quantity and issued_quantity != 0">
|
||||||
|
|
||||||
<field name="s_no"/>
|
<field name="s_no"/>
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
<field name="mon_date"/>
|
<field name="mon_date"/>
|
||||||
<field name="min_no" string="Issue Note Ref No" />
|
<field name="min_no" string="Issue Note Ref No" />
|
||||||
<field name="purpose"/>
|
<field name="purpose"/>
|
||||||
|
<field name="customer_name" groups="sos_inventory.sos_ce_user"/>
|
||||||
<field name="approx_value" string="Order Value" optional="hide"/>
|
<field name="approx_value" string="Order Value" optional="hide"/>
|
||||||
<field name="prepared_by_name" string="Prepared By" widget="many2one_avatar_user"/>
|
<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"/>
|
<field name="dept_in_charge_name" string="Department In-Charge" widget="many2one_avatar_user"/>
|
||||||
|
|
@ -59,9 +60,9 @@
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
<widget name="web_ribbon" text="Open" bg_color="bg-danger" invisible="status == 'close'"/>
|
<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="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>
|
<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;">
|
<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="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="set_qty" invisible="auto_load == 'fg' or auto_load == False" />
|
||||||
<field name="fg_set_qty" invisible="auto_load != 'fg'" />
|
<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>
|
</group>
|
||||||
<!-- Second Column -->
|
<!-- Second Column -->
|
||||||
|
|
@ -110,7 +112,7 @@
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Materials" invisible="material_option == False">
|
<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>
|
<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">
|
<tree editable="bottom">
|
||||||
<field name="s_no"/>
|
<field name="s_no"/>
|
||||||
<field name="com_type" decoration-info="com_type == 'new'"/>
|
<field name="com_type" decoration-info="com_type == 'new'"/>
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
|
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Materials" invisible="material_option == False">
|
<page string="Materials" invisible="material_option == False">
|
||||||
<field name="line_ids_material">
|
<field name="line_ids_material" readonly="stores_approved_by">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="component_id" string="Material Name"/>
|
<field name="component_id" string="Material Name"/>
|
||||||
<field name="approx_price"/>
|
<field name="approx_price"/>
|
||||||
|
|
@ -104,10 +104,11 @@
|
||||||
<field name="approx_value" widget="monetary" options="{'currency_field': 'currency_id'}" class="oe_inline"/>
|
<field name="approx_value" widget="monetary" options="{'currency_field': 'currency_id'}" class="oe_inline"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br></br>
|
<br></br> <br></br>
|
||||||
|
|
||||||
</page>
|
</page>
|
||||||
<page string="Semi-Finished Goods" invisible="sfg_option == False">
|
<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">
|
<tree editable="bottom">
|
||||||
<field name="component_id"/>
|
<field name="component_id"/>
|
||||||
<field name="qp_no"/>
|
<field name="qp_no"/>
|
||||||
|
|
@ -128,7 +129,7 @@
|
||||||
|
|
||||||
</page>
|
</page>
|
||||||
<page string="Finished Goods" invisible="fg_option == False">
|
<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">
|
<tree editable="bottom">
|
||||||
<field name="component_id"/>
|
<field name="component_id"/>
|
||||||
<field name="batch_No"/>
|
<field name="batch_No"/>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
<tree>
|
<tree>
|
||||||
<header>
|
<header>
|
||||||
<button name="%(action_ncmr_wizard)d" string="Report" type="action" class="oe_highlight" display="always"/>
|
<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>
|
</header>
|
||||||
<field name="ncmr_no"/>
|
<field name="ncmr_no"/>
|
||||||
<field name="ncmr_date"/>
|
<field name="ncmr_date"/>
|
||||||
|
|
@ -59,17 +60,20 @@
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
<br></br>
|
<br></br>
|
||||||
|
|
||||||
<!-- Topmost Group -->
|
<!-- Topmost Group -->
|
||||||
<group>
|
<group>
|
||||||
<!-- First Column -->
|
<!-- First Column -->
|
||||||
<group>
|
<group>
|
||||||
<field name="rca_required" invisible="1"/>
|
<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="status" invisible="1"/>
|
||||||
<field name="department"/>
|
<field name="department"/>
|
||||||
<field name="ncmr_no"/>
|
<field name="ncmr_no"/>
|
||||||
<field name="ncmr_type" invisible="1"/>
|
<field name="ncmr_type" invisible="1"/>
|
||||||
<field name="ncmr_date"/>
|
<field name="ncmr_date"/>
|
||||||
<field name="outsourcing_return_ref_no" invisible="rework_action == 'inhouse'"/>
|
<field name="outsourcing_return_ref_no"/>
|
||||||
</group>
|
</group>
|
||||||
<!-- Second Column -->
|
<!-- Second Column -->
|
||||||
<group>
|
<group>
|
||||||
|
|
@ -77,7 +81,7 @@
|
||||||
|
|
||||||
<field name="fg_name"/>
|
<field name="fg_name"/>
|
||||||
<field name="fg_category" invisible="1"/>
|
<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="batch_no"/>
|
||||||
<field name="rejected_qty" invisible="fg_option != True"/>
|
<field name="rejected_qty" invisible="fg_option != True"/>
|
||||||
|
|
@ -109,7 +113,7 @@
|
||||||
border-radius: 5px;margin-bottom: 20px;"/>
|
border-radius: 5px;margin-bottom: 20px;"/>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Defective Details" invisible="fg_option != True">
|
<page string="D0: Defective Details/Symptom" invisible="fg_option != True">
|
||||||
|
|
||||||
<field name="line_ids">
|
<field name="line_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
|
|
@ -126,7 +130,7 @@
|
||||||
<label for="fg_unique_defect_count"/><field name="fg_unique_defect_count" nolabel="1" readonly="True"/>
|
<label for="fg_unique_defect_count"/><field name="fg_unique_defect_count" nolabel="1" readonly="True"/>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Defective Details" invisible="sfg_option != True">
|
<page string="D0: Defective Details/Symptom" invisible="sfg_option != True">
|
||||||
|
|
||||||
<field name="line_ids">
|
<field name="line_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
|
|
@ -144,7 +148,7 @@
|
||||||
<label for="unique_defect_count"/><field name="unique_defect_count" nolabel="1" readonly="True"/>
|
<label for="unique_defect_count"/><field name="unique_defect_count" nolabel="1" readonly="True"/>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Defective Details" invisible="material_option != True">
|
<page string="D0: Defective Details/Symptom" invisible="material_option != True">
|
||||||
|
|
||||||
<field name="line_ids">
|
<field name="line_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
|
|
@ -161,7 +165,7 @@
|
||||||
<label for="material_unique_defect_count"/><field name="material_unique_defect_count" nolabel="1" readonly="True"/>
|
<label for="material_unique_defect_count"/><field name="material_unique_defect_count" nolabel="1" readonly="True"/>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Document Reference">
|
<page string="D1: Team Formation & Document Reference">
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -173,8 +177,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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">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><field name="return_incoming_resposibility"/></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>
|
<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">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">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">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><field name="returned_fg_responsibility"/></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><field name="finished_fg_assy_responsibility"/></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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</page>
|
</page>
|
||||||
<page string="Description of NC">
|
<page string="D2:Problem Description">
|
||||||
<field name="description_of_nc"/>
|
<!-- <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>
|
||||||
<page string="Root Cause of NC" invisible="rca_required == 'no'">
|
|
||||||
<field name="root_cause_of_nc"/>
|
<page string="D3: Containment Action" >
|
||||||
</page>
|
|
||||||
<page string="Containment Action" invisible="rca_required == 'no'">
|
|
||||||
<field name="containment_action_of_nc"/>
|
<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>
|
||||||
|
|
||||||
|
<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'">
|
<page string="CAPA" invisible="rca_required == 'no'">
|
||||||
<field name="capa_line_ids">
|
<field name="capa_line_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="issue"/>
|
<field name="issue"/>
|
||||||
<field name="corrective_action"/>
|
<field name="corrective_action"/>
|
||||||
|
<field name="implement_validate_corrective_action"/>
|
||||||
<field name="preventive_action"/>
|
<field name="preventive_action"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</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>
|
||||||
<page string="Comments on CAPA" invisible="rca_required == 'no'">
|
<!-- <page string="Comments on CAPA" invisible="rca_required == 'no'">
|
||||||
<field name="comments_on_capa"/>
|
<field name="comments_on_capa"/>
|
||||||
</page>
|
</page> -->
|
||||||
<page string="Status" invisible="sfg_option != True">
|
<page string="D8: Team Recognition" invisible="sfg_option != True">
|
||||||
<field name="defective_status_ids">
|
<field name="defective_status_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="defective_id"/>
|
<field name="defective_id"/>
|
||||||
<field name="aodr_no"/>
|
<field name="aodr_no"/>
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</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>
|
||||||
<page string="Status" invisible="material_option != True">
|
<page string="D8: Team Recognition" invisible="material_option != True">
|
||||||
<field name="defective_status_ids">
|
<field name="defective_status_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="material_defective_id"/>
|
<field name="material_defective_id"/>
|
||||||
<field name="aodr_no"/>
|
<field name="aodr_no"/>
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</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>
|
||||||
<page string="Status" invisible="fg_option != True">
|
<page string="D8: Team Recognition" invisible="fg_option != True">
|
||||||
<field name="defective_status_ids">
|
<field name="defective_status_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="fg_defective_id"/>
|
<field name="fg_defective_id"/>
|
||||||
<field name="aodr_no"/>
|
<field name="aodr_no"/>
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</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>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -424,6 +497,8 @@
|
||||||
</record>
|
</record>
|
||||||
<menuitem id="ncmr_menu"
|
<menuitem id="ncmr_menu"
|
||||||
name="Non-Conforming Material Report (NCMR)"
|
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>
|
</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="lead_time"/>
|
||||||
<field name="customer_po_no"/>
|
<field name="customer_po_no"/>
|
||||||
<field name="customer_po_date"/>
|
<field name="customer_po_date"/>
|
||||||
|
<field name="customer_location"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<!-- <field name="email_to" widget="many2many_tags"/> -->
|
<!-- <field name="email_to" widget="many2many_tags"/> -->
|
||||||
|
|
@ -29,6 +30,7 @@
|
||||||
<page string="Commercial Details">
|
<page string="Commercial Details">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
|
|
||||||
<field name="purpose_of_delivery"/>
|
<field name="purpose_of_delivery"/>
|
||||||
<field name="payment_status"/>
|
<field name="payment_status"/>
|
||||||
<field name="payment_terms"/>
|
<field name="payment_terms"/>
|
||||||
|
|
@ -38,6 +40,8 @@
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
|
<field name="customer_name"/>
|
||||||
|
<field name="customer_location"/>
|
||||||
<field name="billing_address"/>
|
<field name="billing_address"/>
|
||||||
<field name="shipping_address"/>
|
<field name="shipping_address"/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@
|
||||||
<field name="ref_no"/>
|
<field name="ref_no"/>
|
||||||
<field name="customer_name"/>
|
<field name="customer_name"/>
|
||||||
<field name="contact_person"/>
|
<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="location"/>
|
||||||
<field name="mobile_no"/>
|
<field name="mobile_no"/>
|
||||||
<field name="email"/>
|
<field name="email"/>
|
||||||
|
|
@ -74,9 +78,6 @@
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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>
|
</odoo>
|
||||||
|
|
@ -46,15 +46,16 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="orr_no"/>
|
<field name="orr_no"/>
|
||||||
<field name="iqi_no"/>
|
<field name="iqi_no"/>
|
||||||
|
<field name="rework_type"/>
|
||||||
<field name="goods_type"/>
|
<field name="goods_type"/>
|
||||||
<field name="service_provider_name" invisible="goods_type != 'SFG'"/>
|
<field name="service_provider_name" invisible="goods_type != 'SFG' or rework_type !='outsourcing'"/>
|
||||||
<field name="supplier_name" invisible="goods_type != 'Materials'"/>
|
<field name="supplier_name" invisible="goods_type != 'Materials' or rework_type !='outsourcing'"/>
|
||||||
<field name="returned_qty"/>
|
<field name="returned_qty"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="iqi_date"/>
|
<field name="iqi_date"/>
|
||||||
<field name="sfg_name" invisible="goods_type != 'SFG'"/>
|
<field name="sfg_name" invisible="goods_type != 'SFG' or rework_type !='outsourcing'"/>
|
||||||
<field name="material_name" invisible="goods_type != 'Materials'"/>
|
<field name="material_name" invisible="goods_type != 'Materials' or rework_type !='outsourcing'"/>
|
||||||
<field name="remarks"/>
|
<field name="remarks"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<field name="res_model">sos_wo</field>
|
<field name="res_model">sos_wo</field>
|
||||||
<field name="view_mode">tree,form,kanban</field>
|
<field name="view_mode">tree,form,kanban</field>
|
||||||
</record>
|
</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="name">📝 Amend</field>
|
||||||
<field name="model_id" ref="model_sos_wo"/>
|
<field name="model_id" ref="model_sos_wo"/>
|
||||||
<field name="binding_model_id" ref="model_sos_wo"/>
|
<field name="binding_model_id" ref="model_sos_wo"/>
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
action = model.action_amend()
|
action = model.action_amend()
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="sos_wo_view_panel" model="ir.ui.view">
|
<record id="sos_wo_view_panel" model="ir.ui.view">
|
||||||
<field name="name">sos_wo.search</field>
|
<field name="name">sos_wo.search</field>
|
||||||
<field name="model">sos_wo</field>
|
<field name="model">sos_wo</field>
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue