moved directory structure

This commit is contained in:
Rushabh Mehta
2012-09-24 19:13:42 +05:30
parent e47a6779e9
commit 2fa2f7178d
1637 changed files with 47 additions and 11450 deletions

View File

@@ -0,0 +1,153 @@
# DocType Mapper, Delivery Note-Installation Note
[
# These values are common in all dictionaries
{
'creation': '2010-08-08 17:09:34',
'docstatus': 0,
'modified': '2011-09-15 15:04:42',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'name': '__common__',
'parent': 'Delivery Note-Installation Note',
'parentfield': 'table_mapper_details',
'parenttype': 'DocType Mapper'
},
# These values are common for all Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'map': 'Yes',
'name': '__common__',
'parent': 'Delivery Note-Installation Note',
'parentfield': 'field_mapper_details',
'parenttype': 'DocType Mapper'
},
# These values are common for all DocType Mapper
{
'doctype': u'DocType Mapper',
'from_doctype': 'Delivery Note',
'module': 'Selling',
'name': '__common__',
'ref_doc_submitted': 1,
'to_doctype': 'Installation Note'
},
# DocType Mapper, Delivery Note-Installation Note
{
'doctype': u'DocType Mapper',
'name': 'Delivery Note-Installation Note'
},
# Field Mapper Detail
{
'checking_operator': '=',
'doctype': 'Field Mapper Detail',
'from_field': 'company',
'match_id': 0,
'to_field': 'company'
},
# Field Mapper Detail
{
'checking_operator': '=',
'doctype': 'Field Mapper Detail',
'from_field': 'customer',
'match_id': 0,
'to_field': 'customer'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'name',
'match_id': 0,
'to_field': 'delivery_note_no'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'name',
'match_id': 1,
'to_field': 'prevdoc_detail_docname'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'parent',
'match_id': 1,
'to_field': 'prevdoc_docname'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'parenttype',
'match_id': 1,
'to_field': 'prevdoc_doctype'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'eval: flt(obj.qty) - flt(obj.installed_qty)',
'match_id': 1,
'to_field': 'qty'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'posting_date',
'match_id': 2,
'to_field': 'prevdoc_date'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'serial_no',
'match_id': 1,
'to_field': 'serial_no'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_field': 'delivery_note_details',
'from_table': 'Delivery Note Item',
'match_id': 1,
'to_field': 'installed_item_details',
'to_table': 'Installation Note Item',
'validation_logic': 'qty > ifnull(installed_qty,0) and docstatus = 1'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_table': 'Delivery Note',
'match_id': 0,
'to_table': 'Installation Note',
'validation_logic': 'docstatus = 1'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_table': 'Delivery Note',
'match_id': 2,
'reference_doctype_key': 'prevdoc_doctype',
'reference_key': 'prevdoc_docname',
'to_field': 'installed_item_details',
'to_table': 'Installation Note Item',
'validation_logic': 'docstatus = 1'
}
]

View File

@@ -0,0 +1,84 @@
# DocType Mapper, Lead-Customer
[
# These values are common in all dictionaries
{
'creation': '2010-08-08 17:09:34',
'docstatus': 0,
'modified': '2011-09-14 12:36:24',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_table': 'Lead',
'match_id': 0,
'name': '__common__',
'parent': 'Lead-Customer',
'parentfield': 'table_mapper_details',
'parenttype': 'DocType Mapper',
'to_table': 'Customer',
'validation_logic': 'name is not null'
},
# These values are common for all Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'map': 'Yes',
'match_id': 0,
'name': '__common__',
'parent': 'Lead-Customer',
'parentfield': 'field_mapper_details',
'parenttype': 'DocType Mapper'
},
# These values are common for all DocType Mapper
{
'doctype': u'DocType Mapper',
'from_doctype': 'Lead',
'module': 'Selling',
'name': '__common__',
'to_doctype': 'Customer'
},
# DocType Mapper, Lead-Customer
{
'doctype': u'DocType Mapper',
'name': 'Lead-Customer'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'name',
'to_field': 'lead_name'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'company_name',
'to_field': 'customer_name'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'contact_no',
'to_field': 'phone_1'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'fax',
'to_field': 'fax_1'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail'
}
]

View File

@@ -0,0 +1,87 @@
# DocType Mapper, Lead-Opportunity
[
# These values are common in all dictionaries
{
'creation': '2010-08-08 17:09:34',
'docstatus': 0,
'modified': '2012-04-03 12:49:50',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all Table Mapper Detail
{
'doctype': u'Table Mapper Detail',
'from_table': u'Lead',
'match_id': 0,
'name': '__common__',
'parent': u'Lead-Opportunity',
'parentfield': u'table_mapper_details',
'parenttype': u'DocType Mapper',
'to_table': u'Opportunity',
'validation_logic': u'name is not null'
},
# These values are common for all Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'match_id': 0,
'name': '__common__',
'parent': u'Lead-Opportunity',
'parentfield': u'field_mapper_details',
'parenttype': u'DocType Mapper'
},
# These values are common for all DocType Mapper
{
'doctype': u'DocType Mapper',
'from_doctype': u'Lead',
'module': u'Selling',
'name': '__common__',
'to_doctype': u'Opportunity'
},
# DocType Mapper, Lead-Opportunity
{
'doctype': u'DocType Mapper',
'name': u'Lead-Opportunity'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'campaign_name',
'map': u'Yes',
'to_field': u'campaign'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'doctype',
'map': u'Yes',
'to_field': u'enquiry_from'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'name',
'map': u'Yes',
'to_field': u'lead'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'status',
'map': u'No',
'to_field': u'status'
},
# Table Mapper Detail
{
'doctype': u'Table Mapper Detail'
}
]

View File

@@ -0,0 +1,146 @@
# DocType Mapper, Opportunity-Quotation
[
# These values are common in all dictionaries
{
'creation': '2010-08-08 17:09:34',
'docstatus': 0,
'modified': '2012-04-03 12:49:50',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all Table Mapper Detail
{
'doctype': u'Table Mapper Detail',
'name': '__common__',
'parent': u'Opportunity-Quotation',
'parentfield': u'table_mapper_details',
'parenttype': u'DocType Mapper',
'validation_logic': u'docstatus=1'
},
# These values are common for all Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'name': '__common__',
'parent': u'Opportunity-Quotation',
'parentfield': u'field_mapper_details',
'parenttype': u'DocType Mapper'
},
# These values are common for all DocType Mapper
{
'doctype': u'DocType Mapper',
'from_doctype': u'Opportunity',
'module': u'Selling',
'name': '__common__',
'ref_doc_submitted': 1,
'to_doctype': u'Quotation'
},
# DocType Mapper, Opportunity-Quotation
{
'doctype': u'DocType Mapper',
'name': u'Opportunity-Quotation'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'uom',
'map': u'Yes',
'match_id': 1,
'to_field': u'stock_uom'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'name',
'map': u'Yes',
'match_id': 0,
'to_field': u'enq_no'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'parent',
'map': u'Yes',
'match_id': 1,
'to_field': u'prevdoc_docname'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'parenttype',
'map': u'Yes',
'match_id': 1,
'to_field': u'prevdoc_doctype'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'enquiry_from',
'map': u'Yes',
'match_id': 0,
'to_field': u'quotation_to'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'enquiry_type',
'map': u'Yes',
'match_id': 0,
'to_field': u'order_type'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'transaction_date',
'map': u'No',
'match_id': 0,
'to_field': u'transaction_date'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'status',
'map': u'No',
'match_id': 0,
'to_field': u'status'
},
# Field Mapper Detail
{
'doctype': u'Field Mapper Detail',
'from_field': u'naming_series',
'map': u'No',
'match_id': 0,
'to_field': u'naming_series'
},
# Table Mapper Detail
{
'doctype': u'Table Mapper Detail',
'from_table': u'Opportunity',
'match_id': 0,
'to_table': u'Quotation'
},
# Table Mapper Detail
{
'doctype': u'Table Mapper Detail',
'from_field': u'enq_details',
'from_table': u'Opportunity Item',
'match_id': 1,
'to_field': u'quotation_details',
'to_table': u'Quotation Item'
}
]

View File

@@ -0,0 +1,64 @@
# DocType Mapper, Project-Sales Order
[
# These values are common in all dictionaries
{
'creation': '2010-09-01 15:47:59',
'docstatus': 0,
'modified': '2011-09-15 15:04:43',
'modified_by': 'Administrator',
'owner': 'ashwini@webnotestech.com'
},
# These values are common for all Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_table': 'Project',
'match_id': 0,
'name': '__common__',
'parent': 'Project-Sales Order',
'parentfield': 'table_mapper_details',
'parenttype': 'DocType Mapper',
'to_table': 'Sales Order',
'validation_logic': 'name is not null'
},
# These values are common for all Field Mapper Detail
{
'checking_operator': '=',
'doctype': 'Field Mapper Detail',
'from_field': 'customer',
'map': 'Yes',
'match_id': 0,
'name': '__common__',
'parent': 'Project-Sales Order',
'parentfield': 'field_mapper_details',
'parenttype': 'DocType Mapper',
'to_field': 'customer'
},
# These values are common for all DocType Mapper
{
'doctype': 'DocType Mapper',
'from_doctype': 'Project',
'module': 'Selling',
'name': '__common__',
'to_doctype': 'Sales Order'
},
# DocType Mapper, Project-Sales Order
{
'doctype': 'DocType Mapper',
'name': 'Project-Sales Order'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail'
}
]

View File

@@ -0,0 +1,165 @@
# DocType Mapper, Quotation-Sales Order
[
# These values are common in all dictionaries
{
'creation': '2010-08-08 17:09:35',
'docstatus': 0,
'modified': '2011-09-14 12:36:24',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'name': '__common__',
'parent': 'Quotation-Sales Order',
'parentfield': 'table_mapper_details',
'parenttype': 'DocType Mapper'
},
# These values are common for all Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'name': '__common__',
'parent': 'Quotation-Sales Order',
'parentfield': 'field_mapper_details',
'parenttype': 'DocType Mapper'
},
# These values are common for all DocType Mapper
{
'doctype': u'DocType Mapper',
'from_doctype': 'Quotation',
'module': 'Selling',
'name': '__common__',
'ref_doc_submitted': 1,
'to_doctype': 'Sales Order'
},
# DocType Mapper, Quotation-Sales Order
{
'doctype': u'DocType Mapper',
'name': 'Quotation-Sales Order'
},
# Field Mapper Detail
{
'checking_operator': '>=',
'doctype': 'Field Mapper Detail',
'from_field': 'transaction_date',
'map': 'No',
'match_id': 0,
'to_field': 'transaction_date'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'transaction_date',
'map': 'Yes',
'match_id': 0,
'to_field': 'quotation_date'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'name',
'map': 'Yes',
'match_id': 0,
'to_field': 'quotation_no'
},
# Field Mapper Detail
{
'checking_operator': '=',
'doctype': 'Field Mapper Detail',
'from_field': 'company',
'map': 'Yes',
'match_id': 0,
'to_field': 'company'
},
# Field Mapper Detail
{
'checking_operator': '=',
'doctype': 'Field Mapper Detail',
'from_field': 'fiscal_year',
'map': 'Yes',
'match_id': 0,
'to_field': 'fiscal_year'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'parent',
'map': 'Yes',
'match_id': 1,
'to_field': 'prevdoc_docname'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'naming_series',
'map': 'No',
'match_id': 0,
'to_field': 'naming_series'
},
# Field Mapper Detail
{
'doctype': 'Field Mapper Detail',
'from_field': 'status',
'map': 'No',
'match_id': 0,
'to_field': 'status'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_field': 'sales_team',
'from_table': 'Sales Team',
'match_id': 3,
'to_field': 'sales_team',
'to_table': 'Sales Team',
'validation_logic': 'name is not null'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_field': 'other_charges',
'from_table': 'Sales Taxes and Charges',
'match_id': 2,
'to_field': 'other_charges',
'to_table': 'Sales Taxes and Charges',
'validation_logic': 'name is not null'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_field': 'quotation_details',
'from_table': 'Quotation Item',
'match_id': 1,
'reference_doctype_key': 'prevdoc_doctype',
'to_field': 'sales_order_details',
'to_table': 'Sales Order Item',
'validation_logic': 'name is not null'
},
# Table Mapper Detail
{
'doctype': 'Table Mapper Detail',
'from_table': 'Quotation',
'match_id': 0,
'reference_key': 'prevdoc_docname',
'to_table': 'Sales Order',
'validation_logic': 'docstatus = 1'
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8
selling/__init__.py Normal file
View File

@@ -0,0 +1,8 @@
from __future__ import unicode_literals
install_docs = [
{"doctype":"Role", "role_name":"Customer", "name":"Customer"},
{"doctype":"Role", "role_name":"Partner", "name":"Partner"},
{"doctype":"Role", "role_name":"Sales Manager", "name":"Sales Manager"},
{"doctype":"Role", "role_name":"Sales Master Manager", "name":"Sales Master Manager"},
{"doctype":"Role", "role_name":"Sales User", "name":"Sales User"},
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,26 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
}

View File

@@ -0,0 +1,162 @@
# DocType, Campaign
[
# These values are common in all dictionaries
{
'creation': '2012-07-03 13:30:38',
'docstatus': 0,
'modified': '2012-07-12 13:21:52',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1326102553',
'allow_trash': 1,
'autoname': u'field:campaign_name',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'description': u'Keep Track of Sales Campaigns. Keep track of Leads, Quotations, Sales Order etc from Campaigns to gauge Return on Investment. ',
'doctype': 'DocType',
'document_type': u'Master',
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 1
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Campaign',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
'amend': 0,
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'Campaign',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1,
'submit': 0
},
# DocType, Campaign
{
'doctype': 'DocType',
'name': u'Campaign'
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Manager',
'write': 0
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'write': 0
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Master Manager',
'write': 0
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales User',
'write': 0
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'write': 0
},
# DocPerm
{
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Master Manager',
'write': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'trash_reason',
'fieldtype': u'Small Text',
'label': u'Trash Reason',
'oldfieldname': u'trash_reason',
'oldfieldtype': u'Small Text',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'campaign',
'fieldtype': u'Section Break',
'label': u'Campaign',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'campaign_name',
'fieldtype': u'Data',
'label': u'Campaign Name',
'oldfieldname': u'campaign_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Text',
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Text',
'permlevel': 0,
'width': u'300px'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,209 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
wn.require('erpnext/setup/doctype/contact_control/contact_control.js');
wn.require('erpnext/support/doctype/communication/communication.js');
/* ********************************* onload ********************************************* */
cur_frm.cscript.onload = function(doc,dt,dn){
// history doctypes and scripts
cur_frm.history_dict = {
'Quotation' : 'cur_frm.cscript.make_qtn_list(this.body, this.doc)',
'Sales Order' : 'cur_frm.cscript.make_so_list(this.body, this.doc)',
'Delivery Note' : 'cur_frm.cscript.make_dn_list(this.body, this.doc)',
'Sales Invoice' : 'cur_frm.cscript.make_si_list(this.body, this.doc)'
}
// make address, contact, shipping, history list body
cur_frm.cscript.make_hl_body();
//cur_frm.cscript.make_sl_body();
cur_frm.cscript.load_defaults(doc, dt, dn);
cur_frm.cscript.make_communication_body();
}
cur_frm.cscript.load_defaults = function(doc, dt, dn) {
doc = locals[doc.doctype][doc.name];
if(!(doc.__islocal && doc.lead_name)) { return; }
var fields_to_refresh = LocalDB.set_default_values(doc);
if(fields_to_refresh) { refresh_many(fields_to_refresh); }
}
cur_frm.add_fetch('lead_name', 'company_name', 'customer_name');
cur_frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate');
/* ********************************* refresh ********************************************* */
cur_frm.cscript.refresh = function(doc,dt,dn) {
if(sys_defaults.cust_master_name == 'Customer Name')
hide_field('naming_series');
else
unhide_field('naming_series');
if(doc.__islocal){
hide_field(['address_html','contact_html']);
//cur_frm.cscript.set_hl_msg(doc);
//cur_frm.cscript.set_sl_msg(doc);
}else{
unhide_field(['address_html','contact_html']);
// make lists
cur_frm.cscript.make_address(doc,dt,dn);
cur_frm.cscript.make_contact(doc,dt,dn);
cur_frm.cscript.make_history(doc,dt,dn);
cur_frm.cscript.render_communication_list(doc, cdt, cdn);
//cur_frm.cscript.make_shipping_address(doc,dt,dn);
}
}
cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 2,
new_doctype: "Address",
get_query: function() {
return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_address desc"
},
as_dict: 1,
no_results_message: 'No addresses created',
render_row: cur_frm.cscript.render_address_row,
});
// note: render_address_row is defined in contact_control.js
}
cur_frm.address_list.run();
}
cur_frm.cscript.make_contact = function() {
if(!cur_frm.contact_list) {
cur_frm.contact_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 2,
new_doctype: "Contact",
get_query: 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',
render_row: cur_frm.cscript.render_contact_row,
});
// note: render_contact_row is defined in contact_control.js
}
cur_frm.contact_list.run();
}
/* ********************************* client triggers ************************************** */
// ---------------
// customer group
// ---------------
cur_frm.fields_dict['customer_group'].get_query = function(doc,dt,dn) {
return 'SELECT `tabCustomer Group`.`name`, `tabCustomer Group`.`parent_customer_group` FROM `tabCustomer Group` WHERE `tabCustomer Group`.`is_group` = "No" AND `tabCustomer Group`.`docstatus`!= 2 AND `tabCustomer Group`.%(key)s LIKE "%s" ORDER BY `tabCustomer Group`.`name` ASC LIMIT 50';
}
// -----
// lead
// -----
cur_frm.fields_dict['lead_name'].get_query = function(doc,dt,dn){
return 'SELECT `tabLead`.`name` FROM `tabLead` WHERE `tabLead`.`status`!="Converted" AND `tabLead`.%(key)s LIKE "%s" ORDER BY `tabLead`.`name` ASC LIMIT 50';
}
// Transaction History
// functions called by these functions are defined in communication.js
cur_frm.cscript.make_qtn_list = function(parent, doc) {
cur_frm.cscript.get_common_list_view(parent, doc, 'Quotation');
}
cur_frm.cscript.make_so_list = function(parent, doc) {
cur_frm.cscript.get_common_list_view(parent, doc, 'Sales Order');
}
cur_frm.cscript.make_dn_list = function(parent, doc) {
cur_frm.cscript.get_common_list_view(parent, doc, 'Delivery Note');
}
cur_frm.cscript.get_common_list_view = function(parent, doc, doctype) {
var ListView = wn.views.ListView.extend({
init: function(doclistview) {
this._super(doclistview);
this.fields = this.fields.concat([
"`tab" + doctype + "`.status",
"`tab" + doctype + "`.currency",
"ifnull(`tab" + doctype + "`.grand_total_export, 0) as grand_total_export",
]);
},
prepare_data: function(data) {
this._super(data);
data.grand_total_export = data.currency + " " + fmt_money(data.grand_total_export)
},
columns: [
{width: '3%', content: 'docstatus'},
{width: '25%', content: 'name'},
{width: '25%', content: 'status'},
{width: '35%', content: 'grand_total_export', css: {'text-align': 'right'}},
{width: '12%', content:'modified', css: {'text-align': 'right'}}
],
});
cur_frm.cscript.render_list(doc, doctype, parent, ListView);
}
cur_frm.cscript.make_si_list = function(parent, doc) {
var ListView = wn.views.ListView.extend({
init: function(doclistview) {
this._super(doclistview);
this.fields = this.fields.concat([
"ifnull(`tabSales Invoice`.outstanding_amount, 0) as outstanding_amount",
"`tabSales Invoice`.currency",
"ifnull(`tabSales Invoice`.conversion_rate, 0) as conversion_rate",
"ifnull(`tabSales Invoice`.grand_total_export, 0) as grand_total_export",
]);
},
prepare_data: function(data) {
this._super(data);
if (data.outstanding_amount) {
data.outstanding_amount = data.currency + " " +
fmt_money(flt(data.outstanding_amount)/flt(data.conversion_rate)) +
" [outstanding]";
} else {
data.outstanding_amount = '';
}
data.grand_total_export = data.currency + " " + fmt_money(data.grand_total_export);
},
columns: [
{width: '3%', content: 'docstatus'},
{width: '25%', content: 'name'},
{width: '25%', content: 'outstanding_amount',
css: {'text-align': 'right', 'color': '#777'}},
{width: '35%', content: 'grand_total_export', css: {'text-align': 'right'}},
{width: '12%', content:'modified', css: {'text-align': 'right'}}
],
});
cur_frm.cscript.render_list(doc, 'Sales Invoice', parent, ListView);
}

View File

@@ -0,0 +1,288 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cstr, date_diff, flt, formatdate, get_defaults, getdate, has_common, now, nowdate, replace_newlines, sendmail, set_default, user_format, validate_email_add
from webnotes.model.doc import Document, make_autoname
from webnotes.model.code import get_obj
from webnotes import msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
# ******************************************************* autoname ***********************************************************
def autoname(self):
cust_master_name = get_defaults().get('cust_master_name')
if cust_master_name == 'Customer Name':
# filter out bad characters in name
#cust = self.doc.customer_name.replace('&','and').replace('.','').replace("'",'').replace('"','').replace(',','').replace('`','')
cust = self.doc.customer_name
supp = sql("select name from `tabSupplier` where name = %s", (cust))
supp = supp and supp[0][0] or ''
if supp:
msgprint("You already have a Supplier with same name")
raise Exception("You already have a Supplier with same name")
else:
self.doc.name = cust
else:
self.doc.name = make_autoname(self.doc.naming_series+'.#####')
# ******************************************************* triggers ***********************************************************
# ----------------
# get company abbr
# -----------------
def get_company_abbr(self):
return get_value('Company', self.doc.company, 'abbr')
# -----------------------------------------------------------------------------------------------------
# get parent account(i.e receivables group from company where default account head need to be created)
# -----------------------------------------------------------------------------------------------------
def get_receivables_group(self):
g = sql("select receivables_group from tabCompany where name=%s", self.doc.company)
g = g and g[0][0] or ''
if not g:
msgprint("Update Company master, assign a default group for Receivables")
raise Exception
return g
# ******************************************************* validate *********************************************************
# ----------------
# validate values
# ----------------
def validate_values(self):
# Master name by naming series -> Series field mandatory
if get_defaults().get('cust_master_name') == 'Naming Series' and not self.doc.naming_series:
msgprint("Series is Mandatory.")
raise Exception
# ---------
# validate
# ---------
def validate(self):
self.validate_values()
# ******************************************************* on update *********************************************************
# ------------------------
# create customer address
# ------------------------
def create_customer_address(self):
addr_flds = [self.doc.address_line1, self.doc.address_line2, self.doc.city, self.doc.state, self.doc.country, self.doc.pincode]
address_line = "\n".join(filter(lambda x : (x!='' and x!=None),addr_flds))
if self.doc.phone_1:
address_line = address_line + "\n" + "Phone: " + cstr(self.doc.phone_1)
if self.doc.email_id:
address_line = address_line + "\n" + "E-mail: " + cstr(self.doc.email_id)
set(self.doc,'address', address_line)
telephone = "(O): " + cstr(self.doc.phone_1) +"\n"+ cstr(self.doc.phone_2) + "\n" + "(M): " + "\n" + "(fax): " + cstr(self.doc.fax_1)
set(self.doc,'telephone',telephone)
# ------------------------------------
# create primary contact for customer
# ------------------------------------
def create_p_contact(self,nm,phn_no,email_id,mob_no,fax,cont_addr):
c1 = Document('Contact')
c1.first_name = nm
c1.contact_name = nm
c1.contact_no = phn_no
c1.email_id = email_id
c1.mobile_no = mob_no
c1.fax = fax
c1.contact_address = cont_addr
c1.is_primary_contact = 'Yes'
c1.is_customer =1
c1.customer = self.doc.name
c1.customer_name = self.doc.customer_name
c1.customer_address = self.doc.address
c1.customer_group = self.doc.customer_group
c1.save(1)
# ------------------------
# create customer contact
# ------------------------
def create_customer_contact(self):
contact = sql("select distinct name from `tabContact` where customer_name=%s", (self.doc.customer_name))
contact = contact and contact[0][0] or ''
if not contact:
# create primary contact for individual customer
if self.doc.customer_type == 'Individual':
self.create_p_contact(self.doc.customer_name,self.doc.phone_1,self.doc.email_id,'',self.doc.fax_1,self.doc.address)
# create primary contact for lead
elif self.doc.lead_name:
c_detail = sql("select lead_name, company_name, contact_no, mobile_no, email_id, fax, address from `tabLead` where name =%s", self.doc.lead_name, as_dict=1)
self.create_p_contact(c_detail and c_detail[0]['lead_name'] or '', c_detail and c_detail[0]['contact_no'] or '', c_detail and c_detail[0]['email_id'] or '', c_detail and c_detail[0]['mobile_no'] or '', c_detail and c_detail[0]['fax'] or '', c_detail and c_detail[0]['address'] or '')
# -------------------
# update lead status
# -------------------
def update_lead_status(self):
if self.doc.lead_name:
sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
# -------------------------------------------------------------------------
# create accont head - in tree under receivables_group of selected company
# -------------------------------------------------------------------------
def create_account_head(self):
if self.doc.company :
abbr = self.get_company_abbr()
if not sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)):
parent_account = self.get_receivables_group()
arg = {'account_name':self.doc.name,'parent_account': parent_account, 'group_or_ledger':'Ledger', 'company':self.doc.company,'account_type':'','tax_rate':'0','master_type':'Customer','master_name':self.doc.name,'address':self.doc.address}
# create
ac = get_obj('GL Control').add_ac(cstr(arg))
msgprint("Account Head created for "+ac)
else :
msgprint("Please Select Company under which you want to create account head")
# ----------------------------------------
# update credit days and limit in account
# ----------------------------------------
def update_credit_days_limit(self):
sql("update tabAccount set credit_days = '%s', credit_limit = '%s' where name = '%s'" % (self.doc.credit_days, self.doc.credit_limit, self.doc.name + " - " + self.get_company_abbr()))
#create address and contact from lead
def create_lead_address_contact(self):
if self.doc.lead_name:
details = sql("select name, lead_name, address_line1, address_line2, city, country, state, pincode, phone, mobile_no, fax, email_id from `tabLead` where name = '%s'" %(self.doc.lead_name), as_dict = 1)
d = Document('Address')
d.address_line1 = details[0]['address_line1']
d.address_line2 = details[0]['address_line2']
d.city = details[0]['city']
d.country = details[0]['country']
d.pincode = details[0]['pincode']
d.state = details[0]['state']
d.fax = details[0]['fax']
d.email_id = details[0]['email_id']
d.phone = details[0]['phone']
d.customer = self.doc.name
d.customer_name = self.doc.customer_name
d.is_primary_address = 1
d.address_type = 'Office'
try:
d.save(1)
except NameError, e:
pass
c = Document('Contact')
c.first_name = details[0]['lead_name']
c.email_id = details[0]['email_id']
c.phone = details[0]['phone']
c.mobile_no = details[0]['mobile_no']
c.customer = self.doc.name
c.customer_name = self.doc.customer_name
c.is_primary_contact = 1
try:
c.save(1)
except NameError, e:
pass
# ----------
# on update
# ----------
def on_update(self):
# create customer addr
#self.create_customer_address()
# create customer contact
#self.create_customer_contact()
# update lead status
self.update_lead_status()
# create account head
self.create_account_head()
# update credit days and limit in account
self.update_credit_days_limit()
#create address and contact from lead
self.create_lead_address_contact()
def delete_customer_address(self):
for rec in sql("select * from `tabAddress` where customer='%s'" %(self.doc.name), as_dict=1):
sql("delete from `tabAddress` where name=%s",(rec['name']))
def delete_customer_contact(self):
for rec in sql("select * from `tabContact` where customer='%s'" %(self.doc.name), as_dict=1):
sql("delete from `tabContact` where name=%s",(rec['name']))
def delete_customer_communication(self):
webnotes.conn.sql("""\
delete from `tabCommunication`
where customer = %s and supplier is null""", self.doc.name)
def delete_customer_account(self):
"""delete customer's ledger if exist and check balance before deletion"""
acc = sql("select name from `tabAccount` where master_type = 'Customer' \
and master_name = %s and docstatus < 2", self.doc.name)
if acc:
from webnotes.model import delete_doc
delete_doc('Account', acc[0][0])
def on_trash(self):
self.delete_customer_address()
self.delete_customer_contact()
self.delete_customer_communication()
self.delete_customer_account()
if self.doc.lead_name:
sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
# on rename
# ---------
def on_rename(self,newdn,olddn):
#update customer_name if not naming series
if get_defaults().get('cust_master_name') == 'Customer Name':
update_fields = [
('Customer', 'name'),
('Address', 'customer'),
('Contact', 'customer'),
('Customer Issue', 'customer'),
('Delivery Note', 'customer'),
('Opportunity', 'customer'),
('Installation Note', 'customer'),
('Maintenance Schedule', 'customer'),
('Maintenance Visit', 'customer'),
('Project', 'customer'),
('Quotation', 'customer'),
('Sales Invoice', 'customer'),
('Sales Order', 'customer'),
('Serial No', 'customer'),
('Shipping Address', 'customer'),
('Stock Entry', 'customer'),
('Support Ticket', 'customer'),
('Task', 'customer')]
for rec in update_fields:
sql("update `tab%s` set customer_name = '%s' where %s = '%s'" %(rec[0],newdn,rec[1],olddn))
#update master_name in doctype account
sql("update `tabAccount` set master_name = '%s', master_type = 'Customer' where master_name = '%s'" %(newdn,olddn))

View File

@@ -0,0 +1,534 @@
# DocType, Customer
[
# These values are common in all dictionaries
{
u'creation': '2012-07-18 20:34:41',
u'docstatus': 0,
u'modified': '2012-09-17 11:31:55',
u'modified_by': u'Administrator',
u'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1330501485',
'allow_print': 0,
'allow_trash': 1,
'colour': u'White:FFF',
'default_print_format': u'Standard',
u'doctype': u'DocType',
'document_type': u'Master',
'module': u'Selling',
u'name': u'__common__',
'search_fields': u'customer_name,customer_group,country,territory',
'section_style': u'Tabbed',
'server_code_error': u' ',
'show_in_menu': 0,
'subject': u'eval:"%(customer_name)s"=="%(name)s" ? "" : "%(customer_name)s"',
'tag_fields': u'customer_group,customer_type',
'version': 1
},
# These values are common for all DocField
{
u'doctype': u'DocField',
u'name': u'__common__',
'parent': u'Customer',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
u'doctype': u'DocPerm',
u'name': u'__common__',
'parent': u'Customer',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1
},
# DocType, Customer
{
u'doctype': u'DocType',
u'name': u'Customer'
},
# DocField
{
'colour': u'White:FFF',
'description': u'Note: You Can Manage Multiple Address or Contacts via Addresses & Contacts',
u'doctype': u'DocField',
'fieldname': u'basic_info',
'fieldtype': u'Section Break',
'label': u'Basic Info',
'oldfieldtype': u'Section Break',
'permlevel': 0,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'customer_name',
'fieldtype': u'Data',
'hidden': 0,
'in_filter': 1,
'label': u'Customer Name',
'no_copy': 1,
'oldfieldname': u'customer_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 0,
'report_hide': 0,
'reqd': 1,
'search_index': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'customer_type',
'fieldtype': u'Select',
'label': u'Customer Type',
'oldfieldname': u'customer_type',
'oldfieldtype': u'Select',
'options': u'\nCompany\nIndividual',
'permlevel': 0,
'reqd': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'naming_series',
'fieldtype': u'Select',
'label': u'Series',
'no_copy': 1,
'options': u'\nCUST\nCUSTMUM',
'permlevel': 0,
'print_hide': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'Fetch lead which will be converted into customer.',
u'doctype': u'DocField',
'fieldname': u'lead_name',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Lead Ref',
'no_copy': 1,
'oldfieldname': u'lead_name',
'oldfieldtype': u'Link',
'options': u'Lead',
'permlevel': 0,
'print_hide': 1,
'report_hide': 1,
'trigger': u'Client'
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break0',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'description': u'<a href="#!Sales Browser/Customer Group">To manage Customer Groups, click here</a>',
u'doctype': u'DocField',
'fieldname': u'customer_group',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Customer Group',
'oldfieldname': u'customer_group',
'oldfieldtype': u'Link',
'options': u'Customer Group',
'permlevel': 0,
'print_hide': 0,
'reqd': 1,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'description': u'<a href="#!Sales Browser/Territory">To manage Territory, click here</a>',
u'doctype': u'DocField',
'fieldname': u'territory',
'fieldtype': u'Link',
'label': u'Territory',
'oldfieldname': u'territory',
'oldfieldtype': u'Link',
'options': u'Territory',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'address_contacts',
'fieldtype': u'Section Break',
'label': u'Address & Contacts',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:doc.__islocal',
u'doctype': u'DocField',
'fieldname': u'address_desc',
'fieldtype': u'HTML',
'label': u'Address Desc',
'options': u'<em>Addresses will appear only when you save the customer</em>',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'address_html',
'fieldtype': u'HTML',
'label': u'Address HTML',
'permlevel': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:doc.__islocal',
u'doctype': u'DocField',
'fieldname': u'contact_desc',
'fieldtype': u'HTML',
'label': u'Contact Desc',
'options': u'<em>Contact Details will appear only when you save the customer</em>',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'contact_html',
'fieldtype': u'HTML',
'label': u'Contact HTML',
'oldfieldtype': u'HTML',
'permlevel': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'communication_history',
'fieldtype': u'Section Break',
'label': u'Communication History',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'communication_html',
'fieldtype': u'HTML',
'label': u'Communication HTML',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'more_info',
'fieldtype': u'Section Break',
'label': u'More Info',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break2',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'description': u'To create an Account Head under a different company, select the company and save customer.',
u'doctype': u'DocField',
'fieldname': u'company',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Company',
'oldfieldname': u'company',
'oldfieldtype': u'Link',
'options': u'Company',
'permlevel': 0,
'reqd': 1,
'search_index': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'default_price_list',
'fieldtype': u'Link',
'label': u'Default Price List',
'options': u'Price List',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'This currency will get fetched in Sales transactions of this customer',
u'doctype': u'DocField',
'fieldname': u'default_currency',
'fieldtype': u'Select',
'label': u'Default Currency',
'no_copy': 1,
'options': u'link:Currency',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u"Your Customer's TAX registration numbers (if applicable) or any general information",
u'doctype': u'DocField',
'fieldname': u'customer_details',
'fieldtype': u'Text',
'label': u'Customer Details',
'oldfieldname': u'customer_details',
'oldfieldtype': u'Code',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break3',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'credit_days',
'fieldtype': u'Int',
'label': u'Credit Days',
'oldfieldname': u'credit_days',
'oldfieldtype': u'Int',
'permlevel': 2
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'credit_limit',
'fieldtype': u'Currency',
'label': u'Credit Limit',
'oldfieldname': u'credit_limit',
'oldfieldtype': u'Currency',
'permlevel': 2
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'website',
'fieldtype': u'Data',
'label': u'Website',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'sales_team_section_break',
'fieldtype': u'Section Break',
'label': u'Sales Team',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'default_sales_partner',
'fieldtype': u'Link',
'label': u'Default Sales Partner',
'oldfieldname': u'default_sales_partner',
'oldfieldtype': u'Link',
'options': u'Sales Partner',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'default_commission_rate',
'fieldtype': u'Currency',
'label': u'Default Commission Rate',
'oldfieldname': u'default_commission_rate',
'oldfieldtype': u'Currency',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'sales_team',
'fieldtype': u'Table',
'label': u'Sales Team Details',
'oldfieldname': u'sales_team',
'oldfieldtype': u'Table',
'options': u'Sales Team',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:!doc.__islocal',
u'doctype': u'DocField',
'fieldname': u'transaction_history',
'fieldtype': u'Section Break',
'label': u'Transaction History',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:!doc.__islocal',
u'doctype': u'DocField',
'fieldname': u'history_html',
'fieldtype': u'HTML',
'label': u'History HTML',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'trash_reason',
'fieldtype': u'Small Text',
'label': u'Trash Reason',
'oldfieldname': u'trash_reason',
'oldfieldtype': u'Small Text',
'permlevel': 1
},
# DocPerm
{
'amend': 0,
'cancel': 1,
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Master Manager',
'submit': 0,
'write': 1
},
# DocPerm
{
'cancel': 1,
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Accounts Manager',
'write': 1
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
u'doctype': u'DocPerm',
'permlevel': 1,
'role': u'All',
'submit': 0,
'write': 0
},
# DocPerm
{
u'doctype': u'DocPerm',
'permlevel': 2,
'role': u'Accounts Manager',
'write': 1
},
# DocPerm
{
u'doctype': u'DocPerm',
'permlevel': 2,
'role': u'System Manager',
'write': 1
},
# DocPerm
{
u'doctype': u'DocPerm',
'permlevel': 2,
'role': u'All'
}
]

View File

@@ -0,0 +1,28 @@
// render
wn.doclistviews['Customer'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
"`tabCustomer`.customer_name",
"`tabCustomer`.territory",
]);
this.show_hide_check_column();
},
prepare_data: function(data) {
this._super(data);
data.customer_name = repl("<a href=\"#!Form/Customer/%(name)s\">%(customer_name)s</a>",
data);
},
columns: [
{width: '3%', content:'check'},
{width: '5%', content:'avatar'},
{width: '50%', content:'customer_name'},
{width: '10%', content:'tags'},
{width: '20%', content:'territory',
css: {'color': '#aaa'}},
{width: '12%', content:'modified',
css: {'text-align': 'right', 'color':'#777'}}
],
});

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,26 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
}

View File

@@ -0,0 +1,85 @@
# DocType, Industry Type
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:09',
'docstatus': 0,
'modified': '2012-03-27 14:36:09',
'modified_by': u'Administrator',
'owner': u'harshada@webnotestech.com'
},
# These values are common for all DocType
{
'autoname': u'field:industry',
'colour': u'White:FFF',
'doctype': 'DocType',
'document_type': u'Master',
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'version': 4
},
# These values are common for all DocField
{
'doctype': u'DocField',
'fieldname': u'industry',
'fieldtype': u'Data',
'label': u'Industry',
'name': '__common__',
'oldfieldname': u'industry',
'oldfieldtype': u'Data',
'parent': u'Industry Type',
'parentfield': u'fields',
'parenttype': u'DocType',
'permlevel': 0,
'reqd': 1
},
# These values are common for all DocPerm
{
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'Industry Type',
'parentfield': u'permissions',
'parenttype': u'DocType',
'permlevel': 0,
'read': 1
},
# DocType, Industry Type
{
'doctype': 'DocType',
'name': u'Industry Type'
},
# DocPerm
{
'create': 1,
'doctype': u'DocPerm',
'role': u'Sales Manager',
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'role': u'Sales User'
},
# DocPerm
{
'create': 1,
'doctype': u'DocPerm',
'role': u'Sales Master Manager',
'write': 1
},
# DocField
{
'doctype': u'DocField'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,85 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
cur_frm.cscript.tname = "Installation Note Item";
cur_frm.cscript.fname = "installed_item_details";
cur_frm.cscript.onload = function(doc, dt, dn) {
if(!doc.status) set_multiple(dt,dn,{status:'Draft'});
if(doc.__islocal){
set_multiple(dt,dn,{inst_date:get_today()});
hide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
}
if (doc.customer) {
unhide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
}
}
cur_frm.fields_dict['delivery_note_no'].get_query = function(doc) {
doc = locals[this.doctype][this.docname];
var cond = '';
if(doc.customer) {
cond = '`tabDelivery Note`.customer = "'+doc.customer+'" AND';
}
return repl('SELECT DISTINCT `tabDelivery Note`.name, `tabDelivery Note`.customer_name FROM `tabDelivery Note`, `tabDelivery Note Item` WHERE `tabDelivery Note`.company = "%(company)s" AND `tabDelivery Note`.docstatus = 1 AND ifnull(`tabDelivery Note`.per_installed,0) < 100 AND %(cond)s `tabDelivery Note`.name LIKE "%s" ORDER BY `tabDelivery Note`.name DESC LIMIT 50', {company:doc.company, cond:cond});
}
cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50';
}
cur_frm.cscript.get_items = function(doc, dt, dn) {
var callback = function(r,rt) {
unhide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
cur_frm.refresh();
}
get_server_fields('pull_delivery_note_details','','',doc, dt, dn,1,callback);
}
//customer
cur_frm.cscript.customer = function(doc,dt,dn) {
var callback = function(r,rt) {
var doc = locals[cur_frm.doctype][cur_frm.docname];
cur_frm.refresh();
}
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
if(doc.customer) unhide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
}
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) 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.fields_dict.customer_address.on_new = function(dn) {
locals['Address'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Address'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict.contact_person.on_new = function(dn) {
locals['Contact'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Contact'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,address_line1,city FROM tabAddress WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,CONCAT(first_name," ",ifnull(last_name,"")) As FullName,department,designation FROM tabContact WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}

View File

@@ -0,0 +1,213 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
class DocType(TransactionBase):
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
self.tname = 'Installation Note Item'
self.fname = 'installed_item_details'
# Autoname
# ---------
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+'.#####')
#fetch delivery note details
#====================================
def pull_delivery_note_details(self):
self.validate_prev_docname()
self.doclist = get_obj('DocType Mapper', 'Delivery Note-Installation Note').dt_map('Delivery Note', 'Installation Note', self.doc.delivery_note_no, self.doc, self.doclist, "[['Delivery Note', 'Installation Note'],['Delivery Note Item', 'Installation Note Item']]")
# Validates that Delivery Note is not pulled twice
#============================================
def validate_prev_docname(self):
for d in getlist(self.doclist, 'installed_item_details'):
if self.doc.delivery_note_no == d.prevdoc_docname:
msgprint(cstr(self.doc.delivery_note_no) + " delivery note details have already been pulled. ")
raise Exception, "Validation Error. "
#Fiscal Year Validation
#================================
def validate_fiscal_year(self):
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.inst_date,'Installation Date')
# Validate Mandatory
#===============================
def validate_mandatory(self):
# Amendment Date
if self.doc.amended_from and not self.doc.amendment_date:
msgprint("Please Enter Amendment Date")
raise Exception, "Validation Error. "
# Validate values with reference document
#----------------------------------------
def validate_reference_value(self):
get_obj('DocType Mapper', 'Delivery Note-Installation Note', with_children = 1).validate_reference_value(self, self.doc.name)
#check if serial no added
#-----------------------------
def is_serial_no_added(self,item_code,serial_no):
ar_required = sql("select has_serial_no from tabItem where name = '%s'" % item_code)
ar_required = ar_required and ar_required[0][0] or ''
if ar_required == 'Yes' and not serial_no:
msgprint("Serial No is mandatory for item: "+ item_code)
raise Exception
elif ar_required != 'Yes' and cstr(serial_no).strip():
msgprint("If serial no required, please select 'Yes' in 'Has Serial No' in Item :"+item_code)
raise Exception
#check if serial no exist in system
#-------------------------------------
def is_serial_no_exist(self, item_code, serial_no):
for x in serial_no:
chk = sql("select name from `tabSerial No` where name =%s", x)
if not chk:
msgprint("Serial No "+x+" does not exist in the system")
raise Exception
#check if serial no already installed
#------------------------------------------
def is_serial_no_installed(self,cur_s_no,item_code):
for x in cur_s_no:
status = sql("select status from `tabSerial No` where name = %s", x)
status = status and status[0][0] or ''
if status == 'Installed':
msgprint("Item "+item_code+" with serial no. "+x+" already installed")
raise Exception, "Validation Error."
#get list of serial no from previous_doc
#----------------------------------------------
def get_prevdoc_serial_no(self, prevdoc_detail_docname, prevdoc_docname):
from stock.doctype.stock_ledger.stock_ledger import get_sr_no_list
res = sql("select serial_no from `tabDelivery Note Item` where name = '%s' and parent ='%s'" % (prevdoc_detail_docname, prevdoc_docname))
return get_sr_no_list(res[0][0])
#check if all serial nos from current record exist in resp delivery note
#---------------------------------------------------------------------------------
def is_serial_no_match(self, cur_s_no, prevdoc_s_no, prevdoc_docname):
for x in cur_s_no:
if not(x in prevdoc_s_no):
msgprint("Serial No. "+x+" not present in the Delivery Note "+prevdoc_docname, raise_exception = 1)
raise Exception, "Validation Error."
#validate serial number
#----------------------------------------
def validate_serial_no(self):
cur_s_no, prevdoc_s_no, sr_list = [], [], []
from stock.doctype.stock_ledger.stock_ledger import get_sr_no_list
for d in getlist(self.doclist, 'installed_item_details'):
self.is_serial_no_added(d.item_code, d.serial_no)
if d.serial_no:
sr_list = get_sr_no_list(d.serial_no, d.qty, d.item_code)
self.is_serial_no_exist(d.item_code, sr_list)
prevdoc_s_no = self.get_prevdoc_serial_no(d.prevdoc_detail_docname, d.prevdoc_docname)
if prevdoc_s_no:
self.is_serial_no_match(sr_list, prevdoc_s_no, d.prevdoc_docname)
self.is_serial_no_installed(sr_list, d.item_code)
return sr_list
#validate installation date
#-------------------------------
def validate_installation_date(self):
for d in getlist(self.doclist, 'installed_item_details'):
if d.prevdoc_docname:
d_date = sql("select posting_date from `tabDelivery Note` where name=%s", d.prevdoc_docname)
d_date = d_date and d_date[0][0] or ''
if d_date > getdate(self.doc.inst_date):
msgprint("Installation Date can not be before Delivery Date "+cstr(d_date)+" for item "+d.item_code)
raise Exception
def validate(self):
self.validate_fiscal_year()
self.validate_installation_date()
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)
self.validate_mandatory()
self.validate_reference_value()
def check_item_table(self):
if not(getlist(self.doclist, 'installed_item_details')):
msgprint("Please fetch items from Delivery Note selected")
raise Exception
def on_update(self):
set(self.doc, 'status', 'Draft')
def on_submit(self):
valid_lst = []
valid_lst = self.validate_serial_no()
get_obj("Sales Common").update_prevdoc_detail(1,self)
for x in valid_lst:
wp = sql("select warranty_period from `tabSerial No` where name = '%s'"% x)
wp = wp and wp[0][0] or 0
if wp:
sql("update `tabSerial No` set maintenance_status = 'Under Warranty' where name = '%s'" % x)
sql("update `tabSerial No` set status = 'Installed' where name = '%s'" % x)
set(self.doc, 'status', 'Submitted')
def on_cancel(self):
cur_s_no = []
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.update_prevdoc_detail(0,self)
for d in getlist(self.doclist, 'installed_item_details'):
if d.serial_no:
#get current list of serial no
cur_serial_no = d.serial_no.replace(' ', '')
cur_s_no = cur_serial_no.split(',')
for x in cur_s_no:
sql("update `tabSerial No` set status = 'Delivered' where name = '%s'" % x)
set(self.doc, 'status', 'Cancelled')

View File

@@ -0,0 +1,453 @@
# DocType, Installation Note
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:09',
'docstatus': 0,
'modified': '2012-03-27 18:48:02',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1306480044',
'autoname': u'IN/.####',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'is_submittable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'subject': u'At %(customer_name)s on %(inst_date)s',
'version': 98
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Installation Note',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'Installation Note',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1
},
# DocType, Installation Note
{
'doctype': 'DocType',
'name': u'Installation Note'
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'System Manager',
'submit': 1,
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'System Manager'
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 1,
'write': 1
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'submit': 1,
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales User'
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Manager'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'installation_note',
'fieldtype': u'Section Break',
'label': u'Installation Note',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break0',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'naming_series',
'fieldtype': u'Select',
'label': u'Series',
'no_copy': 1,
'oldfieldname': u'naming_series',
'oldfieldtype': u'Select',
'options': u'\nIN',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer',
'fieldtype': u'Link',
'label': u'Customer',
'oldfieldname': u'customer',
'oldfieldtype': u'Link',
'options': u'Customer',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_address',
'fieldtype': u'Link',
'label': u'Customer Address',
'options': u'Address',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_person',
'fieldtype': u'Link',
'label': u'Contact Person',
'options': u'Contact',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'customer_name',
'fieldtype': u'Data',
'label': u'Name',
'oldfieldname': u'customer_name',
'oldfieldtype': u'Data',
'permlevel': 1,
'reqd': 0,
'search_index': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'address_display',
'fieldtype': u'Small Text',
'label': u'Address',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_display',
'fieldtype': u'Small Text',
'label': u'Contact',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_mobile',
'fieldtype': u'Text',
'label': u'Mobile No',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_email',
'fieldtype': u'Text',
'label': u'Contact Email',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'territory',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Territory',
'options': u'Territory',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_group',
'fieldtype': u'Link',
'label': u'Customer Group',
'options': u'Customer Group',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'inst_date',
'fieldtype': u'Date',
'label': u'Installation Date',
'oldfieldname': u'inst_date',
'oldfieldtype': u'Date',
'permlevel': 0,
'reqd': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'inst_time',
'fieldtype': u'Time',
'label': u'Installation Time',
'oldfieldname': u'inst_time',
'oldfieldtype': u'Time',
'permlevel': 0
},
# DocField
{
'default': u'Draft',
'doctype': u'DocField',
'fieldname': u'status',
'fieldtype': u'Select',
'label': u'Status',
'no_copy': 1,
'oldfieldname': u'status',
'oldfieldtype': u'Select',
'options': u'Draft\nSubmitted\nCancelled',
'permlevel': 1,
'print_hide': 1,
'reqd': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'Select the relevant company name if you have multiple companies.',
'doctype': u'DocField',
'fieldname': u'company',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Company',
'oldfieldname': u'company',
'oldfieldtype': u'Select',
'options': u'link:Company',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 0,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'fiscal_year',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Fiscal Year',
'oldfieldname': u'fiscal_year',
'oldfieldtype': u'Select',
'options': u'link:Fiscal Year',
'permlevel': 0,
'print_hide': 1,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'amended_from',
'fieldtype': u'Data',
'label': u'Amended From',
'no_copy': 1,
'oldfieldname': u'amended_from',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'The date at which current entry is corrected in the system.',
'doctype': u'DocField',
'fieldname': u'amendment_date',
'fieldtype': u'Date',
'hidden': 1,
'label': u'Amendment Date',
'no_copy': 1,
'oldfieldname': u'amendment_date',
'oldfieldtype': u'Date',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'remarks',
'fieldtype': u'Small Text',
'label': u'Remarks',
'oldfieldname': u'remarks',
'oldfieldtype': u'Small Text',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'cancel_reason',
'fieldtype': u'Data',
'hidden': 1,
'label': u'Cancel Reason',
'no_copy': 1,
'oldfieldname': u'cancel_reason',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_details',
'fieldtype': u'Section Break',
'label': u'Item Details',
'oldfieldtype': u'Section Break',
'options': u'Simple',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'delivery_note_no',
'fieldtype': u'Link',
'label': u'Delivery Note No',
'no_copy': 1,
'oldfieldname': u'delivery_note_no',
'oldfieldtype': u'Link',
'options': u'Delivery Note',
'permlevel': 0,
'print_hide': 0,
'reqd': 1,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'get_items',
'fieldtype': u'Button',
'hidden': 0,
'label': u'Get Items',
'oldfieldtype': u'Button',
'options': u'pull_delivery_note_details',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'installed_item_details',
'fieldtype': u'Table',
'label': u'Installation Note Item',
'oldfieldname': u'installed_item_details',
'oldfieldtype': u'Table',
'options': u'Installation Note Item',
'permlevel': 0
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,153 @@
# DocType, Installation Note Item
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:10',
'docstatus': 0,
'modified': '2012-03-27 14:36:10',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'autoname': u'IID/.#####',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 25
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Installation Note Item',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# DocType, Installation Note Item
{
'doctype': 'DocType',
'name': u'Installation Note Item'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_code',
'fieldtype': u'Link',
'label': u'Item Code',
'oldfieldname': u'item_code',
'oldfieldtype': u'Link',
'options': u'Item',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Data',
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Data',
'permlevel': 1,
'width': u'300px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_date',
'fieldtype': u'Date',
'hidden': 0,
'label': u'Delivery Date',
'oldfieldname': u'prevdoc_date',
'oldfieldtype': u'Date',
'permlevel': 1,
'print_hide': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'serial_no',
'fieldtype': u'Small Text',
'label': u'Serial No',
'oldfieldname': u'serial_no',
'oldfieldtype': u'Small Text',
'permlevel': 0,
'width': u'180px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_detail_docname',
'fieldtype': u'Data',
'hidden': 1,
'label': u'Against Document Detail No',
'no_copy': 1,
'oldfieldname': u'prevdoc_detail_docname',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_docname',
'fieldtype': u'Data',
'hidden': 1,
'in_filter': 1,
'label': u'Against Document No',
'no_copy': 1,
'oldfieldname': u'prevdoc_docname',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'search_index': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_doctype',
'fieldtype': u'Data',
'hidden': 1,
'in_filter': 1,
'label': u'Document Type',
'no_copy': 1,
'oldfieldname': u'prevdoc_doctype',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'search_index': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'qty',
'fieldtype': u'Currency',
'label': u'Installed Qty',
'oldfieldname': u'qty',
'oldfieldtype': u'Currency',
'permlevel': 0,
'reqd': 1
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,143 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Module CRM
wn.require('erpnext/utilities/doctype/sms_control/sms_control.js');
wn.require('erpnext/support/doctype/communication/communication.js');
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(user =='Guest'){
hide_field(['status', 'naming_series', 'order_lost_reason',
'customer', 'rating', 'fax', 'website', 'territory',
'address_line1', 'address_line2', 'city', 'state',
'country', 'pincode', 'address', 'lead_owner', 'market_segment',
'industry', 'campaign_name', 'interested_in', 'company',
'fiscal_year', 'contact_by', 'contact_date', 'last_contact_date',
'contact_date_ref', 'to_discuss', 'more_info', 'follow_up',
'communication_history', 'cc_to', 'subject', 'message', 'lead_attachment_detail',
'Create Customer', 'Create Opportunity', 'transaction_date', 'type', 'source']);
doc.source = 'Website';
}
if(!doc.status) set_multiple(dt,dn,{status:'Open'});
if (!doc.date){
doc.date = date.obj_to_str(new Date());
}
// set naming series
if(user=='Guest') doc.naming_series = 'WebLead';
cur_frm.add_fetch('customer', 'customer_name', 'company_name');
cur_frm.cscript.make_communication_body();
}
cur_frm.cscript.refresh_custom_buttons = function() {
cur_frm.clear_custom_buttons();
if(!doc.__islocal && !in_list(['Converted', 'Lead Lost'], doc.status)) {
if (doc.source != 'Existing Customer') {
cur_frm.add_custom_button('Create Customer',
cur_frm.cscript['Create Customer']);
}
cur_frm.add_custom_button('Create Opportunity',
cur_frm.cscript['Create Opportunity']);
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
}
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
// custom buttons
//---------------
cur_frm.cscript.refresh_custom_buttons();
erpnext.hide_naming_series();
if (!doc.__islocal) cur_frm.cscript.render_communication_list(doc, cdt, cdn);
}
// Client Side Triggers
// ===========================================================
// ************ Status ******************
cur_frm.cscript.status = function(doc, cdt, cdn){
cur_frm.cscript.refresh(doc, cdt, cdn);
}
//Trigger in Item Table
//===================================
cur_frm.cscript.item_code=function(doc,cdt,cdn){
var d = locals[cdt][cdn];
if (d.item_code) { get_server_fields('get_item_detail',d.item_code,'lead_item_detail',doc,cdt,cdn,1);}
}
// Create New Customer
// ===============================================================
cur_frm.cscript['Create Customer'] = function(){
var doc = cur_frm.doc;
$c('runserverobj',args={ 'method':'check_status', 'docs':compress_doclist(make_doclist(doc.doctype, doc.name))},
function(r,rt){
if(r.message == 'Converted'){
msgprint("This lead is already converted to customer");
}
else{
n = createLocal("Customer");
$c('dt_map', args={
'docs':compress_doclist([locals["Customer"][n]]),
'from_doctype':'Lead',
'to_doctype':'Customer',
'from_docname':doc.name,
'from_to_list':"[['Lead', 'Customer']]"
},
function(r,rt) {
loaddoc("Customer", n);
}
);
}
}
);
}
// Create New Opportunity
// ===============================================================
cur_frm.cscript['Create Opportunity'] = function(){
var doc = cur_frm.doc;
$c('runserverobj',args={ 'method':'check_status', 'docs':compress_doclist(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 = createLocal("Opportunity");
$c('dt_map', args={
'docs':compress_doclist([locals["Opportunity"][n]]),
'from_doctype':'Lead',
'to_doctype':'Opportunity',
'from_docname':doc.name,
'from_to_list':"[['Lead', 'Opportunity']]"
}
, function(r,rt) {
loaddoc("Opportunity", n);
}
);
}
}
);
}
//get query select Territory
cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50';
}

View File

@@ -0,0 +1,147 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
class DocType:
def __init__(self, doc, doclist):
self.doc = doc
self.doclist = doclist
# Autoname
# ---------
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+'.#####')
#check status of lead
#------------------------
def check_status(self):
chk = sql("select status from `tabLead` where name=%s", self.doc.name)
chk = chk and chk[0][0] or ''
return cstr(chk)
# Get item detail (will be removed later)
#=======================================
def get_item_detail(self,item_code):
it=sql("select item_name,brand,item_group,description,stock_uom from `tabItem` where name='%s'"%item_code)
if it:
ret = {
'item_name' : it and it[0][0] or '',
'brand' : it and it[0][1] or '',
'item_group' : it and it[0][2] or '',
'description': it and it[0][3] or '',
'uom' : it and it[0][4] or ''
}
return ret
def validate(self):
import string
if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason:
msgprint("Please Enter Lost Reason under More Info section")
raise Exception
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
msgprint("Please specify campaign name")
raise Exception
if self.doc.email_id:
if not validate_email_add(self.doc.email_id):
msgprint('Please enter valid email id.')
raise Exception
def on_update(self):
if self.doc.contact_by:
self.add_calendar_event()
if not self.doc.naming_series:
if session['user'] == 'Guest':
import webnotes.model.doctype
docfield = webnotes.model.doctype.get('Lead')
series = [d.options for d in docfield if d.doctype == 'DocField' and d.fieldname == 'naming_series']
if series:
sr = series[0].split("\n")
set(self.doc, 'naming_series', sr[0])
else:
msgprint("Please specify naming series")
raise Exception
# Add to Calendar
# ===========================================================================
def add_calendar_event(self):
# delete any earlier event by this lead
sql("delete from tabEvent where ref_type='Lead' and ref_name=%s", self.doc.name)
in_calendar_of = self.doc.lead_owner
# get profile (id) if exists for contact_by
email_id = webnotes.conn.get_value('Sales Person', self.doc.contact_by, 'email_id')
if webnotes.conn.exists('Profile', email_id):
in_calendar_of = email_id
ev = Document('Event')
ev.owner = in_calendar_of
ev.description = 'Contact ' + cstr(self.doc.lead_name) + '.By : ' + cstr(self.doc.contact_by) + '.To Discuss : ' + cstr(self.doc.remark)
ev.event_date = self.doc.contact_date
ev.event_hour = '10:00'
ev.event_type = 'Private'
ev.ref_type = 'Lead'
ev.ref_name = self.doc.name
ev.save(1)
def add_in_follow_up(self,message,type):
import datetime
child = addchild( self.doc, 'follow_up', 'Communication Log', 1, self.doclist)
child.date = datetime.datetime.now().date().strftime('%Y-%m-%d')
child.notes = message
child.follow_up_type = type
child.save()
#-------------------SMS----------------------------------------------
def send_sms(self):
if not self.doc.sms_message or not self.doc.mobile_no:
msgprint("Please enter mobile number in Basic Info Section and message in SMS Section ")
raise Exception
else:
receiver_list = []
if self.doc.mobile_no:
receiver_list.append(self.doc.mobile_no)
for d in getlist(self.doclist,'lead_sms_detail'):
if d.other_mobile_no:
receiver_list.append(d.other_mobile_no)
if receiver_list:
msgprint(get_obj('SMS Control', 'SMS Control').send_sms(receiver_list, self.doc.sms_message))
# self.add_in_follow_up(self.doc.sms_message,'SMS')

View File

@@ -0,0 +1,702 @@
# DocType, Lead
[
# These values are common in all dictionaries
{
u'creation': '2012-06-05 20:03:20',
u'docstatus': 0,
u'modified': '2012-08-06 14:49:48',
u'modified_by': u'Administrator',
u'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1332222225',
'allow_trash': 1,
'colour': u'White:FFF',
'default_print_format': u'Standard',
u'doctype': u'DocType',
'document_type': u'Master',
'module': u'Selling',
u'name': u'__common__',
'search_fields': u'lead_name,lead_owner,status',
'section_style': u'Tabbed',
'server_code_error': u' ',
'show_in_menu': 0,
'subject': u'%(lead_name)s from %(company_name)s | To Discuss: %(to_discuss)s',
'tag_fields': u'status,source',
'version': 1
},
# These values are common for all DocField
{
u'doctype': u'DocField',
u'name': u'__common__',
'parent': u'Lead',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
u'doctype': u'DocPerm',
u'name': u'__common__',
'parent': u'Lead',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1
},
# DocType, Lead
{
u'doctype': u'DocType',
u'name': u'Lead'
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'basic_info',
'fieldtype': u'Section Break',
'label': u'Basic Info',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break0',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'description': u'To manage multiple series please go to Setup > Manage Series',
u'doctype': u'DocField',
'fieldname': u'naming_series',
'fieldtype': u'Select',
'label': u'Naming Series',
'no_copy': 1,
'oldfieldname': u'naming_series',
'oldfieldtype': u'Select',
'options': u'LEAD\nLEAD/10-11/\nLEAD/MUMBAI/',
'permlevel': 0,
'reqd': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'lead_name',
'fieldtype': u'Data',
'in_filter': 1,
'label': u'Contact Name',
'oldfieldname': u'lead_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 1,
'search_index': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'Name of organization from where lead has come',
u'doctype': u'DocField',
'fieldname': u'company_name',
'fieldtype': u'Data',
'in_filter': 1,
'label': u'Company Name',
'oldfieldname': u'company_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 0,
'search_index': 0,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'description': u'Source of the lead. If via a campaign, select "Campaign"',
u'doctype': u'DocField',
'fieldname': u'source',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Source',
'no_copy': 1,
'oldfieldname': u'source',
'oldfieldtype': u'Select',
'options': u'\nAdvertisement\nBlog\nCampaign\nCall\nCustomer\nExhibition\nSupplier\nWebsite',
'permlevel': 0,
'reqd': 1,
'search_index': 0,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.source == 'Existing Customer'",
'description': u'Source of th',
u'doctype': u'DocField',
'fieldname': u'customer',
'fieldtype': u'Link',
'hidden': 0,
'label': u'From Customer',
'oldfieldname': u'customer',
'oldfieldtype': u'Link',
'options': u'Customer',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.source == 'Campaign'",
'description': u'Enter campaign name if the source of lead is campaign.',
u'doctype': u'DocField',
'fieldname': u'campaign_name',
'fieldtype': u'Link',
'hidden': 0,
'label': u'Campaign Name',
'oldfieldname': u'campaign_name',
'oldfieldtype': u'Link',
'options': u'Campaign',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'default': u'Open',
u'doctype': u'DocField',
'fieldname': u'status',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Status',
'no_copy': 1,
'oldfieldname': u'status',
'oldfieldtype': u'Select',
'options': u'\nOpen\nAttempted to Contact\nContact in Future\nContacted\nInterested\nNot interested\nLead Lost\nConverted',
'permlevel': 0,
'reqd': 1,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'type',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Lead Type',
'oldfieldname': u'type',
'oldfieldtype': u'Select',
'options': u'\nClient\nChannel Partner\nConsultant',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'remark',
'fieldtype': u'Small Text',
'label': u'Remark',
'oldfieldname': u'remark',
'oldfieldtype': u'Text',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'communication_history',
'fieldtype': u'Section Break',
'label': u'Communication History',
'permlevel': 0
},
# DocField
{
'allow_on_submit': 0,
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'communication_html',
'fieldtype': u'HTML',
'label': u'Communication HTML',
'oldfieldname': u'follow_up',
'oldfieldtype': u'Table',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'contact_info',
'fieldtype': u'Section Break',
'label': u'Contact Info',
'oldfieldtype': u'Column Break',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'phone',
'fieldtype': u'Data',
'label': u'Phone',
'oldfieldname': u'contact_no',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'mobile_no',
'fieldtype': u'Data',
'label': u'Mobile No.',
'oldfieldname': u'mobile_no',
'oldfieldtype': u'Data',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'email_id',
'fieldtype': u'Data',
'label': u'Email Id',
'oldfieldname': u'email_id',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'fax',
'fieldtype': u'Data',
'label': u'Fax',
'oldfieldname': u'fax',
'oldfieldtype': u'Data',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'website',
'fieldtype': u'Data',
'label': u'Website',
'oldfieldname': u'website',
'oldfieldtype': u'Data',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'<a href="javascript:cur_frm.cscript.TerritoryHelp();">To manage Territory, click here</a>',
u'doctype': u'DocField',
'fieldname': u'territory',
'fieldtype': u'Link',
'label': u'Territory',
'oldfieldname': u'territory',
'oldfieldtype': u'Link',
'options': u'Territory',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break2',
'fieldtype': u'Column Break',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'address_line1',
'fieldtype': u'Data',
'label': u'Address Line 1',
'oldfieldname': u'address_line1',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 1,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'address_line2',
'fieldtype': u'Data',
'label': u'Address Line 2',
'oldfieldname': u'address_line2',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'city',
'fieldtype': u'Data',
'label': u'City',
'oldfieldname': u'city',
'oldfieldtype': u'Select',
'permlevel': 0,
'print_hide': 1,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'country',
'fieldtype': u'Select',
'label': u'Country',
'oldfieldname': u'country',
'oldfieldtype': u'Select',
'options': u'link:Country',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'state',
'fieldtype': u'Data',
'label': u'State',
'oldfieldname': u'state',
'oldfieldtype': u'Select',
'options': u'Suggest',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'pincode',
'fieldtype': u'Data',
'label': u'Pin Code',
'oldfieldname': u'pincode',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'more_info',
'fieldtype': u'Section Break',
'label': u'More Info',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'default': u'__user',
u'doctype': u'DocField',
'fieldname': u'lead_owner',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Lead Owner',
'oldfieldname': u'lead_owner',
'oldfieldtype': u'Link',
'options': u'Profile',
'permlevel': 0,
'search_index': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'market_segment',
'fieldtype': u'Select',
'hidden': 0,
'in_filter': 1,
'label': u'Market Segment',
'oldfieldname': u'market_segment',
'oldfieldtype': u'Select',
'options': u'\nLower Income\nMiddle Income\nUpper Income',
'permlevel': 0,
'reqd': 0,
'search_index': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'industry',
'fieldtype': u'Link',
'label': u'Industry',
'oldfieldname': u'industry',
'oldfieldtype': u'Link',
'options': u'Industry Type',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'request_type',
'fieldtype': u'Select',
'label': u'Request Type',
'oldfieldname': u'request_type',
'oldfieldtype': u'Select',
'options': u'\nProduct Enquiry\nRequest for Information\nSuggestions\nOther',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'fiscal_year',
'fieldtype': u'Select',
'hidden': 1,
'in_filter': 1,
'label': u'Fiscal Year',
'oldfieldname': u'fiscal_year',
'oldfieldtype': u'Select',
'options': u'link:Fiscal Year',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'column_break3',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'allow_on_submit': 0,
'depends_on': u"eval:doc.status == 'Lead Lost'",
u'doctype': u'DocField',
'fieldname': u'order_lost_reason',
'fieldtype': u'Link',
'hidden': 0,
'label': u'Lost Reason',
'oldfieldname': u'order_lost_reason',
'oldfieldtype': u'Link',
'options': u'Quotation Lost Reason',
'permlevel': 0
},
# DocField
{
'allow_on_submit': 0,
'colour': u'White:FFF',
'description': u'Your sales person who will contact the lead in future',
u'doctype': u'DocField',
'fieldname': u'contact_by',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Next Contact By',
'oldfieldname': u'contact_by',
'oldfieldtype': u'Link',
'options': u'Profile',
'permlevel': 0,
'print_hide': 0,
'reqd': 0,
'width': u'100px'
},
# DocField
{
'allow_on_submit': 0,
'colour': u'White:FFF',
'description': u'Your sales person will get a reminder on this date to contact the lead',
u'doctype': u'DocField',
'fieldname': u'contact_date',
'fieldtype': u'Date',
'in_filter': 1,
'label': u'Next Contact Date',
'no_copy': 1,
'oldfieldname': u'contact_date',
'oldfieldtype': u'Date',
'permlevel': 0,
'reqd': 0,
'width': u'100px'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:!doc.__islocal',
'description': u'Date on which the lead was last contacted',
u'doctype': u'DocField',
'fieldname': u'last_contact_date',
'fieldtype': u'Date',
'label': u'Last Contact Date',
'no_copy': 1,
'oldfieldname': u'last_contact_date',
'oldfieldtype': u'Date',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
u'doctype': u'DocField',
'fieldname': u'company',
'fieldtype': u'Link',
'label': u'Company',
'oldfieldname': u'company',
'oldfieldtype': u'Link',
'options': u'Company',
'permlevel': 0,
'reqd': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'trash_reason',
'fieldtype': u'Small Text',
'label': u'Trash Reason',
'no_copy': 1,
'oldfieldname': u'trash_reason',
'oldfieldtype': u'Small Text',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'unsubscribed',
'fieldtype': u'Check',
'label': u'Unsubscribed',
'permlevel': 0
},
# DocField
{
u'doctype': u'DocField',
'fieldname': u'blog_subscriber',
'fieldtype': u'Check',
'label': u'Blog Subscriber',
'permlevel': 0
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
u'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales User',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
u'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Manager',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 0,
'cancel': 1,
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'submit': 0,
'write': 1
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 0,
'write': 1
},
# DocPerm
{
u'doctype': u'DocPerm',
'permlevel': 1,
'role': u'All'
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'System Manager',
'submit': 0,
'write': 1
},
# DocPerm
{
'create': 1,
u'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Guest',
'write': 1
}
]

View File

@@ -0,0 +1,34 @@
wn.doclistviews['Lead'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
'tabLead.lead_name',
'tabLead.status',
'tabLead.source'
]);
this.stats = this.stats.concat(['status', 'source', 'rating', 'company']);
},
prepare_data: function(data) {
this._super(data);
if(data.status=='Interested') {
data.label_type = 'success'
}
else if(['Open', 'Attempted to Contact', 'Contacted', 'Contact in Future'].indexOf(data.status)!=-1) {
data.label_type = 'info'
}
data.status_html = repl('<span class="label label-%(label_type)s">%(status)s</span>', data);
data.lead_name = repl("<a href=\"#!Form/Lead/%(name)s\">%(lead_name)s</a>",
data);
data.lead_status = (data.rating ? ('['+data.rating+'] ') : '') + '['+data.source+']';
},
columns: [
{width: '3%', content: 'check'},
{width: '5%', content:'avatar'},
{width: '30%', content:'lead_name'},
{width: '12%', content:'status_html'},
{width: '38%', content:'lead_status+tags', css: {color:'#222'}},
{width: '12%', content:'modified', css: {'text-align': 'right', 'color':'#777'}}
]
})

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,215 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
wn.require('erpnext/utilities/doctype/sms_control/sms_control.js');
wn.require('erpnext/support/doctype/communication/communication.js');
cur_frm.cscript.refresh = function(doc, cdt, cdn){
erpnext.hide_naming_series();
cur_frm.clear_custom_buttons();
if(doc.docstatus == 1) {
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);
}
if(!doc.__islocal) cur_frm.cscript.render_communication_list(doc, cdt, cdn);
}
// ONLOAD
// ===============================================================
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(!doc.enquiry_from) hide_field(['customer', 'customer_address', 'contact_person', 'customer_name','lead', 'lead_name', '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') {
hide_field(['lead', 'lead_name']);
}
else if (doc.enquiry_from == 'Lead') {
hide_field(['customer', 'customer_address', 'contact_person', 'customer_name', 'contact_display', 'customer_group']);
}
}
// setup fetch
cur_frm.cscript.set_fetch();
cur_frm.cscript.make_communication_body();
}
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
if(doc.enquiry_from == 'Lead' && doc.lead) {
cur_frm.cscript.lead(doc,cdt,cdn);
}
}
// fetch
// ===============================================================
cur_frm.cscript.set_fetch = function() {
// item
cur_frm.add_fetch('item_code', 'item_name', 'item_name');
cur_frm.add_fetch('item_code', 'stock_uom', 'uom');
cur_frm.add_fetch('item_code', 'description', 'description');
cur_frm.add_fetch('item_code', 'item_group', 'item_group');
cur_frm.add_fetch('item_code', 'brand', 'brand');
// customer
}
// hide - unhide fields on basis of enquiry_from lead or customer
cur_frm.cscript.enquiry_from = function(doc,cdt,cdn){
cur_frm.cscript.lead_cust_show(doc,cdt,cdn);
}
// hide - unhide fields based on lead or customer
cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
if(doc.enquiry_from == 'Lead'){
unhide_field(['lead']);
hide_field(['lead_name','customer','customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
doc.lead = doc.lead_name = doc.customer = doc.customer_address = doc.contact_person = doc.address_display = doc.contact_display = doc.contact_mobile = doc.contact_email = doc.territory = doc.customer_group = "";
}
else if(doc.enquiry_from == 'Customer'){
unhide_field(['customer']);
hide_field(['lead','lead_name','address_display','contact_display','contact_mobile','contact_email','territory']);
doc.lead = doc.lead_name = doc.customer = doc.customer_address = doc.contact_person = doc.address_display = doc.contact_display = doc.contact_mobile = doc.contact_email = doc.territory = doc.customer_group = "";
}
}
// customer
cur_frm.cscript.customer = function(doc,dt,dn) {
if(doc.customer) get_server_fields('get_default_customer_address', JSON.stringify({customer: doc.customer}),'', doc, dt, dn, 1);
if(doc.customer) unhide_field(['customer_name','customer_address','contact_person','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
}
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) 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.fields_dict.customer_address.on_new = function(dn) {
locals['Address'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Address'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict.contact_person.on_new = function(dn) {
locals['Contact'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Contact'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,address_line1,city FROM tabAddress WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,CONCAT(first_name," ",ifnull(last_name,"")) As FullName,department,designation FROM tabContact WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
// lead
cur_frm.fields_dict['lead'].get_query = function(doc,cdt,cdn){
return 'SELECT `tabLead`.name, `tabLead`.lead_name FROM `tabLead` WHERE `tabLead`.%(key)s LIKE "%s" ORDER BY `tabLead`.`name` ASC LIMIT 50';
}
cur_frm.cscript.lead = function(doc, cdt, cdn) {
if(doc.lead) get_server_fields('get_lead_details', doc.lead,'', doc, cdt, cdn, 1);
if(doc.lead) unhide_field(['lead_name','address_display','contact_mobile','contact_email','territory']);
}
//item getquery
//=======================================
cur_frm.fields_dict['enquiry_details'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {
if (doc.enquiry_type == 'Maintenance')
return 'SELECT tabItem.name,tabItem.item_name,tabItem.description FROM tabItem WHERE tabItem.is_service_item="Yes" AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") AND tabItem.%(key)s LIKE "%s" LIMIT 50';
else
return 'SELECT tabItem.name,tabItem.item_name,tabItem.description FROM tabItem WHERE tabItem.is_sales_item="Yes" AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") AND tabItem.%(key)s LIKE "%s" LIMIT 50';
}
// Create New Quotation
cur_frm.cscript['Create Quotation'] = function(){
n = createLocal("Quotation");
$c('dt_map', args={
'docs':compress_doclist([locals["Quotation"][n]]),
'from_doctype':'Opportunity',
'to_doctype':'Quotation',
'from_docname':cur_frm.docname,
'from_to_list':"[['Opportunity', 'Quotation'],['Opportunity Item','Quotation Item']]"
}
, function(r,rt) {
loaddoc("Quotation", n);
}
);
}
// declare enquiry lost
//-------------------------
cur_frm.cscript['Declare Opportunity Lost'] = function(){
var e_lost_dialog;
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();
}
}
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");
}
}
}
if(!e_lost_dialog){
set_e_lost_dialog();
}
e_lost_dialog.show();
}
//get query select Territory
cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50';}

View File

@@ -0,0 +1,229 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
class DocType(TransactionBase):
def __init__(self,doc,doclist=[]):
self.doc = doc
self.doclist = doclist
self.fname = 'enq_details'
self.tname = 'Opportunity Item'
# Autoname
# ====================================================================================================================
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+'.####')
#--------Get customer address-------
# ====================================================================================================================
def get_cust_address(self,name):
details = sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
if details:
ret = {
'customer_name': details and details[0]['customer_name'] or '',
'address' : details and details[0]['address'] or '',
'territory' : details and details[0]['territory'] or '',
'customer_group' : details and details[0]['customer_group'] or ''
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
ret['email_id'] = contact_det and contact_det[0]['email_id'] or ''
return ret
else:
msgprint("Customer : %s does not exist in system." % (name))
raise Exception
# ====================================================================================================================
def get_contact_details(self, arg):
arg = eval(arg)
contact = sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
ret = {
'contact_no' : contact and contact[0]['contact_no'] or '',
'email_id' : contact and contact[0]['email_id'] or ''
}
return ret
# ====================================================================================================================
def on_update(self):
# Add to calendar
#if self.doc.contact_date and self.doc.last_contact_date != self.doc.contact_date:
if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
if self.doc.contact_by:
self.add_calendar_event()
set(self.doc, 'contact_date_ref',self.doc.contact_date)
set(self.doc, 'status', 'Draft')
# Add to Calendar
# ====================================================================================================================
def add_calendar_event(self):
desc=''
user_lst =[]
if self.doc.customer:
if self.doc.contact_person:
desc = 'Contact '+cstr(self.doc.contact_person)
else:
desc = 'Contact customer '+cstr(self.doc.customer)
elif self.doc.lead:
if self.doc.lead_name:
desc = 'Contact '+cstr(self.doc.lead_name)
else:
desc = 'Contact lead '+cstr(self.doc.lead)
desc = desc+ '. By : ' + cstr(self.doc.contact_by)
if self.doc.to_discuss:
desc = desc+' To Discuss : ' + cstr(self.doc.to_discuss)
ev = Document('Event')
ev.description = desc
ev.event_date = self.doc.contact_date
ev.event_hour = '10:00'
ev.event_type = 'Private'
ev.ref_type = 'Opportunity'
ev.ref_name = self.doc.name
ev.save(1)
user_lst.append(self.doc.owner)
chk = sql("select t1.name from `tabProfile` t1, `tabSales Person` t2 where t2.email_id = t1.name and t2.name=%s",self.doc.contact_by)
if chk:
user_lst.append(chk[0][0])
for d in user_lst:
ch = addchild(ev, 'event_individuals', 'Event User', 0)
ch.person = d
ch.save(1)
#--------------Validation For Last Contact Date-----------------
# ====================================================================================================================
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
# check if item present in item table
# ====================================================================================================================
def validate_item_details(self):
if not getlist(self.doclist, 'enquiry_details'):
msgprint("Please select items for which enquiry needs to be made")
raise Exception
#check if enquiry date in the range of fiscal year selected
#=====================================================
def validate_fiscal_year(self):
fy=sql("select year_start_date from `tabFiscal Year` where name='%s'"%self.doc.fiscal_year)
ysd=fy and fy[0][0] or ""
yed=add_days(str(ysd),365)
if str(self.doc.transaction_date) < str(ysd) or str(self.doc.transaction_date) > str(yed):
msgprint("Opportunity Date is not within the Fiscal Year selected")
raise Exception
def validate_lead_cust(self):
if self.doc.enquiry_from == 'Lead' and not self.doc.lead:
msgprint("Lead Id is mandatory if 'Opportunity From' is selected as Lead", raise_exception=1)
elif self.doc.enquiry_from == 'Customer' and not self.doc.customer:
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
def validate(self):
self.validate_fiscal_year()
self.set_last_contact_date()
self.validate_item_details()
self.validate_lead_cust()
# On Submit Functions
# ====================================================================================================================
def on_submit(self):
set(self.doc, 'status', 'Submitted')
# ====================================================================================================================
def on_cancel(self):
chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
if chk:
msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.")
raise Exception
else:
set(self.doc, 'status', 'Cancelled')
# declare as enquiry lost
#---------------------------
def declare_enquiry_lost(self,arg):
chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
if chk:
msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.")
raise Exception
else:
set(self.doc, 'status', 'Opportunity Lost')
set(self.doc, 'order_lost_reason', arg)
return 'true'
#---------------------- Add details in follow up table----------------
# ====================================================================================================================
def add_in_follow_up(self,message,type):
import datetime
child = addchild( self.doc, 'follow_up', 'Communication Log', 1, self.doclist)
child.date = datetime.datetime.now().date().strftime('%Y-%m-%d')
child.notes = message
child.follow_up_type = type
child.save()
#-------------------SMS----------------------------------------------
# ====================================================================================================================
def send_sms(self):
if not self.doc.sms_message:
msgprint("Please enter message in SMS Section ")
raise Exception
elif not getlist(self.doclist, 'enquiry_sms_detail'):
msgprint("Please mention mobile no. to which sms needs to be sent")
raise Exception
else:
receiver_list = []
for d in getlist(self.doclist,'enquiry_sms_detail'):
if d.other_mobile_no:
receiver_list.append(d.other_mobile_no)
if receiver_list:
msgprint(get_obj('SMS Control', 'SMS Control').send_sms(receiver_list, self.doc.sms_message))
self.add_in_follow_up(self.doc.sms_message,'SMS')

View File

@@ -0,0 +1,640 @@
# DocType, Opportunity
[
# These values are common in all dictionaries
{
'creation': '2012-05-15 12:14:52',
'docstatus': 0,
'modified': '2012-05-31 12:42:38',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1324284087',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'document_type': u'Transaction',
'is_submittable': 1,
'module': u'Selling',
'name': '__common__',
'search_fields': u'status,transaction_date,customer,lead,enquiry_type,territory,company',
'section_style': u'Tabbed',
'server_code_error': u' ',
'show_in_menu': 0,
'subject': u'To %(customer_name)s%(lead_name)s on %(transaction_date)s',
'version': 1
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Opportunity',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'Opportunity',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1
},
# DocType, Opportunity
{
'doctype': 'DocType',
'name': u'Opportunity'
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Manager',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'System Manager',
'submit': 1,
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'System Manager'
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 1,
'write': 1
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales User',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'submit': 1,
'write': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'Enter customer enquiry for which you might raise a quotation in future',
'doctype': u'DocField',
'fieldname': u'basic_info',
'fieldtype': u'Section Break',
'label': u'Basic Info',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'To manage multiple series please go to Setup > Manage Series',
'doctype': u'DocField',
'fieldname': u'naming_series',
'fieldtype': u'Select',
'label': u'Naming Series',
'no_copy': 1,
'oldfieldname': u'naming_series',
'oldfieldtype': u'Select',
'options': u'ENQUIRY\nENQ',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'enquiry_from',
'fieldtype': u'Select',
'label': u'Opportunity From',
'oldfieldname': u'enquiry_from',
'oldfieldtype': u'Select',
'options': u'\nLead\nCustomer',
'permlevel': 0,
'print_hide': 1,
'report_hide': 0,
'reqd': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'customer',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Customer',
'oldfieldname': u'customer',
'oldfieldtype': u'Link',
'options': u'Customer',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'search_index': 0,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'lead',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Lead',
'oldfieldname': u'lead',
'oldfieldtype': u'Link',
'options': u'Lead',
'permlevel': 0,
'print_hide': 1,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break0',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'default': u'Draft',
'doctype': u'DocField',
'fieldname': u'status',
'fieldtype': u'Select',
'label': u'Status',
'no_copy': 1,
'oldfieldname': u'status',
'oldfieldtype': u'Select',
'options': u'\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled',
'permlevel': 1,
'reqd': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'enquiry_type',
'fieldtype': u'Select',
'label': u'Opportunity Type',
'oldfieldname': u'enquiry_type',
'oldfieldtype': u'Select',
'options': u'\nSales\nMaintenance',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'items',
'fieldtype': u'Section Break',
'label': u'Items',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u"Items which do not exist in Item master can also be entered on customer's request",
'doctype': u'DocField',
'fieldname': u'enquiry_details',
'fieldtype': u'Table',
'label': u'Opportunity Items',
'oldfieldname': u'enquiry_details',
'oldfieldtype': u'Table',
'options': u'Opportunity Item',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'Keep a track of communication related to this enquiry which will help for future reference.',
'doctype': u'DocField',
'fieldname': u'communication_history',
'fieldtype': u'Section Break',
'label': u'Communication History',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'allow_on_submit': 1,
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'communication_html',
'fieldtype': u'HTML',
'label': u'Communication HTML',
'oldfieldname': u'follow_up',
'oldfieldtype': u'Table',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_info',
'fieldtype': u'Section Break',
'label': u'Contact Info',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_person',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Contact Person',
'options': u'Contact',
'permlevel': 0,
'print_hide': 1,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_address',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Customer Address',
'options': u'Address',
'permlevel': 0,
'print_hide': 1,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_name',
'fieldtype': u'Data',
'label': u'Customer Name',
'permlevel': 1,
'print_hide': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'address_display',
'fieldtype': u'Small Text',
'hidden': 0,
'label': u'Address',
'oldfieldname': u'address',
'oldfieldtype': u'Small Text',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break3',
'fieldtype': u'Column Break',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_display',
'fieldtype': u'Small Text',
'label': u'Contact',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_email',
'fieldtype': u'Text',
'label': u'Contact Email',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_mobile',
'fieldtype': u'Text',
'label': u'Contact Mobile No',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'lead_name',
'fieldtype': u'Data',
'hidden': 0,
'label': u'Name',
'oldfieldname': u'lead_name',
'oldfieldtype': u'Data',
'permlevel': 1
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:doc.enquiry_from=="Customer"',
'description': u'<a href="javascript:cur_frm.cscript.CGHelp();">To Manage Customer Groups, click here</a>',
'doctype': u'DocField',
'fieldname': u'customer_group',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Customer Group',
'oldfieldname': u'customer_group',
'oldfieldtype': u'Link',
'options': u'Customer Group',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'description': u'<a href="javascript:cur_frm.cscript.TerritoryHelp();">To Manage Territory, click here</a>',
'doctype': u'DocField',
'fieldname': u'territory',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Territory',
'options': u'Territory',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'search_index': 1,
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'description': u'Filing in Additional Information about the Opportunity will help you analyze your data better.',
'doctype': u'DocField',
'fieldname': u'more_info',
'fieldtype': u'Section Break',
'label': u'More Info',
'oldfieldtype': u'Section Break',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'default': u'Today',
'description': u'The date at which current entry is made in system.',
'doctype': u'DocField',
'fieldname': u'transaction_date',
'fieldtype': u'Date',
'label': u'Opportunity Date',
'oldfieldname': u'transaction_date',
'oldfieldtype': u'Date',
'permlevel': 0,
'reqd': 1,
'width': u'50px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'fiscal_year',
'fieldtype': u'Select',
'in_filter': 1,
'label': u'Fiscal Year',
'oldfieldname': u'fiscal_year',
'oldfieldtype': u'Select',
'options': u'link:Fiscal Year',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'source',
'fieldtype': u'Select',
'label': u'Source',
'oldfieldname': u'source',
'oldfieldtype': u'Select',
'options': u"\nExisting Customer\nReference\nAdvertisement\nCold Calling\nExhibition\nSupplier Reference\nMass Mailing\nCustomer's Vendor\nCampaign\nWalk In",
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'description': u'Enter name of campaign if source of enquiry is campaign',
'doctype': u'DocField',
'fieldname': u'campaign',
'fieldtype': u'Link',
'label': u'Campaign',
'oldfieldname': u'campaign',
'oldfieldtype': u'Link',
'options': u'Campaign',
'permlevel': 0
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u'eval:!doc.__islocal',
'doctype': u'DocField',
'fieldname': u'order_lost_reason',
'fieldtype': u'Small Text',
'label': u'Quotation Lost Reason',
'no_copy': 1,
'oldfieldname': u'order_lost_reason',
'oldfieldtype': u'Small Text',
'permlevel': 1,
'report_hide': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'company',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Company',
'oldfieldname': u'company',
'oldfieldtype': u'Link',
'options': u'Company',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break2',
'fieldtype': u'Column Break',
'oldfieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'colour': u'White:FFF',
'description': u'Your sales person who will contact the customer in future',
'doctype': u'DocField',
'fieldname': u'contact_by',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Next Contact By',
'oldfieldname': u'contact_by',
'oldfieldtype': u'Link',
'options': u'Profile',
'permlevel': 0,
'width': u'75px'
},
# DocField
{
'colour': u'White:FFF',
'description': u'Your sales person will get a reminder on this date to contact the customer',
'doctype': u'DocField',
'fieldname': u'contact_date',
'fieldtype': u'Date',
'label': u'Next Contact Date',
'oldfieldname': u'contact_date',
'oldfieldtype': u'Date',
'permlevel': 0
},
# DocField
{
'allow_on_submit': 0,
'colour': u'White:FFF',
'depends_on': u'eval:!doc.__islocal',
'description': u'Date on which the lead was last contacted',
'doctype': u'DocField',
'fieldname': u'last_contact_date',
'fieldtype': u'Date',
'label': u'Last Contact Date',
'no_copy': 1,
'oldfieldname': u'last_contact_date',
'oldfieldtype': u'Date',
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'to_discuss',
'fieldtype': u'Small Text',
'label': u'To Discuss',
'no_copy': 1,
'oldfieldname': u'to_discuss',
'oldfieldtype': u'Small Text',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'amended_from',
'fieldtype': u'Data',
'label': u'Amended From',
'no_copy': 1,
'oldfieldname': u'amended_from',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'amendment_date',
'fieldtype': u'Date',
'label': u'Amendment Date',
'no_copy': 1,
'oldfieldname': u'amendment_date',
'oldfieldtype': u'Date',
'permlevel': 1,
'print_hide': 1,
'width': u'150px'
}
]

View File

@@ -0,0 +1,41 @@
wn.doclistviews['Opportunity'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
'tabOpportunity.enquiry_from',
'tabOpportunity.lead_name',
'tabOpportunity.customer_name',
'tabOpportunity.status',
'tabOpportunity.transaction_date',
]);
this.stats = this.stats.concat(['status', 'source', 'enquiry_from', 'company']);
},
prepare_data: function(data) {
this._super(data);
if(['Order Confirmed', 'Quotation Sent']
.indexOf(data.status)!=-1) {
data.label_type = 'success';
} else if(data.status == 'Draft') {
data.label_type = 'info';
} else if(data.status == 'Submit') {
data.label_type = 'important';
}
data.status_html = repl('<span class="label label-%(label_type)s">%(status)s</span>', data);
if(data.enquiry_from == 'Lead') {
data.enquiry_name = repl('[%(enquiry_from)s] %(lead_name)s', data);
} else {
data.enquiry_name = repl('[%(enquiry_from)s] %(customer_name)s', data);
}
},
columns: [
{width: '3%', content: 'check'},
{width: '15%', content:'name'},
{width: '18%', content:'status_html'},
{width: '52%', content:'enquiry_name+tags', css: {color:'#222'}},
{width: '12%', content:'transaction_date',
css: {'text-align': 'right', 'color':'#777'},
title: "Opportunity Date", type: "date"}
]
})

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,140 @@
# DocType, Opportunity Item
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:08',
'docstatus': 0,
'modified': '2012-03-27 14:36:08',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'colour': u'White:FFF',
'doctype': 'DocType',
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 59
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Opportunity Item',
'parentfield': u'fields',
'parenttype': u'DocType',
'permlevel': 0
},
# DocType, Opportunity Item
{
'doctype': 'DocType',
'name': u'Opportunity Item'
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'item_code',
'fieldtype': u'Link',
'label': u'Item Code',
'oldfieldname': u'item_code',
'oldfieldtype': u'Link',
'options': u'Item',
'reqd': 0,
'trigger': u'Client'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_name',
'fieldtype': u'Data',
'label': u'Item Name',
'oldfieldname': u'item_name',
'oldfieldtype': u'Data',
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Text',
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Text',
'reqd': 1,
'width': u'300px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_group',
'fieldtype': u'Link',
'hidden': 1,
'label': u'Item Group',
'oldfieldname': u'item_group',
'oldfieldtype': u'Link',
'options': u'Item Group',
'print_hide': 1,
'search_index': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'brand',
'fieldtype': u'Link',
'hidden': 1,
'label': u'Brand',
'oldfieldname': u'brand',
'oldfieldtype': u'Link',
'options': u'Brand',
'print_hide': 1,
'search_index': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'basic_rate',
'fieldtype': u'Currency',
'hidden': 1,
'label': u'Basic Rate',
'oldfieldname': u'basic_rate',
'oldfieldtype': u'Currency',
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'qty',
'fieldtype': u'Currency',
'label': u'Qty',
'oldfieldname': u'qty',
'oldfieldtype': u'Currency'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'uom',
'fieldtype': u'Link',
'label': u'UOM',
'oldfieldname': u'uom',
'oldfieldtype': u'Link',
'options': u'UOM',
'search_index': 0
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,246 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
class DocType:
def __init__(self,doc,doclist = []):
self.doc ,self.doclist = doc, doclist
#============================get monthly sales====================================================
def get_monthwise_amount(self,lst):
lst = lst.split(',')
if not lst[1]:
ret = convert_to_lists(sql("SELECT SUM(grand_total) AMOUNT,CASE MONTH(due_date) WHEN 1 THEN 'JAN' WHEN 2 THEN 'FEB' WHEN 3 THEN 'MAR' WHEN 4 THEN 'APR' WHEN 5 THEN 'MAY' WHEN 6 THEN 'JUN' WHEN 7 THEN 'JUL' WHEN 8 THEN 'AUG' WHEN 9 THEN 'SEP' WHEN 10 THEN 'OCT' WHEN 11 THEN 'NOV' WHEN 12 THEN 'DEC' END MONTHNAME FROM `tabSales Invoice` WHERE docstatus = 1 AND fiscal_year = '%s' GROUP BY MONTH(due_date) ORDER BY MONTH(due_date)"%lst[0]))
else:
ret = convert_to_lists(sql("select sum(t2.amount) AMOUNT ,CASE MONTH(t1.due_date) WHEN 1 THEN 'JAN' WHEN 2 THEN 'FEB' WHEN 3 THEN 'MAR' WHEN 4 THEN 'APR' WHEN 5 THEN 'MAY' WHEN 6 THEN 'JUN' WHEN 7 THEN 'JUL' WHEN 8 THEN 'AUG' WHEN 9 THEN 'SEP' WHEN 10 THEN 'OCT' WHEN 11 THEN 'NOV' WHEN 12 THEN 'DEC' END MONTHNAME from `tabSales Invoice` t1,`tabSales Invoice Item` t2 WHERE t1.name = t2.parent and t1.docstatus = 1 and t2.item_group = '%s' AND t1.fiscal_year = '%s' GROUP BY MONTH(t1.due_date) ORDER BY MONTH(t1.due_date)"%(lst[1],lst[0])))
m =cint(sql("select month('%s')"%(get_defaults()['year_start_date']))[0][0])
lst1 = [[1,'JAN'],[2 ,'FEB'], [3,'MAR'],[4,'APR'],[5,'MAY'],[6,'JUN'],[7,'JUL'],[8,'AUG'],[9,'SEP'],[10,'OCT'],[11,'NOV'],[12,'DEC']]
lst2=[]
k=1
for i in range(1,13):
for j in lst1:
if j[0]==m:
lst2.append([k,j[1]])
m +=1
if m==13: m=1
k +=1
return {'msg_data':ret,'x_axis':lst2}
#===============================get weekly sales=================================================
def get_weekwise_amount(self,lst):
lst = lst.split(',')
cases = self.get_week_cases(lst[0],lst[1])
if not lst[2]:
query = "SELECT SUM(grand_total) AMOUNT,CASE WEEK(due_date)"+ cases +"END Weekly FROM `tabSales Invoice` WHERE MONTH(due_date) = %d AND docstatus = 1 AND fiscal_year = '%s' GROUP BY Weekly ORDER BY Weekly"
ret = convert_to_lists(sql(query%(cint(lst[0]),lst[1])))
else:
query = "SELECT SUM(t2.amount) AMOUNT,CASE WEEK(t1.due_date)" + cases + "END Weekly FROM `tabSales Invoice` t1, `tabSales Invoice Item` t2 WHERE MONTH(t1.due_date) = %d AND t1.docstatus = 1 AND t1.fiscal_year = '%s' AND t1.name = t2.parent AND t2.item_group ='%s' GROUP BY Weekly ORDER BY Weekly"
ret =convert_to_lists(sql(query%(cint(lst[0]),lst[1],lst[2])))
return ret and ret or ''
#================================================================================
def get_week_cases(self,m1,fy):
d1 = self.make_date("%s,%s"%(cstr(m1),fy))
w = sql("select week('%s'),week(last_day('%s'))"%(d1,d1))
w1 = cint(w[0][0])
w2 = cint(w[0][1])
w3 = []
str1 = " "
for i in range(1,7):
if(w1 <= w2):
w3.append(w1)
str1 += "WHEN "+ cstr(w1) +" THEN 'Week"+cstr(i) +"' "
w1 += 1
return str1
#===============================get yearly weekwise sales=================================================
def get_year_weekwise_amount(self,lst):
lst = lst.split(',')
yr_st = get_defaults()['year_start_date']
fy = lst[0]
m1 = cint(yr_st.split('-')[1])
cases = ' '
for i in range(1,13):
cases += self.get_week_cases(m1,fy)
m1 +=1
if(m1 == 13): m1 = 1
if not lst[1]:
query = "SELECT SUM(grand_total) AMOUNT,CASE WEEK(due_date)"+cases+"END Weekly, month(due_date) month FROM `tabSales Invoice` WHERE docstatus = 1 AND fiscal_year = '%s' GROUP BY `month`,weekly ORDER BY `month`,weekly"
ret = convert_to_lists(sql(query%lst[0]))
else:
query = "SELECT SUM(t2.amount) AMOUNT,CASE WEEK(t1.due_date)" + cases + "END Weekly, month(due_date) month FROM `tabSales Invoice` t1, `tabSales Invoice Item` t2 WHERE t1.docstatus = 1 AND t1.fiscal_year = '%s' AND t1.name = t2.parent AND t2.item_group ='%s' GROUP BY Weekly ORDER BY Weekly"
ret = convert_to_lists(sql(query%(lst[0],lst[1])))
return ret and ret or ''
#====================================make yearly weekwise dates================================================
def yr_wk_dates(self,fy):
from datetime import date
yr_st = get_defaults()['year_start_date']
yr_en = get_defaults()['year_end_date']
fy = fy.split('-')
y1 = yr_st.split('-')
date1 = date(cint(fy[0]),cint(y1[1]),cint(y1[2]))
y2 = yr_en.split('-')
date2 = date(cint(fy[1]),cint(y2[1]),cint(y2[2]))
date_lst = [[1,self.get_months(cint(y1[1]))]]
m1=cint(y1[1])+1
x_axis_lst = [[1,'Week1',cint(y1[1])]]
from datetime import date, timedelta
d =dt= date1
week=k=1
for i in range(0,53):
if dt <= date2:
if(d.weekday()>3):
d = d+timedelta(7-d.weekday())
else:
d = d - timedelta(d.weekday())
dlt = timedelta(days = (week-1)*7)
dt = d + dlt + timedelta(days=6)
m2 = cint(sql("Select month('%s')"%dt)[0][0])
if(m1 == m2):
date_lst.append([i+2,self.get_months(m2)])
x_axis_lst.append([i+2,'Week1',m2])
k=1
m1 += 1
if(m1==13): m1 =1
else:
date_lst.append([i+2,' '])
x_axis_lst.append([i+2,'Week%d'%k,m2])
week += 1
k +=1
return [date_lst,x_axis_lst]
#===================================================================================
def get_months(self,m):
m_lst = {1:'JAN',2:'FEB',3:'MAR',4:'APR',5:'MAY',6:'JUN',7:'JUL',8:'AUG',9:'SEP',10:'OCT',11:'NOV',12:'DEC'}
return m_lst[m]
def get_weekdates(self,lst):
from datetime import date, timedelta
d = dt = self.make_date(lst)
date_lst = [[1,cstr(d.strftime("%d/%m/%y"))]]
week=flag =1
j=1
last_day = sql("select last_day('%s')"%d)[0][0]
lst_m = cint(lst.split(',')[0])
for i in range(2,8):
f=0
if(dt < last_day):
#if(d.weekday()>4):
#d = d+timedelta(7-d.weekday())
#else:
d = d - timedelta(d.weekday()-1)
dlt = timedelta(days = (week-1)*7)
dt = d + dlt + timedelta(days=6)
if(cint(sql("select month('%s')"%dt)[0][0]) == lst_m and dt!=last_day):
for k in date_lst:
if(cstr(dt.strftime("%d/%m/%y")) == k[1]):
f = 1
if f == 0:
date_lst.append([i,cstr(dt.strftime("%d/%m/%y"))])
elif(dt==last_day and flag ==1):
date_lst.append([i,cstr(last_day.strftime("%d/%m/%y"))])
flag = 0
elif(flag == 1):
date_lst.append([i,cstr(last_day.strftime("%d/%m/%y"))])
week += 1
return date_lst and date_lst or ''
def make_date(self,lst):
from datetime import date, timedelta
lst = lst.split(',')
year = lst[1].split('-')
if(len(lst[0])==1): month = '0'+lst[0]
else: month = lst[0]
if(1<=cint(month)<=3): year = year[1]
elif(4<=cint(month)<=12): year = year[0]
d = date(cint(year),cint(month),1)
return d
def get_item_groups(self):
ret = convert_to_lists(sql("select name from `tabItem Group` where docstatus != 2 and is_group = 'No'"))
#ret = convert_to_lists(sql("select item_group from `tabItem` where is_sales_item='Yes' and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now()) and item_group !=''"))
return ret and ret or ''
def get_fiscal_year(self):
ret = convert_to_lists(sql("select name from `tabFiscal Year` where docstatus =0"))
return ret and ret or ''

View File

@@ -0,0 +1,30 @@
# DocType, Plot Control
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:12',
'docstatus': 0,
'modified': '2012-03-27 14:36:12',
'modified_by': u'Administrator',
'owner': u'harshada@webnotestech.com'
},
# These values are common for all DocType
{
'colour': u'White:FFF',
'doctype': 'DocType',
'issingle': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'version': 215
},
# DocType, Plot Control
{
'doctype': 'DocType',
'name': u'Plot Control'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,340 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Module CRM
cur_frm.cscript.tname = "Quotation Item";
cur_frm.cscript.fname = "quotation_details";
cur_frm.cscript.other_fname = "other_charges";
cur_frm.cscript.sales_team_fname = "sales_team";
// =====================================================================================
wn.require('erpnext/selling/doctype/sales_common/sales_common.js');
wn.require('erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('erpnext/utilities/doctype/sms_control/sms_control.js');
wn.require('erpnext/setup/doctype/notification_control/notification_control.js');
wn.require('erpnext/support/doctype/communication/communication.js');
// ONLOAD
// ===================================================================================
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(!doc.quotation_to) hide_field(['customer','customer_address','contact_person','customer_name','lead', 'lead_name', 'address_display', 'contact_display', 'contact_mobile', 'contact_email', 'territory', 'customer_group']);
if(!doc.price_list_name) set_multiple(cdt,cdn,{price_list_name:sys_defaults.price_list_name});
if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
if(!doc.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
if(!doc.conversion_rate) set_multiple(cdt,cdn,{conversion_rate:'1.00'});
if(!doc.currency && sys_defaults.currency) set_multiple(cdt,cdn,{currency:sys_defaults.currency});
if(!doc.price_list_currency) set_multiple(cdt, cdn, {price_list_currency: doc.currency, plc_conversion_rate: 1});
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.quotation_to) {
if(doc.quotation_to == 'Customer') {
hide_field(['lead', 'lead_name', 'organization']);
}
else if (doc.quotation_to == 'Lead') {
hide_field(['customer','customer_address','contact_person', 'customer_name','contact_display', 'customer_group']);
}
}
cur_frm.cscript.make_communication_body();
}
cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
var callback = function(doc, dt, dn) {
// defined in sales_common.js
cur_frm.cscript.update_item_details(doc, dt, dn);
}
cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback);
}
// hide - unhide fields based on lead or customer..
// =======================================================================================================================
cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
hide_field(['lead', 'lead_name','customer','customer_address','contact_person',
'customer_name','address_display','contact_display','contact_mobile','contact_email',
'territory','customer_group', 'organization']);
if(doc.quotation_to == 'Lead') unhide_field(['lead']);
else if(doc.quotation_to == 'Customer') unhide_field(['customer']);
doc.lead = doc.lead_name = doc.customer = doc.customer_name = doc.customer_address = doc.contact_person = doc.address_display = doc.contact_display = doc.contact_mobile = doc.contact_email = doc.territory = doc.customer_group = doc.organization = "";
}
//================ hide - unhide fields on basis of quotation to either lead or customer ===============================
cur_frm.cscript.quotation_to = function(doc,cdt,cdn){
cur_frm.cscript.lead_cust_show(doc,cdt,cdn);
}
// REFRESH
// ===================================================================================
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.clear_custom_buttons();
if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn);
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']);
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
}
erpnext.hide_naming_series();
if(doc.customer || doc.lead) $(cur_frm.fields_dict.contact_section.row.wrapper).toggle(true);
else $(cur_frm.fields_dict.contact_section.row.wrapper).toggle(false);
if (!doc.__islocal) cur_frm.cscript.render_communication_list(doc, cdt, cdn);
}
//customer
cur_frm.cscript.customer = function(doc,dt,dn) {
var pl = doc.price_list_name;
var callback = function(r,rt) {
var doc = locals[cur_frm.doctype][cur_frm.docname];
cur_frm.refresh();
if (pl != doc.price_list_name) cur_frm.cscript.price_list_name(doc, dt, dn);
}
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name),
'get_default_customer_address', '', callback);
if(doc.customer) unhide_field(['customer_address','contact_person','territory', 'customer_group']);
}
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) 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.fields_dict.customer_address.on_new = function(dn) {
locals['Address'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Address'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict.contact_person.on_new = function(dn) {
locals['Contact'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Contact'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,address_line1,city FROM tabAddress WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,CONCAT(first_name," ",ifnull(last_name,"")) As FullName,department,designation FROM tabContact WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
//lead
cur_frm.fields_dict['lead'].get_query = function(doc,cdt,cdn){
return 'SELECT `tabLead`.name, `tabLead`.lead_name FROM `tabLead` WHERE `tabLead`.%(key)s LIKE "%s" ORDER BY `tabLead`.`name` ASC LIMIT 50';
}
cur_frm.cscript.lead = function(doc, cdt, cdn) {
if(doc.lead) {
get_server_fields('get_lead_details', doc.lead,'', doc, cdt, cdn, 1);
unhide_field('territory');
}
}
// =====================================================================================
cur_frm.fields_dict['enq_no'].get_query = function(doc,cdt,cdn){
var cond='';
var cond1='';
if(doc.order_type) cond = 'ifnull(`tabOpportunity`.enquiry_type, "") = "'+doc.order_type+'" AND';
if(doc.customer) cond1 = '`tabOpportunity`.customer = "'+doc.customer+'" AND';
else if(doc.lead) cond1 = '`tabOpportunity`.lead = "'+doc.lead+'" AND';
return repl('SELECT `tabOpportunity`.`name` FROM `tabOpportunity` WHERE `tabOpportunity`.`docstatus` = 1 AND `tabOpportunity`.status = "Submitted" AND %(cond)s %(cond1)s `tabOpportunity`.`name` LIKE "%s" ORDER BY `tabOpportunity`.`name` ASC LIMIT 50', {cond:cond, cond1:cond1});
}
// Make Sales Order
// =====================================================================================
cur_frm.cscript['Make Sales Order'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
var n = createLocal("Sales Order");
$c('dt_map', args={
'docs':compress_doclist([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);
});
}
}
//pull enquiry details
cur_frm.cscript.pull_enquiry_detail = function(doc,cdt,cdn){
var callback = function(r,rt){
if(r.message){
doc.quotation_to = r.message;
if(doc.quotation_to == 'Lead') {
unhide_field('lead');
}
else if(doc.quotation_to == 'Customer') {
unhide_field(['customer','customer_address','contact_person','territory','customer_group']);
}
refresh_many(['quotation_details','quotation_to','customer','customer_address','contact_person','lead','lead_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group','order_type']);
}
}
$c_obj(make_doclist(doc.doctype, doc.name),'pull_enq_details','',callback);
}
// declare order lost
//-------------------------
cur_frm.cscript['Declare Order Lost'] = function(){
var qtn_lost_dialog;
set_qtn_lost_dialog = function(doc,cdt,cdn){
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();
}
}
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(doc,cdt,cdn);
}
qtn_lost_dialog.show();
}
//===================== Quotation to validation - either customer or lead mandatory ====================
cur_frm.cscript.quot_to_validate = function(doc,cdt,cdn){
if(doc.quotation_to == 'Lead'){
if(!doc.lead){
alert("Lead is mandatory.");
validated = false;
}
}
else if(doc.quotation_to == 'Customer'){
if(!doc.customer){
alert("Customer is mandatory.");
validated = false;
}
}
}
//===================validation function =================================
cur_frm.cscript.validate = function(doc,cdt,cdn){
cur_frm.cscript.recalculate_values(doc, cdt, cdn);
cur_frm.cscript.quot_to_validate(doc,cdt,cdn);
}
//================ Last Quoted Price and Last Sold Price suggestion ======================
cur_frm.fields_dict['quotation_details'].grid.get_field('item_code').get_query= function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
var cond = (doc.order_type == 'Maintenance') ? " and item.is_service_item = 'Yes'" : " and item.is_sales_item = 'Yes'";
if(doc.customer) {
var export_rate_field = wn.meta.get_docfield(cdt, 'export_rate', cdn);
var precision = (export_rate_field && export_rate_field.fieldtype) === 'Float' ? 6 : 2;
return repl("\
select \
item.name, \
( \
select concat('Last Quote @ ', q.currency, ' ', \
format(q_item.export_rate, %(precision)s)) \
from `tabQuotation` q, `tabQuotation Item` q_item \
where \
q.name = q_item.parent \
and q_item.item_code = item.name \
and q.docstatus = 1 \
and q.customer = \"%(cust)s\" \
order by q.transaction_date desc \
limit 1 \
) as quote_rate, \
( \
select concat('Last Sale @ ', si.currency, ' ', \
format(si_item.basic_rate, %(precision)s)) \
from `tabSales Invoice` si, `tabSales Invoice Item` si_item \
where \
si.name = si_item.parent \
and si_item.item_code = item.name \
and si.docstatus = 1 \
and si.customer = \"%(cust)s\" \
order by si.voucher_date desc \
limit 1 \
) as sales_rate, \
item.item_name, item.description \
from `tabItem` item \
where \
item.%(key)s like \"%s\" \
%(cond)s \
limit 25", {
cust: doc.customer,
cond: cond,
precision: precision
});
} else {
return repl("SELECT name, item_name, description FROM `tabItem` item WHERE item.%(key)s LIKE '%s' %(cond)s ORDER BY item.item_code DESC LIMIT 50", {cond:cond});
}
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
var args = {
type: 'Quotation',
doctype: 'Quotation'
}
cur_frm.cscript.notify(doc, args);
}

View File

@@ -0,0 +1,355 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, load_json
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
class DocType(TransactionBase):
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
self.tname = 'Quotation Item'
self.fname = 'quotation_details'
# Autoname
# ---------
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+'.#####')
# DOCTYPE TRIGGER FUNCTIONS
# ==============================================================================
# Pull Opportunity Details
# --------------------
def pull_enq_details(self):
self.doclist = self.doc.clear_table(self.doclist, 'quotation_details')
get_obj('DocType Mapper', 'Opportunity-Quotation').dt_map('Opportunity', 'Quotation', self.doc.enq_no, self.doc, self.doclist, "[['Opportunity', 'Quotation'],['Opportunity Item', 'Quotation Item']]")
self.get_adj_percent()
return self.doc.quotation_to
# Get contact person details based on customer selected
# ------------------------------------------------------
def get_contact_details(self):
return get_obj('Sales Common').get_contact_details(self,0)
# QUOTATION DETAILS TRIGGER FUNCTIONS
# ================================================================================
# Get Item Details
# -----------------
def get_item_details(self, args=None):
import json
args = args and json.loads(args) or {}
if args.get('item_code'):
return get_obj('Sales Common').get_item_details(args, self)
else:
obj = get_obj('Sales Common')
for doc in self.doclist:
if doc.fields.get('item_code'):
arg = {
'item_code': doc.fields.get('item_code'),
'income_account': doc.fields.get('income_account'),
'cost_center': doc.fields.get('cost_center'),
'warehouse': doc.fields.get('warehouse')
}
res = obj.get_item_details(arg, self) or {}
for r in res:
if not doc.fields.get(r):
doc.fields[r] = res[r]
# Re-calculates Basic Rate & amount based on Price List Selected
# --------------------------------------------------------------
def get_adj_percent(self, arg=''):
get_obj('Sales Common').get_adj_percent(self)
# OTHER CHARGES TRIGGER FUNCTIONS
# ====================================================================================
# Get Tax rate if account type is TAX
# -----------------------------------
def get_rate(self,arg):
return get_obj('Sales Common').get_rate(arg)
# Load Default Charges
# ----------------------------------------------------------
def load_default_taxes(self):
self.doclist = get_obj('Sales Common').load_default_taxes(self)
# Pull details from other charges master (Get Sales Taxes and Charges Master)
# ----------------------------------------------------------
def get_other_charges(self):
self.doclist = get_obj('Sales Common').get_other_charges(self)
# GET TERMS AND CONDITIONS
# ====================================================================================
def get_tc_details(self):
return get_obj('Sales Common').get_tc_details(self)
# VALIDATE
# ==============================================================================================
# Amendment date is necessary if document is amended
# --------------------------------------------------
def validate_mandatory(self):
if self.doc.amended_from and not self.doc.amendment_date:
msgprint("Please Enter Amendment Date")
raise Exception
# Fiscal Year Validation
# ----------------------
def validate_fiscal_year(self):
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'Quotation Date')
# Does not allow same item code to be entered twice
# -------------------------------------------------
def validate_for_items(self):
chk_dupl_itm = []
for d in getlist(self.doclist,'quotation_details'):
if [cstr(d.item_code),cstr(d.description)] in chk_dupl_itm:
msgprint("Item %s has been entered twice. Please change description atleast to continue" % d.item_code)
raise Exception
else:
chk_dupl_itm.append([cstr(d.item_code),cstr(d.description)])
#do not allow sales item in maintenance quotation and service item in sales quotation
#-----------------------------------------------------------------------------------------------
def validate_order_type(self):
if self.doc.order_type in ['Maintenance', 'Service']:
for d in getlist(self.doclist, 'quotation_details'):
is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code)
is_service_item = is_service_item and is_service_item[0][0] or 'No'
if is_service_item == 'No':
msgprint("You can not select non service item "+d.item_code+" in Maintenance Quotation")
raise Exception
else:
for d in getlist(self.doclist, 'quotation_details'):
is_sales_item = sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
is_sales_item = is_sales_item and is_sales_item[0][0] or 'No'
if is_sales_item == 'No':
msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation")
raise Exception
#--------------Validation For Last Contact Date-----------------
# ====================================================================================================================
def set_last_contact_date(self):
#if not self.doc.contact_date_ref:
#self.doc.contact_date_ref=self.doc.contact_date
#self.doc.last_contact_date=self.doc.contact_date_ref
if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date:
if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date):
self.doc.last_contact_date=self.doc.contact_date_ref
else:
msgprint("Contact Date Cannot be before Last Contact Date")
raise Exception
#set(self.doc, 'contact_date_ref',self.doc.contact_date)
# Validate
# --------
def validate(self):
self.validate_fiscal_year()
self.validate_mandatory()
self.set_last_contact_date()
self.validate_order_type()
self.validate_for_items()
sales_com_obj = get_obj('Sales Common')
sales_com_obj.check_active_sales_items(self)
sales_com_obj.validate_max_discount(self,'quotation_details') #verify whether rate is not greater than max_discount
sales_com_obj.check_conversion_rate(self)
# Get total in words
dcc = TransactionBase().get_company_currency(self.doc.company)
self.doc.in_words = sales_com_obj.get_total_in_words(dcc, self.doc.rounded_total)
self.doc.in_words_export = sales_com_obj.get_total_in_words(self.doc.currency, self.doc.rounded_total_export)
def on_update(self):
# Add to calendar
if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
if self.doc.contact_by:
self.add_calendar_event()
set(self.doc, 'contact_date_ref',self.doc.contact_date)
# Set Quotation Status
set(self.doc, 'status', 'Draft')
# subject for follow
self.doc.subject = '[%(status)s] To %(customer)s worth %(currency)s %(grand_total)s' % self.doc.fields
# Add to Calendar
# ====================================================================================================================
def add_calendar_event(self):
desc=''
user_lst =[]
if self.doc.customer:
if self.doc.contact_person:
desc = 'Contact '+cstr(self.doc.contact_person)
else:
desc = 'Contact customer '+cstr(self.doc.customer)
elif self.doc.lead:
if self.doc.lead_name:
desc = 'Contact '+cstr(self.doc.lead_name)
else:
desc = 'Contact lead '+cstr(self.doc.lead)
desc = desc+ '.By : ' + cstr(self.doc.contact_by)
if self.doc.to_discuss:
desc = desc+' To Discuss : ' + cstr(self.doc.to_discuss)
ev = Document('Event')
ev.description = desc
ev.event_date = self.doc.contact_date
ev.event_hour = '10:00'
ev.event_type = 'Private'
ev.ref_type = 'Opportunity'
ev.ref_name = self.doc.name
ev.save(1)
user_lst.append(self.doc.owner)
chk = sql("select t1.name from `tabProfile` t1, `tabSales Person` t2 where t2.email_id = t1.name and t2.name=%s",self.doc.contact_by)
if chk:
user_lst.append(chk[0][0])
for d in user_lst:
ch = addchild(ev, 'event_individuals', 'Event User', 0)
ch.person = d
ch.save(1)
#update enquiry
#------------------
def update_enquiry(self, flag):
prevdoc=''
for d in getlist(self.doclist, 'quotation_details'):
if d.prevdoc_docname:
prevdoc = d.prevdoc_docname
if prevdoc:
if flag == 'submit': #on submit
sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc)
elif flag == 'cancel': #on cancel
sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc)
elif flag == 'order lost': #order lost
sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc)
elif flag == 'order confirm': #order confirm
sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc)
# declare as order lost
#-------------------------
def declare_order_lost(self,arg):
chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name)
if chk:
msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.")
raise Exception
else:
set(self.doc, 'status', 'Order Lost')
set(self.doc, 'order_lost_reason', arg)
self.update_enquiry('order lost')
return 'true'
#check if value entered in item table
#--------------------------------------
def check_item_table(self):
if not getlist(self.doclist, 'quotation_details'):
msgprint("Please enter item details")
raise Exception
# ON SUBMIT
# =========================================================================
def on_submit(self):
self.check_item_table()
if not self.doc.amended_from:
set(self.doc, 'message', 'Quotation: '+self.doc.name+' has been sent')
else:
set(self.doc, 'message', 'Quotation has been amended. New Quotation no:'+self.doc.name)
# 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
set(self.doc, 'status', 'Submitted')
#update enquiry status
self.update_enquiry('submit')
# ON CANCEL
# ==========================================================================
def on_cancel(self):
set(self.doc, 'message', 'Quotation: '+self.doc.name+' has been cancelled')
#update enquiry status
self.update_enquiry('cancel')
set(self.doc,'status','Cancelled')
# SEND SMS
# =============================================================================
def send_sms(self):
if not self.doc.customer_mobile_no:
msgprint("Please enter customer mobile no")
elif not self.doc.message:
msgprint("Please enter the message you want to send")
else:
msgprint(get_obj("SMS Control", "SMS Control").send_sms([self.doc.contact_mobile,], self.doc.message))
# Print other charges
# ===========================================================================
def print_other_charges(self,docname):
print_lst = []
for d in getlist(self.doclist,'other_charges'):
lst1 = []
lst1.append(d.description)
lst1.append(d.total)
print_lst.append(lst1)
return print_lst
def update_followup_details(self):
sql("delete from `tabCommunication Log` where parent = '%s'"%self.doc.name)
for d in getlist(self.doclist, 'follow_up'):
d.save()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
// render
wn.doclistviews['Quotation'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
"`tabQuotation`.quotation_to",
"`tabQuotation`.lead_name",
"`tabQuotation`.customer_name",
"`tabQuotation`.currency",
"ifnull(`tabQuotation`.grand_total_export,0) as grand_total_export",
"`tabQuotation`.transaction_date",
]);
this.stats = this.stats.concat(['status', 'quotation_to', 'company']);
},
prepare_data: function(data) {
this._super(data);
if(data.quotation_to == 'Lead') {
data.quotation_name = repl('[%(quotation_to)s] %(lead_name)s', data);
} else {
data.quotation_name = repl('[%(quotation_to)s] %(customer_name)s', data);
}
},
columns: [
{width: '3%', content: 'check'},
{width: '5%', content:'avatar'},
{width: '3%', content:'docstatus'},
{width: '15%', content:'name'},
{width: '44%', content:'quotation_name+tags', css: {color:'#222'}},
{
width: '18%',
content: function(parent, data) {
$(parent).html(data.currency + ' ' + fmt_money(data.grand_total_export))
},
css: {'text-align':'right'}
},
{width: '12%', content:'transaction_date',
css: {'text-align': 'right', 'color':'#777'},
title: "Quotation Date", type: "date"}
]
});

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,345 @@
# DocType, Quotation Item
[
# These values are common in all dictionaries
{
'creation': '2012-06-08 16:07:57',
'docstatus': 0,
'modified': '2012-07-09 11:04:47',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'autoname': u'QUOD/.#####',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'is_transaction_doc': 0,
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Tray',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 1
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Quotation Item',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# DocType, Quotation Item
{
'doctype': 'DocType',
'name': u'Quotation Item'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_code',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Item Code',
'oldfieldname': u'item_code',
'oldfieldtype': u'Link',
'options': u'Item',
'permlevel': 0,
'print_hide': 0,
'reqd': 1,
'search_index': 1,
'trigger': u'Client',
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_item_code',
'fieldtype': u'Data',
'hidden': 1,
'label': u"Customer's Item Code",
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_name',
'fieldtype': u'Data',
'in_filter': 1,
'label': u'Item Name',
'oldfieldname': u'item_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'search_index': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Small Text',
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Small Text',
'permlevel': 0,
'print_hide': 0,
'reqd': 1,
'width': u'300px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'qty',
'fieldtype': u'Currency',
'in_filter': 0,
'label': u'Quantity',
'oldfieldname': u'qty',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 0,
'reqd': 1,
'search_index': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'stock_uom',
'fieldtype': u'Data',
'label': u'UOM',
'oldfieldname': u'stock_uom',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 0,
'reqd': 0,
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'ref_rate',
'fieldtype': u'Currency',
'label': u'Price List Rate',
'oldfieldname': u'ref_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'adj_rate',
'fieldtype': u'Float',
'label': u'Discount (%)',
'oldfieldname': u'adj_rate',
'oldfieldtype': u'Float',
'permlevel': 0,
'print_hide': 1,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'export_rate',
'fieldtype': u'Currency',
'in_filter': 0,
'label': u'Rate',
'oldfieldname': u'export_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 0,
'reqd': 0,
'search_index': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'export_amount',
'fieldtype': u'Currency',
'in_filter': 0,
'label': u'Amount',
'oldfieldname': u'export_amount',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 0,
'reqd': 0,
'search_index': 0,
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'base_ref_rate',
'fieldtype': u'Currency',
'label': u'Price List Rate*',
'oldfieldname': u'base_ref_rate',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'basic_rate',
'fieldtype': u'Currency',
'in_filter': 0,
'label': u'Basic Rate*',
'oldfieldname': u'basic_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'search_index': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'amount',
'fieldtype': u'Currency',
'in_filter': 0,
'label': u'Amount*',
'oldfieldname': u'amount',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'reqd': 0,
'search_index': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_group',
'fieldtype': u'Link',
'hidden': 1,
'in_filter': 1,
'label': u'Item Group',
'oldfieldname': u'item_group',
'oldfieldtype': u'Link',
'options': u'Item Group',
'permlevel': 1,
'print_hide': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'brand',
'fieldtype': u'Link',
'hidden': 1,
'in_filter': 1,
'label': u'Brand',
'oldfieldname': u'brand',
'oldfieldtype': u'Link',
'options': u'Brand',
'permlevel': 1,
'print_hide': 1,
'search_index': 1,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_tax_rate',
'fieldtype': u'Small Text',
'hidden': 1,
'label': u'Item Tax Rate',
'oldfieldname': u'item_tax_rate',
'oldfieldtype': u'Small Text',
'permlevel': 1,
'print_hide': 1,
'report_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_docname',
'fieldtype': u'Data',
'label': u'Against Docname',
'no_copy': 1,
'oldfieldname': u'prevdoc_docname',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'report_hide': 0,
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_doctype',
'fieldtype': u'Data',
'hidden': 1,
'label': u'Against Doctype',
'no_copy': 1,
'oldfieldname': u'prevdoc_doctype',
'oldfieldtype': u'Data',
'permlevel': 1,
'print_hide': 1,
'report_hide': 0,
'width': u'150px'
},
# DocField
{
'allow_on_submit': 1,
'doctype': u'DocField',
'fieldname': u'page_break',
'fieldtype': u'Check',
'hidden': 0,
'label': u'Page Break',
'no_copy': 1,
'oldfieldname': u'page_break',
'oldfieldtype': u'Check',
'permlevel': 0,
'print_hide': 1,
'report_hide': 1
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,142 @@
# DocType, Sales and Purchase Return Item
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:14',
'docstatus': 0,
'modified': '2012-03-27 14:36:14',
'modified_by': u'Administrator',
'owner': u'wasim@webnotestech.com'
},
# These values are common for all DocType
{
'colour': u'White:FFF',
'doctype': 'DocType',
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 8
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Sales and Purchase Return Item',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# DocType, Sales and Purchase Return Item
{
'doctype': 'DocType',
'name': u'Sales and Purchase Return Item'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_code',
'fieldtype': u'Link',
'label': u'Item Code',
'oldfieldname': u'item_code',
'oldfieldtype': u'Link',
'options': u'Item',
'permlevel': 1,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Data',
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Data',
'permlevel': 1,
'width': u'300px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'uom',
'fieldtype': u'Link',
'label': u'UOM',
'oldfieldname': u'uom',
'oldfieldtype': u'Link',
'options': u'UOM',
'permlevel': 1,
'search_index': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'rate',
'fieldtype': u'Currency',
'label': u'Rate',
'oldfieldname': u'rate',
'oldfieldtype': u'Currency',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'qty',
'fieldtype': u'Data',
'label': u'Qty',
'oldfieldname': u'qty',
'oldfieldtype': u'Data',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'returned_qty',
'fieldtype': u'Data',
'label': u'Returned Qty',
'oldfieldname': u'returned_qty',
'oldfieldtype': u'Data',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'serial_no',
'fieldtype': u'Small Text',
'label': u'Serial No',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'batch_no',
'fieldtype': u'Data',
'label': u'Batch No',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'detail_name',
'fieldtype': u'Data',
'hidden': 1,
'label': u'Detail Name',
'oldfieldname': u'detail_name',
'oldfieldtype': u'Data',
'permlevel': 1
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,859 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Preset
// ------
// cur_frm.cscript.tname - Details table name
// cur_frm.cscript.fname - Details fieldname
// cur_frm.cscript.other_fname - wn.require('erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js'); fieldname
// cur_frm.cscript.sales_team_fname - Sales Team fieldname
// ============== Load Default Taxes ===================
cur_frm.cscript.load_taxes = function(doc, cdt, cdn, callback) {
// run if this is not executed from dt_map...
doc = locals[doc.doctype][doc.name];
if(doc.customer || getchildren('Sales Taxes and Charges', doc.name, 'other_charges', doc.doctype).length) {
if(callback) {
callback(doc, cdt, cdn);
}
} else {
$c_obj(make_doclist(doc.doctype, doc.name),'load_default_taxes','',function(r,rt){
refresh_field('other_charges');
if(callback) callback(doc, cdt, cdn);
});
}
}
// Gets called after existing item details are update to fill in
// remaining default values
cur_frm.cscript.load_defaults = function(doc, dt, dn, callback) {
if(!cur_frm.doc.__islocal) { return; }
doc = locals[doc.doctype][doc.name];
var fields_to_refresh = LocalDB.set_default_values(doc);
if(fields_to_refresh) { refresh_many(fields_to_refresh); }
fields_to_refresh = null;
var children = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
if(!children) { return; }
for(var i=0; i<children.length; i++) {
LocalDB.set_default_values(children[i]);
}
refresh_field(cur_frm.cscript.fname);
cur_frm.cscript.load_taxes(doc, dt, dn, callback);
}
// Update existing item details
cur_frm.cscript.update_item_details = function(doc, dt, dn, callback) {
doc = locals[doc.doctype][doc.name];
if(!cur_frm.doc.__islocal) return;
var children = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
if(children.length) {
$c_obj(make_doclist(doc.doctype, doc.name), 'get_item_details', '',
function(r, rt) {
if(!r.exc) {
refresh_field(cur_frm.cscript.fname);
doc = locals[doc.doctype][doc.name];
cur_frm.cscript.load_defaults(doc, dt, dn, callback);
}
});
} else {
cur_frm.cscript.load_taxes(doc, dt, dn, callback);
}
}
var set_dynamic_label_par = function(doc, cdt, cdn, base_curr) {
//parent flds
par_cols_base = {'net_total': 'Net Total', 'other_charges_total': 'Taxes and Charges Total',
'grand_total': 'Grand Total', 'rounded_total': 'Rounded Total', 'in_words': 'In Words'}
par_cols_export = {'grand_total_export': 'Grand Total', 'rounded_total_export': 'Rounded Total', 'in_words_export': 'In Words'};
for (d in par_cols_base) cur_frm.fields_dict[d].label_span.innerHTML = par_cols_base[d]+' (' + base_curr + ')';
for (d in par_cols_export) cur_frm.fields_dict[d].label_span.innerHTML = par_cols_export[d]+' (' + doc.currency + ')';
cur_frm.fields_dict['conversion_rate'].label_span.innerHTML = "Conversion Rate (" + doc.currency +' -> '+ base_curr + ')';
cur_frm.fields_dict['plc_conversion_rate'].label_span.innerHTML = 'Price List Currency Conversion Rate (' + doc.price_list_currency +' -> '+ base_curr + ')';
if (doc.doctype == 'Sales Invoice') {
si_cols = {'total_advance': 'Total Advance', 'outstanding_amount': 'Outstanding Amount', 'paid_amount': 'Paid Amount', 'write_off_amount': 'Write Off Amount'}
for (d in si_cols) cur_frm.fields_dict[d].label_span.innerHTML = si_cols[d] + ' (' + base_curr + ')';
}
}
var set_dynamic_label_child = function(doc, cdt, cdn, base_curr) {
// item table flds
item_cols_base = {'basic_rate': 'Basic Rate', 'base_ref_rate': 'Price List Rate', 'amount': 'Amount'};
item_cols_export = {'export_rate': 'Basic Rate', 'ref_rate': 'Price List Rate', 'export_amount': 'Amount'};
for (d in item_cols_base) $('[data-grid-fieldname="'+cur_frm.cscript.tname+'-'+d+'"]').html(item_cols_base[d]+' ('+base_curr+')');
for (d in item_cols_export) $('[data-grid-fieldname="'+cur_frm.cscript.tname+'-'+d+'"]').html(item_cols_export[d]+' ('+doc.currency+')');
var hide = (doc.currency == sys_defaults['currency']) ? false : true;
for (f in item_cols_base) {
cur_frm.fields_dict[cur_frm.cscript.fname].grid.set_column_disp(f, hide);
}
//tax table flds
tax_cols = {'tax_amount': 'Amount', 'total': 'Total'};
for (d in tax_cols) $('[data-grid-fieldname="Sales Taxes and Charges-'+d+'"]').html(tax_cols[d]+' ('+base_curr+')');
if (doc.doctype == 'Sales Invoice') {
// advance table flds
adv_cols = {'advance_amount': 'Advance Amount', 'allocated_amount': 'Allocated Amount'}
for (d in adv_cols) $('[data-grid-fieldname="Sales Invoice Advance-'+d+'"]').html(adv_cols[d]+' ('+base_curr+')');
}
}
// Change label dynamically based on currency
//------------------------------------------------------------------
cur_frm.cscript.dynamic_label = function(doc, cdt, cdn, base_curr, callback) {
cur_frm.cscript.base_currency = base_curr;
set_dynamic_label_par(doc, cdt, cdn, base_curr);
set_dynamic_label_child(doc, cdt, cdn, base_curr);
set_sales_bom_help(doc);
if (callback) callback(doc, cdt, cdn);
}
// Help for Sales BOM items
var set_sales_bom_help = function(doc) {
if(!cur_frm.fields_dict.packing_list) return;
if (getchildren('Delivery Note Packing Item', doc.name, 'packing_details').length) {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
help_msg = "<div class='help-box'> \
For 'Sales BOM' items, warehouse, serial no and batch no \
will be considered from the 'Packing List' table. \
If warehouse and batch no are same for all packing items for any 'Sales BOM' item, \
those values can be entered in the main item table, values will be copied to 'Packing List' table. \
</div>";
wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = help_msg;
}
} else {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = '';
}
}
refresh_field('sales_bom_help');
}
// hide / unhide price list currency based on availability of price list in customer's currency
//---------------------------------------------------------------------------------------------------
cur_frm.cscript.hide_price_list_currency = function(doc, cdt, cdn, callback1) {
if (doc.price_list_name && doc.currency) {
wn.call({
method: 'selling.doctype.sales_common.sales_common.get_price_list_currency',
args: {'price_list':doc.price_list_name, 'company': doc.company},
callback: function(r, rt) {
pl_currency = r.message[0]?r.message[0]:[];
unhide_field(['price_list_currency', 'plc_conversion_rate']);
if (pl_currency.length==1) {
if (doc.price_list_currency != pl_currency[0]) set_multiple(cdt, cdn, {price_list_currency:pl_currency[0]});
if (pl_currency[0] == doc.currency) {
if(doc.plc_conversion_rate != doc.conversion_rate) set_multiple(cdt, cdn, {plc_conversion_rate:doc.conversion_rate});
hide_field(['price_list_currency', 'plc_conversion_rate']);
} else if (pl_currency[0] == r.message[1]) {
if (doc.plc_conversion_rate != 1) set_multiple(cdt, cdn, {plc_conversion_rate:1})
hide_field(['price_list_currency', 'plc_conversion_rate']);
}
}
if (r.message[1] == doc.currency) {
if (doc.conversion_rate != 1) set_multiple(cdt, cdn, {conversion_rate:1});
hide_field(['conversion_rate', 'grand_total_export', 'in_words_export', 'rounded_total_export']);
} else unhide_field(['conversion_rate', 'grand_total_export', 'in_words_export', 'rounded_total_export']);
if (r.message[1] == doc.price_list_currency) {
if (doc.plc_conversion_rate != 1) set_multiple(cdt, cdn, {plc_conversion_rate:1});
hide_field('plc_conversion_rate');
} else unhide_field('plc_conversion_rate');
cur_frm.cscript.dynamic_label(doc, cdt, cdn, r.message[1], callback1);
}
})
}
}
// TRIGGERS FOR CALCULATIONS
// =====================================================================================================
// ********************* CURRENCY ******************************
cur_frm.cscript.currency = function(doc, cdt, cdn) {
cur_frm.cscript.price_list_name(doc, cdt, cdn);
}
cur_frm.cscript.price_list_currency = cur_frm.cscript.currency;
cur_frm.cscript.conversion_rate = cur_frm.cscript.currency;
cur_frm.cscript.plc_conversion_rate = cur_frm.cscript.currency;
cur_frm.cscript.company = function(doc, cdt, cdn) {
wn.call({
method: 'selling.doctype.sales_common.sales_common.get_comp_base_currency',
args: {company:doc.company},
callback: function(r, rt) {
var doc = locals[cdt][cdn];
set_multiple(doc.doctype, doc.name, {
currency:r.message,
price_list_currency:r.message
});
cur_frm.cscript.currency(doc, cdt, cdn);
}
});
}
// ******************** PRICE LIST ******************************
cur_frm.cscript.price_list_name = function(doc, cdt, cdn) {
var callback = function() {
var fname = cur_frm.cscript.fname;
var cl = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
if(doc.price_list_name && doc.currency && doc.price_list_currency && doc.conversion_rate && doc.plc_conversion_rate) {
$c_obj(make_doclist(doc.doctype, doc.name), 'get_adj_percent', '',
function(r, rt) {
refresh_field(fname);
var doc = locals[cdt][cdn];
cur_frm.cscript.recalc(doc,3); //this is to re-calculate BASIC RATE and AMOUNT on basis of changed REF RATE
}
);
}
}
cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn, callback);
}
// ******************** ITEM CODE ********************************
cur_frm.fields_dict[cur_frm.cscript.fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
if (inList(['Maintenance', 'Service'], doc.order_type))
return 'SELECT tabItem.name,tabItem.item_name,tabItem.description \
FROM tabItem WHERE tabItem.is_service_item="Yes" \
AND tabItem.docstatus != 2 \
AND (ifnull(`tabItem`.`end_of_life`,"") = "" \
OR `tabItem`.`end_of_life` > NOW() \
OR `tabItem`.`end_of_life`="0000-00-00") \
AND tabItem.%(key)s LIKE "%s" LIMIT 50';
else
return 'SELECT tabItem.name,tabItem.item_name,tabItem.description FROM tabItem \
WHERE tabItem.is_sales_item="Yes" AND tabItem.docstatus != 2 \
AND (ifnull(`tabItem`.`end_of_life`,"") = "" \
OR `tabItem`.`end_of_life` > NOW() \
OR `tabItem`.`end_of_life`="0000-00-00") \
AND tabItem.%(key)s LIKE "%s" LIMIT 50';
}
cur_frm.cscript.item_code = function(doc, cdt, cdn) {
var fname = cur_frm.cscript.fname;
var d = locals[cdt][cdn];
if (d.item_code) {
if (!doc.company) {
msgprint("Please select company to proceed");
d.item_code = '';
refresh_field('item_code', d.name, fname);
} else {
var callback = function(r, rt){
cur_frm.cscript.recalc(doc, 1);
}
var args = {
'item_code':d.item_code,
'income_account':d.income_account,
'cost_center': d.cost_center,
'warehouse': d.warehouse
};
get_server_fields('get_item_details',JSON.stringify(args),
fname,doc,cdt,cdn,1,callback);
}
}
if(cur_frm.cscript.custom_item_code){
cur_frm.cscript.custom_item_code(doc, cdt, cdn);
}
}
//Barcode
//
cur_frm.cscript.barcode = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
var callback = function(r, rt) {
cur_frm.cscript.item_code(doc, cdt, cdn);
}
get_server_fields('get_barcode_details', d.barcode, cur_frm.cscript.fname, doc, cdt, cdn, 1, callback);
}
// *********************** QUANTITY ***************************
cur_frm.cscript.qty = function(doc, cdt, cdn) { cur_frm.cscript.recalc(doc, 1); }
// ************************ DISCOUNT (%) ***********************
cur_frm.cscript.adj_rate = function(doc, cdt, cdn) { cur_frm.cscript.recalc(doc, 1); }
// ************************ REF RATE ****************************
cur_frm.cscript.ref_rate = function(doc, cdt, cdn){
var d = locals[cdt][cdn];
var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, cur_frm.cscript.other_fname);
if(!consider_incl_rate) {
set_multiple(cur_frm.cscript.tname, d.name, {'export_rate': flt(d.ref_rate) * (100 - flt(d.adj_rate)) / 100}, cur_frm.cscript.fname);
}
cur_frm.cscript.recalc(doc, 1);
}
// *********************** BASIC RATE **************************
cur_frm.cscript.basic_rate = function(doc, cdt, cdn) {
var fname = cur_frm.cscript.fname;
var d = locals[cdt][cdn];
if(!d.qty) {
d.qty = 1;
refresh_field('qty', d.name, fname);
}
var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, cur_frm.cscript.other_fname);
if(!consider_incl_rate) {
cur_frm.cscript.recalc(doc, 2);
} else {
var basic_rate = cur_frm.cscript.back_calc_basic_rate(
doc, cur_frm.cscript.tname, fname, d, cur_frm.cscript.other_fname
);
// TODO: remove roundNumber for basic_rate comparison
if (d.basic_rate != roundNumber(basic_rate, 2)) {
d.basic_rate = basic_rate;
refresh_field('basic_rate', d.name, fname);
msgprint("You cannot change Basic Rate* (Base Currency) when \
considering rates inclusive of taxes.<br /> \
Please either <br /> \
* Specify Basic Rate (i.e. Rate which will be displayed in print) <br /> \
-- or -- <br />\
* Uncheck 'Is this Tax included in Basic Rate?' in the tax entries of Taxes section.");
}
}
}
// ************************ EXPORT RATE *************************
cur_frm.cscript.export_rate = function(doc,cdt,cdn) {
var cur_rec = locals[cdt][cdn];
var fname = cur_frm.cscript.fname;
var tname = cur_frm.cscript.tname;
if(flt(cur_rec.ref_rate)>0 && flt(cur_rec.export_rate)>0) {
var adj_rate = 100 * (1 - (flt(cur_rec.export_rate) / flt(cur_rec.ref_rate)));
set_multiple(tname, cur_rec.name, { 'adj_rate': adj_rate }, fname);
}
doc = locals[doc.doctype][doc.name];
cur_frm.cscript.recalc(doc, 1);
}
// ************* GET OTHER CHARGES BASED ON COMPANY *************
cur_frm.fields_dict.charge.get_query = function(doc) {
return 'SELECT DISTINCT `tabSales Taxes and Charges Master`.name FROM \
`tabSales Taxes and Charges Master` WHERE `tabSales Taxes and Charges Master`.company = "'
+doc.company+'" AND `tabSales Taxes and Charges Master`.company is not NULL \
AND `tabSales Taxes and Charges Master`.docstatus != 2 \
AND `tabSales Taxes and Charges Master`.%(key)s LIKE "%s" \
ORDER BY `tabSales Taxes and Charges Master`.name LIMIT 50';
}
// ********************* Get Charges ****************************
cur_frm.cscript.get_charges = function(doc, cdt, cdn) {
$c_obj(make_doclist(doc.doctype,doc.name),
'get_other_charges',
'',
function(r, rt) { cur_frm.cscript.calculate_charges(doc, cdt, cdn);}
,null,null,cur_frm.fields_dict.get_charges.input);
}
// CALCULATION OF TOTAL AMOUNTS
// ========================================================================================================
cur_frm.cscript.recalc = function(doc, n) {
if(!n)n=0;
doc = locals[doc.doctype][doc.name];
var tname = cur_frm.cscript.tname;
var fname = cur_frm.cscript.fname;
var sales_team = cur_frm.cscript.sales_team_fname;
var other_fname = cur_frm.cscript.other_fname;
if(!flt(doc.conversion_rate)) {
doc.conversion_rate = 1;
refresh_field('conversion_rate');
}
if(!flt(doc.plc_conversion_rate)) {
doc.plc_conversion_rate = 1;
refresh_field('plc_conversion_rate');
}
if(n > 0) cur_frm.cscript.update_fname_table(doc , tname , fname , n, other_fname); // updates all values in table (i.e. amount, export amount, net total etc.)
if(flt(doc.net_total) > 0) {
var cl = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
for(var i = 0; i<cl.length; i++){
cl[i].total_tax_amount = 0;
cl[i].total_amount = 0;
cl[i].tax_amount = 0; // this is done to calculate other charges
cl[i].total = 0;
cl[i].item_wise_tax_detail = "";
if(in_list(['On Previous Row Amount','On Previous Row Total'],cl[i].charge_type) && !cl[i].row_id){
alert("Please Enter Row on which amount needs to be calculated for row : "+cl[i].idx);
validated = false;
}
}
cur_frm.cscript.calc_other_charges(doc , tname , fname , other_fname); // calculate other charges
}
cur_frm.cscript.calc_doc_values(doc, null, null, tname, fname, other_fname); // calculates total amounts
// ******************* calculate allocated amount of sales person ************************
cl = getchildren('Sales Team', doc.name, sales_team);
for(var i=0;i<cl.length;i++) {
if (cl[i].allocated_percentage) {
cl[i].allocated_amount = flt(flt(doc.net_total)*flt(cl[i].allocated_percentage)/100);
refresh_field('allocated_amount', cl[i].name, sales_team);
}
}
doc.in_words = '';
doc.in_words_export = '';
refresh_many(['total_discount_rate','total_discount','net_total','total_commission','grand_total','rounded_total','grand_total_export','rounded_total_export','in_words','in_words_export','other_charges','other_charges_total']);
if(cur_frm.cscript.custom_recalc)cur_frm.cscript.custom_recalc(doc);
}
// ******* Calculation of total amounts of document (item amount + other charges)****************
cur_frm.cscript.calc_doc_values = function(doc, cdt, cdn, tname, fname, other_fname) {
doc = locals[doc.doctype][doc.name];
var net_total = 0; var other_charges_total = 0;
var net_total_incl = 0
var cl = getchildren(tname, doc.name, fname);
for(var i = 0; i<cl.length; i++){
//net_total += flt(cl[i].basic_rate) * flt(cl[i].qty);
net_total += flt(cl[i].amount);
net_total_incl += flt(cl[i].export_amount);
}
var inclusive_rate = 0
var d = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
for(var j = 0; j<d.length; j++){
other_charges_total += flt(d[j].tax_amount);
if(d[j].included_in_print_rate) {
inclusive_rate = 1;
}
}
if(flt(doc.conversion_rate)>1) {
net_total_incl *= flt(doc.conversion_rate);
}
doc.net_total = inclusive_rate ? flt(net_total_incl) : flt(net_total);
doc.other_charges_total = roundNumber(flt(other_charges_total), 2);
doc.grand_total = roundNumber((flt(net_total) + flt(other_charges_total)), 2);
doc.rounded_total = Math.round(doc.grand_total);
doc.grand_total_export = roundNumber((flt(doc.grand_total) / flt(doc.conversion_rate)), 2);
doc.rounded_total_export = Math.round(doc.grand_total_export);
doc.total_commission = flt(flt(net_total) * flt(doc.commission_rate) / 100);
}
// ******************************* OTHER CHARGES *************************************
cur_frm.cscript.calc_other_charges = function(doc , tname , fname , other_fname) {
doc = locals[doc.doctype][doc.name];
// Make Display Area
cur_frm.fields_dict['other_charges_calculation'].disp_area.innerHTML =
'<b style="padding: 8px 0px;">Calculation Details for Taxes and Charges:</b>';
var cl = getchildren(tname, doc.name, fname);
var tax = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
// Make display table
var otc = make_table(cur_frm.fields_dict['other_charges_calculation'].disp_area,
cl.length + 1, tax.length + 1, '90%', [], { border:'1px solid #AAA', padding:'2px' });
$y(otc,{marginTop:'8px'});
var tax_desc = {}; var tax_desc_rates = []; var net_total = 0;
for(var i=0;i<cl.length;i++) {
net_total += flt(flt(cl[i].qty) * flt(cl[i].basic_rate));
var prev_total = flt(cl[i].amount);
if(cl[i].item_tax_rate) {
try {
var check_tax = JSON.parse(cl[i].item_tax_rate); //to get in dictionary
} catch(exception) {
var check_tax = eval('var a='+cl[i].item_tax_rate+';a'); //to get in dictionary
}
}
// Add Item Code in new Row
$td(otc,i+1,0).innerHTML = cl[i].item_code ? cl[i].item_code : cl[i].description;
//var tax = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
var total = net_total;
for(var t=0;t<tax.length;t++){
var account = tax[t].account_head;
$td(otc,0,t+1).innerHTML = account?account:'';
//Check For Rate
if(cl[i].item_tax_rate && check_tax[account]!=null) {
var rate = flt(check_tax[account]);
} else {
// if particular item doesn't have particular rate it will take other charges rate
var rate = flt(tax[t].rate);
}
//Check For Rate and get tax amount
var tax_amount = cur_frm.cscript.check_charge_type_and_get_tax_amount(doc,tax,t, cl[i], rate);
//enter item_wise_tax_detail i.e. tax rate on each item
var item_wise_tax_detail = cur_frm.cscript.get_item_wise_tax_detail(doc, rate, cl, i, tax, t);
if(tax[t].charge_type != "Actual") tax[t].item_wise_tax_detail += item_wise_tax_detail;
tax[t].total_amount = flt(tax_amount); //stores actual tax amount in virtual field
tax[t].total_tax_amount = flt(prev_total); //stores total amount in virtual field
tax[t].tax_amount += flt(tax_amount);
var total_amount = flt(tax[t].tax_amount);
total_tax_amount = flt(tax[t].total_tax_amount) + flt(total_amount);
set_multiple('Sales Taxes and Charges', tax[t].name, { 'item_wise_tax_detail':tax[t].item_wise_tax_detail, 'amount':roundNumber(flt(total_amount), 2), 'total':roundNumber(flt(total)+flt(tax[t].tax_amount), 2)}, other_fname);
prev_total += flt(tax[t].total_amount); // for previous row total
total += flt(tax[t].tax_amount); // for adding total to previous amount
if(tax[t].charge_type == 'Actual')
$td(otc,i+1,t+1).innerHTML = fmt_money(tax[t].total_amount);
else
$td(otc,i+1,t+1).innerHTML = '('+fmt_money(rate) + '%) ' +fmt_money(tax[t].total_amount);
}
}
for(var t=0;t<tax.length;t++){
tax[t].tax_amount = roundNumber(tax[t].tax_amount, 2);
}
}
cur_frm.cscript.check_charge_type_and_get_tax_amount = function( doc, tax, t, cl, rate, print_amt) {
doc = locals[doc.doctype][doc.name];
if (! print_amt) print_amt = 0;
var tax_amount = 0;
if(tax[t].charge_type == 'Actual') {
var value = flt(tax[t].rate) / flt(doc.net_total); // this give the ratio in which all items are divided
return tax_amount = flt(value) * flt(cl.amount);
}
else if(tax[t].charge_type == 'On Net Total') {
if (flt(print_amt) == 1) {
doc.excise_rate = flt(rate);
doc.total_excise_rate += flt(rate);
refresh_field('excise_rate');
refresh_field('total_excise_rate');
return
}
return tax_amount = (flt(rate) * flt(cl.amount) / 100);
}
else if(tax[t].charge_type == 'On Previous Row Amount'){
if(flt(print_amt) == 1) {
doc.total_excise_rate += flt(flt(doc.excise_rate) * 0.01 * flt(rate));
refresh_field('total_excise_rate');
return
}
var row_no = (tax[t].row_id).toString();
var row = (row_no).split("+"); // splits the values and stores in an array
for(var r = 0;r<row.length;r++){
var id = cint(row[r].replace(/^\s+|\s+$/g,""));
tax_amount += (flt(rate) * flt(tax[id-1].total_amount) / 100);
}
var row_id = row_no.indexOf("/");
if(row_id != -1) {
rate = '';
var row = (row_no).split("/"); // splits the values and stores in an array
if(row.length>2) alert("You cannot enter more than 2 nos. for division");
var id1 = cint(row[0].replace(/^\s+|\s+$/g,""));
var id2 = cint(row[1].replace(/^\s+|\s+$/g,""));
tax_amount = flt(tax[id1-1].total_amount) / flt(tax[id2-1].total_amount);
}
return tax_amount
}
else if(tax[t].charge_type == 'On Previous Row Total') {
if(flt(print_amt) == 1) {
doc.sales_tax_rate += flt(rate);
refresh_field('sales_tax_rate');
return
}
var row = cint(tax[t].row_id);
return tax_amount = flt(rate) * (flt(tax[row-1].total_tax_amount)+flt(tax[row-1].total_amount)) / 100;
}
}
// ********************** Functions for inclusive value calc ******************************
cur_frm.cscript.consider_incl_rate = function(doc, other_fname) {
var tax_list = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
for(var i=0; i<tax_list.length; i++) {
if(tax_list[i].included_in_print_rate) {
return true;
}
}
return false;
}
cur_frm.cscript.back_calc_basic_rate = function(doc, tname, fname, child, other_fname) {
var get_item_tax_rate = function(item, tax) {
if(item.item_tax_rate) {
try {
var item_tax = JSON.parse(item.item_tax_rate);
} catch(exception) {
var item_tax = eval('var a='+item.item_tax_rate+';a');
}
if(item_tax[tax.account_head]!=null) {
return flt(item_tax[tax.account_head]);
}
}
};
var tax_list = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
var total = 1;
var temp_tax_list = [];
var amt = 0;
var item_tax_rate = 0;
var rate = 0;
for(var i=0; i<tax_list.length; i++) {
amt = 0;
item_tax_rate = get_item_tax_rate(child, tax_list[i]);
rate = item_tax_rate ? item_tax_rate : flt(tax_list[i].rate);
if(tax_list[i].included_in_print_rate) {
if(tax_list[i].charge_type=='On Net Total') {
amt = flt(rate / 100);
} else if(tax_list[i].charge_type=='On Previous Row Total') {
amt = flt((rate * temp_tax_list[tax_list[i].row_id-1]['total']) / 100);
} else if(tax_list[i].charge_type=='On Previous Row Amount') {
amt = flt((rate * temp_tax_list[tax_list[i].row_id-1]['amt']) / 100);
}
}
total += flt(amt);
temp_tax_list[i] = {
amt: amt,
total: total
};
}
var basic_rate = (child.export_rate * flt(doc.conversion_rate)) / total;
//console.log(temp_tax_list);
//console.log('in basic rate back calc');
//console.log(basic_rate);
return basic_rate;
}
cur_frm.cscript.included_in_print_rate = function(doc, cdt, cdn) {
var tax = locals[cdt][cdn];
if(tax.included_in_print_rate==1) {
if(!inList(['On Net Total', 'On Previous Row Total', 'On Previous Row Amount'], tax.charge_type)) {
msgprint("'Is this Tax included in Basic Rate?' (i.e. Inclusive Price) is only valid for charges of type: <br /> \
* On Net Total <br /> \
* On Previous Row Amount <br /> \
* On Previous Row Total");
tax.included_in_print_rate = 0;
refresh_field('included_in_print_rate', tax.name, cur_frm.cscript.other_fname);
}
var tax_list = getchildren('Sales Taxes and Charges', doc.name, cur_frm.cscript.other_fname, doc.doctype);
cur_frm.cscript.validate_print_rate_option(doc, tax_list, tax.idx-1);
}
}
// ********************** Update values in table ******************************
cur_frm.cscript.update_fname_table = function(doc , tname , fname , n, other_fname) {
doc = locals[doc.doctype][doc.name]
var net_total = 0
var cl = getchildren(tname, doc.name, fname);
var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, other_fname);
for(var i=0;i<cl.length;i++) {
if(n == 1){
if(!consider_incl_rate) {
if(flt(cl[i].ref_rate) > 0) {
set_multiple(tname, cl[i].name, {
'export_rate': flt(flt(cl[i].ref_rate) * (100 - flt(cl[i].adj_rate)) / 100)
}, fname);
}
set_multiple(tname, cl[i].name, {
'export_amount': flt(flt(cl[i].qty) * flt(cl[i].export_rate)),
'basic_rate': flt(flt(cl[i].export_rate) * flt(doc.conversion_rate)),
'amount': roundNumber(flt((flt(cl[i].export_rate) * flt(doc.conversion_rate)) * flt(cl[i].qty)), 2)
}, fname);
//var base_ref_rate = flt(cl[i].basic_rate) + flt(flt(cl[i].basic_rate) * flt(cl[i].adj_rate) / 100);
//set_multiple(tname, cl[i].name, {
// 'base_ref_rate': flt(base_ref_rate)
//}, fname);
} else if(consider_incl_rate) {
if(flt(cl[i].export_rate) > 0) {
// calculate basic rate based on taxes
// then calculate and set basic_rate, base_ref_rate, ref_rate, amount, export_amount
var ref_rate = flt(cl[i].adj_rate)!=flt(100) ?
flt((100 * flt(cl[i].export_rate))/flt(100 - flt(cl[i].adj_rate))) :
flt(0)
set_multiple(tname, cl[i].name, { 'ref_rate': ref_rate }, fname);
} else if((flt(cl[i].ref_rate) > 0) && (flt(cl[i].adj_rate) > 0)) {
var export_rate = flt(cl[i].ref_rate) * flt(1 - flt(cl[i].adj_rate / 100));
set_multiple(tname, cl[i].name, { 'export_rate': flt(export_rate) }, fname);
}
//console.log("export_rate: " + cl[i].export_rate);
var basic_rate = cur_frm.cscript.back_calc_basic_rate(doc, tname, fname, cl[i], other_fname);
var base_ref_rate = basic_rate + flt(basic_rate * flt(cl[i].adj_rate) / 100);
set_multiple(tname, cl[i].name, {
'basic_rate': flt(basic_rate),
'amount': roundNumber(flt(basic_rate * flt(cl[i].qty)), 2),
'export_amount': flt(flt(cl[i].qty) * flt(cl[i].export_rate)),
'base_ref_rate': flt(base_ref_rate)
}, fname);
}
}
else if(n == 2){
if(flt(cl[i].ref_rate) > 0)
set_multiple(tname, cl[i].name, {'adj_rate': 100 - flt(flt(cl[i].basic_rate) * 100 / (flt(cl[i].ref_rate) * flt(doc.conversion_rate)))}, fname);
set_multiple(tname, cl[i].name, {'amount': flt(flt(cl[i].qty) * flt(cl[i].basic_rate)), 'export_rate': flt(flt(cl[i].basic_rate) / flt(doc.conversion_rate)), 'export_amount': flt((flt(cl[i].basic_rate) / flt(doc.conversion_rate)) * flt(cl[i].qty)) }, fname);
}
/*else if(n == 3){
set_multiple(tname, cl[i].name, {'basic_rate': flt(flt(cl[i].export_rate) * flt(doc.conversion_rate))}, fname);
set_multiple(tname, cl[i].name, {'amount' : flt(flt(cl[i].basic_rate) * flt(cl[i].qty)), 'export_amount': flt(flt(cl[i].export_rate) * flt(cl[i].qty))}, fname);
if(cl[i].ref_rate > 0)
set_multiple(tname, cl[i].name, {'adj_rate': 100 - flt(flt(cl[i].export_rate) * 100 / flt(cl[i].ref_rate)), 'base_ref_rate': flt(flt(cl[i].ref_rate) * flt(doc.conversion_rate)) }, fname);
}*/
net_total += flt(flt(cl[i].qty) * flt(cl[i].basic_rate));
}
doc.net_total = net_total;
refresh_field('net_total');
}
cur_frm.cscript.get_item_wise_tax_detail = function( doc, rate, cl, i, tax, t) {
doc = locals[doc.doctype][doc.name];
var detail = '';
detail = cl[i].item_code + " : " + cstr(rate) + NEWLINE;
return detail;
}
// **************** RE-CALCULATE VALUES ***************************
cur_frm.cscript.recalculate_values = function(doc, cdt, cdn) {
cur_frm.cscript.calculate_charges(doc,cdt,cdn);
}
cur_frm.cscript.validate_print_rate_option = function(doc, taxes, i) {
if(in_list(['On Previous Row Amount','On Previous Row Total'], taxes[i].charge_type)) {
if(!taxes[i].row_id){
alert("Please Enter Row on which amount needs to be calculated for row : "+taxes[i].idx);
validated = false;
} else if(taxes[i].included_in_print_rate && taxes[taxes[i].row_id-1].charge_type=='Actual') {
msgprint("Row of type 'Actual' cannot be depended on for type '" + taxes[i].charge_type + "'\
when using tax inclusive prices.<br />\
This will lead to incorrect values.<br /><br /> \
<b>Please specify correct value in 'Enter Row' column of <span style='color:red'>Row: "
+ taxes[i].idx + "</span> in Taxes table</b>");
validated = false;
taxes[i].included_in_print_rate = 0;
refresh_field('included_in_print_rate', taxes[i].name, other_fname);
} else if ((taxes[i].included_in_print_rate && !taxes[taxes[i].row_id-1].included_in_print_rate) ||
(!taxes[i].included_in_print_rate && taxes[taxes[i].row_id-1].included_in_print_rate)) {
msgprint("If any row in the tax table depends on 'Previous Row Amount/Total', <br />\
'Is this Tax included in Basic Rate?' column should be same for both row <br />\
i.e for that row and the previous row. <br /><br />\
The same is violated for row #"+(i+1)+" and row #"+taxes[i].row_id
);
validated = false;
}
}
}
cur_frm.cscript.calculate_charges = function(doc, cdt, cdn) {
var other_fname = cur_frm.cscript.other_fname;
var cl = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
for(var i = 0; i<cl.length; i++){
cl[i].total_tax_amount = 0;
cl[i].total_amount = 0;
cl[i].tax_amount = 0; // this is done to calculate other charges
cl[i].total = 0;
cur_frm.cscript.validate_print_rate_option(doc, cl, i);
}
cur_frm.cscript.recalc(doc, 1);
}
// Get Sales Partner Commission
// =================================================================================
cur_frm.cscript.sales_partner = function(doc, cdt, cdn){
if(doc.sales_partner){
get_server_fields('get_comm_rate', doc.sales_partner, '', doc, cdt, cdn, 1);
}
}
// *******Commission Rate Trigger (calculates total commission amount)*********
cur_frm.cscript.commission_rate = function(doc, cdt, cdn) {
if(doc.commission_rate > 100){
alert("Commision rate cannot be greater than 100.");
doc.total_commission = 0;
doc.commission_rate = 0;
}
else
doc.total_commission = doc.net_total * doc.commission_rate / 100;
refresh_many(['total_commission','commission_rate']);
}
// *******Total Commission Trigger (calculates commission rate)*********
cur_frm.cscript.total_commission = function(doc, cdt, cdn) {
if(doc.net_total){
if(doc.net_total < doc.total_commission){
alert("Total commission cannot be greater than net total.");
doc.total_commission = 0;
doc.commission_rate = 0;
}
else
doc.commission_rate = doc.total_commission * 100 / doc.net_total;
refresh_many(['total_commission','commission_rate']);
}
}
// Sales Person Allocated % trigger
// ==============================================================================
cur_frm.cscript.allocated_percentage = function(doc, cdt, cdn) {
var fname = cur_frm.cscript.sales_team_fname;
var d = locals[cdt][cdn];
if (d.allocated_percentage) {
d.allocated_amount = flt(flt(doc.net_total)*flt(d.allocated_percentage)/100);
refresh_field('allocated_amount', d.name, fname);
}
}
// Client Side Validation
// =================================================================================
cur_frm.cscript.validate = function(doc, cdt, cdn) {
cur_frm.cscript.validate_items(doc);
var cl = getchildren('Sales Taxes and Charges Master', doc.name, 'other_charges');
for(var i =0;i<cl.length;i++) {
if(!cl[i].amount) {
alert("Please Enter Amount in Row no. "+cl[i].idx+" in Taxes and Charges table");
validated = false;
}
}
cur_frm.cscript.calculate_charges (doc, cdt, cdn);
if (cur_frm.cscript.calc_adjustment_amount) cur_frm.cscript.calc_adjustment_amount(doc);
}
// ************** Atleast one item in document ****************
cur_frm.cscript.validate_items = function(doc) {
var cl = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
if(!cl.length){
alert("Please enter Items for " + doc.doctype);
validated = false;
}
}

View File

@@ -0,0 +1,904 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
@webnotes.whitelist()
def get_comp_base_currency(arg=None):
""" get default currency of company"""
res = webnotes.conn.sql("""select default_currency from `tabCompany`
where name = %s""", webnotes.form_dict.get('company'))
return res and res[0][0] or None
@webnotes.whitelist()
def get_price_list_currency(arg=None):
""" Get all currency in which price list is maintained"""
plc = webnotes.conn.sql("select distinct ref_currency from `tabItem Price` where price_list_name = %s", webnotes.form_dict['price_list'])
plc = [d[0] for d in plc]
base_currency = get_comp_base_currency(webnotes.form_dict['company'])
return plc, base_currency
class DocType(TransactionBase):
def __init__(self,d,dl):
self.doc, self.doclist = d,dl
self.doctype_dict = {
'Sales Order' : 'Sales Order Item',
'Delivery Note' : 'Delivery Note Item',
'Sales Invoice':'Sales Invoice Item',
'Installation Note' : 'Installation Note Item'
}
self.ref_doctype_dict= {}
self.next_dt_detail = {
'delivered_qty' : 'Delivery Note Item',
'billed_qty' : 'Sales Invoice Item',
'installed_qty' : 'Installation Note Item'}
self.msg = []
# Get Sales Person Details
# ==========================
# TODO: To be deprecated if not in use
def get_sales_person_details(self, obj):
if obj.doc.doctype != 'Quotation':
obj.doclist = obj.doc.clear_table(obj.doclist,'sales_team')
idx = 0
for d in webnotes.conn.sql("select sales_person, allocated_percentage, allocated_amount, incentives from `tabSales Team` where parent = '%s'" % obj.doc.customer):
ch = addchild(obj.doc, 'sales_team', 'Sales Team', 1, obj.doclist)
ch.sales_person = d and cstr(d[0]) or ''
ch.allocated_percentage = d and flt(d[1]) or 0
ch.allocated_amount = d and flt(d[2]) or 0
ch.incentives = d and flt(d[3]) or 0
ch.idx = idx
idx += 1
return obj.doclist
# Get customer's contact person details
# ==============================================================
def get_contact_details(self, obj = '', primary = 0):
cond = " and contact_name = '"+cstr(obj.doc.contact_person)+"'"
if primary: cond = " and is_primary_contact = 'Yes'"
contact = webnotes.conn.sql("select contact_name, contact_no, email_id, contact_address from `tabContact` where customer = '%s' and docstatus != 2 %s" %(obj.doc.customer, cond), as_dict = 1)
if not contact:
return
c = contact[0]
obj.doc.contact_person = c['contact_name'] or ''
obj.doc.contact_no = c['contact_no'] or ''
obj.doc.email_id = c['email_id'] or ''
obj.doc.customer_mobile_no = c['contact_no'] or ''
if c['contact_address']:
obj.doc.customer_address = c['contact_address']
# Get customer's primary shipping details
# ==============================================================
def get_shipping_details(self, obj = ''):
det = webnotes.conn.sql("select name, ship_to, shipping_address from `tabShipping Address` where customer = '%s' and docstatus != 2 and ifnull(is_primary_address, 'Yes') = 'Yes'" %(obj.doc.customer), as_dict = 1)
obj.doc.ship_det_no = det and det[0]['name'] or ''
obj.doc.ship_to = det and det[0]['ship_to'] or ''
obj.doc.shipping_address = det and det[0]['shipping_address'] or ''
# get invoice details
# ====================
def get_invoice_details(self, obj = ''):
if obj.doc.company:
acc_head = webnotes.conn.sql("select name from `tabAccount` where name = '%s' and docstatus != 2" % (cstr(obj.doc.customer) + " - " + get_value('Company', obj.doc.company, 'abbr')))
obj.doc.debit_to = acc_head and acc_head[0][0] or ''
# Get Item Details
# ===============================================================
def get_item_details(self, args, obj):
import json
if not obj.doc.price_list_name:
msgprint("Please Select Price List before selecting Items")
raise Exception
item = webnotes.conn.sql("select description, item_name, brand, item_group, stock_uom, default_warehouse, default_income_account, default_sales_cost_center, description_html, barcode from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or end_of_life > now() or end_of_life = '0000-00-00') and (is_sales_item = 'Yes' or is_service_item = 'Yes')" % (args['item_code']), as_dict=1)
tax = webnotes.conn.sql("select tax_type, tax_rate from `tabItem Tax` where parent = %s" , args['item_code'])
t = {}
for x in tax: t[x[0]] = flt(x[1])
ret = {
'description' : item and item[0]['description_html'] or item[0]['description'],
'barcode' : item and item[0]['barcode'] or '',
'item_group' : item and item[0]['item_group'] or '',
'item_name' : item and item[0]['item_name'] or '',
'brand' : item and item[0]['brand'] or '',
'stock_uom' : item and item[0]['stock_uom'] or '',
'reserved_warehouse' : item and item[0]['default_warehouse'] or '',
'warehouse' : item and item[0]['default_warehouse'] or args.get('warehouse'),
'income_account' : item and item[0]['default_income_account'] or args.get('income_account'),
'cost_center' : item and item[0]['default_sales_cost_center'] or args.get('cost_center'),
'qty' : 1.00, # this is done coz if item once fetched is fetched again thn its qty shld be reset to 1
'adj_rate' : 0,
'amount' : 0,
'export_amount' : 0,
'item_tax_rate' : json.dumps(t),
'batch_no' : ''
}
if(obj.doc.price_list_name and item): #this is done to fetch the changed BASIC RATE and REF RATE based on PRICE LIST
base_ref_rate = self.get_ref_rate(args['item_code'], obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
ret['ref_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
ret['export_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
ret['base_ref_rate'] = flt(base_ref_rate)
ret['basic_rate'] = flt(base_ref_rate)
if ret['warehouse'] or ret['reserved_warehouse']:
av_qty = self.get_available_qty({'item_code': args['item_code'], 'warehouse': ret['warehouse'] or ret['reserved_warehouse']})
ret.update(av_qty)
# get customer code for given item from Item Customer Detail
customer_item_code_row = webnotes.conn.sql("""\
select ref_code from `tabItem Customer Detail`
where parent = %s and customer_name = %s""",
(args['item_code'], obj.doc.customer))
if customer_item_code_row and customer_item_code_row[0][0]:
ret['customer_item_code'] = customer_item_code_row[0][0]
return ret
def get_item_defaults(self, args):
item = webnotes.conn.sql("""select default_warehouse, default_income_account, default_sales_cost_center from `tabItem`
where name = '%s' and (ifnull(end_of_life,'') = '' or end_of_life > now() or end_of_life = '0000-00-00')
and (is_sales_item = 'Yes' or is_service_item = 'Yes') """ % (args['item_code']), as_dict=1)
ret = {
'reserved_warehouse' : item and item[0]['default_warehouse'] or '',
'warehouse' : item and item[0]['default_warehouse'] or args.get('warehouse'),
'income_account' : item and item[0]['default_income_account'] or args.get('income_account'),
'cost_center' : item and item[0]['default_sales_cost_center'] or args.get('cost_center')
}
return ret
def get_available_qty(self,args):
tot_avail_qty = webnotes.conn.sql("select projected_qty, actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1)
ret = {
'projected_qty' : tot_avail_qty and flt(tot_avail_qty[0]['projected_qty']) or 0,
'actual_qty' : tot_avail_qty and flt(tot_avail_qty[0]['actual_qty']) or 0
}
return ret
# ***************** Get Ref rate as entered in Item Master ********************
def get_ref_rate(self, item_code, price_list_name, price_list_currency, plc_conv_rate):
ref_rate = webnotes.conn.sql("select ref_rate from `tabItem Price` where parent = %s and price_list_name = %s and ref_currency = %s", (item_code, price_list_name, price_list_currency))
base_ref_rate = ref_rate and flt(ref_rate[0][0]) * flt(plc_conv_rate) or 0
return base_ref_rate
def get_barcode_details(self, barcode):
item = webnotes.conn.sql("select name, end_of_life, is_sales_item, is_service_item \
from `tabItem` where barcode = %s", barcode, as_dict=1)
ret = {}
if not item:
msgprint("""No item found for this barcode: %s.
May be barcode not updated in item master. Please check""" % barcode)
elif item[0]['end_of_life'] and getdate(cstr(item[0]['end_of_life'])) < nowdate():
msgprint("Item: %s has been expired. Please check 'End of Life' field in item master" % item[0]['name'])
elif item[0]['is_sales_item'] == 'No' and item[0]['is_service_item'] == 'No':
msgprint("Item: %s is not a sales or service item" % item[0]['name'])
elif len(item) > 1:
msgprint("There are multiple item for this barcode. \nPlease select item code manually")
else:
ret = {'item_code': item and item[0]['name'] or ''}
return ret
# ****** Re-cancellculates Basic Rate & amount based on Price List Selected ******
def get_adj_percent(self, obj):
for d in getlist(obj.doclist, obj.fname):
base_ref_rate = self.get_ref_rate(d.item_code, obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
d.adj_rate = 0
d.ref_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
d.basic_rate = flt(base_ref_rate)
d.base_ref_rate = flt(base_ref_rate)
d.export_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
d.amount = flt(d.qty)*flt(base_ref_rate)
d.export_amount = flt(d.qty)*flt(base_ref_rate)/flt(obj.doc.conversion_rate)
# Load Default Taxes
# ====================
def load_default_taxes(self, obj):
if cstr(obj.doc.charge):
return self.get_other_charges(obj)
else:
return self.get_other_charges(obj, 1)
# Get other charges from Master
# =================================================================================
def get_other_charges(self,obj, default=0):
obj.doclist = obj.doc.clear_table(obj.doclist, 'other_charges')
if not getlist(obj.doclist, 'other_charges'):
if default: add_cond = 'ifnull(t2.is_default,0) = 1'
else: add_cond = 't1.parent = "'+cstr(obj.doc.charge)+'"'
idx = 0
other_charge = webnotes.conn.sql("""\
select t1.*
from
`tabSales Taxes and Charges` t1,
`tabSales Taxes and Charges Master` t2
where
t1.parent = t2.name and
t2.company = '%s' and
%s
order by t1.idx""" % (obj.doc.company, add_cond), as_dict=1)
from webnotes.model import default_fields
for other in other_charge:
# remove default fields like parent, parenttype etc.
# from query results
for field in default_fields:
if field in other: del other[field]
d = addchild(obj.doc, 'other_charges', 'Sales Taxes and Charges', 1,
obj.doclist)
d.fields.update(other)
d.rate = flt(d.rate)
d.tax_amount = flt(d.tax_rate)
d.included_in_print_rate = cint(d.included_in_print_rate)
d.idx = idx
idx += 1
return obj.doclist
# Get TERMS AND CONDITIONS
# =======================================================================================
def get_tc_details(self,obj):
r = webnotes.conn.sql("select terms from `tabTerms and Conditions` where name = %s", obj.doc.tc_name)
if r: obj.doc.terms = r[0][0]
#---------------------------------------- Get Tax Details -------------------------------#
def get_tax_details(self, item_code, obj):
import json
tax = webnotes.conn.sql("select tax_type, tax_rate from `tabItem Tax` where parent = %s" , item_code)
t = {}
for x in tax: t[x[0]] = flt(x[1])
ret = {
'item_tax_rate' : tax and json.dumps(t) or ''
}
return ret
# Get Serial No Details
# ==========================================================================
def get_serial_details(self, serial_no, obj):
import json
item = webnotes.conn.sql("select item_code, make, label,brand, description from `tabSerial No` where name = '%s' and docstatus != 2" %(serial_no), as_dict=1)
tax = webnotes.conn.sql("select tax_type, tax_rate from `tabItem Tax` where parent = %s" , item[0]['item_code'])
t = {}
for x in tax: t[x[0]] = flt(x[1])
ret = {
'item_code' : item and item[0]['item_code'] or '',
'make' : item and item[0]['make'] or '',
'label' : item and item[0]['label'] or '',
'brand' : item and item[0]['brand'] or '',
'description' : item and item[0]['description'] or '',
'item_tax_rate' : json.dumps(t)
}
return ret
# Get Commission rate
# =======================================================================
def get_comm_rate(self, sales_partner, obj):
comm_rate = webnotes.conn.sql("select commission_rate from `tabSales Partner` where name = '%s' and docstatus != 2" %(sales_partner), as_dict=1)
if comm_rate:
total_comm = flt(comm_rate[0]['commission_rate']) * flt(obj.doc.net_total) / 100
ret = {
'commission_rate' : comm_rate and flt(comm_rate[0]['commission_rate']) or 0,
'total_commission' : flt(total_comm)
}
return ret
else:
msgprint("Business Associate : %s does not exist in the system." % (sales_partner))
raise Exception
# To verify whether rate entered in details table does not exceed max discount %
# =======================================================================================
def validate_max_discount(self,obj, detail_table):
for d in getlist(obj.doclist, detail_table):
discount = webnotes.conn.sql("select max_discount from tabItem where name = '%s'" %(d.item_code),as_dict = 1)
if discount and discount[0]['max_discount'] and (flt(d.adj_rate)>flt(discount[0]['max_discount'])):
msgprint("You cannot give more than " + cstr(discount[0]['max_discount']) + " % discount on Item Code : "+cstr(d.item_code))
raise Exception
# Get sum of allocated % of sales person (it should be 100%)
# ========================================================================
# it indicates % contribution of sales person in sales
def get_allocated_sum(self,obj):
sum = 0
for d in getlist(obj.doclist,'sales_team'):
sum += flt(d.allocated_percentage)
if (flt(sum) != 100) and getlist(obj.doclist,'sales_team'):
msgprint("Total Allocated % of Sales Persons should be 100%")
raise Exception
# Check Conversion Rate (i.e. it will not allow conversion rate to be 1 for Currency other than default currency set in Global Defaults)
# ===========================================================================
def check_conversion_rate(self, obj):
default_currency = TransactionBase().get_company_currency(obj.doc.company)
if not default_currency:
msgprint('Message: Please enter default currency in Company Master')
raise Exception
if (obj.doc.currency == default_currency and flt(obj.doc.conversion_rate) != 1.00) or not obj.doc.conversion_rate or (obj.doc.currency != default_currency and flt(obj.doc.conversion_rate) == 1.00):
msgprint("Please Enter Appropriate Conversion Rate for Customer's Currency to Base Currency (%s --> %s)" % (obj.doc.currency, default_currency), raise_exception = 1)
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"""
il = []
for d in getlist(obj.doclist,obj.fname):
reserved_wh, reserved_qty = '', 0 # used for delivery note
qty = flt(d.qty)
if is_stopped:
qty = flt(d.qty) > flt(d.delivered_qty) and flt(flt(d.qty) - flt(d.delivered_qty)) or 0
if d.prevdoc_doctype == 'Sales Order':
# used in delivery note to reduce reserved_qty
# Eg.: 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.
tot_qty, max_qty, tot_amt, max_amt, reserved_wh = self.get_curr_and_ref_doc_details(d.doctype, 'prevdoc_detail_docname', d.prevdoc_detail_docname, obj.doc.name, obj.doc.doctype)
if((flt(tot_qty) + flt(qty) > flt(max_qty))):
reserved_qty = -(flt(max_qty)-flt(tot_qty))
else:
reserved_qty = - flt(qty)
if obj.doc.doctype == 'Sales Order':
reserved_wh = d.reserved_warehouse
if self.has_sales_bom(d.item_code):
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({
'warehouse': p.warehouse,
'reserved_warehouse': reserved_wh,
'item_code': p.item_code,
'qty': flt(p.qty),
'reserved_qty': (flt(p.qty)/qty)*(reserved_qty),
'uom': p.uom,
'batch_no': p.batch_no,
'serial_no': p.serial_no,
'name': d.name
})
else:
il.append({
'warehouse': d.warehouse,
'reserved_warehouse': reserved_wh,
'item_code': d.item_code,
'qty': qty,
'reserved_qty': reserved_qty,
'uom': d.stock_uom,
'batch_no': d.batch_no,
'serial_no': d.serial_no,
'name': d.name
})
return il
def get_curr_and_ref_doc_details(self, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name, curr_parent_doctype):
""" Get qty, amount already billed or delivered against curr line item for current doctype
For Eg: SO-RV get total qty, amount from SO and also total qty, amount against that SO in RV
"""
#Get total qty, amt of current doctype (eg RV) except for qty, amt of this transaction
if curr_parent_doctype == 'Installation Note':
curr_det = webnotes.conn.sql("select sum(qty) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
qty, amt = curr_det and flt(curr_det[0][0]) or 0, 0
else:
curr_det = webnotes.conn.sql("select sum(qty), sum(amount) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
qty, amt = curr_det and flt(curr_det[0][0]) or 0, curr_det and flt(curr_det[0][1]) or 0
# get total qty of ref doctype
so_det = webnotes.conn.sql("select qty, amount, reserved_warehouse from `tabSales Order Item` where name = '%s' and docstatus = 1"% ref_tab_dn)
max_qty, max_amt, res_wh = so_det and flt(so_det[0][0]) or 0, so_det and flt(so_det[0][1]) or 0, so_det and cstr(so_det[0][2]) or ''
return qty, max_qty, amt, max_amt, res_wh
# Make Packing List from Sales BOM
# =======================================================================
def has_sales_bom(self, item_code):
return webnotes.conn.sql("select name from `tabSales BOM` where new_item_code=%s and docstatus != 2", item_code)
def get_sales_bom_items(self, item_code):
return webnotes.conn.sql("""select t1.item_code, t1.qty, t1.uom
from `tabSales BOM Item` t1, `tabSales BOM` t2
where t2.new_item_code=%s and t1.parent = t2.name""", item_code, as_dict=1)
def get_packing_item_details(self, item):
return webnotes.conn.sql("select item_name, description, stock_uom from `tabItem` where name = %s", item, as_dict = 1)[0]
def get_bin_qty(self, item, warehouse):
det = webnotes.conn.sql("select actual_qty, projected_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (item, warehouse), as_dict = 1)
return det and det[0] or ''
def update_packing_list_item(self,obj, packing_item_code, qty, warehouse, line):
bin = self.get_bin_qty(packing_item_code, warehouse)
item = self.get_packing_item_details(packing_item_code)
# check if exists
exists = 0
for d in getlist(obj.doclist, 'packing_details'):
if d.parent_item == line.item_code and d.item_code == packing_item_code and d.parent_detail_docname == line.name:
pi, exists = d, 1
break
if not exists:
pi = addchild(obj.doc, 'packing_details', 'Delivery Note Packing Item', 1, obj.doclist)
pi.parent_item = line.item_code
pi.item_code = packing_item_code
pi.item_name = item['item_name']
pi.parent_detail_docname = line.name
pi.description = item['description']
pi.uom = item['stock_uom']
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:
pi.batch_no = cstr(line.batch_no)
pi.idx = self.packing_list_idx
# saved, since this function is called on_update of delivery note
pi.save()
self.packing_list_idx += 1
def make_packing_list(self, obj, fname):
"""make packing list for sales bom item"""
self.packing_list_idx = 0
parent_items = []
for d in getlist(obj.doclist, fname):
warehouse = fname == "sales_order_details" and d.reserved_warehouse or d.warehouse
if self.has_sales_bom(d.item_code):
for i in self.get_sales_bom_items(d.item_code):
self.update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), warehouse, d)
if [d.item_code, d.name] not in parent_items:
parent_items.append([d.item_code, d.name])
obj.doclist = self.cleanup_packing_list(obj, parent_items)
return obj.doclist
def cleanup_packing_list(self, obj, parent_items):
"""Remove all those child items which are no longer present in main item table"""
delete_list = []
for d in getlist(obj.doclist, 'packing_details'):
if [d.parent_item, d.parent_detail_docname] not in parent_items:
# mark for deletion from doclist
delete_list.append(d.name)
if not delete_list:
return obj.doclist
# delete from doclist
obj.doclist = filter(lambda d: d.name not in delete_list, obj.doclist)
# delete from db
webnotes.conn.sql("""\
delete from `tabDelivery Note Packing Item`
where name in (%s)"""
% (", ".join(["%s"] * len(delete_list))),
tuple(delete_list))
return obj.doclist
# Get total in words
# ==================================================================
def get_total_in_words(self, currency, amount):
from webnotes.utils import money_in_words
return money_in_words(amount, currency)
# Get month based on date (required in sales person and sales partner)
# ========================================================================
def get_month(self,date):
month_list = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
month_idx = cint(cstr(date).split('-')[1])-1
return month_list[month_idx]
# **** Check for Stop SO as no transactions can be made against Stopped SO. Need to unstop it. ***
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
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:
so_status = webnotes.conn.sql("select status from `tabSales Order` where name = %s",ref_doc_name)
so_status = so_status and so_status[0][0] or ''
if so_status == 'Stopped':
msgprint("You cannot do any transaction against Sales Order : '%s' as it is Stopped." %(ref_doc_name))
raise Exception
# ****** Check for Item.is_sales_item = 'Yes' and Item.docstatus != 2 *******
def check_active_sales_items(self,obj):
for d in getlist(obj.doclist, obj.fname):
if d.item_code: # extra condn coz item_code is not mandatory in RV
valid_item = webnotes.conn.sql("select docstatus,is_sales_item, is_service_item from tabItem where name = %s",d.item_code)
if valid_item and valid_item[0][0] == 2:
msgprint("Item : '%s' does not exist in system." %(d.item_code))
raise Exception
sales_item = valid_item and valid_item[0][1] or 'No'
service_item = valid_item and valid_item[0][2] or 'No'
if sales_item == 'No' and service_item == 'No':
msgprint("Item : '%s' is neither Sales nor Service Item"%(d.item_code))
raise Exception
# **************************************************************************************************************************************************
def check_credit(self,obj,grand_total):
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])
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 validate_fiscal_year(self,fiscal_year,transaction_date,dn):
fy=webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name='%s'"%fiscal_year)
ysd=fy and fy[0][0] or ""
yed=add_days(str(ysd),365)
if str(transaction_date) < str(ysd) or str(transaction_date) > str(yed):
msgprint("%s not within the fiscal year"%(dn))
raise Exception
# get against document date self.prevdoc_date_field
#-----------------------------
def get_prevdoc_date(self, obj):
import datetime
for d in getlist(obj.doclist, obj.fname):
if d.prevdoc_doctype and d.prevdoc_docname:
if d.prevdoc_doctype == 'Sales Invoice':
dt = webnotes.conn.sql("select posting_date from `tab%s` where name = '%s'" % (d.prevdoc_doctype, d.prevdoc_docname))
else:
dt = webnotes.conn.sql("select transaction_date from `tab%s` where name = '%s'" % (d.prevdoc_doctype, d.prevdoc_docname))
d.prevdoc_date = (dt and dt[0][0]) and dt[0][0].strftime('%Y-%m-%d') or ''
def update_prevdoc_detail(self, is_submit, obj):
StatusUpdater(obj, is_submit).update()
#
# make item code readonly if (detail no is set)
#
class StatusUpdater:
"""
Updates the status of the calling records
From Delivery Note
- Update Delivered Qty
- Update Percent
- Validate over delivery
From Sales Invoice
- Update Billed Amt
- Update Percent
- Validate over billing
From Installation Note
- Update Installed Qty
- Update Percent Qty
- Validate over installation
"""
def __init__(self, obj, is_submit):
self.obj = obj # caller object
self.is_submit = is_submit
self.tolerance = {}
self.global_tolerance = None
def update(self):
self.update_all_qty()
self.validate_all_qty()
def validate_all_qty(self):
"""
Validates over-billing / delivery / installation in Delivery Note, Sales Invoice, Installation Note
To called after update_all_qty
"""
if self.obj.doc.doctype=='Delivery Note':
self.validate_qty({
'source_dt' :'Delivery Note Item',
'compare_field' :'delivered_qty',
'compare_ref_field' :'qty',
'target_dt' :'Sales Order Item',
'join_field' :'prevdoc_detail_docname'
})
elif self.obj.doc.doctype=='Sales Invoice':
self.validate_qty({
'source_dt' :'Sales Invoice Item',
'compare_field' :'billed_amt',
'compare_ref_field' :'export_amount',
'target_dt' :'Sales Order Item',
'join_field' :'so_detail'
})
self.validate_qty({
'source_dt' :'Sales Invoice Item',
'compare_field' :'billed_amt',
'compare_ref_field' :'export_amount',
'target_dt' :'Delivery Note Item',
'join_field' :'dn_detail'
}, no_tolerance =1)
elif self.obj.doc.doctype=='Installation Note':
self.validate_qty({
'source_dt' :'Installation Item Details',
'compare_field' :'installed_qty',
'compare_ref_field' :'qty',
'target_dt' :'Delivery Note Item',
'join_field' :'dn_detail'
}, no_tolerance =1)
def get_tolerance_for(self, item_code):
"""
Returns the tolerance for the item, if not set, returns global tolerance
"""
if self.tolerance.get(item_code):
return self.tolerance[item_code]
tolerance = flt(get_value('Item',item_code,'tolerance') or 0)
if not(tolerance):
if self.global_tolerance == None:
self.global_tolerance = flt(get_value('Global Defaults',None,'tolerance') or 0)
tolerance = self.global_tolerance
self.tolerance[item_code] = tolerance
return tolerance
def check_overflow_with_tolerance(self, item, args):
"""
Checks if there is overflow condering a relaxation tolerance
"""
# check if overflow is within tolerance
tolerance = self.get_tolerance_for(item['item_code'])
overflow_percent = ((item[args['compare_field']] - item[args['compare_ref_field']]) / item[args['compare_ref_field']] * 100)
if overflow_percent - tolerance > 0.01:
item['max_allowed'] = flt(item[args['compare_ref_field']] * (100+tolerance)/100)
item['reduce_by'] = item[args['compare_field']] - item['max_allowed']
msgprint("""
Row #%(idx)s: Max %(compare_ref_field)s allowed for <b>Item %(item_code)s</b> against <b>%(parenttype)s %(parent)s</b> is <b>%(max_allowed)s</b>.
If you want to increase your overflow tolerance, please increase tolerance %% in Global Defaults or Item master.
Or, you must reduce the %(compare_ref_field)s by %(reduce_by)s
Also, please check if the order item has already been billed in the Sales Order""" % item, raise_exception=1)
def validate_qty(self, args, no_tolerance=None):
"""
Validates qty at row level
"""
# get unique transactions to update
for d in self.obj.doclist:
if d.doctype == args['source_dt']:
args['name'] = d.fields[args['join_field']]
# get all qty where qty > compare_field
item = webnotes.conn.sql("""
select item_code, `%(compare_ref_field)s`, `%(compare_field)s`, parenttype, parent from `tab%(target_dt)s`
where `%(compare_ref_field)s` < `%(compare_field)s` and name="%(name)s" and docstatus=1
""" % args, as_dict=1)
if item:
item = item[0]
item['idx'] = d.idx
item['compare_ref_field'] = args['compare_ref_field'].replace('_', ' ')
if not item[args['compare_ref_field']]:
msgprint("As %(compare_ref_field)s for item: %(item_code)s in %(parenttype)s: %(parent)s is zero, system will not check over-delivery or over-billed" % item)
elif no_tolerance:
item['reduce_by'] = item[args['compare_field']] - item[args['compare_ref_field']]
if item['reduce_by'] > .01:
msgprint("""
Row #%(idx)s: Max %(compare_ref_field)s allowed for <b>Item %(item_code)s</b> against
<b>%(parenttype)s %(parent)s</b> is <b>""" % item
+ cstr(item[args['compare_ref_field']]) + """</b>.
You must reduce the %(compare_ref_field)s by %(reduce_by)s""" % item, raise_exception=1)
else:
self.check_overflow_with_tolerance(item, args)
def update_all_qty(self):
"""
Updates delivered / billed / installed qty in Sales Order & Delivery Note
"""
if self.obj.doc.doctype=='Delivery Note':
self.update_qty({
'target_field' :'delivered_qty',
'target_dt' :'Sales Order Item',
'target_parent_dt' :'Sales Order',
'target_parent_field' :'per_delivered',
'target_ref_field' :'qty',
'source_dt' :'Delivery Note Item',
'source_field' :'qty',
'join_field' :'prevdoc_detail_docname',
'percent_join_field' :'prevdoc_docname',
'status_field' :'delivery_status',
'keyword' :'Delivered'
})
elif self.obj.doc.doctype=='Sales Invoice':
self.update_qty({
'target_field' :'billed_amt',
'target_dt' :'Sales Order Item',
'target_parent_dt' :'Sales Order',
'target_parent_field' :'per_billed',
'target_ref_field' :'export_amount',
'source_dt' :'Sales Invoice Item',
'source_field' :'export_amount',
'join_field' :'so_detail',
'percent_join_field' :'sales_order',
'status_field' :'billing_status',
'keyword' :'Billed'
})
self.update_qty({
'target_field' :'billed_amt',
'target_dt' :'Delivery Note Item',
'target_parent_dt' :'Delivery Note',
'target_parent_field' :'per_billed',
'target_ref_field' :'export_amount',
'source_dt' :'Sales Invoice Item',
'source_field' :'export_amount',
'join_field' :'dn_detail',
'percent_join_field' :'delivery_note',
'status_field' :'billing_status',
'keyword' :'Billed'
})
if self.obj.doc.doctype=='Installation Note':
self.update_qty({
'target_field' :'installed_qty',
'target_dt' :'Delivery Note Item',
'target_parent_dt' :'Delivery Note',
'target_parent_field' :'per_installed',
'target_ref_field' :'qty',
'source_dt' :'Installation Note Item',
'source_field' :'qty',
'join_field' :'prevdoc_detail_docname',
'percent_join_field' :'prevdoc_docname',
'status_field' :'installation_status',
'keyword' :'Installed'
})
def update_qty(self, args):
"""
Updates qty at row level
"""
# condition to include current record (if submit or no if cancel)
if self.is_submit:
args['cond'] = ' or parent="%s"' % self.obj.doc.name
else:
args['cond'] = ' and parent!="%s"' % self.obj.doc.name
# update quantities in child table
for d in self.obj.doclist:
if d.doctype == args['source_dt']:
# updates qty in the child table
args['detail_id'] = d.fields.get(args['join_field'])
if args['detail_id']:
webnotes.conn.sql("""
update
`tab%(target_dt)s`
set
%(target_field)s = (select sum(%(source_field)s) from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s" and (docstatus=1 %(cond)s))
where
name="%(detail_id)s"
""" % args)
# get unique transactions to update
for name in set([d.fields.get(args['percent_join_field']) for d in self.obj.doclist if d.doctype == args['source_dt']]):
if name:
args['name'] = name
# update percent complete in the parent table
webnotes.conn.sql("""
update
`tab%(target_parent_dt)s`
set
%(target_parent_field)s =
(select sum(if(%(target_ref_field)s > ifnull(%(target_field)s, 0), %(target_field)s, %(target_ref_field)s))/sum(%(target_ref_field)s)*100 from `tab%(target_dt)s` where parent="%(name)s"),
modified = now()
where
name="%(name)s"
""" % args)
# update field
if args['status_field']:
webnotes.conn.sql("""
update
`tab%(target_parent_dt)s`
set
%(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001, 'Not %(keyword)s',
if(%(target_parent_field)s>=99.99, 'Fully %(keyword)s', 'Partly %(keyword)s')
)
where
name="%(name)s"
""" % args)

View File

@@ -0,0 +1,31 @@
# DocType, Sales Common
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:14',
'docstatus': 0,
'modified': '2012-03-27 14:36:14',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'colour': u'White:FFF',
'doctype': 'DocType',
'issingle': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 290
},
# DocType, Sales Common
{
'doctype': 'DocType',
'name': u'Sales Common'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,365 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Module CRM
cur_frm.cscript.tname = "Sales Order Item";
cur_frm.cscript.fname = "sales_order_details";
cur_frm.cscript.other_fname = "other_charges";
cur_frm.cscript.sales_team_fname = "sales_team";
wn.require('erpnext/selling/doctype/sales_common/sales_common.js');
wn.require('erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('erpnext/utilities/doctype/sms_control/sms_control.js');
wn.require('erpnext/setup/doctype/notification_control/notification_control.js');
// ONLOAD
// ================================================================================================
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
if(!doc.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
if(!doc.price_list_currency) set_multiple(cdt, cdn, {price_list_currency: doc.currency, plc_conversion_rate: 1});
// load default charges
if(doc.__islocal && !doc.customer){
hide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group','shipping_address']);
}
}
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
var callback = function(doc, cdt, cdn) {
if(doc.__islocal) {
// defined in sales_common.js
cur_frm.cscript.update_item_details(doc, cdt, cdn);
}
}
cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn, callback);
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.clear_custom_buttons();
erpnext.hide_naming_series();
if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn);
if(doc.customer) $(cur_frm.fields_dict.contact_info.row.wrapper).toggle(true);
else $(cur_frm.fields_dict.contact_info.row.wrapper).toggle(false);
if(doc.docstatus==1) {
if(doc.status != 'Stopped') {
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
// delivery note
if(doc.per_delivered < 100 && doc.order_type=='Sales')
cur_frm.add_custom_button('Make Delivery', cur_frm.cscript['Make Delivery Note']);
// maintenance
if(doc.per_delivered < 100 && (doc.order_type !='Sales')) {
cur_frm.add_custom_button('Make Maint. Visit', cur_frm.cscript.make_maintenance_visit);
cur_frm.add_custom_button('Make Maint. Schedule', cur_frm.cscript['Make Maintenance Schedule']);
}
// indent
if(!doc.order_type || (doc.order_type == 'Sales'))
cur_frm.add_custom_button('Make ' + get_doctype_label('Purchase Request'), cur_frm.cscript['Make Purchase Request']);
// sales invoice
if(doc.per_billed < 100)
cur_frm.add_custom_button('Make Invoice', cur_frm.cscript['Make Sales Invoice']);
// stop
if(doc.per_delivered < 100 || doc.per_billed < 100)
cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Sales Order']);
} else {
// un-stop
cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Sales Order']);
}
}
}
//customer
cur_frm.cscript.customer = function(doc,dt,dn) {
var pl = doc.price_list_name;
var callback = function(r,rt) {
var callback2 = function(r, rt) {
if(doc.customer) unhide_field(['customer_address', 'contact_person', 'territory','customer_group','shipping_address']);
cur_frm.refresh();
if(!onload && (pl != doc.price_list_name)) cur_frm.cscript.price_list_name(doc, dt, dn);
}
var doc = locals[cur_frm.doctype][cur_frm.docname];
get_server_fields('get_shipping_address',doc.customer,'',doc, dt, dn, 0, callback2);
}
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
}
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) 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.fields_dict.customer_address.on_new = function(dn) {
locals['Address'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Address'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict.contact_person.on_new = function(dn) {
locals['Contact'][dn].customer = locals[cur_frm.doctype][cur_frm.docname].customer;
locals['Contact'][dn].customer_name = locals[cur_frm.doctype][cur_frm.docname].customer_name;
}
cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,address_line1,city FROM tabAddress WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
return 'SELECT name,CONCAT(first_name," ",ifnull(last_name,"")) As FullName,department,designation FROM tabContact WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND name LIKE "%s" ORDER BY name ASC LIMIT 50';
}
cur_frm.cscript.pull_quotation_details = function(doc,dt,dn) {
var callback = function(r,rt){
var doc = locals[cur_frm.doctype][cur_frm.docname];
if(r.message){
doc.quotation_no = r.message;
if(doc.quotation_no) {
unhide_field(['quotation_date','customer_address','contact_person','territory','customer_group','shipping_address']);
if(doc.customer) get_server_fields('get_shipping_address',doc.customer,'',doc, dt, dn, 0);
}
cur_frm.refresh();
}
}
$c_obj(make_doclist(doc.doctype, doc.name),'pull_quotation_details','',callback);
}
//================ create new contact ============================================================================
cur_frm.cscript.new_contact = function(){
tn = createLocal('Contact');
locals['Contact'][tn].is_customer = 1;
if(doc.customer) locals['Contact'][tn].customer = doc.customer;
loaddoc('Contact', tn);
}
// DOCTYPE TRIGGERS
// ================================================================================================
// ***************** Get project name *****************
cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) {
var cond = '';
if(doc.customer) cond = '(`tabProject`.customer = "'+doc.customer+'" OR IFNULL(`tabProject`.customer,"")="") AND';
return repl('SELECT `tabProject`.name FROM `tabProject` WHERE `tabProject`.status = "Open" AND %(cond)s `tabProject`.name LIKE "%s" ORDER BY `tabProject`.name ASC LIMIT 50', {cond:cond});
}
//---- get customer details ----------------------------
cur_frm.cscript.project_name = function(doc,cdt,cdn){
$c_obj(make_doclist(doc.doctype, doc.name),'pull_project_customer','', function(r,rt){
refresh_many(['customer','customer_name', 'customer_address', 'contact_person', 'territory', 'contact_no', 'email_id', 'customer_group']);
});
}
// *************** Customized link query for QUOTATION *****************************
cur_frm.fields_dict['quotation_no'].get_query = function(doc) {
var cond='';
if(doc.order_type) cond = ' ifnull(`tabQuotation`.order_type, "") = "'+doc.order_type+'" and';
if(doc.customer) cond += ' ifnull(`tabQuotation`.customer, "") = "'+doc.customer+'" and';
return repl('SELECT DISTINCT name, customer, transaction_date FROM `tabQuotation` WHERE `tabQuotation`.company = "' + doc.company + '" and `tabQuotation`.`docstatus` = 1 and `tabQuotation`.status != "Order Lost" and %(cond)s `tabQuotation`.%(key)s LIKE "%s" ORDER BY `tabQuotation`.`name` DESC LIMIT 50', {cond:cond});
}
// SALES ORDER DETAILS TRIGGERS
// ================================================================================================
// ***************** Get available qty in warehouse of item selected ****************
cur_frm.cscript.reserved_warehouse = function(doc, cdt , cdn) {
var d = locals[cdt][cdn];
if (d.reserved_warehouse) {
arg = "{'item_code':'" + d.item_code + "','warehouse':'" + d.reserved_warehouse +"'}";
get_server_fields('get_available_qty',arg,'sales_order_details',doc,cdt,cdn,1);
}
}
//----------- make maintenance schedule----------
cur_frm.cscript['Make Maintenance Schedule'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
$c_obj(make_doclist(doc.doctype, doc.name),'check_maintenance_schedule','',
function(r,rt){
if(r.message == 'No'){
n = createLocal("Maintenance Schedule");
$c('dt_map', args={
'docs':compress_doclist([locals["Maintenance Schedule"][n]]),
'from_doctype':'Sales Order',
'to_doctype':'Maintenance Schedule',
'from_docname':doc.name,
'from_to_list':"[['Sales Order', 'Maintenance Schedule'], ['Sales Order Item', 'Maintenance Schedule Item']]"
}
, function(r,rt) {
loaddoc("Maintenance Schedule", n);
}
);
}
else{
msgprint("You have already created Maintenance Schedule against this Sales Order");
}
}
);
}
}
//------------ make maintenance visit ------------
cur_frm.cscript.make_maintenance_visit = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
$c_obj(make_doclist(doc.doctype, doc.name),'check_maintenance_visit','',
function(r,rt){
if(r.message == 'No'){
n = createLocal("Maintenance Visit");
$c('dt_map', args={
'docs':compress_doclist([locals["Maintenance Visit"][n]]),
'from_doctype':'Sales Order',
'to_doctype':'Maintenance Visit',
'from_docname':doc.name,
'from_to_list':"[['Sales Order', 'Maintenance Visit'], ['Sales Order Item', 'Maintenance Visit Purpose']]"
}
, function(r,rt) {
loaddoc("Maintenance Visit", n);
}
);
}
else{
msgprint("You have already completed maintenance against this Sales Order");
}
}
);
}
}
// make indent
// ================================================================================================
cur_frm.cscript['Make Purchase Request'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
n = createLocal("Purchase Request");
$c('dt_map', args={
'docs':compress_doclist([locals["Purchase Request"][n]]),
'from_doctype':'Sales Order',
'to_doctype':'Purchase Request',
'from_docname':doc.name,
'from_to_list':"[['Sales Order', 'Purchase Request'], ['Sales Order Item', 'Purchase Request Item']]"
}
, function(r,rt) {
loaddoc("Purchase Request", n);
}
);
}
}
// MAKE DELIVERY NOTE
// ================================================================================================
cur_frm.cscript['Make Delivery Note'] = function() {
var doc = cur_frm.doc;
if (doc.docstatus == 1) {
n = createLocal("Delivery Note");
$c('dt_map', args={
'docs':compress_doclist([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);
}
);
}
}
// MAKE SALES INVOICE
// ================================================================================================
cur_frm.cscript['Make Sales Invoice'] = function() {
var doc = cur_frm.doc;
n = createLocal('Sales Invoice');
$c('dt_map', args={
'docs':compress_doclist([locals['Sales Invoice'][n]]),
'from_doctype':doc.doctype,
'to_doctype':'Sales Invoice',
'from_docname':doc.name,
'from_to_list':"[['Sales Order','Sales Invoice'],['Sales Order Item','Sales Invoice Item'],['Sales Taxes and Charges','Sales Taxes and Charges'],['Sales Team','Sales Team']]"
}, function(r,rt) {
loaddoc('Sales Invoice', n);
}
);
}
// STOP SALES ORDER
// ==================================================================================================
cur_frm.cscript['Stop Sales Order'] = function() {
var doc = cur_frm.doc;
var check = confirm("Are you sure you want to STOP " + doc.name);
if (check) {
$c('runserverobj', args={'method':'stop_sales_order', 'docs': compress_doclist(make_doclist(doc.doctype, doc.name))}, function(r,rt) {
cur_frm.refresh();
});
}
}
// UNSTOP SALES ORDER
// ==================================================================================================
cur_frm.cscript['Unstop Sales Order'] = function() {
var doc = cur_frm.doc;
var check = confirm("Are you sure you want to UNSTOP " + doc.name);
if (check) {
$c('runserverobj', args={'method':'unstop_sales_order', 'docs': compress_doclist(make_doclist(doc.doctype, doc.name))}, function(r,rt) {
cur_frm.refresh();
});
}
}
//get query select Territory
//=======================================================================================================================
cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50';
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
var args = {
type: 'Sales Order',
doctype: 'Sales Order'
}
cur_frm.cscript.notify(doc, args);
}

View File

@@ -0,0 +1,479 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
class DocType(TransactionBase):
def __init__(self, doc, doclist=None):
self.doc = doc
if not doclist: doclist = []
self.doclist = doclist
self.tname = 'Sales Order Item'
self.fname = 'sales_order_details'
self.person_tname = 'Target Detail'
self.partner_tname = 'Partner Target Detail'
self.territory_tname = 'Territory Target Detail'
# Autoname
# ===============
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+'.#####')
# DOCTYPE TRIGGER FUNCTIONS
# =============================
# Pull Quotation Items
# -----------------------
def pull_quotation_details(self):
self.doclist = self.doc.clear_table(self.doclist, 'other_charges')
self.doclist = self.doc.clear_table(self.doclist, 'sales_order_details')
self.doclist = self.doc.clear_table(self.doclist, 'sales_team')
self.doclist = self.doc.clear_table(self.doclist, 'tc_details')
if self.doc.quotation_no:
get_obj('DocType Mapper', 'Quotation-Sales Order').dt_map('Quotation', 'Sales Order', self.doc.quotation_no, self.doc, self.doclist, "[['Quotation', 'Sales Order'],['Quotation Item', 'Sales Order Item'],['Sales Taxes and Charges','Sales Taxes and Charges'],['Sales Team','Sales Team'],['TC Detail','TC Detail']]")
else:
msgprint("Please select Quotation whose details need to pull")
return cstr(self.doc.quotation_no)
#pull project customer
#-------------------------
def pull_project_customer(self):
res = sql("select customer from `tabProject` where name = '%s'"%self.doc.project_name)
if res:
get_obj('DocType Mapper', 'Project-Sales Order').dt_map('Project', 'Sales Order', self.doc.project_name, self.doc, self.doclist, "[['Project', 'Sales Order']]")
# Get contact person details based on customer selected
# ------------------------------------------------------
def get_contact_details(self):
get_obj('Sales Common').get_contact_details(self,0)
# Get Commission rate of Sales Partner
# -------------------------------------
def get_comm_rate(self, sales_partner):
return get_obj('Sales Common').get_comm_rate(sales_partner, self)
# SALES ORDER DETAILS TRIGGER FUNCTIONS
# ================================================================================
# Get Item Details
# ----------------
def get_item_details(self, args=None):
import json
args = args and json.loads(args) or {}
if args.get('item_code'):
return get_obj('Sales Common').get_item_details(args, self)
else:
obj = get_obj('Sales Common')
for doc in self.doclist:
if doc.fields.get('item_code'):
arg = {'item_code':doc.fields.get('item_code'), 'income_account':doc.fields.get('income_account'),
'cost_center': doc.fields.get('cost_center'), 'warehouse': doc.fields.get('warehouse')};
ret = obj.get_item_defaults(arg)
for r in ret:
if not doc.fields.get(r):
doc.fields[r] = ret[r]
# 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 projected qty of item based on warehouse selected
# -----------------------------------------------------
def get_available_qty(self,args):
return get_obj('Sales Common').get_available_qty(eval(args))
# OTHER CHARGES TRIGGER FUNCTIONS
# ====================================================================================
# Get Tax rate if account type is TAX
# ------------------------------------
def get_rate(self,arg):
return get_obj('Sales Common').get_rate(arg)
# Load Default Charges
# ----------------------------------------------------------
def load_default_taxes(self):
self.doclist = get_obj('Sales Common').load_default_taxes(self)
# Pull details from other charges master (Get Sales Taxes and Charges Master)
# ----------------------------------------------------------
def get_other_charges(self):
self.doclist = get_obj('Sales Common').get_other_charges(self)
# GET TERMS & CONDITIONS
# =====================================================================================
def get_tc_details(self):
return get_obj('Sales Common').get_tc_details(self)
#check if maintenance schedule already generated
#============================================
def check_maintenance_schedule(self):
nm = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1", self.doc.name)
nm = nm and nm[0][0] or ''
if not nm:
return 'No'
#check if maintenance visit already generated
#============================================
def check_maintenance_visit(self):
nm = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1 and t1.completion_status='Fully Completed'", self.doc.name)
nm = nm and nm[0][0] or ''
if not nm:
return 'No'
# VALIDATE
# =====================================================================================
# Fiscal Year Validation
# ----------------------
def validate_fiscal_year(self):
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'Sales Order Date')
# Validate values with reference document
#----------------------------------------
def validate_reference_value(self):
get_obj('DocType Mapper', 'Quotation-Sales Order', with_children = 1).validate_reference_value(self, self.doc.name)
# Validate Mandatory
# -------------------
def validate_mandatory(self):
# validate transaction date v/s delivery date
if self.doc.delivery_date:
if getdate(self.doc.transaction_date) > getdate(self.doc.delivery_date):
msgprint("Expected Delivery Date cannot be before Sales Order Date")
raise Exception
# amendment date is necessary if document is amended
if self.doc.amended_from and not self.doc.amendment_date:
msgprint("Please Enter Amendment Date")
raise Exception
# Validate P.O Date
# ------------------
def validate_po(self):
# validate p.o date v/s delivery date
if self.doc.po_date and self.doc.delivery_date and getdate(self.doc.po_date) > getdate(self.doc.delivery_date):
msgprint("Expected Delivery Date cannot be before Purchase Order Date")
raise Exception
if self.doc.po_no and self.doc.customer:
so = webnotes.conn.sql("select name from `tabSales Order` \
where ifnull(po_no, '') = %s and name != %s and docstatus < 2\
and customer = %s", (self.doc.po_no, self.doc.name, self.doc.customer))
if so and so[0][0]:
msgprint("""Another Sales Order (%s) exists against same PO No and Customer.
Please be sure, you are not making duplicate entry.""" % so[0][0])
# Validations of Details Table
# -----------------------------
def validate_for_items(self):
check_list,flag = [],0
chk_dupl_itm = []
# Sales Order Items Validations
for d in getlist(self.doclist, 'sales_order_details'):
if cstr(self.doc.quotation_no) == cstr(d.prevdoc_docname):
flag = 1
if d.prevdoc_docname:
if self.doc.quotation_date and getdate(self.doc.quotation_date) > getdate(self.doc.transaction_date):
msgprint("Sales Order Date cannot be before Quotation Date")
raise Exception
# validates whether quotation no in doctype and in table is same
if not cstr(d.prevdoc_docname) == cstr(self.doc.quotation_no):
msgprint("Items in table does not belong to the Quotation No mentioned.")
raise Exception
# validates whether item is not entered twice
e = [d.item_code, d.description, d.reserved_warehouse, d.prevdoc_docname or '']
f = [d.item_code, d.description]
#check item is stock item
st_itm = sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
if st_itm and st_itm[0][0] == 'Yes':
if e in check_list:
msgprint("Item %s has been entered twice." % d.item_code)
else:
check_list.append(e)
elif st_itm and st_itm[0][0]== 'No':
if f in chk_dupl_itm:
msgprint("Item %s has been entered twice." % d.item_code)
else:
chk_dupl_itm.append(f)
# used for production plan
d.transaction_date = self.doc.transaction_date
d.delivery_date = self.doc.delivery_date
# gets total projected qty of item in warehouse selected (this case arises when warehouse is selected b4 item)
tot_avail_qty = sql("select projected_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d.item_code,d.reserved_warehouse))
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
if flag == 0:
msgprint("There are no items of the quotation selected.")
raise Exception
# validate sales/ maintenance quotation against order type
#------------------------------------------------------------------
def validate_sales_mntc_quotation(self):
for d in getlist(self.doclist, 'sales_order_details'):
if d.prevdoc_docname:
res = sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
if not res:
msgprint("""Order Type (%s) should be same in Quotation: %s \
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname))
def validate_order_type(self):
#validate delivery date
if self.doc.order_type == 'Sales' and not self.doc.delivery_date:
msgprint("Please enter 'Expected Delivery Date'")
raise Exception
self.validate_sales_mntc_quotation()
#check for does customer belong to same project as entered..
#-------------------------------------------------------------------------------------------------
def validate_proj_cust(self):
if self.doc.project_name and self.doc.customer_name:
res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
if not res:
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name))
raise Exception
# Validate
# ---------
def validate(self):
self.validate_fiscal_year()
self.validate_order_type()
self.validate_mandatory()
self.validate_proj_cust()
self.validate_po()
#self.validate_reference_value()
self.validate_for_items()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
sales_com_obj.check_conversion_rate(self)
# verify whether rate is not greater than max_discount
sales_com_obj.validate_max_discount(self,'sales_order_details')
# this is to verify that the allocated % of sales persons is 100%
sales_com_obj.get_allocated_sum(self)
self.doclist = sales_com_obj.make_packing_list(self,'sales_order_details')
# get total in words
dcc = TransactionBase().get_company_currency(self.doc.company)
self.doc.in_words = sales_com_obj.get_total_in_words(dcc, self.doc.rounded_total)
self.doc.in_words_export = sales_com_obj.get_total_in_words(self.doc.currency, self.doc.rounded_total_export)
# set SO status
self.doc.status='Draft'
if not self.doc.billing_status: self.doc.billing_status = 'Not Billed'
if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered'
# ON SUBMIT
# ===============================================================================================
# Checks Quotation Status
# ------------------------
def check_prev_docstatus(self):
for d in getlist(self.doclist, 'sales_order_details'):
cancel_quo = sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname)
if cancel_quo:
msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !")
raise Exception , "Validation Error. "
def update_enquiry_status(self, prevdoc, flag):
enq = sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
if enq:
sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
#update status of quotation, enquiry
#----------------------------------------
def update_prevdoc_status(self, flag):
for d in getlist(self.doclist, 'sales_order_details'):
if d.prevdoc_docname:
if flag=='submit':
sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname)
#update enquiry
self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed')
elif flag == 'cancel':
chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name))
if not chk:
sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname)
#update enquiry
self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
# Submit
# -------
def on_submit(self):
self.check_prev_docstatus()
self.update_stock_ledger(update_stock = 1)
self.set_sms_msg(1)
# update customer's last sales order no.
update_customer = sql("update `tabCustomer` set last_sales_order = '%s', modified = '%s' where name = '%s'" %(self.doc.name, self.doc.modified, self.doc.customer))
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
# Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self)
#update prevdoc status
self.update_prevdoc_status('submit')
# set SO status
set(self.doc, 'status', 'Submitted')
# ON CANCEL
# ===============================================================================================
def on_cancel(self):
# Cannot cancel stopped SO
if self.doc.status == 'Stopped':
msgprint("Sales Order : '%s' cannot be cancelled as it is Stopped. Unstop it for any further transactions" %(self.doc.name))
raise Exception
self.check_nextdoc_docstatus()
self.update_stock_ledger(update_stock = -1)
self.set_sms_msg()
#update prevdoc status
self.update_prevdoc_status('cancel')
# ::::::::: SET SO STATUS ::::::::::
set(self.doc, 'status', 'Cancelled')
# CHECK NEXT DOCSTATUS
# does not allow to cancel document if DN or RV made against it is SUBMITTED
# ----------------------------------------------------------------------------
def check_nextdoc_docstatus(self):
# Checks Delivery Note
submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_dn:
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# Checks Sales Invoice
submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
#check maintenance schedule
submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_ms:
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_mv:
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
def check_modified_date(self):
mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
if date_diff and date_diff[0][0]:
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
raise Exception
# STOP SALES ORDER
# ==============================================================================================
# Stops Sales Order & no more transactions will be created against this Sales Order
def stop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(update_stock = -1,clear = 1)
# ::::::::: SET SO STATUS ::::::::::
set(self.doc, 'status', 'Stopped')
msgprint(self.doc.doctype + ": " + self.doc.name + " has been Stopped. To make transactions against this Sales Order you need to Unstop it.")
# UNSTOP SALES ORDER
# ==============================================================================================
# Unstops Sales Order & now transactions can be continued against this Sales Order
def unstop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(update_stock = 1,clear = 1)
# ::::::::: SET SO STATUS ::::::::::
set(self.doc, 'status', 'Submitted')
msgprint(self.doc.doctype + ": " + self.doc.name + " has been Unstopped.")
# UPDATE STOCK LEDGER
# ===============================================================================================
def update_stock_ledger(self, update_stock, clear = 0):
for d in self.get_item_list(clear):
stock_item = sql("SELECT is_stock_item FROM tabItem where name = '%s'"%(d['item_code']),as_dict = 1)
# stock ledger will be updated only if it is a stock item
if stock_item and stock_item[0]['is_stock_item'] == "Yes":
if not d['reserved_warehouse']:
msgprint("Message: Please enter Reserved Warehouse for item %s as it is stock item."% d['item_code'])
raise Exception
bin = get_obj('Warehouse', d['reserved_warehouse']).update_bin( 0, flt(update_stock) * flt(d['qty']), \
0, 0, 0, d['item_code'], self.doc.transaction_date,doc_type=self.doc.doctype,\
doc_name=self.doc.name, is_amended = (self.doc.amended_from and 'Yes' or 'No'))
# Gets Items from packing list
#=================================
def get_item_list(self, clear):
return get_obj('Sales Common').get_item_list( self, clear)
# SET MESSAGE FOR SMS
#======================
def set_sms_msg(self, is_submitted = 0):
if is_submitted:
if not self.doc.amended_from:
msg = 'Sales Order: '+self.doc.name+' has been made against PO no: '+cstr(self.doc.po_no)
set(self.doc, 'message', msg)
else:
msg = 'Sales Order has been amended. New SO no:'+self.doc.name
set(self.doc, 'message', msg)
else:
msg = 'Sales Order: '+self.doc.name+' has been cancelled.'
set(self.doc, 'message', msg)
# SEND SMS
# =========
def send_sms(self):
if not self.doc.customer_mobile_no:
msgprint("Please enter customer mobile no")
elif not self.doc.message:
msgprint("Please enter the message you want to send")
else:
msgprint(get_obj("SMS Control", "SMS Control").send_sms([self.doc.customer_mobile_no,], self.doc.message))
# on update
def on_update(self):
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// render
wn.doclistviews['Sales Order'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
"`tabSales Order`.customer_name",
"`tabSales Order`.status",
"`tabSales Order`.order_type",
"ifnull(`tabSales Order`.per_delivered,0) as per_delivered",
"ifnull(`tabSales Order`.per_billed,0) as per_billed",
"`tabSales Order`.currency",
"ifnull(`tabSales Order`.grand_total_export,0) as grand_total_export",
"`tabSales Order`.transaction_date",
]);
this.stats = this.stats.concat(['status', 'order_type', 'company']);
},
columns: [
{width: '3%', content: 'check'},
{width: '5%', content: 'avatar'},
{width: '3%', content: 'docstatus'},
{width: '15%', content: 'name'},
{width: '29%', content: 'customer_name+tags', css: {color:'#222'}},
{
width: '18%',
content: function(parent, data) {
$(parent).html(data.currency + ' ' + fmt_money(data.grand_total_export))
},
css: {'text-align':'right'}
},
{
width: '11%',
content: function(parent, data, me) {
var order_type = data.order_type.toLowerCase();
if (order_type === 'sales') {
me.render_icon(parent, 'icon-tag', data.order_type);
me.render_bar_graph(parent, data, 'per_delivered', 'Delivered');
} else if (order_type === 'maintenance') {
me.render_icon(parent, 'icon-wrench', data.order_type);
}
},
},
{width: '8%', content: 'per_billed', type:'bar-graph', label:'Billed'},
{width: '12%', content:'transaction_date',
css: {'text-align': 'right', 'color':'#777'},
title: "Sales Order Date", type: "date"}
]
});

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,444 @@
# DocType, Sales Order Item
[
# These values are common in all dictionaries
{
'creation': '2012-06-08 16:07:58',
'docstatus': 0,
'modified': '2012-07-09 11:05:16',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'autoname': u'SOD/.#####',
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Tray',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 1
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Sales Order Item',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# DocType, Sales Order Item
{
'doctype': 'DocType',
'name': u'Sales Order Item'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_code',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Item Code',
'oldfieldname': u'item_code',
'oldfieldtype': u'Link',
'options': u'Item',
'permlevel': 0,
'reqd': 1,
'search_index': 1,
'trigger': u'Client',
'width': u'150px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_item_code',
'fieldtype': u'Data',
'hidden': 1,
'label': u"Customer's Item Code",
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'item_name',
'fieldtype': u'Data',
'label': u'Item Name',
'oldfieldname': u'item_name',
'oldfieldtype': u'Data',
'permlevel': 0,
'print_hide': 1,
'reqd': 1,
'width': u'150'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'description',
'fieldtype': u'Small Text',
'in_filter': 1,
'label': u'Description',
'oldfieldname': u'description',
'oldfieldtype': u'Small Text',
'permlevel': 0,
'reqd': 1,
'search_index': 1,
'width': u'300px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'qty',
'fieldtype': u'Currency',
'label': u'Quantity',
'oldfieldname': u'qty',
'oldfieldtype': u'Currency',
'permlevel': 0,
'reqd': 1,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'stock_uom',
'fieldtype': u'Data',
'hidden': 0,
'label': u'UOM',
'oldfieldname': u'stock_uom',
'oldfieldtype': u'Data',
'permlevel': 1,
'reqd': 0,
'width': u'70px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'ref_rate',
'fieldtype': u'Currency',
'label': u'Price List Rate',
'oldfieldname': u'ref_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'trigger': u'Client',
'width': u'70px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'adj_rate',
'fieldtype': u'Float',
'label': u'Discount(%)',
'oldfieldname': u'adj_rate',
'oldfieldtype': u'Float',
'permlevel': 0,
'print_hide': 1,
'trigger': u'Client',
'width': u'70px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'export_rate',
'fieldtype': u'Currency',
'label': u'Rate',
'oldfieldname': u'export_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'reqd': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'export_amount',
'fieldtype': u'Currency',
'label': u'Amount',
'no_copy': 0,
'oldfieldname': u'export_amount',
'oldfieldtype': u'Currency',
'permlevel': 1,
'reqd': 0,
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'base_ref_rate',
'fieldtype': u'Currency',
'label': u'Price List Rate*',
'oldfieldname': u'base_ref_rate',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'basic_rate',
'fieldtype': u'Currency',
'label': u'Basic Rate*',
'oldfieldname': u'basic_rate',
'oldfieldtype': u'Currency',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'amount',
'fieldtype': u'Currency',
'label': u'Amount*',
'no_copy': 0,
'oldfieldname': u'amount',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'reqd': 0,
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'reserved_warehouse',
'fieldtype': u'Link',
'label': u'Reserved Warehouse',
'no_copy': 1,
'oldfieldname': u'reserved_warehouse',
'oldfieldtype': u'Link',
'options': u'Warehouse',
'permlevel': 0,
'print_hide': 1,
'reqd': 0,
'trigger': u'Client',
'width': u'150px'
},
# DocField
{
'colour': u'White:FFF',
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'projected_qty',
'fieldtype': u'Currency',
'hidden': 1,
'label': u'Projected Qty',
'no_copy': 1,
'oldfieldname': u'projected_qty',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'width': u'70px'
},
# DocField
{
'colour': u'White:FFF',
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'actual_qty',
'fieldtype': u'Currency',
'label': u'Actual Qty',
'no_copy': 1,
'permlevel': 1,
'print_hide': 1,
'width': u'70px'
},
# DocField
{
'colour': u'White:FFF',
'default': u'0.00',
'doctype': u'DocField',
'fieldname': u'delivered_qty',
'fieldtype': u'Currency',
'hidden': 0,
'in_filter': 0,
'label': u'Delivered Qty',
'no_copy': 1,
'oldfieldname': u'delivered_qty',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'search_index': 0,
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'billed_amt',
'fieldtype': u'Currency',
'label': u'Billed Amt',
'no_copy': 1,
'permlevel': 1,
'print_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'For Production',
'doctype': u'DocField',
'fieldname': u'planned_qty',
'fieldtype': u'Currency',
'hidden': 1,
'label': u'Planned Quantity',
'no_copy': 1,
'oldfieldname': u'planned_qty',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'report_hide': 1,
'width': u'50px'
},
# DocField
{
'colour': u'White:FFF',
'description': u'For Production',
'doctype': u'DocField',
'fieldname': u'produced_qty',
'fieldtype': u'Currency',
'hidden': 1,
'label': u'Produced Quantity',
'oldfieldname': u'produced_qty',
'oldfieldtype': u'Currency',
'permlevel': 1,
'print_hide': 1,
'report_hide': 1,
'width': u'50px'
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'brand',
'fieldtype': u'Link',
'hidden': 1,
'in_filter': 1,
'label': u'Brand Name',
'oldfieldname': u'brand',
'oldfieldtype': u'Link',
'options': u'Brand',
'permlevel': 1,
'print_hide': 1,
'search_index': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'item_group',
'fieldtype': u'Link',
'hidden': 1,
'in_filter': 1,
'label': u'Item Group',
'oldfieldname': u'item_group',
'oldfieldtype': u'Link',
'options': u'Item Group',
'permlevel': 1,
'print_hide': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'prevdoc_docname',
'fieldtype': u'Link',
'hidden': 0,
'in_filter': 1,
'label': u'Quotation No.',
'oldfieldname': u'prevdoc_docname',
'oldfieldtype': u'Link',
'options': u'Quotation',
'permlevel': 1,
'print_hide': 1,
'search_index': 1
},
# DocField
{
'allow_on_submit': 1,
'doctype': u'DocField',
'fieldname': u'page_break',
'fieldtype': u'Check',
'label': u'Page Break',
'oldfieldname': u'page_break',
'oldfieldtype': u'Check',
'permlevel': 0,
'print_hide': 1,
'report_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'item_tax_rate',
'fieldtype': u'Small Text',
'hidden': 1,
'label': u'Item Tax Rate',
'oldfieldname': u'item_tax_rate',
'oldfieldtype': u'Small Text',
'permlevel': 1,
'print_hide': 1,
'report_hide': 1
},
# DocField
{
'colour': u'White:FFF',
'description': u'The date at which current entry is made in system.',
'doctype': u'DocField',
'fieldname': u'transaction_date',
'fieldtype': u'Date',
'hidden': 1,
'in_filter': 0,
'label': u'Sales Order Date',
'oldfieldname': u'transaction_date',
'oldfieldtype': u'Date',
'permlevel': 1,
'print_hide': 1,
'report_hide': 1,
'search_index': 0
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,128 @@
# DocType, Sales Team
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:17',
'docstatus': 0,
'modified': '2012-03-27 14:36:17',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'colour': u'White:FFF',
'doctype': 'DocType',
'istable': 1,
'module': u'Selling',
'name': '__common__',
'section_style': u'Tray',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 5
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Sales Team',
'parentfield': u'fields',
'parenttype': u'DocType',
'permlevel': 0
},
# DocType, Sales Team
{
'doctype': 'DocType',
'name': u'Sales Team'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'sales_person',
'fieldtype': u'Link',
'in_filter': 1,
'label': u'Sales Person',
'oldfieldname': u'sales_person',
'oldfieldtype': u'Link',
'options': u'Sales Person',
'reqd': 1,
'search_index': 1,
'width': u'200px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'sales_designation',
'fieldtype': u'Data',
'label': u'Designation',
'oldfieldname': u'sales_designation',
'oldfieldtype': u'Data',
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'contact_no',
'fieldtype': u'Data',
'hidden': 1,
'label': u'Contact No.',
'oldfieldname': u'contact_no',
'oldfieldtype': u'Data',
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'allocated_percentage',
'fieldtype': u'Currency',
'label': u'Allocated (%)',
'oldfieldname': u'allocated_percentage',
'oldfieldtype': u'Currency',
'reqd': 0,
'trigger': u'Client',
'width': u'100px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'allocated_amount',
'fieldtype': u'Currency',
'label': u'Allocated Amount',
'oldfieldname': u'allocated_amount',
'oldfieldtype': u'Currency',
'reqd': 0,
'width': u'120px'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'parenttype',
'fieldtype': u'Data',
'hidden': 1,
'in_filter': 1,
'label': u'Parenttype',
'oldfieldname': u'parenttype',
'oldfieldtype': u'Data',
'print_hide': 1,
'search_index': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'incentives',
'fieldtype': u'Currency',
'label': u'Incentives',
'oldfieldname': u'incentives',
'oldfieldtype': u'Currency'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,20 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Get Customer Details
// =====================================================================
cur_frm.add_fetch('customer','customer_name','customer_name');
cur_frm.add_fetch('customer','address','customer_address');

View File

@@ -0,0 +1,42 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
sql = webnotes.conn.sql
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
# on update
# ----------
def on_update(self):
self.update_primary_shipping_address()
self.get_customer_details()
# set is_primary_address for other shipping addresses belonging to same customer
# -------------------------------------------------------------------------------
def update_primary_shipping_address(self):
if self.doc.is_primary_address == 'Yes':
sql("update `tabShipping Address` set is_primary_address = 'No' where customer = %s and is_primary_address = 'Yes' and name != %s",(self.doc.customer, self.doc.name))
# Get Customer Details
# ---------------------
def get_customer_details(self):
det = sql("select customer_name, address from tabCustomer where name = '%s'" % (self.doc.customer))
self.doc.customer_name = det and det[0][0] or ''
self.doc.customer_address = det and det[0][1] or ''

View File

@@ -0,0 +1,181 @@
# DocType, Shipping Address
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:17',
'docstatus': 0,
'modified': '2012-03-27 14:36:17',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'allow_trash': 1,
'autoname': u'SA.#####',
'colour': u'White:FFF',
'doctype': 'DocType',
'document_type': u'Master',
'module': u'Selling',
'name': '__common__',
'search_fields': u'customer, ship_to, shipping_address',
'section_style': u'Simple',
'show_in_menu': 0,
'version': 8
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'Shipping Address',
'parentfield': u'fields',
'parenttype': u'DocType'
},
# These values are common for all DocPerm
{
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'Shipping Address',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1
},
# DocType, Shipping Address
{
'doctype': 'DocType',
'name': u'Shipping Address'
},
# DocPerm
{
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Master Manager',
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Master Manager'
},
# DocPerm
{
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales Manager',
'write': 1
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales Manager'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break0',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer',
'fieldtype': u'Link',
'label': u'Customer',
'options': u'Customer',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_name',
'fieldtype': u'Data',
'label': u'Customer Name',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'customer_address',
'fieldtype': u'Text',
'label': u'Customer Address',
'permlevel': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'ship_to',
'fieldtype': u'Data',
'label': u'Ship To',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'shipping_address',
'fieldtype': u'Text',
'label': u'Shipping Address',
'permlevel': 0,
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'permlevel': 0,
'width': u'50%'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'is_primary_address',
'fieldtype': u'Select',
'label': u'Is Primary Address',
'options': u'Yes\nNo',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'shipping_details',
'fieldtype': u'Text Editor',
'label': u'Shipping Details',
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'trash_reason',
'fieldtype': u'Small Text',
'label': u'Trash Reason',
'permlevel': 1
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,82 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
# ----------
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
def create_receiver_list(self):
rec, where_clause = '', ''
if self.doc.send_to == 'All Customer Contact':
where_clause = self.doc.customer and " and customer = '%s'" % self.doc.customer or " and ifnull(is_customer, 0) = 1"
if self.doc.send_to == 'All Supplier Contact':
where_clause = self.doc.supplier and " and ifnull(is_supplier, 0) = 1 and supplier = '%s'" % self.doc.supplier or " and ifnull(is_supplier, 0) = 1"
if self.doc.send_to == 'All Sales Partner Contact':
where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_aprtner = '%s'" % self.doc.sales_partner or " and ifnull(is_sales_partner, 0) = 1"
if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
elif self.doc.send_to == 'All Lead (Open)':
rec = sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
elif self.doc.send_to == 'All Employee (Active)':
where_clause = self.doc.department and " and t1.department = '%s'" % self.doc.department or ""
where_clause += self.doc.branch and " and t1.branch = '%s'" % self.doc.branch or ""
rec = sql("select t1.employee_name, t2.cell_number from `tabEmployee` t1, `tabEmployee Profile` t2 where t2.employee = t1.name and t1.status = 'Active' and t1.docstatus != 2 and ifnull(t2.cell_number,'')!='' %s" % where_clause)
elif self.doc.send_to == 'All Sales Person':
rec = sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
rec_list = ''
for d in rec:
rec_list += d[0] + ' - ' + d[1] + '\n'
self.doc.receiver_list = rec_list
def get_receiver_nos(self):
receiver_nos = []
for d in self.doc.receiver_list.split('\n'):
receiver_no = d
if '-' in d:
receiver_no = receiver_no.split('-')[1]
if receiver_no.strip():
receiver_nos.append(cstr(receiver_no).strip())
return receiver_nos
def send_sms(self):
if not self.doc.message:
msgprint("Please enter message before sending")
else:
receiver_list = self.get_receiver_nos()
if receiver_list:
msgprint(get_obj('SMS Control', 'SMS Control').send_sms(receiver_list, cstr(self.doc.message)))

View File

@@ -0,0 +1,185 @@
# DocType, SMS Center
[
# These values are common in all dictionaries
{
'creation': '2012-03-27 14:36:17',
'docstatus': 0,
'modified': '2012-03-27 14:36:17',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all DocType
{
'_last_update': u'1322549700',
'allow_attach': 0,
'allow_copy': 1,
'allow_email': 1,
'allow_print': 1,
'colour': u'White:FFF',
'default_print_format': u'Standard',
'doctype': 'DocType',
'hide_heading': 0,
'hide_toolbar': 0,
'in_create': 0,
'issingle': 1,
'menu_index': 4,
'module': u'Selling',
'name': '__common__',
'read_only': 1,
'section_style': u'Simple',
'server_code_error': u' ',
'show_in_menu': 1,
'version': 41
},
# These values are common for all DocField
{
'doctype': u'DocField',
'name': '__common__',
'parent': u'SMS Center',
'parentfield': u'fields',
'parenttype': u'DocType',
'permlevel': 0
},
# These values are common for all DocPerm
{
'doctype': u'DocPerm',
'name': '__common__',
'parent': u'SMS Center',
'parentfield': u'permissions',
'parenttype': u'DocType',
'read': 1,
'role': u'System Manager'
},
# DocType, SMS Center
{
'doctype': 'DocType',
'name': u'SMS Center'
},
# DocPerm
{
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'write': 1
},
# DocPerm
{
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'write': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break1',
'fieldtype': u'Column Break',
'width': u'50%'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'send_to',
'fieldtype': u'Select',
'label': u'Send To',
'options': u'\nAll Contact\nAll Customer Contact\nAll Supplier Contact\nAll Sales Partner Contact\nAll Lead (Open)\nAll Employee (Active)\nAll Sales Person',
'trigger': u'Client'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.send_to=='All Customer Contact'",
'doctype': u'DocField',
'fieldname': u'customer',
'fieldtype': u'Link',
'label': u'Customer',
'options': u'Customer'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.send_to=='All Supplier Contact'",
'doctype': u'DocField',
'fieldname': u'supplier',
'fieldtype': u'Link',
'label': u'Supplier',
'options': u'Supplier'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.send_to=='All Employee (Active)'",
'doctype': u'DocField',
'fieldname': u'department',
'fieldtype': u'Select',
'label': u'Department',
'options': u'link:Department'
},
# DocField
{
'colour': u'White:FFF',
'depends_on': u"eval:doc.send_to=='All Employee (Active)'",
'doctype': u'DocField',
'fieldname': u'branch',
'fieldtype': u'Select',
'label': u'Branch',
'options': u'link:Branch'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'create_receiver_list',
'fieldtype': u'Button',
'label': u'Create Receiver List',
'options': u'create_receiver_list'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'receiver_list',
'fieldtype': u'Code',
'label': u'Receiver List'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'column_break9',
'fieldtype': u'Column Break',
'width': u'50%'
},
# DocField
{
'description': u'Message greater than 160 character will be splitted into multiple mesage',
'doctype': u'DocField',
'fieldname': u'message',
'fieldtype': u'Text',
'label': u'Message',
'reqd': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'send_sms',
'fieldtype': u'Button',
'label': u'Send SMS',
'options': u'send_sms'
}
]

1
selling/page/__init__.py Normal file
View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

View File

@@ -0,0 +1,264 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
wn.pages['sales-analytics'].onload = function(wrapper) {
wn.ui.make_app_page({
parent: wrapper,
title: 'Sales Analytics',
single_column: true
});
new erpnext.SalesAnalytics(wrapper);
}
erpnext.SalesAnalytics = wn.views.TreeGridReport.extend({
init: function(wrapper) {
this._super({
title: "Sales Analytics",
page: wrapper,
parent: $(wrapper).find('.layout-main'),
appframe: wrapper.appframe,
doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company",
"Sales Invoice", "Sales Invoice Item", "Territory"],
tree_grid: { show: true }
});
this.tree_grids = {
"Customer Group": {
label: "Customer Group / Customer",
show: true,
item_key: "customer",
parent_field: "parent_customer_group",
formatter: function(item) {
// return repl('<a href="#Report2/stock-invoices/customer=%(enc_value)s">%(value)s</a>', {
// value: item.name,
// enc_value: encodeURIComponent(item.name)
// });
return item.name;
}
},
"Customer": {
label: "Customer",
show: false,
item_key: "customer",
formatter: function(item) {
return item.name;
}
},
"Item Group": {
label: "Item",
show: true,
parent_field: "parent_item_group",
item_key: "item_code",
formatter: function(item) {
return item.name;
}
},
"Item": {
label: "Item",
show: false,
item_key: "item_code",
formatter: function(item) {
return item.name;
}
},
"Territory": {
label: "Territory / Customer",
show: true,
item_key: "customer",
parent_field: "parent_territory",
formatter: function(item) {
return item.name;
}
}
}
},
setup_columns: function() {
this.tree_grid = this.tree_grids[this.tree_type];
var std_columns = [
{id: "check", name: "Plot", field: "check", width: 30,
formatter: this.check_formatter},
{id: "name", name: this.tree_grid.label, field: "name", width: 300,
formatter: this.tree_formatter},
{id: "total", name: "Total", field: "total", plot: false,
formatter: this.currency_formatter}
];
this.make_date_range_columns();
this.columns = std_columns.concat(this.columns);
},
filters: [
{fieldtype:"Select", label: "Tree Type", options:["Customer Group", "Customer",
"Item Group", "Item", "Territory"],
filter: function(val, item, opts, me) {
return me.apply_zero_filter(val, item, opts, me);
}},
{fieldtype:"Select", label: "Value or Qty", options:["Value", "Quantity"]},
{fieldtype:"Select", label: "Company", link:"Company",
default_value: "Select Company..."},
{fieldtype:"Date", label: "From Date"},
{fieldtype:"Label", label: "To"},
{fieldtype:"Date", label: "To Date"},
{fieldtype:"Select", label: "Range",
options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]},
{fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"},
{fieldtype:"Button", label: "Reset Filters"}
],
setup_filters: function() {
var me = this;
this._super();
this.filter_inputs.value_or_qty.change(function() {
me.filter_inputs.refresh.click();
});
this.filter_inputs.tree_type.change(function() {
me.filter_inputs.refresh.click();
});
this.show_zero_check()
this.setup_plot_check();
},
init_filter_values: function() {
this._super();
this.filter_inputs.range.val('Weekly');
},
prepare_data: function() {
var me = this;
if (!this.tl) {
this.make_transaction_list("Sales Invoice", "Sales Invoice Item");
// add 'Not Set' Customer & Item
// (Customer / Item are not mandatory!!)
wn.report_dump.data["Customer"].push({
name: "Not Set",
parent_customer_group: "All Customer Groups",
parent_territory: "All Territories",
id: "Not Set",
});
wn.report_dump.data["Item"].push({
name: "Not Set",
parent_item_group: "All Item Groups",
id: "Not Set",
});
}
if(!this.data || me.item_type != me.tree_type) {
if(me.tree_type=='Customer') {
var items = wn.report_dump.data["Customer"];
} if(me.tree_type=='Customer Group') {
var items = this.prepare_tree("Customer", "Customer Group");
} else if(me.tree_type=="Item Group") {
var items = this.prepare_tree("Item", "Item Group");
} else if(me.tree_type=="Item") {
var items = wn.report_dump.data["Item"];
} else if(me.tree_type=="Territory") {
var items = this.prepare_tree("Customer", "Territory");
}
me.item_type = me.tree_type
me.parent_map = {};
me.item_by_name = {};
me.data = [];
$.each(items, function(i, v) {
var d = copy_dict(v);
me.data.push(d);
me.item_by_name[d.name] = d;
if(d[me.tree_grid.parent_field]) {
me.parent_map[d.name] = d[me.tree_grid.parent_field];
}
me.reset_item_values(d);
});
this.set_indent();
} else {
// otherwise, only reset values
$.each(this.data, function(i, d) {
me.reset_item_values(d);
});
}
this.prepare_balances();
if(me.tree_grid.show) {
this.set_totals(false);
this.update_groups();
} else {
this.set_totals(true);
}
},
prepare_balances: function() {
var me = this;
var from_date = dateutil.str_to_obj(this.from_date);
var to_date = dateutil.str_to_obj(this.to_date);
var is_val = this.value_or_qty == 'Value';
$.each(this.tl, function(i, tl) {
if (me.is_default('company') ? true : me.apply_filter(tl, "company")) {
var posting_date = dateutil.str_to_obj(tl.posting_date);
if (posting_date >= from_date && posting_date <= to_date) {
var item = me.item_by_name[tl[me.tree_grid.item_key]] || me.item_by_name['Not Set'];
item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty);
}
}
});
},
update_groups: function() {
var me = this;
$.each(this.data, function(i, item) {
var parent = me.parent_map[item.name];
while(parent) {
parent_group = me.item_by_name[parent];
$.each(me.columns, function(c, col) {
if (col.formatter == me.currency_formatter) {
parent_group[col.field] =
flt(parent_group[col.field])
+ flt(item[col.field]);
}
});
parent = me.parent_map[parent];
}
});
},
set_totals: function(sort) {
var me = this;
var checked = false;
$.each(this.data, function(i, d) {
d.total = 0.0;
$.each(me.columns, function(i, col) {
if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total")
d.total += d[col.field];
if(d.checked) checked = true;
})
});
if(sort)this.data = this.data.sort(function(a, b) { return a.total < b.total; });
if(!this.checked) {
this.data[0].checked = true;
}
},
get_plot_points: function(item, col, idx) {
return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]],
[dateutil.user_to_obj(col.name).getTime(), item[col.field]]];
}
});

View File

@@ -0,0 +1,28 @@
# Page, sales-analytics
[
# These values are common in all dictionaries
{
u'creation': '2012-09-21 12:06:14',
u'docstatus': 0,
u'modified': '2012-09-21 12:06:14',
u'modified_by': u'Administrator',
u'owner': u'Administrator'
},
# These values are common for all Page
{
u'doctype': u'Page',
'module': u'Selling',
u'name': u'__common__',
'page_name': u'sales-analytics',
'standard': u'Yes',
'title': u'Sales Analytics'
},
# Page, sales-analytics
{
u'doctype': u'Page',
u'name': u'sales-analytics'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,14 @@
span.tree-node-toolbar {
padding: 2px;
margin-left: 15px;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-color: #ddd;
}
.tree-area a.selected {
font-weight: bold;
text-decoration: underline;
}

View File

@@ -0,0 +1,11 @@
<div class="layout-wrapper layout-wrapper-background">
<div class="appframe-area"></div>
<div class="layout-main-section">
<div class="tree-area"></div>
</div>
<div class="layout-side-section">
<div class="help">To add child nodes, explore tree and click on the node under which you want to add more nodes.
</div>
</div>
<div class="clear"></div>
</div>

View File

@@ -0,0 +1,144 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pscript['onload_Sales Browser'] = function(wrapper){
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.appframe-area'));
wrapper.appframe.add_button('Refresh', function() {
wrapper.make_tree();
}, 'icon-refresh');
wrapper.make_tree = function() {
var ctype = wn.get_route()[1] || 'Territory';
erpnext.sales_chart = new erpnext.SalesChart(ctype, wrapper);
}
wrapper.make_tree();
}
pscript['onshow_Sales Browser'] = function(wrapper){
// set route
var ctype = wn.get_route()[1] || 'Territory';
wrapper.appframe.clear_breadcrumbs();
wrapper.appframe.add_breadcrumb(ctype+' Tree')
document.title = ctype+' Tree';
wrapper.appframe.add_breadcrumb(' in <a href="#!selling-home">Selling</a>');
if(erpnext.sales_chart && erpnext.sales_chart.ctype != ctype) {
wrapper.make_tree();
}
};
erpnext.SalesChart = Class.extend({
init: function(ctype, wrapper) {
var root_nodes = {
'Territory': 'All Territories',
'Item Group': 'All Item Groups',
'Customer Group': 'All Customer Groups',
'Sales Person': 'All Sales Persons'
}
$(wrapper).find('.tree-area').empty();
var me = this;
me.ctype = ctype;
this.tree = new wn.ui.Tree({
parent: $(wrapper).find('.tree-area'),
label: root_nodes[ctype],
args: {ctype: ctype},
method: 'selling.page.sales_browser.sales_browser.get_children',
click: function(link) {
if(me.cur_toolbar)
$(me.cur_toolbar).toggle(false);
if(!link.toolbar)
me.make_link_toolbar(link);
if(link.toolbar) {
me.cur_toolbar = link.toolbar;
$(me.cur_toolbar).toggle(true);
}
}
});
this.tree.rootnode.$a
.data('node-data', {value: root_nodes[ctype], expandable:1})
.click();
},
make_link_toolbar: function(link) {
var data = $(link).data('node-data');
if(!data) return;
link.toolbar = $('<span class="tree-node-toolbar"></span>').insertAfter(link);
// edit
var node_links = [];
if (wn.boot.profile.can_read.indexOf(this.ctype) !== -1) {
node_links.push('<a href="#!Form/'+encodeURIComponent(this.ctype)+'/'
+encodeURIComponent(data.value)+'">Edit</a>');
}
if(data.expandable) {
if (wn.boot.profile.can_create.indexOf(this.ctype) !== -1 ||
wn.boot.profile.in_create.indexOf(this.ctype) !== -1) {
node_links.push('<a onclick="erpnext.sales_chart.new_node();">Add Child</a>');
}
}
link.toolbar.append(node_links.join(" | "));
},
new_node: function() {
var me = this;
// the dialog
var d = new wn.ui.Dialog({
title:'New ' + me.ctype,
fields: [
{fieldtype:'Data', fieldname: 'name_field', label:'New ' + me.ctype + ' Name', reqd:true},
{fieldtype:'Select', fieldname:'is_group', label:'Group Node',
options:'No\nYes', description:'Entries can made only against non-group (leaf) nodes'},
{fieldtype:'Button', fieldname:'create_new', label:'Create New' }
]
})
// create
$(d.fields_dict.create_new.input).click(function() {
var btn = this;
$(btn).set_working();
var v = d.get_values();
if(!v) return;
var node = me.selected_node();
v.parent = node.data('label');
v.ctype = me.ctype;
wn.call({
method: 'selling.page.sales_browser.sales_browser.add_node',
args: v,
callback: function() {
$(btn).done_working();
d.hide();
node.trigger('reload');
}
})
});
d.show();
},
selected_node: function() {
return this.tree.$w.find('.tree-link.selected');
}
});

View File

@@ -0,0 +1,26 @@
from __future__ import unicode_literals
import webnotes
@webnotes.whitelist()
def get_children():
ctype = webnotes.form_dict.get('ctype')
webnotes.form_dict['parent_field'] = 'parent_' + ctype.lower().replace(' ', '_')
return webnotes.conn.sql("""select name as value,
if(is_group='Yes', 1, 0) as expandable
from `tab%(ctype)s`
where docstatus < 2
and %(parent_field)s = "%(parent)s"
order by name""" % webnotes.form_dict, as_dict=1)
@webnotes.whitelist()
def add_node():
from webnotes.model.doc import Document
ctype = webnotes.form_dict.get('ctype')
parent_field = 'parent_' + ctype.lower().replace(' ', '_')
d = Document(ctype)
d.fields[ctype.lower().replace(' ', '_') + '_name'] = webnotes.form_dict['name_field']
d.fields[parent_field] = webnotes.form_dict['parent']
d.is_group = webnotes.form_dict['is_group']
d.save()

View File

@@ -0,0 +1,51 @@
# Page, Sales Browser
[
# These values are common in all dictionaries
{
'creation': '2010-12-14 10:23:21',
'docstatus': 0,
'modified': '2010-12-24 11:56:34',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all Page
{
'doctype': 'Page',
'module': 'Selling',
'name': '__common__',
'page_name': 'Sales Browser',
'show_in_menu': 0,
'standard': 'Yes'
},
# These values are common for all Page Role
{
'doctype': 'Page Role',
'name': '__common__',
'parent': 'Sales Browser',
'parentfield': 'roles',
'parenttype': 'Page'
},
# Page, Sales Browser
{
'doctype': 'Page',
'name': 'Sales Browser'
},
# Page Role
{
'doctype': 'Page Role',
'idx': 1,
'role': 'Sales Master Manager'
},
# Page Role
{
'doctype': 'Page Role',
'idx': 2,
'role': 'Material Master Manager'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,125 @@
<div class="layout-wrapper layout-wrapper-background">
<div class="appframe-area"></div>
<div class="layout-main-section">
<div style="width: 48%; float: left;">
<h4><a href="#!List/Lead">Lead</a></h4>
<p class="help">Prospective customers</p>
<br>
<h4><a href="#!List/Opportunity">Opportunity</a></h4>
<p class="help">Business opportunities</p>
<br>
<h4><a href="#!List/Quotation">Quotation</a></h4>
<p class="help">Quotes sent to Leads / Customers</p>
<br>
<h4><a href="#!List/Sales Order">Sales Order</a></h4>
<p class="help">Confirmed orders from Customers</p>
</div>
<div style="width: 48%; float: right;">
<h4><a href="#!List/Customer">Customer</a></h4>
<p class="help">Customer Master</p>
<br>
<h4><a href="#!List/Item">Item</a></h4>
<p class="help">Item Master</p>
<br>
<h4><a href="#!List/Contact">Contact</a></h4>
<p class="help">Contact Master</p>
<br>
<h4><a href="#!List/Address">Address</a></h4>
<p class="help">Address Master</p>
<br>
<h4><a href="#sales-analytics" data-role="Analytics">Sales Analytics</a>
<span style="background-color: #fed; font-weight: normal; font-size: 80%">beta</span>
</h4>
<p class="help">Sales trends based on Sales Invoice</p>
</div>
<div style="clear: both"></div>
<hr>
<h3>Reports</h3>
<div class="reports-list"></div>
</div>
<div class="layout-side-section">
<div class="psidebar">
<div class="section">
<div class="section-head">Setup</div>
<div class="section-body">
<div class="section-item">
<a class="section-link"
title = "Tax and charges structure master"
href="#!List/Sales Taxes and Charges Master">Sales Taxes and Charges Master</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Multiple prices lists for items"
href="#!List/Price List">Price List</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Group items and accessories in one item code"
href="#!List/Sales BOM">Sales BOM</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Terms of contract template"
href="#!List/Terms and Conditions">Terms and Conditions Template</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Tree of customer groups"
href="#!Sales Browser/Customer Group">Customer Group</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Tree of sales territories"
href="#!Sales Browser/Territory">Territory</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Sales persons and targets"
href="#!Sales Browser/Sales Person">Sales Person</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Commission partners and targets"
href="#!List/Sales Partner">Sales Partner</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Tree of item classification"
href="#!Sales Browser/Item Group">Item Group</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Sales campaigns"
href="#!List/Campaign">Campaign</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Send mass SMS to your contacts, leads and employees"
href="#!Form/SMS Center/SMS Center">SMS Center</a>
</div>
</div>
</div>
<div class="section">
<div class="section-head">Tools</div>
<div class="section-body">
<div class="section-item">
<a class="section-link"
title = "Helper for managing return of goods (sales or purchase)"
href="#!Form/Sales and Purchase Return Tool/Sales and Purchase Return Tool">Sales Returns</a>
</div>
<div class="section-item">
<a class="section-link"
title = "Analyze Sales and Purchase trends and slice them based on item, customer, groups etc"
href="#!Report/Profile/Trend Analyzer">Trend Analyzer</a>
</div>
<!--<div class="section-item">
<a class="section-link"
title = "sales trends"
href="#!Sales Dashboard">Sales Dashboard</a>
</div>-->
</div>
</div>
</div>
</div>
<div style="clear: both;"></div>
</div>

View File

@@ -0,0 +1,20 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pscript['onload_selling-home'] = function(wrapper) {
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.appframe-area'), 'Selling');
erpnext.module_page.setup_page('Selling', wrapper);
}

View File

@@ -0,0 +1,43 @@
# Page, selling-home
[
# These values are common in all dictionaries
{
'creation': '2012-02-20 15:46:39',
'docstatus': 0,
'modified': '2012-02-20 15:46:57',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all Page
{
'doctype': 'Page',
'module': u'Selling',
'name': '__common__',
'page_name': u'selling-home',
'standard': u'Yes',
'title': u'Selling Home'
},
# These values are common for all Page Role
{
'doctype': u'Page Role',
'name': '__common__',
'parent': u'selling-home',
'parentfield': u'roles',
'parenttype': u'Page',
'role': u'All'
},
# Page, selling-home
{
'doctype': 'Page',
'name': u'selling-home'
},
# Page Role
{
'doctype': u'Page Role'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,23 @@
from __future__ import unicode_literals
col_defs = [
{'label': 'Id', 'type': 'Link', 'width': '', 'options': 'Customer'},
{'label': 'Customer Name'},
{'label': 'Address Line 1', 'width': '200px'},
{'label': 'Address Line 2', 'width': '200px'},
{'label': 'City'},
{'label': 'State'},
{'label': 'Pincode', 'width': '80px'},
{'label': 'Country', 'width': '100px'},
{'label': 'Contact First Name'},
{'label': 'Contact Last Name'},
{'label': 'Contact Phone', 'width': '100px'},
{'label': 'Contact Mobile', 'width': '100px'},
{'label': 'Contact Email'},
]
webnotes.msgprint(colnames)
for col in col_defs:
colnames.append(col['label'])
coltypes.append(col.get('type') or 'Data')
colwidths.append(col.get('width') or '150px')
coloptions.append(col.get('options') or '')
col_idx[col['label']] = len(colnames) - 1

View File

@@ -0,0 +1,26 @@
select
`tabCustomer`.name,
`tabCustomer`.customer_name,
`tabAddress`.address_line1,
`tabAddress`.address_line2,
`tabAddress`.city,
`tabAddress`.state,
`tabAddress`.pincode,
`tabAddress`.country,
`tabContact`.first_name,
`tabContact`.last_name,
`tabContact`.phone,
`tabContact`.mobile_no,
`tabContact`.email_id
from
`tabCustomer`
left join `tabAddress` on (
`tabAddress`.customer=`tabCustomer`.name and
ifnull(`tabAddress`.is_primary_address, 0)=1
)
left join `tabContact` on (
`tabContact`.customer=`tabCustomer`.name and
ifnull(`tabContact`.is_primary_contact, 0)=1
)
order by
`tabCustomer`.customer_name asc

View File

@@ -0,0 +1,31 @@
# Search Criteria, customer_address_contact
[
# These values are common in all dictionaries
{
'creation': '2012-04-17 11:29:10',
'docstatus': 0,
'modified': '2012-05-23 18:17:40',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all Search Criteria
{
'columns': u'Customer\x01ID,Customer\x01Customer Name',
'criteria_name': u'Customer Address Contact',
'doc_type': u'Customer',
'doctype': 'Search Criteria',
'filters': u"{'Customer\x01Saved':1,'Customer\x01Submitted':1}",
'module': u'Selling',
'name': '__common__',
'page_len': 50,
'standard': u'Yes'
},
# Search Criteria, customer_address_contact
{
'doctype': 'Search Criteria',
'name': u'customer_address_contact'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,20 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
report.customize_filters = function() {
this.filter_fields_dict['Delivery Note'+FILTER_SEP +'Company'].df['report_default'] = sys_defaults.company;
this.filter_fields_dict['Delivery Note'+FILTER_SEP +'Fiscal Year'].df['report_default'] = sys_defaults.fiscal_year;
}

View File

@@ -0,0 +1,37 @@
# Search Criteria, delivered_items_to_be_install
[
# These values are common in all dictionaries
{
'creation': '2012-04-03 12:49:51',
'docstatus': 0,
'modified': '2012-04-03 12:49:51',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
# These values are common for all Search Criteria
{
'add_col': u"(`tabDelivery Note Item`.`qty`- ifnull(`tabDelivery Note Item`.`installed_qty`, 0)) AS 'Pending to Install'",
'add_cond': u'`tabDelivery Note Item`.`qty` > ifnull(`tabDelivery Note Item`.`installed_qty`, 0)',
'columns': u'Delivery Note\x01ID,Delivery Note\x01Status,Delivery Note\x01Customer,Delivery Note\x01Customer Name,Delivery Note\x01Contact Person,Delivery Note\x01Voucher Date,Delivery Note Item\x01Item Code,Delivery Note Item\x01Item Name,Delivery Note Item\x01Quantity,Delivery Note Item\x01Installed Qty,Delivery Note\x01% Installed',
'criteria_name': u'Delivered Items to be Install',
'description': u'Delivered Items to be Install',
'doc_type': u'Delivery Note Item',
'doctype': 'Search Criteria',
'filters': u"{'Delivery Note\x01Saved':1,'Delivery Note\x01Submitted':1,'Delivery Note\x01Status':'','Delivery Note\x01Fiscal Year':''}",
'module': u'Selling',
'name': '__common__',
'page_len': 50,
'parent_doc_type': u'Delivery Note',
'sort_by': u'`tabDelivery Note`.`name`',
'sort_order': u'DESC',
'standard': u'Yes'
},
# Search Criteria, delivered_items_to_be_install
{
'doctype': 'Search Criteria',
'name': u'delivered_items_to_be_install'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,37 @@
# Search Criteria, delivery_note_itemwise_pending_to_bill
[
# These values are common in all dictionaries
{
'creation': '2012-04-03 12:49:51',
'docstatus': 0,
'modified': '2012-04-03 12:49:51',
'modified_by': u'Administrator',
'owner': u'jai@webnotestech.com'
},
# These values are common for all Search Criteria
{
'add_col': u"SUM(`tabDelivery Note Item`.`qty` - `tabDelivery Note Item`.`billed_qty`) AS 'Pending Qty'\nSUM((`tabDelivery Note Item`.`qty` - `tabDelivery Note Item`.`billed_qty`) * `tabDelivery Note Item`.`basic_rate`) AS 'Pending Amount'",
'add_cond': u"`tabDelivery Note`.status != 'Stopped'\nCASE WHEN `tabDelivery Note`.`per_billed` IS NULL OR `tabDelivery Note`.per_billed = '' THEN 0 < 100 ELSE `tabDelivery Note`.per_billed <100 END",
'columns': u'Delivery Note\x01ID,Delivery Note\x01Owner,Delivery Note\x01Status,Delivery Note\x01Customer Name,Delivery Note\x01Voucher Date,Delivery Note\x01% Billed,Delivery Note\x01Posting Date,Delivery Note\x01Company Name,Delivery Note\x01Fiscal Year,Delivery Note Item\x01Item Code,Delivery Note Item\x01Against Document No,Delivery Note Item\x01Document Type,Delivery Note Item\x01Against Document Detail No',
'criteria_name': u'Delivery Note Itemwise Pending To Bill',
'doc_type': u'Delivery Note Item',
'doctype': 'Search Criteria',
'filters': u"{'Delivery Note\x01Saved':1,'Delivery Note\x01Submitted':1,'Delivery Note\x01Status':'','Delivery Note\x01Company Name':'','Delivery Note\x01Fiscal Year':''}",
'group_by': u'`tabDelivery Note Item`.item_code, `tabDelivery Note`.`name`',
'module': u'Selling',
'name': '__common__',
'page_len': 50,
'parent_doc_type': u'Delivery Note',
'sort_by': u'`tabDelivery Note`.`name`',
'sort_order': u'DESC',
'standard': u'Yes'
},
# Search Criteria, delivery_note_itemwise_pending_to_bill
{
'doctype': 'Search Criteria',
'name': u'delivery_note_itemwise_pending_to_bill'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

Some files were not shown because too many files have changed in this diff Show More