diff --git a/erpnext/__init__.py b/erpnext/__init__.py index e0a37e9d5f..6dc828c721 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.48' +__version__ = '10.1.49' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 566baa55f5..eef85de0b9 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -212,10 +212,13 @@ def validate_account_number(name, account_number, company): @frappe.whitelist() def update_account_number(name, account_name, account_number=None): - account = frappe.db.get_value("Account", name, ["company"], as_dict=True) + account = frappe.db.get_value("Account", name, "company", as_dict=True) + if not account: return validate_account_number(name, account_number, account.company) if account_number: frappe.db.set_value("Account", name, "account_number", account_number.strip()) + else: + frappe.db.set_value("Account", name, "account_number", "") frappe.db.set_value("Account", name, "account_name", account_name.strip()) new_name = get_account_autoname(account_number, account_name, account.company) diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py index cce4d48e7d..cdbe95bdc9 100644 --- a/erpnext/accounts/doctype/budget/budget.py +++ b/erpnext/accounts/doctype/budget/budget.py @@ -29,13 +29,21 @@ class Budget(Document): def validate_duplicate(self): budget_against_field = frappe.scrub(self.budget_against) budget_against = self.get(budget_against_field) - existing_budget = frappe.db.get_value("Budget", {budget_against_field: budget_against, - "fiscal_year": self.fiscal_year, "company": self.company, - "name": ["!=", self.name], "docstatus": ["!=", 2]}) - if existing_budget: - frappe.throw(_("Another Budget record '{0}' already exists against {1} '{2}' for fiscal year {3}") - .format(existing_budget, self.budget_against, budget_against, self.fiscal_year), DuplicateBudgetError) - + + accounts = [d.account for d in self.accounts] or [] + existing_budget = frappe.db.sql(""" + select + b.name, ba.account from `tabBudget` b, `tabBudget Account` ba + where + ba.parent = b.name and b.company = %s and %s=%s and + b.fiscal_year=%s and b.name != %sand ba.account in (%s) """ + % ('%s', budget_against_field, '%s', '%s', '%s', ','.join(['%s'] * len(accounts))), + (self.company, budget_against, self.fiscal_year, self.name) + tuple(accounts), as_dict=1) + + for d in existing_budget: + frappe.throw(_("Another Budget record '{0}' already exists against {1} '{2}' and account '{3}' for fiscal year {4}") + .format(d.name, self.budget_against, budget_against, d.account, self.fiscal_year), DuplicateBudgetError) + def validate_accounts(self): account_list = [] for d in self.get('accounts'): diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json index c21830700b..66d527da4d 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.json +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json @@ -139,7 +139,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -777,7 +777,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -827,7 +827,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:44.156222", + "modified": "2018-08-21 16:15:45.156222", "modified_by": "Administrator", "module": "Accounts", "name": "GL Entry", diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 347a950566..690a7a3443 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -438,7 +438,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index eddcd5ecd3..a072199f84 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -204,7 +204,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -853,7 +853,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-05 17:50:25.961397", + "modified": "2018-05-07 17:50:25.961397", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index ebb98d52d4..bffe6690a1 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -304,7 +304,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -1531,7 +1531,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -1906,7 +1906,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 14:44:28.647566", + "modified": "2018-08-21 15:44:28.647566", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 4548c044cb..eaafdc0a08 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -604,6 +604,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2291,7 +2323,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-07-22 18:00:51.377605", + "modified": "2018-08-06 05:18:38.205356", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index d1c1838d30..70429a46f0 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -830,6 +830,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2616,7 +2648,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-14 06:26:59.609228", + "modified": "2018-08-06 05:18:07.578350", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 3691b1ec74..abcfa73a07 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -124,9 +124,6 @@ class ReceivablePayableReport(object): currency_precision = get_currency_precision() or 2 dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" - dn_details = get_dn_details(args.get("party_type")) - voucher_details = self.get_voucher_details(args.get("party_type"), dn_details) - future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type")) if not self.filters.get("company"): @@ -139,7 +136,14 @@ class ReceivablePayableReport(object): data = [] pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date) - for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")): + gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type")) + + if gl_entries_data: + voucher_nos = [d.voucher_no for d in gl_entries_data] or [] + dn_details = get_dn_details(args.get("party_type"), voucher_nos) + voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details) + + for gle in gl_entries_data: if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers): outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, self.filters.report_date, dr_or_cr, return_entries, currency_precision) @@ -172,7 +176,7 @@ class ReceivablePayableReport(object): if self.filters.ageing_based_on == "Due Date": entry_date = due_date elif self.filters.ageing_based_on == "Supplier Invoice Date": - entry_date = bill_date + entry_date = bill_date else: entry_date = gle.posting_date @@ -221,12 +225,11 @@ class ReceivablePayableReport(object): def get_entries_after(self, report_date, party_type): # returns a distinct list - return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries(party_type) - if getdate(e.posting_date) > report_date])) + return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries(party_type, report_date, for_future=True)])) def get_entries_till(self, report_date, party_type): # returns a generator - return (e for e in self.get_gl_entries(party_type) if getdate(e.posting_date) <= report_date) + return self.get_gl_entries(party_type, report_date) def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers): return ( @@ -289,42 +292,31 @@ class ReceivablePayableReport(object): return self.party_map - def get_voucher_details(self, party_type, dn_details): - voucher_details = frappe._dict() + def get_gl_entries(self, party_type, date=None, for_future=False): + conditions, values = self.prepare_conditions(party_type) - if party_type == "Customer": - for si in frappe.db.sql("""select name, due_date, po_no - from `tabSales Invoice` where docstatus=1""", as_dict=1): - si['delivery_note'] = dn_details.get(si.name) - voucher_details.setdefault(si.name, si) + if self.filters.get(scrub(party_type)): + select_fields = "sum(debit_in_account_currency) as debit, sum(credit_in_account_currency) as credit" + else: + select_fields = "sum(debit) as debit, sum(credit) as credit" - if party_type == "Supplier": - for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date - from `tabPurchase Invoice` where docstatus = 1 - union - select name, due_date, bill_no, bill_date from `tabJournal Entry` - where docstatus = 1 and bill_no is not NULL""", as_dict=1): - voucher_details.setdefault(pi.name, pi) + if date and not for_future: + conditions += " and posting_date <= '%s'" % date - return voucher_details + if date and for_future: + conditions += " and posting_date > '%s'" % date - def get_gl_entries(self, party_type): - if not hasattr(self, "gl_entries"): - conditions, values = self.prepare_conditions(party_type) - - if self.filters.get(scrub(party_type)): - select_fields = "sum(debit_in_account_currency) as debit, sum(credit_in_account_currency) as credit" - else: - select_fields = "sum(debit) as debit, sum(credit) as credit" - - self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, - voucher_type, voucher_no, against_voucher_type, against_voucher, - account_currency, remarks, {0} - from `tabGL Entry` - where docstatus < 2 and party_type=%s and (party is not null and party != '') {1} + self.gl_entries = frappe.db.sql(""" + select + name, posting_date, account, party_type, party, voucher_type, voucher_no, + against_voucher_type, against_voucher, account_currency, remarks, {0} + from + `tabGL Entry` + where + docstatus < 2 and party_type=%s and (party is not null and party != '') {1} group by voucher_type, voucher_no, against_voucher_type, against_voucher, party order by posting_date, party""" - .format(select_fields, conditions), values, as_dict=True) + .format(select_fields, conditions), values, as_dict=True) return self.gl_entries @@ -492,18 +484,57 @@ def get_pdc_details(party_type, report_date): return pdc_details -def get_dn_details(party_type): +def get_dn_details(party_type, voucher_nos): dn_details = frappe._dict() if party_type == "Customer": - for si in frappe.db.sql("""select parent, GROUP_CONCAT(delivery_note SEPARATOR ', ') as dn - from `tabSales Invoice Item` - where docstatus=1 and delivery_note is not null and delivery_note != '' group by parent - Union - select against_sales_invoice as parent, GROUP_CONCAT(parent SEPARATOR ', ') as dn - from `tabDelivery Note Item` - where docstatus=1 and against_sales_invoice is not null - and against_sales_invoice != '' group by against_sales_invoice""", as_dict=1): + for si in frappe.db.sql(""" + select + parent, GROUP_CONCAT(delivery_note SEPARATOR ', ') as dn + from + `tabSales Invoice Item` + where + docstatus=1 and delivery_note is not null and delivery_note != '' + and parent in (%s) group by parent + """ %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1): + dn_details.setdefault(si.parent, si.dn) + + for si in frappe.db.sql(""" + select + against_sales_invoice as parent, GROUP_CONCAT(parent SEPARATOR ', ') as dn + from + `tabDelivery Note Item` + where + docstatus=1 and against_sales_invoice is not null and against_sales_invoice != '' + and against_sales_invoice in (%s) + group by against_sales_invoice + """ %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1): + if si.parent in dn_details: + dn_details[si.parent] += ', %s' %(si.dn) + else: dn_details.setdefault(si.parent, si.dn) return dn_details + +def get_voucher_details(party_type, voucher_nos, dn_details): + voucher_details = frappe._dict() + + if party_type == "Customer": + for si in frappe.db.sql("""select name, due_date, po_no + from `tabSales Invoice` where docstatus=1 and name in (%s) + """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1): + si['delivery_note'] = dn_details.get(si.name) + voucher_details.setdefault(si.name, si) + + if party_type == "Supplier": + for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date + from `tabPurchase Invoice` where docstatus = 1 and name in (%s) + """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1): + voucher_details.setdefault(pi.name, pi) + + for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date from + `tabJournal Entry` where docstatus = 1 and bill_no is not NULL and name in (%s) + """ %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1): + voucher_details.setdefault(pi.name, pi) + + return voucher_details diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js index 6f0c428c4d..74963c2aa9 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.js +++ b/erpnext/assets/doctype/asset_category/asset_category.js @@ -22,7 +22,7 @@ frappe.ui.form.on('Asset Category', { var d = locals[cdt][cdn]; return { "filters": { - "root_type": "Asset", + "account_type": "Accumulated Depreciation", "is_group": 0, "company": d.company_name } @@ -52,4 +52,4 @@ frappe.ui.form.on('Asset Category', { }); } -}); \ No newline at end of file +}); diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 2623078013..0423588d05 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -676,6 +676,38 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "col_break3", "fieldtype": "Column Break", "hidden": 0, @@ -2309,7 +2341,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-07-18 07:53:54.677844", + "modified": "2018-08-06 05:16:58.258276", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index da78c12ba0..e3c581e7f8 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -470,6 +470,38 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1645,7 +1677,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-01-25 15:04:40.171617", + "modified": "2018-08-06 05:33:07.404385", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index fe85540a10..4c16323ca3 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -219,7 +219,8 @@ def bom(doctype, txt, searchfield, start, page_len, filters): def get_project_name(doctype, txt, searchfield, start, page_len, filters): cond = '' if filters.get('customer'): - cond = '(`tabProject`.customer = "' + filters['customer'] + '" or ifnull(`tabProject`.customer,"")="") and' + cond = """(`tabProject`.customer = '%s' or + ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer"))) return frappe.db.sql("""select `tabProject`.name from `tabProject` where `tabProject`.status not in ("Completed", "Cancelled") diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index ea5116ff43..43d820ff39 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -149,6 +149,7 @@ def get_ref_item_dict(valid_items, ref_item_row): "rejected_qty": 0, "received_qty": 0, "serial_no": [], + "conversion_factor": ref_item_row.get("conversion_factor", 1), "batch_no": [] })) item_dict = valid_items[ref_item_row.item_code] diff --git a/erpnext/education/doctype/assessment_result/assessment_result.json b/erpnext/education/doctype/assessment_result/assessment_result.json index 1bca275546..80eed7bea9 100644 --- a/erpnext/education/doctype/assessment_result/assessment_result.json +++ b/erpnext/education/doctype/assessment_result/assessment_result.json @@ -1,7 +1,7 @@ { "allow_copy": 0, "allow_guest_to_view": 0, - "allow_import": 0, + "allow_import": 1, "allow_rename": 0, "autoname": "EDU-RES-.YYYY.-.#####", "beta": 0, @@ -704,7 +704,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:55.372499", + "modified": "2018-08-21 17:15:55.372499", "modified_by": "Administrator", "module": "Education", "name": "Assessment Result", diff --git a/erpnext/hub_node/page/__init__.py b/erpnext/hub_node/page/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches.txt b/erpnext/patches.txt index b971a58f21..cbc02e2980 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -557,4 +557,5 @@ erpnext.patches.v11_0.set_department_for_doctypes erpnext.patches.v11_0.update_allow_transfer_for_manufacture erpnext.patches.v11_0.add_item_group_defaults erpnext.patches.v10_0.update_address_template_for_india - +erpnext.patches.v10_0.set_discount_amount +erpnext.patches.v10_0.recalculate_gross_margin_for_project diff --git a/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py b/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py new file mode 100644 index 0000000000..6d461f3bc9 --- /dev/null +++ b/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py @@ -0,0 +1,14 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('projects', 'doctype', 'project') + for d in frappe.db.sql(""" select name from `tabProject` where + ifnull(total_consumed_material_cost, 0 ) > 0 and ifnull(total_billed_amount, 0) > 0""", as_dict=1): + doc = frappe.get_doc("Project", d.name) + doc.calculate_gross_margin() + doc.db_set('gross_margin', doc.gross_margin) + doc.db_set('per_gross_margin', doc.per_gross_margin) \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_discount_amount.py b/erpnext/patches/v10_0/set_discount_amount.py new file mode 100644 index 0000000000..019d245d45 --- /dev/null +++ b/erpnext/patches/v10_0/set_discount_amount.py @@ -0,0 +1,56 @@ + +import frappe + +def execute(): + frappe.reload_doc("accounts", "doctype", "sales_invoice_item") + frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_item') + frappe.reload_doc('buying', 'doctype', 'purchase_order_item') + frappe.reload_doc('buying', 'doctype', 'supplier_quotation_item') + frappe.reload_doc('selling', 'doctype', 'sales_order_item') + frappe.reload_doc('selling', 'doctype', 'quotation_item') + frappe.reload_doc('stock', 'doctype', 'delivery_note_item') + frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item') + + selling_doctypes = ["Sales Order Item", "Sales Invoice Item", "Delivery Note Item", "Quotation Item"] + buying_doctypes = ["Purchase Order Item", "Purchase Invoice Item", "Purchase Receipt Item", "Supplier Quotation Item"] + + for doctype in selling_doctypes: + values = frappe.db.sql(''' + SELECT + discount_percentage, rate_with_margin, price_list_rate, name + FROM + `tab%s` + WHERE + ifnull(discount_percentage, 0) > 0 + ''' % (doctype), as_dict=True) + calculate_discount(doctype, values) + + for doctype in buying_doctypes: + values = frappe.db.sql(''' + SELECT + discount_percentage, price_list_rate, name + FROM + `tab%s` + WHERE + discount_percentage > 0 + ''' % (doctype), as_dict=True) + calculate_discount(doctype, values) + +def calculate_discount(doctype, values): + rate = None + if not values: return + for d in values: + if d.rate_with_margin and d.rate_with_margin > 0: + rate = d.rate_with_margin + else: + rate = d.price_list_rate + + discount_value = rate * d.get('discount_percentage') / 100 + frappe.db.sql(''' + UPDATE + `tab%s` + SET + discount_amount = %s + WHERE + name = '%s' + ''' % (doctype, discount_value, d.get('name'))) diff --git a/erpnext/portal/doctype/products_settings/products_settings.json b/erpnext/portal/doctype/products_settings/products_settings.json index 2d025cfe65..69abae13a4 100644 --- a/erpnext/portal/doctype/products_settings/products_settings.json +++ b/erpnext/portal/doctype/products_settings/products_settings.json @@ -14,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +42,43 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +105,75 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "show_availability_status", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Show Availability Status", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -103,6 +202,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -116,7 +216,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2017-11-07 19:34:33.055048", + "modified": "2018-08-14 17:59:58.473100", "modified_by": "Administrator", "module": "Portal", "name": "Products Settings", diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index b231ee1d74..8b73b9b392 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -72,6 +72,7 @@ class Project(Document): self.tasks = [] self.load_tasks() self.send_welcome_email() + self.update_percent_complete() def validate_project_name(self): if self.get("__islocal") and frappe.db.exists("Project", self.project_name): @@ -239,10 +240,13 @@ class Project(Document): self.update_purchase_costing() self.update_sales_amount() self.update_billed_amount() + self.calculate_gross_margin() - self.gross_margin = flt(self.total_billed_amount) - ( - flt(self.total_costing_amount) + flt(self.total_expense_claim) + flt(self.total_purchase_cost)) + def calculate_gross_margin(self): + expense_amount = (flt(self.total_costing_amount) + flt(self.total_expense_claim) + + flt(self.total_purchase_cost) + flt(self.get('total_consumed_material_cost', 0))) + self.gross_margin = flt(self.total_billed_amount) - expense_amount if self.total_billed_amount: self.per_gross_margin = (self.gross_margin / flt(self.total_billed_amount)) * 100 diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 0ecf6e15f3..55fcaab3e7 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -119,7 +119,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ if (doc.doctype == "Purchase Order" && item.blanket_order_rate) { item_rate = item.blanket_order_rate; } - item.rate = flt(item_rate * (1 - item.discount_percentage / 100.0), precision("rate", item)); + item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100; + item.rate = flt((item.price_list_rate) - (item.discount_amount), precision('rate', item)); this.calculate_taxes_and_totals(); }, diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 9279021af5..ecf1d955ba 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -19,8 +19,8 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ item.rate = flt(item.rate_with_margin , precision("rate", item)); if(item.discount_percentage){ - var discount_value = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; - item.rate = flt((item.rate_with_margin) - (discount_value), precision('rate', item)); + item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; + item.rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item)); } }, diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 005cc5a04a..3b1c4805cc 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -847,6 +847,38 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount", "fieldname": "base_rate_with_margin", "fieldtype": "Currency", @@ -1878,7 +1910,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2018-08-21 16:15:52.750381", + "modified": "2018-08-22 16:15:52.750381", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 7795becad7..675526b4a3 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -878,6 +878,38 @@ "unique": 0, "width": "70px" }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2370,7 +2402,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2018-07-26 05:52:36.908884", + "modified": "2018-08-08 05:17:51.297862", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 4eb99c5df5..038fb44e32 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -146,6 +146,15 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.set_gross_profit(item); }, + discount_amount: function(doc, cdt, cdn) { + var item = frappe.get_doc(cdt, cdn); + if(!item.price_list_rate) { + item.discount_amount = 0.0; + } else { + this.price_list_rate(doc, cdt, cdn); + } + }, + commission_rate: function() { this.calculate_commission(); refresh_field("total_commission"); diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index 9e35d27ff4..6bc9036195 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -166,6 +166,9 @@ def get_item_for_list_in_html(context): if (context.get("website_image") or "").startswith("files/"): context["website_image"] = "/" + urllib.quote(context["website_image"]) + context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings', + 'show_availability_status')) + products_template = 'templates/includes/products_as_grid.html' if cint(frappe.db.get_single_value('Products Settings', 'products_as_list')): products_template = 'templates/includes/products_as_list.html' diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index ebf7ea170e..98887c3d59 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -845,6 +845,38 @@ "unique": 0, "width": "100px" }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2207,7 +2239,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-04-11 14:05:39.905947", + "modified": "2018-08-07 05:18:26.132899", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index cfd80aac1a..f547ef0763 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -785,6 +785,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "discount_percentage", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Amount", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2496,7 +2528,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-08 06:56:45.396664", + "modified": "2018-08-09 06:56:45.396664", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e3dfff7d60..cd0255e0cc 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -99,6 +99,7 @@ class StockEntry(StockController): self.update_stock_ledger() self.make_gl_entries_on_cancel() + self.update_cost_in_project() def validate_work_order_status(self): pro_doc = frappe.get_doc("Work Order", self.work_order) @@ -129,8 +130,8 @@ class StockEntry(StockController): se.docstatus = 1 and se.project = %s and sed.parent = se.name and (sed.t_warehouse is null or sed.t_warehouse = '')""", self.project, as_list=1) - if amount: - frappe.db.set_value('Project', self.project, 'total_consumed_material_cost', amount[0][0]) + amount = amount[0][0] if amount else 0 + frappe.db.set_value('Project', self.project, 'total_consumed_material_cost', amount) def validate_item(self): stock_items = self.get_stock_items() diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index e73c6270af..420d9d8c3e 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -645,8 +645,8 @@ def get_projected_qty(item_code, warehouse): @frappe.whitelist() def get_bin_details(item_code, warehouse): return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, - ["projected_qty", "actual_qty"], as_dict=True, cache=True) \ - or {"projected_qty": 0, "actual_qty": 0} + ["projected_qty", "actual_qty", "reserved_qty"], as_dict=True, cache=True) \ + or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} @frappe.whitelist() def get_serial_no_details(item_code, warehouse, stock_qty, serial_no): diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 7d73f77847..55078a55f7 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -11,8 +11,7 @@ from six import string_types class InvalidWarehouseCompany(frappe.ValidationError): pass -def get_stock_value_from_bin (warehouse=None, item_code=None): - +def get_stock_value_from_bin(warehouse=None, item_code=None): values = {} conditions = "" if warehouse: @@ -28,14 +27,13 @@ def get_stock_value_from_bin (warehouse=None, item_code=None): if item_code: conditions += " and item_code = %(item_code)s" - values['item_code'] = item_code - query = "select sum(stock_value) from `tabBin` where 1 = 1" + conditions + query = "select sum(stock_value) from `tabBin` where 1 = 1 %s" % conditions stock_value = frappe.db.sql(query, values) - return stock_value; + return stock_value def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): if not posting_date: posting_date = nowdate() diff --git a/erpnext/templates/includes/products_as_grid.html b/erpnext/templates/includes/products_as_grid.html index a057f5d6f2..9908c8a247 100644 --- a/erpnext/templates/includes/products_as_grid.html +++ b/erpnext/templates/includes/products_as_grid.html @@ -12,8 +12,9 @@
 
 
{% endif %} - {% if show_stock_qty %} - {% if in_stock %} + + {% if show_availability_status %} + {% if in_stock or not is_stock_item %}
{{ _("In stock") }}
{% else %}
{{ _("Not in stock") }}