From 9b44c16a329cd3ad799420e265073ab6e9eb42e7 Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Fri, 1 Sep 2017 15:18:04 +0530 Subject: [PATCH] add the fee schedule in config --- .../doctype/payment_entry/payment_entry.py | 6 +- erpnext/config/schools.py | 4 ++ .../doctype/fee_schedule/fee_schedule.js | 41 ++++++----- .../doctype/fee_schedule/fee_schedule.json | 70 +++++++++++++++++-- .../doctype/fee_schedule/fee_schedule.py | 23 ++++-- .../doctype/fee_structure/fee_structure.js | 15 ++++ .../doctype/fee_structure/fee_structure.json | 42 +++++++++-- .../doctype/fee_structure/fee_structure.py | 16 +++++ .../fee_structure/test_fee_structure.js | 23 ++++++ erpnext/schools/doctype/fees/fees.py | 1 - 10 files changed, 203 insertions(+), 38 deletions(-) create mode 100644 erpnext/schools/doctype/fee_structure/test_fee_structure.js diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index d39fd208c7d..e6639833e9a 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -403,9 +403,9 @@ class PaymentEntry(AccountsController): "against": against_account, "account_currency": self.party_account_currency }) - + dr_or_cr = "credit" if self.party_type in ["Customer", "Student"] else "debit" - + for d in self.get("references"): gle = party_gl_dict.copy() gle.update({ @@ -530,7 +530,7 @@ def get_outstanding_reference_documents(args): if (args.get("party_type") != "Student"): orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"), party_account_currency, company_currency) - + return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency): diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py index b984578ca1e..dbdcd3561d4 100644 --- a/erpnext/config/schools.py +++ b/erpnext/config/schools.py @@ -154,6 +154,10 @@ def get_data(): "type": "doctype", "name": "Fees" }, + { + "type": "doctype", + "name": "Fee Schedule" + }, { "type": "doctype", "name": "Fee Structure" diff --git a/erpnext/schools/doctype/fee_schedule/fee_schedule.js b/erpnext/schools/doctype/fee_schedule/fee_schedule.js index 9e5a156284a..757355da449 100644 --- a/erpnext/schools/doctype/fee_schedule/fee_schedule.js +++ b/erpnext/schools/doctype/fee_schedule/fee_schedule.js @@ -3,9 +3,16 @@ frappe.ui.form.on('Fee Schedule', { setup: function(frm) { - frm.add_fetch("company", "default_receivable_account", "debit_to"); - frm.add_fetch("company", "default_income_account", "against_income_account"); - frm.add_fetch("company", "cost_center", "cost_center"); + frm.add_fetch("fee_structure", "default_receivable_account", "debit_to"); + frm.add_fetch("fee_structure", "default_income_account", "against_income_account"); + frm.add_fetch("fee_structure", "cost_center", "cost_center"); + + frm.set_query("student_group", "student_groups", function() { + return { + "program": frm.doc.program, + "academic_year": frm.doc.academic_year + }; + }); }, refresh: function(frm) { @@ -47,20 +54,20 @@ frappe.ui.form.on('Fee Schedule', { } }); -frappe.ui.form.on("Fee Component", { - refresh: function(frm) { - frm.set_read_only(); - } -}); - frappe.ui.form.on("Fee Schedule Student Group", { - onload: function(frm) { - frm.set_query("student_group",function(){ - return{ - "filters":{ - "group_based_on": "Batch" + student_group: function(frm, cdt, cdn) { + var row = locals[cdt][cdn]; + frappe.call({ + method: "erpnext.schools.doctype.fee_schedule.fee_schedule.get_total_students", + args: { + "student_group": row.student_group, + "student_category": frm.doc.student_category + }, + callback: function(r) { + if(!r.exc) { + frappe.model.set_value(cdt, cdn, "total_students", r.message); } - }; - }); + } + }) } -}); +}) \ No newline at end of file diff --git a/erpnext/schools/doctype/fee_schedule/fee_schedule.json b/erpnext/schools/doctype/fee_schedule/fee_schedule.json index c1fb2ec158f..7215603adc1 100644 --- a/erpnext/schools/doctype/fee_schedule/fee_schedule.json +++ b/erpnext/schools/doctype/fee_schedule/fee_schedule.json @@ -165,6 +165,68 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "student_category", + "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": "Student Category", + "length": 0, + "no_copy": 0, + "options": "Student Category", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "program", + "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": "Program", + "length": 0, + "no_copy": 0, + "options": "Program", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -188,7 +250,7 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -219,7 +281,7 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -315,7 +377,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -937,7 +999,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-23 15:58:34.051237", + "modified": "2017-09-07 12:36:02.678355", "modified_by": "Administrator", "module": "Schools", "name": "Fee Schedule", diff --git a/erpnext/schools/doctype/fee_schedule/fee_schedule.py b/erpnext/schools/doctype/fee_schedule/fee_schedule.py index 80165f4d05c..822a62dc8e8 100644 --- a/erpnext/schools/doctype/fee_schedule/fee_schedule.py +++ b/erpnext/schools/doctype/fee_schedule/fee_schedule.py @@ -34,7 +34,7 @@ class FeeSchedule(Document): no_of_students = 0 for d in self.student_groups: # if not d.total_students: - d.total_students = get_total_students(d.student_group) + d.total_students = get_total_students(d.student_group, self.student_category) no_of_students += cint(d.total_students) self.grand_total = no_of_students*self.total_amount self.grand_total_in_words = money_in_words(self.grand_total) @@ -44,7 +44,7 @@ class FeeSchedule(Document): self.fee_creation_status = "In Process" enqueue(generate_fee, queue='default', timeout=6000, event='generate_fee', fee_schedule=self.name) - frappe.msgprint(_("Fee generation started")) + frappe.msgprint(_("Fee records will be created in the background. In case of any error, the error message will be updated in the Schedule, check after refresh in 5 minutes.")) def generate_fee(fee_schedule): @@ -84,7 +84,6 @@ def generate_fee(fee_schedule): frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", err_msg) else: - frappe.db.commit() frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Successful") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", None) @@ -98,7 +97,17 @@ def get_fee_structure(source_name,target_doc=None): return fee_request @frappe.whitelist() -def get_total_students(student_group): - students = frappe.get_all("Student Group Student", - filters={"parent": student_group, "parenttype": "Student Group", "active": 1}) or [] - return len(students) \ No newline at end of file +def get_total_students(student_group, student_category=None): + conditions = "" + if student_category: + conditions = " and s.student_category='{}'".format(frappe.db.escape(student_category)) + + return frappe.db.sql(""" + select count(s.name) + from `tabStudent` s, `tabStudent Group Student` sgs + where + s.name = sgs.student + and sgs.parent = %s + and sgs.active = 1 + {conditions} + """.format(conditions=conditions), student_group)[0][0] diff --git a/erpnext/schools/doctype/fee_structure/fee_structure.js b/erpnext/schools/doctype/fee_structure/fee_structure.js index 7619cf5fbcd..78b85887a87 100644 --- a/erpnext/schools/doctype/fee_structure/fee_structure.js +++ b/erpnext/schools/doctype/fee_structure/fee_structure.js @@ -16,6 +16,21 @@ frappe.ui.form.on('Fee Structure', { } }; }); + }, + + refresh: function(frm) { + if(frm.doc.docstatus === 1) { + frm.add_custom_button(__("Make Fee Schedule"), function() { + frm.events.make_fee_schedule(frm); + }); + } + }, + + make_fee_schedule: function(frm) { + frappe.model.open_mapped_doc({ + method: "erpnext.schools.doctype.fee_structure.fee_structure.make_fee_schedule", + frm: frm + }); } }); diff --git a/erpnext/schools/doctype/fee_structure/fee_structure.json b/erpnext/schools/doctype/fee_structure/fee_structure.json index da8d7c94d23..c3df7bb67a7 100644 --- a/erpnext/schools/doctype/fee_structure/fee_structure.json +++ b/erpnext/schools/doctype/fee_structure/fee_structure.json @@ -564,6 +564,36 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "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": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Fee Structure", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "has_web_view": 0, @@ -573,12 +603,12 @@ "idx": 0, "image_view": 0, "in_create": 0, - "is_submittable": 0, + "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-08-02 16:31:35.861158", + "modified": "2017-09-07 12:04:14.807690", "modified_by": "Administrator", "module": "Schools", "name": "Fee Structure", @@ -586,15 +616,15 @@ "owner": "Administrator", "permissions": [ { - "amend": 0, + "amend": 1, "apply_user_permissions": 0, - "cancel": 0, + "cancel": 1, "create": 1, "delete": 1, "email": 1, "export": 1, "if_owner": 0, - "import": 0, + "import": 1, "permlevel": 0, "print": 1, "read": 1, @@ -602,7 +632,7 @@ "role": "Academics User", "set_user_permissions": 0, "share": 1, - "submit": 0, + "submit": 1, "write": 1 } ], diff --git a/erpnext/schools/doctype/fee_structure/fee_structure.py b/erpnext/schools/doctype/fee_structure/fee_structure.py index b71c507dd48..781382b51be 100644 --- a/erpnext/schools/doctype/fee_structure/fee_structure.py +++ b/erpnext/schools/doctype/fee_structure/fee_structure.py @@ -5,6 +5,8 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe.model.mapper import get_mapped_doc + class FeeStructure(Document): def validate(self): @@ -16,3 +18,17 @@ class FeeStructure(Document): for d in self.components: self.total_amount += d.amount + +@frappe.whitelist() +def make_fee_schedule(source_name, target_doc=None): + return get_mapped_doc("Fee Structure", source_name, { + "Fee Structure": { + "doctype": "Fee Schedule", + "validation": { + "docstatus": ["=", 1], + } + }, + "Fee Component": { + "doctype": "Fee Component" + } + }, target_doc) \ No newline at end of file diff --git a/erpnext/schools/doctype/fee_structure/test_fee_structure.js b/erpnext/schools/doctype/fee_structure/test_fee_structure.js new file mode 100644 index 00000000000..61f41354c34 --- /dev/null +++ b/erpnext/schools/doctype/fee_structure/test_fee_structure.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Fee Structure", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Fee Structure + () => frappe.tests.make('Fee Structure', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/schools/doctype/fees/fees.py b/erpnext/schools/doctype/fees/fees.py index 2e1a49bf611..ac5564e300b 100644 --- a/erpnext/schools/doctype/fees/fees.py +++ b/erpnext/schools/doctype/fees/fees.py @@ -10,7 +10,6 @@ from frappe.utils import money_in_words from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from frappe.utils.csvutils import getlink from erpnext.controllers.accounts_controller import AccountsController -from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.accounts.general_ledger import delete_gl_entries