mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 03:39:11 +00:00
[minor] fixed conflict
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");
|
||||
@@ -99,7 +98,7 @@ cur_frm.cscript.make_contact = function() {
|
||||
return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc"
|
||||
},
|
||||
as_dict: 1,
|
||||
no_results_message: 'No contacts created',
|
||||
no_results_message: wn._('No contacts created'),
|
||||
render_row: cur_frm.cscript.render_contact_row,
|
||||
});
|
||||
// note: render_contact_row is defined in contact_control.js
|
||||
@@ -119,4 +118,4 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) {
|
||||
return{
|
||||
query:"controllers.queries.lead_query"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ class DocType(TransactionBase):
|
||||
ac_bean.ignore_permissions = True
|
||||
ac_bean.insert()
|
||||
|
||||
msgprint("Account Head: %s created" % ac_bean.doc.name)
|
||||
msgprint(_("Account Head") + ": " + ac_bean.doc.name + _(" created"))
|
||||
else :
|
||||
msgprint("Please Select Company under which you want to create account head")
|
||||
msgprint(_("Please Select Company under which you want to create account head"))
|
||||
|
||||
def update_credit_days_limit(self):
|
||||
webnotes.conn.sql("""update tabAccount set credit_days = %s, credit_limit = %s
|
||||
|
||||
@@ -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("Create Customer", this.create_customer);
|
||||
|
||||
@@ -26,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 = 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):
|
||||
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")
|
||||
@@ -75,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):
|
||||
@@ -125,7 +114,11 @@ def make_opportunity(source_name, target_doclist=None):
|
||||
"campaign_name": "campaign",
|
||||
"doctype": "enquiry_from",
|
||||
"name": "lead",
|
||||
"lead_name": "contact_display",
|
||||
"company_name": "customer_name",
|
||||
"email_id": "contact_email",
|
||||
"mobile_no": "contact_mobile"
|
||||
}
|
||||
}}, 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-10 10:52:20",
|
||||
"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\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
|
||||
"options": "Lead\nOpen\nReplied\nOpportunity\nInterested\nConverted\nDo Not Contact",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
@@ -158,10 +159,64 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "communication_history",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Communication History",
|
||||
"label": "Communication",
|
||||
"options": "icon-comments",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "__user",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "lead_owner",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Lead Owner",
|
||||
"oldfieldname": "lead_owner",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Profile",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "col_break123",
|
||||
"fieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"description": "Your sales person who will contact the lead in future",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_by",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 1,
|
||||
"label": "Next Contact By",
|
||||
"oldfieldname": "contact_by",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Profile",
|
||||
"print_hide": 0,
|
||||
"reqd": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"description": "Your sales person will get a reminder on this date to contact the lead",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_date",
|
||||
"fieldtype": "Date",
|
||||
"in_filter": 1,
|
||||
"label": "Next Contact Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "contact_date",
|
||||
"oldfieldtype": "Date",
|
||||
"reqd": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "sec_break123",
|
||||
"fieldtype": "Section Break",
|
||||
"options": "Simple"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"doctype": "DocField",
|
||||
@@ -169,8 +224,7 @@
|
||||
"fieldtype": "HTML",
|
||||
"label": "Communication HTML",
|
||||
"oldfieldname": "follow_up",
|
||||
"oldfieldtype": "Table",
|
||||
"print_hide": 1
|
||||
"oldfieldtype": "Table"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -274,18 +328,6 @@
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nClient\nChannel Partner\nConsultant"
|
||||
},
|
||||
{
|
||||
"default": "__user",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "lead_owner",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Lead Owner",
|
||||
"oldfieldname": "lead_owner",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Profile",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "market_segment",
|
||||
@@ -335,61 +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"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"description": "Your sales person who will contact the lead in future",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_by",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 1,
|
||||
"label": "Next Contact By",
|
||||
"oldfieldname": "contact_by",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Profile",
|
||||
"print_hide": 0,
|
||||
"reqd": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"description": "Your sales person will get a reminder on this date to contact the lead",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_date",
|
||||
"fieldtype": "Date",
|
||||
"in_filter": 1,
|
||||
"label": "Next Contact Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "contact_date",
|
||||
"oldfieldtype": "Date",
|
||||
"reqd": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"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": "company",
|
||||
@@ -418,8 +405,7 @@
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"print_hide": 1
|
||||
"options": "Communication"
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
|
||||
@@ -53,6 +53,11 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({
|
||||
this.frm.set_query("contact_by", erpnext.queries.profile);
|
||||
}
|
||||
|
||||
this.frm.set_query("customer_address", function() {
|
||||
if(me.frm.doc.lead) return {filters: { lead: me.frm.doc.lead } };
|
||||
else if(me.frm.doc.customer) return {filters: { customer: me.frm.doc.customer } };
|
||||
});
|
||||
|
||||
this.frm.set_query("item_code", "enquiry_details", function() {
|
||||
return {
|
||||
query: "controllers.queries.item_query",
|
||||
@@ -63,7 +68,6 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({
|
||||
|
||||
$.each([["lead", "lead"],
|
||||
["customer", "customer"],
|
||||
["customer_address", "customer_filter"],
|
||||
["contact_person", "customer_filter"],
|
||||
["territory", "not_a_group_filter"]], function(i, opts) {
|
||||
me.frm.set_query(opts[0], erpnext.queries[opts[1]]);
|
||||
@@ -97,20 +101,13 @@ $.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();
|
||||
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('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);
|
||||
}
|
||||
|
||||
@@ -151,8 +148,14 @@ cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer) return get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc, dt, dn) {
|
||||
args = {
|
||||
address: doc.customer_address,
|
||||
contact: doc.contact_person
|
||||
}
|
||||
if(doc.customer) args.update({customer: doc.customer});
|
||||
|
||||
return get_server_fields('get_customer_address', JSON.stringify(args),'', doc, dt, dn, 1);
|
||||
}
|
||||
|
||||
cur_frm.cscript.lead = function(doc, cdt, cdn) {
|
||||
@@ -163,7 +166,7 @@ cur_frm.cscript.lead = function(doc, cdt, cdn) {
|
||||
source_name: cur_frm.doc.lead
|
||||
})
|
||||
|
||||
unhide_field(['customer_name', 'address_display','contact_mobile',
|
||||
unhide_field(['customer_name', 'address_display','contact_mobile', 'customer_address',
|
||||
'contact_email', 'territory']);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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, _
|
||||
|
||||
|
||||
from utilities.transaction_base import TransactionBase
|
||||
@@ -17,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,
|
||||
@@ -67,12 +67,9 @@ class DocType(TransactionBase):
|
||||
'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):
|
||||
@@ -100,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")
|
||||
@@ -120,41 +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")
|
||||
|
||||
if not self.doc.status:
|
||||
self.doc.status = "Draft"
|
||||
|
||||
def on_submit(self):
|
||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||
if self.doc.lead:
|
||||
webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True)
|
||||
|
||||
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 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.has_quotation():
|
||||
webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
|
||||
self.set_status(update=True)
|
||||
|
||||
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 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-10 10:52:49",
|
||||
"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
|
||||
},
|
||||
{
|
||||
@@ -190,34 +189,16 @@
|
||||
"options": "icon-bullhorn",
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_person",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Contact Person",
|
||||
"options": "Contact",
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "customer_address",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Customer Address",
|
||||
"label": "Customer / Lead Address",
|
||||
"options": "Address",
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Customer Name",
|
||||
"print_hide": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "address_display",
|
||||
@@ -228,12 +209,60 @@
|
||||
"oldfieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"description": "<a href=\"#Sales Browser/Territory\">To manage Territory, click here</a>",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Territory",
|
||||
"options": "Territory",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enquiry_from==\"Customer\"",
|
||||
"description": "<a href=\"#Sales Browser/Customer Group\">To manage Territory, click here</a>",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 1,
|
||||
"label": "Customer Group",
|
||||
"oldfieldname": "customer_group",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer Group",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "column_break3",
|
||||
"fieldtype": "Column Break",
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Customer Name",
|
||||
"print_hide": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_person",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Contact Person",
|
||||
"options": "Contact",
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "contact_display",
|
||||
@@ -255,36 +284,6 @@
|
||||
"label": "Contact Mobile No",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enquiry_from==\"Customer\"",
|
||||
"description": "<a href=\"#Sales Browser/Customer Group\">To manage Territory, click here</a>",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 1,
|
||||
"label": "Customer Group",
|
||||
"oldfieldname": "customer_group",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer Group",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"description": "<a href=\"#Sales Browser/Territory\">To manage Territory, click here</a>",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Territory",
|
||||
"options": "Territory",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"description": "Filing in Additional Information about the Opportunity will help you analyze your data better.",
|
||||
"doctype": "DocField",
|
||||
@@ -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,19 +24,10 @@ 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");
|
||||
}
|
||||
}
|
||||
|
||||
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']);
|
||||
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('Send SMS', cur_frm.cscript.send_sms);
|
||||
@@ -82,12 +74,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,7 +4,7 @@
|
||||
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
|
||||
@@ -47,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):
|
||||
@@ -92,30 +91,9 @@ class DocType(SellingController):
|
||||
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()
|
||||
|
||||
@@ -125,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
|
||||
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)
|
||||
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 = 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 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
|
||||
#--------------------------------------
|
||||
@@ -176,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
|
||||
# ===========================================================================
|
||||
@@ -202,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-03 16:31:55",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_email": 0,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
@@ -733,7 +734,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 +842,7 @@
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"print_hide": 1
|
||||
"options": "Communication"
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
|
||||
@@ -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:
|
||||
@@ -140,7 +120,7 @@ class DocType(TransactionBase):
|
||||
for p in getlist(obj.doclist, 'packing_details'):
|
||||
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
|
||||
# the packing details table's qty is already multiplied with parent's qty
|
||||
il.append({
|
||||
il.append(webnotes._dict({
|
||||
'warehouse': p.warehouse,
|
||||
'reserved_warehouse': reserved_warehouse,
|
||||
'item_code': p.item_code,
|
||||
@@ -150,9 +130,9 @@ class DocType(TransactionBase):
|
||||
'batch_no': cstr(p.batch_no).strip(),
|
||||
'serial_no': cstr(p.serial_no).strip(),
|
||||
'name': d.name
|
||||
})
|
||||
}))
|
||||
else:
|
||||
il.append({
|
||||
il.append(webnotes._dict({
|
||||
'warehouse': d.warehouse,
|
||||
'reserved_warehouse': reserved_warehouse,
|
||||
'item_code': d.item_code,
|
||||
@@ -162,13 +142,13 @@ class DocType(TransactionBase):
|
||||
'batch_no': cstr(d.batch_no).strip(),
|
||||
'serial_no': cstr(d.serial_no).strip(),
|
||||
'name': d.name
|
||||
})
|
||||
}))
|
||||
return il
|
||||
|
||||
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:
|
||||
@@ -311,24 +290,14 @@ class DocType(TransactionBase):
|
||||
acc_head = webnotes.conn.sql("select name from `tabAccount` where company = '%s' and master_name = '%s'"%(obj.doc.company, obj.doc.customer))
|
||||
if acc_head:
|
||||
tot_outstanding = 0
|
||||
dbcr = webnotes.conn.sql("select sum(debit), sum(credit) from `tabGL Entry` where account = '%s' and ifnull(is_cancelled, 'No')='No'" % acc_head[0][0])
|
||||
dbcr = webnotes.conn.sql("""select sum(debit), sum(credit) from `tabGL Entry`
|
||||
where account = %s""", acc_head[0][0])
|
||||
if dbcr:
|
||||
tot_outstanding = flt(dbcr[0][0])-flt(dbcr[0][1])
|
||||
|
||||
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
|
||||
|
||||
@@ -336,7 +305,6 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
return webnotes.conn.sql("""select batch_no from `tabStock Ledger Entry` sle
|
||||
where item_code = '%(item_code)s'
|
||||
and warehouse = '%(warehouse)s'
|
||||
and ifnull(is_cancelled, 'No') = 'No'
|
||||
and batch_no like '%(txt)s'
|
||||
and exists(select * from `tabBatch`
|
||||
where name = sle.batch_no
|
||||
|
||||
@@ -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) {
|
||||
@@ -26,34 +27,34 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
cur_frm.dashboard.add_progress(cint(doc.per_billed) + wn._("% Billed"),
|
||||
doc.per_billed);
|
||||
|
||||
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
|
||||
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && doc.order_type=='Sales')
|
||||
cur_frm.add_custom_button('Make Delivery', this.make_delivery_note);
|
||||
cur_frm.add_custom_button(wn._('Make Delivery'), this.make_delivery_note);
|
||||
|
||||
// maintenance
|
||||
if(flt(doc.per_delivered, 2) < 100 && (doc.order_type !='Sales')) {
|
||||
cur_frm.add_custom_button('Make Maint. Visit', this.make_maintenance_visit);
|
||||
cur_frm.add_custom_button('Make Maint. Schedule',
|
||||
cur_frm.add_custom_button(wn._('Make Maint. Visit'), this.make_maintenance_visit);
|
||||
cur_frm.add_custom_button(wn._('Make Maint. Schedule'),
|
||||
this.make_maintenance_schedule);
|
||||
}
|
||||
|
||||
// indent
|
||||
if(!doc.order_type || (doc.order_type == 'Sales'))
|
||||
cur_frm.add_custom_button('Make ' + wn._('Material Request'),
|
||||
cur_frm.add_custom_button(wn._('Make ') + wn._('Material Request'),
|
||||
this.make_material_request);
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 2) < 100)
|
||||
cur_frm.add_custom_button('Make Invoice', this.make_sales_invoice);
|
||||
cur_frm.add_custom_button(wn._('Make Invoice'), this.make_sales_invoice);
|
||||
|
||||
// stop
|
||||
if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100)
|
||||
cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Sales Order']);
|
||||
cur_frm.add_custom_button(wn._('Stop!'), cur_frm.cscript['Stop Sales Order']);
|
||||
} else {
|
||||
// un-stop
|
||||
cur_frm.dashboard.set_headline_alert("Stopped", "alert-danger", "icon-stop");
|
||||
cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Sales Order']);
|
||||
cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
|
||||
cur_frm.add_custom_button(wn._('Unstop'), cur_frm.cscript['Unstop Sales Order']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -157,7 +158,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript['Stop Sales Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
|
||||
var check = confirm("Are you sure you want to STOP " + doc.name);
|
||||
var check = confirm(wn._("Are you sure you want to STOP ") + doc.name);
|
||||
|
||||
if (check) {
|
||||
return $c('runserverobj', {
|
||||
@@ -172,7 +173,7 @@ cur_frm.cscript['Stop Sales Order'] = function() {
|
||||
cur_frm.cscript['Unstop Sales Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
|
||||
var check = confirm("Are you sure you want to UNSTOP " + doc.name);
|
||||
var check = confirm(wn._("Are you sure you want to UNSTOP ") + doc.name);
|
||||
|
||||
if (check) {
|
||||
return $c('runserverobj', {
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -38,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:
|
||||
@@ -126,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)
|
||||
@@ -147,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, {
|
||||
@@ -165,36 +163,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):
|
||||
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:
|
||||
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':
|
||||
webnotes.conn.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 = 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 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)
|
||||
@@ -218,7 +200,7 @@ class DocType(SellingController):
|
||||
|
||||
def check_nextdoc_docstatus(self):
|
||||
# Checks Delivery Note
|
||||
submit_dn = webnotes.conn.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)
|
||||
|
||||
@@ -266,17 +248,19 @@ class DocType(SellingController):
|
||||
|
||||
|
||||
def update_stock_ledger(self, update_stock, is_stopped = 0):
|
||||
from stock.utils import update_bin
|
||||
for d in self.get_item_list(is_stopped):
|
||||
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
|
||||
args = {
|
||||
"item_code": d['item_code'],
|
||||
"warehouse": d['reserved_warehouse'],
|
||||
"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
|
||||
"posting_date": self.doc.transaction_date,
|
||||
"voucher_type": self.doc.doctype,
|
||||
"voucher_no": self.doc.name,
|
||||
"is_amended": self.doc.amended_from and 'Yes' or 'No'
|
||||
}
|
||||
get_obj('Warehouse', d['reserved_warehouse']).update_bin(args)
|
||||
update_bin(args)
|
||||
|
||||
|
||||
def get_item_list(self, is_stopped):
|
||||
@@ -339,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-02 14:24:37",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
|
||||
@@ -74,8 +74,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
|
||||
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
|
||||
|
||||
@@ -41,7 +41,7 @@ class DocType:
|
||||
for d in rec:
|
||||
rec_list += d[0] + ' - ' + d[1] + '\n'
|
||||
self.doc.receiver_list = rec_list
|
||||
webnotes.errprint(rec_list)
|
||||
|
||||
def get_receiver_nos(self):
|
||||
receiver_nos = []
|
||||
for d in self.doc.receiver_list.split('\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
|
||||
|
||||
@@ -286,7 +286,7 @@ def apply_cart_settings(party=None, quotation=None):
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
|
||||
billing_territory = get_address_territory(quotation.doc.customer_address) or \
|
||||
party.territory
|
||||
party.territory or "All Territories"
|
||||
|
||||
set_price_list_and_rate(quotation, cart_settings, billing_territory)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def get_product_info(item_code):
|
||||
else:
|
||||
in_stock = -1
|
||||
|
||||
price = price_list and webnotes.conn.sql("""select ip.ref_rate, pl.ref_currency from
|
||||
price = price_list and webnotes.conn.sql("""select ip.ref_rate, pl.currency from
|
||||
`tabItem Price` ip, `tabPrice List` pl where ip.parent = pl.name and
|
||||
ip.item_code=%s and ip.parent=%s""",
|
||||
(item_code, price_list), as_dict=1) or []
|
||||
@@ -36,10 +36,10 @@ def get_product_info(item_code):
|
||||
qty = 0
|
||||
|
||||
if price:
|
||||
price["formatted_price"] = fmt_money(price["ref_rate"], currency=price["ref_currency"])
|
||||
price["formatted_price"] = fmt_money(price["ref_rate"], currency=price["currency"])
|
||||
|
||||
price["ref_currency"] = not cint(webnotes.conn.get_default("hide_currency_symbol")) \
|
||||
and (webnotes.conn.get_value("Currency", price.ref_currency, "symbol") or price.ref_currency) \
|
||||
price["currency"] = not cint(webnotes.conn.get_default("hide_currency_symbol")) \
|
||||
and (webnotes.conn.get_value("Currency", price.currency, "symbol") or price.currency) \
|
||||
or ""
|
||||
|
||||
if webnotes.session.user != "Guest":
|
||||
|
||||
Reference in New Issue
Block a user