527 lines
20 KiB
Python
Executable File
527 lines
20 KiB
Python
Executable File
from odoo import models, fields, api
|
|
from datetime import date
|
|
from odoo.exceptions import UserError
|
|
from datetime import date, timedelta
|
|
from calendar import month_name
|
|
|
|
|
|
class sos_sales_action_plan(models.Model):
|
|
_name = 'sos_sales_action_plan'
|
|
_description = 'Sosaley Sales Action Plan'
|
|
_rec_name="customer_name"
|
|
|
|
date = fields.Date(string="Action Date",required=True)
|
|
customer_name = fields.Many2one(
|
|
'sos_customers',
|
|
string="Customer Name",
|
|
required=True,
|
|
domain=lambda self: self._get_customer_domain()
|
|
)
|
|
end_customer_name = fields.Char(string="End Customer Name")
|
|
quote_no = fields.Char(string="Quote/W.O No",help="Fill this if the same customer has different work orders.")
|
|
quote_no_selector = fields.Many2one(
|
|
'sos_case_diary',
|
|
string="End Customer/Quote No",
|
|
domain="[('customer_name', '=', customer_name), ('quote_no', '!=', False)]"
|
|
)
|
|
interested_in = fields.Selection(
|
|
[
|
|
('Product', 'Products'),
|
|
('Project', 'Projects')
|
|
],
|
|
string="Interested In",required=True,default="Product")
|
|
sales_type = fields.Selection(
|
|
[
|
|
('Domestic', 'Domestic'),
|
|
('International', 'International')
|
|
],
|
|
string="Sales Type",default="Domestic")
|
|
project_name= fields.Many2one('sos_projects',string="Project Name")
|
|
country = fields.Many2one(
|
|
'res.country',
|
|
string='Country',
|
|
default=lambda self: self.env['res.country'].search([('code', '=', 'IN')], limit=1)
|
|
)
|
|
ce_product_type = fields.Selection(
|
|
[
|
|
('Sales', 'Sales'),
|
|
('Service', 'Service'),
|
|
('Spare', 'Spare'),
|
|
('Cloud', 'Cloud')
|
|
],
|
|
string="Service Type")
|
|
product = 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")
|
|
location = fields.Char(string="Location")
|
|
quantity = fields.Char(string="Quantity")
|
|
sales_executive = fields.Many2one(
|
|
'res.users',
|
|
string='Sales Executive',
|
|
default=lambda self: self.env.user,
|
|
readonly=True
|
|
)
|
|
sales_head = fields.Many2one(
|
|
'res.users',
|
|
string='Sales Head',
|
|
default=lambda self: self.env.user,
|
|
domain=lambda self: [('groups_id', 'in', self.env.ref('sos_inventory.sos_sales_user').ids + self.env.ref('sos_inventory.sos_ce_head').ids + self.env.ref('sos_inventory.sos_sales_sapl_user').ids)]
|
|
|
|
)
|
|
action_type = fields.Selection([
|
|
('Meeting', 'Meeting'),
|
|
('Demo', 'Demo'),
|
|
('Discussion', 'Discussion'),
|
|
('Visit', 'Direct Visit'),
|
|
('Negotiation', 'Negotiation'),
|
|
('Validation', 'Validation'),
|
|
('Proposal', 'Proposal'),
|
|
('Email/Call/Video Call', 'Email/Call/Video Call')
|
|
], string='Action Type',requierd=True)
|
|
current_spenco_status = fields.Selection([
|
|
('Suspects', 'Suspects'),
|
|
('Prospects', 'Prospects'),
|
|
('Engaged', 'Engaged'),
|
|
('Negotiation', 'Negotiation'),
|
|
('Commercial Order', 'Commercial Order')
|
|
], string='Current SPENCO Status')
|
|
po_copy = fields.Binary(string='PO Copy', attachment=True)
|
|
po_copy_filename = fields.Char(string='PO Copy Filename')
|
|
action = fields.Selection(
|
|
[
|
|
('Generate More Suspects', 'Generate More Suspects'),
|
|
('Suspect to Prospects', 'Suspect to Prospects'),
|
|
('Prospect to Engaged', 'Prospect to Engaged'),
|
|
('Engaged to Negotiation', 'Engaged to Negotiation'),
|
|
('Negotiation to Order', 'Negotiation to Order')
|
|
],
|
|
string="Action Category",required=True)
|
|
action_plan = fields.Text(string="Action Plan")
|
|
result = fields.Text(string="Result")
|
|
status = fields.Selection(
|
|
[
|
|
('open', 'Open'),
|
|
('close', 'Closed without Order'),
|
|
('close_order', 'Closed with Order')
|
|
],
|
|
string="Status",default='open',required=True)
|
|
currency_id = fields.Many2one('res.currency', string='Currency')
|
|
po_no= fields.Char(string="PO No")
|
|
value = fields.Monetary(currency_field='currency_id', string="Value (In Lakhs)")
|
|
next_action_date = fields.Date(string="Next Action On")
|
|
update_done = fields.Boolean(string="Update Done", default=False)
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('confirmed', 'Confirmed'),
|
|
], string='State', default='draft', readonly=True)
|
|
is_ce_user_created = fields.Boolean(
|
|
compute='_compute_is_ce_user_created',
|
|
store=True,
|
|
string='Created by CE User'
|
|
)
|
|
reporting_to = fields.Many2one('res.users',related="sales_executive.reporting_to", string='Reporting To')
|
|
@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
|
|
)
|
|
def _get_customer_domain(self):
|
|
if (
|
|
self.env.user.has_group('sos_inventory.sos_management_user') or
|
|
self.env.user.has_group('sos_inventory.sos_ce_head') or
|
|
self.env.user.has_group('sos_inventory.sos_ce_user')
|
|
):
|
|
return [] # no filter, show all
|
|
return [('responsible', '=', self.env.uid)]
|
|
|
|
|
|
@api.onchange('quote_no_selector')
|
|
def _onchange_quote_no_selector(self):
|
|
if self.quote_no_selector:
|
|
self.quote_no = self.quote_no_selector.quote_no
|
|
self.end_customer_name = self.quote_no_selector.end_customer_name
|
|
|
|
def action_prev_action_plans(self):
|
|
domain = [('customer_name', '=', self.customer_name.id)]
|
|
if self.quote_no:
|
|
domain.append(('quote_no', '=', self.quote_no))
|
|
if self.quote_no:
|
|
domain.append(('product', '=', self.product))
|
|
prev_action_plans = self.env['sos_sales_action_plan'].search(domain)
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'name': 'Previous Action Plans',
|
|
'res_model': 'sos_sales_action_plan',
|
|
'view_mode': 'tree',
|
|
'views': [(self.env.ref('sos_sales.view_prev_action_plan_tree').id, 'tree')],
|
|
'domain': [('id', 'in', prev_action_plans.ids)],
|
|
'target': 'new',
|
|
}
|
|
@api.onchange('quote_no')
|
|
def _onchange_quote_no(self):
|
|
"""Set products from sos_case_diary if quote_no and customer match"""
|
|
if self.customer_name and self.quote_no:
|
|
case = self.env['sos_case_diary'].search([
|
|
('customer_name', '=', self.customer_name.id),
|
|
('quote_no', '=', self.quote_no)
|
|
], limit=1)
|
|
|
|
if case:
|
|
self.product = case.products # assuming it's Char or same type
|
|
self.location = case.customer_city
|
|
self.quantity = case.quantity
|
|
else:
|
|
self.product = False
|
|
self.location = False
|
|
self.quantity = False
|
|
def write(self, vals):
|
|
if 'status' in vals:
|
|
for record in self:
|
|
domain = [
|
|
('customer_name', '=', record.customer_name.customer_name),
|
|
('products', '=', record.product),
|
|
('sales_person', '=', record.sales_executive.id)
|
|
]
|
|
if record.quote_no:
|
|
domain.append(('quote_no', '=', record.quote_no))
|
|
|
|
case_diary_records = self.env['sos_case_diary'].search(domain, limit=1)
|
|
if case_diary_records:
|
|
case_diary_records.write({"status": vals['status']})
|
|
|
|
return super().write(vals)
|
|
|
|
|
|
def action_view_po(self):
|
|
# Check if there is a test report
|
|
if not self.po_copy:
|
|
raise UserError("No po available for this record.")
|
|
|
|
# Use `ir.actions.act_url` to open the binary file as a PDF
|
|
return {
|
|
'type': 'ir.actions.act_url',
|
|
'url': '/web/content/{}/{}/{}?download=false'.format(
|
|
self._name, self.id, 'po_copy'),
|
|
'target': 'new', # This opens the PDF in a new tab
|
|
}
|
|
@api.onchange('current_spenco_status')
|
|
def _onchange_current_spenco_status(self):
|
|
if self.current_spenco_status != 'Commercial Order':
|
|
self.po_copy = False
|
|
|
|
def unlink(self):
|
|
for record in self:
|
|
if record.update_done:
|
|
raise UserError("You can't delete the action plan after case diary updation!")
|
|
|
|
action_plan_date = record.date
|
|
sales_executive = record.sales_executive
|
|
|
|
# Week-wise
|
|
week_number = record._compute_week_number(action_plan_date)
|
|
record.decrement_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='week_number',
|
|
field_value=week_number,
|
|
model_name='sos_action_plan_summary_week_wise'
|
|
)
|
|
# Month-wise
|
|
month_number = record._compute_month_number(action_plan_date)
|
|
record.decrement_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='month_number',
|
|
field_value=month_number,
|
|
model_name='sos_action_plan_summary_month_wise'
|
|
)
|
|
# Quarter-wise
|
|
quarter_number = record._compute_quarter_number(action_plan_date)
|
|
record.decrement_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='quarter_number',
|
|
field_value=quarter_number,
|
|
model_name='sos_action_plan_summary_quarter_wise'
|
|
)
|
|
# Year-wise
|
|
year_number = record._compute_year_number(action_plan_date)
|
|
record.decrement_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='year',
|
|
field_value=year_number,
|
|
model_name='sos_action_plan_summary_year_wise'
|
|
)
|
|
|
|
return super(sos_sales_action_plan, self).unlink()
|
|
|
|
def decrement_summary(self, action_plan_date, sales_executive, field_name, field_value, model_name):
|
|
SummaryModel = self.env[model_name]
|
|
|
|
record = SummaryModel.search([
|
|
('sales_executive', '=', sales_executive.id),
|
|
(field_name, '=', field_value),
|
|
('action', '=', self.action),
|
|
('action_type', '=', self.action_type)
|
|
], limit=1)
|
|
|
|
if record and record.count > 1:
|
|
record.write({'count': record.count - 1})
|
|
elif record:
|
|
record.unlink()
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
record = super(sos_sales_action_plan, self).create(vals)
|
|
record.state = 'confirmed'
|
|
|
|
# Now access fields from the created record
|
|
sales_executive = record.sales_executive
|
|
action_plan_date = record.date
|
|
#week wise
|
|
week_number = record._compute_week_number(action_plan_date)
|
|
record.update_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='week_number',
|
|
field_value=week_number,
|
|
model_name='sos_action_plan_summary_week_wise'
|
|
)
|
|
#month wise
|
|
month_number = record._compute_month_number(action_plan_date)
|
|
record.update_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='month_number',
|
|
field_value=month_number,
|
|
model_name='sos_action_plan_summary_month_wise'
|
|
)
|
|
#quarter wise
|
|
quarter_number = record._compute_quarter_number(action_plan_date)
|
|
record.update_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='quarter_number',
|
|
field_value=quarter_number,
|
|
model_name='sos_action_plan_summary_quarter_wise'
|
|
)
|
|
#year wise
|
|
year_number = record._compute_year_number(action_plan_date)
|
|
record.update_summary(
|
|
action_plan_date=action_plan_date,
|
|
sales_executive=sales_executive,
|
|
field_name='year',
|
|
field_value=year_number,
|
|
model_name='sos_action_plan_summary_year_wise'
|
|
)
|
|
return record
|
|
def _compute_year_number(self,action_plan_date):
|
|
month_number = action_plan_date.strftime('%B')
|
|
month = action_plan_date.month
|
|
year = action_plan_date.year
|
|
year_number = f"{year}-{year + 1}" if month >= 4 else f"{year - 1}-{year}"
|
|
return year_number
|
|
def _compute_quarter_number(self,action_plan_date):
|
|
month_number = action_plan_date.strftime('%B')
|
|
month = action_plan_date.month
|
|
quarter_number = (
|
|
"Q1" if 4 <= month <= 6 else
|
|
"Q2" if 7 <= month <= 9 else
|
|
"Q3" if 10 <= month <= 12 else "Q4"
|
|
)
|
|
return quarter_number
|
|
def _compute_month_number(self,action_plan_date):
|
|
month_number = action_plan_date.strftime('%B')
|
|
return month_number
|
|
def _compute_week_number(self,action_plan_date):
|
|
start_of_week = action_plan_date - timedelta(days=action_plan_date.weekday())
|
|
end_of_week = start_of_week + timedelta(days=5)
|
|
return f"{start_of_week.strftime('%b %d')} - {end_of_week.strftime('%b %d')}"
|
|
def update_summary(self, action_plan_date, sales_executive, field_name, field_value, model_name):
|
|
SummaryModel = self.env[model_name]
|
|
|
|
record = SummaryModel.search([
|
|
('sales_executive', '=', sales_executive.id),
|
|
(field_name, '=', field_value),
|
|
('action', '=', self.action),
|
|
('action_type', '=', self.action_type)
|
|
], limit=1)
|
|
|
|
if record:
|
|
record.write({
|
|
'count': record.count + 1
|
|
})
|
|
else:
|
|
record = SummaryModel.create({
|
|
'sales_executive': sales_executive.id,
|
|
field_name: field_value,
|
|
'action': self.action,
|
|
'action_type': self.action_type,
|
|
'entered_date': action_plan_date,
|
|
'count': 1
|
|
})
|
|
|
|
return record
|
|
|
|
def view_casediary(self):
|
|
domain = [
|
|
('customer_name', '=', self.customer_name.id),
|
|
('products', '=', self.product),
|
|
('sales_person', '=', self.sales_executive.id)
|
|
]
|
|
if self.quote_no:
|
|
domain.append(('quote_no', '=', self.quote_no))
|
|
case_diary_records = self.env['sos_case_diary'].search(domain, limit=1)
|
|
if case_diary_records:
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'name': 'Case Diary',
|
|
'res_model': 'sos_case_diary',
|
|
'view_mode': 'form',
|
|
'res_id': case_diary_records.id,
|
|
'target': 'current',
|
|
}
|
|
else:
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'message': "Not Found",
|
|
'type': 'danger',
|
|
'sticky': False
|
|
}
|
|
}
|
|
|
|
|
|
|
|
def update_casediary(self):
|
|
if self.update_done:
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'message': "Already updated!",
|
|
'type': 'warning',
|
|
'sticky': False
|
|
}
|
|
}
|
|
|
|
# Validate mandatory fields
|
|
missing_fields = []
|
|
if not self.current_spenco_status:
|
|
missing_fields.append("Current SPENCO Status")
|
|
if not self.next_action_date:
|
|
missing_fields.append("Next Action Date")
|
|
if not self.result:
|
|
missing_fields.append("Result")
|
|
if self.value <= 0.00:
|
|
if self.current_spenco_status != "Suspects":
|
|
missing_fields.append("Value")
|
|
|
|
if missing_fields:
|
|
raise UserError(
|
|
f"The following fields are required before updating the Case Diary: {', '.join(missing_fields)}"
|
|
)
|
|
|
|
self.update_done = True
|
|
|
|
domain = [
|
|
('customer_name', '=', self.customer_name.id),
|
|
('products', '=', self.product),
|
|
('sales_person', '=', self.env.user.id)
|
|
]
|
|
|
|
if self.quote_no:
|
|
domain.append(('quote_no', '=', self.quote_no))
|
|
if self.end_customer_name:
|
|
domain.append(('end_customer_name', '=', self.end_customer_name))
|
|
case_diary_records = self.env['sos_case_diary'].search(domain, limit=1)
|
|
|
|
if case_diary_records:
|
|
case_diary_records.write({
|
|
'status': self.status,
|
|
'po_copy':self.po_copy,
|
|
'po_no':self.po_no,
|
|
'quantity':self.quantity,
|
|
'po_copy_filename':self.po_copy_filename
|
|
})
|
|
case_diary_records.line_ids.create({
|
|
'ref_id': case_diary_records.id,
|
|
'action_plan_date': self.date,
|
|
'action_plan': self.action_plan,
|
|
'action_type': self.action_type,
|
|
'notes': self.result,
|
|
'next_action_date': self.next_action_date,
|
|
'status_changed_on': date.today(),
|
|
'spenco_status': self.current_spenco_status,
|
|
'current_state_value': self.value,
|
|
})
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'message': "Updated",
|
|
'type': 'success',
|
|
'sticky': False
|
|
}
|
|
}
|
|
else:
|
|
interested_in=self.interested_in.lower()+'s'
|
|
vals = {
|
|
'customer_name': self.customer_name.id,
|
|
'end_customer_name': self.end_customer_name,
|
|
'customer_city': self.location,
|
|
'sales_person': self.sales_executive.id,
|
|
'products': self.product,
|
|
'proposal_value': self.value,
|
|
'status': self.status,
|
|
'quote_no': self.quote_no,
|
|
'quantity': self.quantity,
|
|
'po_no': self.po_no,
|
|
'po_copy': self.po_copy,
|
|
'po_copy_filename': self.po_copy_filename,
|
|
'sales_type':self.sales_type,
|
|
'project_name':self.project_name.id,
|
|
'interested_in':interested_in,
|
|
'country':self.country.id
|
|
}
|
|
if self.ce_product_type:
|
|
vals['ce_product_type'] = self.ce_product_type
|
|
casediary_record = self.env['sos_case_diary'].create(vals)
|
|
self.env['sos_case_diary_line'].create({
|
|
'ref_id': casediary_record.id,
|
|
'action_plan_date': self.date,
|
|
'action_plan': self.action_plan,
|
|
'action_type': self.action_type,
|
|
'notes': self.result,
|
|
'next_action_date': self.next_action_date,
|
|
'status_changed_on': date.today(),
|
|
'spenco_status': self.current_spenco_status,
|
|
'current_state_value': self.value
|
|
})
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'message': "Created New Case Diary",
|
|
'type': 'success',
|
|
'sticky': False
|
|
}
|
|
}
|