leads of sales and inside sales matched

This commit is contained in:
Deena 2025-08-01 22:14:43 +05:30
parent 590d716eec
commit 0565053d7a
43 changed files with 646 additions and 199 deletions

View File

@ -15,6 +15,7 @@
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'security/record_rules.xml', 'security/record_rules.xml',
'data/lead_source_data.xml',
'views/menu.xml', 'views/menu.xml',
'views/sos_inside_sales_leads_view.xml', 'views/sos_inside_sales_leads_view.xml',
'views/sos_target_tracker_view.xml', 'views/sos_target_tracker_view.xml',

View File

@ -0,0 +1,16 @@
<odoo>
<data noupdate="1">
<record id="lead_source_website" model="lead_source">
<field name="name">Website</field>
</record>
<record id="lead_source_expo" model="lead_source">
<field name="name">Expo</field>
</record>
<record id="lead_source_cold_calls" model="lead_source">
<field name="name">Cold Calls</field>
</record>
<record id="lead_source_linkedin" model="lead_source">
<field name="name">Linkedin</field>
</record>
</data>
</odoo>

View File

@ -20,31 +20,44 @@ class sos_inside_sales_leads(models.Model):
moved_on = fields.Date(string="Moved On") moved_on = fields.Date(string="Moved On")
location = fields.Char(string="Location") location = fields.Char(string="Location")
website_url = fields.Char(string="Website URL") website_url = fields.Char(string="Website URL")
vertical_domain = fields.Many2one('sos_vertical_domain',string="Domain / Industry", ondelete="cascade") vertical_domain = fields.Many2many('sos_vertical_domain',string="Domain / Industry", ondelete="cascade")
line_ids_contacts = fields.One2many('sos_leads_contact_lines', 'ref_id', string="Contact Details",copy=True) line_ids_contacts = fields.One2many('sos_leads_contact_lines', 'ref_id', string="Contact Details",copy=True)
remarks=fields.Text(string="Remarks") remarks=fields.Text(string="Remarks")
linkedin_profile = fields.Char(string="Linkedin profile") linkedin_profile = fields.Char(string="Linkedin profile")
products = fields.Selection( # products = fields.Selection(
# [
# ('BHMS 1.2V', 'BHMS 1.2V'),
# ('BHMS 2V', 'BHMS 2V'),
# ('BHMS 12V', 'BHMS 12V'),
# ('BMS-HV', 'BMS-HV'),
# ('BMS-LV 100A', 'BMS-LV 100A'),
# ('BMS-LV 40A', 'BMS-LV 40A'),
# ('SBMS 55A', 'SBMS 55A'),
# ('MC 250W', 'MC 250W'),
# ('HeartTarang', 'HeartTarang')
# ],
# string="Product Interested In")
products_interested = fields.Many2many('sos_products',string="Product Interested In")
service = fields.Selection(
[ [
('BHMS 1.2V', 'BHMS 1.2V'), ('Product', 'Products'),
('BHMS 2V', 'BHMS 2V'), ('Project', 'Projects')
('BHMS 12V', 'BHMS 12V'),
('BMS-HV', 'BMS-HV'),
('BMS-LV 100A', 'BMS-LV 100A'),
('BMS-LV 40A', 'BMS-LV 40A'),
('SBMS 55A', 'SBMS 55A'),
('MC 250W', 'MC 250W'),
('HeartTarang', 'HeartTarang')
], ],
string="Product Interested In") string="Service Type",default="Product")
source = fields.Selection( project_name= fields.Many2one('sos_projects',string="Project Name")
status = fields.Selection(
[ [
('website', 'Website'), ('Open', 'Open'),
('expo', 'Expo'), ('Close', 'Close'),
('cold_calls', 'Cold Calls'), ('New', 'New'),
('linkedin', 'Linkedin') ('In-Progress', 'In-Progress'),
('Qualified', 'Qualified'),
('Unqualified', 'Unqualified')
], ],
string="Source") string="Status",default="New")
new_source = fields.Many2one('lead_source', string="Source")
meeting_scheduled = fields.Selection( meeting_scheduled = fields.Selection(
[ [
('Online', 'Online'), ('Online', 'Online'),
@ -52,12 +65,24 @@ class sos_inside_sales_leads(models.Model):
], ],
string="Meeting Schedule") string="Meeting Schedule")
expo_name = fields.Char(string="Expo Name") expo_name = fields.Char(string="Expo Name")
move_to_sales = fields.Many2many('res.users',string="Move Lead to") move_to_sales = fields.Many2many('res.users',string="Move Lead to", domain=lambda self: [('groups_id', 'in', self.env.ref('sos_inventory.sos_sales_user').ids + self.env.ref('sos_inventory.sos_ce_head').ids)])
cc_mail = fields.Many2one('res.users',string="CC to") cc_mail = fields.Many2one('res.users',string="CC to", domain=lambda self: [('groups_id', 'in', self.env.ref('sos_inventory.sos_sales_user').ids + self.env.ref('sos_inventory.sos_ce_head').ids)])
move_div_display = fields.Boolean(default=False,string="Moved to Sales") move_div_display = fields.Boolean(default=False,string="Moved to Sales")
line_ids = fields.One2many('sos_inside_sales_activities_line', 'ref_id', string="Action") line_ids = fields.One2many('sos_inside_sales_activities_line', 'ref_id', string="Action")
week = fields.Char(string="Week") week = fields.Char(string="Week")
reporting_to = fields.Many2one('res.users', string='Reporting To') reporting_to = fields.Many2one('res.users', string='Reporting To')
sales_type = fields.Selection(
[
('Domestic', 'Domestic'),
('International', 'International')
],
string="Sales Type",default="Domestic")
country = fields.Many2one(
'res.country',
string='Country',
default=lambda self: self.env['res.country'].search([('code', '=', 'IN')], limit=1)
)
@api.model @api.model
def create(self, vals): def create(self, vals):
create_uid = vals.get('create_uid', self.env.uid) create_uid = vals.get('create_uid', self.env.uid)
@ -122,14 +147,29 @@ class sos_inside_sales_leads(models.Model):
'transferred_on': fields.Date.today(), 'transferred_on': fields.Date.today(),
'location':self.location, 'location':self.location,
'website_url':self.website_url, 'website_url':self.website_url,
'vertical_domain':self.vertical_domain.id, 'vertical_domain': [(6, 0, self.vertical_domain.ids)],
'linkedin_profile':self.linkedin_profile, 'linkedin_profile':self.linkedin_profile,
'products':self.products, 'products_interested':[(6, 0,self.products_interested.ids)],
'source':'inside_sales', 'source':'inside_sales',
'expo_name':self.expo_name, 'expo_name':self.expo_name,
'lead_generated_by':self.env.user.id 'lead_generated_by':self.env.user.id,
'sales_type':self.sales_type,
'interested_in':self.service,
'project_name':self.project_name.id
}) })
if new_record: if new_record:
if self.line_ids_contacts:
for contact in self.line_ids_contacts:
self.env['sos_leads_customer_contact_lines'].create({
'ref_id': new_record.id,
'name': contact.name,
'dept': contact.dept,
'email': contact.email,
'mobile_number': contact.mobile_number,
'set_as_primary': contact.set_as_primary,
'linkedin_profile': contact.linkedin_profile,
'remarks': contact.remarks
})
self.move_div_display = True self.move_div_display = True
return { return {
'type': 'ir.actions.client', 'type': 'ir.actions.client',
@ -151,6 +191,8 @@ class SOS_Leads_Line(models.Model):
email = fields.Char(string="Email Id") email = fields.Char(string="Email Id")
mobile_number = fields.Char(string="Contact Number") mobile_number = fields.Char(string="Contact Number")
set_as_primary = fields.Boolean(string="Set Primary") set_as_primary = fields.Boolean(string="Set Primary")
linkedin_profile = fields.Char(string="LinkedIn Profile")
remarks = fields.Text(string="Remarks")
@api.model @api.model
def create(self, vals): def create(self, vals):
record = super(SOS_Leads_Line, self).create(vals) record = super(SOS_Leads_Line, self).create(vals)
@ -176,4 +218,11 @@ class sos_inside_sales_activities_lines(models.Model):
ref_id = fields.Many2one('sos_inside_sales_leads', ondelete="cascade") ref_id = fields.Many2one('sos_inside_sales_leads', ondelete="cascade")
action_date = fields.Date(string="Action Date") action_date = fields.Date(string="Action Date")
remarks = fields.Text(string="Remarks") next_action_on = fields.Date(string="Next Action On")
remarks = fields.Text(string="Remarks")
class LeadSource(models.Model):
_name = 'lead_source'
_description = 'Lead Source Master'
name = fields.Char(string="Source Name", required=True)

View File

@ -4,3 +4,5 @@ access_sos_inside_sales_activities_line,sos_inside_sales_activities_line access,
access_sos_target_tracker,sos_target_tracker access,model_sos_target_tracker,base.group_user,1,1,1,1 access_sos_target_tracker,sos_target_tracker access,model_sos_target_tracker,base.group_user,1,1,1,1
access_sos_leads_contact_lines,sos_leads_contact_lines access,model_sos_leads_contact_lines,base.group_user,1,1,1,1 access_sos_leads_contact_lines,sos_leads_contact_lines access,model_sos_leads_contact_lines,base.group_user,1,1,1,1
access_action_leads_report_wizard,action_leads_report_wizard access,model_action_leads_report_wizard,base.group_user,1,1,1,1 access_action_leads_report_wizard,action_leads_report_wizard access,model_action_leads_report_wizard,base.group_user,1,1,1,1
access_lead_source,lead_source access,model_lead_source,base.group_user,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
4 access_sos_target_tracker sos_target_tracker access model_sos_target_tracker base.group_user 1 1 1 1
5 access_sos_leads_contact_lines sos_leads_contact_lines access model_sos_leads_contact_lines base.group_user 1 1 1 1
6 access_action_leads_report_wizard action_leads_report_wizard access model_action_leads_report_wizard base.group_user 1 1 1 1
7 access_lead_source lead_source access model_lead_source base.group_user 1 1 1 1
8

View File

@ -7,10 +7,12 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="company_name"/> <field name="company_name"/>
<field name="status"/>
<field name="location"/> <field name="location"/>
<field name="vertical_domain"/> <field name="products_interested" string="Products" widget="many2many_tags" options="{'color_field': 'color'}"/>
<field name="project_name"/>
<field name="lead_generated_by"/> <field name="lead_generated_by"/>
<field name="entry_date" string="Lead Generated On"/> <!-- <field name="entry_date" string="Lead Generated On"/> -->
<field name="move_div_display" widget="boolean_toggle" readonly="1"/> <field name="move_div_display" widget="boolean_toggle" readonly="1"/>
</tree> </tree>
</field> </field>
@ -20,17 +22,21 @@
<field name="model">sos_inside_sales_leads</field> <field name="model">sos_inside_sales_leads</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<searchpanel>
<field name="products" string="Products Interested In" icon="fa-list-ul" enable_counters="1"/> <searchpanel>
<field name="vertical_domain" string="Vertical/Domain" icon="fa-pie-chart" enable_counters="1"/>
</searchpanel> <field name="sales_type" string="Type" icon="fa-list-ul" enable_counters="1"/>
</searchpanel>
<!-- Add fields to search on --> <!-- Add fields to search on -->
<field name="company_name" string="Company Name"/> <field name="company_name" string="Company Name"/>
<field name="vertical_domain" string="Domain/Vertical"/> <field name="vertical_domain" string="Domain/Vertical"/>
<field name="lead_generated_by" string="Lead Generated By"/> <field name="lead_generated_by" string="Lead Generated By"/>
<field name="products_interested"/>
<filter name="product_filter"
string="Product"
domain="[('products_interested', 'in', products_interested)]"/>
</search> </search>
@ -50,18 +56,24 @@
<group> <group>
<group> <group>
<field name="move_div_display" invisible="1"/> <field name="move_div_display" invisible="1"/>
<field name="sales_type"/>
<field name="company_name"/> <field name="company_name"/>
<field name="entry_date"/> <field name="entry_date"/>
<field name="location"/> <field name="country" invisible="sales_type != 'International'"/>
<field name="vertical_domain"/> <field name="location" string="City/State"/>
<field name="vertical_domain" widget="many2many_tags"/>
<field name="status"/>
</group> </group>
<group> <group>
<field name="website_url"/> <field name="website_url"/>
<field name="linkedin_profile"/> <field name="linkedin_profile"/>
<field name="products"/> <field name="service"/>
<field name="products_interested"
<field name="source"/> options="{'no_create': True, 'no_edit': True, 'no_create_edit': True}"
<field name="expo_name" invisible="source != 'expo'"/> widget="many2many_tags" invisible="service != 'Product'"/>
<field name="project_name" invisible="service != 'Project'"/>
<field name="new_source"/>
<field name="expo_name" invisible="new_source != 2"/>
<field name="meeting_scheduled"/> <field name="meeting_scheduled"/>
<field name="remarks"/> <field name="remarks"/>
</group> </group>
@ -77,6 +89,8 @@
<field name="dept"/> <field name="dept"/>
<field name="email"/> <field name="email"/>
<field name="mobile_number"/> <field name="mobile_number"/>
<field name="linkedin_profile"/>
<field name="remarks"/>
</tree> </tree>
</field> </field>
@ -87,6 +101,8 @@
<tree editable="bottom"> <tree editable="bottom">
<field name="action_date"/> <field name="action_date"/>
<field name="remarks"/> <field name="remarks"/>
<field name="next_action_on"/>
</tree> </tree>

View File

@ -63,6 +63,9 @@ class FIR_Only(models.Model):
cloud_data = fields.Binary("Cloud Data", required=False, attachment=True) cloud_data = fields.Binary("Cloud Data", required=False, attachment=True)
cloud_data_filename = fields.Char("Cloud Data Filename") cloud_data_filename = fields.Char("Cloud Data Filename")
firmware_data = fields.Binary("Firmware Data", required=False, attachment=True)
firmware_data_filename = fields.Char("Firmware Data Filename")
@api.onchange('batch_size') @api.onchange('batch_size')
def _onchange_batch_size(self): def _onchange_batch_size(self):
if self._origin and self.batch_size is not False: if self._origin and self.batch_size is not False:
@ -75,11 +78,11 @@ class FIR_Only(models.Model):
] ]
self.testing_parameter_line_ids = line_values self.testing_parameter_line_ids = line_values
@api.constrains('test_log_filename', 'sd_card_data_filename', 'cloud_data_filename') @api.constrains('test_log_filename', 'sd_card_data_filename', 'cloud_data_filename', 'firmware_data_filename')
def _check_file_extension(self): def _check_file_extension(self):
allowed_extensions = ['xlsx', 'xls', 'csv', 'zip', 'pdf'] allowed_extensions = ['xlsx', 'xls', 'csv', 'zip', 'pdf']
for record in self: for record in self:
for field_name in ['test_log_filename', 'sd_card_data_filename', 'cloud_data_filename']: for field_name in ['test_log_filename', 'sd_card_data_filename', 'cloud_data_filename','firmware_data_filename']:
file_name = getattr(record, field_name) file_name = getattr(record, field_name)
if file_name: if file_name:
ext = file_name.split('.')[-1].lower() ext = file_name.split('.')[-1].lower()

View File

@ -13,3 +13,23 @@ class sos_inventory_customers(models.Model):
customer_name = fields.Char(string="Customer Name") customer_name = fields.Char(string="Customer Name")
customer_location = fields.Char(string="Location") customer_location = fields.Char(string="Location")
@api.model
def create(self, vals):
new_name = (vals.get('customer_name') or '').lower()
if new_name and len(new_name) >= 5:
existing_customers = self.search([])
for customer in existing_customers:
existing_name = (customer.customer_name or '').lower()
# Check all substrings of length 5 or more
for i in range(len(new_name) - 4):
substring = new_name[i:i+5]
if substring in existing_name:
raise UserError(
f"A customer with a similar name already exists: '{customer.customer_name}' "
f"(matched substring: '{substring}')"
)
return super(sos_inventory_customers, self).create(vals)

View File

@ -154,7 +154,7 @@ class SOS_IR(models.Model):
self.line_ids_material = lines self.line_ids_material = lines
except Exception as e: except Exception as e:
_logger.error("Error processing po_no: %s", str(e)) print("Error processing po_no: %s", str(e))
@api.onchange('wo_no') @api.onchange('wo_no')
def _onchange_wo_no(self): def _onchange_wo_no(self):
if self.wo_no: if self.wo_no:
@ -170,7 +170,7 @@ class SOS_IR(models.Model):
self.line_ids_sfg = lines self.line_ids_sfg = lines
except Exception as e: except Exception as e:
_logger.error("Error processing po_no: %s", str(e)) print("Error processing po_no: %s", str(e))
@api.onchange('wo_no_inhouse') @api.onchange('wo_no_inhouse')
def _onchange_wo_no_inhouse(self): def _onchange_wo_no_inhouse(self):
if self.wo_no_inhouse: if self.wo_no_inhouse:
@ -186,7 +186,7 @@ class SOS_IR(models.Model):
self.line_ids_sfg = lines self.line_ids_sfg = lines
except Exception as e: except Exception as e:
_logger.error("Error processing po_no: %s", str(e)) print("Error processing po_no: %s", str(e))
def action_report_ir_btn(self): def action_report_ir_btn(self):
@ -409,6 +409,7 @@ class SOS_IR_Line_Material(models.Model):
unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id') unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id')
test_report = fields.Binary(string="Test Report") test_report = fields.Binary(string="Test Report")
test_report_filename=fields.Char(string="Test Report File Name") test_report_filename=fields.Char(string="Test Report File Name")
expiry_date = fields.Date(string="Expiry Date")
@api.onchange('component_id') @api.onchange('component_id')
def _onchange_component_id(self): def _onchange_component_id(self):
if self.component_id: if self.component_id:

View File

@ -48,6 +48,8 @@ class SOS_Material(models.Model):
string="Materials History - In", string="Materials History - In",
domain=[('action', '=', 'in')] domain=[('action', '=', 'in')]
) )
shelf_life = fields.Selection([('yes', 'Yes'), ('no', 'No')],default="no", string="Shelf Life",required=True)
line_ids_out = fields.One2many( line_ids_out = fields.One2many(
'sos_material_transaction_history', 'ref_id', 'sos_material_transaction_history', 'ref_id',

View File

@ -14,7 +14,7 @@ class sos__mon(models.Model):
mon_date = fields.Date(string="MON/SON/FON Date", required=True, default=fields.Date.today) mon_date = fields.Date(string="MON/SON/FON Date", required=True, default=fields.Date.today)
min_no = fields.Many2one('sos_min',string="MIN/SIN/FIN No") min_no = fields.Many2one('sos_min',string="MIN/SIN/FIN No")
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') 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")
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')
@ -61,7 +61,7 @@ class sos__mon(models.Model):
auto_load_fg_item_ids = fields.Many2many( auto_load_fg_item_ids = fields.Many2many(
'sos_fg', 'sos_fg',
compute='_compute_fg_items', compute='_compute_fg_items',
store=False store=True
) )
company_id = fields.Many2one('res.company', store=True, copy=False, company_id = fields.Many2one('res.company', store=True, copy=False,
string="Company", string="Company",
@ -70,7 +70,7 @@ class sos__mon(models.Model):
related='company_id.currency_id', related='company_id.currency_id',
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,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)
@api.constrains('indent_ref_no', 'auto_load_fg_items') @api.constrains('indent_ref_no', 'auto_load_fg_items')
@ -189,6 +189,8 @@ class sos__mon(models.Model):
@api.onchange('auto_load_fg_items') @api.onchange('auto_load_fg_items')
def _onchange_auto_load_fg_items(self): def _onchange_auto_load_fg_items(self):
if not self.auto_load_fg_items:
return
if self.auto_load_fg_items: if self.auto_load_fg_items:
self.material_option = True self.material_option = True
self.sfg_option = True self.sfg_option = True

View File

@ -46,7 +46,51 @@ 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)
@api.onchange('min_no')
def _onchange_min_no(self):
if self.min_no:
self.material_option = self.min_no.material_option
self.sfg_option = self.min_no.sfg_option
self.fg_option = self.min_no.fg_option
#materials
self.line_ids_material = [(5, 0, 0)]
material_lines = []
for material in self.min_no.line_ids_material:
line_vals = {
'mrn_id': self.id,
'component_id': material.component_id,
'qp_no': material.qp_no,
'uom': material.uom,
'quantity': material.quantity
}
material_lines.append((0, 0, line_vals))
self.line_ids_material = material_lines
#sfg
self.line_ids_sfg = [(5, 0, 0)]
sfg_lines = []
for sfg in self.min_no.line_ids_sfg:
line_vals_sfg = {
'mrn_id': self.id,
'component_id': sfg.component_id,
'qp_no': sfg.qp_no,
'quantity': sfg.quantity
}
sfg_lines.append((0, 0, line_vals_sfg))
self.line_ids_sfg = sfg_lines
#sfg
self.line_ids_fg = [(5, 0, 0)]
fg_lines = []
for fg in self.min_no.line_ids_fg:
line_vals_fg = {
'mrn_id': self.id,
'component_id': fg.component_id,
'quantity': fg.quantity
}
fg_lines.append((0, 0, line_vals_fg))
self.line_ids_fg = fg_lines
@api.depends('line_ids_material.total_cost') @api.depends('line_ids_material.total_cost')
def _compute_approx_value(self): def _compute_approx_value(self):
for record in self: for record in self:
@ -115,6 +159,7 @@ class sos__mrn(models.Model):
def action_report_esign_btn1(self): def action_report_esign_btn1(self):
sequence_util = self.env['sos_common_scripts'] sequence_util = self.env['sos_common_scripts']
splitted=self.order_type.split(",") splitted=self.order_type.split(",")
customer_return_record = False
if self.return_type == "customer": if self.return_type == "customer":
sequence_util = self.env['sos_common_scripts'] sequence_util = self.env['sos_common_scripts']
tc_no = sequence_util.generate_sequence('sos_transfer_challan_return_from_customer','TC', 'tc_no') tc_no = sequence_util.generate_sequence('sos_transfer_challan_return_from_customer','TC', 'tc_no')

View File

@ -56,6 +56,7 @@ class NCMR_Model(models.Model):
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")
qa_done_on = fields.Date(string="Verified On") qa_done_on = fields.Date(string="Verified On")
rework_responsible_rd_user = fields.Many2one('res.users',string='R&D User')
rd_user = fields.Many2many('res.users',string='R&D User', relation='sos_ncmr_rd_user_rel') rd_user = fields.Many2many('res.users',string='R&D User', relation='sos_ncmr_rd_user_rel')
qa_by = fields.Many2one('res.users',string='QC In-Charge',readonly=True) qa_by = fields.Many2one('res.users',string='QC In-Charge',readonly=True)
qa_sign = fields.Image(related="qa_by.signature_image",string='QC In-Charge',readonly=True) qa_sign = fields.Image(related="qa_by.signature_image",string='QC In-Charge',readonly=True)
@ -94,10 +95,15 @@ class NCMR_Model(models.Model):
string="Rework Action", string="Rework Action",
default="inhouse" default="inhouse"
) )
rework_action_by_qc = fields.Boolean(string="Rework")
rd_comments=fields.Text(string="Comments") rd_comments=fields.Text(string="Comments")
rd_approval_by = fields.Many2one('res.users',string='R&D In-Charge',readonly=True) rd_approval_by = fields.Many2one('res.users',string='R&D In-Charge',readonly=True)
rd_approval_sign = fields.Image(related="rd_approval_by.signature_image",string='R&D In-Charge',readonly=True) rd_approval_sign = fields.Image(related="rd_approval_by.signature_image",string='R&D In-Charge',readonly=True)
rd_approval_on = fields.Datetime(string="Approved On") rd_approval_on = fields.Datetime(string="Approved On")
rework_rd_approval_by = fields.Many2one('res.users',string='Rework - R&D In-Charge',readonly=True)
rework_rd_approval_sign = fields.Image(related="rework_rd_approval_by.signature_image",string='Rework - R&D In-Charge',readonly=True)
rework_rd_approval_on = fields.Datetime(string="Approved On")
combined_incoming_doc_ref = fields.Reference( combined_incoming_doc_ref = fields.Reference(
selection=[ selection=[
('sos_iqi', 'IQI Ref No'), ('sos_iqi', 'IQI Ref No'),
@ -244,7 +250,8 @@ class NCMR_Model(models.Model):
open_count = sum(1 for rec in line.defective_status_ids if rec.status == 'open') open_count = sum(1 for rec in line.defective_status_ids if rec.status == 'open')
closed_count = sum(1 for rec in line.defective_status_ids if rec.status == 'closed') closed_count = sum(1 for rec in line.defective_status_ids if rec.status == 'closed')
closure_rate = ((closed_count/required_ncmr)*100) closure_rate = (closed_count / required_ncmr) * 100 if required_ncmr else 0.0
ppm = None ppm = None
@ -668,6 +675,13 @@ class NCMR_Model(models.Model):
'rd_approval_by', 'rd_approval_by',
'rd_approval_on' 'rd_approval_on'
) )
def action_rework_rd_esign_btn(self):
send_email = self.env['sos_common_scripts']
send_email.action_assign_signature(
self,
'rework_rd_approval_by',
'rework_rd_approval_on'
)
def action_qa_esign_btn(self): def action_qa_esign_btn(self):
if self.action_group: if self.action_group:
@ -678,6 +692,20 @@ class NCMR_Model(models.Model):
'qa_tested_on', 'qa_tested_on',
'sos_inventory.sos_qc_user' 'sos_inventory.sos_qc_user'
) )
if self.rework_action_by_qc:
# Email part
body_html = f"""
<p>Below <b>NCMR</b> is waiting for your Action</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_direct_email(
self.env,
"sos_ncmr",
self.id,
self.rework_responsible_rd_user.login,
"NCMR Rework Action Request",
body_html
)
if self.action_group == "rd": if self.action_group == "rd":
# Email part # Email part
body_html = f""" body_html = f"""

View File

@ -6,7 +6,7 @@ class SosTestingParameters(models.Model):
_rec_name='fg_name' _rec_name='fg_name'
fg_name = fields.Many2one('sos_fg',string="FG Name") fg_name = fields.Many2one('sos_fg',string="FG Name")
parameter_ids = fields.One2many('sos_parameter', 'testing_id', string= 'BRR Testing Parameters',copy=True) parameter_ids = fields.One2many('sos_parameter', 'testing_id', string= 'In-Process/BRR Testing Parameters',copy=True)
fir_parameter_ids = fields.One2many('sos_parameter_fir', 'testing_id', string= 'FIR Testing Parameters',copy=True) fir_parameter_ids = fields.One2many('sos_parameter_fir', 'testing_id', string= 'FIR Testing Parameters',copy=True)
specification_ids = fields.One2many('sos_specification', 'spec_id', string='Specifications',copy=True) specification_ids = fields.One2many('sos_specification', 'spec_id', string='Specifications',copy=True)
deliverables_ids = fields.One2many('sos_deliverables', 'accessory_id', string='Deliverables',copy=True) deliverables_ids = fields.One2many('sos_deliverables', 'accessory_id', string='Deliverables',copy=True)

View File

@ -44,11 +44,10 @@
<field name="perm_create" eval="1"/> <field name="perm_create" eval="1"/>
<field name="perm_unlink" eval="0"/> <field name="perm_unlink" eval="0"/>
</record> </record>
<record id="sos_ncmr_all_records_rule" model="ir.rule">
<record id="sos_ncmr_all_records_rule" model="ir.rule">
<field name="name">Sos NCMR: All Records - Read Access</field> <field name="name">Sos NCMR: All Records - Read Access</field>
<field name="model_id" ref="model_sos_ncmr"/> <field name="model_id" ref="model_sos_ncmr"/>
<field name="domain_force">[('rd_user', '=', user.id)]</field> <field name="domain_force">[('rd_user', '=', user.id), ('rework_responsible_rd_user', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/> <field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1"/>

View File

@ -192,7 +192,7 @@
</record> </record>
<!-- Menuitem --> <!-- Menuitem -->
<menuitem id="menu_sos_fir_brr" sequence="3" name="Batch Realease Report (BRR)" parent="mop_forms_menu_root" action="action_sos_fir_brr" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user"/> <menuitem id="menu_sos_fir_brr" sequence="3" name="In-Process Inspection / Batch Realease Report (BRR)" parent="mop_forms_menu_root" action="action_sos_fir_brr" groups="sos_inventory.sos_healthcare_user,sos_inventory.sos_scg_group_user,sos_inventory.sos_qc_user,sos_inventory.sos_management_user"/>
</data> </data>
</odoo> </odoo>

View File

@ -119,6 +119,12 @@
<br></br> <br></br>
<hr></hr> <hr></hr>
</page> </page>
<page string="Firmware Data">
<field name="firmware_data" filename="firmware_data_filename"/>
<field name="firmware_data_filename" invisible="1"/>
<br></br>
<hr></hr>
</page>
</notebook> </notebook>
<templates> <templates>

View File

@ -99,6 +99,7 @@
<field name="order_qty"/> <field name="order_qty"/>
<field name="qty"/> <field name="qty"/>
<field name="unit_price"/> <field name="unit_price"/>
<field name="expiry_date"/>
<field name="test_report" widget="binary" filename="test_report_filename"/> <field name="test_report" widget="binary" filename="test_report_filename"/>
<field name="test_report_filename" column_invisible="1"/> <field name="test_report_filename" column_invisible="1"/>
<button name="action_view_pdf" invisible="not test_report" type="object" string="View" class="btn-primary" icon="fa-eye"/> <button name="action_view_pdf" invisible="not test_report" type="object" string="View" class="btn-primary" icon="fa-eye"/>

View File

@ -118,6 +118,7 @@
<field name="description"/> <field name="description"/>
<field name="category"/> <field name="category"/>
<field name="uom"/> <field name="uom"/>
<field name="shelf_life"/>
<field name="inspection_method" widget="color_picker"/> <field name="inspection_method" widget="color_picker"/>
<field name="qp_no"/> <field name="qp_no"/>
<field name="hsn_code"/> <field name="hsn_code"/>

View File

@ -29,7 +29,7 @@
<field name="forward_by" string="QA Approval" widget="many2one_avatar_user"/> <field name="forward_by" string="QA Approval" widget="many2one_avatar_user"/>
<field name="status" widget="badge" decoration-success="status == 'closed'" decoration-danger="status == 'open'"/> <field name="status" widget="badge" decoration-success="status == 'closed'" decoration-danger="status == 'open'"/>
<field name="rework_action_by_qc" widget="boolean_toggle"/>
<field name="write_uid" string="Last Edited By" optional="hide"/> <field name="write_uid" string="Last Edited By" optional="hide"/>
<field name="write_date" string="Last Edited On" optional="hide"/> <field name="write_date" string="Last Edited On" optional="hide"/>
@ -242,19 +242,27 @@
<templates> <templates>
<div class="container"> <div class="container">
<div class="row" style="margin-top:100px"> <div class="row" style="margin-top:100px">
<div class="col-6"> <div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;">
<table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <table class="table_custom" >
<tr><td colspan="2" class="table_custom_header">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">QC</span> Team</td></tr> <tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">QC</span> Team</td></tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>QC Comments</b></td> <td style="padding: 8px;" class="column"><b>QC Comments</b></td>
<td><field name="comments"/></td> <td><field name="comments"/></td>
</tr> </tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>Action to be taken By</b></td> <td style="padding: 8px;" class="column"><b>Action to be taken By</b></td>
<td><field name="action_group"/><field name="rd_user" widget="many2many_tags" invisible="action_group != 'rd'"/></td> <td><field name="action_group"/><field name="rd_user" widget="many2many_tags" invisible="action_group != 'rd'"/></td>
</tr> </tr>
<tr>
<td style="padding: 8px;" class="column"><b>Rework Decision</b></td>
<td><field name="rework_action_by_qc" widget="boolean_toggle"/>
<field name="rework_responsible_rd_user" invisible="rework_action_by_qc != True"/>
</td>
</tr>
<tr style="border-bottom: solid 1px #ccc;"> <tr style="border-bottom: solid 1px #ccc;">
<td style="padding: 8px;" class="column"><b>QC Tested By </b></td> <td style="padding: 8px;" class="column"><b>QC Tested By </b></td>
<td> <td>
@ -270,8 +278,8 @@
<td><field name="qa_by" readonly="1"/></td> <td><field name="qa_by" readonly="1"/></td>
</tr> </tr>
</table></div> </table></div>
<div class="col-6"><table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"><table class="table_custom" >
<tr><td colspan="2" class="table_custom_header">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">SCG</span> Team</td></tr> <tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">SCG</span> Team</td></tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>Comments</b></td> <td style="padding: 8px;" class="column"><b>Comments</b></td>
@ -301,8 +309,8 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-6" invisible="rework_action == 'outsourcing_vendor'"><table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;" invisible="rework_action == 'outsourcing_vendor'"><table class="table_custom" >
<tr><td colspan="2" class="table_custom_header">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">Production</span> Team</td></tr> <tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">Production</span> Team</td></tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>Comments</b></td> <td style="padding: 8px;" class="column"><b>Comments</b></td>
@ -323,9 +331,9 @@
<td><field name="production_approval_by" readonly="1"/></td> <td><field name="production_approval_by" readonly="1"/></td>
</tr> </tr>
</table></div> </table></div>
<div class="col-6"> <table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <table class="table_custom" >
<tr><td colspan="2" class="table_custom_header">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">QA</span> Team</td></tr> <tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">QA</span> Team</td></tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>Comments</b></td> <td style="padding: 8px;" class="column"><b>Comments</b></td>
@ -362,8 +370,8 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-6" invisible="action_group != 'rd'"><table class="table_custom" style="box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;"> <div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;" invisible="action_group != 'rd'"><table class="table_custom" >
<tr><td colspan="2" class="table_custom_header">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">R&amp;D</span> Team</td></tr> <tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">R&amp;D</span> Team</td></tr>
<tr> <tr>
<td style="padding: 8px;" class="column"><b>Comments</b></td> <td style="padding: 8px;" class="column"><b>Comments</b></td>
@ -383,7 +391,27 @@
<td style="padding: 8px;" class="column"><b>Approved By</b></td> <td style="padding: 8px;" class="column"><b>Approved By</b></td>
<td><field name="rd_approval_by" readonly="1"/></td> <td><field name="rd_approval_by" readonly="1"/></td>
</tr> </tr>
</table></div></div> </table></div>
<div class="col-6" style="padding: 0px;box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;background-color: #fff;border: solid 4px #9689c1;" invisible="rework_action_by_qc != True"><table class="table_custom" >
<tr><td colspan="2" class="table_custom_header" style="color:#fff">To Be Filled By <span style="font-size: 18px;padding: 0px; color: #ffcc00;">R&amp;D</span> Team(Rework)</td></tr>
<tr style="border-bottom: solid 1px #ccc;">
<td style="padding: 8px;" class="column"><b>Approved By </b></td>
<td>
<button string="Approve" invisible="rework_rd_approval_sign" class="btn-primary custom_btn" type="object" name="action_rework_rd_esign_btn"></button>
<field name="rework_rd_approval_sign" widget="image"/></td>
</tr>
<tr invisible="rework_rd_approval_sign == False">
<td style="padding: 8px;" class="column"><b>Approved On</b></td>
<td><field name="rework_rd_approval_on" readonly="1"/></td>
</tr>
<tr invisible="rework_rd_approval_sign == False">
<td style="padding: 8px;" class="column"><b>Approved By</b></td>
<td><field name="rework_rd_approval_by" readonly="1"/></td>
</tr>
</table></div>
</div>
</div> </div>
</templates> </templates>

View File

@ -38,7 +38,7 @@
<field name="fg_name"/> <field name="fg_name"/>
</group> </group>
<notebook> <notebook>
<page string="BRR Testing Parameters" groups="sos_inventory.sos_qc_user,sos_inventory.sos_qa_user"> <page string="In-Process/BRR Testing Parameters" groups="sos_inventory.sos_qc_user,sos_inventory.sos_qa_user">
<field name="parameter_ids"> <field name="parameter_ids">
<tree string="Parameters" editable="bottom"> <tree string="Parameters" editable="bottom">
<field name="sequence" widget="handle"/> <field name="sequence" widget="handle"/>
@ -115,7 +115,7 @@
</record> </record>
<!-- Action to open sos_testing_parameters --> <!-- Action to open sos_testing_parameters -->
<record id="action_sos_testing_parameters" model="ir.actions.act_window"> <record id="action_sos_testing_parameters" model="ir.actions.act_window">
<field name="name">FG Configurations</field> <field name="name">In-Process Configurations</field>
<field name="res_model">sos_testing_parameters</field> <field name="res_model">sos_testing_parameters</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="help" type="html"> <field name="help" type="html">
@ -136,7 +136,7 @@
</record> </record>
<!-- Menu item to access sos_testing_parameters --> <!-- Menu item to access sos_testing_parameters -->
<menuitem id="menu_sos_testing_parameters" <menuitem id="menu_sos_testing_parameters"
name="FG Configurations" name="In-Process Configurations"
parent="settings_root_menu" action="action_sos_testing_parameters" groups="sos_inventory.sos_qc_user,sos_inventory.sos_qa_user,sos_inventory.sos_ce_user,sos_inventory.sos_production_user,sos_inventory.sos_management_user"/> parent="settings_root_menu" action="action_sos_testing_parameters" groups="sos_inventory.sos_qc_user,sos_inventory.sos_qa_user,sos_inventory.sos_ce_user,sos_inventory.sos_production_user,sos_inventory.sos_management_user"/>
<menuitem id="menu_sos_fir_testing_parameters" <menuitem id="menu_sos_fir_testing_parameters"
name="FIR Parameters Configurations" name="FIR Parameters Configurations"

View File

@ -152,7 +152,8 @@ class sos_case_diary(models.Model):
'ref_id': ref_id, 'ref_id': ref_id,
'customer_name': self.customer_name.id, 'customer_name': self.customer_name.id,
'action_date': last_record.status_changed_on, 'action_date': last_record.status_changed_on,
'proposal_value': proposal_value 'proposal_value': proposal_value,
'po_no':self.po_no
}) })
# Assign signature # Assign signature

View File

@ -13,7 +13,7 @@ class SOS_Sales_Achievement_Report(models.Model):
_sql_constraints = [ _sql_constraints = [
('unique_financial_year_sales_person', 'UNIQUE(financial_year, sales_person)', 'The combination of Financial Year and Sales Person must be unique.') ('unique_financial_year_sales_person', 'UNIQUE(financial_year, sales_person)', 'The combination of Financial Year and Sales Person must be unique.')
] ]
display_name = fields.Char(string="Name", compute='_compute_display_name', store=True)
financial_year = fields.Char(string="Financial Year", default=lambda self: self._get_financial_year()) financial_year = fields.Char(string="Financial Year", default=lambda self: self._get_financial_year())
sales_person = fields.Many2one('res.users', string='Sales person',required=True) sales_person = fields.Many2one('res.users', string='Sales person',required=True)
overall_target = fields.Float(string="Overall Target") overall_target = fields.Float(string="Overall Target")
@ -114,6 +114,11 @@ class SOS_Sales_Achievement_Report(models.Model):
'ref_id', 'ref_id',
string="Billing Collection Lines" string="Billing Collection Lines"
) )
@api.depends('financial_year', 'sales_person')
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.financial_year or ''} / {record.sales_person.name or ''}"
@api.depends('opening_balance', 'actual_target_april', 'billed_target_april') @api.depends('opening_balance', 'actual_target_april', 'billed_target_april')
def _compute_yet_to_billed_april(self): def _compute_yet_to_billed_april(self):
for rec in self: for rec in self:
@ -226,24 +231,24 @@ class SOS_Sales_Achievement_Report(models.Model):
'target': 'new', 'target': 'new',
'res_id': wizard.id, 'res_id': wizard.id,
} }
def action_view_brief_lines(self): # def action_view_brief_lines_acc(self):
# return {
# 'name': "Action",
# 'type': 'ir.actions.act_window',
# 'res_model': 'sos_sales_achievement_report_brief',
# 'view_mode': 'form',
# 'view_id': self.env.ref('sos_sales.view_form_sos_sales_achievement_acc').id,
# 'target': 'new',
# 'context': {
# 'ref_record_id': self.id
# }
# }
def action_view_brief_lines_acc(self):
self.ensure_one() self.ensure_one()
domain = [('ref_id', '=', self.id)] domain = [('ref_record_id', '=', self.id)]
# Extract year from 'FY 2025-2026'
match = re.search(r'FY\s*(\d{4})', self.financial_year or '')
if match:
year = int(match.group(1))
else:
raise ValueError(f"Unable to extract year from financial year: {self.financial_year}")
# Filter by month if present
month = int(self.env.context.get('month', 0))
if month:
domain.append(('action_date', '>=', f'{year}-{month:02d}-01'))
last_day = calendar.monthrange(year, month)[1]
domain.append(('action_date', '<=', f'{year}-{month:02d}-{last_day:02d}'))
brief_lines = self.env['sos_sales_achievement_report_brief'].search(domain) brief_lines = self.env['sos_sales_achievement_report_brief'].search(domain)
@ -258,6 +263,45 @@ class SOS_Sales_Achievement_Report(models.Model):
'default_parent_id': self.id, 'default_parent_id': self.id,
} }
} }
def action_view_brief_lines(self):
self.ensure_one()
domain = [('ref_id', '=', self.id)]
# Extract starting year from 'FY 2025-2026'
match = re.search(r'FY\s*(\d{4})', self.financial_year or '')
if match:
year = int(match.group(1))
else:
raise ValueError(f"Unable to extract year from financial year: {self.financial_year}")
month = int(self.env.context.get('month', 0))
if month:
# Filter specific month
domain.append(('action_date', '>=', f'{year}-{month:02d}-01'))
last_day = calendar.monthrange(year, month)[1]
domain.append(('action_date', '<=', f'{year}-{month:02d}-{last_day:02d}'))
else:
# Filter for entire financial year (April to March)
start_date = f'{year}-04-01'
end_date = f'{year + 1}-03-31'
domain.append(('action_date', '>=', start_date))
domain.append(('action_date', '<=', end_date))
brief_lines = self.env['sos_sales_achievement_report_brief'].search(domain)
return {
'name': 'Achievement Brief Lines',
'type': 'ir.actions.act_window',
'res_model': 'sos_sales_achievement_report_brief_wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_brief_line_ids': [(6, 0, brief_lines.ids)],
'default_parent_id': self.id,
}
}
@api.depends( @api.depends(
@ -554,17 +598,59 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
_name = 'sos_sales_achievement_report_brief' _name = 'sos_sales_achievement_report_brief'
_description = 'Achievement Brief' _description = 'Achievement Brief'
_order = 'action_date desc' _order = 'action_date desc'
def get_financial_year_selection(self):
current_date = date.today()
start_year = 2024 # starting from FY 2024-2025
current_year = current_date.year if current_date.month >= 4 else current_date.year - 1
end_year = current_year + 1
selection = []
for y in range(start_year, current_year + 1):
fy = f"FY {y}-{y+1}"
selection.append((fy, fy))
return selection
ref_id = fields.Many2one('sos_sales_achievement_report', string="Financial Year", ondelete="cascade") ref_id = fields.Many2one('sos_sales_achievement_report', string="Financial Year", ondelete="cascade")
ref_record_id = fields.Integer(string="Reference")
customer_name = fields.Many2one('sos_customers',string="Customer Name", required=True) customer_name = fields.Many2one('sos_customers',string="Customer Name", required=True)
action_date = fields.Date(string="Date") action_date = fields.Date(string="PO Date")
currency_id = fields.Many2one( currency_id = fields.Many2one(
'res.currency', 'res.currency',
string='Currency', string='Currency',
default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False
) )
proposal_value = fields.Monetary(currency_field='currency_id',string="PO Received(In Lakhs)") financial_year = fields.Selection(
selection=get_financial_year_selection,
string="Financial Year",
required=True
)
sales_person = fields.Many2one('res.users', string='Sales person',related="ref_id.sales_person",store=True)
po_no = fields.Char(string="PO No")
invoice_no = fields.Char(string="Invoice No")
proposal_value = fields.Monetary(currency_field='currency_id',string="PO Value(In Lakhs)")
billed_date = fields.Date(string="Billed Date") billed_date = fields.Date(string="Billed Date")
billed_amount = fields.Monetary(currency_field='currency_id',string="Billed Value(In Lakhs)") billed_amount = fields.Monetary(currency_field='currency_id',string="Billed Value(In Lakhs)")
# def view_lines_acc(self):
# self.ensure_one()
# return {
# 'name': 'Achievement Brief Lines',
# 'type': 'ir.actions.act_window',
# 'res_model': 'sos_sales_achievement_report_brief',
# 'view_mode': 'tree',
# 'domain': [('ref_record_id', '=', self.id)],
# 'context': {
# 'default_ref_record_id': self.id
# },
# 'target': 'current',
# }
def delete_achievement_line(self):
self.unlink()
def unlink(self):
for record in self:
report = self.env['sos_sales_achievement_report'].browse(record.ref_id.id)
if report and hasattr(report, 'opening_balance'):
report.write({'opening_balance': report.opening_balance - record.proposal_value})
return super(SOS_Sales_Achievement_Report_Brief, self).unlink()
def open_line_form(self): def open_line_form(self):
self.ensure_one() self.ensure_one()
return { return {
@ -589,7 +675,6 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
# New values # New values
new_billed_date = vals.get('billed_date', old_billed_date) new_billed_date = vals.get('billed_date', old_billed_date)
new_billed_amount = vals.get('billed_amount', old_billed_amount) new_billed_amount = vals.get('billed_amount', old_billed_amount)
if isinstance(new_billed_date, str): if isinstance(new_billed_date, str):
new_billed_date = datetime.strptime(new_billed_date, '%Y-%m-%d').date() new_billed_date = datetime.strptime(new_billed_date, '%Y-%m-%d').date()
@ -609,53 +694,63 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
new_field_billed: (getattr(report, new_field_billed, 0.0) or 0.0) + new_billed_amount new_field_billed: (getattr(report, new_field_billed, 0.0) or 0.0) + new_billed_amount
}) })
# Optionally create billing collection entry (if needed) # Optionally create billing collection entry (if needed)
if new_billed_amount > 0: if new_billed_amount > 0:
self.env['sos_billing_collection'].create({ self.env['sos_billing_collection'].create({
'ref_id': report.id, 'ref_id': report.id,
'customer_name': vals.get('customer_name', rec.customer_name.id), 'customer_name': vals.get('customer_name', rec.customer_name.id),
'sales_person': report.sales_person.id, 'sales_person': report.sales_person.id,
'action_status': 'Billed', 'action_status': 'Billed',
'date_of_action': new_billed_date, 'date_of_action': new_billed_date,
'value': new_billed_amount 'value': new_billed_amount
}) })
return super(SOS_Sales_Achievement_Report_Brief, self).write(vals) return super(SOS_Sales_Achievement_Report_Brief, self).write(vals)
@api.model @api.model
def create(self, vals): def create(self, vals):
ref_id = vals.get('ref_id')
vals['ref_record_id'] = ref_id
action_date = vals.get('action_date') action_date = vals.get('action_date')
billed_date = vals.get('billed_date') billed_date = vals.get('billed_date')
customer_name = vals.get('customer_name') customer_name = vals.get('customer_name')
value = vals.get('proposal_value', 0.0)
billed_value = vals.get('billed_amount', 0.0)
ref_id = vals.get('ref_id')
if isinstance(action_date, str): if isinstance(action_date, str):
action_date = datetime.strptime(action_date, '%Y-%m-%d').date() action_date = datetime.strptime(action_date, '%Y-%m-%d').date()
if isinstance(billed_date, str): if isinstance(billed_date, str):
billed_date = datetime.strptime(billed_date, '%Y-%m-%d').date() billed_date = datetime.strptime(billed_date, '%Y-%m-%d').date()
month_name = action_date.strftime('%B').lower() if ref_id and action_date:
value = vals.get('proposal_value', 0.0)
actual_field = f"actual_target_{month_name}"
ref_id = vals.get('ref_id')
if ref_id:
report = self.env['sos_sales_achievement_report'].browse(ref_id) report = self.env['sos_sales_achievement_report'].browse(ref_id)
sales_person = report.sales_person month_name = action_date.strftime('%B').lower()
if sales_person and hasattr(report, actual_field): actual_field = f"actual_target_{month_name}"
current_value = getattr(report, actual_field, 0.0) or 0.0 current_date = date.today()
report.write({actual_field: current_value + value}) start_year = current_date.year if current_date.month >= 4 else current_date.year - 1
end_year = start_year + 1
current_fy = f"FY {start_year}-{end_year}"
if vals.get('financial_year') != current_fy:
report.write({'opening_balance': report.opening_balance + value})
# Instead of also summing billed_value here, just create billing line
if billed_date: if vals.get('financial_year') == current_fy:
self.env['sos_billing_collection'].create({ if hasattr(report, actual_field):
'ref_id': report.id, current_val = getattr(report, actual_field) or 0.0
'customer_name': customer_name, report.write({actual_field: current_val + value})
'sales_person': report.sales_person.id,
'action_status': 'Billed',
'date_of_action': billed_date,
'value': vals.get('billed_amount', 0.0)
})
return super(SOS_Sales_Achievement_Report_Brief, self).create(vals) if billed_date:
self.env['sos_billing_collection'].create({
'ref_id': report.id,
'customer_name': customer_name,
'sales_person': report.sales_person.id,
'action_status': 'Billed',
'date_of_action': billed_date,
'value': billed_value
})
new_record = super(SOS_Sales_Achievement_Report_Brief, self).create(vals)
return new_record
class SOS_Sales_Achievement_Report_Brief_Wizard(models.TransientModel): class SOS_Sales_Achievement_Report_Brief_Wizard(models.TransientModel):
@ -780,6 +875,33 @@ class SosBillingCollection(models.Model):
start_year = current_date.year if current_date.month >= 4 else current_date.year - 1 start_year = current_date.year if current_date.month >= 4 else current_date.year - 1
end_year = start_year + 1 end_year = start_year + 1
return f"FY {start_year}-{end_year}" return f"FY {start_year}-{end_year}"
def delete_form_line(self):
self.unlink()
def unlink(self):
for record in self:
if record.date_of_action:
fy = self._get_financial_year(record.date_of_action)
month_name = record.date_of_action.strftime('%B').lower()
else:
fy = False
month_name = False
if fy and month_name:
actual_field_name = f"{record.action_status.lower()}_target_{month_name}"
# Fetch related record where field update should happen (example logic)
report = self.env['sos_sales_achievement_report'].search([
('financial_year', '=', fy),
('sales_person', '=', record.sales_person.id)
], limit=1)
if report and hasattr(report, actual_field_name):
current_val = getattr(report, actual_field_name, 0.0)
setattr(report, actual_field_name, current_val - record.value)
return super(SosBillingCollection, self).unlink()
@api.model @api.model
def create(self, vals): def create(self, vals):

View File

@ -1,4 +1,5 @@
from odoo import models, fields, api from odoo import models, fields, api
import random
class sos_sales_leads(models.Model): class sos_sales_leads(models.Model):
_name = 'sos_sales_leads' _name = 'sos_sales_leads'
@ -9,31 +10,43 @@ class sos_sales_leads(models.Model):
transferred_on = fields.Date(string="Transferred On") transferred_on = fields.Date(string="Transferred On")
location = fields.Char(string="Location") location = fields.Char(string="Location")
website_url = fields.Char(string="Website URL") website_url = fields.Char(string="Website URL")
vertical_domain = fields.Many2one('sos_vertical_domain',string="Domain / Industry", ondelete="cascade") vertical_domain = fields.Many2many('sos_vertical_domain',string="Domain / Industry", ondelete="cascade")
linkedin_profile = fields.Char(string="Linkedin profile") linkedin_profile = fields.Char(string="Linkedin profile")
status = fields.Char(string="Status") status = fields.Char(string="Status")
correspondence_address = fields.Text(string="Correspondence Address") correspondence_address = fields.Text(string="Correspondence Address")
interested_in = fields.Selection( interested_in = fields.Selection(
[ [
('products', 'Products'), ('Product', 'Products'),
('projects', 'Projects') ('Project', 'Projects')
], ],
string="Interested In",required=True,default="products") string="Service Type",required=True,default="Product")
project_name = fields.Char(string="Project Name") sales_type = fields.Selection(
products = fields.Selection(
[ [
('BHMS 1.2V', 'BHMS 1.2V'), ('Domestic', 'Domestic'),
('BHMS 2V', 'BHMS 2V'), ('International', 'International')
('BHMS 12V', 'BHMS 12V'),
('BHMS 48V', 'BHMS 48V'),
('BMS-HV', 'BMS-HV'),
('BMS-LV 100A', 'BMS-LV 100A'),
('BMS-LV 40A', 'BMS-LV 40A'),
('SBMS 55A', 'SBMS 55A'),
('MC 250W', 'MC 250W'),
('HeartTarang', 'HeartTarang')
], ],
string="Products") string="Sales Type",default="Domestic")
project_name= fields.Many2one('sos_projects',string="Project Name")
products_interested = fields.Many2many('sos_products',string="Product Interested In")
# products = fields.Selection(
# [
# ('BHMS 1.2V', 'BHMS 1.2V'),
# ('BHMS 2V', 'BHMS 2V'),
# ('BHMS 12V', 'BHMS 12V'),
# ('BHMS 48V', 'BHMS 48V'),
# ('BMS-HV', 'BMS-HV'),
# ('BMS-LV 100A', 'BMS-LV 100A'),
# ('BMS-LV 40A', 'BMS-LV 40A'),
# ('SBMS 55A', 'SBMS 55A'),
# ('MC 250W', 'MC 250W'),
# ('HeartTarang', 'HeartTarang')
# ],
# string="Products")
country = fields.Many2one(
'res.country',
string='Country',
default=lambda self: self.env['res.country'].search([('code', '=', 'IN')], limit=1)
)
source = fields.Selection( source = fields.Selection(
[ [
('self', 'Self'), ('self', 'Self'),
@ -91,16 +104,18 @@ class SOS_Leads_Lines(models.Model):
email = fields.Char(string="Email Id") email = fields.Char(string="Email Id")
mobile_number = fields.Char(string="Contact Number") mobile_number = fields.Char(string="Contact Number")
set_as_primary = fields.Boolean(string="Set Primary") set_as_primary = fields.Boolean(string="Set Primary")
@api.model linkedin_profile = fields.Char(string="LinkedIn Profile")
def create(self, vals): remarks = fields.Text(string="Remarks")
record = super(SOS_Leads_Lines, self).create(vals) # @api.model
if not self.env['sos_leads_customer_contact_lines'].search([ # def create(self, vals):
('ref_id', '=', record.ref_id.id), # record = super(SOS_Leads_Lines, self).create(vals)
('set_as_primary', '=', True) # if not self.env['sos_leads_customer_contact_lines'].search([
]): # ('ref_id', '=', record.ref_id.id),
# Set the created record as primary # ('set_as_primary', '=', True)
record.set_as_primary = True # ]):
return record # # Set the created record as primary
# record.set_as_primary = True
# return record
def write(self, vals): def write(self, vals):
res = super(SOS_Leads_Lines, self).write(vals) res = super(SOS_Leads_Lines, self).write(vals)
if 'set_as_primary' in vals and vals['set_as_primary']: if 'set_as_primary' in vals and vals['set_as_primary']:
@ -109,4 +124,22 @@ class SOS_Leads_Lines(models.Model):
('ref_id', '=', record.ref_id.id), ('ref_id', '=', record.ref_id.id),
('id', '!=', record.id) ('id', '!=', record.id)
]).write({'set_as_primary': False}) ]).write({'set_as_primary': False})
return res return res
class ProductInterest(models.Model):
_name = 'sos_products'
_description = 'Product Interest'
name = fields.Char(string="Product Name", required=True)
color = fields.Integer(string="Colour")
@api.model
def create(self, vals):
if 'color' not in vals:
vals['color'] = random.randint(1, 11)
return super(ProductInterest, self).create(vals)
class ProjectMaster(models.Model):
_name = 'sos_projects'
_description = 'Projects'
name = fields.Char(string="Project Name", required=True)

View File

@ -17,13 +17,11 @@ class ReportBusinessPerformance(models.AbstractModel):
financial_year = self._get_financial_year() financial_year = self._get_financial_year()
domain = [('financial_year', '=', financial_year)] domain = [('financial_year', '=', financial_year)]
if sales_person_id: if sales_person_id:
domain.append(('sales_person', '=', sales_person_id)) domain.append(('sales_person', '=', sales_person_id))
records = self.env['sos_sales_achievement_report'].search(domain, order="sales_person ASC") records = self.env['sos_sales_achievement_report'].search(domain, order="sales_person ASC")
months = [ months = [
'april', 'may', 'june', 'july', 'august', 'september', 'april', 'may', 'june', 'july', 'august', 'september',
'october', 'november', 'december', 'october', 'november', 'december',
@ -39,8 +37,10 @@ class ReportBusinessPerformance(models.AbstractModel):
current_month = date.today().month current_month = date.today().month
if current_month >= 4: if current_month >= 4:
ytd_months = months[:current_month - 4 + 1] ytd_months = months[:current_month - 4 + 1]
current_month_key = months[current_month - 4]
else: else:
ytd_months = months[:current_month + 9 + 1] ytd_months = months[:current_month + 9 + 1]
current_month_key = months[current_month + 9]
records = list(records) records = list(records)
@ -54,7 +54,7 @@ class ReportBusinessPerformance(models.AbstractModel):
'target': 0.0, 'target': 0.0,
'sales': 0.0, 'sales': 0.0,
'sales_percentage': 0.0, 'sales_percentage': 0.0,
'yet_to_billed':0.0, 'yet_to_billed': 0.0,
'billed': 0.0, 'billed': 0.0,
'collected': 0.0, 'collected': 0.0,
} }
@ -77,16 +77,18 @@ class ReportBusinessPerformance(models.AbstractModel):
for m in ytd_months: for m in ytd_months:
ytd_target += round(getattr(doc, f'planned_target_{m}', 0.0), 2) ytd_target += round(getattr(doc, f'planned_target_{m}', 0.0), 2)
ytd_sales += round(getattr(doc, f'actual_target_{m}', 0.0), 2) ytd_sales += round(getattr(doc, f'actual_target_{m}', 0.0), 2)
ytd_yet_to_billed += round(getattr(doc, f'yet_to_billed_target_{m}', 0.0), 2)
ytd_billed += round(getattr(doc, f'billed_target_{m}', 0.0), 2) ytd_billed += round(getattr(doc, f'billed_target_{m}', 0.0), 2)
ytd_collected += round(getattr(doc, f'collected_target_{m}', 0.0), 2) ytd_collected += round(getattr(doc, f'collected_target_{m}', 0.0), 2)
summary['ytd']['target'] += round(getattr(doc, f'planned_target_{m}', 0.0), 2) summary['ytd']['target'] += round(getattr(doc, f'planned_target_{m}', 0.0), 2)
summary['ytd']['sales'] += round(getattr(doc, f'actual_target_{m}', 0.0), 2) summary['ytd']['sales'] += round(getattr(doc, f'actual_target_{m}', 0.0), 2)
summary['ytd']['yet_to_billed'] += round(getattr(doc, f'yet_to_billed_target_{m}', 0.0), 2)
summary['ytd']['billed'] += round(getattr(doc, f'billed_target_{m}', 0.0), 2) summary['ytd']['billed'] += round(getattr(doc, f'billed_target_{m}', 0.0), 2)
summary['ytd']['collected'] += round(getattr(doc, f'collected_target_{m}', 0.0), 2) summary['ytd']['collected'] += round(getattr(doc, f'collected_target_{m}', 0.0), 2)
# Override YTD "yet_to_billed" with only current month value
ytd_yet_to_billed = round(getattr(doc, f'yet_to_billed_target_{current_month_key}', 0.0), 2)
summary['ytd']['yet_to_billed'] += ytd_yet_to_billed
# Assign as formatted string with 2 decimal places # Assign as formatted string with 2 decimal places
doc.ytd_target = "%.2f" % ytd_target doc.ytd_target = "%.2f" % ytd_target
doc.ytd_sales = "%.2f" % ytd_sales doc.ytd_sales = "%.2f" % ytd_sales
@ -104,18 +106,21 @@ class ReportBusinessPerformance(models.AbstractModel):
else: else:
summary['ytd']['sales_percentage'] = "0.00" summary['ytd']['sales_percentage'] = "0.00"
# Also convert YTD values in summary to formatted strings
for key in ['target', 'sales', 'billed', 'collected']: for key in ['target', 'sales', 'billed', 'collected']:
summary['ytd'][key] = "%.2f" % summary['ytd'][key] summary['ytd'][key] = "%.2f" % summary['ytd'][key]
summary['ytd']['yet_to_billed'] = "%.2f" % summary['ytd']['yet_to_billed']
current_month_index = months.index(current_month_key) if current_month_key in months else 0
return { return {
'doc_ids': [rec.id for rec in records], 'doc_ids': [rec.id for rec in records],
'doc_model': 'sos_sales_achievement_report', 'doc_model': 'sos_sales_achievement_report',
'docs': records, 'docs': records,
'financial_year': financial_year, 'financial_year': financial_year,
'enumerated_months': list(enumerate(months)),
'months': months, 'months': months,
'month_names': month_names, 'month_names': month_names,
'summary': summary, 'summary': summary,
'ytd_months': ytd_months, 'ytd_months': ytd_months,
'current_month_index': int(current_month_index),
'is_filtered_by_sales_person': bool(sales_person_id) 'is_filtered_by_sales_person': bool(sales_person_id)
} }

View File

@ -9,7 +9,7 @@
<div class="page"> <div class="page">
<br></br> <br></br>
<h4 style="text-align: center;">Business Performance Report- <t t-esc="financial_year"/></h4> <h4 style="text-align: center;">Business Performance Report- <t t-esc="financial_year"/></h4>
<span style="float: right;font-weight: bold;">Note : Rupees(In Lakhs)</span>
<!-- ✅ SUMMARY TABLE --> <!-- ✅ SUMMARY TABLE -->
<t t-if="not is_filtered_by_sales_person"> <t t-if="not is_filtered_by_sales_person">
@ -64,25 +64,38 @@
<td><t t-esc="summary['ytd']['billed']"/></td> <td><t t-esc="summary['ytd']['billed']"/></td>
</tr> </tr>
<tr> <tr>
<td style="background-color:#e4e0f9"><strong>Yet to Bill</strong></td> <td style="background-color:#e4e0f9"><strong>Yet to Bill</strong></td>
<t t-set="total_yet_billed" t-value="0"/> <t t-set="total_yet_billed" t-value="0"/>
<t t-foreach="months" t-as="m">
<t t-set="val" t-value="summary['yet_to_billed'][m]"/> <t t-foreach="enumerated_months" t-as="item">
<td><t t-esc="'%.2f' % val"/></td> <t t-set="i" t-value="item[0]"/>
<t t-set="total_yet_billed" t-value="total_billed + val"/> <t t-set="m" t-value="item[1]"/>
</t>
<t t-if="i &lt;= current_month_index">
<t t-set="val" t-value="summary['yet_to_billed'][m] or 0.0"/>
<td><t t-esc="'%.2f' % val"/></td>
<t t-set="total_yet_billed" t-value="total_yet_billed + val"/>
</t>
<t t-else="">
<td>0.00</td>
</t>
</t>
<td><t t-esc="summary['ytd']['yet_to_billed']"/></td>
<td><t t-esc="summary['ytd']['yet_to_billed']"/></td>
</tr>
<td><t t-esc="'%.2f' % float(total_yet_billed)"/></td>
<td><t t-esc="summary['ytd']['yet_to_billed']"/></td>
</tr>
<tr> <tr>
<td style="background-color:#e4e0f9"><strong>Collected</strong></td> <td style="background-color:#e4e0f9"><strong>Collected</strong></td>
<t t-set="total_collected" t-value="0"/> <t t-set="total_collected" t-value="0"/>
<t t-foreach="months" t-as="m"> <t t-foreach="months" t-as="m">
<t t-set="val" t-value="summary['collected'][m]"/> <t t-set="val" t-value="summary['collected'][m]"/>
<td><t t-esc="val"/></td> <td><t t-esc="'%.2f' % val"/></td>
<t t-set="total_collected" t-value="total_collected + val"/> <t t-set="total_collected" t-value="total_collected + val"/>
</t> </t>
<td><t t-esc="'%.2f' % float(total_collected)"/></td> <td><t t-esc="'%.2f' % float(total_collected)"/></td>
@ -186,22 +199,25 @@
<td><t t-esc="'%.2f' % float(doc.ytd_billed)"/></td> <td><t t-esc="'%.2f' % float(doc.ytd_billed)"/></td>
</tr> </tr>
<tr> <tr>
<td style="background-color:#e4e0f9"><strong>Yet to Bill</strong></td> <td style="background-color:#e4e0f9"><strong>Yet to Bill</strong></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_april)"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_may)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_april) if current_month_index >= 0 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_june)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_may) if current_month_index >= 1 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_july)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_june) if current_month_index >= 2 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_august)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_july) if current_month_index >= 3 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_september)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_august) if current_month_index >= 4 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_october)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_september) if current_month_index >= 5 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_november)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_october) if current_month_index >= 6 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_december)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_november) if current_month_index >= 7 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_january)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_december) if current_month_index >= 8 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_february)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_january) if current_month_index >= 9 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_march)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_february) if current_month_index >= 10 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_total)"/></td> <td><t t-esc="'%.2f' % float(doc.yet_to_billed_target_march) if current_month_index >= 11 else '0.00'"/></td>
<td><t t-esc="'%.2f' % float(doc.ytd_yet_to_billed)"/></td>
</tr> <td><t t-esc="'%.2f' % float(doc.ytd_yet_to_billed)"/></td>
<td><t t-esc="'%.2f' % float(doc.ytd_yet_to_billed)"/></td>
</tr>
<tr> <tr>
<td style="background-color:#e4e0f9"><strong>Collected</strong></td> <td style="background-color:#e4e0f9"><strong>Collected</strong></td>
<td><t t-esc="'%.2f' % float(doc.collected_target_april)"/></td> <td><t t-esc="'%.2f' % float(doc.collected_target_april)"/></td>

View File

@ -61,5 +61,7 @@ access_sos_sales_achievement_report_brief_wizard,sos_sales_achievement_report_br
access_sos_billing_collection,sos_billing_collection access,model_sos_billing_collection,base.group_user,1,1,1,1 access_sos_billing_collection,sos_billing_collection access,model_sos_billing_collection,base.group_user,1,1,1,1
access_sos_billed_collection_wizard,sos_billed_collection_wizard access,model_sos_billed_collection_wizard,base.group_user,1,1,1,1 access_sos_billed_collection_wizard,sos_billed_collection_wizard access,model_sos_billed_collection_wizard,base.group_user,1,1,1,1
access_sos_business_performance_wizard,sos_business_performance_wizard access,model_sos_business_performance_wizard,base.group_user,1,1,1,1 access_sos_business_performance_wizard,sos_business_performance_wizard access,model_sos_business_performance_wizard,base.group_user,1,1,1,1
access_sos_products,sos_products access,model_sos_products,base.group_user,1,1,1,1
access_sos_projects,sos_projects access,model_sos_projects,base.group_user,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
61 access_sos_billing_collection sos_billing_collection access model_sos_billing_collection base.group_user 1 1 1 1
62 access_sos_billed_collection_wizard sos_billed_collection_wizard access model_sos_billed_collection_wizard base.group_user 1 1 1 1
63 access_sos_business_performance_wizard sos_business_performance_wizard access model_sos_business_performance_wizard base.group_user 1 1 1 1
64 access_sos_products sos_products access model_sos_products base.group_user 1 1 1 1
65 access_sos_projects sos_projects access model_sos_projects base.group_user 1 1 1 1
66
67

View File

@ -13,13 +13,23 @@ name="action_report_achievement_btn"><i class="fa fa-print"></i> Print Report</b
<sheet> <sheet>
<h2 style="text-align: center;text-transform: uppercase;text-shadow: 1px 1p 1px #140718;color: #65407c;padding:5px;">Sales Achievements Report</h2><hr></hr><br></br> <h2 style="text-align: center;text-transform: uppercase;text-shadow: 1px 1p 1px #140718;color: #65407c;padding:5px;">Sales Achievements Report</h2><hr></hr><br></br>
<group> <group>
<field name="financial_year" style="font-size: 20px; pointer-events: none; color: #793595;"/> <group><field name="financial_year" style="font-size: 20px; pointer-events: none; color: #793595;"/>
<field name="sales_person" />
<field name="overall_target" />
<field name="opening_balance" groups="sos_inventory.sos_finance_user,sos_inventory.sos_management_user"/>
</group> </group>
<group><field name="sales_person" /></group>
<group><field name="overall_target" /></group>
<table style="margin-left: 15px;"><tr>
<td><group><field name="opening_balance" groups="sos_inventory.sos_finance_user,sos_inventory.sos_management_user"/>
</group></td>
<td><button name="action_view_brief_lines_acc"
type="object"
string="📊"
class="btn-link"
context="{'month': 0}"
style="padding: 0; border: none; background: none; font-size: 18px; box-shadow: 4px 5px 5px #e3e2e2;"/>
</td>
</tr></table>
</group>
<br></br> <br></br>
<table class="table_custom"> <table class="table_custom">
<thead> <thead>

View File

@ -22,11 +22,11 @@
<field name="model">sos_sales_leads</field> <field name="model">sos_sales_leads</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<searchpanel> <searchpanel>
<field name="products" string="Products Interested In" icon="fa-list-ul" enable_counters="1"/>
<field name="vertical_domain" string="Vertical/Domain" icon="fa-pie-chart" enable_counters="1"/>
</searchpanel> <field name="sales_type" string="Type" icon="fa-list-ul" enable_counters="1"/>
</searchpanel>
<!-- Add fields to search on --> <!-- Add fields to search on -->
<field name="company_name" string="Company Name"/> <field name="company_name" string="Company Name"/>
@ -53,20 +53,25 @@
<group> <group>
<group> <group>
<field name="sales_type"/>
<field name="lead_generated_by"/> <field name="lead_generated_by"/>
<field name="company_name"/> <field name="company_name"/>
<field name="convert_to_customer_btn_display" invisible="1"/> <field name="convert_to_customer_btn_display" invisible="1"/>
<field name="transferred_on" invisible="1"/> <field name="transferred_on" invisible="1"/>
<field name="country" invisible="sales_type != 'International'"/>
<field name="website_url"/> <field name="website_url"/>
<field name="linkedin_profile"/> <field name="linkedin_profile"/>
<field name="correspondence_address"/> <field name="correspondence_address"/>
</group> </group>
<group> <group>
<field name="interested_in"/> <field name="interested_in"/>
<field name="project_name" invisible="interested_in == 'products'"/> <field name="project_name" invisible="interested_in == 'Product'"/>
<field name="products" invisible="interested_in == 'projects'"/> <field name="products_interested"
options="{'no_create': True, 'no_edit': True, 'no_create_edit': True}"
widget="many2many_tags" invisible="interested_in != 'Product'"/>
<field name="location"/> <field name="location"/>
<field name="vertical_domain"/> <field name="vertical_domain" widget="many2many_tags"/>
<field name="source"/> <field name="source"/>
<field name="expo_name" invisible="source != 'expo'"/> <field name="expo_name" invisible="source != 'expo'"/>
</group> </group>
@ -82,6 +87,8 @@
<field name="dept"/> <field name="dept"/>
<field name="email"/> <field name="email"/>
<field name="mobile_number"/> <field name="mobile_number"/>
<field name="linkedin_profile"/>
<field name="remarks"/>
</tree> </tree>
</field> </field>

View File

@ -1,5 +1,29 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<record id="view_form_sos_sales_achievement_acc" model="ir.ui.view">
<field name="name">sos.sales.achievement.report.brief.form</field>
<field name="model">sos_sales_achievement_report_brief</field>
<field name="arch" type="xml">
<form string="Achievement Brief">
<sheet>
<group>
<field name="ref_id" invisible="1"/>
<field name="financial_year"/>
<field name="sales_person"/>
<field name="customer_name"/>
<field name="invoice_no"/>
<field name="action_date"/>
<field name="po_no"/>
<field name="proposal_value"/>
<field name="billed_date"/>
<field name="billed_amount"/>
<field name="currency_id" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_sos_sales_achievement_brief_wizard_form" model="ir.ui.view"> <record id="view_sos_sales_achievement_brief_wizard_form" model="ir.ui.view">
<field name="name">sos_sales_achievement_report_brief_wizard.form</field> <field name="name">sos_sales_achievement_report_brief_wizard.form</field>
@ -19,13 +43,18 @@
<field name="brief_line_ids" nolabel="1"> <field name="brief_line_ids" nolabel="1">
<tree> <tree>
<field name="financial_year"/>
<field name="action_date" string="Date"/> <field name="action_date" string="Date"/>
<field name="customer_name"/> <field name="customer_name"/>
<field name="po_no"/>
<field name="invoice_no"/>
<field name="proposal_value"/> <field name="proposal_value"/>
<field name="billed_date"/> <field name="billed_date"/>
<field name="billed_amount"/> <field name="billed_amount"/>
<button name="open_line_form" string="Edit" <button name="delete_achievement_line" class="btn btn-primary" string="Delete"
type="object" icon="fa-pencil" invisible="billed_date != False and billed_amount != False"/> type="object" icon="fa-times"/>
<button name="open_line_form" class="btn btn-primary" string="Edit"
type="object" icon="fa-pencil"/>
</tree> </tree>
</field> </field>
@ -139,6 +168,8 @@
<field name="customer_name"/> <field name="customer_name"/>
<field name="value"/> <field name="value"/>
<field name="invoice_no"/> <field name="invoice_no"/>
<button name="delete_form_line" class="btn btn-primary" string="Delete"
type="object" icon="fa-times"/>
</tree> </tree>
</field> </field>
<footer> <footer>