diff --git a/erpnext/__init__.py b/erpnext/__init__.py index ad827e5b275..235b1b0a01e 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '8.0.36' +__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 f32cfcd232f..6d88326f1ae 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -415,10 +415,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/docs/user/manual/en/stock/item/item-valuation-fifo-and-moving-average.md b/erpnext/docs/user/manual/en/stock/item/item-valuation-fifo-and-moving-average.md index 9344870081c..fc5ef001712 100644 --- a/erpnext/docs/user/manual/en/stock/item/item-valuation-fifo-and-moving-average.md +++ b/erpnext/docs/user/manual/en/stock/item/item-valuation-fifo-and-moving-average.md @@ -24,5 +24,3 @@ There are two major ways in which ERPNext values your items. * **Moving Average:** In this method, ERPNext assumes that the value of the item at any point is the average price of the units of that Item in stock. For example, if the value of an Item is X in a Warehouse with quantity Y and another quantity Y1 is added to the Warehouse at cost X1, the new value X2 would be: > New Value X2 = (X * Y + X1 * Y1) / (Y + Y1) - -{next} diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index c42403c010d..7dc6f2c3588 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -1586,32 +1586,12 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-04-10 12:13:59.630780", + "modified": "2017-05-20 13:10:59.630780", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", "owner": "Administrator", "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "All", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, { "amend": 0, "apply_user_permissions": 0, @@ -1662,4 +1642,4 @@ "sort_order": "DESC", "track_changes": 1, "track_seen": 0 -} \ No newline at end of file +} diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 5d2d2f05171..e42d2d18260 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -397,4 +397,5 @@ 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.set_sales_invoice_serial_number_from_delivery_note -erpnext.patches.v8_0.update_stock_qty_value_in_bom_item \ No newline at end of file +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/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 44bf21da3ec..2d0d83b125b 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -15,10 +15,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ // if rate is greater than price_list_rate, set margin // or set discount item.discount_percentage = 0; - item.margin_type = 'Percentage'; - item.margin_rate_or_amount = flt(Math.abs(1 - item.rate / item.price_list_rate) * 100.0, - precision("discount_percentage", item)); - item.rate_with_margin = item.rate; + item.margin_type = 'Amount'; + item.margin_rate_or_amount = flt(item.rate - item.price_list_rate, + precision("margin_rate_or_amount", item)); + item.rate_with_margin = item.rate; } else { item.discount_percentage = flt((1 - item.rate / item.price_list_rate) * 100.0, precision("discount_percentage", item)); 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/selling/sales_common.js b/erpnext/selling/sales_common.js index 715434384be..1fcf334717b 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -348,9 +348,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ margin_type: function(doc, cdt, cdn){ // calculate the revised total margin and rate on margin type changes item = locals[cdt][cdn]; - this.apply_pricing_rule_on_item(item, doc,cdt, cdn) - this.calculate_taxes_and_totals(); - cur_frm.refresh_fields(); + if(!item.margin_type) { + frappe.model.set_value(cdt, cdn, "margin_rate_or_amount", 0); + } else { + this.apply_pricing_rule_on_item(item, doc,cdt, cdn) + this.calculate_taxes_and_totals(); + cur_frm.refresh_fields(); + } } }); diff --git a/erpnext/setup/doctype/email_digest/templates/default.html b/erpnext/setup/doctype/email_digest/templates/default.html index 78acbd9251e..5a657d26a3a 100644 --- a/erpnext/setup/doctype/email_digest/templates/default.html +++ b/erpnext/setup/doctype/email_digest/templates/default.html @@ -1,6 +1,6 @@ {% macro show_card(card) %}
-
{{ card.label }} +
{{ _(card.label) }} {% if card.count %} ({{ card.count }}) {% endif %}
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/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 58c16e1964c..b386a478dca 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -33,7 +33,7 @@ frappe.ui.form.on("Material Request Item", { "qty": function(frm, doctype, name) { var d = locals[doctype][name]; if (flt(d.qty) < flt(d.min_order_qty)) { - alert(__("Warning: Material Requested Qty is less than Minimum Order Qty")); + frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty")); } } } 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