diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index dde12d79c7a..b4d584fbdef 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -402,9 +402,9 @@ class TestPurchaseInvoice(unittest.TestCase): pi.save() pi.submit() - self.assertEqual(pi.payment_schedule[0].payment_amount, 756.15) + self.assertEqual(pi.payment_schedule[0].payment_amount, 606.15) self.assertEqual(pi.payment_schedule[0].due_date, pi.posting_date) - self.assertEqual(pi.payment_schedule[1].payment_amount, 756.15) + self.assertEqual(pi.payment_schedule[1].payment_amount, 606.15) self.assertEqual(pi.payment_schedule[1].due_date, add_days(pi.posting_date, 30)) pi.load_from_db() diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js index 29db2276129..7908c07a0ad 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js @@ -8,7 +8,8 @@ frappe.query_reports["Inactive Sales Items"] = { fieldname: "territory", label: __("Territory"), fieldtype: "Link", - options: "Territory" + options: "Territory", + reqd: 1, }, { fieldname: "item", diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index 42761a58b95..b670e6e91fa 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -96,6 +96,8 @@ def get_data(filters): "qty": item_obj.qty, "days_since_last_order": item_obj.days_since_last_order }) + else: + continue data.append(row) diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py index 400f6be826a..63e7ad965da 100644 --- a/erpnext/config/selling.py +++ b/erpnext/config/selling.py @@ -10,7 +10,7 @@ def get_data(): { "type": "doctype", "name": "Customer", - "description": _("Customer database."), + "description": _("Customer Database."), "onboard": 1, }, { @@ -34,6 +34,13 @@ def get_data(): "onboard": 1, "dependencies": ["Item", "Customer"], }, + { + "type": "doctype", + "name": "Blanket Order", + "description": _("Blanket Orders from Costumers."), + "onboard": 1, + "dependencies": ["Item", "Customer"], + }, { "type": "doctype", "name": "Sales Partner", diff --git a/erpnext/config/settings.py b/erpnext/config/settings.py index a97e8ce5d7f..323683a3e6d 100644 --- a/erpnext/config/settings.py +++ b/erpnext/config/settings.py @@ -90,12 +90,6 @@ def get_data(): "label": _("Email"), "icon": "fa fa-envelope", "items": [ - { - "type": "doctype", - "name": "Feedback Trigger", - "label": _("Feedback Trigger"), - "description": _("Automatically triggers the feedback request based on conditions.") - }, { "type": "doctype", "name": "Email Digest", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 155a996a15a..0672b2d0ccc 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -787,6 +787,9 @@ class AccountsController(TransactionBase): if self.doctype in ("Sales Invoice", "Purchase Invoice"): grand_total = grand_total - flt(self.write_off_amount) + if self.get("total_advance"): + grand_total -= self.get("total_advance") + if not self.get("payment_schedule"): if self.get("payment_terms_template"): data = get_payment_terms(self.payment_terms_template, posting_date, grand_total) @@ -832,6 +835,9 @@ class AccountsController(TransactionBase): total = flt(total, self.precision("grand_total")) grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total')) + if self.get("total_advance"): + grand_total -= self.get("total_advance") + if self.doctype in ("Sales Invoice", "Purchase Invoice"): grand_total = grand_total - flt(self.write_off_amount) if total != grand_total: diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py index 987823a01e9..0747a22f8da 100644 --- a/erpnext/education/doctype/course/course.py +++ b/erpnext/education/doctype/course/course.py @@ -20,9 +20,9 @@ class Course(Document): frappe.throw(_("Total Weightage of all Assessment Criteria must be 100%")) def get_topics(self): - try: - topic_list = self.get_all_children() - topic_data = [frappe.get_doc("Topic", topic.topic) for topic in topic_list] - except frappe.DoesNotExistError: - return None + topic_data= [] + for topic in self.topics: + topic_doc = frappe.get_doc("Topic", topic.topic) + if topic_doc.topic_content: + topic_data.append(topic_doc) return topic_data \ No newline at end of file diff --git a/erpnext/education/doctype/course/test_course.py b/erpnext/education/doctype/course/test_course.py index a24ba8a5276..4667ac45a23 100644 --- a/erpnext/education/doctype/course/test_course.py +++ b/erpnext/education/doctype/course/test_course.py @@ -3,6 +3,7 @@ # See license.txt from __future__ import unicode_literals from erpnext.education.doctype.topic.test_topic import make_topic +from erpnext.education.doctype.topic.test_topic import make_topic_and_linked_content import frappe import unittest @@ -11,6 +12,8 @@ import unittest class TestCourse(unittest.TestCase): def setUp(self): + make_topic_and_linked_content("_Test Topic 1", [{"type":"Article", "name": "_Test Article 1"}]) + make_topic_and_linked_content("_Test Topic 2", [{"type":"Article", "name": "_Test Article 2"}]) make_course_and_linked_topic("_Test Course 1", ["_Test Topic 1", "_Test Topic 2"]) def test_get_topics(self): diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.py b/erpnext/education/doctype/course_enrollment/course_enrollment.py index 9508636d2ff..6f2bb0db1f1 100644 --- a/erpnext/education/doctype/course_enrollment/course_enrollment.py +++ b/erpnext/education/doctype/course_enrollment/course_enrollment.py @@ -21,7 +21,10 @@ class CourseEnrollment(Document): progress = [] for topic in topics: progress.append(student.get_topic_progress(self.name, topic)) - return reduce(lambda x,y: x+y, progress) # Flatten out the List + if progress: + return reduce(lambda x,y: x+y, progress) # Flatten out the List + else: + return [] def validate_duplication(self): enrollment = frappe.get_all("Course Enrollment", filters={ diff --git a/erpnext/education/doctype/education_settings/education_settings.json b/erpnext/education/doctype/education_settings/education_settings.json index 3be4988d217..32b5fb81986 100644 --- a/erpnext/education/doctype/education_settings/education_settings.json +++ b/erpnext/education/doctype/education_settings/education_settings.json @@ -1,492 +1,136 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, "creation": "2017-04-05 13:33:04.519313", - "custom": 0, - "docstatus": 0, "doctype": "DocType", - "document_type": "", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "current_academic_year", + "current_academic_term", + "attendance_freeze_date", + "column_break_4", + "validate_batch", + "validate_course", + "academic_term_reqd", + "section_break_7", + "instructor_created_by", + "web_academy_settings_section", + "enable_lms", + "portal_title", + "description" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "current_academic_year", "fieldtype": "Link", - "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": "Current Academic Year", - "length": 0, - "no_copy": 0, - "options": "Academic Year", - "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 + "options": "Academic Year" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "current_academic_term", "fieldtype": "Link", - "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": "Current Academic Term", - "length": 0, - "no_copy": 0, - "options": "Academic Term", - "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 + "options": "Academic Term" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "attendance_freeze_date", "fieldtype": "Date", - "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": "Attendance Freeze Date", - "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 + "label": "Attendance Freeze Date" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_4", - "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 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.", "fieldname": "validate_batch", "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": "Validate Batch for Students in Student Group", - "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 + "label": "Validate Batch for Students in Student Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.", "fieldname": "validate_course", "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": "Validate Enrolled Course for Students in Student Group", - "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 + "label": "Validate Enrolled Course for Students in Student Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "description": "If enabled, field Academic Term will be Mandatory in Program Enrollment Tool.", "fieldname": "academic_term_reqd", "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": "Make Academic Term Mandatory", - "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 + "label": "Make Academic Term Mandatory" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_7", - "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 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Full Name", "fieldname": "instructor_created_by", "fieldtype": "Select", - "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": "Instructor Records to be created by", - "length": 0, - "no_copy": 0, - "options": "Full Name\nNaming Series\nEmployee Number", - "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 + "options": "Full Name\nNaming Series\nEmployee Number" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "web_academy_settings_section", "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, - "label": "LMS Settings", - "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 + "label": "LMS Settings" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "eval: doc.enable_lms", "fieldname": "portal_title", "fieldtype": "Data", - "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": "Portal Title", - "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 + "label": "LMS Title" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "eval: doc.enable_lms", "fieldname": "description", "fieldtype": "Small Text", - "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": "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, - "translatable": 0, - "unique": 0 + "label": "Description" + }, + { + "fieldname": "enable_lms", + "fieldtype": "Check", + "label": "Enable LMS" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2018-12-11 15:49:15.045116", + "modified": "2019-05-13 18:36:13.127563", "modified_by": "Administrator", "module": "Education", "name": "Education Settings", - "name_case": "", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, - "report": 0, "role": "System Manager", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, - "report": 0, "role": "Education Manager", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, - "report": 0, "role": "Guest", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 + "share": 1 } ], "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Education", - "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/education/doctype/education_settings/education_settings.py b/erpnext/education/doctype/education_settings/education_settings.py index 9286efa7c49..a85d3e70f34 100644 --- a/erpnext/education/doctype/education_settings/education_settings.py +++ b/erpnext/education/doctype/education_settings/education_settings.py @@ -34,3 +34,6 @@ class EducationSettings(Document): make_property_setter('Instructor', "naming_series", "hidden", 0, "Check") else: make_property_setter('Instructor', "naming_series", "hidden", 1, "Check") + +def update_website_context(context): + context["lms_enabled"] = frappe.get_doc("Education Settings").enable_lms \ No newline at end of file diff --git a/erpnext/education/doctype/program/program.py b/erpnext/education/doctype/program/program.py index dbeda40775f..d24df5d6142 100644 --- a/erpnext/education/doctype/program/program.py +++ b/erpnext/education/doctype/program/program.py @@ -9,6 +9,6 @@ from frappe.model.document import Document class Program(Document): def get_course_list(self): - program_course_list = self.get_all_children() + program_course_list = self.courses course_list = [frappe.get_doc("Course", program_course.course) for program_course in program_course_list] return course_list \ No newline at end of file diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py index cf8407c4eac..529f78d4f53 100644 --- a/erpnext/education/doctype/student/student.py +++ b/erpnext/education/doctype/student/student.py @@ -90,13 +90,14 @@ class Student(Document): """ contents = topic.get_contents() progress = [] - for content in contents: - if content.doctype in ('Article', 'Video'): - status = check_content_completion(content.name, content.doctype, course_enrollment_name) - progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status}) - elif content.doctype == 'Quiz': - status, score, result = check_quiz_completion(content, course_enrollment_name) - progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status, 'score': score, 'result': result}) + if contents: + for content in contents: + if content.doctype in ('Article', 'Video'): + status = check_content_completion(content.name, content.doctype, course_enrollment_name) + progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status}) + elif content.doctype == 'Quiz': + status, score, result = check_quiz_completion(content, course_enrollment_name) + progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status, 'score': score, 'result': result}) return progress def enroll_in_program(self, program_name): diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py index 339fc7d8871..7e5da329ebe 100644 --- a/erpnext/education/doctype/topic/topic.py +++ b/erpnext/education/doctype/topic/topic.py @@ -9,7 +9,7 @@ from frappe.model.document import Document class Topic(Document): def get_contents(self): try: - topic_content_list = self.get_all_children() + topic_content_list = self.topic_content content_data = [frappe.get_doc(topic_content.content_type, topic_content.content) for topic_content in topic_content_list] except Exception as e: frappe.log_error(frappe.get_traceback()) diff --git a/erpnext/education/doctype/topic_content/topic_content.json b/erpnext/education/doctype/topic_content/topic_content.json index 52207882e0c..444fd1d07c0 100644 --- a/erpnext/education/doctype/topic_content/topic_content.json +++ b/erpnext/education/doctype/topic_content/topic_content.json @@ -1,140 +1,44 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, "creation": "2018-12-12 11:42:57.987434", - "custom": 0, - "docstatus": 0, "doctype": "DocType", - "document_type": "", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "content_type", + "column_break_2", + "content" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "content_type", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Content Type", - "length": 0, - "no_copy": 0, "options": "\nArticle\nVideo\nQuiz", - "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 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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_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 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "content", "fieldtype": "Dynamic Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Content", - "length": 0, - "no_copy": 0, "options": "content_type", - "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 + "reqd": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2018-12-12 11:46:46.112018", + "modified": "2019-05-14 11:12:49.153771", "modified_by": "Administrator", "module": "Education", "name": "Topic Content", - "name_case": "", "owner": "Administrator", "permissions": [], "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 8ae9267b642..53da013f8d6 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -50,7 +50,7 @@ on_logout = "erpnext.shopping_cart.utils.clear_cart_count" treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group'] # website -update_website_context = "erpnext.shopping_cart.utils.update_website_context" +update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"] my_account_context = "erpnext.shopping_cart.utils.update_my_account_context" email_append_to = ["Job Applicant", "Lead", "Opportunity", "Issue"] diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.json b/erpnext/hr/doctype/payroll_entry/payroll_entry.json index 562b999b827..d51684f651a 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.json +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.json @@ -21,6 +21,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break0", "fieldtype": "Section Break", "hidden": 0, @@ -53,6 +54,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break0", "fieldtype": "Column Break", "hidden": 0, @@ -86,6 +88,7 @@ "collapsible": 0, "columns": 0, "default": "Today", + "fetch_if_empty": 0, "fieldname": "posting_date", "fieldtype": "Date", "hidden": 0, @@ -120,6 +123,7 @@ "columns": 0, "default": "", "depends_on": "eval:doc.salary_slip_based_on_timesheet == 0", + "fetch_if_empty": 0, "fieldname": "payroll_frequency", "fieldtype": "Select", "hidden": 0, @@ -153,6 +157,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break1", "fieldtype": "Column Break", "hidden": 0, @@ -186,6 +191,7 @@ "collapsible": 0, "columns": 0, "default": "", + "fetch_if_empty": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 0, @@ -220,6 +226,7 @@ "collapsible": 0, "collapsible_depends_on": "", "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_8", "fieldtype": "Section Break", "hidden": 0, @@ -252,6 +259,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "branch", "fieldtype": "Link", "hidden": 0, @@ -285,6 +293,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "department", "fieldtype": "Link", "hidden": 0, @@ -318,6 +327,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_10", "fieldtype": "Column Break", "hidden": 0, @@ -349,6 +359,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "designation", "fieldtype": "Link", "hidden": 0, @@ -382,6 +393,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "number_of_employees", "fieldtype": "Int", "hidden": 0, @@ -414,6 +426,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "sec_break20", "fieldtype": "Section Break", "hidden": 0, @@ -445,6 +458,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "employees", "fieldtype": "Table", "hidden": 0, @@ -478,6 +492,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_13", "fieldtype": "Section Break", "hidden": 0, @@ -509,6 +524,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "validate_attendance", "fieldtype": "Check", "hidden": 0, @@ -541,6 +557,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "attendance_detail_html", "fieldtype": "HTML", "hidden": 0, @@ -572,6 +589,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_12", "fieldtype": "Section Break", "hidden": 0, @@ -604,6 +622,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "salary_slip_based_on_timesheet", "fieldtype": "Check", "hidden": 0, @@ -637,6 +656,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "select_payroll_period", "fieldtype": "Section Break", "hidden": 0, @@ -670,6 +690,7 @@ "collapsible": 0, "columns": 0, "default": "", + "fetch_if_empty": 0, "fieldname": "start_date", "fieldtype": "Date", "hidden": 0, @@ -703,6 +724,7 @@ "collapsible": 0, "columns": 0, "default": "", + "fetch_if_empty": 0, "fieldname": "end_date", "fieldtype": "Date", "hidden": 0, @@ -735,6 +757,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_11", "fieldtype": "Column Break", "hidden": 0, @@ -766,6 +789,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "deduct_tax_for_unclaimed_employee_benefits", "fieldtype": "Check", "hidden": 0, @@ -798,6 +822,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "deduct_tax_for_unsubmitted_tax_exemption_proof", "fieldtype": "Check", "hidden": 0, @@ -830,6 +855,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_16", "fieldtype": "Section Break", "hidden": 0, @@ -864,6 +890,7 @@ "columns": 0, "default": ":Company", "fetch_from": "", + "fetch_if_empty": 0, "fieldname": "cost_center", "fieldtype": "Link", "hidden": 0, @@ -897,6 +924,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_18", "fieldtype": "Column Break", "hidden": 0, @@ -928,6 +956,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "project", "fieldtype": "Link", "hidden": 0, @@ -961,6 +990,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break2", "fieldtype": "Column Break", "hidden": 0, @@ -993,6 +1023,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "account", "fieldtype": "Section Break", "hidden": 0, @@ -1026,6 +1057,7 @@ "collapsible": 0, "columns": 0, "description": "Select Payment Account to make Bank Entry", + "fetch_if_empty": 0, "fieldname": "payment_account", "fieldtype": "Link", "hidden": 0, @@ -1059,6 +1091,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break2", "fieldtype": "Section Break", "hidden": 0, @@ -1090,6 +1123,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "amended_from", "fieldtype": "Link", "hidden": 0, @@ -1122,6 +1156,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "salary_slips_created", "fieldtype": "Check", "hidden": 1, @@ -1154,6 +1189,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "salary_slips_submitted", "fieldtype": "Check", "hidden": 1, @@ -1181,17 +1217,16 @@ } ], "has_web_view": 0, - "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-cog", "idx": 0, - "image_view": 0, "in_create": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-02-05 10:41:08.865842", + "menu_index": 0, + "modified": "2019-03-26 16:55:04.158800", "modified_by": "Administrator", "module": "HR", "name": "Payroll Entry", @@ -1210,7 +1245,7 @@ "permlevel": 0, "print": 0, "read": 1, - "report": 0, + "report": 1, "role": "HR Manager", "set_user_permissions": 0, "share": 1, @@ -1220,7 +1255,6 @@ ], "quick_entry": 0, "read_only": 0, - "read_only_onload": 0, "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/hr/report/bank_remittance/__init__.py b/erpnext/hr/report/bank_remittance/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hr/report/bank_remittance/bank_remittance.js b/erpnext/hr/report/bank_remittance/bank_remittance.js new file mode 100644 index 00000000000..1e10f24301e --- /dev/null +++ b/erpnext/hr/report/bank_remittance/bank_remittance.js @@ -0,0 +1,28 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Bank Remittance"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + fieldname:"from_date", + label: __("From Date"), + fieldtype: "Date", + }, + { + fieldname:"to_date", + label: __("To Date"), + fieldtype: "Date", + }, + + ] +} + diff --git a/erpnext/hr/report/bank_remittance/bank_remittance.json b/erpnext/hr/report/bank_remittance/bank_remittance.json new file mode 100644 index 00000000000..5a6228e3985 --- /dev/null +++ b/erpnext/hr/report/bank_remittance/bank_remittance.json @@ -0,0 +1,25 @@ +{ + "add_total_row": 0, + "creation": "2019-03-26 16:57:52.558895", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "letter_head": "Gadgets International", + "modified": "2019-03-26 16:57:52.558895", + "modified_by": "Administrator", + "module": "HR", + "name": "Bank Remittance", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Payroll Entry", + "report_name": "Bank Remittance", + "report_type": "Script Report", + "roles": [ + { + "role": "HR Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/hr/report/bank_remittance/bank_remittance.py b/erpnext/hr/report/bank_remittance/bank_remittance.py new file mode 100644 index 00000000000..b2d2c530247 --- /dev/null +++ b/erpnext/hr/report/bank_remittance/bank_remittance.py @@ -0,0 +1,154 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import formatdate +import itertools +from frappe import _, get_all + +def execute(filters=None): + columns = [ + { + "label": _("Payroll Number"), + "fieldtype": "Link", + "fieldname": "payroll_no", + "options": "Payroll Entry", + "width": 150 + }, + { + "label": _("Debit A/C Number"), + "fieldtype": "Int", + "fieldname": "debit_account", + "hidden": 1, + "width": 200 + }, + { + "label": _("Payment Date"), + "fieldtype": "Data", + "fieldname": "payment_date", + "width": 100 + }, + { + "label": _("Employee Name"), + "fieldtype": "Link", + "fieldname": "employee_name", + "options": "Employee", + "width": 200 + }, + { + "label": _("Bank Name"), + "fieldtype": "Data", + "fieldname": "bank_name", + "width": 50 + }, + { + "label": _("Employee A/C Number"), + "fieldtype": "Int", + "fieldname": "employee_account_no", + "width": 50 + }, + { + "label": _("IFSC Code"), + "fieldtype": "Data", + "fieldname": "bank_code", + "width": 100 + }, + { + "label": _("Currency"), + "fieldtype": "Data", + "fieldname": "currency", + "width": 50 + }, + { + "label": _("Net Salary Amount"), + "fieldtype": "Currency", + "options": "currency", + "fieldname": "amount", + "width": 100 + } + ] + data = [] + + accounts = get_bank_accounts() + payroll_entries = get_payroll_entries(accounts, filters) + salary_slips = get_salary_slips(payroll_entries) + get_emp_bank_ifsc_code(salary_slips) + + for salary in salary_slips: + if salary.bank_name and salary.bank_account_no and salary.debit_acc_no and salary.status in ["Submitted", "Paid"]: + row = { + "payroll_no": salary.payroll_entry, + "debit_account": salary.debit_acc_no, + "payment_date": frappe.utils.formatdate(salary.modified.strftime('%Y-%m-%d')), + "bank_name": salary.bank_name, + "employee_account_no": salary.bank_account_no, + "bank_code": salary.ifsc_code, + "employee_name": salary.employee+": " + salary.employee_name, + "currency": frappe.get_cached_value('Company', filters.company, 'default_currency'), + "amount": salary.net_pay, + } + data.append(row) + return columns, data + +def get_bank_accounts(): + accounts = [d.name for d in get_all("Account", filters={"account_type": "Bank"})] + return accounts + +def get_payroll_entries(accounts, filters): + payroll_filter = [ + ('payment_account', 'IN', accounts), + ('number_of_employees', '>', 0), + ('Company', '=', filters.company) + ] + if filters.to_date: + payroll_filter.append(('posting_date', '<', filters.to_date)) + + if filters.from_date: + payroll_filter.append(('posting_date', '>', filters.from_date)) + + entries = get_all("Payroll Entry", payroll_filter, ["name", "payment_account"]) + + payment_accounts = [d.payment_account for d in entries] + set_company_account(payment_accounts, entries) + return entries + +def get_salary_slips(payroll_entries): + payroll = [d.name for d in payroll_entries] + salary_slips = get_all("Salary Slip", filters = [("payroll_entry", "IN", payroll)], + fields = ["modified", "net_pay", "bank_name", "bank_account_no", "payroll_entry", "employee", "employee_name", "status"] + ) + + payroll_entry_map = {} + for entry in payroll_entries: + payroll_entry_map[entry.name] = entry + + # appending company debit accounts + for slip in salary_slips: + slip["debit_acc_no"] = payroll_entry_map[slip.payroll_entry]['company_account'] + + return salary_slips + +def get_emp_bank_ifsc_code(salary_slips): + emp_names = [d.employee for d in salary_slips] + ifsc_codes = get_all("Employee", [("name", "IN", emp_names)], ["ifsc_code", "name"]) + + ifsc_codes_map = {} + for code in ifsc_codes: + ifsc_codes_map[code.name] = code + + for slip in salary_slips: + slip["ifsc_code"] = ifsc_codes_map[code.name]['ifsc_code'] + + return salary_slips + +def set_company_account(payment_accounts, payroll_entries): + company_accounts = get_all("Bank Account", [("account", "in", payment_accounts)], ["account", "bank_account_no"]) + company_accounts_map = {} + for acc in company_accounts: + company_accounts_map[acc.account] = acc + + for entry in payroll_entries: + entry["company_account"] = company_accounts_map[entry.payment_account]['bank_account_no'] + + return payroll_entries diff --git a/erpnext/public/js/education/lms/components/CourseCard.vue b/erpnext/public/js/education/lms/components/CourseCard.vue index 16f8873bd1b..dff896f6f9e 100644 --- a/erpnext/public/js/education/lms/components/CourseCard.vue +++ b/erpnext/public/js/education/lms/components/CourseCard.vue @@ -8,12 +8,7 @@
{{ course.course_name }}
- Topics - + {{ course.course_intro }}
diff --git a/erpnext/public/js/education/lms/components/Video.vue b/erpnext/public/js/education/lms/components/Video.vue index 27f922f4874..ec7b0c08b02 100644 --- a/erpnext/public/js/education/lms/components/Video.vue +++ b/erpnext/public/js/education/lms/components/Video.vue @@ -6,8 +6,7 @@

{{ contentData.name }}

- {{ contentData.duration }} Mins - — Published on {{ contentData.publish_date }}. + {{ contentData.duration }} Mins — Published on {{ contentData.publish_date }}.
diff --git a/erpnext/www/lms.html b/erpnext/www/lms.html index 17961945854..aa76ca06e72 100644 --- a/erpnext/www/lms.html +++ b/erpnext/www/lms.html @@ -5,6 +5,35 @@ {% block navbar %}{% endblock %} {% block content %} +{% if lms_enabled %}
+{% else %} + + +
+
+ {{_("Page Missing or Moved")}} +
+

{{_("The page you are looking for is missing. This could be because it is moved or there is a typo in the link.")}}

+
{{ _("Home") }}
+
+

{{ _("Error Code: {0}").format('404') }}

+ +{% endif %} {% endblock %} \ No newline at end of file