diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index bc992282ca..f7aeecde35 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -75,6 +75,19 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ this.is_opening(doc); }, + + supplier: function() { + if(this.frm.updating_party_details) + return; + erpnext.selling.get_party_details(this.frm, + "erpnext.accounts.party.get_party_details", { + posting_date: this.frm.doc.posting_date, + company: this.frm.doc.company, + party: this.frm.doc.supplier, + party_type: "Supplier", + account: this.frm.doc.debit_to + }) + }, credit_to: function() { this.supplier(); diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 6a6254a7fb..9fc04e6c3e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -12,8 +12,9 @@ from erpnext.setup.utils import get_company_currency import webnotes.defaults - from erpnext.controllers.buying_controller import BuyingController +from erpnext.accounts.party import get_party_account, get_due_date + class DocType(BuyingController): def __init__(self,d,dl): self.doc, self.doclist = d, dl @@ -55,31 +56,16 @@ class DocType(BuyingController): self.update_valuation_rate("entries") self.validate_multiple_billing("Purchase Receipt", "pr_detail", "import_amount", "purchase_receipt_details") - - def get_credit_to(self): - ret = {} - if self.doc.supplier: - acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount` - where (name = %s or (master_name = %s and master_type = 'supplier')) - and docstatus != 2 and company = %s""", - (cstr(self.doc.supplier) + " - " + self.company_abbr, - self.doc.supplier, self.doc.company)) - - if acc_head and acc_head[0][0]: - ret['credit_to'] = acc_head[0][0] - if not self.doc.due_date: - ret['due_date'] = add_days(cstr(self.doc.posting_date), - acc_head and cint(acc_head[0][1]) or 0) - elif not acc_head: - msgprint("%s does not have an Account Head in %s. \ - You must first create it from the Supplier Master" % \ - (self.doc.supplier, self.doc.company)) - return ret - - def set_supplier_defaults(self): - self.doc.fields.update(self.get_credit_to()) - super(DocType, self).set_supplier_defaults() + + def set_missing_values(self, for_validate=False): + if not self.doc.credit_to: + self.doc.credit_to = get_party_account(self.doc.company, self.doc.supplier, "Supplier") + if not self.doc.due_date: + self.doc.due_date = get_due_date(self.doc.posting_date, self.doc.supplier, "Supplier", + self.doc.credit_to, self.doc.company) + super(DocType, self).set_missing_values(for_validate) + def get_advances(self): super(DocType, self).get_advances(self.doc.credit_to, "Purchase Invoice Advance", "advance_allocation_details", "debit") diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 2362f3f202..fdf2265b9a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -155,6 +155,19 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } }, + customer: function() { + if(this.frm.updating_party_details) + return; + erpnext.selling.get_party_details(this.frm, + "erpnext.accounts.party.get_party_details", { + posting_date: this.frm.doc.posting_date, + company: this.frm.doc.company, + party: this.frm.doc.customer, + party_type: "Customer", + account: this.frm.doc.debit_to + }) + }, + debit_to: function() { this.customer(); }, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index cfa1aa7c8f..bb7d1c1b8c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -8,13 +8,14 @@ import webnotes.defaults from webnotes.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \ get_first_day, get_last_day -from webnotes.utils.email_lib import sendmail from webnotes.utils import comma_and, get_url from webnotes.model.doc import make_autoname from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint +from erpnext.accounts.party import get_party_account, get_due_date + month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12} from erpnext.controllers.selling_controller import SellingController @@ -149,23 +150,13 @@ class DocType(SellingController): self.set_pos_fields(for_validate) if not self.doc.debit_to: - self.doc.debit_to = self.get_customer_account() + self.doc.debit_to = get_party_account(self.doc.company, self.doc.customer, "Customer") if not self.doc.due_date: - self.doc.due_date = self.get_due_date() + self.doc.due_date = get_due_date(self.doc.posting_date, self.doc.customer, "Customer", + self.doc.debit_to, self.doc.company) super(DocType, self).set_missing_values(for_validate) - - def set_customer_defaults(self): - # TODO cleanup these methods - if self.doc.customer: - self.doc.debit_to = self.get_customer_account() - elif self.doc.debit_to: - self.doc.customer = webnotes.conn.get_value('Account', self.doc.debit_to, 'master_name') - - self.doc.due_date = self.get_due_date() - - super(DocType, self).set_customer_defaults() - + def update_time_log_batch(self, sales_invoice): for d in self.doclist.get({"doctype":"Sales Invoice Item"}): if d.time_log_batch: @@ -192,7 +183,7 @@ class DocType(SellingController): if pos: if not for_validate and not self.doc.customer: self.doc.customer = pos.customer - self.set_customer_defaults() + # self.set_customer_defaults() for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name', 'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account'): @@ -214,46 +205,8 @@ class DocType(SellingController): self.doc.terms = webnotes.conn.get_value("Terms and Conditions", self.doc.tc_name, "terms") # fetch charges - if self.doc.taxes_and_charges and not len(self.doclist.get({"parentfield": "other_charges"})): + if self.doc.charge and not len(self.doclist.get({"parentfield": "other_charges"})): self.set_taxes("other_charges", "taxes_and_charges") - - def get_customer_account(self): - """Get Account Head to which amount needs to be Debited based on Customer""" - if not self.doc.company: - msgprint("Please select company first and re-select the customer after doing so", - raise_exception=1) - if self.doc.customer: - acc_head = webnotes.conn.sql("""select name from `tabAccount` - where (name = %s or (master_name = %s and master_type = 'customer')) - and docstatus != 2 and company = %s""", - (cstr(self.doc.customer) + " - " + self.get_company_abbr(), - self.doc.customer, self.doc.company)) - - if acc_head and acc_head[0][0]: - return acc_head[0][0] - else: - msgprint("%s does not have an Account Head in %s. \ - You must first create it from the Customer Master" % - (self.doc.customer, self.doc.company)) - - def get_due_date(self): - """Set Due Date = Posting Date + Credit Days""" - due_date = None - if self.doc.posting_date: - credit_days = 0 - if self.doc.debit_to: - credit_days = webnotes.conn.get_value("Account", self.doc.debit_to, "credit_days") - if self.doc.customer and not credit_days: - credit_days = webnotes.conn.get_value("Customer", self.doc.customer, "credit_days") - if self.doc.company and not credit_days: - credit_days = webnotes.conn.get_value("Company", self.doc.company, "credit_days") - - if credit_days: - due_date = add_days(self.doc.posting_date, credit_days) - else: - due_date = self.doc.posting_date - - return due_date def get_advances(self): super(DocType, self).get_advances(self.doc.debit_to, @@ -735,7 +688,7 @@ def manage_recurring_invoices(next_date=None, commit=True): webnotes.conn.begin() webnotes.conn.sql("update `tabSales Invoice` set \ convert_into_recurring_invoice = 0 where name = %s", ref_invoice) - notify_errors(ref_invoice, ref_wrapper.doc.owner) + notify_errors(ref_invoice, ref_wrapper.doc.customer, ref_wrapper.doc.owner) webnotes.conn.commit() exception_list.append(webnotes.get_traceback()) @@ -784,101 +737,23 @@ def make_new_invoice(ref_wrapper, posting_date): def send_notification(new_rv): """Notify concerned persons about recurring invoice generation""" - subject = "Invoice : " + new_rv.doc.name - - com = new_rv.doc.company - - hd = '''

%s

-

Invoice: %s

- - - - - -
Customer
%s
%s
Invoice Date : %s
Invoice Period : %s to %s
Due Date : %s
- ''' % (com, new_rv.doc.name, new_rv.doc.customer_name, new_rv.doc.address_display, getdate(new_rv.doc.posting_date).strftime("%d-%m-%Y"), \ - getdate(new_rv.doc.invoice_period_from_date).strftime("%d-%m-%Y"), getdate(new_rv.doc.invoice_period_to_date).strftime("%d-%m-%Y"),\ - getdate(new_rv.doc.due_date).strftime("%d-%m-%Y")) - - tbl = ''' - - - - - - - - ''' - for d in getlist(new_rv.doclist, 'entries'): - tbl += '' - tbl += '
ItemDescriptionQtyRateAmount
' + cstr(d.item_code) +'' + cstr(d.description) + \ - '' + cstr(d.qty) +'' + cstr(d.basic_rate) + \ - '' + cstr(d.amount) +'
' - - totals =''' - - - - - - -
- - - - - - - - - - -
Net Total: %s
Total Tax: %s
Grand Total: %s
In Words: %s
-
Terms and Conditions:
%s
- ''' % (new_rv.doc.net_total, - new_rv.doc.other_charges_total,new_rv.doc.grand_total, - new_rv.doc.in_words,new_rv.doc.terms) - - - msg = hd + tbl + totals - - sendmail(new_rv.doc.notification_email_address, subject=subject, msg = msg) + from webnotes.core.doctype.print_format.print_format import get_html + webnotes.sendmail(new_rv.doc.notification_email_address, + subject="New Invoice : " + new_rv.doc.name, + message = get_html(new_rv.doc, new_rv.doclist, "SalesInvoice")) -def notify_errors(inv, owner): - import webnotes - - exception_msg = """ - Dear User, - - An error occured while creating recurring invoice from %s (at %s). - - May be there are some invalid email ids mentioned in the invoice. - - To stop sending repetitive error notifications from the system, we have unchecked - "Convert into Recurring" field in the invoice %s. - - - Please correct the invoice and make the invoice recurring again. - - It is necessary to take this action today itself for the above mentioned recurring invoice \ - to be generated. If delayed, you will have to manually change the "Repeat on Day of Month" field \ - of this invoice for generating the recurring invoice. - - Regards, - Administrator - - """ % (inv, get_url(), inv) - subj = "[Urgent] Error while creating recurring invoice from %s" % inv - +def notify_errors(inv, customer, owner): from webnotes.profile import get_system_managers - recipients = get_system_managers() - owner_email = webnotes.conn.get_value("Profile", owner, "email") - if not owner_email in recipients: - recipients.append(owner_email) - - assign_task_to_owner(inv, exception_msg, recipients) - sendmail(recipients, subject=subj, msg = exception_msg) + + webnotes.sendmail(recipients=get_system_managers() + [webnotes.conn.get_value("Profile", owner, "email")], + subject="[Urgent] Error while creating recurring invoice for %s" % inv, + message = webnotes.get_template("template/emails/recurring_invoice_failed.html").render({ + "name": inv, + "customer": customer + }) + + assign_task_to_owner(inv, "Recurring Invoice Failed", recipients) def assign_task_to_owner(inv, msg, users): for d in users: diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 939b3973fa..2ed9847c07 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -756,7 +756,7 @@ class TestSalesInvoice(unittest.TestCase): def _test_recurring_invoice(self, base_si, first_and_last_day): from webnotes.utils import add_months, get_last_day - from accounts.doctype.sales_invoice.sales_invoice \ + from erpnext.accounts.doctype.sales_invoice.sales_invoice \ import manage_recurring_invoices, get_next_date no_of_months = ({"Monthly": 1, "Quarterly": 3, "Yearly": 12})[base_si.doc.recurring_type] @@ -764,10 +764,10 @@ class TestSalesInvoice(unittest.TestCase): def _test(i): self.assertEquals(i+1, webnotes.conn.sql("""select count(*) from `tabSales Invoice` where recurring_id=%s and docstatus=1""", base_si.doc.recurring_id)[0][0]) - + next_date = get_next_date(base_si.doc.posting_date, no_of_months, base_si.doc.repeat_on_day_of_month) - + manage_recurring_invoices(next_date=next_date, commit=False) recurred_invoices = webnotes.conn.sql("""select name from `tabSales Invoice` diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py new file mode 100644 index 0000000000..0eedd9924e --- /dev/null +++ b/erpnext/accounts/party.py @@ -0,0 +1,85 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import webnotes +from webnotes import _ + +@webnotes.whitelist() +def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None): + if not webnotes.has_permission(party_type, "read", party): + webnotes.throw("No Permission") + + if party_type=="Customer": + get_party_details = webnotes.get_attr("erpnext.selling.doctype.customer.customer.get_customer_details") + else: + get_party_details = webnotes.get_attr("erpnext.buying.doctype.supplier.supplier.get_supplier_details") + + if party: + account = get_party_account(company, party, party_type) + elif account: + party = webnotes.conn.get_value('Account', account, 'master_name') + + account_fieldname = "debit_to" if party_type=="Customer" else "credit_to" + + out = { + party_type.lower(): party, + account_fieldname : account, + "due_date": get_due_date(posting_date, party, party_type, account, company) + } + out.update(get_party_details(party)) + return out + +def get_party_account(company, party, party_type): + if not company: + webnotes.throw(_("Please select company first.")) + + if party: + acc_head = webnotes.conn.get_value("Account", {"master_name":party, + "master_type": party_type, "company": company}) + + if not acc_head: + create_party_account(party, party_type, company) + + return acc_head + +def get_due_date(posting_date, party, party_type, account, company): + """Set Due Date = Posting Date + Credit Days""" + due_date = None + if posting_date: + credit_days = 0 + if account: + credit_days = webnotes.conn.get_value("Account", account, "credit_days") + if party and not credit_days: + credit_days = webnotes.conn.get_value(party_type, party, "credit_days") + if company and not credit_days: + credit_days = webnotes.conn.get_value("Company", company, "credit_days") + + due_date = add_days(posting_date, credit_days) if credit_days else posting_date + + return due_date + +def create_party_account(party, party_type, company): + if not company: + webnotes.throw(_("Company is required")) + + company_details = webnotes.conn.get_value("Company", company, + ["abbr", "receivables_group", "payables_group"], as_dict=True) + if not webnotes.conn.exists("Account", (party + " - " + company_details.abbr)): + parent_account = company_details.receivables_group \ + if party_type=="Customer" else company_details.payables_group + + # create + account = webnotes.bean({ + "doctype": "Account", + 'account_name': party, + 'parent_account': parent_account, + 'group_or_ledger':'Ledger', + 'company': company, + 'master_type': party_type, + 'master_name': party, + "freeze_account": "No" + }).insert(ignore_permissions=True) + + webnotes.msgprint(_("Account Created") + ": " + account.doc.name) diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index 039165f891..95250bab22 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -62,43 +62,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }, supplier: function() { - var me = this; - if(this.frm.doc.supplier || this.frm.doc.credit_to) { - if(!this.frm.doc.company) { - this.frm.set_value("supplier", null); - msgprint(wn._("Please specify Company")); - } else { - var buying_price_list = this.frm.doc.buying_price_list; - return this.frm.call({ - doc: this.frm.doc, - method: "set_supplier_defaults", - freeze: true, - callback: function(r) { - if(!r.exc) { - if(me.frm.doc.buying_price_list !== buying_price_list) me.buying_price_list(); - if (me.frm.doc.taxes_and_charges) - me.frm.script_manager.trigger("taxes_and_charges") - } - } - }); - } - } + erpnext.utils.get_party_details(this.frm); }, supplier_address: function() { - var me = this; - if (this.frm.doc.supplier) { - return wn.call({ - doc: this.frm.doc, - method: "set_supplier_address", - freeze: true, - args: { - supplier: this.frm.doc.supplier, - address: this.frm.doc.supplier_address, - contact: this.frm.doc.contact_person - }, - }); - } + erpnext.utils.get_address_display(this.frm); }, contact_person: function() { @@ -478,4 +446,4 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }); var tname = cur_frm.cscript.tname; -var fname = cur_frm.cscript.fname; \ No newline at end of file +var fname = cur_frm.cscript.fname; diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index ebfda85366..89e980697d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -225,7 +225,6 @@ def make_purchase_invoice(source_name, target_doclist=None): def set_missing_values(source, target): bean = webnotes.bean(target) bean.run_method("set_missing_values") - bean.run_method("set_supplier_defaults") def update_item(obj, target, source_parent): target.import_amount = flt(obj.import_amount) - flt(obj.billed_amt) diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 99c7352360..94bc679baa 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -8,7 +8,7 @@ import webnotes.defaults from webnotes.utils import cint from webnotes import msgprint, _ from webnotes.model.doc import make_autoname - +from erpnext.accounts.party import create_party_account from erpnext.utilities.transaction_base import TransactionBase @@ -47,88 +47,20 @@ class DocType(TransactionBase): self.update_contact() # create account head - self.create_account_head() + create_party_account(self.doc.name, "Supplier", self.doc.company) # update credit days and limit in account self.update_credit_days_limit() - - def get_payables_group(self): - g = webnotes.conn.sql("select payables_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 Payables") - raise Exception - return g - - def add_account(self, ac, par, abbr): - ac_bean = webnotes.bean({ - "doctype": "Account", - 'account_name':ac, - 'parent_account':par, - 'group_or_ledger':'Group', - 'company':self.doc.company, - "freeze_account": "No", - }) - ac_bean.ignore_permissions = True - ac_bean.insert() - msgprint(_("Created Group ") + ac) - def get_company_abbr(self): return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] - def get_parent_account(self, abbr): - if (not self.doc.supplier_type): - msgprint("Supplier Type is mandatory") - raise Exception - - if not webnotes.conn.sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)): - - # if not group created , create it - self.add_account(self.doc.supplier_type, self.get_payables_group(), abbr) - - return self.doc.supplier_type + " - " + abbr - def validate(self): #validation for Naming Series mandatory field... if webnotes.defaults.get_global_default('supp_master_name') == 'Naming Series': if not self.doc.naming_series: msgprint("Series is Mandatory.", raise_exception=1) - - def create_account_head(self): - if self.doc.company : - abbr = self.get_company_abbr() - parent_account = self.get_parent_account(abbr) - - if not webnotes.conn.sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)): - ac_bean = webnotes.bean({ - "doctype": "Account", - 'account_name': self.doc.name, - 'parent_account': parent_account, - 'group_or_ledger':'Ledger', - 'company': self.doc.company, - 'account_type': '', - 'tax_rate': '0', - 'master_type': 'Supplier', - 'master_name': self.doc.name, - "freeze_account": "No" - }) - ac_bean.ignore_permissions = True - ac_bean.insert() - - msgprint(_("Created Account Head: ") + ac_bean.doc.name) - else: - self.check_parent_account(parent_account, abbr) - else : - msgprint("Please select Company under which you want to create account head") - - def check_parent_account(self, parent_account, abbr): - if webnotes.conn.get_value("Account", self.doc.name + " - " + abbr, - "parent_account") != parent_account: - ac = webnotes.bean("Account", self.doc.name + " - " + abbr) - ac.doc.parent_account = parent_account - ac.save() - + def get_contacts(self,nm): if nm: contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm)) @@ -194,4 +126,28 @@ def get_dashboard_info(supplier): out["total_billing"] = billing[0][0] out["total_unpaid"] = billing[0][1] + return out + +@webnotes.whitelist() +def get_supplier_details(supplier, price_list=None, currency=None): + if not webnotes.has_permission("Supplier", "read", supplier): + webnotes.msgprint("No Permission", raise_exception=webnotes.PermissionError) + + supplier = webnotes.doc("Supplier", supplier) + + out = webnotes._dict({ + "supplier_address": webnotes.conn.get_value("Address", + {"supplier": supplier.name, "is_primary_address":1}, "name"), + "contact_person": webnotes.conn.get_value("Contact", + {"supplier":supplier.name, "is_primary_contact":1}, "name") + }) + + for f in ['currency', 'taxes_and_charges']: + if supplier.fields.get("default_" + f): + out[f] = supplier.fields.get("default_" + f) + + out.supplier_name = supplier.supplier_name + out.currency = supplier.default_currency or currency + out.buying_price_list = supplier.default_price_list or price_list + return out \ No newline at end of file diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 7ef771af83..5c45c11e33 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -7,6 +7,7 @@ from webnotes import _, msgprint from webnotes.utils import flt, _round from erpnext.buying.utils import get_item_details from erpnext.setup.utils import get_company_currency +from erpnext.buying.doctype.supplier.supplier import get_supplier_details from erpnext.controllers.stock_controller import StockController @@ -31,10 +32,8 @@ class BuyingController(StockController): self.set_price_list_currency("Buying") # set contact and address details for supplier, if they are not mentioned - if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address): - for fieldname, val in self.get_supplier_defaults().items(): - if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): - self.doc.fields[fieldname] = val + if self.doc.supplier: + self.doc.update_if_missing(get_supplier_details(self.doc.supplier)) self.set_missing_item_details(get_item_details) if self.doc.fields.get("__islocal"): diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index bcfe0bcfad..75b27a5ddf 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -33,18 +33,12 @@ class SellingController(StockController): self.set_taxes("other_charges", "taxes_and_charges") def set_missing_lead_customer_details(self): + from erpnext.selling.doctype.customer.customer import get_customer_details if self.doc.customer: - if not (self.doc.contact_person and self.doc.customer_address and self.doc.customer_name): - for fieldname, val in self.get_customer_defaults().items(): - if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): - self.doc.fields[fieldname] = val + self.doc.update_if_missing(get_customer_details(self.doc.customer)) elif self.doc.lead: - if not (self.doc.customer_address and self.doc.customer_name and \ - self.doc.contact_display): - for fieldname, val in self.get_lead_defaults().items(): - if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): - self.doc.fields[fieldname] = val + self.doc.update_if_missing(self.get_lead_defaults()) def set_price_list_and_item_details(self): self.set_price_list_currency("Selling") diff --git a/erpnext/public/build.json b/erpnext/public/build.json index ea9808abcd..d0891781bb 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -11,6 +11,7 @@ "public/js/toolbar.js", "public/js/feature_setup.js", "public/js/utils.js", - "public/js/queries.js" + "public/js/queries.js", + "public/js/utils/party.js" ] } \ No newline at end of file diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js new file mode 100644 index 0000000000..bda44cea7e --- /dev/null +++ b/erpnext/public/js/utils/party.js @@ -0,0 +1,76 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +wn.provide("erpnext.utils"); +erpnext.utils.get_party_details = function(frm, method, args) { + if(!method) { + if(frm.doc.customer) { + method = "erpnext.selling.doctype.customer.customer.get_customer_details"; + var price_list_field = "selling_price_list"; + } else { + method = "erpnext.buying.doctype.supplier.supplier.get_supplier_details"; + var price_list_field = "buying_price_list"; + } + } + if(!args) { + if(frm.doc.customer) { + args = { + customer: frm.doc.customer, + price_list: frm.doc.selling_price_list + }; + } else { + args = { + supplier: frm.doc.supplier, + price_list: frm.doc.buying_price_list + }; + } + args.currency = frm.doc.currency; + } + wn.call({ + method: method, + args: args, + callback: function(r) { + if(r.message) { + frm.updating_party_details = true; + frm.set_value(r.message); + frm.updating_party_details = false; + } + } + }); +} + +erpnext.utils.get_address_display = function(frm, address_field) { + if(frm.updating_party_details) return; + if(!address_field) { + if(frm.doc.customer) { + address_field = "customer_address"; + } else { + address_field = "supplier_address"; + } + } + if(frm.doc[address_field]) { + wn.call({ + method: "erpnext.utilities.doctype.address.address.get_address_display", + args: {address: frm.doc[address_field] }, + callback: function(r) { + if(r.message) + frm.set_value("address_display", r.message) + } + }) + } +} + +erpnext.utils.get_contact_details = function(frm) { + if(frm.updating_party_details) return; + + if(frm.doc[address_field]) { + wn.call({ + method: "erpnext.utilities.doctype.contact.contact.get_contact_details", + args: {contact: frm.doc.contact_person }, + callback: function(r) { + if(r.message) + frm.set_value(r.message); + } + }) + } +} \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index ee54f9319f..c8c619aaeb 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -3,13 +3,16 @@ from __future__ import unicode_literals import webnotes - +from webnotes.utils import cstr from webnotes.model.doc import Document, make_autoname from webnotes import msgprint, _ import webnotes.defaults from erpnext.utilities.transaction_base import TransactionBase +from erpnext.utilities.doctype.address.address import get_address_display +from erpnext.utilities.doctype.contact.contact import get_contact_details +from erpnext.accounts.party import create_party_account class DocType(TransactionBase): def __init__(self, doc, doclist=[]): @@ -27,14 +30,6 @@ class DocType(TransactionBase): def get_company_abbr(self): return webnotes.conn.get_value('Company', self.doc.company, 'abbr') - - def get_receivables_group(self): - g = webnotes.conn.sql("select receivables_group from tabCompany where name=%s", self.doc.company) - g = g and g[0][0] or '' - if not g: - msgprint("Update Company master, assign a default group for Receivables") - raise Exception - return g def validate_values(self): if webnotes.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.doc.naming_series: @@ -55,29 +50,6 @@ class DocType(TransactionBase): webnotes.conn.sql("""update `tabContact` set customer_name=%s, modified=NOW() where customer=%s""", (self.doc.customer_name, self.doc.name)) - def create_account_head(self): - if self.doc.company : - abbr = self.get_company_abbr() - if not webnotes.conn.exists("Account", (self.doc.name + " - " + abbr)): - parent_account = self.get_receivables_group() - # create - ac_bean = webnotes.bean({ - "doctype": "Account", - 'account_name': self.doc.name, - 'parent_account': parent_account, - 'group_or_ledger':'Ledger', - 'company':self.doc.company, - 'master_type':'Customer', - 'master_name':self.doc.name, - "freeze_account": "No" - }) - ac_bean.ignore_permissions = True - ac_bean.insert() - - msgprint(_("Account Head") + ": " + ac_bean.doc.name + _(" created")) - else : - msgprint(_("Please Select Company under which you want to create account head")) - def update_credit_days_limit(self): webnotes.conn.sql("""update tabAccount set credit_days = %s, credit_limit = %s where master_type='Customer' and master_name = %s""", @@ -111,7 +83,8 @@ class DocType(TransactionBase): self.update_contact() # create account head - self.create_account_head() + create_party_account(self.doc.name, "Customer", self.doc.company) + # update credit days and limit in account self.update_credit_days_limit() #create address and contact from lead @@ -189,4 +162,59 @@ def get_dashboard_info(customer): out["total_billing"] = billing[0][0] out["total_unpaid"] = billing[0][1] + return out + +@webnotes.whitelist() +def get_customer_details(customer, price_list=None, currency=None): + if not webnotes.has_permission("Customer", "read", customer): + webnotes.throw("Not Permitted", webnotes.PermissionError) + + out = {} + customer_bean = webnotes.bean("Customer", customer) + customer = customer_bean.doc + + out = webnotes._dict({ + "customer_address": webnotes.conn.get_value("Address", + {"customer": customer.name, "is_primary_address":1}, "name"), + "contact_person": webnotes.conn.get_value("Contact", + {"customer":customer.name, "is_primary_contact":1}, "name") + }) + + # address display + out.address_display = get_address_display(out.customer_address) + + # primary contact details + out.update(get_contact_details(out.contact_person)) + + # copy + for f in ['customer_name', 'customer_group', 'territory']: + out[f] = customer.get(f) + + # fields prepended with default in Customer doctype + for f in ['sales_partner', 'commission_rate', 'currency', 'price_list', 'taxes_and_charges']: + if customer.get("default_" + f): + out[f] = customer.get("default_" + f) + + # price list + from webnotes.defaults import get_defaults_for + out.selling_price_list = get_defaults_for(webnotes.session.user).get(price_list) + if isinstance(out.selling_price_list, list): + out.selling_price_list = None + + out.selling_price_list = out.selling_price_list or customer.price_list \ + or webnotes.conn.get_value("Customer Group", + customer.customer_group, "default_price_list") or price_list + + if out.selling_price_list: + out.price_list_currency = webnotes.conn.get_value("Price List", out.selling_price_list, "currency") + + if not out.currency: + out.currency = currency + + # sales team + out.sales_team = [{ + "sales_person": d.sales_person, + "sales_designation": d.sales_designation + } for d in customer_bean.doclist.get({"doctype":"Sales Team"})] + return out \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 707d38a086..b3e0372195 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -6,7 +6,38 @@ from __future__ import unicode_literals import webnotes import unittest +from webnotes.test_runner import make_test_records + + class TestCustomer(unittest.TestCase): + def test_get_customer_details(self): + from erpnext.selling.doctype.customer.customer import get_customer_details + + to_check = { + 'address_display': '_Test Address Line 1\n_Test City\nIndia\nPhone: +91 0000000000', + 'selling_price_list': None, + 'customer_group': '_Test Customer Group', + 'contact_designation': None, + 'customer_address': '_Test Address-Office', + 'contact_department': None, + 'contact_email': 'test_contact_customer@example.com', + 'contact_mobile': None, + '_sales_team': [], + 'contact_display': '_Test Contact For _Test Customer', + 'contact_person': '_Test Contact For _Test Customer-_Test Customer', + 'territory': u'_Test Territory', + 'contact_phone': '+91 0000000000', + 'customer_name': '_Test Customer' + } + + make_test_records("Address") + make_test_records("Contact") + + details = get_customer_details("_Test Customer") + + for key, value in to_check.iteritems(): + self.assertEquals(value, details.get(key)) + def test_rename(self): self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer 1"), (("_Test Customer 1",),)) @@ -20,7 +51,6 @@ class TestCustomer(unittest.TestCase): webnotes.rename_doc("Customer", "_Test Customer 1 Renamed", "_Test Customer 1") def test_merge(self): - from webnotes.test_runner import make_test_records make_test_records("Sales Invoice") # clear transactions for new name diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js index 223bd8d279..1373225f06 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.js +++ b/erpnext/selling/doctype/installation_note/installation_note.js @@ -4,6 +4,16 @@ cur_frm.cscript.tname = "Installation Note Item"; cur_frm.cscript.fname = "installed_item_details"; + +wn.ui.form.on_change("Installation Note", "customer", + function(frm) { erpnext.utils.get_party_details(frm); }); + +wn.ui.form.on_change("Installation Note", "customer_address", + function(frm) { erpnext.utils.get_address_display(frm); }); + +wn.ui.form.on_change("Installation Note", "contact_person", + function(frm) { erpnext.utils.get_contact_details(frm); }); + wn.provide("erpnext.selling"); // TODO commonify this code erpnext.selling.InstallationNote = wn.ui.form.Controller.extend({ @@ -11,11 +21,6 @@ erpnext.selling.InstallationNote = wn.ui.form.Controller.extend({ if(!this.frm.doc.status) set_multiple(dt,dn,{ status:'Draft'}); if(this.frm.doc.__islocal) set_multiple(this.frm.doc.doctype, this.frm.doc.name, {inst_date: get_today()}); - - fields = ['customer_address', 'contact_person','customer_name', 'address_display', - 'contact_display', 'contact_mobile', 'contact_email', 'territory', 'customer_group'] - if(this.frm.doc.customer) unhide_field(fields); - else hide_field(fields) this.setup_queries(); }, @@ -60,42 +65,7 @@ erpnext.selling.InstallationNote = wn.ui.form.Controller.extend({ } ); } - }, - - customer: function() { - var me = this; - if(this.frm.doc.customer) { - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - }); - - // TODO shift this to depends_on - unhide_field(['customer_address', 'contact_person', 'customer_name', - 'address_display', 'contact_display', 'contact_mobile', 'contact_email', - 'territory', 'customer_group']); - } - }, - - customer_address: function() { - var me = this; - if(this.frm.doc.customer) { - return this.frm.call({ - doc: this.frm.doc, - args: { - customer: this.frm.doc.customer, - address: this.frm.doc.customer_address, - contact: this.frm.doc.contact_person - }, - method: "get_customer_address", - freeze: true, - }); - } - }, - - contact_person: function() { - this.customer_address(); - }, + }, }); $.extend(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm})); \ No newline at end of file diff --git a/erpnext/selling/doctype/installation_note/installation_note.txt b/erpnext/selling/doctype/installation_note/installation_note.txt index 8f01a19aa5..5e519829df 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.txt +++ b/erpnext/selling/doctype/installation_note/installation_note.txt @@ -74,6 +74,7 @@ "search_index": 1 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "customer_address", "fieldtype": "Link", @@ -82,6 +83,7 @@ "print_hide": 1 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "contact_person", "fieldtype": "Link", @@ -104,6 +106,7 @@ "doctype": "DocField", "fieldname": "address_display", "fieldtype": "Small Text", + "hidden": 1, "label": "Address", "read_only": 1 }, @@ -111,10 +114,12 @@ "doctype": "DocField", "fieldname": "contact_display", "fieldtype": "Small Text", + "hidden": 1, "label": "Contact", "read_only": 1 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "contact_mobile", "fieldtype": "Text", @@ -122,6 +127,7 @@ "read_only": 1 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "contact_email", "fieldtype": "Text", @@ -130,6 +136,7 @@ "read_only": 1 }, { + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "territory", @@ -142,6 +149,7 @@ "search_index": 1 }, { + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "customer_group", diff --git a/erpnext/selling/doctype/opportunity/opportunity.js b/erpnext/selling/doctype/opportunity/opportunity.js index 538b05d47d..3de7f1ee83 100644 --- a/erpnext/selling/doctype/opportunity/opportunity.js +++ b/erpnext/selling/doctype/opportunity/opportunity.js @@ -3,6 +3,12 @@ {% include 'utilities/doctype/sms_control/sms_control.js' %}; +wn.ui.form.on_change("Opportunity", "customer", function(frm) { + erpnext.utils.get_party_details(frm) }); +wn.ui.form.on_change("Opportunity", "customer_address", erpnext.utils.get_address_display); +wn.ui.form.on_change("Opportunity", "contact_person", erpnext.utils.get_contact_details); + + wn.provide("erpnext.selling"); // TODO commonify this code erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ @@ -12,8 +18,6 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ if(!this.frm.doc.enquiry_from && this.frm.doc.lead) this.frm.doc.enquiry_from = "Lead"; - if(!this.frm.doc.enquiry_from) - hide_field(['customer', 'customer_address', 'contact_person', 'customer_name','lead', 'address_display', 'contact_display', 'contact_mobile', 'contact_email', 'territory', 'customer_group']); if(!this.frm.doc.status) set_multiple(cdt, cdn, { status:'Draft' }); if(!this.frm.doc.date) @@ -23,14 +27,6 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ if(!this.frm.doc.fiscal_year && sys_defaults.fiscal_year) set_multiple(cdt, cdn, { fiscal_year:sys_defaults.fiscal_year }); - if(this.frm.doc.enquiry_from) { - if(this.frm.doc.enquiry_from == 'Customer') { - hide_field('lead'); - } - else if (this.frm.doc.enquiry_from == 'Lead') { - hide_field(['customer', 'customer_address', 'contact_person', 'customer_group']); - } - } if(!this.frm.doc.__islocal) { cur_frm.communication_view = new wn.views.CommunicationList({ @@ -73,22 +69,7 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({ me.frm.set_query(opts[0], erpnext.queries[opts[1]]); }); }, - - customer: function() { - var me = this; - if(this.frm.doc.customer) { - // TODO shift this to depends_on - unhide_field(['customer_address', 'contact_person', 'customer_name', - 'address_display', 'contact_display', 'contact_mobile', 'contact_email', - 'territory', 'customer_group']); - - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - }); - } - }, - + create_quotation: function() { wn.model.open_mapped_doc({ method: "erpnext.selling.doctype.opportunity.opportunity.make_quotation", @@ -109,10 +90,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.add_custom_button(wn._('Opportunity Lost'), cur_frm.cscript['Declare Opportunity Lost']); cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms, "icon-mobile-phone"); - } - - cur_frm.toggle_display("contact_info", doc.customer || doc.lead); - + } } cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { @@ -122,50 +100,18 @@ cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.item_code = function(doc, cdt, cdn) { var d = locals[cdt][cdn]; - if (d.item_code) - return get_server_fields('get_item_details', d.item_code, 'enquiry_details', doc, cdt, cdn, 1); -} - -// 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(['customer','customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']); - doc.lead = 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 = ""; + if (d.item_code) { + return get_server_fields('get_item_details', d.item_code, + 'enquiry_details', doc, cdt, cdn, 1); } - else if(doc.enquiry_from == 'Customer') { - unhide_field(['customer']); - hide_field(['lead', 'address_display', 'contact_display', 'contact_mobile', - 'contact_email', 'territory', 'customer_group']); - doc.lead = 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 = ""; - } -} - -cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc, dt, dn) { - args = { - address: doc.customer_address, - contact: doc.contact_person - } - if(doc.customer) args.update({customer: doc.customer}); - - return get_server_fields('get_customer_address', JSON.stringify(args),'', doc, dt, dn, 1); } cur_frm.cscript.lead = function(doc, cdt, cdn) { cur_frm.toggle_display("contact_info", doc.customer || doc.lead); - wn.model.map_current_doc({ method: "erpnext.selling.doctype.lead.lead.make_opportunity", source_name: cur_frm.doc.lead }); - - unhide_field(['customer_name', 'address_display','contact_mobile', 'customer_address', - 'contact_email', 'territory']); } cur_frm.cscript['Declare Opportunity Lost'] = function() { diff --git a/erpnext/selling/doctype/opportunity/opportunity.txt b/erpnext/selling/doctype/opportunity/opportunity.txt index 613ed7b4d1..8cb0f2531b 100644 --- a/erpnext/selling/doctype/opportunity/opportunity.txt +++ b/erpnext/selling/doctype/opportunity/opportunity.txt @@ -81,6 +81,7 @@ "reqd": 1 }, { + "depends_on": "eval:doc.enquiry_from===\"Customer\"", "doctype": "DocField", "fieldname": "customer", "fieldtype": "Link", @@ -97,6 +98,7 @@ "search_index": 0 }, { + "depends_on": "eval:doc.enquiry_from===\"Lead\"", "doctype": "DocField", "fieldname": "lead", "fieldtype": "Link", @@ -184,6 +186,7 @@ "read_only": 0 }, { + "depends_on": "eval:doc.lead || doc.customer", "doctype": "DocField", "fieldname": "contact_info", "fieldtype": "Section Break", @@ -192,6 +195,7 @@ "read_only": 0 }, { + "depends_on": "eval:doc.customer || doc.lead", "doctype": "DocField", "fieldname": "customer_address", "fieldtype": "Link", @@ -205,13 +209,14 @@ "doctype": "DocField", "fieldname": "address_display", "fieldtype": "Small Text", - "hidden": 0, + "hidden": 1, "label": "Address", "oldfieldname": "address", "oldfieldtype": "Small Text", "read_only": 1 }, { + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "territory", @@ -225,7 +230,7 @@ "search_index": 1 }, { - "depends_on": "eval:doc.enquiry_from==\"Customer\"", + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "customer_group", @@ -248,6 +253,7 @@ "read_only": 0 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "customer_name", "fieldtype": "Data", @@ -256,6 +262,7 @@ "read_only": 1 }, { + "depends_on": "eval:doc.lead || doc.customer", "doctype": "DocField", "fieldname": "contact_person", "fieldtype": "Link", @@ -266,6 +273,7 @@ "read_only": 0 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "contact_display", "fieldtype": "Small Text", @@ -273,6 +281,7 @@ "read_only": 1 }, { + "depends_on": "eval:doc.lead || doc.customer", "doctype": "DocField", "fieldname": "contact_email", "fieldtype": "Text", @@ -280,6 +289,7 @@ "read_only": 1 }, { + "depends_on": "eval:doc.lead || doc.customer", "doctype": "DocField", "fieldname": "contact_mobile", "fieldtype": "Text", diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index fe78ee78ce..718d8a6fb2 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -10,6 +10,7 @@ wn.provide("erpnext.selling"); wn.require("assets/erpnext/js/transaction.js"); + {% include "public/js/controllers/accounts.js" %} erpnext.selling.SellingController = erpnext.TransactionController.extend({ @@ -103,49 +104,15 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, customer: function() { - var me = this; - if(this.frm.doc.customer || this.frm.doc.debit_to) { - if(!this.frm.doc.company) { - this.frm.set_value("customer", null); - msgprint(wn._("Please specify Company")); - } else { - var selling_price_list = this.frm.doc.selling_price_list; - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - freeze: true, - callback: function(r) { - if(!r.exc) { - (me.frm.doc.selling_price_list !== selling_price_list) ? - me.selling_price_list() : - me.price_list_currency(); - if (me.frm.doc.taxes_and_charges) - me.frm.script_manager.trigger("taxes_and_charges") - } - } - }); - } - } + erpnext.utils.get_party_details(this.frm); }, customer_address: function() { - var me = this; - if(this.frm.doc.customer) { - return this.frm.call({ - doc: this.frm.doc, - args: { - customer: this.frm.doc.customer, - address: this.frm.doc.customer_address, - contact: this.frm.doc.contact_person - }, - method: "set_customer_address", - freeze: true, - }); - } + erpnext.utils.get_address_display(this.frm, "customer_address"); }, contact_person: function() { - this.customer_address(); + erpnext.utils.get_contact_details(this.frm); }, barcode: function(doc, cdt, cdn) { @@ -670,4 +637,4 @@ var set_sales_bom_help = function(doc) { } } refresh_field('sales_bom_help'); -} \ No newline at end of file +} diff --git a/erpnext/setup/doctype/company/company.txt b/erpnext/setup/doctype/company/company.txt index 4159c51834..4832ae03da 100644 --- a/erpnext/setup/doctype/company/company.txt +++ b/erpnext/setup/doctype/company/company.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 08:35:39", "docstatus": 0, - "modified": "2014-01-20 17:48:28", + "modified": "2014-01-30 16:32:41", "modified_by": "Administrator", "owner": "Administrator" }, @@ -110,6 +110,7 @@ "fieldname": "default_cash_account", "fieldtype": "Link", "label": "Default Cash Account", + "no_copy": 1, "options": "Account", "read_only": 0 }, @@ -142,6 +143,7 @@ "fieldname": "default_expense_account", "fieldtype": "Link", "label": "Default Expense Account", + "no_copy": 1, "options": "Account" }, { @@ -149,6 +151,7 @@ "fieldname": "default_income_account", "fieldtype": "Link", "label": "Default Income Account", + "no_copy": 1, "options": "Account" }, { diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 7a33971542..955262f77c 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -301,7 +301,6 @@ def make_purchase_invoice(source_name, target_doclist=None): def set_missing_values(source, target): bean = webnotes.bean(target) bean.run_method("set_missing_values") - bean.run_method("set_supplier_defaults") doclist = get_mapped_doclist("Purchase Receipt", source_name, { "Purchase Receipt": { diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 52436ee829..5c7fdef32b 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -93,9 +93,8 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ if(cint(wn.defaults.get_default("auto_accounting_for_stock"))) { var account_for = "stock_adjustment_account"; - if (this.frm.doc.purpose == "Sales Return") - account_for = "stock_in_hand_account"; - else if (this.frm.doc.purpose == "Purchase Return") + + if (this.frm.doc.purpose == "Purchase Return") account_for = "stock_received_but_not_billed"; return this.frm.call({ @@ -236,7 +235,50 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ mtn_details_on_form_rendered: function(doc, grid_row) { erpnext.setup_serial_no(grid_row) + }, + + customer: function() { + return this.frm.call({ + method: "erpnext.selling.doctype.customer.customer.get_customer_details", + args: { customer: this.frm.doc.customer } + }); + }, + + supplier: function() { + return this.frm.call({ + method: "erpnext.buying.doctype.supplier.supplier.get_supplier_details", + args: { supplier: this.frm.doc.supplier } + }); + }, + + delivery_note_no: function() { + this.get_party_details({ + ref_dt: "Delivery Note", + ref_dn: this.frm.doc.delivery_note_no + }) + }, + + sales_invoice_no: function() { + this.get_party_details({ + ref_dt: "Sales Invoice", + ref_dn: this.frm.doc.sales_invoice_no + }) + }, + + purchase_receipt_no: function() { + this.get_party_details({ + ref_dt: "Purchase Receipt", + ref_dn: this.frm.doc.purchase_receipt_no + }) + }, + + get_party_details: function(args) { + return this.frm.call({ + method: "erpnext.stock.doctype.stock_entry.stock_entry.get_party_details", + args: args, + }) } + }); cur_frm.script_manager.make(erpnext.stock.StockEntry); @@ -265,31 +307,6 @@ cur_frm.cscript.toggle_related_fields = function(doc) { } } -cur_frm.cscript.delivery_note_no = function(doc, cdt, cdn) { - if(doc.delivery_note_no) - return get_server_fields('get_cust_values', '', '', doc, cdt, cdn, 1); -} - -cur_frm.cscript.sales_invoice_no = function(doc, cdt, cdn) { - if(doc.sales_invoice_no) - return get_server_fields('get_cust_values', '', '', doc, cdt, cdn, 1); -} - -cur_frm.cscript.customer = function(doc, cdt, cdn) { - if(doc.customer) - return get_server_fields('get_cust_addr', '', '', doc, cdt, cdn, 1); -} - -cur_frm.cscript.purchase_receipt_no = function(doc, cdt, cdn) { - if(doc.purchase_receipt_no) - return get_server_fields('get_supp_values', '', '', doc, cdt, cdn, 1); -} - -cur_frm.cscript.supplier = function(doc, cdt, cdn) { - if(doc.supplier) - return get_server_fields('get_supp_addr', '', '', doc, cdt, cdn, 1); -} - cur_frm.fields_dict['production_order'].get_query = function(doc) { return { filters: [ @@ -389,4 +406,4 @@ cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) { cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) { return { query: "erpnext.controllers.queries.supplier_query" } -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 5c760f4aa0..161a3ad391 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -590,56 +590,6 @@ class DocType(StockController): # increment idx by 1 idx += 1 return idx - - def get_cust_values(self): - """fetches customer details""" - if self.doc.delivery_note_no: - doctype = "Delivery Note" - name = self.doc.delivery_note_no - else: - doctype = "Sales Invoice" - name = self.doc.sales_invoice_no - - result = webnotes.conn.sql("""select customer, customer_name, - address_display as customer_address - from `tab%s` where name=%s""" % (doctype, "%s"), (name,), as_dict=1) - - return result and result[0] or {} - - def get_cust_addr(self): - from erpnext.utilities.transaction_base import get_default_address, get_address_display - res = webnotes.conn.sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer) - address_display = None - customer_address = get_default_address("customer", self.doc.customer) - if customer_address: - address_display = get_address_display(customer_address) - ret = { - 'customer_name' : res and res[0][0] or '', - 'customer_address' : address_display} - - return ret - - def get_supp_values(self): - result = webnotes.conn.sql("""select supplier, supplier_name, - address_display as supplier_address - from `tabPurchase Receipt` where name=%s""", (self.doc.purchase_receipt_no,), - as_dict=1) - - return result and result[0] or {} - - def get_supp_addr(self): - from erpnext.utilities.transaction_base import get_default_address, get_address_display - res = webnotes.conn.sql("""select supplier_name from `tabSupplier` - where name=%s""", self.doc.supplier) - address_display = None - supplier_address = get_default_address("customer", self.doc.customer) - if supplier_address: - address_display = get_address_display(supplier_address) - - ret = { - 'supplier_name' : res and res[0][0] or '', - 'supplier_address' : address_display } - return ret def validate_with_material_request(self): for item in self.doclist.get({"parentfield": "mtn_details"}): @@ -653,6 +603,17 @@ class DocType(StockController): + _("Material Request") + (" - %s" % item.material_request), raise_exception=webnotes.MappingMismatchError) +@webnotes.whitelist() +def get_party_details(ref_dt, ref_dn): + if ref_dt in ["Delivery Note", "Sales Invoice"]: + res = webnotes.conn.get_value(ref_dt, ref_dn, + ["customer", "customer_name", "address_display as customer_address"], as_dict=1) + else: + res = webnotes.conn.get_value(ref_dt, ref_dn, + ["supplier", "supplier_name", "address_display as supplier_address"], as_dict=1) + print ref_dt, ref_dn, res + return res or {} + @webnotes.whitelist() def get_production_order_details(production_order): result = webnotes.conn.sql("""select bom_no, @@ -965,5 +926,4 @@ def make_return_jv_from_purchase_receipt(se, ref): result = [parent] + [{"account": account} for account in children] - return result - + return result \ No newline at end of file diff --git a/erpnext/support/doctype/customer_issue/customer_issue.js b/erpnext/support/doctype/customer_issue/customer_issue.js index 0ff3f17585..36bfe97266 100644 --- a/erpnext/support/doctype/customer_issue/customer_issue.js +++ b/erpnext/support/doctype/customer_issue/customer_issue.js @@ -2,27 +2,21 @@ // License: GNU General Public License v3. See license.txt wn.provide("erpnext.support"); -// TODO commonify this code + +wn.ui.form.on_change("Customer Issue", "customer", function(frm) { + erpnext.utils.get_party_details(frm) }); +wn.ui.form.on_change("Customer Issue", "customer_address", + erpnext.utils.get_address_display); +wn.ui.form.on_change("Customer Issue", "contact_person", + erpnext.utils.get_contact_details); + erpnext.support.CustomerIssue = wn.ui.form.Controller.extend({ refresh: function() { if((cur_frm.doc.status=='Open' || cur_frm.doc.status == 'Work In Progress')) { cur_frm.add_custom_button(wn._('Make Maintenance Visit'), this.make_maintenance_visit) } }, - - customer: function() { - var me = this; - if(this.frm.doc.customer) { - // TODO shift this to depends_on - unhide_field(['customer_address', 'contact_person']); - - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - }); - } - }, - + make_maintenance_visit: function() { wn.model.open_mapped_doc({ method: "erpnext.support.doctype.customer_issue.customer_issue.make_maintenance_visit", @@ -35,16 +29,7 @@ $.extend(cur_frm.cscript, new erpnext.support.CustomerIssue({frm: cur_frm})); cur_frm.cscript.onload = function(doc,cdt,cdn){ if(!doc.status) - set_multiple(dt,dn,{status:'Open'}); - if(doc.__islocal){ - hide_field(['customer_address','contact_person']); - } -} - -cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) { - if(doc.customer) - return get_server_fields('get_customer_address', - JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1); + set_multiple(dt,dn,{status:'Open'}); } cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) { @@ -82,6 +67,8 @@ cur_frm.add_fetch('serial_no', 'amc_expiry_date', 'amc_expiry_date'); cur_frm.add_fetch('serial_no', 'customer', 'customer'); cur_frm.add_fetch('serial_no', 'customer_name', 'customer_name'); cur_frm.add_fetch('serial_no', 'delivery_address', 'customer_address'); +cur_frm.add_fetch('item_code', 'item_name', 'item_name'); +cur_frm.add_fetch('item_code', 'description', 'description'); cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) { if(doc.serial_no) { @@ -98,8 +85,6 @@ cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) { } } -cur_frm.add_fetch('item_code', 'item_name', 'item_name'); -cur_frm.add_fetch('item_code', 'description', 'description'); cur_frm.fields_dict.customer.get_query = function(doc,cdt,cdn) { diff --git a/erpnext/support/doctype/customer_issue/customer_issue.txt b/erpnext/support/doctype/customer_issue/customer_issue.txt index d8b8a0bc63..37db518888 100644 --- a/erpnext/support/doctype/customer_issue/customer_issue.txt +++ b/erpnext/support/doctype/customer_issue/customer_issue.txt @@ -276,6 +276,7 @@ "width": "50%" }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "customer_name", "fieldtype": "Data", @@ -283,6 +284,7 @@ "read_only": 1 }, { + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "customer_group", @@ -293,6 +295,7 @@ "reqd": 0 }, { + "depends_on": "customer", "description": "Add / Edit", "doctype": "DocField", "fieldname": "territory", @@ -307,10 +310,27 @@ "search_index": 1 }, { + "depends_on": "customer", "doctype": "DocField", - "fieldname": "address_display", + "fieldname": "contact_display", "fieldtype": "Small Text", - "label": "Address", + "label": "Contact", + "read_only": 1 + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "contact_mobile", + "fieldtype": "Data", + "label": "Mobile No", + "read_only": 1 + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "contact_email", + "fieldtype": "Data", + "label": "Contact Email", "read_only": 1 }, { @@ -320,27 +340,8 @@ "width": "50%" }, { - "doctype": "DocField", - "fieldname": "contact_display", - "fieldtype": "Small Text", - "label": "Contact", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_mobile", - "fieldtype": "Data", - "label": "Mobile No", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_email", - "fieldtype": "Data", - "label": "Contact Email", - "read_only": 1 - }, - { + "depends_on": "customer", + "description": "If different than customer address", "doctype": "DocField", "fieldname": "service_address", "fieldtype": "Small Text", @@ -348,6 +349,15 @@ "oldfieldname": "service_address", "oldfieldtype": "Small Text" }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "address_display", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Address", + "read_only": 1 + }, { "doctype": "DocField", "fieldname": "more_info", diff --git a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js index 2ee8b80e47..c8af280d89 100644 --- a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js @@ -2,6 +2,14 @@ // License: GNU General Public License v3. See license.txt wn.provide("erpnext.support"); + +wn.ui.form.on_change("Maintenance Schedule", "customer", function(frm) { + erpnext.utils.get_party_details(frm) }); +wn.ui.form.on_change("Maintenance Schedule", "customer_address", + erpnext.utils.get_address_display); +wn.ui.form.on_change("Maintenance Schedule", "contact_person", + erpnext.utils.get_contact_details); + // TODO commonify this code erpnext.support.MaintenanceSchedule = wn.ui.form.Controller.extend({ refresh: function() { @@ -30,36 +38,16 @@ erpnext.support.MaintenanceSchedule = wn.ui.form.Controller.extend({ }); } }, - customer: function() { - var me = this; - if(this.frm.doc.customer) { - return this.frm.call({ - doc: me.frm.doc, - method: "set_customer_defaults", - }); - } - }, }); $.extend(cur_frm.cscript, new erpnext.support.MaintenanceSchedule({frm: cur_frm})); cur_frm.cscript.onload = function(doc, dt, dn) { - if (!doc.status) - set_multiple(dt, dn, { status:'Draft' }); - - if (doc.__islocal) { - set_multiple(dt, dn, { transaction_date:get_today() }); - hide_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) { - return get_server_fields('get_customer_address', - JSON.stringify({customer: doc.customer, address: doc.customer_address, - contact: doc.contact_person}), '', doc, dt, dn, 1); - } + if(!doc.status) set_multiple(dt,dn,{status:'Draft'}); + + if(doc.__islocal){ + set_multiple(dt,dn,{transaction_date:get_today()}); + } } cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) { diff --git a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.txt b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.txt index 5321ed9003..56278898aa 100644 --- a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.txt +++ b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.txt @@ -54,12 +54,6 @@ "oldfieldtype": "Section Break", "options": "icon-user" }, - { - "doctype": "DocField", - "fieldname": "column_break0", - "fieldtype": "Column Break", - "oldfieldtype": "Column Break" - }, { "doctype": "DocField", "fieldname": "customer", @@ -76,83 +70,10 @@ }, { "doctype": "DocField", - "fieldname": "customer_address", - "fieldtype": "Link", - "label": "Customer Address", - "options": "Address", - "print_hide": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_person", - "fieldtype": "Link", - "label": "Contact Person", - "options": "Contact", - "print_hide": 1 - }, - { - "doctype": "DocField", - "fieldname": "customer_name", - "fieldtype": "Data", - "in_filter": 1, - "in_list_view": 1, - "label": "Customer Name", - "oldfieldname": "customer_name", - "oldfieldtype": "Data", - "read_only": 1, - "reqd": 0, - "search_index": 0 - }, - { - "doctype": "DocField", - "fieldname": "address_display", - "fieldtype": "Small Text", - "hidden": 1, - "label": "Address", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_display", - "fieldtype": "Small Text", - "hidden": 1, - "label": "Contact", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_mobile", - "fieldtype": "Data", - "hidden": 1, - "label": "Mobile No", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "contact_email", - "fieldtype": "Data", - "hidden": 1, - "label": "Contact Email", - "print_hide": 1, - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "column_break1", + "fieldname": "column_break0", "fieldtype": "Column Break", "oldfieldtype": "Column Break" }, - { - "doctype": "DocField", - "fieldname": "transaction_date", - "fieldtype": "Date", - "in_filter": 1, - "label": "Transaction Date", - "oldfieldname": "transaction_date", - "oldfieldtype": "Date", - "reqd": 1, - "search_index": 0 - }, { "default": "Draft", "doctype": "DocField", @@ -170,49 +91,15 @@ }, { "doctype": "DocField", - "fieldname": "amended_from", - "fieldtype": "Data", - "ignore_restrictions": 1, - "label": "Amended From", - "no_copy": 1, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "company", - "fieldtype": "Link", + "fieldname": "transaction_date", + "fieldtype": "Date", "in_filter": 1, - "label": "Company", - "oldfieldname": "company", - "oldfieldtype": "Link", - "options": "Company", + "label": "Transaction Date", + "oldfieldname": "transaction_date", + "oldfieldtype": "Date", "reqd": 1, "search_index": 0 }, - { - "description": "Add / Edit", - "doctype": "DocField", - "fieldname": "territory", - "fieldtype": "Link", - "in_filter": 1, - "label": "Territory", - "oldfieldname": "territory", - "oldfieldtype": "Link", - "options": "Territory", - "reqd": 1, - "search_index": 0 - }, - { - "description": "Add / Edit", - "doctype": "DocField", - "fieldname": "customer_group", - "fieldtype": "Link", - "label": "Customer Group", - "options": "Customer Group", - "reqd": 1 - }, { "doctype": "DocField", "fieldname": "items", @@ -255,6 +142,120 @@ "options": "Maintenance Schedule Detail", "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "contact_info", + "fieldtype": "Section Break", + "label": "Contact Info" + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "customer_name", + "fieldtype": "Data", + "in_filter": 1, + "in_list_view": 1, + "label": "Customer Name", + "oldfieldname": "customer_name", + "oldfieldtype": "Data", + "read_only": 1, + "reqd": 0, + "search_index": 0 + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "contact_person", + "fieldtype": "Link", + "label": "Contact Person", + "options": "Contact", + "print_hide": 1 + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "contact_mobile", + "fieldtype": "Data", + "hidden": 1, + "label": "Mobile No", + "read_only": 1 + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "contact_email", + "fieldtype": "Data", + "hidden": 1, + "label": "Contact Email", + "print_hide": 1, + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Contact", + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "column_break_17", + "fieldtype": "Column Break" + }, + { + "depends_on": "customer", + "doctype": "DocField", + "fieldname": "customer_address", + "fieldtype": "Link", + "label": "Customer Address", + "options": "Address", + "print_hide": 1 + }, + { + "doctype": "DocField", + "fieldname": "address_display", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Address", + "read_only": 1 + }, + { + "depends_on": "customer", + "description": "Add / Edit", + "doctype": "DocField", + "fieldname": "territory", + "fieldtype": "Link", + "in_filter": 1, + "label": "Territory", + "oldfieldname": "territory", + "oldfieldtype": "Link", + "options": "Territory", + "reqd": 1, + "search_index": 0 + }, + { + "depends_on": "customer", + "description": "Add / Edit", + "doctype": "DocField", + "fieldname": "customer_group", + "fieldtype": "Link", + "label": "Customer Group", + "options": "Customer Group", + "reqd": 1 + }, + { + "doctype": "DocField", + "fieldname": "company", + "fieldtype": "Link", + "in_filter": 1, + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "reqd": 1, + "search_index": 0 + }, { "doctype": "DocPerm" } diff --git a/erpnext/support/doctype/maintenance_visit/maintenance_visit.js b/erpnext/support/doctype/maintenance_visit/maintenance_visit.js index f571b9aa9c..186e07c1c3 100644 --- a/erpnext/support/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/support/doctype/maintenance_visit/maintenance_visit.js @@ -2,6 +2,14 @@ // License: GNU General Public License v3. See license.txt wn.provide("erpnext.support"); + +wn.ui.form.on_change("Maintenance Visit", "customer", function(frm) { + erpnext.utils.get_party_details(frm) }); +wn.ui.form.on_change("Maintenance Visit", "customer_address", + erpnext.utils.get_address_display); +wn.ui.form.on_change("Maintenance Visit", "contact_person", + erpnext.utils.get_contact_details); + // TODO commonify this code erpnext.support.MaintenanceVisit = wn.ui.form.Controller.extend({ refresh: function() { @@ -44,20 +52,7 @@ erpnext.support.MaintenanceVisit = wn.ui.form.Controller.extend({ }) }); } - cur_frm.cscript.hide_contact_info(); }, - customer: function() { - var me = this; - if(this.frm.doc.customer) { - // TODO shift this to depends_on - cur_frm.cscript.hide_contact_info(); - - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - }); - } - }, }); $.extend(cur_frm.cscript, new erpnext.support.MaintenanceVisit({frm: cur_frm})); @@ -65,15 +60,6 @@ $.extend(cur_frm.cscript, new erpnext.support.MaintenanceVisit({frm: cur_frm})); cur_frm.cscript.onload = function(doc, dt, dn) { if(!doc.status) set_multiple(dt,dn,{status:'Draft'}); if(doc.__islocal) set_multiple(dt,dn,{mntc_date:get_today()}); - cur_frm.cscript.hide_contact_info(); -} - -cur_frm.cscript.hide_contact_info = function() { - cur_frm.toggle_display("contact_info_section", cur_frm.doc.customer ? true : false); -} - -cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) { - if(doc.customer) return get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1); } cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) { diff --git a/erpnext/support/doctype/maintenance_visit/maintenance_visit.txt b/erpnext/support/doctype/maintenance_visit/maintenance_visit.txt index 7693d39da7..6a03292dca 100644 --- a/erpnext/support/doctype/maintenance_visit/maintenance_visit.txt +++ b/erpnext/support/doctype/maintenance_visit/maintenance_visit.txt @@ -269,6 +269,7 @@ "search_index": 0 }, { + "depends_on": "customer", "doctype": "DocField", "fieldname": "contact_info_section", "fieldtype": "Section Break", diff --git a/erpnext/support/doctype/support_ticket/support_ticket.js b/erpnext/support/doctype/support_ticket/support_ticket.js index b5224e7b66..a276e36a77 100644 --- a/erpnext/support/doctype/support_ticket/support_ticket.js +++ b/erpnext/support/doctype/support_ticket/support_ticket.js @@ -5,20 +5,8 @@ cur_frm.fields_dict.customer.get_query = function(doc,cdt,cdn) { return{ query: "erpnext.controllers.queries.customer_query" } } wn.provide("erpnext.support"); -// TODO commonify this code -erpnext.support.SupportTicket = wn.ui.form.Controller.extend({ - customer: function() { - var me = this; - if(this.frm.doc.customer) { - return this.frm.call({ - doc: this.frm.doc, - method: "set_customer_defaults", - }); - } - } -}); -$.extend(cur_frm.cscript, new erpnext.support.SupportTicket({frm: cur_frm})); +cur_frm.add_fetch("customer", "customer_name", "customer_name") $.extend(cur_frm.cscript, { onload: function(doc, dt, dn) { diff --git a/erpnext/templates/emails/recurring_invoice_failed.html b/erpnext/templates/emails/recurring_invoice_failed.html new file mode 100644 index 0000000000..dd3b913cea --- /dev/null +++ b/erpnext/templates/emails/recurring_invoice_failed.html @@ -0,0 +1,12 @@ +

Recurring Invoice Failed

+ +

An error occured while creating recurring invoice {{ name }} for {{ customer }}.

+

This could be because of some invalid email ids in the invoice.

+

To stop sending repetitive error notifications from the system, we have unchecked +"Convert into Recurring" field in the invoice {{ name }}.

+

Please correct the invoice and make the invoice recurring again.

+
+

It is necessary to take this action today itself for the above mentioned recurring invoice \ +to be generated. If delayed, you will have to manually change the "Repeat on Day of Month" field \ +of this invoice for generating the recurring invoice.

+

[This email is autogenerated]

diff --git a/erpnext/utilities/doctype/address/address.py b/erpnext/utilities/doctype/address/address.py index e371b515f8..e450d8418b 100644 --- a/erpnext/utilities/doctype/address/address.py +++ b/erpnext/utilities/doctype/address/address.py @@ -51,3 +51,26 @@ class DocType: webnotes.conn.sql("""update `tabAddress` set `%s`=0 where `%s`=%s and name!=%s""" % (is_address_type, fieldname, "%s", "%s"), (self.doc.fields[fieldname], self.doc.name)) break + +@webnotes.whitelist() +def get_address_display(address_dict): + if not isinstance(address_dict, dict): + address_dict = webnotes.conn.get_value("Address", address_dict, "*", as_dict=True) or {} + + meta = webnotes.get_doctype("Address") + sequence = (("", "address_line1"), + ("\n", "address_line2"), + ("\n", "city"), + ("\n", "state"), + ("\n" + meta.get_label("pincode") + ": ", "pincode"), + ("\n", "country"), + ("\n" + meta.get_label("phone") + ": ", "phone"), + ("\n" + meta.get_label("fax") + ": ", "fax")) + + display = "" + for separator, fieldname in sequence: + if address_dict.get(fieldname): + display += separator + address_dict.get(fieldname) + + return display.strip() + diff --git a/erpnext/utilities/doctype/contact/contact.py b/erpnext/utilities/doctype/contact/contact.py index 301d7fdda0..2abd0dc550 100644 --- a/erpnext/utilities/doctype/contact/contact.py +++ b/erpnext/utilities/doctype/contact/contact.py @@ -5,9 +5,9 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cstr, extract_email_id -from erpnext.utilities.transaction_base import TransactionBase +from erpnext.controllers.status_updater import StatusUpdater -class DocType(TransactionBase): +class DocType(StatusUpdater): def __init__(self, doc, doclist=[]): self.doc = doc self.doclist = doclist @@ -49,3 +49,19 @@ class DocType(TransactionBase): def on_trash(self): webnotes.conn.sql("""update `tabSupport Ticket` set contact='' where contact=%s""", self.doc.name) + +@webnotes.whitelist() +def get_contact_details(contact): + contact = webnotes.doc("Contact", contact) + out = { + "contact_person": contact.get("name"), + "contact_display": " ".join(filter(None, + [contact.get("first_name"), contact.get("last_name")])), + "contact_email": contact.get("email_id"), + "contact_mobile": contact.get("mobile_no"), + "contact_phone": contact.get("phone"), + "contact_designation": contact.get("designation"), + "contact_department": contact.get("department") + } + + return out \ No newline at end of file diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py index 8df7f25b4d..098a4bd8e9 100644 --- a/erpnext/utilities/transaction_base.py +++ b/erpnext/utilities/transaction_base.py @@ -2,36 +2,14 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import webnotes, json +import webnotes from webnotes import msgprint, _ from webnotes.utils import cstr, flt, now_datetime, cint -from webnotes.model.doc import addchild from erpnext.controllers.status_updater import StatusUpdater + class TransactionBase(StatusUpdater): - def get_default_address_and_contact(self, party_field, party_name=None): - """get a dict of default field values of address and contact for a given party type - party_type can be one of: customer, supplier""" - if not party_name: - party_name = self.doc.fields.get(party_field) - - return get_default_address_and_contact(party_field, party_name, - fetch_shipping_address=True if self.meta.get_field("shipping_address_name") else False) - - def set_address_fields(self): - party_type, party_name = self.get_party_type_and_name() - - if party_type in ("Customer", "Lead"): - if self.doc.customer_address: - self.doc.address_display = get_address_display(self.doc.customer_address) - - if self.doc.shipping_address_name: - self.doc.shipping_address = get_address_display(self.doc.shipping_address_name) - - elif self.doc.supplier_address: - self.doc.address_display = get_address_display(self.doc.supplier_address) - def set_contact_fields(self): party_type, party_name = self.get_party_type_and_name() @@ -53,96 +31,6 @@ class TransactionBase(StatusUpdater): break return self._party_type_and_name - - def get_customer_defaults(self): - if not self.doc.customer: return {} - - out = self.get_default_address_and_contact("customer") - - customer = webnotes.doc("Customer", self.doc.customer) - for f in ['customer_name', 'customer_group', 'territory']: - out[f] = customer.fields.get(f) - - # fields prepended with default in Customer doctype - for f in ['sales_partner', 'commission_rate', 'currency', 'price_list', 'taxes_and_charges']: - if customer.fields.get("default_" + f): - out[f] = customer.fields.get("default_" + f) - - return out - - def set_customer_defaults(self): - """ - For a customer: - 1. Sets default address and contact - 2. Sets values like Territory, Customer Group, etc. - 3. Clears existing Sales Team and fetches the one mentioned in Customer - """ - customer_defaults = self.get_customer_defaults() - - customer_defaults["selling_price_list"] = \ - self.get_user_default_price_list("selling_price_list") or \ - customer_defaults.get("price_list") or \ - webnotes.conn.get_value("Customer Group", self.doc.customer_group, - "default_price_list") or self.doc.selling_price_list - - for fieldname, val in customer_defaults.items(): - if self.meta.get_field(fieldname): - self.doc.fields[fieldname] = val - - if self.meta.get_field("sales_team") and self.doc.customer: - self.set_sales_team_for_customer() - - def get_user_default_price_list(self, price_list): - from webnotes.defaults import get_defaults_for - user_default_price_list = get_defaults_for(webnotes.session.user).get(price_list) - return cstr(user_default_price_list) \ - if not isinstance(user_default_price_list, list) else "" - - def set_sales_team_for_customer(self): - from webnotes.model import default_fields - - # clear table - self.doclist = self.doc.clear_table(self.doclist, "sales_team") - - sales_team = webnotes.conn.sql("""select * from `tabSales Team` - where parenttype="Customer" and parent=%s""", self.doc.customer, as_dict=True) - for i, sales_person in enumerate(sales_team): - # remove default fields - for fieldname in default_fields: - if fieldname in sales_person: - del sales_person[fieldname] - - sales_person.update({ - "doctype": "Sales Team", - "parentfield": "sales_team", - "idx": i + 1 - }) - - # add child - self.doclist.append(sales_person) - - def get_supplier_defaults(self): - out = self.get_default_address_and_contact("supplier") - - supplier = webnotes.doc("Supplier", self.doc.supplier) - out["supplier_name"] = supplier.supplier_name - if supplier.default_currency: - out["currency"] = supplier.default_currency - - # fields prepended with default in Customer doctype - for f in ['currency', 'taxes_and_charges']: - if supplier.fields.get("default_" + f): - out[f] = supplier.fields.get("default_" + f) - - out["buying_price_list"] = self.get_user_default_price_list("buying_price_list") or \ - supplier.default_price_list or self.doc.buying_price_list - - return out - - def set_supplier_defaults(self): - for fieldname, val in self.get_supplier_defaults().items(): - if self.meta.get_field(fieldname): - self.doc.fields[fieldname] = val def get_lead_defaults(self): out = self.get_default_address_and_contact("lead") @@ -157,88 +45,6 @@ class TransactionBase(StatusUpdater): def set_lead_defaults(self): self.doc.fields.update(self.get_lead_defaults()) - - def get_customer_address(self, args): - args = json.loads(args) - ret = { - 'customer_address' : args["address"], - 'address_display' : get_address_display(args["address"]), - } - if args.get('contact'): - ret.update(map_party_contact_details(args['contact'])) - - return ret - - def set_customer_address(self, args): - self.doc.fields.update(self.get_customer_address(args)) - - # TODO deprecate this - used only in sales_order.js - def get_shipping_address(self, name): - shipping_address = get_default_address("customer", name, is_shipping_address=True) - return { - 'shipping_address_name' : shipping_address, - 'shipping_address' : get_address_display(shipping_address) if shipping_address else None - } - - # Get Supplier Default Primary Address - first load - # ----------------------- - def get_default_supplier_address(self, args): - if isinstance(args, basestring): - args = json.loads(args) - - address_name = get_default_address("supplier", args["supplier"]) - ret = { - 'supplier_address' : address_name, - 'address_display' : get_address_display(address_name), - } - ret.update(map_party_contact_details(None, "supplier", args["supplier"])) - ret.update(self.get_supplier_details(args['supplier'])) - return ret - - # Get Supplier Address - # ----------------------- - def get_supplier_address(self, args): - args = json.loads(args) - ret = { - 'supplier_address' : args['address'], - 'address_display' : get_address_display(args["address"]), - } - ret.update(map_party_contact_details(contact_name=args['contact'])) - return ret - - def set_supplier_address(self, args): - self.doc.fields.update(self.get_supplier_address(args)) - - # Get Supplier Details - # ----------------------- - def get_supplier_details(self, name): - supplier_details = webnotes.conn.sql("""\ - select supplier_name, default_currency - from `tabSupplier` - where name = %s and docstatus < 2""", name, as_dict=1) - if supplier_details: - return { - 'supplier_name': (supplier_details[0]['supplier_name'] - or self.doc.fields.get('supplier_name')), - 'currency': (supplier_details[0]['default_currency'] - or self.doc.fields.get('currency')), - } - else: - return {} - - # Get Sales Person Details of Customer - # ------------------------------------ - def get_sales_person(self, name): - self.doclist = self.doc.clear_table(self.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'" % name): - ch = addchild(self.doc, 'sales_team', 'Sales Team', self.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 def load_notification_message(self): dt = self.doc.doctype.lower().replace(" ", "_") @@ -321,68 +127,13 @@ class TransactionBase(StatusUpdater): if prevdoc_values[field] is not None: self.validate_value(field, condition, prevdoc_values[field], doc) -def get_default_address_and_contact(party_field, party_name, fetch_shipping_address=False): - out = {} - - # get addresses - billing_address = get_default_address(party_field, party_name) - if billing_address: - out[party_field + "_address"] = billing_address - out["address_display"] = get_address_display(billing_address) - else: - out[party_field + "_address"] = out["address_display"] = None - - if fetch_shipping_address: - shipping_address = get_default_address(party_field, party_name, is_shipping_address=True) - if shipping_address: - out["shipping_address_name"] = shipping_address - out["shipping_address"] = get_address_display(shipping_address) - else: - out["shipping_address_name"] = out["shipping_address"] = None - - # get contact - if party_field == "lead": - out["customer_address"] = out.get("lead_address") - out.update(map_lead_contact_details(party_name)) - else: - out.update(map_party_contact_details(None, party_field, party_name)) - - return out - -def get_default_address(party_field, party_name, is_shipping_address=False): - if is_shipping_address: - order_by = "is_shipping_address desc, is_primary_address desc, name asc" - else: - order_by = "is_primary_address desc, name asc" - - address = webnotes.conn.sql("""select name from `tabAddress` where `%s`=%s order by %s - limit 1""" % (party_field, "%s", order_by), party_name) - - return address[0][0] if address else None - def get_default_contact(party_field, party_name): contact = webnotes.conn.sql("""select name from `tabContact` where `%s`=%s order by is_primary_contact desc, name asc limit 1""" % (party_field, "%s"), (party_name,)) return contact[0][0] if contact else None - -def get_address_display(address_dict): - if not isinstance(address_dict, dict): - address_dict = webnotes.conn.get_value("Address", address_dict, "*", as_dict=True) or {} - - meta = webnotes.get_doctype("Address") - sequence = (("", "address_line1"), ("\n", "address_line2"), ("\n", "city"), - ("\n", "state"), ("\n" + meta.get_label("pincode") + ": ", "pincode"), ("\n", "country"), - ("\n" + meta.get_label("phone") + ": ", "phone"), ("\n" + meta.get_label("fax") + ": ", "fax")) - - display = "" - for separator, fieldname in sequence: - if address_dict.get(fieldname): - display += separator + address_dict.get(fieldname) - return display.strip() - def map_lead_contact_details(party_name): out = {} for fieldname in ["contact_display", "contact_email", "contact_mobile", "contact_phone"]: