diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 076baeaac7c..235b1b0a01e 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '8.0.37' +__version__ = '8.0.38' def get_default_company(user=None): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 6e3990ac8d2..4b1837d4d73 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -411,10 +411,10 @@ class SalesInvoice(SellingController): throw(_("Customer {0} does not belong to project {1}").format(self.customer,self.project)) def validate_pos(self): - if flt(self.paid_amount) + flt(self.write_off_amount) \ - - flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)) and self.is_return: - frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total""")) - + if self.is_return: + 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")) def validate_item_code(self): for d in self.get('items'): diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index f0c29bc36ef..0501d3870bf 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -7,10 +7,13 @@ import frappe import datetime from frappe import _, msgprint, scrub from frappe.defaults import get_user_permissions -from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, add_years, get_timestamp +from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \ + add_years, get_timestamp, nowdate from frappe.geo.doctype.address.address import get_address_display, get_default_address from frappe.email.doctype.contact.contact import get_contact_details, get_default_contact from erpnext.exceptions import PartyFrozen, InvalidCurrency, PartyDisabled, InvalidAccountCurrency +from erpnext.accounts.utils import get_fiscal_year +from erpnext import get_default_currency class DuplicatePartyAccountError(frappe.ValidationError): pass @@ -359,4 +362,37 @@ def get_timeline_data(doctype, name): timestamp = get_timestamp(date) out.update({ timestamp: count }) - return out \ No newline at end of file + return out + +def get_dashboard_info(party_type, party): + current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True) + party_account_currency = get_party_account_currency(party_type, party, frappe.db.get_default("company")) + company_default_currency = get_default_currency() + + if party_account_currency==company_default_currency: + total_field = "base_grand_total" + else: + total_field = "grand_total" + + doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" + + billing_this_year = frappe.db.sql(""" + select sum({0}) + from `tab{1}` + where {2}=%s and docstatus=1 and posting_date between %s and %s + """.format(total_field, doctype, party_type.lower()), + (party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date)) + + total_unpaid = frappe.db.sql(""" + select sum(debit_in_account_currency) - sum(credit_in_account_currency) + from `tabGL Entry` + where party_type = %s and party=%s""", (party_type, party)) + + info = {} + info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 + info["currency"] = party_account_currency + info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 + if party_type == "Supplier": + info["total_unpaid"] = -1 * info["total_unpaid"] + + return info \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 704e8285b1f..3b6ae620d16 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -6,11 +6,9 @@ import frappe import frappe.defaults from frappe import msgprint, _ from frappe.model.naming import make_autoname -from frappe.geo.address_and_contact import (load_address_and_contact, - delete_contact_and_address) - +from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address from erpnext.utilities.transaction_base import TransactionBase -from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this +from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this class Supplier(TransactionBase): def get_feed(self): @@ -22,22 +20,7 @@ class Supplier(TransactionBase): self.load_dashboard_info() def load_dashboard_info(self): - billing_this_year = frappe.db.sql(""" - select sum(credit_in_account_currency) - sum(debit_in_account_currency) - from `tabGL Entry` - where voucher_type='Purchase Invoice' and party_type = 'Supplier' - and party=%s and fiscal_year = %s""", - (self.name, frappe.db.get_default("fiscal_year"))) - - total_unpaid = frappe.db.sql("""select sum(outstanding_amount) - from `tabPurchase Invoice` - where supplier=%s and docstatus = 1""", self.name) - - - info = {} - info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 - info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 - + info = get_dashboard_info(self.doctype, self.name) self.set_onload('dashboard_info', info) def autoname(self): diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ac91f6038b7..853efa1cc30 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -396,3 +396,4 @@ erpnext.patches.v8_0.merge_student_batch_and_student_group erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017 erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice +erpnext.patches.v8_0.delete_schools_depricated_doctypes diff --git a/erpnext/patches/v7_2/update_assessment_modules.py b/erpnext/patches/v7_2/update_assessment_modules.py index 9c00902f862..9075bbf87db 100644 --- a/erpnext/patches/v7_2/update_assessment_modules.py +++ b/erpnext/patches/v7_2/update_assessment_modules.py @@ -3,26 +3,32 @@ from frappe.model.utils.rename_field import rename_field def execute(): #Rename Grading Structure to Grading Scale - frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True) - frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True) + if not frappe.db.exists("DocType", "Grading Scale"): + frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True) + if not frappe.db.exists("DocType", "Grading Scale Interval"): + frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True) frappe.reload_doc("schools", "doctype", "grading_scale_interval") - rename_field("Grading Scale Interval", "to_score", "threshold") + if "to_score" in frappe.db.get_table_columns("Grading Scale Interval"): + rename_field("Grading Scale Interval", "to_score", "threshold") - frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True) + if not frappe.db.exists("DocType", "Assessment Plan"): + frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True) #Rename Assessment Results frappe.reload_doc("schools", "doctype", "assessment_plan") - rename_field("Assessment Plan", "grading_structure", "grading_scale") + if "grading_structure" in frappe.db.get_table_columns("Assessment Plan"): + rename_field("Assessment Plan", "grading_structure", "grading_scale") frappe.reload_doc("schools", "doctype", "assessment_result") frappe.reload_doc("schools", "doctype", "assessment_result_detail") frappe.reload_doc("schools", "doctype", "assessment_criteria") - for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]): - print assessment - for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", assessment.name, as_dict=True): + for assessment in frappe.get_all("Assessment Plan", + fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]): + for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", + assessment.name, as_dict=True): if stud_result.result: assessment_result = frappe.new_doc("Assessment Result") assessment_result.student = stud_result.student diff --git a/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py b/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py new file mode 100644 index 00000000000..09a78ed3ca6 --- /dev/null +++ b/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py @@ -0,0 +1,14 @@ +# Copyright (c) 2017, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + """ delete doctypes """ + + if frappe.db.exists("DocType", "Grading Structure"): + frappe.delete_doc("DocType", "Grading Structure", force=1) + + if frappe.db.exists("DocType", "Grade Interval"): + frappe.delete_doc("DocType", "Grade Interval", force=1) \ No newline at end of file diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html index 181a41f2d5e..6065e603c79 100644 --- a/erpnext/public/js/pos/pos.html +++ b/erpnext/public/js/pos/pos.html @@ -68,12 +68,12 @@ - \ No newline at end of file + diff --git a/erpnext/schools/doctype/grade_interval/__init__.py b/erpnext/schools/doctype/grade_interval/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/schools/doctype/grade_interval/grade_interval.json b/erpnext/schools/doctype/grade_interval/grade_interval.json deleted file mode 100644 index c9c59495d9e..00000000000 --- a/erpnext/schools/doctype/grade_interval/grade_interval.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2016-08-26 03:11:09.591049", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grade_code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Grade Code", - "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": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "min_score", - "fieldtype": "Percent", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Min Score", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "1", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grade_description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Grade Description", - "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, - "unique": 0 - } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2016-12-14 12:54:56.902465", - "modified_by": "Administrator", - "module": "Schools", - "name": "Grade Interval", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/schools/doctype/grade_interval/grade_interval.py b/erpnext/schools/doctype/grade_interval/grade_interval.py deleted file mode 100644 index c8ded136ecc..00000000000 --- a/erpnext/schools/doctype/grade_interval/grade_interval.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.document import Document - -class GradeInterval(Document): - def validate(self): - pass \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_structure/__init__.py b/erpnext/schools/doctype/grading_structure/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.js b/erpnext/schools/doctype/grading_structure/grading_structure.js deleted file mode 100644 index 36f45042c0c..00000000000 --- a/erpnext/schools/doctype/grading_structure/grading_structure.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Grading Structure', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.json b/erpnext/schools/doctype/grading_structure/grading_structure.json deleted file mode 100644 index 3c30f299d2f..00000000000 --- a/erpnext/schools/doctype/grading_structure/grading_structure.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 1, - "autoname": "field:grading_system_name", - "beta": 0, - "creation": "2016-08-26 03:06:53.922972", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grading_system_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Grading System Name", - "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": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 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, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "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, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grading_intervals_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Grading Intervals", - "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, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "grade_intervals", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Grade Intervals", - "length": 0, - "no_copy": 0, - "options": "Grade Interval", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2016-12-14 12:35:39.690256", - "modified_by": "Administrator", - "module": "Schools", - "name": "Grading Structure", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Academics User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "grading_system_name", - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.py b/erpnext/schools/doctype/grading_structure/grading_structure.py deleted file mode 100644 index 1b5d6a8d2ed..00000000000 --- a/erpnext/schools/doctype/grading_structure/grading_structure.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.document import Document -from frappe import _ -from frappe.utils import cstr - -class GradingStructure(Document): - def validate(self): - grade_intervals = self.get("grade_intervals") - check_overlap(grade_intervals, self) - -#Check if any of the grade intervals for this grading structure overlap -def check_overlap(grade_intervals, parent_doc): - for interval1 in grade_intervals: - for interval2 in grade_intervals: - if interval1.name == interval2.name: - pass - else: - if (interval1.from_score <= interval2.from_score and interval1.to_score >= interval2.from_score) or (interval1.from_score <= interval2.to_score and interval1.to_score >= interval2.to_score): - frappe.throw(_("""The intervals for Grade Code {0} overlaps with the grade intervals for other grades. - Please check intervals {0} and {1} and try again""".format(interval1.grade_code, interval2.grade_code))) \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_structure/test_grading_structure.py b/erpnext/schools/doctype/grading_structure/test_grading_structure.py deleted file mode 100644 index 0e360806788..00000000000 --- a/erpnext/schools/doctype/grading_structure/test_grading_structure.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import frappe -import unittest - -# test_records = frappe.get_test_records('Grading Structure') - -class TestGradingStructure(unittest.TestCase): - pass diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index e4101af4bfc..c0b3b847750 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -10,8 +10,7 @@ from frappe.utils import flt, cint, cstr from frappe.desk.reportview import build_match_conditions from erpnext.utilities.transaction_base import TransactionBase from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address -from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this -from erpnext import get_default_currency +from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this class Customer(TransactionBase): def get_feed(self): @@ -23,25 +22,9 @@ class Customer(TransactionBase): self.load_dashboard_info() def load_dashboard_info(self): - billing_this_year = frappe.db.sql(""" - select sum(debit_in_account_currency) - sum(credit_in_account_currency), account_currency - from `tabGL Entry` - where voucher_type='Sales Invoice' and party_type = 'Customer' - and party=%s and fiscal_year = %s""", - (self.name, frappe.db.get_default("fiscal_year"))) - - total_unpaid = frappe.db.sql("""select sum(outstanding_amount) - from `tabSales Invoice` - where customer=%s and docstatus = 1""", self.name) - - info = {} - info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 - info["currency"] = billing_this_year[0][1] if billing_this_year else get_default_currency() - info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 - + info = get_dashboard_info(self.doctype, self.name) self.set_onload('dashboard_info', info) - def autoname(self): cust_master_name = frappe.defaults.get_global_default('cust_master_name') if cust_master_name == 'Customer Name': diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 55a0fd3c011..46e4d5c4f58 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -91,8 +91,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None): response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) - return flt(value) except: - frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}").format(from_currency, to_currency, transaction_date)) + frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date)) return 0.0 \ No newline at end of file diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 057c78a81f1..86c69594488 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -44,8 +44,6 @@ frappe.ui.form.on("Item", { }, __("View")); } - // make sensitive fields(has_serial_no, is_stock_item, valuation_method) - // read only if any stock ledger entry exists if(!frm.doc.is_fixed_asset) { erpnext.item.make_dashboard(frm); } @@ -77,6 +75,8 @@ frappe.ui.form.on("Item", { erpnext.item.edit_prices_button(frm); + // make sensitive fields(has_serial_no, is_stock_item, valuation_method, has_batch_no) + // read only if any stock ledger entry exists if (!frm.doc.__islocal && frm.doc.is_stock_item) { frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'], (frm.doc.__onload && frm.doc.__onload.sle_exists=="exists") ? false : true); diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 055b9c47f92..c11965e2560 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -74,7 +74,8 @@ class PurchaseReceipt(BuyingController): "Purchase Order Item": { "ref_dn_field": "purchase_order_item", "compare_fields": [["project", "="], ["uom", "="], ["item_code", "="]], - "is_child_table": True + "is_child_table": True, + "allow_duplicate_prev_row_id": True } }) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index 68d64a24740..d9d9568e40c 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -26,3 +26,19 @@ class StockSettings(Document): # show/hide barcode field frappe.make_property_setter({'fieldname': 'barcode', 'property': 'hidden', 'value': 0 if self.show_barcode_field else 1}) + + self.cant_change_valuation_method() + + def cant_change_valuation_method(self): + db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method") + + if db_valuation_method and db_valuation_method != self.valuation_method: + # check if there are any stock ledger entries against items + # which does not have it's own valuation method + sle = frappe.db.sql("""select name from `tabStock Ledger Entry` sle + where exists(select name from tabItem + where name=sle.item_code and (valuation_method is null or valuation_method='')) + """) + + if sle: + frappe.throw(_("Can't change valuation method, as there are transactions against some items which does not have it's own valuation method")) \ No newline at end of file