diff --git a/erpnext/accounts/doctype/c_form/c_form.py b/erpnext/accounts/doctype/c_form/c_form.py index e0f008f8ad..88ced9a813 100644 --- a/erpnext/accounts/doctype/c_form/c_form.py +++ b/erpnext/accounts/doctype/c_form/c_form.py @@ -55,12 +55,12 @@ class CForm(Document): def get_invoice_details(self, invoice_no): """ Pull details from invoices for referrence """ - - inv = frappe.db.get_value("Sales Invoice", invoice_no, - ["posting_date", "territory", "net_total", "grand_total"], as_dict=True) - return { - 'invoice_date' : inv.posting_date, - 'territory' : inv.territory, - 'net_total' : inv.net_total, - 'grand_total' : inv.grand_total - } + if invoice_no: + inv = frappe.db.get_value("Sales Invoice", invoice_no, + ["posting_date", "territory", "net_total", "grand_total"], as_dict=True) + return { + 'invoice_date' : inv.posting_date, + 'territory' : inv.territory, + 'net_total' : inv.net_total, + 'grand_total' : inv.grand_total + } diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 9141697a77..9a3b3121f4 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -183,7 +183,7 @@ def get_pricing_rules(args): group_condition = _get_tree_conditions(parenttype) if group_condition: conditions += " and " + group_condition - + if not args.price_list: args.price_list = None conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')" if args.get("transaction_date"): diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 80aa73a197..74a9628209 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -30,6 +30,7 @@ class PurchaseInvoice(BuyingController): 'target_ref_field': 'amount', 'source_field': 'amount', 'percent_join_field': 'purchase_order', + 'overflow_type': 'billing' }] def validate(self): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 834865bcd6..0f6737cc87 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -36,7 +36,8 @@ class SalesInvoice(SellingController): 'join_field': 'so_detail', 'percent_join_field': 'sales_order', 'status_field': 'billing_status', - 'keyword': 'Billed' + 'keyword': 'Billed', + 'overflow_type': 'billing' }] def validate(self): @@ -134,7 +135,8 @@ class SalesInvoice(SellingController): 'keyword':'Delivered', 'second_source_dt': 'Delivery Note Item', 'second_source_field': 'qty', - 'second_join_field': 'prevdoc_detail_docname' + 'second_join_field': 'prevdoc_detail_docname', + 'overflow_type': 'delivery' }) def on_update_after_submit(self): @@ -339,8 +341,8 @@ class SalesInvoice(SellingController): def validate_pos(self): if not self.cash_bank_account and flt(self.paid_amount): - msgprint(_("Cash or Bank Account is mandatory for making payment entry")) - raise Exception + frappe.throw(_("Cash or Bank Account is mandatory for making payment entry")) + if flt(self.paid_amount) + flt(self.write_off_amount) \ - flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)): frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total""")) @@ -431,9 +433,8 @@ class SalesInvoice(SellingController): submitted = frappe.db.sql("""select name from `tabSales Order` where docstatus = 1 and name = %s""", d.sales_order) if not submitted: - msgprint(_("Sales Order {0} is not submitted").format(d.sales_order)) - raise Exception - + frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order)) + if d.delivery_note: submitted = frappe.db.sql("""select name from `tabDelivery Note` where docstatus = 1 and name = %s""", d.delivery_note) @@ -682,7 +683,7 @@ def manage_recurring_invoices(next_date=None, commit=True): if exception_list: exception_message = "\n\n".join([cstr(d) for d in exception_list]) - raise Exception, exception_message + frappe.throw(exception_message) def make_new_invoice(ref_wrapper, posting_date): from erpnext.accounts.utils import get_fiscal_year diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.html b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.html new file mode 100644 index 0000000000..91e07ab7da --- /dev/null +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.html @@ -0,0 +1,46 @@ +
{%= __("Posting Date") %} | +{%= __("Journal Voucher") %} | +{%= __("Reference") %} | +{%= __("Debit") %} | +{%= __("Credit") %} | +{%= dateutil.str_to_user(data[i].posting_date) %} | +{%= data[i].journal_voucher %} | +{%= __("Against") %}: {%= data[i].against_account %}
+ {% if (data[i].reference) { %}
+ {%= __("Reference") %}: {%= data[i].reference %} + {% if (data[i].ref_date) { %} + {%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i].ref_date) %} + {% } %} + {% } %} + {% if (data[i].clearance_date) { %} + {%= __("Clearance Date") %}: {%= dateutil.str_to_user(data[i].clearance_date) %} + {% } %} + |
+ {%= format_currency(data[i].debit) %} | +{%= format_currency(data[i].credit) %} | + + {% } else { %} +
---|---|---|---|---|
+ | + | {%= data[i].journal_voucher %} | +{%= format_currency(data[i].debit) %} | +{%= format_currency(data[i].credit) %} | +
Printed On {%= dateutil.str_to_user(dateutil.get_datetime_as_string()) %}
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index e87fbd3226..119de09e41 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -19,28 +19,29 @@ def execute(filters=None): total_debit, total_credit = 0,0 for d in data: - total_debit += flt(d[4]) - total_credit += flt(d[5]) + total_debit += flt(d[2]) + total_credit += flt(d[3]) bank_bal = flt(balance_as_per_company) - flt(total_debit) + flt(total_credit) data += [ get_balance_row("Balance as per company books", balance_as_per_company), - ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], + ["", "Amounts not reflected in bank", total_debit, total_credit, "", "", "", ""], get_balance_row("Balance as per bank", bank_bal) ] return columns, data def get_columns(): - return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", - "Clearance Date:Date:110", "Against Account:Link/Account:200", - "Debit:Currency:120", "Credit:Currency:120" + return ["Posting Date:Date:100", "Journal Voucher:Link/Journal Voucher:200", + "Debit:Currency:120", "Credit:Currency:120", + "Against Account:Link/Account:200", "Reference::100", "Ref Date:Date:110", "Clearance Date:Date:110" ] def get_entries(filters): entries = frappe.db.sql("""select - jv.name, jv.posting_date, jv.clearance_date, jvd.against_account, jvd.debit, jvd.credit + jv.posting_date, jv.name, jvd.debit, jvd.credit, + jvd.against_account, jv.cheque_no, jv.cheque_date, jv.clearance_date from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv where jvd.parent = jv.name and jv.docstatus=1 @@ -52,6 +53,6 @@ def get_entries(filters): def get_balance_row(label, amount): if amount > 0: - return ["", "", "", label, amount, 0] + return ["", label, amount, 0, "", "", "", ""] else: - return ["", "", "", label, 0, amount] + return ["", label, 0, amount, "", "", "", ""] diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 0fa7e446fe..dd8052835e 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -63,6 +63,8 @@ def get_gl_entries(filters): def get_conditions(filters): conditions = [] if filters.get("account"): + if not frappe.db.exists("Account", filters["account"]): + frappe.throw(_("Account {0} is not valid").format(filters["account"])) lft, rgt = frappe.db.get_value("Account", filters["account"], ["lft", "rgt"]) conditions.append("""account in (select name from tabAccount where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt)) diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index c3ef365f68..3c63508991 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -75,7 +75,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }, buying_price_list: function() { - this.get_price_list_currency("Buying"); + this.apply_price_list(); }, price_list_rate: function(doc, cdt, cdn) { diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 2109d72aa2..f9f5103726 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -24,6 +24,7 @@ class PurchaseOrder(BuyingController): 'target_ref_field': 'qty', 'source_field': 'qty', 'percent_join_field': 'prevdoc_docname', + 'overflow_type': 'order' }] def validate(self): diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index 99d0e4e9f5..c2b29a4a17 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -69,7 +69,8 @@ cur_frm.cscript.make_address = function() { page_length: 5, new_doctype: "Address", get_query: function() { - return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where supplier='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_address desc" + return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where supplier='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_address desc" }, as_dict: 1, no_results_message: __('No addresses created'), @@ -87,7 +88,8 @@ cur_frm.cscript.make_contact = function() { page_length: 5, new_doctype: "Contact", get_query: function() { - return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where supplier='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc" + return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where supplier='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_contact desc" }, as_dict: 1, no_results_message: __('No contacts created'), diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index df5370ae19..3df62e7934 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _, throw from frappe.utils import flt, cint, today -from erpnext.setup.utils import get_company_currency +from erpnext.setup.utils import get_company_currency, get_exchange_rate from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year from erpnext.utilities.transaction_base import TransactionBase import json @@ -68,7 +68,7 @@ class AccountsController(TransactionBase): self.plc_conversion_rate = 1.0 elif not self.plc_conversion_rate: - self.plc_conversion_rate = self.get_exchange_rate( + self.plc_conversion_rate = get_exchange_rate( self.price_list_currency, company_currency) # currency @@ -78,13 +78,9 @@ class AccountsController(TransactionBase): elif self.currency == company_currency: self.conversion_rate = 1.0 elif not self.conversion_rate: - self.conversion_rate = self.get_exchange_rate(self.currency, + self.conversion_rate = get_exchange_rate(self.currency, company_currency) - def get_exchange_rate(self, from_currency, to_currency): - exchange = "%s-%s" % (from_currency, to_currency) - return flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate")) - def set_missing_item_details(self): """set missing item values""" from erpnext.stock.get_item_details import get_item_details diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 16d27d47fc..2650c66ac2 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -32,34 +32,46 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select name, employee_name from `tabEmployee` where status = 'Active' and docstatus < 2 - and (%(key)s like "%(txt)s" - or employee_name like "%(txt)s") - %(mcond)s + and ({key} like %(txt)s + or employee_name like %(txt)s) + {mcond} order by - if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999), - if(locate("%(_txt)s", employee_name), locate("%(_txt)s", employee_name), 99999), + if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), + if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999), name, employee_name - limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, - '_txt': txt.replace("%", ""), - 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) + limit %(start)s, %(page_len)s""".format(**{ + 'key': searchfield, + 'mcond': get_match_cond(doctype) + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len + }) # searches for leads which are not converted def lead_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select name, lead_name, company_name from `tabLead` where docstatus < 2 and ifnull(status, '') != 'Converted' - and (%(key)s like "%(txt)s" - or lead_name like "%(txt)s" - or company_name like "%(txt)s") - %(mcond)s + and ({key} like %(txt)s + or lead_name like %(txt)s + or company_name like %(txt)s) + {mcond} order by - if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999), - if(locate("%(_txt)s", lead_name), locate("%(_txt)s", lead_name), 99999), - if(locate("%(_txt)s", company_name), locate("%(_txt)s", company_name), 99999), + if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), + if(locate(%(_txt)s, lead_name), locate(%(_txt)s, lead_name), 99999), + if(locate(%(_txt)s, company_name), locate(%(_txt)s, company_name), 99999), name, lead_name - limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, - '_txt': txt.replace("%", ""), - 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) + limit %(start)s, %(page_len)s""".format(**{ + 'key': searchfield, + 'mcond':get_match_cond(doctype) + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len + }) # searches for customer def customer_query(doctype, txt, searchfield, start, page_len, filters): @@ -72,19 +84,25 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters): fields = ", ".join(fields) - return frappe.db.sql("""select %(field)s from `tabCustomer` + return frappe.db.sql("""select {fields} from `tabCustomer` where docstatus < 2 - and (%(key)s like "%(txt)s" - or customer_name like "%(txt)s") - %(mcond)s + and ({key} like %(txt)s + or customer_name like %(txt)s) + {mcond} order by - if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999), - if(locate("%(_txt)s", customer_name), locate("%(_txt)s", customer_name), 99999), + if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), + if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999), name, customer_name - limit %(start)s, %(page_len)s""" % {'field': fields,'key': searchfield, - 'txt': "%%%s%%" % txt, '_txt': txt.replace("%", ""), - 'mcond':get_match_cond(doctype), - 'start': start, 'page_len': page_len}) + limit %(start)s, %(page_len)s""".format(**{ + "fields": fields, + "key": searchfield, + "mcond": get_match_cond(doctype) + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len + }) # searches for supplier def supplier_query(doctype, txt, searchfield, start, page_len, filters): @@ -95,19 +113,25 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): fields = ["name", "supplier_name", "supplier_type"] fields = ", ".join(fields) - return frappe.db.sql("""select %(field)s from `tabSupplier` + return frappe.db.sql("""select {field} from `tabSupplier` where docstatus < 2 - and (%(key)s like "%(txt)s" - or supplier_name like "%(txt)s") - %(mcond)s + and ({key} like %(txt)s + or supplier_name like %(txt)s) + {mcond} order by - if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999), - if(locate("%(_txt)s", supplier_name), locate("%(_txt)s", supplier_name), 99999), + if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), + if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999), name, supplier_name - limit %(start)s, %(page_len)s """ % {'field': fields,'key': searchfield, - 'txt': "%%%s%%" % txt, '_txt': txt.replace("%", ""), - 'mcond':get_match_cond(doctype), 'start': start, - 'page_len': page_len}) + limit %(start)s, %(page_len)s """.format(**{ + 'field': fields, + 'key': searchfield, + 'mcond':get_match_cond(doctype) + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len + }) def tax_account_query(doctype, txt, searchfield, start, page_len, filters): tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 90eacd9820..3c6355488f 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -132,11 +132,12 @@ class StatusUpdater(Document): if not item[args['target_ref_field']]: msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code)) elif args.get('no_tolerance'): - item['reduce_by'] = item[args['target_field']] - \ - item[args['target_ref_field']] + item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']] if item['reduce_by'] > .01: - msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}").format(item.item_code)) - throw(_("{0} must be less than or equal to {1}").format(_(item.target_ref_field), item[args["target_ref_field"]])) + msgprint(_("Allowance for over-{0} crossed for Item {1}") + .format(args["overflow_type"], item.item_code)) + throw(_("{0} must be reduced by {1} or you should increase overflow tolerance") + .format(_(item.target_ref_field.title()), item["reduce_by"])) else: self.check_overflow_with_tolerance(item, args) @@ -156,8 +157,10 @@ class StatusUpdater(Document): item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100) item['reduce_by'] = item[args['target_field']] - item['max_allowed'] - msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}.").format(item["item_code"])) - throw(_("{0} must be less than or equal to {1}").format(item["target_ref_field"].title(), item["max_allowed"])) + msgprint(_("Allowance for over-{0} crossed for Item {1}.") + .format(args["overflow_type"], item["item_code"])) + throw(_("{0} must be reduced by {1} or you should increase overflow tolerance") + .format(_(item["target_ref_field"].title()), item["reduce_by"])) def update_qty(self, change_modified=True): """ diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 1dde6386d2..df15916f7a 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -7,6 +7,8 @@ app_icon = "icon-th" app_color = "#e74c3c" app_version = __version__ +error_report_email = "support@erpnext.com" + app_include_js = "assets/js/erpnext.min.js" app_include_css = "assets/css/erpnext.css" web_include_js = "assets/js/erpnext-web.min.js" diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.js b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.js index 0415c911e1..d57f639f7f 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.js +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.js @@ -37,8 +37,8 @@ cur_frm.fields_dict['pp_details'].grid.get_field('item_code').get_query = functi }); } -cur_frm.fields_dict['pp_details'].grid.get_field('bom_no').get_query = function(doc) { - var d = locals[this.doctype][this.docname]; +cur_frm.fields_dict['pp_details'].grid.get_field('bom_no').get_query = function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; if (d.item_code) { return { query: "erpnext.controllers.queries.bom", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1c2112d7b8..b7fc5e7768 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -67,4 +67,4 @@ erpnext.patches.v4_0.set_naming_series_property_setter erpnext.patches.v4_1.set_outgoing_email_footer erpnext.patches.v4_1.fix_jv_remarks erpnext.patches.v4_1.fix_sales_order_delivered_status -erpnext.patches.v4_1.fix_delivery_and_billing_status_for_draft_so \ No newline at end of file +erpnext.patches.v4_1.fix_delivery_and_billing_status diff --git a/erpnext/patches/v4_1/fix_delivery_and_billing_status_for_draft_so.py b/erpnext/patches/v4_1/fix_delivery_and_billing_status.py similarity index 80% rename from erpnext/patches/v4_1/fix_delivery_and_billing_status_for_draft_so.py rename to erpnext/patches/v4_1/fix_delivery_and_billing_status.py index 8d38338e04..2dbc825085 100644 --- a/erpnext/patches/v4_1/fix_delivery_and_billing_status_for_draft_so.py +++ b/erpnext/patches/v4_1/fix_delivery_and_billing_status.py @@ -5,8 +5,8 @@ from __future__ import unicode_literals import frappe def execute(): - frappe.db.sql("""update `tabSales Order` set delivery_status = 'Not Delivered' - where delivery_status = 'Delivered' and ifnull(per_delivered, 0) = 0 and docstatus = 0""") + frappe.db.sql("""update `tabSales Order` set delivery_status = 'Not Delivered' + where delivery_status = 'Delivered' and ifnull(per_delivered, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") - frappe.db.sql("""update `tabSales Order` set billing_status = 'Not Billed' - where billing_status = 'Billed' and ifnull(per_billed, 0) = 0 and docstatus = 0""") \ No newline at end of file + frappe.db.sql("""update `tabSales Order` set billing_status = 'Not Billed' + where billing_status = 'Billed' and ifnull(per_billed, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index bce9c52688..4a14c55c3a 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -55,7 +55,7 @@ class Project(Document): "event_type": "Private", "ref_type": self.doctype, "ref_name": self.name - }).insert() + }).insert(ignore_permissions=True) def on_trash(self): delete_events(self.doctype, self.name) diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index 3c99ced701..1790a47252 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -241,31 +241,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ if(flt(this.frm.doc.conversion_rate)>0.0) { if(this.frm.doc.ignore_pricing_rule) { this.calculate_taxes_and_totals(); - } else { - this.apply_pricing_rule(); + } else if (!this.in_apply_price_list){ + this.apply_price_list(); } } }, - get_price_list_currency: function(buying_or_selling) { - var me = this; - var fieldname = buying_or_selling.toLowerCase() + "_price_list"; - if(this.frm.doc[fieldname]) { - return this.frm.call({ - method: "erpnext.setup.utils.get_price_list_currency", - args: { - price_list: this.frm.doc[fieldname], - }, - callback: function(r) { - if(!r.exc) { - me.price_list_currency(); - } - } - }); - } - }, - get_exchange_rate: function(from_currency, to_currency, callback) { var exchange_name = from_currency + "-" + to_currency; frappe.model.with_doc("Currency Exchange", exchange_name, function(name) { @@ -277,22 +259,17 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ price_list_currency: function() { var me=this; this.set_dynamic_labels(); - - var company_currency = this.get_company_currency(); - if(this.frm.doc.price_list_currency !== company_currency) { - this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency, - function(exchange_rate) { - if(exchange_rate) { - me.frm.set_value("plc_conversion_rate", exchange_rate); - me.plc_conversion_rate(); - } - }); - } else { - this.plc_conversion_rate(); - } + this.set_plc_conversion_rate(); }, plc_conversion_rate: function() { + this.set_plc_conversion_rate(); + if(!this.in_apply_price_list) { + this.apply_price_list(); + } + }, + + set_plc_conversion_rate: function() { if(this.frm.doc.price_list_currency === this.get_company_currency()) { this.frm.set_value("plc_conversion_rate", 1.0); } @@ -351,9 +328,22 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ apply_pricing_rule: function(item, calculate_taxes_and_totals) { var me = this; - var item_list = this._get_item_list(item); - var args = { - "item_list": item_list, + return this.frm.call({ + method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule", + args: { args: this._get_args(item) }, + callback: function(r) { + if (!r.exc) { + me._set_values_for_item_list(r.message); + if(calculate_taxes_and_totals) me.calculate_taxes_and_totals(); + } + } + }); + }, + + _get_args: function(item) { + var me = this; + return { + "item_list": this._get_item_list(item), "customer": me.frm.doc.customer, "customer_group": me.frm.doc.customer_group, "territory": me.frm.doc.territory, @@ -371,22 +361,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ "parenttype": me.frm.doc.doctype, "parent": me.frm.doc.name }; - return this.frm.call({ - method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule", - args: { args: args }, - callback: function(r) { - if (!r.exc) { - $.each(r.message, function(i, d) { - $.each(d, function(k, v) { - if (["doctype", "name"].indexOf(k)===-1) { - frappe.model.set_value(d.doctype, d.name, k, v); - } - }); - }); - if(calculate_taxes_and_totals) me.calculate_taxes_and_totals(); - } - } - }); }, _get_item_list: function(item) { @@ -412,6 +386,33 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ return item_list; }, + _set_values_for_item_list: function(children) { + $.each(children, function(i, d) { + $.each(d, function(k, v) { + if (["doctype", "name"].indexOf(k)===-1) { + frappe.model.set_value(d.doctype, d.name, k, v); + } + }); + }); + }, + + apply_price_list: function() { + var me = this; + return this.frm.call({ + method: "erpnext.stock.get_item_details.apply_price_list", + args: { args: this._get_args() }, + callback: function(r) { + if (!r.exc) { + me.in_apply_price_list = true; + me.frm.set_value("price_list_currency", r.message.parent.price_list_currency); + me.frm.set_value("plc_conversion_rate", r.message.parent.plc_conversion_rate); + me.in_apply_price_list = false; + me._set_values_for_item_list(r.message.children); + } + } + }); + }, + included_in_print_rate: function(doc, cdt, cdn) { var tax = frappe.get_doc(cdt, cdn); try { diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index e8407581d1..9a4a356d17 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -86,7 +86,8 @@ cur_frm.cscript.make_address = function() { page_length: 5, new_doctype: "Address", get_query: function() { - return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_address desc" + return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where customer='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_address desc" }, as_dict: 1, no_results_message: __('No addresses created'), @@ -104,7 +105,8 @@ cur_frm.cscript.make_contact = function() { page_length: 5, new_doctype: "Contact", get_query: function() { - return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc" + return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_contact desc" }, as_dict: 1, no_results_message: __('No contacts created'), diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py index 7d2d3d0663..0477abc265 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.py +++ b/erpnext/selling/doctype/installation_note/installation_note.py @@ -28,7 +28,8 @@ class InstallationNote(TransactionBase): 'source_field': 'qty', 'percent_join_field': 'prevdoc_docname', 'status_field': 'installation_status', - 'keyword': 'Installed' + 'keyword': 'Installed', + 'overflow_type': 'installation' }] def validate(self): diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index ebe1d84eda..bb5211312c 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -420,7 +420,7 @@ "label": "Taxes and Charges Calculation", "oldfieldtype": "HTML", "permlevel": 0, - "print_hide": 0 + "print_hide": 1 }, { "fieldname": "section_break_43", @@ -883,7 +883,7 @@ "idx": 1, "is_submittable": 1, "issingle": 0, - "modified": "2014-07-07 17:47:40.089520", + "modified": "2014-07-10 02:43:45.504009", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 2021490bb7..fff7ef9cd3 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -137,7 +137,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, selling_price_list: function() { - this.get_price_list_currency("Selling"); + this.apply_price_list(); }, price_list_rate: function(doc, cdt, cdn) { diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.js b/erpnext/setup/doctype/sales_partner/sales_partner.js index 02af9f7276..64c4e2106c 100644 --- a/erpnext/setup/doctype/sales_partner/sales_partner.js +++ b/erpnext/setup/doctype/sales_partner/sales_partner.js @@ -41,7 +41,8 @@ cur_frm.cscript.make_address = function() { frappe.set_route("Form", "Address", address.name); }, get_query: function() { - return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where sales_partner='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_address desc" + return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where sales_partner='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_address desc" }, as_dict: 1, no_results_message: __('No addresses created'), @@ -64,7 +65,8 @@ cur_frm.cscript.make_contact = function() { frappe.set_route("Form", "Contact", contact.name); }, get_query: function() { - return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where sales_partner='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc" + return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where sales_partner='" + + cur_frm.doc.name.replace("'", "\\'") + "' and docstatus != 2 order by is_primary_contact desc" }, as_dict: 1, no_results_message: __('No contacts created'), diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index a734ffd127..e7d78abb42 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _, throw +from frappe.utils import flt def get_company_currency(company): currency = frappe.db.get_value("Company", company, "default_currency") @@ -28,16 +29,6 @@ def get_ancestors_of(doctype, name): where lft<%s and rgt>%s order by lft desc""" % (doctype, "%s", "%s"), (lft, rgt)) return result or [] -@frappe.whitelist() -def get_price_list_currency(price_list): - price_list_currency = frappe.db.get_value("Price List", {"name": price_list, - "enabled": 1}, "currency") - - if not price_list_currency: - throw(_("Price List {0} is disabled").format(price_list)) - else: - return {"price_list_currency": price_list_currency} - def before_tests(): # complete setup if missing from erpnext.setup.page.setup_wizard.setup_wizard import setup_account @@ -64,3 +55,7 @@ def before_tests(): frappe.db.sql("delete from `tabSalary Slip`") frappe.db.sql("delete from `tabItem Price`") frappe.db.commit() + +def get_exchange_rate(from_currency, to_currency): + exchange = "%s-%s" % (from_currency, to_currency) + return flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate")) diff --git a/erpnext/startup/__init__.py b/erpnext/startup/__init__.py index 576ab05627..a3b96cf46c 100644 --- a/erpnext/startup/__init__.py +++ b/erpnext/startup/__init__.py @@ -2,17 +2,17 @@ # ERPNext - web based ERP (http://erpnext.com) # Copyright (C) 2012 Web Notes Technologies Pvt Ltd -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program. If not, see