Merge branch 'responsive' of github.com:webnotes/erpnext into responsive

Conflicts:
	selling/doctype/lead/lead.txt
This commit is contained in:
Anand Doshi
2013-07-04 17:18:45 +05:30
44 changed files with 1061 additions and 622 deletions

View File

@@ -32,6 +32,7 @@ cur_frm.add_fetch('lead_name', 'company_name', 'customer_name');
cur_frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate');
cur_frm.cscript.refresh = function(doc,dt,dn) {
cur_frm.cscript.setup_dashboard(doc);
if(sys_defaults.cust_master_name == 'Customer Name')
hide_field('naming_series');
else
@@ -39,7 +40,7 @@ cur_frm.cscript.refresh = function(doc,dt,dn) {
if(doc.__islocal){
hide_field(['address_html','contact_html']);
}else{
}else{
unhide_field(['address_html','contact_html']);
// make lists
cur_frm.cscript.make_address(doc,dt,dn);
@@ -53,6 +54,36 @@ cur_frm.cscript.refresh = function(doc,dt,dn) {
}
}
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.add_doctype_badge("Opportunity", "customer");
cur_frm.dashboard.add_doctype_badge("Quotation", "customer");
cur_frm.dashboard.add_doctype_badge("Sales Order", "customer");
cur_frm.dashboard.add_doctype_badge("Delivery Note", "customer");
cur_frm.dashboard.add_doctype_badge("Sales Invoice", "customer");
wn.call({
type: "GET",
method:"selling.doctype.customer.customer.get_dashboard_info",
args: {
customer: cur_frm.doc.name
},
callback: function(r) {
cur_frm.dashboard.set_headline(
wn._("Total Billing This Year: ") + "<b>"
+ format_currency(r.message.total_billing, cur_frm.doc.default_currency)
+ '</b> / <span class="text-muted">' + wn._("Unpaid") + ": <b>"
+ format_currency(r.message.total_unpaid, cur_frm.doc.default_currency)
+ '</b></span>');
cur_frm.dashboard.set_badge_count(r.message);
}
})
}
cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({
@@ -95,4 +126,4 @@ cur_frm.fields_dict['customer_group'].get_query = function(doc,dt,dn) {
}
cur_frm.fields_dict.lead_name.get_query = erpnext.utils.lead_query;
cur_frm.fields_dict.lead_name.get_query = erpnext.utils.lead_query;

View File

@@ -173,4 +173,25 @@ class DocType(TransactionBase):
#update master_name in doctype account
webnotes.conn.sql("""update `tabAccount` set master_name = %s,
master_type = 'Customer' where master_name = %s""", (new,old))
master_type = 'Customer' where master_name = %s""", (new,old))
@webnotes.whitelist()
def get_dashboard_info(customer):
if not webnotes.has_permission("Customer", customer):
webnotes.msgprint("No Permission", raise_exception=True)
out = {}
for doctype in ["Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]:
out[doctype] = webnotes.conn.get_value(doctype,
{"customer": customer, "docstatus": ["!=", 2] }, "count(*)")
billing = webnotes.conn.sql("""select sum(grand_total), sum(outstanding_amount)
from `tabSales Invoice`
where customer=%s
and docstatus = 1
and fiscal_year = %s""", (customer, webnotes.conn.get_default("fiscal_year")))
out["total_billing"] = billing[0][0]
out["total_unpaid"] = billing[0][1]
return out

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-06-11 14:26:44",
"docstatus": 0,
"modified": "2013-06-11 14:27:57",
"modified": "2013-07-03 10:26:04",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -43,6 +43,7 @@
"fieldtype": "Section Break",
"label": "Basic Info",
"oldfieldtype": "Section Break",
"options": "icon-user",
"permlevel": 0,
"reqd": 0
},
@@ -142,6 +143,7 @@
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"label": "Address & Contacts",
"options": "icon-map-marker",
"permlevel": 0
},
{
@@ -190,6 +192,8 @@
"doctype": "DocField",
"fieldname": "communication_history",
"fieldtype": "Section Break",
"label": "Communication History",
"options": "icon-comments",
"permlevel": 0
},
{
@@ -205,6 +209,7 @@
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"permlevel": 0
},
{
@@ -295,6 +300,7 @@
"fieldtype": "Section Break",
"label": "Sales Team",
"oldfieldtype": "Section Break",
"options": "icon-group",
"permlevel": 0
},
{

View File

@@ -40,9 +40,19 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
},
refresh: function() {
var doc = this.frm.doc;
erpnext.hide_naming_series();
this.frm.clear_custom_buttons();
this.frm.dashboard.reset(doc);
if(!doc.__islocal) {
if(doc.status=="Converted") {
this.frm.dashboard.set_headline_alert(wn._("Converted"), "alert-success", "icon-ok-sign");
} else {
this.frm.dashboard.set_headline_alert(wn._(doc.status), "alert-info", "icon-exclamation-sign");
}
}
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.frm.cscript['Create Customer']);
@@ -89,63 +99,15 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
$.extend(cur_frm.cscript, new erpnext.LeadController({frm: cur_frm}));
cur_frm.cscript['Create Customer'] = function(){
var doc = cur_frm.doc;
$c('runserverobj',args={ 'method':'check_status', 'docs':wn.model.compress(make_doclist(doc.doctype, doc.name))},
function(r,rt){
if(r.message == 'Converted'){
msgprint("This lead is already converted to customer");
}
else{
n = wn.model.make_new_doc_and_get_name("Customer");
$c('dt_map', args={
'docs':wn.model.compress([locals["Customer"][n]]),
'from_doctype':'Lead',
'to_doctype':'Customer',
'from_docname':doc.name,
'from_to_list':"[['Lead', 'Customer']]"
},
function(r,rt) {
wn.model.with_doctype("Customer", function() {
var customer = wn.model.get_doc("Customer", n);
var customer_copy = $.extend({}, customer);
var updated = wn.model.set_default_values(customer_copy);
$.each(updated, function(i, f) {
if(!customer[f]) customer[f] = customer_copy[f];
});
loaddoc("Customer", n);
});
}
);
}
}
);
wn.model.open_mapped_doc({
method: "selling.doctype.lead.lead.make_customer",
source_name: cur_frm.doc.name
})
}
// Create New Opportunity
// ===============================================================
cur_frm.cscript['Create Opportunity'] = function(){
var doc = cur_frm.doc;
$c('runserverobj',args={ 'method':'check_status', 'docs':wn.model.compress(make_doclist(doc.doctype, doc.name))},
function(r,rt){
if(r.message == 'Converted'){
msgprint("This lead is now converted to customer. Please create enquiry on behalf of customer");
}
else{
n = wn.model.make_new_doc_and_get_name("Opportunity");
$c('dt_map', args={
'docs':wn.model.compress([locals["Opportunity"][n]]),
'from_doctype':'Lead',
'to_doctype':'Opportunity',
'from_docname':doc.name,
'from_to_list':"[['Lead', 'Opportunity']]"
}
, function(r,rt) {
loaddoc("Opportunity", n);
}
);
}
}
);
wn.model.open_mapped_doc({
method: "selling.doctype.lead.lead.make_opportunity",
source_name: cur_frm.doc.name
})
}

View File

@@ -95,4 +95,37 @@ class DocType(SellingController):
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
self.doc.name)
self.delete_events()
self.delete_events()
@webnotes.whitelist()
def make_customer(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
doclist = get_mapped_doclist("Lead", source_name,
{"Lead": {
"doctype": "Customer",
"field_map": {
"name": "lead_name",
"company_name": "customer_name",
"contact_no": "phone_1",
"fax": "fax_1"
}
}}, target_doclist)
return [d.fields for d in doclist]
@webnotes.whitelist()
def make_opportunity(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
doclist = get_mapped_doclist("Lead", source_name,
{"Lead": {
"doctype": "Opportunity",
"field_map": {
"campaign_name": "campaign",
"doctype": "enquiry_from",
"name": "lead",
}
}}, target_doclist)
return [d.fields for d in doclist]

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-04-10 11:45:37",
"docstatus": 0,
"modified": "2013-07-02 16:03:50",
"modified": "2013-07-03 10:24:00",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -40,6 +40,13 @@
"doctype": "DocType",
"name": "Lead"
},
{
"doctype": "DocField",
"fieldname": "lead_details",
"fieldtype": "Section Break",
"label": "Lead Details",
"options": "icon-user"
},
{
"description": "To manage multiple series please go to Setup > Manage Series",
"doctype": "DocField",
@@ -149,7 +156,9 @@
{
"doctype": "DocField",
"fieldname": "communication_history",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Communication History",
"options": "icon-comments"
},
{
"allow_on_submit": 0,
@@ -165,7 +174,8 @@
"fieldname": "contact_info",
"fieldtype": "Section Break",
"label": "Address & Contact",
"oldfieldtype": "Column Break"
"oldfieldtype": "Column Break",
"options": "icon-map-marker"
},
{
"depends_on": "eval:doc.__islocal",
@@ -248,7 +258,8 @@
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break"
"oldfieldtype": "Section Break",
"options": "icon-file-text"
},
{
"doctype": "DocField",

View File

@@ -1,3 +1,5 @@
from __future__ import unicode_literals
test_records = [
[{"doctype":"Lead", "lead_name": "_Test Lead", "status":"Open",
"email_id":"test_lead@example.com"}],
@@ -8,3 +10,17 @@ test_records = [
[{"doctype":"Lead", "lead_name": "_Test Lead 3", "status":"Converted",
"email_id":"test_lead3@example.com"}],
]
import webnotes
import unittest
class TestLead(unittest.TestCase):
def test_make_customer(self):
from selling.doctype.lead.lead import make_customer
customer = make_customer("_T-Lead-00001")
self.assertEquals(customer[0]["doctype"], "Customer")
self.assertEquals(customer[0]["lead_name"], "_T-Lead-00001")
webnotes.bean(customer).insert()

View File

@@ -42,9 +42,18 @@ $.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) {
if(doc.docstatus === 1 && doc.status!=="Opportunity 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']);
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
@@ -58,11 +67,21 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn){
// ===============================================================
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(!doc.enquiry_from) hide_field(['customer', 'customer_address', 'contact_person', 'customer_name','lead', 'address_display', 'contact_display', 'contact_mobile', 'contact_email', 'territory', 'customer_group']);
if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
if(!doc.date) doc.transaction_date = date.obj_to_str(new Date());
if(!doc.company && sys_defaults.company) set_multiple(cdt,cdn,{company:sys_defaults.company});
if(!doc.fiscal_year && sys_defaults.fiscal_year) set_multiple(cdt,cdn,{fiscal_year:sys_defaults.fiscal_year});
if(!doc.enquiry_from && doc.customer)
doc.enquiry_from = "Customer";
if(!doc.enquiry_from && doc.lead)
doc.enquiry_from = "Lead";
if(!doc.enquiry_from)
hide_field(['customer', 'customer_address', 'contact_person', 'customer_name','lead', 'address_display', 'contact_display', 'contact_mobile', 'contact_email', 'territory', 'customer_group']);
if(!doc.status)
set_multiple(cdt,cdn,{status:'Draft'});
if(!doc.date)
doc.transaction_date = date.obj_to_str(new Date());
if(!doc.company && sys_defaults.company)
set_multiple(cdt,cdn,{company:sys_defaults.company});
if(!doc.fiscal_year && sys_defaults.fiscal_year)
set_multiple(cdt,cdn,{fiscal_year:sys_defaults.fiscal_year});
if(doc.enquiry_from) {
if(doc.enquiry_from == 'Customer') {
@@ -85,6 +104,8 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(cur_frm.fields_dict.contact_by.df.options.match(/^Profile/)) {
cur_frm.fields_dict.contact_by.get_query = erpnext.utils.profile_query;
}
if(doc.customer && !doc.customer_name) cur_frm.cscript.customer(doc);
}
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
@@ -196,56 +217,35 @@ cur_frm.cscript['Create Quotation'] = function(){
// declare enquiry lost
//-------------------------
cur_frm.cscript['Declare Opportunity Lost'] = function(){
var e_lost_dialog;
var dialog = new wn.ui.Dialog({
title: "Set as Lost",
fields: [
{"fieldtype": "Text", "label": "Reason for losing", "fieldname": "reason",
"reqd": 1 },
{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
]
});
set_e_lost_dialog = function(){
e_lost_dialog = new Dialog(400,150,'Add Opportunity Lost Reason');
e_lost_dialog.make_body([
['HTML', 'Message', '<div class="comment">Please add enquiry lost reason</div>'],
['Text', 'Opportunity Lost Reason'],
['HTML', 'Response', '<div class = "comment" id="update_enquiry_dialog_response"></div>'],
['HTML', 'Add Reason', '<div></div>']
]);
var add_reason_btn1 = $a($i(e_lost_dialog.widgets['Add Reason']), 'button', 'button');
add_reason_btn1.innerHTML = 'Add';
add_reason_btn1.onclick = function(){ e_lost_dialog.add(); }
var add_reason_btn2 = $a($i(e_lost_dialog.widgets['Add Reason']), 'button', 'button');
add_reason_btn2.innerHTML = 'Cancel';
$y(add_reason_btn2,{marginLeft:'4px'});
add_reason_btn2.onclick = function(){ e_lost_dialog.hide();}
e_lost_dialog.onshow = function() {
e_lost_dialog.widgets['Opportunity Lost Reason'].value = '';
$i('update_enquiry_dialog_response').innerHTML = '';
}
e_lost_dialog.add = function() {
// sending...
$i('update_enquiry_dialog_response').innerHTML = 'Processing...';
var arg = strip(e_lost_dialog.widgets['Opportunity Lost Reason'].value);
var call_back = function(r,rt) {
if(r.message == 'true'){
$i('update_enquiry_dialog_response').innerHTML = 'Done';
e_lost_dialog.hide();
cur_frm.refresh();
dialog.fields_dict.update.$input.click(function() {
args = dialog.get_values();
if(!args) return;
cur_frm.call({
doc: cur_frm.doc,
method: "declare_enquiry_lost",
args: args.reason,
callback: function(r) {
if(r.exc) {
msgprint("There were errors.");
return;
}
}
if(arg) {
$c_obj(make_doclist(cur_frm.doc.doctype, cur_frm.doc.name),'declare_enquiry_lost',arg,call_back);
}
else{
msgprint("Please add enquiry lost reason");
}
}
}
dialog.hide();
cur_frm.refresh();
},
btn: this
})
});
dialog.show();
if(!e_lost_dialog){
set_e_lost_dialog();
}
e_lost_dialog.show();
}
//get query select Territory

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-03-07 18:50:30",
"docstatus": 0,
"modified": "2013-06-11 16:03:41",
"modified": "2013-07-03 10:29:20",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -43,6 +43,13 @@
"doctype": "DocType",
"name": "Opportunity"
},
{
"doctype": "DocField",
"fieldname": "from_section",
"fieldtype": "Section Break",
"label": "From",
"options": "icon-user"
},
{
"description": "To manage multiple series please go to Setup > Manage Series",
"doctype": "DocField",
@@ -138,6 +145,7 @@
"fieldtype": "Section Break",
"label": "Items",
"oldfieldtype": "Section Break",
"options": "icon-shopping-cart",
"read_only": 0
},
{
@@ -156,7 +164,9 @@
"doctype": "DocField",
"fieldname": "communication_history",
"fieldtype": "Section Break",
"label": "Communication History",
"oldfieldtype": "Section Break",
"options": "icon-comments",
"read_only": 0
},
{
@@ -174,6 +184,7 @@
"fieldname": "contact_info",
"fieldtype": "Section Break",
"label": "Contact Info",
"options": "icon-bullhorn",
"read_only": 0
},
{
@@ -278,6 +289,7 @@
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"read_only": 0
},
{

View File

@@ -26,12 +26,31 @@ wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/selling/doctype/sales_common/sales_common.js');
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
this._super(doc, dt, dn);
if(doc.customer && !doc.quotation_to)
doc.quotation_to = "Customer";
else if(doc.lead && !doc.quotation_to)
doc.quotation_to = "Lead";
},
refresh: function(doc, dt, dn) {
this._super();
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!=='Order Lost') {
cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
if(doc.status!=="Order Confirmed") {
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);
}
@@ -108,20 +127,10 @@ cur_frm.fields_dict['enq_no'].get_query = function(doc,cdt,cdn){
// Make Sales Order
// =====================================================================================
cur_frm.cscript['Make Sales Order'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
var n = wn.model.make_new_doc_and_get_name("Sales Order");
$c('dt_map', args={
'docs':wn.model.compress([locals["Sales Order"][n]]),
'from_doctype':'Quotation',
'to_doctype':'Sales Order',
'from_docname':doc.name,
'from_to_list':"[['Quotation', 'Sales Order'], ['Quotation Item', 'Sales Order Item'],['Sales Taxes and Charges','Sales Taxes and Charges'], ['Sales Team', 'Sales Team'], ['TC Detail', 'TC Detail']]"
}, function(r,rt) {
loaddoc("Sales Order", n);
});
}
wn.model.open_mapped_doc({
method: "selling.doctype.quotation.quotation.make_sales_order",
source_name: cur_frm.doc.name
})
}
//pull enquiry details
@@ -150,51 +159,35 @@ cur_frm.cscript.pull_enquiry_detail = function(doc,cdt,cdn){
// declare order lost
//-------------------------
cur_frm.cscript['Declare Order Lost'] = function(){
var qtn_lost_dialog;
var dialog = new wn.ui.Dialog({
title: "Set as Lost",
fields: [
{"fieldtype": "Text", "label": "Reason for losing", "fieldname": "reason",
"reqd": 1 },
{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
]
});
set_qtn_lost_dialog = function(){
qtn_lost_dialog = new Dialog(400,400,'Add Quotation Lost Reason');
qtn_lost_dialog.make_body([
['HTML', 'Message', '<div class="comment">Please add quotation lost reason</div>'],
['Text', 'Quotation Lost Reason'],
['HTML', 'Response', '<div class = "comment" id="update_quotation_dialog_response"></div>'],
['HTML', 'Add Reason', '<div></div>']
]);
var add_reason_btn1 = $a($i(qtn_lost_dialog.widgets['Add Reason']), 'button', 'button');
add_reason_btn1.innerHTML = 'Add';
add_reason_btn1.onclick = function(){ qtn_lost_dialog.add(); }
var add_reason_btn2 = $a($i(qtn_lost_dialog.widgets['Add Reason']), 'button', 'button');
add_reason_btn2.innerHTML = 'Cancel';
$y(add_reason_btn2,{marginLeft:'4px'});
add_reason_btn2.onclick = function(){ qtn_lost_dialog.hide();}
qtn_lost_dialog.onshow = function() {
qtn_lost_dialog.widgets['Quotation Lost Reason'].value = '';
$i('update_quotation_dialog_response').innerHTML = '';
}
qtn_lost_dialog.add = function() {
// sending...
$i('update_quotation_dialog_response').innerHTML = 'Processing...';
var arg = strip(qtn_lost_dialog.widgets['Quotation Lost Reason'].value);
var call_back = function(r,rt) {
if(r.message == 'true'){
$i('update_quotation_dialog_response').innerHTML = 'Done';
qtn_lost_dialog.hide();
cur_frm.refresh();
dialog.fields_dict.update.$input.click(function() {
args = dialog.get_values();
if(!args) return;
cur_frm.call({
method: "declare_order_lost",
doc: cur_frm.doc,
args: args.reason,
callback: function(r) {
if(r.exc) {
msgprint("There were errors.");
return;
}
}
if(arg) $c_obj(make_doclist(cur_frm.doc.doctype, cur_frm.doc.name),'declare_order_lost',arg,call_back);
else msgprint("Please add Quotation lost reason");
}
}
if(!qtn_lost_dialog){
set_qtn_lost_dialog();
}
qtn_lost_dialog.show();
dialog.hide();
cur_frm.refresh();
},
btn: this
})
});
dialog.show();
}
//================ Last Quoted Price and Last Sold Price suggestion ======================

View File

@@ -154,8 +154,11 @@ class DocType(SellingController):
super(DocType, self).validate()
import utilities
utilities.validate_status(self.doc.status, ["Draft", "Submitted",
"Order Confirmed", "Order Lost", "Cancelled"])
if not self.doc.status:
self.doc.status = "Draft"
else:
utilities.validate_status(self.doc.status, ["Draft", "Submitted",
"Order Confirmed", "Order Lost", "Cancelled"])
self.validate_fiscal_year()
self.set_last_contact_date()
@@ -191,7 +194,7 @@ class DocType(SellingController):
# declare as order lost
#-------------------------
def declare_order_lost(self,arg):
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.")
@@ -247,3 +250,37 @@ class DocType(SellingController):
sql("delete from `tabCommunication Log` where parent = '%s'"%self.doc.name)
for d in getlist(self.doclist, 'follow_up'):
d.save()
@webnotes.whitelist()
def make_sales_order(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
if target_doclist:
target_doclist = json.loads(target_doclist)
doclist = get_mapped_doclist("Quotation", source_name, {
"Quotation": {
"doctype": "Sales Order",
"field_map": {
"name": "quotation_no",
"transaction_date": "quotation_date"
},
"validation": {
"docstatus": ["=", 1]
}
},
"Quotation Item": {
"doctype": "Sales Order Item",
"field_map": {
"parent": "prevdoc_docname"
}
},
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",
},
"Sales Team": {
"doctype": "Sales Team",
}
}, target_doclist)
return [d.fields for d in doclist]

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
"modified": "2013-06-28 12:47:10",
"modified": "2013-07-04 10:56:10",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -42,6 +42,13 @@
"doctype": "DocType",
"name": "Quotation"
},
{
"doctype": "DocField",
"fieldname": "customer_section",
"fieldtype": "Section Break",
"label": "Customer",
"options": "icon-user"
},
{
"doctype": "DocField",
"fieldname": "column_break0",
@@ -107,21 +114,19 @@
"read_only": 0
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "customer_name",
"fieldtype": "Data",
"hidden": 0,
"hidden": 1,
"in_list_view": 1,
"label": "Customer Name",
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "address_display",
"fieldtype": "Small Text",
"hidden": 0,
"hidden": 1,
"in_filter": 0,
"label": "Address",
"oldfieldname": "customer_address",
@@ -132,32 +137,29 @@
"search_index": 0
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_display",
"fieldtype": "Small Text",
"hidden": 0,
"hidden": 1,
"in_filter": 0,
"label": "Contact",
"print_hide": 0,
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_mobile",
"fieldtype": "Text",
"hidden": 0,
"hidden": 1,
"label": "Mobile No",
"print_hide": 0,
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_email",
"fieldtype": "Text",
"hidden": 0,
"hidden": 1,
"label": "Contact Email",
"print_hide": 1,
"read_only": 1
@@ -234,6 +236,7 @@
"fieldname": "section_break0",
"fieldtype": "Section Break",
"label": "Price List and Currency",
"options": "icon-tag",
"read_only": 0
},
{
@@ -316,6 +319,7 @@
"fieldtype": "Section Break",
"label": "Items",
"oldfieldtype": "Section Break",
"options": "icon-shopping-cart",
"print_hide": 0,
"read_only": 0,
"search_index": 0
@@ -337,7 +341,6 @@
"doctype": "DocField",
"fieldname": "sec_break23",
"fieldtype": "Section Break",
"options": "Simple",
"read_only": 0
},
{
@@ -413,6 +416,7 @@
"fieldtype": "Section Break",
"label": "Taxes",
"oldfieldtype": "Section Break",
"options": "icon-money",
"read_only": 0
},
{
@@ -512,6 +516,7 @@
"fieldtype": "Section Break",
"label": "Totals",
"oldfieldtype": "Section Break",
"options": "icon-money",
"print_hide": 1,
"read_only": 0
},
@@ -612,6 +617,7 @@
"fieldtype": "Section Break",
"label": "Terms and Conditions",
"oldfieldtype": "Section Break",
"options": "icon-legal",
"print_hide": 0,
"read_only": 0
},
@@ -659,6 +665,7 @@
"fieldname": "contact_section",
"fieldtype": "Section Break",
"label": "Contact Info",
"options": "icon-bullhorn",
"read_only": 0
},
{
@@ -748,6 +755,7 @@
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"print_hide": 1,
"read_only": 0
},
@@ -874,8 +882,9 @@
"doctype": "DocField",
"fieldname": "communication_history",
"fieldtype": "Section Break",
"label": "Communication History",
"oldfieldtype": "Section Break",
"options": "Simple",
"options": "icon-comments",
"print_hide": 1,
"read_only": 0
},

View File

@@ -0,0 +1,63 @@
import webnotes, json
from webnotes.utils import flt
import unittest
test_dependencies = ["Sales BOM"]
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("Quotation","_T-Quotation-00001")
quotation.submit()
sales_order = make_sales_order("_T-Quotation-00001")
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[0]["customer"], "_Test Customer")
sales_order[0]["delivery_date"] = "2014-01-01"
webnotes.print_messages = True
webnotes.bean(sales_order).insert()
test_records = [
[
{
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"customer_group": "_Test Customer Group",
"doctype": "Quotation",
"fiscal_year": "_Test Fiscal Year 2013",
"order_type": "Sales",
"plc_conversion_rate": 1.0,
"price_list_currency": "INR",
"price_list_name": "_Test Price List",
"territory": "_Test Territory",
"transaction_date": "2013-02-21",
"grand_total": 1000.0,
"grand_total_export": 1000.0,
},
{
"description": "CPU",
"doctype": "Quotation Item",
"item_code": "_Test Item Home Desktop 100",
"item_name": "CPU",
"parentfield": "quotation_details",
"qty": 10.0,
"basic_rate": 100.0,
"export_rate": 100.0,
"amount": 1000.0,
}
],
]

View File

@@ -105,6 +105,12 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.toggle_rounded_total();
},
refresh: function(doc) {
this.frm.toggle_display("customer_name",
(this.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer));
this._super();
},
customer: function() {
var me = this;
if(this.frm.doc.customer || this.frm.doc.debit_to) {
@@ -592,4 +598,4 @@ var set_sales_bom_help = function(doc) {
}
}
refresh_field('sales_bom_help');
}
}

View File

@@ -29,9 +29,16 @@ wn.require('app/utilities/doctype/sms_control/sms_control.js');
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
refresh: function(doc, dt, dn) {
this._super();
this.frm.dashboard.reset();
if(doc.docstatus==1) {
if(doc.status != 'Stopped') {
cur_frm.dashboard.add_progress(cint(doc.per_delivered) + wn._("% Delivered"),
doc.per_delivered);
cur_frm.dashboard.add_progress(cint(doc.per_delivered) + wn._("% Billed"),
doc.per_billed);
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
// delivery note
if(flt(doc.per_delivered, 2) < 100 && doc.order_type=='Sales')
@@ -56,6 +63,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
cur_frm.add_custom_button('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']);
}
}
@@ -187,40 +195,18 @@ cur_frm.cscript.make_maintenance_visit = function() {
}
cur_frm.cscript['Make Material Request'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
n = wn.model.make_new_doc_and_get_name("Material Request");
$c('dt_map', args={
'docs':wn.model.compress([locals["Material Request"][n]]),
'from_doctype':'Sales Order',
'to_doctype':'Material Request',
'from_docname':doc.name,
'from_to_list':"[['Sales Order', 'Material Request'], ['Sales Order Item', 'Material Request Item']]"
}
, function(r,rt) {
loaddoc("Material Request", n);
}
);
}
wn.model.open_mapped_doc({
method: "selling.doctype.sales_order.sales_order.make_material_request",
source_name: cur_frm.doc.name
})
}
cur_frm.cscript['Make Delivery Note'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
n = wn.model.make_new_doc_and_get_name("Delivery Note");
$c('dt_map', args={
'docs':wn.model.compress([locals["Delivery Note"][n]]),
'from_doctype':'Sales Order',
'to_doctype':'Delivery Note',
'from_docname':doc.name,
'from_to_list':"[['Sales Order', 'Delivery Note'], ['Sales Order Item', 'Delivery Note Item'],['Sales Taxes and Charges','Sales Taxes and Charges'],['Sales Team','Sales Team']]"
}
, function(r,rt) {
loaddoc("Delivery Note", n);
}
);
}
wn.model.open_mapped_doc({
method: "selling.doctype.sales_order.sales_order.make_delivery_note",
source_name: cur_frm.doc.name
})
}

View File

@@ -167,7 +167,7 @@ class DocType(SellingController):
def validate_order_type(self):
super(DocType, self).validate_order_type()
#validate delivery date
def validate_delivery_date(self):
if self.doc.order_type == 'Sales' and not self.doc.delivery_date:
msgprint("Please enter 'Expected Delivery Date'")
raise Exception
@@ -186,6 +186,7 @@ class DocType(SellingController):
self.validate_fiscal_year()
self.validate_order_type()
self.validate_delivery_date()
self.validate_mandatory()
self.validate_proj_cust()
self.validate_po()
@@ -377,4 +378,72 @@ def get_currency_and_number_format():
"currency": webnotes.conn.get_default("currency"),
"currency_symbols": json.dumps(dict(webnotes.conn.sql("""select name, symbol
from tabCurrency where ifnull(enabled,0)=1""")))
}
}
@webnotes.whitelist()
def make_material_request(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
def postprocess(source, doclist):
doclist[0].material_request_type = "Purchase"
doclist = get_mapped_doclist("Sales Order", source_name, {
"Sales Order": {
"doctype": "Material Request",
"validation": {
"docstatus": ["=", 1]
}
},
"Sales Order Item": {
"doctype": "Material Request Item",
"field_map": {
"parent": "sales_order_no",
"reserved_warehouse": "warehouse",
"stock_uom": "uom"
}
}
}, target_doclist, postprocess)
return [d.fields for d in doclist]
@webnotes.whitelist()
def make_delivery_note(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
def update_item(obj, target):
target.amount = (flt(obj.qty) - flt(obj.delivered_qty)) * flt(obj.basic_rate)
target.export_amount = (flt(obj.qty) - flt(obj.delivered_qty)) * flt(obj.export_rate)
target.qty = flt(obj.qty) - flt(obj.delivered_qty)
doclist = get_mapped_doclist("Sales Order", source_name, {
"Sales Order": {
"doctype": "Delivery Note",
"field_map": {
"name": "sales_order_no",
"shipping_address": "address_display",
"shipping_address_name": "customer_address",
},
"validation": {
"docstatus": ["=", 1]
}
},
"Sales Order Item": {
"doctype": "Delivery Note Item",
"field_map": {
"export_rate": "export_rate",
"name": "prevdoc_detail_docname",
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype",
"reserved_warehouse": "warehouse"
},
"postprocess": update_item
},
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",
},
"Sales Team": {
"doctype": "Sales Team",
}
}, target_doclist)
return [d.fields for d in doclist]

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-06-18 12:39:59",
"docstatus": 0,
"modified": "2013-06-27 11:31:02",
"modified": "2013-07-04 10:56:35",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -39,6 +39,13 @@
"doctype": "DocType",
"name": "Sales Order"
},
{
"doctype": "DocField",
"fieldname": "customer_section",
"fieldtype": "Section Break",
"label": "Customer",
"options": "icon-user"
},
{
"doctype": "DocField",
"fieldname": "column_break0",
@@ -77,7 +84,6 @@
"search_index": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "customer_name",
"fieldtype": "Data",
@@ -86,38 +92,34 @@
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "address_display",
"fieldtype": "Small Text",
"hidden": 0,
"hidden": 1,
"label": "Address",
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_display",
"fieldtype": "Small Text",
"hidden": 0,
"hidden": 1,
"label": "Contact",
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_mobile",
"fieldtype": "Text",
"hidden": 0,
"hidden": 1,
"label": "Mobile No",
"read_only": 1
},
{
"depends_on": "customer",
"doctype": "DocField",
"fieldname": "contact_email",
"fieldtype": "Text",
"hidden": 0,
"hidden": 1,
"label": "Contact Email",
"print_hide": 1,
"read_only": 1
@@ -252,7 +254,8 @@
"doctype": "DocField",
"fieldname": "sec_break45",
"fieldtype": "Section Break",
"label": "Price List and Currency"
"label": "Price List and Currency",
"options": "icon-tag"
},
{
"description": "Customer's currency",
@@ -323,7 +326,8 @@
"fieldname": "items",
"fieldtype": "Section Break",
"label": "Items",
"oldfieldtype": "Section Break"
"oldfieldtype": "Section Break",
"options": "icon-shopping-cart"
},
{
"allow_on_submit": 1,
@@ -345,6 +349,7 @@
"hidden": 0,
"label": "Packing List",
"oldfieldtype": "Section Break",
"options": "icon-suitcase",
"print_hide": 1
},
{
@@ -444,6 +449,7 @@
"fieldtype": "Section Break",
"label": "Taxes",
"oldfieldtype": "Section Break",
"options": "icon-money",
"print_hide": 0
},
{
@@ -537,6 +543,7 @@
"fieldtype": "Section Break",
"label": "Totals",
"oldfieldtype": "Section Break",
"options": "icon-money",
"print_hide": 1
},
{
@@ -626,6 +633,7 @@
"fieldtype": "Section Break",
"label": "Terms and Conditions",
"oldfieldtype": "Section Break",
"options": "icon-legal",
"print_hide": 0
},
{
@@ -671,7 +679,8 @@
"doctype": "DocField",
"fieldname": "contact_info",
"fieldtype": "Section Break",
"label": "Contact Info"
"label": "Contact Info",
"options": "icon-bullhorn"
},
{
"doctype": "DocField",
@@ -734,6 +743,7 @@
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"print_hide": 1
},
{
@@ -904,6 +914,7 @@
"fieldtype": "Section Break",
"label": "Sales Team",
"oldfieldtype": "Section Break",
"options": "icon-group",
"print_hide": 1
},
{
@@ -951,7 +962,6 @@
"doctype": "DocField",
"fieldname": "section_break1",
"fieldtype": "Section Break",
"options": "Simple",
"print_hide": 1
},
{

View File

@@ -3,6 +3,36 @@ from webnotes.utils import flt
import unittest
class TestSalesOrder(unittest.TestCase):
def test_make_material_request(self):
from selling.doctype.sales_order.sales_order import make_material_request
so = webnotes.bean(copy=test_records[0]).insert()
self.assertRaises(webnotes.ValidationError, make_material_request,
so.doc.name)
sales_order = webnotes.bean("Sales Order", so.doc.name)
sales_order.submit()
mr = make_material_request(so.doc.name)
self.assertEquals(mr[0]["material_request_type"], "Purchase")
self.assertEquals(len(mr), len(sales_order.doclist))
def test_make_delivery_note(self):
from selling.doctype.sales_order.sales_order import make_delivery_note
so = webnotes.bean(copy=test_records[0]).insert()
self.assertRaises(webnotes.ValidationError, make_delivery_note,
so.doc.name)
sales_order = webnotes.bean("Sales Order", so.doc.name)
sales_order.submit()
dn = make_delivery_note(so.doc.name)
self.assertEquals(dn[0]["doctype"], "Delivery Note")
self.assertEquals(len(dn), len(sales_order.doclist))
def create_so(self, so_doclist = None):
if not so_doclist:
so_doclist =test_records[0]

View File

@@ -7,6 +7,11 @@ wn.module_page["Selling"] = [
title: wn._("Documents"),
icon: "icon-copy",
items: [
{
label: wn._("Customer"),
description: wn._("Customer database."),
doctype:"Customer"
},
{
label: wn._("Lead"),
description: wn._("Database of potential customers."),
@@ -33,11 +38,6 @@ wn.module_page["Selling"] = [
title: wn._("Masters"),
icon: "icon-book",
items: [
{
label: wn._("Customer"),
description: wn._("Customer database."),
doctype:"Customer"
},
{
label: wn._("Contact"),
description: wn._("All Contacts."),