mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 08:54:45 +00:00
Merge branch 'wsgi' of https://github.com/webnotes/erpnext into i18n
Conflicts: accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js public/js/complete_setup.js selling/doctype/opportunity/opportunity.js selling/doctype/quotation/quotation.js
This commit is contained in:
@@ -34,7 +34,6 @@ cur_frm.cscript.refresh = function(doc,dt,dn) {
|
||||
cur_frm.cscript.make_contact(doc,dt,dn);
|
||||
|
||||
cur_frm.communication_view = new wn.views.CommunicationList({
|
||||
list: wn.model.get("Communication", {"customer": doc.name}),
|
||||
parent: cur_frm.fields_dict.communication_html.wrapper,
|
||||
doc: doc,
|
||||
});
|
||||
@@ -45,7 +44,7 @@ cur_frm.cscript.setup_dashboard = function(doc) {
|
||||
cur_frm.dashboard.reset(doc);
|
||||
if(doc.__islocal)
|
||||
return;
|
||||
cur_frm.dashboard.set_headline('<span class="text-muted">Loading...</span>')
|
||||
cur_frm.dashboard.set_headline('<span class="text-muted">'+ wn._('Loading...')+ '</span>')
|
||||
|
||||
cur_frm.dashboard.add_doctype_badge("Opportunity", "customer");
|
||||
cur_frm.dashboard.add_doctype_badge("Quotation", "customer");
|
||||
@@ -119,4 +118,4 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) {
|
||||
return{
|
||||
query:"controllers.queries.lead_query"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ from webnotes.model.doc import Document, make_autoname
|
||||
from webnotes import msgprint, _
|
||||
import webnotes.defaults
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
from utilities.transaction_base import TransactionBase
|
||||
|
||||
@@ -31,7 +30,7 @@ class DocType(TransactionBase):
|
||||
return webnotes.conn.get_value('Company', self.doc.company, 'abbr')
|
||||
|
||||
def get_receivables_group(self):
|
||||
g = sql("select receivables_group from tabCompany where name=%s", self.doc.company)
|
||||
g = webnotes.conn.sql("select receivables_group from tabCompany where name=%s", self.doc.company)
|
||||
g = g and g[0][0] or ''
|
||||
if not g:
|
||||
msgprint("Update Company master, assign a default group for Receivables")
|
||||
@@ -47,7 +46,7 @@ class DocType(TransactionBase):
|
||||
|
||||
def update_lead_status(self):
|
||||
if self.doc.lead_name:
|
||||
sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
|
||||
webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
|
||||
|
||||
def create_account_head(self):
|
||||
if self.doc.company :
|
||||
@@ -132,7 +131,7 @@ class DocType(TransactionBase):
|
||||
|
||||
def delete_customer_account(self):
|
||||
"""delete customer's ledger if exist and check balance before deletion"""
|
||||
acc = sql("select name from `tabAccount` where master_type = 'Customer' \
|
||||
acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Customer' \
|
||||
and master_name = %s and docstatus < 2", self.doc.name)
|
||||
if acc:
|
||||
from webnotes.model import delete_doc
|
||||
@@ -143,7 +142,7 @@ class DocType(TransactionBase):
|
||||
self.delete_customer_contact()
|
||||
self.delete_customer_account()
|
||||
if self.doc.lead_name:
|
||||
sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
|
||||
webnotes.conn.sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
|
||||
|
||||
def on_rename(self, new, old, merge=False):
|
||||
#update customer_name if not naming series
|
||||
|
||||
@@ -17,6 +17,8 @@ class TestCustomer(unittest.TestCase):
|
||||
(("_Test Customer 1 Renamed",),))
|
||||
self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer 1"), ())
|
||||
|
||||
webnotes.rename_doc("Customer", "_Test Customer 1 Renamed", "_Test Customer 1")
|
||||
|
||||
def test_merge(self):
|
||||
from webnotes.test_runner import make_test_records
|
||||
make_test_records("Sales Invoice")
|
||||
@@ -57,6 +59,9 @@ class TestCustomer(unittest.TestCase):
|
||||
# check that old name doesn't exist
|
||||
self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer"), ())
|
||||
self.assertEqual(webnotes.conn.exists("Account", "_Test Customer - _TC"), ())
|
||||
|
||||
# create back _Test Customer
|
||||
webnotes.bean(copy=test_records[0]).insert()
|
||||
|
||||
test_ignore = ["Price List"]
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ class DocType(TransactionBase):
|
||||
self.check_item_table()
|
||||
sales_com_obj = get_obj(dt = 'Sales Common')
|
||||
sales_com_obj.check_active_sales_items(self)
|
||||
sales_com_obj.get_prevdoc_date(self)
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
from accounts.utils import validate_fiscal_year
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-02-22 01:27:51",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-10 14:54:09",
|
||||
"modified": "2013-10-10 17:02:31",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -48,18 +48,6 @@
|
||||
"read_only": 1,
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "prevdoc_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Delivery Date",
|
||||
"oldfieldname": "prevdoc_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "serial_no",
|
||||
|
||||
@@ -29,7 +29,7 @@ def add_sales_communication(subject, content, sender, real_name, mail=None,
|
||||
parent_name = contact_name or lead_name
|
||||
|
||||
message = make(content=content, sender=sender, subject=subject,
|
||||
doctype = parent_doctype, name = parent_name, date=date)
|
||||
doctype = parent_doctype, name = parent_name, date=date, sent_or_received="Received")
|
||||
|
||||
if mail:
|
||||
# save attachments to parent if from mail
|
||||
|
||||
@@ -33,7 +33,7 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
|
||||
var doc = this.frm.doc;
|
||||
erpnext.hide_naming_series();
|
||||
this.frm.clear_custom_buttons();
|
||||
|
||||
|
||||
this.frm.__is_customer = this.frm.__is_customer || this.frm.doc.__is_customer;
|
||||
if(!this.frm.doc.__islocal && !this.frm.__is_customer) {
|
||||
this.frm.add_custom_button(wn._("Create Customer"), this.create_customer);
|
||||
|
||||
@@ -7,7 +7,6 @@ from webnotes import _
|
||||
from webnotes.utils import cstr, validate_email_add, cint, extract_email_id
|
||||
from webnotes import session, msgprint
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
from controllers.selling_controller import SellingController
|
||||
|
||||
@@ -27,24 +26,9 @@ class DocType(SellingController):
|
||||
customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
|
||||
if 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 = sql("select status from `tabLead` where name=%s", self.doc.name)
|
||||
chk = chk and chk[0][0] or ''
|
||||
return cstr(chk)
|
||||
|
||||
def validate(self):
|
||||
if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason:
|
||||
webnotes.throw("Please Enter Lost Reason under More Info section")
|
||||
self.set_status()
|
||||
|
||||
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
|
||||
webnotes.throw("Please specify campaign name")
|
||||
@@ -76,14 +60,18 @@ class DocType(SellingController):
|
||||
webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \
|
||||
", ".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):
|
||||
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
|
||||
self.doc.name)
|
||||
|
||||
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()
|
||||
def make_customer(source_name, target_doclist=None):
|
||||
@@ -133,4 +121,4 @@ def make_opportunity(source_name, target_doclist=None):
|
||||
}
|
||||
}}, target_doclist)
|
||||
|
||||
return [d.fields for d in doclist]
|
||||
return [d if isinstance(d, dict) else d.fields for d in doclist]
|
||||
@@ -2,11 +2,12 @@
|
||||
{
|
||||
"creation": "2013-04-10 11:45:37",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-09-26 16:30:36",
|
||||
"modified": "2013-10-09 15:27:54",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
@@ -101,7 +102,7 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Open",
|
||||
"default": "Lead",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
@@ -111,7 +112,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"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,
|
||||
"search_index": 1
|
||||
},
|
||||
@@ -174,19 +175,6 @@
|
||||
"options": "Profile",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Date on which the lead was last contacted",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "last_contact_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Last Contact Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "last_contact_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "col_break123",
|
||||
@@ -236,8 +224,7 @@
|
||||
"fieldtype": "HTML",
|
||||
"label": "Communication HTML",
|
||||
"oldfieldname": "follow_up",
|
||||
"oldfieldtype": "Table",
|
||||
"print_hide": 1
|
||||
"oldfieldtype": "Table"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -390,18 +377,6 @@
|
||||
"oldfieldtype": "Column Break",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "company",
|
||||
@@ -430,8 +405,7 @@
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"print_hide": 1
|
||||
"options": "Communication"
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
|
||||
@@ -101,21 +101,21 @@ $.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, cdt, cdn){
|
||||
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();
|
||||
<<<<<<< HEAD
|
||||
if(doc.docstatus === 1 && doc.status!=="Opportunity Lost") {
|
||||
cur_frm.add_custom_button( wn._('Create Quotation'), cur_frm.cscript.create_quotation);
|
||||
cur_frm.add_custom_button(wn._('Opportunity Lost'), cur_frm.cscript['Declare Opportunity Lost']);
|
||||
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
|
||||
=======
|
||||
if(doc.docstatus === 1 && doc.status!=="Lost") {
|
||||
cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation);
|
||||
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);
|
||||
>>>>>>> f146e8b7f52a3e46e335c0fefd92c347717b370b
|
||||
}
|
||||
|
||||
cur_frm.toggle_display("contact_info", doc.customer || doc.lead);
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import cstr, getdate, cint
|
||||
from webnotes.utils import cstr, cint
|
||||
from webnotes.model.bean import getlist
|
||||
from webnotes import msgprint
|
||||
from webnotes import msgprint, _
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
from utilities.transaction_base import TransactionBase
|
||||
|
||||
@@ -18,7 +17,7 @@ class DocType(TransactionBase):
|
||||
self.doclist = doclist
|
||||
self.fname = 'enq_details'
|
||||
self.tname = 'Opportunity Item'
|
||||
|
||||
|
||||
self._prev = webnotes._dict({
|
||||
"contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \
|
||||
(not cint(self.doc.fields.get("__islocal"))) else None,
|
||||
@@ -27,7 +26,7 @@ class DocType(TransactionBase):
|
||||
})
|
||||
|
||||
def get_item_details(self, item_code):
|
||||
item = sql("""select item_name, stock_uom, description_html, description, item_group, brand
|
||||
item = webnotes.conn.sql("""select item_name, stock_uom, description_html, description, item_group, brand
|
||||
from `tabItem` where name = %s""", item_code, as_dict=1)
|
||||
ret = {
|
||||
'item_name': item and item[0]['item_name'] or '',
|
||||
@@ -39,7 +38,7 @@ class DocType(TransactionBase):
|
||||
return ret
|
||||
|
||||
def get_cust_address(self,name):
|
||||
details = sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
|
||||
details = webnotes.conn.sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
|
||||
if details:
|
||||
ret = {
|
||||
'customer_name': details and details[0]['customer_name'] or '',
|
||||
@@ -49,7 +48,7 @@ class DocType(TransactionBase):
|
||||
}
|
||||
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
|
||||
|
||||
contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
|
||||
contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
|
||||
|
||||
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
|
||||
ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
|
||||
@@ -62,18 +61,15 @@ class DocType(TransactionBase):
|
||||
|
||||
def get_contact_details(self, arg):
|
||||
arg = eval(arg)
|
||||
contact = sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
|
||||
contact = webnotes.conn.sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
|
||||
ret = {
|
||||
'contact_no' : contact and contact[0]['contact_no'] or '',
|
||||
'email_id' : contact and contact[0]['email_id'] or ''
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
def on_update(self):
|
||||
# Add to calendar
|
||||
if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
|
||||
webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date)
|
||||
|
||||
self.add_calendar_event()
|
||||
|
||||
def add_calendar_event(self, opts=None, force=False):
|
||||
@@ -101,14 +97,6 @@ class DocType(TransactionBase):
|
||||
|
||||
super(DocType, self).add_calendar_event(opts, force)
|
||||
|
||||
def set_last_contact_date(self):
|
||||
if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date:
|
||||
if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date):
|
||||
self.doc.last_contact_date=self.doc.contact_date_ref
|
||||
else:
|
||||
msgprint("Contact Date Cannot be before Last Contact Date")
|
||||
raise Exception
|
||||
|
||||
def validate_item_details(self):
|
||||
if not getlist(self.doclist, 'enquiry_details'):
|
||||
msgprint("Please select items for which enquiry needs to be made")
|
||||
@@ -121,49 +109,36 @@ class DocType(TransactionBase):
|
||||
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
|
||||
|
||||
def validate(self):
|
||||
self.set_last_contact_date()
|
||||
self.set_status()
|
||||
self.validate_item_details()
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_lead_cust()
|
||||
|
||||
from accounts.utils import validate_fiscal_year
|
||||
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
|
||||
self.doc.status = "Draft"
|
||||
|
||||
def on_submit(self):
|
||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||
if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted":
|
||||
webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made")
|
||||
if self.doc.lead:
|
||||
webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True)
|
||||
|
||||
def on_cancel(self):
|
||||
chk = 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 chk:
|
||||
msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.")
|
||||
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)
|
||||
if self.has_quotation():
|
||||
webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
|
||||
self.set_status(update=True)
|
||||
|
||||
def declare_enquiry_lost(self,arg):
|
||||
chk = 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 chk:
|
||||
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')
|
||||
if not self.has_quotation():
|
||||
webnotes.conn.set(self.doc, 'status', 'Lost')
|
||||
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):
|
||||
self.delete_events()
|
||||
|
||||
def has_quotation(self):
|
||||
return webnotes.conn.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
|
||||
|
||||
@webnotes.whitelist()
|
||||
def make_quotation(source_name, target_doclist=None):
|
||||
from webnotes.model.mapper import get_mapped_doclist
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
{
|
||||
"creation": "2013-03-07 18:50:30",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-09-25 19:32:29",
|
||||
"modified": "2013-10-09 15:26:29",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"description": "Potential Sales Deal",
|
||||
"doctype": "DocType",
|
||||
@@ -125,7 +126,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled",
|
||||
"options": "Draft\nSubmitted\nQuotation\nLost\nCancelled\nReplied\nOpen",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
@@ -168,7 +169,6 @@
|
||||
"label": "Communication History",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-comments",
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
@@ -179,7 +179,6 @@
|
||||
"label": "Communication HTML",
|
||||
"oldfieldname": "follow_up",
|
||||
"oldfieldtype": "Table",
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
@@ -351,18 +350,6 @@
|
||||
"options": "Campaign",
|
||||
"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",
|
||||
"fieldname": "company",
|
||||
@@ -377,6 +364,15 @@
|
||||
"reqd": 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",
|
||||
"fieldname": "column_break2",
|
||||
@@ -408,20 +404,6 @@
|
||||
"oldfieldtype": "Date",
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Date on which the lead was last contacted",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "last_contact_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Last Contact Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "last_contact_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "to_discuss",
|
||||
@@ -450,8 +432,7 @@
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"print_hide": 1
|
||||
"options": "Communication"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
|
||||
@@ -11,6 +11,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
|
||||
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
|
||||
wn.require('app/utilities/doctype/sms_control/sms_control.js');
|
||||
wn.require('app/selling/doctype/sales_common/sales_common.js');
|
||||
wn.require('app/accounts/doctype/sales_invoice/pos.js');
|
||||
|
||||
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
|
||||
onload: function(doc, dt, dn) {
|
||||
@@ -23,20 +24,18 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
|
||||
},
|
||||
refresh: function(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");
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
if(doc.docstatus == 1 && doc.status!=='Order Lost') {
|
||||
cur_frm.add_custom_button(wn._('Make Sales Order'), cur_frm.cscript['Make Sales Order']);
|
||||
if(doc.status!=="Order Confirmed") {
|
||||
cur_frm.add_custom_button(wn._('Set as Lost'), cur_frm.cscript['Declare Order Lost']);
|
||||
=======
|
||||
if(doc.docstatus == 1 && doc.status!=='Lost') {
|
||||
cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
|
||||
if(doc.status!=="Ordered") {
|
||||
cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
|
||||
>>>>>>> f146e8b7f52a3e46e335c0fefd92c347717b370b
|
||||
}
|
||||
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
|
||||
}
|
||||
@@ -82,12 +81,12 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
|
||||
},
|
||||
|
||||
validate_company_and_party: function(party_field) {
|
||||
if(this.frm.doc.quotation_to == "Lead") {
|
||||
return true;
|
||||
} else if(!this.frm.doc.quotation_to) {
|
||||
if(!this.frm.doc.quotation_to) {
|
||||
msgprint(wn._("Please select a value for" + " " + wn.meta.get_label(this.frm.doc.doctype,
|
||||
"quotation_to", this.frm.doc.name)));
|
||||
return false;
|
||||
} else if (this.frm.doc.quotation_to == "Lead") {
|
||||
return true;
|
||||
} else {
|
||||
return this._super(party_field);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import cstr, getdate
|
||||
from webnotes.utils import cstr
|
||||
from webnotes.model.bean import getlist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import _, msgprint
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
|
||||
from controllers.selling_controller import SellingController
|
||||
@@ -48,17 +47,16 @@ class DocType(SellingController):
|
||||
if not doc.fields.get(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
|
||||
# --------------------------------------------------------------
|
||||
def get_adj_percent(self, arg=''):
|
||||
get_obj('Sales Common').get_adj_percent(self)
|
||||
|
||||
|
||||
# Get Tax rate if account type is TAX
|
||||
# -----------------------------------
|
||||
def get_rate(self,arg):
|
||||
return get_obj('Sales Common').get_rate(arg)
|
||||
|
||||
# Does not allow same item code to be entered twice
|
||||
# -------------------------------------------------
|
||||
def validate_for_items(self):
|
||||
@@ -78,7 +76,7 @@ class DocType(SellingController):
|
||||
|
||||
if self.doc.order_type in ['Maintenance', 'Service']:
|
||||
for d in getlist(self.doclist, 'quotation_details'):
|
||||
is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code)
|
||||
is_service_item = webnotes.conn.sql("select is_service_item from `tabItem` where name=%s", d.item_code)
|
||||
is_service_item = is_service_item and is_service_item[0][0] or 'No'
|
||||
|
||||
if is_service_item == 'No':
|
||||
@@ -86,37 +84,16 @@ class DocType(SellingController):
|
||||
raise Exception
|
||||
else:
|
||||
for d in getlist(self.doclist, 'quotation_details'):
|
||||
is_sales_item = sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
|
||||
is_sales_item = webnotes.conn.sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
|
||||
is_sales_item = is_sales_item and is_sales_item[0][0] or 'No'
|
||||
|
||||
if is_sales_item == 'No':
|
||||
msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation")
|
||||
raise Exception
|
||||
|
||||
#--------------Validation For Last Contact Date-----------------
|
||||
# ====================================================================================================================
|
||||
def set_last_contact_date(self):
|
||||
#if not self.doc.contact_date_ref:
|
||||
#self.doc.contact_date_ref=self.doc.contact_date
|
||||
#self.doc.last_contact_date=self.doc.contact_date_ref
|
||||
if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date:
|
||||
if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date):
|
||||
self.doc.last_contact_date=self.doc.contact_date_ref
|
||||
else:
|
||||
msgprint("Contact Date Cannot be before Last Contact Date")
|
||||
raise Exception
|
||||
|
||||
def validate(self):
|
||||
super(DocType, self).validate()
|
||||
|
||||
import utilities
|
||||
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_status()
|
||||
self.validate_order_type()
|
||||
self.validate_for_items()
|
||||
|
||||
@@ -126,42 +103,22 @@ class DocType(SellingController):
|
||||
sales_com_obj.check_active_sales_items(self)
|
||||
sales_com_obj.validate_max_discount(self,'quotation_details')
|
||||
sales_com_obj.check_conversion_rate(self)
|
||||
|
||||
|
||||
def on_update(self):
|
||||
# Set Quotation Status
|
||||
webnotes.conn.set(self.doc, 'status', 'Draft')
|
||||
|
||||
|
||||
#update enquiry
|
||||
#------------------
|
||||
def update_enquiry(self, flag):
|
||||
prevdoc=''
|
||||
for d in getlist(self.doclist, 'quotation_details'):
|
||||
if d.prevdoc_docname:
|
||||
prevdoc = d.prevdoc_docname
|
||||
|
||||
if prevdoc:
|
||||
if flag == 'submit': #on submit
|
||||
sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc)
|
||||
elif flag == 'cancel': #on cancel
|
||||
sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc)
|
||||
elif flag == 'order lost': #order lost
|
||||
sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc)
|
||||
elif flag == 'order confirm': #order confirm
|
||||
sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc)
|
||||
def update_opportunity(self):
|
||||
for opportunity in self.doclist.get_distinct_values("prevdoc_docname"):
|
||||
webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True)
|
||||
|
||||
# declare as order lost
|
||||
#-------------------------
|
||||
def declare_order_lost(self, arg):
|
||||
chk = 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 chk:
|
||||
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')
|
||||
if not self.has_sales_order():
|
||||
webnotes.conn.set(self.doc, 'status', 'Lost')
|
||||
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
|
||||
self.update_enquiry('order lost')
|
||||
return 'true'
|
||||
self.update_opportunity()
|
||||
else:
|
||||
webnotes.throw(_("Cannot set as Lost as Sales Order is made."))
|
||||
|
||||
#check if value entered in item table
|
||||
#--------------------------------------
|
||||
@@ -177,21 +134,17 @@ class DocType(SellingController):
|
||||
|
||||
# Check for Approving Authority
|
||||
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
|
||||
self.update_enquiry('submit')
|
||||
self.update_opportunity()
|
||||
|
||||
|
||||
# ON CANCEL
|
||||
# ==========================================================================
|
||||
def on_cancel(self):
|
||||
#update enquiry status
|
||||
self.update_enquiry('cancel')
|
||||
|
||||
webnotes.conn.set(self.doc,'status','Cancelled')
|
||||
self.set_status()
|
||||
self.update_opportunity()
|
||||
|
||||
# Print other charges
|
||||
# ===========================================================================
|
||||
@@ -203,6 +156,7 @@ class DocType(SellingController):
|
||||
lst1.append(d.total)
|
||||
print_lst.append(lst1)
|
||||
return print_lst
|
||||
|
||||
|
||||
@webnotes.whitelist()
|
||||
def make_sales_order(source_name, target_doclist=None):
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
{
|
||||
"creation": "2013-05-24 19:29:08",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-09-10 10:46:33",
|
||||
"modified": "2013-10-11 13:21:07",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_email": 0,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
@@ -257,7 +258,6 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"default": "1.00",
|
||||
"description": "Rate at which customer's currency is converted to company's base currency",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "conversion_rate",
|
||||
@@ -733,7 +733,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nSubmitted\nOrder Confirmed\nOrder Lost\nCancelled",
|
||||
"options": "Draft\nSubmitted\nOrdered\nLost\nCancelled",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
@@ -841,8 +841,7 @@
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"print_hide": 1
|
||||
"options": "Communication"
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
|
||||
@@ -11,17 +11,19 @@ class TestQuotation(unittest.TestCase):
|
||||
def test_make_sales_order(self):
|
||||
from selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
self.assertRaises(webnotes.ValidationError, make_sales_order, "_T-Quotation-00001")
|
||||
quotation = webnotes.bean(copy=test_records[0])
|
||||
quotation.insert()
|
||||
|
||||
self.assertRaises(webnotes.ValidationError, make_sales_order, quotation.doc.name)
|
||||
|
||||
quotation = webnotes.bean("Quotation","_T-Quotation-00001")
|
||||
quotation.submit()
|
||||
|
||||
sales_order = make_sales_order("_T-Quotation-00001")
|
||||
sales_order = make_sales_order(quotation.doc.name)
|
||||
|
||||
self.assertEquals(sales_order[0]["doctype"], "Sales Order")
|
||||
self.assertEquals(len(sales_order), 2)
|
||||
self.assertEquals(sales_order[1]["doctype"], "Sales Order Item")
|
||||
self.assertEquals(sales_order[1]["prevdoc_docname"], "_T-Quotation-00001")
|
||||
self.assertEquals(sales_order[1]["prevdoc_docname"], quotation.doc.name)
|
||||
self.assertEquals(sales_order[0]["customer"], "_Test Customer")
|
||||
|
||||
sales_order[0]["delivery_date"] = "2014-01-01"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
wn.provide("erpnext.selling");
|
||||
wn.require("app/js/transaction.js");
|
||||
wn.require("app/js/controllers/accounts.js");
|
||||
|
||||
erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
onload: function() {
|
||||
@@ -162,8 +163,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
var item = wn.model.get_doc(cdt, cdn);
|
||||
if(item.item_code || item.barcode) {
|
||||
if(!this.validate_company_and_party("customer")) {
|
||||
item.item_code = null;
|
||||
refresh_field("item_code", item.name, item.parentfield);
|
||||
cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove();
|
||||
} else {
|
||||
return this.frm.call({
|
||||
method: "selling.utils.get_item_details",
|
||||
|
||||
@@ -86,26 +86,6 @@ class DocType(TransactionBase):
|
||||
|
||||
if (obj.doc.price_list_currency == default_currency and flt(obj.doc.plc_conversion_rate) != 1.00) or not obj.doc.plc_conversion_rate or (obj.doc.price_list_currency != default_currency and flt(obj.doc.plc_conversion_rate) == 1.00):
|
||||
msgprint("Please Enter Appropriate Conversion Rate for Price List Currency to Base Currency (%s --> %s)" % (obj.doc.price_list_currency, default_currency), raise_exception = 1)
|
||||
|
||||
|
||||
|
||||
# Get Tax rate if account type is TAX
|
||||
# =========================================================================
|
||||
def get_rate(self, arg):
|
||||
arg = eval(arg)
|
||||
rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = '%s' and docstatus != 2" %(arg['account_head']), as_dict=1)
|
||||
ret = {'rate' : 0}
|
||||
if arg['charge_type'] == 'Actual' and rate[0]['account_type'] == 'Tax':
|
||||
msgprint("You cannot select ACCOUNT HEAD of type TAX as your CHARGE TYPE is 'ACTUAL'")
|
||||
ret = {
|
||||
'account_head' : ''
|
||||
}
|
||||
elif rate[0]['account_type'] in ['Tax', 'Chargeable'] and not arg['charge_type'] == 'Actual':
|
||||
ret = {
|
||||
'rate' : rate and flt(rate[0]['tax_rate']) or 0
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
def get_item_list(self, obj, is_stopped=0):
|
||||
"""get item list"""
|
||||
@@ -123,12 +103,12 @@ class DocType(TransactionBase):
|
||||
if flt(d.qty) > flt(d.delivered_qty):
|
||||
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
|
||||
|
||||
if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order':
|
||||
if obj.doc.doctype == "Delivery Note" and d.against_sales_order:
|
||||
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
|
||||
# But in this case reserved qty should only be reduced by 10 and not 12
|
||||
|
||||
already_delivered_qty = self.get_already_delivered_qty(obj.doc.name,
|
||||
d.prevdoc_docname, d.prevdoc_detail_docname)
|
||||
d.against_sales_order, d.prevdoc_detail_docname)
|
||||
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
|
||||
|
||||
if already_delivered_qty + d.qty > so_qty:
|
||||
@@ -168,7 +148,7 @@ class DocType(TransactionBase):
|
||||
def get_already_delivered_qty(self, dn, so, so_detail):
|
||||
qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item`
|
||||
where prevdoc_detail_docname = %s and docstatus = 1
|
||||
and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s
|
||||
and against_sales_order = %s
|
||||
and parent != %s""", (so_detail, so, dn))
|
||||
return qty and flt(qty[0][0]) or 0.0
|
||||
|
||||
@@ -218,7 +198,6 @@ class DocType(TransactionBase):
|
||||
pi.qty = flt(qty)
|
||||
pi.actual_qty = bin and flt(bin['actual_qty']) or 0
|
||||
pi.projected_qty = bin and flt(bin['projected_qty']) or 0
|
||||
pi.prevdoc_doctype = line.prevdoc_doctype
|
||||
if not pi.warehouse:
|
||||
pi.warehouse = warehouse
|
||||
if not pi.batch_no:
|
||||
@@ -283,8 +262,8 @@ class DocType(TransactionBase):
|
||||
def check_stop_sales_order(self,obj):
|
||||
for d in getlist(obj.doclist,obj.fname):
|
||||
ref_doc_name = ''
|
||||
if d.fields.has_key('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_doctype == 'Sales Order':
|
||||
ref_doc_name = d.prevdoc_docname
|
||||
if d.fields.has_key('against_sales_order') and d.against_sales_order:
|
||||
ref_doc_name = d.against_sales_order
|
||||
elif d.fields.has_key('sales_order') and d.sales_order and not d.delivery_note:
|
||||
ref_doc_name = d.sales_order
|
||||
if ref_doc_name:
|
||||
@@ -319,17 +298,6 @@ class DocType(TransactionBase):
|
||||
exact_outstanding = flt(tot_outstanding) + flt(grand_total)
|
||||
get_obj('Account',acc_head[0][0]).check_credit_limit(acc_head[0][0], obj.doc.company, exact_outstanding)
|
||||
|
||||
def get_prevdoc_date(self, obj):
|
||||
for d in getlist(obj.doclist, obj.fname):
|
||||
if d.prevdoc_doctype and d.prevdoc_docname:
|
||||
if d.prevdoc_doctype in ["Sales Invoice", "Delivery Note"]:
|
||||
date_field = "posting_date"
|
||||
else:
|
||||
date_field = "transaction_date"
|
||||
|
||||
d.prevdoc_date = webnotes.conn.get_value(d.prevdoc_doctype,
|
||||
d.prevdoc_docname, date_field)
|
||||
|
||||
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
from controllers.queries import get_match_cond
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
|
||||
wn.require('app/selling/doctype/sales_common/sales_common.js');
|
||||
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
|
||||
wn.require('app/utilities/doctype/sms_control/sms_control.js');
|
||||
wn.require('app/accounts/doctype/sales_invoice/pos.js');
|
||||
|
||||
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
|
||||
refresh: function(doc, dt, dn) {
|
||||
@@ -65,7 +66,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
source_doctype: "Quotation",
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Order Lost"],
|
||||
status: ["!=", "Lost"],
|
||||
order_type: cur_frm.doc.order_type,
|
||||
customer: cur_frm.doc.customer || undefined,
|
||||
company: cur_frm.doc.company
|
||||
@@ -188,4 +189,4 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
if(cint(wn.boot.notification_settings.sales_order)) {
|
||||
cur_frm.email_doc(wn.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint
|
||||
from webnotes.model.mapper import get_mapped_doclist
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
|
||||
from controllers.selling_controller import SellingController
|
||||
@@ -39,9 +38,6 @@ class DocType(SellingController):
|
||||
def get_available_qty(self,args):
|
||||
return get_obj('Sales Common').get_available_qty(eval(args))
|
||||
|
||||
def get_rate(self,arg):
|
||||
return get_obj('Sales Common').get_rate(arg)
|
||||
|
||||
def validate_mandatory(self):
|
||||
# validate transaction date v/s delivery date
|
||||
if self.doc.delivery_date:
|
||||
@@ -88,14 +84,14 @@ class DocType(SellingController):
|
||||
# used for production plan
|
||||
d.transaction_date = self.doc.transaction_date
|
||||
|
||||
tot_avail_qty = sql("select projected_qty from `tabBin` \
|
||||
tot_avail_qty = webnotes.conn.sql("select projected_qty from `tabBin` \
|
||||
where item_code = '%s' and warehouse = '%s'" % (d.item_code,d.reserved_warehouse))
|
||||
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
|
||||
|
||||
def validate_sales_mntc_quotation(self):
|
||||
for d in getlist(self.doclist, 'sales_order_details'):
|
||||
if d.prevdoc_docname:
|
||||
res = sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
|
||||
res = webnotes.conn.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
|
||||
if not res:
|
||||
msgprint("""Order Type (%s) should be same in Quotation: %s \
|
||||
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname))
|
||||
@@ -112,7 +108,7 @@ class DocType(SellingController):
|
||||
|
||||
def validate_proj_cust(self):
|
||||
if self.doc.project_name and self.doc.customer_name:
|
||||
res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
|
||||
res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
|
||||
if not res:
|
||||
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name))
|
||||
raise Exception
|
||||
@@ -127,7 +123,7 @@ class DocType(SellingController):
|
||||
self.validate_po()
|
||||
self.validate_uom_is_integer("stock_uom", "qty")
|
||||
self.validate_for_items()
|
||||
self.validate_warehouse_user()
|
||||
self.validate_warehouse()
|
||||
sales_com_obj = get_obj(dt = 'Sales Common')
|
||||
sales_com_obj.check_active_sales_items(self)
|
||||
sales_com_obj.check_conversion_rate(self)
|
||||
@@ -148,14 +144,15 @@ class DocType(SellingController):
|
||||
if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered'
|
||||
|
||||
|
||||
def validate_warehouse_user(self):
|
||||
from stock.utils import validate_warehouse_user
|
||||
def validate_warehouse(self):
|
||||
from stock.utils import validate_warehouse_user, validate_warehouse_company
|
||||
|
||||
warehouses = list(set([d.reserved_warehouse for d in
|
||||
self.doclist.get({"doctype": self.tname}) if d.reserved_warehouse]))
|
||||
|
||||
for w in warehouses:
|
||||
validate_warehouse_user(w)
|
||||
validate_warehouse_company(w, self.doc.company)
|
||||
|
||||
def validate_with_previous_doc(self):
|
||||
super(DocType, self).validate_with_previous_doc(self.tname, {
|
||||
@@ -166,36 +163,20 @@ class DocType(SellingController):
|
||||
})
|
||||
|
||||
|
||||
def check_prev_docstatus(self):
|
||||
for d in getlist(self.doclist, 'sales_order_details'):
|
||||
cancel_quo = 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):
|
||||
enq = 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:
|
||||
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):
|
||||
for d in getlist(self.doclist, 'sales_order_details'):
|
||||
if d.prevdoc_docname:
|
||||
if flag=='submit':
|
||||
sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname)
|
||||
|
||||
#update enquiry
|
||||
self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed')
|
||||
elif flag == 'cancel':
|
||||
chk = 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:
|
||||
sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname)
|
||||
|
||||
#update enquiry
|
||||
self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
|
||||
def update_prevdoc_status(self, flag):
|
||||
for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
|
||||
bean = webnotes.bean("Quotation", quotation)
|
||||
if bean.doc.docstatus==2:
|
||||
webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled."))
|
||||
|
||||
bean.get_controller().set_status(update=True)
|
||||
|
||||
def on_submit(self):
|
||||
self.check_prev_docstatus()
|
||||
self.update_stock_ledger(update_stock = 1)
|
||||
|
||||
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
|
||||
@@ -219,35 +200,35 @@ class DocType(SellingController):
|
||||
|
||||
def check_nextdoc_docstatus(self):
|
||||
# Checks Delivery Note
|
||||
submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name))
|
||||
submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.doc.name)
|
||||
if submit_dn:
|
||||
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
|
||||
|
||||
# Checks Sales Invoice
|
||||
submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
|
||||
submit_rv = webnotes.conn.sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
|
||||
if submit_rv:
|
||||
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
|
||||
|
||||
#check maintenance schedule
|
||||
submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
|
||||
submit_ms = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
|
||||
if submit_ms:
|
||||
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
|
||||
|
||||
# check maintenance visit
|
||||
submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
|
||||
submit_mv = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
|
||||
if submit_mv:
|
||||
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
|
||||
|
||||
# check production order
|
||||
pro_order = sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
|
||||
pro_order = webnotes.conn.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
|
||||
if pro_order:
|
||||
msgprint("""Production Order: %s exists against this sales order.
|
||||
Please cancel production order first and then cancel this sales order""" %
|
||||
pro_order[0][0], raise_exception=1)
|
||||
|
||||
def check_modified_date(self):
|
||||
mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
|
||||
date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
|
||||
mod_db = webnotes.conn.sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
|
||||
date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
|
||||
if date_diff and date_diff[0][0]:
|
||||
msgprint("%s: %s has been modified after you have opened. Please Refresh"
|
||||
% (self.doc.doctype, self.doc.name), raise_exception=1)
|
||||
@@ -342,8 +323,7 @@ def make_delivery_note(source_name, target_doclist=None):
|
||||
"field_map": {
|
||||
"export_rate": "export_rate",
|
||||
"name": "prevdoc_detail_docname",
|
||||
"parent": "prevdoc_docname",
|
||||
"parenttype": "prevdoc_doctype",
|
||||
"parent": "against_sales_order",
|
||||
"reserved_warehouse": "warehouse"
|
||||
},
|
||||
"postprocess": update_item,
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
{
|
||||
"creation": "2013-06-18 12:39:59",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-08-09 14:46:17",
|
||||
"modified": "2013-10-11 13:18:47",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
@@ -272,7 +273,6 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"default": "1.00",
|
||||
"description": "Rate at which customer's currency is converted to company's base currency",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "conversion_rate",
|
||||
|
||||
@@ -72,10 +72,13 @@ class TestSalesOrder(unittest.TestCase):
|
||||
|
||||
def create_dn_against_so(self, so, delivered_qty=0):
|
||||
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
|
||||
from stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt
|
||||
|
||||
_insert_purchase_receipt(so.doclist[1].item_code)
|
||||
|
||||
dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0]))
|
||||
dn.doclist[1].item_code = so.doclist[1].item_code
|
||||
dn.doclist[1].prevdoc_doctype = "Sales Order"
|
||||
dn.doclist[1].prevdoc_docname = so.doc.name
|
||||
dn.doclist[1].against_sales_order = so.doc.name
|
||||
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
|
||||
if delivered_qty:
|
||||
dn.doclist[1].qty = delivered_qty
|
||||
@@ -273,14 +276,13 @@ class TestSalesOrder(unittest.TestCase):
|
||||
so.doclist[1].reserved_warehouse, 20.0)
|
||||
|
||||
def test_warehouse_user(self):
|
||||
webnotes.session.user = "test@example.com"
|
||||
|
||||
webnotes.bean("Profile", "test@example.com").get_controller()\
|
||||
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
|
||||
|
||||
webnotes.bean("Profile", "test2@example.com").get_controller()\
|
||||
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
|
||||
|
||||
|
||||
webnotes.session.user = "test@example.com"
|
||||
|
||||
from stock.utils import UserNotAllowedForWarehouse
|
||||
so = webnotes.bean(copy = test_records[0])
|
||||
|
||||
@@ -10,7 +10,6 @@ from webnotes.model.bean import copy_doclist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
# ----------
|
||||
|
||||
@@ -29,15 +28,15 @@ class DocType:
|
||||
where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % self.doc.sales_partner or " and ifnull(sales_partner, '') != ''"
|
||||
|
||||
if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
|
||||
rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
|
||||
rec = webnotes.conn.sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
|
||||
elif self.doc.send_to == 'All Lead (Open)':
|
||||
rec = sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
|
||||
rec = webnotes.conn.sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
|
||||
elif self.doc.send_to == 'All Employee (Active)':
|
||||
where_clause = self.doc.department and " and department = '%s'" % self.doc.department or ""
|
||||
where_clause += self.doc.branch and " and branch = '%s'" % self.doc.branch or ""
|
||||
rec = sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
|
||||
rec = webnotes.conn.sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
|
||||
elif self.doc.send_to == 'All Sales Person':
|
||||
rec = sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
|
||||
rec = webnotes.conn.sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
|
||||
rec_list = ''
|
||||
for d in rec:
|
||||
rec_list += d[0] + ' - ' + d[1] + '\n'
|
||||
|
||||
0
selling/page/sales_funnel/__init__.py
Normal file
0
selling/page/sales_funnel/__init__.py
Normal file
3
selling/page/sales_funnel/sales_funnel.css
Normal file
3
selling/page/sales_funnel/sales_funnel.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.funnel-wrapper {
|
||||
margin: 15px;
|
||||
}
|
||||
189
selling/page/sales_funnel/sales_funnel.js
Normal file
189
selling/page/sales_funnel/sales_funnel.js
Normal file
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
wn.pages['sales-funnel'].onload = function(wrapper) {
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'Sales Funnel',
|
||||
single_column: true
|
||||
});
|
||||
|
||||
wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper);
|
||||
|
||||
wrapper.appframe.add_module_icon("Selling", "sales-funnel", function() {
|
||||
wn.set_route("selling-home");
|
||||
});
|
||||
}
|
||||
|
||||
erpnext.CRMFunnel = Class.extend({
|
||||
init: function(wrapper) {
|
||||
var me = this;
|
||||
// 0 setTimeout hack - this gives time for canvas to get width and height
|
||||
setTimeout(function() {
|
||||
me.setup(wrapper);
|
||||
me.get_data();
|
||||
}, 0);
|
||||
},
|
||||
|
||||
setup: function(wrapper) {
|
||||
var me = this;
|
||||
|
||||
this.elements = {
|
||||
layout: $(wrapper).find(".layout-main"),
|
||||
from_date: wrapper.appframe.add_date("From Date"),
|
||||
to_date: wrapper.appframe.add_date("To Date"),
|
||||
refresh_btn: wrapper.appframe.add_button("Refresh",
|
||||
function() { me.get_data(); }, "icon-refresh"),
|
||||
};
|
||||
|
||||
this.elements.no_data = $('<div class="alert alert-warning">No Data</div>')
|
||||
.toggle(false)
|
||||
.appendTo(this.elements.layout);
|
||||
|
||||
this.elements.funnel_wrapper = $('<div class="funnel-wrapper text-center"></div>')
|
||||
.appendTo(this.elements.layout);
|
||||
|
||||
this.options = {
|
||||
from_date: wn.datetime.add_months(wn.datetime.get_today(), -1),
|
||||
to_date: wn.datetime.get_today()
|
||||
};
|
||||
|
||||
// set defaults and bind on change
|
||||
$.each(this.options, function(k, v) {
|
||||
me.elements[k].val(wn.datetime.str_to_user(v));
|
||||
me.elements[k].on("change", function() {
|
||||
me.options[k] = wn.datetime.user_to_str($(this).val());
|
||||
me.get_data();
|
||||
});
|
||||
});
|
||||
|
||||
// bind refresh
|
||||
this.elements.refresh_btn.on("click", function() {
|
||||
me.get_data(this);
|
||||
});
|
||||
|
||||
// bind resize
|
||||
$(window).resize(function() {
|
||||
me.render();
|
||||
});
|
||||
},
|
||||
|
||||
get_data: function(btn) {
|
||||
var me = this;
|
||||
wn.call({
|
||||
module: "selling",
|
||||
page: "crm_funnel",
|
||||
method: "get_funnel_data",
|
||||
args: {
|
||||
from_date: this.options.from_date,
|
||||
to_date: this.options.to_date
|
||||
},
|
||||
btn: btn,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
me.options.data = r.message;
|
||||
me.render();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var me = this;
|
||||
this.prepare();
|
||||
|
||||
var context = this.elements.context,
|
||||
x_start = 0.0,
|
||||
x_end = this.options.width,
|
||||
x_mid = (x_end - x_start) / 2.0,
|
||||
y = 0,
|
||||
y_old = 0.0;
|
||||
|
||||
if(this.options.total_value === 0) {
|
||||
this.elements.no_data.toggle(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.options.data.forEach(function(d) {
|
||||
context.fillStyle = d.color;
|
||||
context.strokeStyle = d.color;
|
||||
me.draw_triangle(x_start, x_mid, x_end, y, me.options.height);
|
||||
|
||||
y_old = y;
|
||||
|
||||
// new y
|
||||
y = y + d.height;
|
||||
|
||||
// new x
|
||||
var half_side = (me.options.height - y) / Math.sqrt(3);
|
||||
x_start = x_mid - half_side;
|
||||
x_end = x_mid + half_side;
|
||||
|
||||
var y_mid = y_old + (y - y_old) / 2.0;
|
||||
|
||||
me.draw_legend(x_mid, y_mid, me.options.width, me.options.height, d.value + " - " + d.title);
|
||||
});
|
||||
},
|
||||
|
||||
prepare: function() {
|
||||
var me = this;
|
||||
|
||||
this.elements.no_data.toggle(false);
|
||||
|
||||
// calculate width and height options
|
||||
this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0;
|
||||
this.options.height = (Math.sqrt(3) * this.options.width) / 2.0;
|
||||
|
||||
// calculate total weightage
|
||||
// as height decreases, area decreases by the square of the reduction
|
||||
// hence, compensating by squaring the index value
|
||||
this.options.total_weightage = this.options.data.reduce(
|
||||
function(prev, curr, i) { return prev + Math.pow(i+1, 2) * curr.value; }, 0.0);
|
||||
|
||||
// calculate height for each data
|
||||
$.each(this.options.data, function(i, d) {
|
||||
d.height = me.options.height * d.value * Math.pow(i+1, 2) / me.options.total_weightage;
|
||||
});
|
||||
|
||||
this.elements.canvas = $('<canvas></canvas>')
|
||||
.appendTo(this.elements.funnel_wrapper.empty())
|
||||
.attr("width", $(this.elements.funnel_wrapper).width())
|
||||
.attr("height", this.options.height);
|
||||
|
||||
this.elements.context = this.elements.canvas.get(0).getContext("2d");
|
||||
},
|
||||
|
||||
draw_triangle: function(x_start, x_mid, x_end, y, height) {
|
||||
var context = this.elements.context;
|
||||
context.beginPath();
|
||||
context.moveTo(x_start, y);
|
||||
context.lineTo(x_end, y);
|
||||
context.lineTo(x_mid, height);
|
||||
context.lineTo(x_start, y);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
},
|
||||
|
||||
draw_legend: function(x_mid, y_mid, width, height, title) {
|
||||
var context = this.elements.context;
|
||||
|
||||
// draw line
|
||||
context.beginPath();
|
||||
context.moveTo(x_mid, y_mid);
|
||||
context.lineTo(width, y_mid);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
// draw circle
|
||||
context.beginPath();
|
||||
context.arc(width, y_mid, 5, 0, Math.PI * 2, false);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
// draw text
|
||||
context.fillStyle = "black";
|
||||
context.textBaseline = "middle";
|
||||
context.font = "1.1em sans-serif";
|
||||
context.fillText(title, width + 20, y_mid);
|
||||
}
|
||||
});
|
||||
33
selling/page/sales_funnel/sales_funnel.py
Normal file
33
selling/page/sales_funnel/sales_funnel.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_funnel_data(from_date, to_date):
|
||||
active_leads = webnotes.conn.sql("""select count(*) from `tabLead`
|
||||
where (`modified` between %s and %s)
|
||||
and status != "Do Not Contact" """, (from_date, to_date))[0][0]
|
||||
|
||||
active_leads += webnotes.conn.sql("""select count(distinct customer) from `tabContact`
|
||||
where (`modified` between %s and %s)
|
||||
and status != "Passive" """, (from_date, to_date))[0][0]
|
||||
|
||||
opportunities = webnotes.conn.sql("""select count(*) from `tabOpportunity`
|
||||
where docstatus = 1 and (`modified` between %s and %s)
|
||||
and status != "Lost" """, (from_date, to_date))[0][0]
|
||||
|
||||
quotations = webnotes.conn.sql("""select count(*) from `tabQuotation`
|
||||
where docstatus = 1 and (`modified` between %s and %s)
|
||||
and status != "Lost" """, (from_date, to_date))[0][0]
|
||||
|
||||
sales_orders = webnotes.conn.sql("""select count(*) from `tabQuotation`
|
||||
where docstatus = 1 and (`modified` between %s and %s)""", (from_date, to_date))[0][0]
|
||||
|
||||
return [
|
||||
{ "title": "Active Leads / Customers", "value": active_leads, "color": "#B03B46" },
|
||||
{ "title": "Opportunities", "value": opportunities, "color": "#F09C00" },
|
||||
{ "title": "Quotations", "value": quotations, "color": "#006685" },
|
||||
{ "title": "Sales Orders", "value": sales_orders, "color": "#00AD65" }
|
||||
]
|
||||
33
selling/page/sales_funnel/sales_funnel.txt
Normal file
33
selling/page/sales_funnel/sales_funnel.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"creation": "2013-10-04 13:17:18",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-10-04 13:17:18",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"doctype": "Page",
|
||||
"icon": "icon-filter",
|
||||
"module": "Selling",
|
||||
"name": "__common__",
|
||||
"page_name": "sales-funnel",
|
||||
"standard": "Yes",
|
||||
"title": "Sales Funnel"
|
||||
},
|
||||
{
|
||||
"doctype": "Page Role",
|
||||
"name": "__common__",
|
||||
"parent": "sales-funnel",
|
||||
"parentfield": "roles",
|
||||
"parenttype": "Page",
|
||||
"role": "Sales Manager"
|
||||
},
|
||||
{
|
||||
"doctype": "Page",
|
||||
"name": "sales-funnel"
|
||||
},
|
||||
{
|
||||
"doctype": "Page Role"
|
||||
}
|
||||
]
|
||||
@@ -155,6 +155,10 @@ wn.module_page["Selling"] = [
|
||||
"label":wn._("Sales Analytics"),
|
||||
page: "sales-analytics"
|
||||
},
|
||||
{
|
||||
"label":wn._("Sales Funnel"),
|
||||
page: "sales-funnel"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ def get_item_details(args):
|
||||
"plc_conversion_rate": 1.0
|
||||
}
|
||||
"""
|
||||
|
||||
if isinstance(args, basestring):
|
||||
args = json.loads(args)
|
||||
args = webnotes._dict(args)
|
||||
@@ -73,7 +74,7 @@ def get_item_details(args):
|
||||
out.update(apply_pos_settings(pos_settings, out))
|
||||
|
||||
if args.doctype in ("Sales Invoice", "Delivery Note"):
|
||||
if item_bean.doc.has_serial_no and not args.serial_no:
|
||||
if item_bean.doc.has_serial_no == "Yes" and not args.serial_no:
|
||||
out.serial_no = _get_serial_nos_by_fifo(args, item_bean)
|
||||
|
||||
return out
|
||||
|
||||
@@ -12,8 +12,8 @@ class WebsitePriceListMissingError(webnotes.ValidationError): pass
|
||||
def set_cart_count(quotation=None):
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation()
|
||||
webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get(
|
||||
{"parentfield": "quotation_details"})) or "")
|
||||
cart_count = cstr(len(quotation.doclist.get({"parentfield": "quotation_details"})))
|
||||
webnotes._response.set_cookie("cart_count", cart_count)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_cart_quotation(doclist=None):
|
||||
@@ -47,7 +47,7 @@ def place_order():
|
||||
sales_order.ignore_permissions = True
|
||||
sales_order.insert()
|
||||
sales_order.submit()
|
||||
webnotes.add_cookies["cart_count"] = ""
|
||||
webnotes._response.set_cookie("cart_count", "")
|
||||
|
||||
return sales_order.doc.name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user