diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index cd13a72b8c..b176e000cd 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -2,6 +2,19 @@ // License: GNU General Public License v3. See license.txt frappe.ui.form.on("Supplier", { + setup: function(frm) { + frm.set_query('default_price_list', { 'buying': 1}); + frm.set_query('account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + filters: { + 'account_type': 'Payable', + 'company': d.company, + "is_group": 0 + } + } + }); + }, refresh: function(frm) { if(frappe.defaults.get_default("supp_master_name")!="Naming Series") { frm.toggle_display("naming_series", false); @@ -16,23 +29,18 @@ frappe.ui.form.on("Supplier", { else { unhide_field(['address_html','contact_html']); erpnext.utils.render_address_and_contact(frm); + + // custom buttons + frm.add_custom_button(__('Accounting Ledger'), function() { + frappe.set_route('query-report', 'General Ledger', + {party_type:'Supplier', party:frm.doc.name}); + }); + frm.add_custom_button(__('Accounts Payable'), function() { + frappe.set_route('query-report', 'Accounts Payable', {supplier:frm.doc.name}); + }); + + // indicators + erpnext.utils.set_party_dashboard_indicators(frm); } }, }); - -cur_frm.fields_dict['default_price_list'].get_query = function(doc, cdt, cdn) { - return{ - filters:{'buying': 1} - } -} - -cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - filters: { - 'account_type': 'Payable', - 'company': d.company, - "is_group": 0 - } - } -} diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index a4ee326f53..3677ee296b 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -18,6 +18,26 @@ class Supplier(TransactionBase): def onload(self): """Load address and contacts in `__onload`""" load_address_and_contact(self, "supplier") + self.load_dashboard_info() + + def load_dashboard_info(self): + billing_this_year = frappe.db.sql(""" + select sum(credit_in_account_currency) - sum(debit_in_account_currency) + from `tabGL Entry` + where voucher_type='Purchase Invoice' and party_type = 'Supplier' + and party=%s and fiscal_year = %s""", + (self.name, frappe.db.get_default("fiscal_year"))) + + total_unpaid = frappe.db.sql("""select sum(outstanding_amount) + from `tabPurchase Invoice` + where supplier=%s and docstatus = 1""", self.name) + + + info = {} + info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 + info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 + + self.set_onload('dashboard_info', info) def autoname(self): supp_master_name = frappe.defaults.get_global_default('supp_master_name') diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 40441c8e22..8ab34dee97 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -328,3 +328,4 @@ erpnext.patches.v7_0.update_conversion_factor_in_supplier_quotation_item erpnext.patches.v7_1.move_sales_invoice_from_parent_to_child_timesheet execute:frappe.db.sql("update `tabTimesheet` ts, `tabEmployee` emp set ts.employee_name = emp.employee_name where emp.name = ts.employee and ts.employee_name is null and ts.employee is not null") erpnext.patches.v7_1.update_lead_source +erpnext.patches.v7_1.fix_link_for_customer_from_lead \ No newline at end of file diff --git a/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py b/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py new file mode 100644 index 0000000000..cbb3ea4092 --- /dev/null +++ b/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py @@ -0,0 +1,6 @@ +import frappe + +def execute(): + for c in frappe.db.sql('select name from tabCustomer where ifnull(lead_name,"")!=""'): + customer = frappe.get_doc('Customer', c[0]) + customer.update_lead_status() \ No newline at end of file diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 7330889734..6c8898dab0 100644 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -108,6 +108,17 @@ $.extend(erpnext.utils, { } }, + set_party_dashboard_indicators: function(frm) { + if(frm.doc.__onload && frm.doc.__onload.dashboard_info) { + var info = frm.doc.__onload.dashboard_info; + frm.dashboard.add_indicator(__('Annual Billing: {0}', + [format_currency(info.billing_this_year, frm.doc.default_currency)]), 'blue'); + frm.dashboard.add_indicator(__('Total Unpaid: {0}', + [format_currency(info.total_unpaid, frm.doc.default_currency)]), + info.total_unpaid ? 'orange' : 'green'); + } + }, + copy_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname) { var d = locals[dt][dn]; if(d[fieldname]){ diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index 20ecc7bf85..ea88e8b8b5 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -2,6 +2,29 @@ // License: GNU General Public License v3. See license.txt frappe.ui.form.on("Customer", { + setup: function(frm) { + frm.add_fetch('lead_name', 'company_name', 'customer_name'); + frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate'); + + frm.set_query('customer_group', {'is_group': 0}); + frm.set_query('default_price_list', { 'selling': 1}); + frm.set_query('account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + var filters = { + 'account_type': 'Receivable', + 'company': d.company, + "is_group": 0 + }; + + if(doc.party_account_currency) { + $.extend(filters, {"account_currency": doc.party_account_currency}); + } + + return { + filters: filters + } + }); + }, refresh: function(frm) { if(frappe.defaults.get_default("cust_master_name")!="Naming Series") { frm.toggle_display("naming_series", false); @@ -13,6 +36,20 @@ frappe.ui.form.on("Customer", { if(!frm.doc.__islocal) { erpnext.utils.render_address_and_contact(frm); + + // custom buttons + frm.add_custom_button(__('Accounting Ledger'), function() { + frappe.set_route('query-report', 'General Ledger', + {party_type:'Customer', party:frm.doc.name}); + }); + + frm.add_custom_button(__('Accounts Receivable'), function() { + frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name}); + }); + + // indicator + erpnext.utils.set_party_dashboard_indicators(frm); + } else { erpnext.utils.clear_address_and_contact(frm); } @@ -23,55 +60,5 @@ frappe.ui.form.on("Customer", { }, validate: function(frm) { if(frm.doc.lead_name) frappe.model.clear_doc("Lead", frm.doc.lead_name); - } + }, }); - -cur_frm.cscript.onload = function(doc, dt, dn) { - cur_frm.cscript.load_defaults(doc, dt, dn); -} - -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 = frappe.model.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'); - -cur_frm.fields_dict['customer_group'].get_query = function(doc, dt, dn) { - return{ - filters:{'is_group': 0} - } -} - -cur_frm.fields_dict.lead_name.get_query = function(doc, cdt, cdn) { - return{ - query: "erpnext.controllers.queries.lead_query" - } -} - -cur_frm.fields_dict['default_price_list'].get_query = function(doc, cdt, cdn) { - return{ - filters:{'selling': 1} - } -} - -cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - var filters = { - 'account_type': 'Receivable', - 'company': d.company, - "is_group": 0 - }; - - if(doc.party_account_currency) { - $.extend(filters, {"account_currency": doc.party_account_currency}); - } - - return { - filters: filters - } -} diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index ee3f6e6503..82dbba7946 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -20,6 +20,26 @@ class Customer(TransactionBase): def onload(self): """Load address and contacts in `__onload`""" load_address_and_contact(self, "customer") + self.load_dashboard_info() + + def load_dashboard_info(self): + billing_this_year = frappe.db.sql(""" + select sum(debit_in_account_currency) - sum(credit_in_account_currency) + from `tabGL Entry` + where voucher_type='Sales Invoice' and party_type = 'Customer' + and party=%s and fiscal_year = %s""", + (self.name, frappe.db.get_default("fiscal_year"))) + + total_unpaid = frappe.db.sql("""select sum(outstanding_amount) + from `tabSales Invoice` + where customer=%s and docstatus = 1""", self.name) + + info = {} + info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 + info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 + + self.set_onload('dashboard_info', info) + def autoname(self): cust_master_name = frappe.defaults.get_global_default('cust_master_name') @@ -40,14 +60,37 @@ class Customer(TransactionBase): return self.customer_name + def after_insert(self): + '''If customer created from Lead, update customer id in quotations, opportunities''' + self.update_lead_status() + def validate(self): self.flags.is_new_doc = self.is_new() + self.flags.old_lead = self.lead_name validate_party_accounts(self) self.status = get_party_status(self) + def on_update(self): + self.validate_name_with_customer_group() + + if self.flags.old_lead != self.lead_name: + self.update_lead_status() + + self.update_address() + self.update_contact() + + if self.flags.is_new_doc: + self.create_lead_address_contact() + def update_lead_status(self): + '''If Customer created from Lead, update lead status to "Converted" + update Customer link in Quotation, Opportunity''' if self.lead_name: - frappe.db.sql("update `tabLead` set status='Converted' where name = %s", self.lead_name) + frappe.db.set_value('Lead', self.lead_name, 'status', 'Converted', update_modified=False) + + for doctype in ('Opportunity', 'Quotation'): + for d in frappe.get_all(doctype, {'lead': self.lead_name}): + frappe.db.set_value(doctype, d.name, 'customer', self.name, update_modified=False) def update_address(self): frappe.db.sql("""update `tabAddress` set customer_name=%s, modified=NOW() @@ -78,16 +121,6 @@ class Customer(TransactionBase): if not frappe.db.exists("Contact", c.name): c.insert() - def on_update(self): - self.validate_name_with_customer_group() - - self.update_lead_status() - self.update_address() - self.update_contact() - - if self.flags.is_new_doc: - self.create_lead_address_contact() - def validate_name_with_customer_group(self): if frappe.db.exists("Customer Group", self.name): frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError) diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py index 8547df18c1..eab38b286c 100644 --- a/erpnext/stock/doctype/material_request/material_request_dashboard.py +++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py @@ -7,5 +7,9 @@ data = { 'label': _('Related'), 'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order'] }, + { + 'label': _('Manufacturing'), + 'items': ['Production Order'] + }, ] } \ No newline at end of file