[crm] Updated status and workflow for Lead > Opportunity > Quotation > Sales Order
This commit is contained in:
parent
43247cedea
commit
800b3aa437
@ -14,7 +14,10 @@ class SellingController(StockController):
|
|||||||
def onload_post_render(self):
|
def onload_post_render(self):
|
||||||
# contact, address, item details and pos details (if applicable)
|
# contact, address, item details and pos details (if applicable)
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
|
|
||||||
|
def get_sender(self, comm):
|
||||||
|
return webnotes.conn.get_value('Sales Email Settings', None, 'email_id')
|
||||||
|
|
||||||
def set_missing_values(self, for_validate=False):
|
def set_missing_values(self, for_validate=False):
|
||||||
super(SellingController, self).set_missing_values(for_validate)
|
super(SellingController, self).set_missing_values(for_validate)
|
||||||
|
|
||||||
|
@ -8,6 +8,51 @@ from webnotes import msgprint
|
|||||||
|
|
||||||
from webnotes.model.controller import DocListController
|
from webnotes.model.controller import DocListController
|
||||||
|
|
||||||
|
status_map = {
|
||||||
|
"Contact": [
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Open", "communication_received"]
|
||||||
|
],
|
||||||
|
"Job Applicant": [
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Open", "communication_received"]
|
||||||
|
],
|
||||||
|
"Lead": [
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Converted", "has_customer"],
|
||||||
|
["Opportunity", "has_opportunity"],
|
||||||
|
["Open", "communication_received"],
|
||||||
|
],
|
||||||
|
"Opportunity": [
|
||||||
|
["Draft", None],
|
||||||
|
["Submitted", "eval:self.doc.docstatus==1"],
|
||||||
|
["Lost", "eval:self.doc.status=='Lost'"],
|
||||||
|
["Quotation", "has_quotation"],
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Cancelled", "eval:self.doc.docstatus==2"],
|
||||||
|
["Open", "communication_received"],
|
||||||
|
],
|
||||||
|
"Quotation": [
|
||||||
|
["Draft", None],
|
||||||
|
["Submitted", "eval:self.doc.docstatus==1"],
|
||||||
|
["Lost", "eval:self.doc.status=='Lost'"],
|
||||||
|
["Ordered", "has_sales_order"],
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Cancelled", "eval:self.doc.docstatus==2"],
|
||||||
|
["Open", "communication_received"],
|
||||||
|
],
|
||||||
|
"Sales Order": [
|
||||||
|
["Draft", None],
|
||||||
|
["Submitted", "eval:self.doc.docstatus==1"],
|
||||||
|
["Stopped", "eval:self.doc.status=='Stopped'"],
|
||||||
|
["Cancelled", "eval:self.doc.docstatus==2"],
|
||||||
|
],
|
||||||
|
"Support Ticket": [
|
||||||
|
["Replied", "communication_sent"],
|
||||||
|
["Open", "communication_received"]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
class StatusUpdater(DocListController):
|
class StatusUpdater(DocListController):
|
||||||
"""
|
"""
|
||||||
Updates the status of the calling records
|
Updates the status of the calling records
|
||||||
@ -20,6 +65,39 @@ class StatusUpdater(DocListController):
|
|||||||
self.update_qty()
|
self.update_qty()
|
||||||
self.validate_qty()
|
self.validate_qty()
|
||||||
|
|
||||||
|
def set_status(self, update=False):
|
||||||
|
if self.doc.get("__islocal"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.doc.doctype in status_map.keys():
|
||||||
|
for s in status_map[self.doc.doctype].reverse():
|
||||||
|
if not s[1]:
|
||||||
|
self.doc.status = s[0]
|
||||||
|
break
|
||||||
|
elif s[1].startwith("eval:"):
|
||||||
|
if eval(s[1][5:]):
|
||||||
|
self.doc.status = s[0]
|
||||||
|
break
|
||||||
|
elif getattr(self, s[1])():
|
||||||
|
self.doc.status = s[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
if update:
|
||||||
|
webnotes.conn.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status)
|
||||||
|
|
||||||
|
def on_communication(self):
|
||||||
|
self.set_status(update=True)
|
||||||
|
|
||||||
|
def communication_received(self):
|
||||||
|
last_comm = self.doclist.get({"doctype":"Communication"})[-1]
|
||||||
|
if last_comm:
|
||||||
|
return last_comm.sent_or_received == "Received"
|
||||||
|
|
||||||
|
def communication_sent(self):
|
||||||
|
last_comm = self.doclist.get({"doctype":"Communication"})[-1]
|
||||||
|
if last_comm:
|
||||||
|
return last_comm.sent_or_received == "Sent"
|
||||||
|
|
||||||
def validate_qty(self):
|
def validate_qty(self):
|
||||||
"""
|
"""
|
||||||
Validates qty at row level
|
Validates qty at row level
|
||||||
|
@ -11,14 +11,9 @@ from webnotes.utils import extract_email_id
|
|||||||
class DocType(TransactionBase):
|
class DocType(TransactionBase):
|
||||||
def __init__(self, d, dl):
|
def __init__(self, d, dl):
|
||||||
self.doc, self.doclist = d, dl
|
self.doc, self.doclist = d, dl
|
||||||
|
|
||||||
def get_sender(self, comm):
|
def get_sender(self, comm):
|
||||||
return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
|
return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
|
||||||
|
|
||||||
def on_communication(self, comm):
|
def validate(self):
|
||||||
if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
|
self.set_status()
|
||||||
status = "Replied"
|
|
||||||
else:
|
|
||||||
status = "Open"
|
|
||||||
|
|
||||||
webnotes.conn.set(self.doc, 'status', status)
|
|
9
patches/october_2013/p02_set_communication_status.py
Normal file
9
patches/october_2013/p02_set_communication_status.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import webnotes
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
webnotes.conn.sql("""update tabCommunication
|
||||||
|
set sent_or_received= if(ifnull(recipients, '')='', "Received", "Sent")""")
|
32
patches/october_2013/p03_crm_update_status.py
Normal file
32
patches/october_2013/p03_crm_update_status.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import webnotes
|
||||||
|
|
||||||
|
# reason field
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
change_map = {
|
||||||
|
"Lead": [
|
||||||
|
["Lead Lost", "Lead"],
|
||||||
|
["Not interested", "Do Not Contact"],
|
||||||
|
["Opportunity Made", "Opportunity"],
|
||||||
|
["Contacted", "Replied"],
|
||||||
|
["Attempted to Contact", "Replied"],
|
||||||
|
["Contact in Future", "Interested"],
|
||||||
|
],
|
||||||
|
"Opportunity": [
|
||||||
|
["Quotation Sent", "Quotation"],
|
||||||
|
["Order Confirmed", "Quotation"],
|
||||||
|
["Opportunity Lost", "Lost"],
|
||||||
|
],
|
||||||
|
"Quotation": [
|
||||||
|
["Order Confirmed", "Ordered"],
|
||||||
|
["Order Lost", "Lost"]
|
||||||
|
],
|
||||||
|
"Support Ticket": [
|
||||||
|
["Waiting for Customer", "Replied"],
|
||||||
|
["To Reply", "Open"],
|
||||||
|
]
|
||||||
|
}
|
@ -221,4 +221,6 @@ patch_list = [
|
|||||||
"patches.september_2013.p05_fix_customer_in_pos",
|
"patches.september_2013.p05_fix_customer_in_pos",
|
||||||
"patches.october_2013.fix_is_cancelled_in_sle",
|
"patches.october_2013.fix_is_cancelled_in_sle",
|
||||||
"patches.october_2013.p01_update_delivery_note_prevdocs",
|
"patches.october_2013.p01_update_delivery_note_prevdocs",
|
||||||
|
"patches.october_2013.p02_set_communication_status",
|
||||||
|
"patches.october_2013.p03_crm_update_status",
|
||||||
]
|
]
|
@ -26,24 +26,9 @@ class DocType(SellingController):
|
|||||||
customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
|
customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
|
||||||
if customer:
|
if customer:
|
||||||
self.doc.fields["__is_customer"] = customer
|
self.doc.fields["__is_customer"] = customer
|
||||||
|
|
||||||
def on_communication(self, comm):
|
|
||||||
if comm.sender == self.get_sender(comm) or \
|
|
||||||
webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
|
|
||||||
status = "Replied"
|
|
||||||
else:
|
|
||||||
status = "Open"
|
|
||||||
|
|
||||||
webnotes.conn.set(self.doc, 'status', status)
|
|
||||||
|
|
||||||
def check_status(self):
|
|
||||||
chk = webnotes.conn.sql("select status from `tabLead` where name=%s", self.doc.name)
|
|
||||||
chk = chk and chk[0][0] or ''
|
|
||||||
return cstr(chk)
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason:
|
self.set_status()
|
||||||
webnotes.throw("Please Enter Lost Reason under More Info section")
|
|
||||||
|
|
||||||
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
|
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
|
||||||
webnotes.throw("Please specify campaign name")
|
webnotes.throw("Please specify campaign name")
|
||||||
@ -75,14 +60,18 @@ class DocType(SellingController):
|
|||||||
webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \
|
webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \
|
||||||
", ".join(items), raise_exception=True)
|
", ".join(items), raise_exception=True)
|
||||||
|
|
||||||
def get_sender(self, comm):
|
|
||||||
return webnotes.conn.get_value('Sales Email Settings',None,'email_id')
|
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
|
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
|
||||||
self.doc.name)
|
self.doc.name)
|
||||||
|
|
||||||
self.delete_events()
|
self.delete_events()
|
||||||
|
|
||||||
|
def has_customer(self):
|
||||||
|
return webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
|
||||||
|
|
||||||
|
def has_opportunity(self):
|
||||||
|
return webnotes.conn.get_value("Opportunity", {"lead": self.doc.name, "docstatus": 1,
|
||||||
|
"status": ["!=", "Lost"]})
|
||||||
|
|
||||||
@webnotes.whitelist()
|
@webnotes.whitelist()
|
||||||
def make_customer(source_name, target_doclist=None):
|
def make_customer(source_name, target_doclist=None):
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-04-10 11:45:37",
|
"creation": "2013-04-10 11:45:37",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-10-02 14:24:30",
|
"modified": "2013-10-03 17:24:33",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -102,7 +102,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Open",
|
"default": "Lead",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
@ -112,7 +112,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
|
"options": "Lead\nOpen\nReplied\nOpportunity\nInterested\nConverted\nDo Not Contact",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
@ -334,18 +334,6 @@
|
|||||||
"oldfieldtype": "Column Break",
|
"oldfieldtype": "Column Break",
|
||||||
"width": "50%"
|
"width": "50%"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"depends_on": "eval:doc.status == 'Lead Lost'",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "order_lost_reason",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Lost Reason",
|
|
||||||
"oldfieldname": "order_lost_reason",
|
|
||||||
"oldfieldtype": "Link",
|
|
||||||
"options": "Quotation Lost Reason"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"description": "Your sales person who will contact the lead in future",
|
"description": "Your sales person who will contact the lead in future",
|
||||||
|
@ -101,20 +101,13 @@ $.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm}));
|
|||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn){
|
cur_frm.cscript.refresh = function(doc, cdt, cdn){
|
||||||
erpnext.hide_naming_series();
|
erpnext.hide_naming_series();
|
||||||
|
|
||||||
cur_frm.dashboard.reset(doc);
|
|
||||||
if(!doc.__islocal) {
|
|
||||||
if(doc.status=="Converted" || doc.status=="Order Confirmed") {
|
|
||||||
cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
|
|
||||||
} else if(doc.status=="Opportunity Lost") {
|
|
||||||
cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.clear_custom_buttons();
|
cur_frm.clear_custom_buttons();
|
||||||
if(doc.docstatus === 1 && doc.status!=="Opportunity Lost") {
|
if(doc.docstatus === 1 && doc.status!=="Lost") {
|
||||||
cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation);
|
cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation);
|
||||||
cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']);
|
if(doc.status!=="Quotation") {
|
||||||
|
cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']);
|
||||||
|
}
|
||||||
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
|
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import webnotes
|
|||||||
|
|
||||||
from webnotes.utils import cstr, getdate, cint
|
from webnotes.utils import cstr, getdate, cint
|
||||||
from webnotes.model.bean import getlist
|
from webnotes.model.bean import getlist
|
||||||
from webnotes import msgprint
|
from webnotes import msgprint, _
|
||||||
|
|
||||||
|
|
||||||
from utilities.transaction_base import TransactionBase
|
from utilities.transaction_base import TransactionBase
|
||||||
@ -67,7 +67,8 @@ class DocType(TransactionBase):
|
|||||||
'email_id' : contact and contact[0]['email_id'] or ''
|
'email_id' : contact and contact[0]['email_id'] or ''
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
# Add to calendar
|
# Add to calendar
|
||||||
if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
|
if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
|
||||||
@ -120,6 +121,7 @@ class DocType(TransactionBase):
|
|||||||
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
|
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
self.set_status()
|
||||||
self.set_last_contact_date()
|
self.set_last_contact_date()
|
||||||
self.validate_item_details()
|
self.validate_item_details()
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
@ -127,42 +129,29 @@ class DocType(TransactionBase):
|
|||||||
|
|
||||||
from accounts.utils import validate_fiscal_year
|
from accounts.utils import validate_fiscal_year
|
||||||
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
|
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
|
||||||
self.doc.status = "Draft"
|
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
if self.doc.lead:
|
||||||
if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted":
|
webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True)
|
||||||
webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made")
|
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
|
if self.has_quotation():
|
||||||
if chk:
|
webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
|
||||||
msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.")
|
self.set_status(update=True)
|
||||||
raise Exception
|
|
||||||
else:
|
|
||||||
webnotes.conn.set(self.doc, 'status', 'Cancelled')
|
|
||||||
if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead,
|
|
||||||
"status")!="Converted":
|
|
||||||
if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}):
|
|
||||||
status = "Contacted"
|
|
||||||
else:
|
|
||||||
status = "Open"
|
|
||||||
|
|
||||||
webnotes.conn.set_value("Lead", self.doc.lead, "status", status)
|
|
||||||
|
|
||||||
def declare_enquiry_lost(self,arg):
|
def declare_enquiry_lost(self,arg):
|
||||||
chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
|
if not self.has_quotation():
|
||||||
if chk:
|
webnotes.conn.set(self.doc, 'status', 'Lost')
|
||||||
msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.")
|
|
||||||
raise Exception
|
|
||||||
else:
|
|
||||||
webnotes.conn.set(self.doc, 'status', 'Opportunity Lost')
|
|
||||||
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
|
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
|
||||||
return 'true'
|
else:
|
||||||
|
webnotes.throw(_("Cannot declare as lost, because Quotation has been made."))
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
self.delete_events()
|
self.delete_events()
|
||||||
|
|
||||||
|
def has_quotation(self):
|
||||||
|
return webnotes.conn.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
|
||||||
|
|
||||||
@webnotes.whitelist()
|
@webnotes.whitelist()
|
||||||
def make_quotation(source_name, target_doclist=None):
|
def make_quotation(source_name, target_doclist=None):
|
||||||
from webnotes.model.mapper import get_mapped_doclist
|
from webnotes.model.mapper import get_mapped_doclist
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-03-07 18:50:30",
|
"creation": "2013-03-07 18:50:30",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-10-02 14:24:30",
|
"modified": "2013-10-03 16:30:58",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -126,7 +126,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled",
|
"options": "Draft\nSubmitted\nQuotation\nLost\nCancelled\nReplied\nOpen",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
@ -350,18 +350,6 @@
|
|||||||
"options": "Campaign",
|
"options": "Campaign",
|
||||||
"read_only": 0
|
"read_only": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "eval:!doc.__islocal",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "order_lost_reason",
|
|
||||||
"fieldtype": "Small Text",
|
|
||||||
"label": "Quotation Lost Reason",
|
|
||||||
"no_copy": 1,
|
|
||||||
"oldfieldname": "order_lost_reason",
|
|
||||||
"oldfieldtype": "Small Text",
|
|
||||||
"read_only": 1,
|
|
||||||
"report_hide": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
@ -376,6 +364,15 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "order_lost_reason",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Lost Reason",
|
||||||
|
"no_copy": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "column_break2",
|
"fieldname": "column_break2",
|
||||||
|
@ -24,19 +24,10 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
|
|||||||
},
|
},
|
||||||
refresh: function(doc, dt, dn) {
|
refresh: function(doc, dt, dn) {
|
||||||
this._super(doc, dt, dn);
|
this._super(doc, dt, dn);
|
||||||
|
|
||||||
cur_frm.dashboard.reset(doc);
|
|
||||||
if(!doc.__islocal) {
|
|
||||||
if(doc.status=="Converted" || doc.status=="Order Confirmed") {
|
|
||||||
cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
|
|
||||||
} else if(doc.status==="Order Lost") {
|
|
||||||
cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(doc.docstatus == 1 && doc.status!=='Order Lost') {
|
if(doc.docstatus == 1 && doc.status!=='Lost') {
|
||||||
cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
|
cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
|
||||||
if(doc.status!=="Order Confirmed") {
|
if(doc.status!=="Ordered") {
|
||||||
cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
|
cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
|
||||||
}
|
}
|
||||||
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
|
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
|
||||||
|
@ -47,6 +47,11 @@ class DocType(SellingController):
|
|||||||
if not doc.fields.get(r):
|
if not doc.fields.get(r):
|
||||||
doc.fields[r] = res[r]
|
doc.fields[r] = res[r]
|
||||||
|
|
||||||
|
|
||||||
|
def has_sales_order(self):
|
||||||
|
return webnotes.conn.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
|
||||||
|
|
||||||
|
|
||||||
# Re-calculates Basic Rate & amount based on Price List Selected
|
# Re-calculates Basic Rate & amount based on Price List Selected
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
def get_adj_percent(self, arg=''):
|
def get_adj_percent(self, arg=''):
|
||||||
@ -108,13 +113,7 @@ class DocType(SellingController):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
super(DocType, self).validate()
|
super(DocType, self).validate()
|
||||||
|
|
||||||
import utilities
|
self.set_status()
|
||||||
if not self.doc.status:
|
|
||||||
self.doc.status = "Draft"
|
|
||||||
else:
|
|
||||||
utilities.validate_status(self.doc.status, ["Draft", "Submitted",
|
|
||||||
"Order Confirmed", "Order Lost", "Cancelled"])
|
|
||||||
|
|
||||||
self.set_last_contact_date()
|
self.set_last_contact_date()
|
||||||
self.validate_order_type()
|
self.validate_order_type()
|
||||||
self.validate_for_items()
|
self.validate_for_items()
|
||||||
@ -125,42 +124,22 @@ class DocType(SellingController):
|
|||||||
sales_com_obj.check_active_sales_items(self)
|
sales_com_obj.check_active_sales_items(self)
|
||||||
sales_com_obj.validate_max_discount(self,'quotation_details')
|
sales_com_obj.validate_max_discount(self,'quotation_details')
|
||||||
sales_com_obj.check_conversion_rate(self)
|
sales_com_obj.check_conversion_rate(self)
|
||||||
|
|
||||||
|
|
||||||
def on_update(self):
|
|
||||||
# Set Quotation Status
|
|
||||||
webnotes.conn.set(self.doc, 'status', 'Draft')
|
|
||||||
|
|
||||||
#update enquiry
|
#update enquiry
|
||||||
#------------------
|
#------------------
|
||||||
def update_enquiry(self, flag):
|
def update_opportunity(self):
|
||||||
prevdoc=''
|
for opportunity in self.doclist.get_distinct_values("prevdoc_docname"):
|
||||||
for d in getlist(self.doclist, 'quotation_details'):
|
webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True)
|
||||||
if d.prevdoc_docname:
|
|
||||||
prevdoc = d.prevdoc_docname
|
|
||||||
|
|
||||||
if prevdoc:
|
|
||||||
if flag == 'submit': #on submit
|
|
||||||
webnotes.conn.sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc)
|
|
||||||
elif flag == 'cancel': #on cancel
|
|
||||||
webnotes.conn.sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc)
|
|
||||||
elif flag == 'order lost': #order lost
|
|
||||||
webnotes.conn.sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc)
|
|
||||||
elif flag == 'order confirm': #order confirm
|
|
||||||
webnotes.conn.sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc)
|
|
||||||
|
|
||||||
# declare as order lost
|
# declare as order lost
|
||||||
#-------------------------
|
#-------------------------
|
||||||
def declare_order_lost(self, arg):
|
def declare_order_lost(self, arg):
|
||||||
chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name)
|
if not self.has_sales_order():
|
||||||
if chk:
|
webnotes.conn.set(self.doc, 'status', 'Lost')
|
||||||
msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.")
|
|
||||||
raise Exception
|
|
||||||
else:
|
|
||||||
webnotes.conn.set(self.doc, 'status', 'Order Lost')
|
|
||||||
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
|
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
|
||||||
self.update_enquiry('order lost')
|
self.update_opportunity()
|
||||||
return 'true'
|
else:
|
||||||
|
webnotes.throw(_("Cannot set as Lost as Sales Order is made."))
|
||||||
|
|
||||||
#check if value entered in item table
|
#check if value entered in item table
|
||||||
#--------------------------------------
|
#--------------------------------------
|
||||||
@ -176,21 +155,17 @@ class DocType(SellingController):
|
|||||||
|
|
||||||
# Check for Approving Authority
|
# Check for Approving Authority
|
||||||
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
|
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
|
||||||
|
|
||||||
# Set Quotation Status
|
|
||||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
|
||||||
|
|
||||||
#update enquiry status
|
#update enquiry status
|
||||||
self.update_enquiry('submit')
|
self.update_opportunity()
|
||||||
|
|
||||||
|
|
||||||
# ON CANCEL
|
# ON CANCEL
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
#update enquiry status
|
#update enquiry status
|
||||||
self.update_enquiry('cancel')
|
self.set_status()
|
||||||
|
self.update_opportunity()
|
||||||
webnotes.conn.set(self.doc,'status','Cancelled')
|
|
||||||
|
|
||||||
# Print other charges
|
# Print other charges
|
||||||
# ===========================================================================
|
# ===========================================================================
|
||||||
@ -202,6 +177,7 @@ class DocType(SellingController):
|
|||||||
lst1.append(d.total)
|
lst1.append(d.total)
|
||||||
print_lst.append(lst1)
|
print_lst.append(lst1)
|
||||||
return print_lst
|
return print_lst
|
||||||
|
|
||||||
|
|
||||||
@webnotes.whitelist()
|
@webnotes.whitelist()
|
||||||
def make_sales_order(source_name, target_doclist=None):
|
def make_sales_order(source_name, target_doclist=None):
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-05-24 19:29:08",
|
"creation": "2013-05-24 19:29:08",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-10-02 14:24:35",
|
"modified": "2013-10-03 16:31:55",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -734,7 +734,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nDraft\nSubmitted\nOrder Confirmed\nOrder Lost\nCancelled",
|
"options": "Draft\nSubmitted\nOrdered\nLost\nCancelled",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
|
@ -66,7 +66,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
source_doctype: "Quotation",
|
source_doctype: "Quotation",
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Order Lost"],
|
status: ["!=", "Lost"],
|
||||||
order_type: cur_frm.doc.order_type,
|
order_type: cur_frm.doc.order_type,
|
||||||
customer: cur_frm.doc.customer || undefined,
|
customer: cur_frm.doc.customer || undefined,
|
||||||
company: cur_frm.doc.company
|
company: cur_frm.doc.company
|
||||||
|
@ -165,36 +165,20 @@ class DocType(SellingController):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def check_prev_docstatus(self):
|
|
||||||
for d in getlist(self.doclist, 'sales_order_details'):
|
|
||||||
cancel_quo = webnotes.conn.sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname)
|
|
||||||
if cancel_quo:
|
|
||||||
msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !")
|
|
||||||
raise Exception , "Validation Error. "
|
|
||||||
|
|
||||||
def update_enquiry_status(self, prevdoc, flag):
|
def update_enquiry_status(self, prevdoc, flag):
|
||||||
enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
|
enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
|
||||||
if enq:
|
if enq:
|
||||||
webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
|
webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
|
||||||
|
|
||||||
def update_prevdoc_status(self, flag):
|
def update_prevdoc_status(self, flag):
|
||||||
for d in getlist(self.doclist, 'sales_order_details'):
|
for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
|
||||||
if d.prevdoc_docname:
|
bean = webnotes.bean("Quotation", quotation)
|
||||||
if flag=='submit':
|
if bean.doc.docstatus==2:
|
||||||
webnotes.conn.sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname)
|
webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled."))
|
||||||
|
|
||||||
#update enquiry
|
bean.get_controller().set_status(update=True)
|
||||||
self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed')
|
|
||||||
elif flag == 'cancel':
|
|
||||||
chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name))
|
|
||||||
if not chk:
|
|
||||||
webnotes.conn.sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname)
|
|
||||||
|
|
||||||
#update enquiry
|
|
||||||
self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
|
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.check_prev_docstatus()
|
|
||||||
self.update_stock_ledger(update_stock = 1)
|
self.update_stock_ledger(update_stock = 1)
|
||||||
|
|
||||||
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
|
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
|
||||||
|
@ -54,7 +54,7 @@ Original Query:
|
|||||||
|
|
||||||
def auto_close_tickets(self):
|
def auto_close_tickets(self):
|
||||||
webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed'
|
webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed'
|
||||||
where status = 'Waiting for Customer'
|
where status = 'Replied'
|
||||||
and date_sub(curdate(),interval 15 Day) > modified""")
|
and date_sub(curdate(),interval 15 Day) > modified""")
|
||||||
|
|
||||||
def get_support_mails():
|
def get_support_mails():
|
||||||
|
@ -14,7 +14,7 @@ class DocType(TransactionBase):
|
|||||||
|
|
||||||
def get_sender(self, comm):
|
def get_sender(self, comm):
|
||||||
return webnotes.conn.get_value('Email Settings',None,'support_email')
|
return webnotes.conn.get_value('Email Settings',None,'support_email')
|
||||||
|
|
||||||
def get_subject(self, comm):
|
def get_subject(self, comm):
|
||||||
return '[' + self.doc.name + '] ' + (comm.subject or 'No Subject Specified')
|
return '[' + self.doc.name + '] ' + (comm.subject or 'No Subject Specified')
|
||||||
|
|
||||||
@ -35,16 +35,7 @@ class DocType(TransactionBase):
|
|||||||
if self.doc.status == "Closed":
|
if self.doc.status == "Closed":
|
||||||
from webnotes.widgets.form.assign_to import clear
|
from webnotes.widgets.form.assign_to import clear
|
||||||
clear(self.doc.doctype, self.doc.name)
|
clear(self.doc.doctype, self.doc.name)
|
||||||
|
|
||||||
def on_communication(self, comm):
|
|
||||||
if comm.sender == self.get_sender(comm) or \
|
|
||||||
webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
|
|
||||||
self.doc.status = "Waiting for Customer"
|
|
||||||
else:
|
|
||||||
self.doc.status = "Open"
|
|
||||||
self.update_status()
|
|
||||||
self.doc.save()
|
|
||||||
|
|
||||||
def set_lead_contact(self, email_id):
|
def set_lead_contact(self, email_id):
|
||||||
import email.utils
|
import email.utils
|
||||||
email_id = email.utils.parseaddr(email_id)
|
email_id = email.utils.parseaddr(email_id)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-02-01 10:36:25",
|
"creation": "2013-02-01 10:36:25",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-09-10 10:54:02",
|
"modified": "2013-10-03 16:45:41",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -71,7 +71,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nOpen\nTo Reply\nWaiting for Customer\nHold\nClosed",
|
"options": "Open\nReplied\nHold\nClosed",
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
|
@ -12,14 +12,6 @@ class DocType(TransactionBase):
|
|||||||
self.doc = doc
|
self.doc = doc
|
||||||
self.doclist = doclist
|
self.doclist = doclist
|
||||||
|
|
||||||
def on_communication(self, comm):
|
|
||||||
if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
|
|
||||||
status = "Replied"
|
|
||||||
else:
|
|
||||||
status = "Open"
|
|
||||||
|
|
||||||
webnotes.conn.set(self.doc, 'status', status)
|
|
||||||
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
# concat first and last name
|
# concat first and last name
|
||||||
self.doc.name = " ".join(filter(None,
|
self.doc.name = " ".join(filter(None,
|
||||||
@ -32,6 +24,7 @@ class DocType(TransactionBase):
|
|||||||
break
|
break
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
self.set_status()
|
||||||
self.validate_primary_contact()
|
self.validate_primary_contact()
|
||||||
|
|
||||||
def validate_primary_contact(self):
|
def validate_primary_contact(self):
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-01-10 16:34:32",
|
"creation": "2013-01-10 16:34:32",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-09-10 10:50:27",
|
"modified": "2013-10-03 16:44:08",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -70,11 +70,12 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Passive",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"options": "\nOpen\nReplied"
|
"options": "Passive\nOpen\nReplied"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user