diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 86d30e0aff9..45602f1ea90 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -24,3 +24,18 @@ def get_default_currency(): company = get_default_company() if company: return frappe.db.get_value('Company', company, 'default_currency') + +def set_perpetual_inventory(enable=1): + accounts_settings = frappe.get_doc("Accounts Settings") + accounts_settings.auto_accounting_for_stock = enable + accounts_settings.save() + +def encode_company_abbr(name, company): + '''Returns name encoded with company abbreviation''' + company_abbr = frappe.db.get_value("Company", company, "abbr") + parts = name.rsplit(" - ", 1) + + if parts[-1].lower() != company_abbr.lower(): + parts.append(company_abbr) + + return " - ".join([parts[0], company_abbr]) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index cedaf60f9f5..11f376d68cb 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -3,11 +3,12 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, cint +from frappe.utils import cint, fmt_money from frappe import throw, _ from frappe.model.document import Document class RootNotEditable(frappe.ValidationError): pass +class BalanceMismatchError(frappe.ValidationError): pass class Account(Document): nsm_parent_field = 'parent_account' @@ -162,23 +163,38 @@ class Account(Document): throw(_("Report Type is mandatory")) def validate_warehouse_account(self): + '''If perpetual inventory is set, and warehouse is linked, + the account balance and stock balance as of now must always match. + ''' + from erpnext.accounts.utils import get_balance_on + from erpnext.stock.utils import get_stock_value_on if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): return - - if self.account_type == "Stock" and not cint(self.is_group): - if not self.warehouse: - throw(_("Warehouse is mandatory")) - - old_warehouse = cstr(frappe.db.get_value("Account", self.name, "warehouse")) - if old_warehouse != cstr(self.warehouse): - if old_warehouse and frappe.db.exists("Warehouse", old_warehouse): - self.validate_warehouse(old_warehouse) - if self.warehouse: - self.validate_warehouse(self.warehouse) - + + if self.account_type == "Stock": + if self.is_group == 0 and not self.warehouse: + frappe.throw(_("Warehouse is mandatory for non group Accounts of type Stock")) + + if self.warehouse: + # company must be same + if frappe.get_value('Warehouse', self.warehouse, 'company') != self.company: + frappe.throw(_("Warehouse company must be same as Account company")) + + # balance must be same + stock_balance = get_stock_value_on(self.warehouse) + if self.is_new(): + account_balance = 0.0 + else: + account_balance = get_balance_on(self.name) + + if account_balance != stock_balance: + frappe.throw(_('Account balance ({0}) and stock value ({1}) must be same')\ + .format(fmt_money(account_balance, self.account_currency), + fmt_money(stock_balance, self.account_currency))) + elif self.warehouse: self.warehouse = None - + def validate_warehouse(self, warehouse): lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index b4bb542aa7a..8756ca44136 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -171,7 +171,7 @@ class TestJournalEntry(unittest.TestCase): }) jv.submit() - + def test_clear_blank_rows(self): je = make_journal_entry("_Test Bank - _TC", "_Test Account Stock Expenses - _TC", 100, save=False) je.append("accounts", { @@ -180,11 +180,11 @@ class TestJournalEntry(unittest.TestCase): "credit_in_account_currency": 0, "exchange_rate": 1 }) - + self.assertEqual(len(je.get("accounts")), 3) je.save() - self.assertEqual(len(je.get("accounts")), 2) - + self.assertEqual(len(je.get("accounts")), 2) + def make_journal_entry(account1, account2, amount, cost_center=None, posting_date=None, exchange_rate=1, save=True, submit=False, project=None): if not cost_center: diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py index 9397ffc726f..029ef747407 100644 --- a/erpnext/config/desktop.py +++ b/erpnext/config/desktop.py @@ -228,15 +228,6 @@ def get_data(): "_doctype": "Student Applicant", "type": "list" }, - { - "module_name": "Assessment", - "color": "#8a70be", - "icon": "fa fa-file-text-alt", - "label": _("Assessment"), - "link": "List/Assessment", - "_doctype": "Assessment", - "type": "list" - }, { "module_name": "Fees", "color": "#83C21E", diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py index 366810d9f59..903f54b4117 100644 --- a/erpnext/config/schools.py +++ b/erpnext/config/schools.py @@ -112,7 +112,7 @@ def get_data(): "items": [ { "type": "doctype", - "name": "Assessment" + "name": "Assessment Plan" }, { "type": "doctype", @@ -120,7 +120,19 @@ def get_data(): }, { "type": "doctype", - "name": "Grading Structure" + "name": "Assessment Result" + }, + { + "type": "doctype", + "name": "Grading Scale" + }, + { + "type": "doctype", + "name": "Evaluation Criteria" + }, + { + "type": "doctype", + "name": "Assessment Result Tool" } ] }, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index da0591134e0..67d48224498 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -113,7 +113,7 @@ class AccountsController(TransactionBase): date_field = "transaction_date" if date_field and self.get(date_field): - validate_fiscal_year(self.get(date_field), self.fiscal_year, self.company, + validate_fiscal_year(self.get(date_field), self.fiscal_year, self.company, self.meta.get_label(date_field), self) def validate_due_date(self): @@ -131,7 +131,7 @@ class AccountsController(TransactionBase): transaction_date = self.posting_date else: transaction_date = self.transaction_date - + if self.meta.get_field("currency"): # price list part fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \ @@ -144,7 +144,7 @@ class AccountsController(TransactionBase): self.plc_conversion_rate = 1.0 elif not self.plc_conversion_rate: - self.plc_conversion_rate = get_exchange_rate(self.price_list_currency, + self.plc_conversion_rate = get_exchange_rate(self.price_list_currency, self.company_currency, transaction_date) # currency @@ -570,7 +570,7 @@ class AccountsController(TransactionBase): elif asset.status in ("Scrapped", "Cancelled", "Sold"): frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}") .format(d.idx, d.asset, asset.status)) - + def delink_advance_entries(self, linked_doc_name): total_allocated_amount = 0 for adv in self.advances: @@ -583,7 +583,7 @@ class AccountsController(TransactionBase): if consider_for_total_advance: total_allocated_amount += flt(adv.allocated_amount, adv.precision("allocated_amount")) - frappe.db.set_value(self.doctype, self.name, "total_advance", + frappe.db.set_value(self.doctype, self.name, "total_advance", total_allocated_amount, update_modified=False) def group_similar_items(self): @@ -711,7 +711,7 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field, .format(order_doctype, order_condition)) reference_condition = " and (" + " or ".join(conditions) + ")" if conditions else "" - + journal_entries = frappe.db.sql(""" select "Journal Entry" as reference_type, t1.name as reference_name, @@ -771,8 +771,8 @@ def get_advance_payment_entries(party_type, party, party_account, def update_invoice_status(): # Daily update the status of the invoices - frappe.db.sql(""" update `tabSales Invoice` set status = 'Overdue' + frappe.db.sql(""" update `tabSales Invoice` set status = 'Overdue' where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""") - frappe.db.sql(""" update `tabPurchase Invoice` set status = 'Overdue' + frappe.db.sql(""" update `tabPurchase Invoice` set status = 'Overdue' where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""") \ No newline at end of file diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 3e900b28140..74ea774ee7d 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cint, flt, cstr, now +from frappe.utils import cint, flt, cstr from frappe import msgprint, _ import frappe.defaults from erpnext.accounts.utils import get_fiscal_year @@ -14,7 +14,7 @@ class StockController(AccountsController): def validate(self): super(StockController, self).validate() self.validate_inspection() - + def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): if self.docstatus == 2: delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name) @@ -43,16 +43,16 @@ class StockController(AccountsController): gl_list = [] warehouse_with_no_account = [] - + for item_row in voucher_details: sle_list = sle_map.get(item_row.name) if sle_list: for sle in sle_list: if warehouse_account.get(sle.warehouse): # from warehouse account - + self.check_expense_account(item_row) - + if not sle.stock_value_difference: self.validate_negative_stock(sle) @@ -80,16 +80,16 @@ class StockController(AccountsController): for wh in warehouse_with_no_account: if frappe.db.get_value("Warehouse", wh, "company"): frappe.throw(_("Warehouse {0} is not linked to any account, please create/link the corresponding (Asset) account for the warehouse.").format(wh)) - + msgprint(_("No accounting entries for the following warehouses") + ": \n" + "\n".join(warehouse_with_no_account)) return process_gl_map(gl_list) - + def validate_negative_stock(self, sle): if sle.qty_after_transaction < 0 and sle.actual_qty < 0: frappe.throw(_("For the Item {0}, valuation rate not found for warehouse {1}. To be able to do accounting entries (for booking expenses), we need valuation rate for item {2}. Please create an incoming stock transaction, on or before {3} {4}, and then try submiting {5}") - .format(sle.item_code, sle.warehouse, + .format(sle.item_code, sle.warehouse, sle.item_code, sle.posting_date, sle.posting_time, self.name)) def get_voucher_details(self, default_expense_account, default_cost_center, sle_map): @@ -248,7 +248,7 @@ class StockController(AccountsController): incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0 return incoming_rate - + def validate_warehouse(self): from erpnext.stock.utils import validate_warehouse_company @@ -257,7 +257,7 @@ class StockController(AccountsController): for w in warehouses: validate_warehouse_company(w, self.company) - + def update_billing_percentage(self, update_modified=True): self._update_percent_field({ "target_dt": self.doctype + " Item", @@ -271,21 +271,21 @@ class StockController(AccountsController): def validate_inspection(self): '''Checks if quality inspection is set for Items that require inspection. On submit, throw an exception''' - + inspection_required_fieldname = None if self.doctype in ["Purchase Receipt", "Purchase Invoice"]: inspection_required_fieldname = "inspection_required_before_purchase" elif self.doctype in ["Delivery Note", "Sales Invoice"]: inspection_required_fieldname = "inspection_required_before_delivery" - + if not inspection_required_fieldname or \ (self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.update_stock): return - + for d in self.get('items'): - if (frappe.db.get_value("Item", d.item_code, inspection_required_fieldname) + if (frappe.db.get_value("Item", d.item_code, inspection_required_fieldname) and not d.quality_inspection): - + frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code)) if self.docstatus==1: raise frappe.ValidationError @@ -301,7 +301,7 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items) gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date) - + for voucher_type, voucher_no in future_stock_vouchers: existing_gle = gle.get((voucher_type, voucher_no), []) voucher_obj = frappe.get_doc(voucher_type, voucher_no) @@ -364,14 +364,19 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date): return gl_entries def get_warehouse_account(): - if not frappe.flags.warehouse_account_map: + if not frappe.flags.warehouse_account_map or frappe.flags.in_test: warehouse_account = frappe._dict() - for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount - where account_type = 'Stock' and (warehouse is not null and warehouse != '' - and is_group != 1) and is_group=0 """, as_dict=1): - warehouse_account.setdefault(d.warehouse, d) - + for d in frappe.db.sql("""select + warehouse, name, account_currency + from + tabAccount + where + account_type = 'Stock' + and (warehouse is not null and warehouse != '') + and is_group=0 """, as_dict=1): + warehouse_account.setdefault(d.warehouse, d) + frappe.flags.warehouse_account_map = warehouse_account - + return frappe.flags.warehouse_account_map diff --git a/erpnext/hooks.py b/erpnext/hooks.py index acea675a777..8443cdf7e10 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -108,8 +108,6 @@ portal_menu_items = [ {"title": _("Issues"), "route": "/issues", "reference_doctype": "Issue", "role":"Customer"}, {"title": _("Addresses"), "route": "/addresses", "reference_doctype": "Address"}, {"title": _("Announcements"), "route": "/announcement", "reference_doctype": "Announcement"}, - {"title": _("Courses"), "route": "/course", "reference_doctype": "Course", "role":"Student"}, - {"title": _("Assessment Schedule"), "route": "/assessment", "reference_doctype": "Assessment", "role":"Student"}, {"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"} ] diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 16c9b53430d..3e3c9edbd1b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -360,6 +360,7 @@ erpnext.patches.v7_1.set_sales_person_status erpnext.patches.v7_1.repost_stock_for_deleted_bins_for_merging_items execute:frappe.delete_doc('Desktop Icon', {'module_name': 'Profit and Loss Statment'}) erpnext.patches.v7_2.update_website_for_variant +erpnext.patches.v7_2.update_assessment_modules erpnext.patches.v7_2.update_doctype_status erpnext.patches.v7_2.update_salary_slips -erpnext.patches.v7_2.delete_fleet_management_module_def +erpnext.patches.v7_2.delete_fleet_management_module_def \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_assessment_modules.py b/erpnext/patches/v7_2/update_assessment_modules.py new file mode 100644 index 00000000000..43c5764505a --- /dev/null +++ b/erpnext/patches/v7_2/update_assessment_modules.py @@ -0,0 +1,31 @@ +import frappe +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) + + frappe.reload_doc("schools", "doctype", "grading_scale_interval") + rename_field("Grading Scale Interval", "to_score", "threshold") + + 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") + + frappe.reload_doc("schools", "doctype", "assessment_result") + for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"]): + 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 + assessment_result.student_name = stud_result.student_name + assessment_result.assessment_plan = assessment.name + assessment_result.grading_scale = assessment.grading_scale + assessment_result.total_score = stud_result.result + assessment_result.flags.ignore_validate = True + assessment_result.save() + + frappe.db.sql("""delete from `tabAssessment Result` where parent != '' or parent is not null""") \ No newline at end of file diff --git a/erpnext/public/build.json b/erpnext/public/build.json index 30b09000fd3..c4056813b68 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -28,7 +28,8 @@ "public/js/templates/item_selector.html", "public/js/utils/item_selector.js", "public/js/help_links.js", - "public/js/schools/student_button.html" + "public/js/schools/student_button.html", + "public/js/schools/assessment_result_tool.html" ], "js/item-dashboard.min.js": [ "stock/dashboard/item_dashboard.html", diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css index ca3b4b5965b..7f85de9315b 100644 --- a/erpnext/public/css/erpnext.css +++ b/erpnext/public/css/erpnext.css @@ -212,3 +212,25 @@ body[data-route="pos"] .modal-dialog { margin: 15px; width: 130px; } +.frappe-control[data-fieldname='result_html'] { + overflow: scroll; +} +.assessment-result-tool { + table-layout: fixed; +} +.assessment-result-tool input { + width: 100%; + border: 0; + outline: none; + text-align: right; +} +.assessment-result-tool th { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.assessment-result-tool .total-score, +.assessment-result-tool .grade, +.assessment-result-tool .score { + text-align: right; +} diff --git a/erpnext/public/js/schools/assessment_result_tool.html b/erpnext/public/js/schools/assessment_result_tool.html new file mode 100644 index 00000000000..6f9e2566c25 --- /dev/null +++ b/erpnext/public/js/schools/assessment_result_tool.html @@ -0,0 +1,44 @@ + + + + + + {% for c in criterias %} + + {% endfor %} + + + + + {% for c in criterias %} + + {% endfor %} + + + + + {% for s in students %} + + + + {% for c in criterias %} + + {% endfor %} + + + {% endfor %} + +
StudentStudent Name{{ c.evaluation_criteria }}Total Marks
{{ c.maximum_score }}{{max_total_score}}
{{ s.student }}{{ s.student_name }} + + + {% if(s.assessment_details) { %} {{s.assessment_details.total_score}} {% } %} +
\ No newline at end of file diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less index e2ccdddf0e7..790a031736d 100644 --- a/erpnext/public/less/erpnext.less +++ b/erpnext/public/less/erpnext.less @@ -257,3 +257,28 @@ body[data-route="pos"] .modal-dialog { margin: 15px; width: 130px; } + +// assessment tool +.frappe-control[data-fieldname='result_html'] { + overflow: scroll; +} +.assessment-result-tool { + table-layout: fixed; + + input { + width: 100%; + border: 0; + outline: none; + text-align: right; + } + + th { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .total-score, .grade, .score { + text-align: right; + } +} \ No newline at end of file diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py index bf09351ff54..e31a9444ca2 100644 --- a/erpnext/schools/api.py +++ b/erpnext/schools/api.py @@ -7,7 +7,7 @@ import frappe import json from frappe import _ from frappe.model.mapper import get_mapped_doc -from frappe.utils import flt +from frappe.utils import flt, cstr @frappe.whitelist() def enroll_student(source_name): @@ -84,7 +84,7 @@ def make_attendance_records(student, student_name, status, course_schedule=None, @frappe.whitelist() def get_student_batch_students(student_batch): - """Returns List of student, student_name in Student Batch. + """Returns List of student, student_name, idx in Student Batch. :param student_batch: Student Batch. """ @@ -163,3 +163,92 @@ def get_course_schedule_events(start, end, filters=None): }, as_dict=True, update={"allDay": 0}) return data + +@frappe.whitelist() +def get_evaluation_criterias(course): + """Returns Evaluation Criterias and their Weightage from Course Master. + + :param Course: Course + """ + return frappe.get_list("Course Evaluation Criteria", \ + fields=["evaluation_criteria", "weightage"], filters={"parent": course}, order_by= "idx") + +@frappe.whitelist() +def get_assessment_students(assessment_plan, student_group=None, student_batch=None): + student_list = [] + if student_group: + student_list = get_student_group_students(student_group) + elif student_batch: + student_list = get_student_batch_students(student_batch) + for i, student in enumerate(student_list): + result = get_result(student.student, assessment_plan) + if result: + student_result = {} + for d in result.details: + student_result.update({d.evaluation_criteria: cstr(d.score) + " ("+ d.grade + ")"}) + student_result.update({"total_score": cstr(result.total_score) + " (" + result.grade + ")"}) + student.update({'assessment_details': student_result}) + else: + student.update({'assessment_details': None}) + return student_list + +@frappe.whitelist() +def get_assessment_details(assessment_plan): + """Returns Evaluation Criteria and Maximum Score from Assessment Plan Master. + + :param Assessment Plan: Assessment Plan + """ + return frappe.get_list("Assessment Evaluation Criteria", \ + fields=["evaluation_criteria", "maximum_score"], filters={"parent": assessment_plan}, order_by= "idx") + +@frappe.whitelist() +def get_result(student, assessment_plan): + """Returns Submitted Result of given student for specified Assessment Plan + + :param Student: Student + :param Assessment Plan: Assessment Plan + """ + results = frappe.get_all("Assessment Result", filters={"student": student, "assessment_plan": assessment_plan, "docstatus": 1}) + if results: + return frappe.get_doc("Assessment Result", results[0]) + else: + return None + +@frappe.whitelist() +def get_grade(grading_scale, percentage): + """Returns Grade based on the Grading Scale and Score. + + :param Grading Scale: Grading Scale + :param Percentage: Score Percentage Percentage + """ + grading_scale_intervals = {} + for d in frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale}): + grading_scale_intervals.update({d.threshold:d.grade_code}) + intervals = sorted(grading_scale_intervals.keys(), key=float, reverse=True) + for interval in intervals: + if flt(percentage) >= interval: + grade = grading_scale_intervals.get(interval) + break + else: + grade = "" + return grade + +@frappe.whitelist() +def mark_assessment_result(student, assessment_plan, scores): + student_score = json.loads(scores) + details = [] + for s in student_score.keys(): + details.append({ + "evaluation_criteria": s, + "score": flt(student_score[s]) + }) + assessment_result = frappe.new_doc("Assessment Result") + assessment_result.update({ + "student": student, + "student_name": frappe.db.get_value("Student", student, "title"), + "assessment_plan": assessment_plan, + "details": details + }) + assessment_result.save() + assessment_result.submit() + return assessment_result \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment/assessment.js b/erpnext/schools/doctype/assessment/assessment.js deleted file mode 100644 index e842f413374..00000000000 --- a/erpnext/schools/doctype/assessment/assessment.js +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -cur_frm.add_fetch("student_group", "course", "course"); -cur_frm.add_fetch("examiner", "instructor_name", "examiner_name"); -cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name"); -cur_frm.add_fetch("student", "title", "student_name"); - -frappe.ui.form.on("Assessment", { - student_group: function(frm) { - frm.set_value("results", ""); - if (frm.doc.student_group) { - frappe.call({ - method: "erpnext.schools.api.get_student_group_students", - args: { - "student_group": frm.doc.student_group - }, - callback: function(r) { - if (r.message) { - $.each(r.message, function(i, d) { - var row = frappe.model.add_child(cur_frm.doc, "Assessment Result", "results"); - row.student = d.student; - row.student_name = d.student_name; - }); - } - refresh_field("results"); - } - }); - } - } -}); - -frappe.ui.form.on("Assessment Result", { - result: function(frm, cdt, cdn) { - if (frm.doc.grading_structure) { - var assessment_result = locals[cdt][cdn]; - frappe.call({ - method: "erpnext.schools.doctype.assessment.assessment.get_grade", - args: { - grading_structure: frm.doc.grading_structure, - result: assessment_result.result - }, - callback: function(r) { - if (r.message) { - frappe.model.set_value(cdt, cdn, 'grade', r.message); - } - } - }); - } - } -}); \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment/assessment.py b/erpnext/schools/doctype/assessment/assessment.py deleted file mode 100644 index 003b4276e7d..00000000000 --- a/erpnext/schools/doctype/assessment/assessment.py +++ /dev/null @@ -1,73 +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 -from frappe.model.document import Document -import frappe -from frappe import _ - -class Assessment(Document): - def validate(self): - self.validate_overlap() - - def validate_overlap(self): - """Validates overlap for Student Group/Student Batch, Instructor, Room""" - - from erpnext.schools.utils import validate_overlap_for - - #Validate overlapping course schedules. - if self.student_batch: - validate_overlap_for(self, "Course Schedule", "student_batch") - - if self.student_group: - validate_overlap_for(self, "Course Schedule", "student_group") - - validate_overlap_for(self, "Course Schedule", "instructor") - validate_overlap_for(self, "Course Schedule", "room") - - #validate overlapping assessment schedules. - if self.student_batch: - validate_overlap_for(self, "Assessment", "student_batch") - - if self.student_group: - validate_overlap_for(self, "Assessment", "student_group") - - validate_overlap_for(self, "Assessment", "room") - validate_overlap_for(self, "Assessment", "supervisor", self.instructor) - - -def get_assessment_list(doctype, txt, filters, limit_start, limit_page_length=20): - user = frappe.session.user - student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) - if student: - return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, - `tabStudent Group Student` as sgs where assessment.student_group = sgs.parent and sgs.student = %s and assessment.docstatus=1 - order by assessment.name asc limit {0} , {1}''' - .format(limit_start, limit_page_length), student, as_dict = True) - -def get_list_context(context=None): - return { - "show_sidebar": True, - 'no_breadcrumbs': True, - "title": _("Assessment Schedule"), - "get_list": get_assessment_list, - "row_template": "templates/includes/assessment/assessment_row.html" - } - -@frappe.whitelist() -def get_grade(grading_structure, result): - grade = frappe.db.sql("""select gi.from_score, gi.to_score, gi.grade_code, gi.grade_description - from `tabGrading Structure` as gs, `tabGrade Interval` as gi - where gs.name = gi.parent and gs.name = %(grading_structure)s and gi.from_score <= %(result)s - and gi.to_score >= %(result)s""".format(), - { - "grading_structure":grading_structure, - "result": result - }, - as_dict=True) - - return grade[0].grade_code if grade else "" - -def validate_grade(score, grade): - pass \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment/__init__.py b/erpnext/schools/doctype/assessment_evaluation_criteria/__init__.py similarity index 100% rename from erpnext/schools/doctype/assessment/__init__.py rename to erpnext/schools/doctype/assessment_evaluation_criteria/__init__.py diff --git a/erpnext/schools/doctype/assessment_evaluation_criteria/assessment_evaluation_criteria.json b/erpnext/schools/doctype/assessment_evaluation_criteria/assessment_evaluation_criteria.json new file mode 100644 index 00000000000..870aaa03544 --- /dev/null +++ b/erpnext/schools/doctype/assessment_evaluation_criteria/assessment_evaluation_criteria.json @@ -0,0 +1,124 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2016-12-14 17:20:27.738226", + "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": "evaluation_criteria", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Evaluation Criteria", + "length": 0, + "no_copy": 0, + "options": "Evaluation Criteria", + "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, + "label": "", + "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": "maximum_score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Maximum Score", + "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 + } + ], + "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 17:31:11.950549", + "modified_by": "Administrator", + "module": "Schools", + "name": "Assessment Evaluation Criteria", + "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/assessment_evaluation_criteria/assessment_evaluation_criteria.py b/erpnext/schools/doctype/assessment_evaluation_criteria/assessment_evaluation_criteria.py new file mode 100644 index 00000000000..08f6fd4b9a0 --- /dev/null +++ b/erpnext/schools/doctype/assessment_evaluation_criteria/assessment_evaluation_criteria.py @@ -0,0 +1,10 @@ +# -*- 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 AssessmentEvaluationCriteria(Document): + pass diff --git a/erpnext/schools/doctype/assessment_plan/__init__.py b/erpnext/schools/doctype/assessment_plan/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.js b/erpnext/schools/doctype/assessment_plan/assessment_plan.js new file mode 100644 index 00000000000..374b444a969 --- /dev/null +++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.js @@ -0,0 +1,36 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +cur_frm.add_fetch("student_group", "course", "course"); +cur_frm.add_fetch("student_group", "student_batch", "student_batch"); +cur_frm.add_fetch("examiner", "instructor_name", "examiner_name"); +cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name"); + +frappe.ui.form.on("Assessment Plan", { + course: function(frm) { + if (frm.doc.course && frm.doc.maximum_assessment_score) { + frappe.call({ + method: "erpnext.schools.api.get_evaluation_criterias", + args: { + course: frm.doc.course + }, + callback: function(r) { + if (r.message) { + frm.doc.evaluation_criterias = []; + $.each(r.message, function(i, d) { + var row = frappe.model.add_child(frm.doc, "Assessment Evaluation Criteria", "evaluation_criterias"); + row.evaluation_criteria = d.evaluation_criteria; + row.maximum_score = d.weightage / 100 * frm.doc.maximum_assessment_score; + }); + } + refresh_field("evaluation_criterias"); + + } + }); + } + }, + + maximum_assessment_score: function(frm) { + frm.trigger("course"); + } +}); \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment/assessment.json b/erpnext/schools/doctype/assessment_plan/assessment_plan.json similarity index 85% rename from erpnext/schools/doctype/assessment/assessment.json rename to erpnext/schools/doctype/assessment_plan/assessment_plan.json index 845f2f65002..967c689f0de 100644 --- a/erpnext/schools/doctype/assessment/assessment.json +++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.json @@ -68,6 +68,175 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "assessment_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Assessment Group", + "length": 0, + "no_copy": 0, + "options": "Assessment Group", + "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": "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": "course", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Course", + "length": 0, + "no_copy": 0, + "options": "Course", + "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": "maximum_assessment_score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maximum Assessment Score", + "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": "grading_scale", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Grading Scale", + "length": 0, + "no_copy": 0, + "options": "Grading Scale", + "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": "section_break_10", + "fieldtype": "Section 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, @@ -97,6 +266,33 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_10", + "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, @@ -130,234 +326,6 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 0, - "fieldname": "grading_structure", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Grading Structure", - "length": 0, - "no_copy": 0, - "options": "Grading Structure", - "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": "course", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Course", - "length": 0, - "no_copy": 0, - "options": "Course", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "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": "assessment_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Assessment Group", - "length": 0, - "no_copy": 0, - "options": "Assessment Group", - "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": "supervisor", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supervisor", - "length": 0, - "no_copy": 0, - "options": "Instructor", - "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": "supervisor_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supervisor Name", - "length": 0, - "no_copy": 0, - "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_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "examiner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Examiner", - "length": 0, - "no_copy": 0, - "options": "Instructor", - "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": "examiner_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Examiner Name", - "length": 0, - "no_copy": 0, - "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_on_submit": 0, - "bold": 0, - "collapsible": 1, "collapsible_depends_on": "", "columns": 0, "depends_on": "", @@ -442,6 +410,63 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "examiner", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Examiner", + "length": 0, + "no_copy": 0, + "options": "Instructor", + "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": "examiner_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Examiner Name", + "length": 0, + "no_copy": 0, + "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_on_submit": 0, "bold": 0, @@ -528,9 +553,66 @@ { "allow_on_submit": 0, "bold": 0, - "collapsible": 1, + "collapsible": 0, "columns": 0, - "fieldname": "section_break_11", + "fieldname": "supervisor", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supervisor", + "length": 0, + "no_copy": 0, + "options": "Instructor", + "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": "supervisor_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supervisor Name", + "length": 0, + "no_copy": 0, + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_20", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, @@ -538,7 +620,6 @@ "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Results", "length": 0, "no_copy": 0, "permlevel": 0, @@ -558,7 +639,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "results", + "fieldname": "evaluation_criterias", "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, @@ -566,10 +647,10 @@ "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "results", + "label": "Evaluation Criterias", "length": 0, "no_copy": 0, - "options": "Assessment Result", + "options": "Assessment Evaluation Criteria", "permlevel": 0, "precision": "", "print_hide": 0, @@ -577,7 +658,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 @@ -598,7 +679,7 @@ "label": "Amended From", "length": 0, "no_copy": 1, - "options": "Assessment", + "options": "Assessment Plan", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -622,10 +703,10 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-11-16 13:05:54.953750", + "modified": "2017-01-05 12:15:33.183100", "modified_by": "Administrator", "module": "Schools", - "name": "Assessment", + "name": "Assessment Plan", "name_case": "", "owner": "Administrator", "permissions": [ @@ -656,5 +737,6 @@ "read_only_onload": 0, "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.py b/erpnext/schools/doctype/assessment_plan/assessment_plan.py new file mode 100644 index 00000000000..aa84ae342db --- /dev/null +++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document +import frappe +from frappe import _ + +class AssessmentPlan(Document): + def validate(self): + if not (self.student_batch or self.student_group): + frappe.throw(_("Please select Student Group or Student Batch")) + self.validate_student_batch() + self.validate_overlap() + + + def validate_overlap(self): + """Validates overlap for Student Group/Student Batch, Instructor, Room""" + + from erpnext.schools.utils import validate_overlap_for + + #Validate overlapping course schedules. + if self.student_batch: + validate_overlap_for(self, "Course Schedule", "student_batch") + + if self.student_group: + validate_overlap_for(self, "Course Schedule", "student_group") + + validate_overlap_for(self, "Course Schedule", "instructor") + validate_overlap_for(self, "Course Schedule", "room") + + #validate overlapping assessment schedules. + if self.student_batch: + validate_overlap_for(self, "Assessment Plan", "student_batch") + + if self.student_group: + validate_overlap_for(self, "Assessment Plan", "student_group") + + validate_overlap_for(self, "Assessment Plan", "room") + validate_overlap_for(self, "Assessment Plan", "supervisor", self.supervisor) + + def validate_student_batch(self): + if self.student_group: + self.student_batch = frappe.db.get_value("Student Group", self.student_group, "student_batch") \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_plan/test_assessment_plan.py b/erpnext/schools/doctype/assessment_plan/test_assessment_plan.py new file mode 100644 index 00000000000..2de4f23f5b9 --- /dev/null +++ b/erpnext/schools/doctype/assessment_plan/test_assessment_plan.py @@ -0,0 +1,12 @@ +# -*- 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('Assessment Plan') + +class TestAssessmentPlan(unittest.TestCase): + pass diff --git a/erpnext/schools/doctype/assessment_result/assessment_result.js b/erpnext/schools/doctype/assessment_result/assessment_result.js new file mode 100644 index 00000000000..265a626a804 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result/assessment_result.js @@ -0,0 +1,51 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +cur_frm.add_fetch("student", "title", "student_name"); +cur_frm.add_fetch("assessment_plan", "grading_scale", "grading_scale"); +cur_frm.add_fetch("assessment_plan", "maximum_assessment_score", "maximum_score"); + +frappe.ui.form.on("Assessment Result", { + assessment_plan: function(frm) { + frappe.call({ + method: "erpnext.schools.api.get_assessment_details", + args: { + assessment_plan: frm.doc.assessment_plan + }, + callback: function(r) { + if (r.message) { + frm.doc.details = []; + $.each(r.message, function(i, d) { + var row = frappe.model.add_child(frm.doc, "Assessment Result Detail", "details"); + row.evaluation_criteria = d.evaluation_criteria; + row.maximum_score = d.maximum_score; + }); + } + refresh_field("details"); + } + }); + } +}); + +frappe.ui.form.on("Assessment Result Detail", { + score: function(frm, cdt, cdn) { + var d = locals[cdt][cdn]; + if (d.score >= d.maximum_score) { + frappe.throw(_("Score cannot be greater than Maximum Score")); + } + else { + frappe.call({ + method: "erpnext.schools.api.get_grade", + args: { + grading_scale: frm.doc.grading_scale, + percentage: ((d.score/d.maximum_score) * 100) + }, + callback: function(r) { + if (r.message) { + frappe.model.set_value(cdt, cdn, "grade", r.message); + } + } + }); + } + } +}); \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_result/assessment_result.json b/erpnext/schools/doctype/assessment_result/assessment_result.json index 91e580d40b6..3bf9758623b 100644 --- a/erpnext/schools/doctype/assessment_result/assessment_result.json +++ b/erpnext/schools/doctype/assessment_result/assessment_result.json @@ -2,6 +2,7 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "autoname": "RES.######", "beta": 0, "creation": "2015-11-13 17:18:06.468332", "custom": 0, @@ -9,18 +10,21 @@ "doctype": "DocType", "document_type": "", "editable_grid": 1, + "engine": "InnoDB", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "student", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 1, + "in_list_view": 0, + "in_standard_filter": 0, "label": "Student", "length": 0, "no_copy": 0, @@ -30,6 +34,7 @@ "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, @@ -40,6 +45,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "student_name", "fieldtype": "Data", "hidden": 0, @@ -47,6 +53,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Student Name", "length": 0, "no_copy": 0, @@ -55,6 +62,7 @@ "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, @@ -65,6 +73,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", "hidden": 0, @@ -72,6 +81,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -79,6 +89,7 @@ "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, @@ -89,21 +100,54 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "result", - "fieldtype": "Data", + "columns": 0, + "fieldname": "assessment_plan", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, - "label": "Result", + "in_standard_filter": 0, + "label": "Assessment Plan", "length": 0, "no_copy": 0, + "options": "Assessment Plan", "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": "grading_scale", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Grading Scale", + "length": 0, + "no_copy": 0, + "options": "Grading Scale", + "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, @@ -114,6 +158,174 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_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, + "depends_on": "", + "fieldname": "details", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Details", + "length": 0, + "no_copy": 0, + "options": "Assessment Result Detail", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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": "section_break_8", + "fieldtype": "Section 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": "maximum_score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maximum Score", + "length": 0, + "no_copy": 0, + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Total Score", + "length": 0, + "no_copy": 0, + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_11", + "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": "grade", "fieldtype": "Data", "hidden": 0, @@ -121,6 +333,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Grade", "length": 0, "no_copy": 0, @@ -129,6 +342,35 @@ "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_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_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Assessment Result", + "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, @@ -142,21 +384,45 @@ "image_view": 0, "in_create": 0, "in_dialog": 0, - "is_submittable": 0, + "is_submittable": 1, "issingle": 0, - "istable": 1, + "istable": 0, "max_attachments": 0, - "modified": "2016-08-27 12:15:01.923000", + "modified": "2017-01-04 16:56:33.868949", "modified_by": "Administrator", "module": "Schools", "name": "Assessment Result", "name_case": "", "owner": "Administrator", - "permissions": [], + "permissions": [ + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "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": 1, + "write": 1 + } + ], "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "sort_field": "modified", "sort_order": "DESC", + "title_field": "student_name", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_result/assessment_result.py b/erpnext/schools/doctype/assessment_result/assessment_result.py index 84cbcfa43b5..860dcbd8ae7 100644 --- a/erpnext/schools/doctype/assessment_result/assessment_result.py +++ b/erpnext/schools/doctype/assessment_result/assessment_result.py @@ -4,7 +4,33 @@ from __future__ import unicode_literals import frappe +from frappe import _ +from frappe.utils import flt from frappe.model.document import Document +from erpnext.schools.api import get_grade +from erpnext.schools.api import get_assessment_details class AssessmentResult(Document): - pass + def validate(self): + self.grading_scale = frappe.db.get_value("Assessment Plan", self.assessment_plan, "grading_scale") + self.validate_maximum_score() + self.validate_grade() + + def validate_maximum_score(self): + self.maximum_score = frappe.db.get_value("Assessment Plan", self.assessment_plan, "maximum_assessment_score") + assessment_details = get_assessment_details(self.assessment_plan) + max_scores = {} + for d in assessment_details: + max_scores.update({d.evaluation_criteria: d.maximum_score}) + + for d in self.details: + d.maximum_score = max_scores.get(d.evaluation_criteria) + if d.score > d.maximum_score: + frappe.throw(_("Score cannot be greater than Maximum Score")) + + def validate_grade(self): + self.total_score = 0.0 + for d in self.details: + d.grade = get_grade(self.grading_scale, (flt(d.score)/d.maximum_score)*100) + self.total_score += d.score + self.grade = get_grade(self.grading_scale, (self.total_score/self.maximum_score)*100) diff --git a/erpnext/schools/doctype/assessment_result/test_assessment_result.py b/erpnext/schools/doctype/assessment_result/test_assessment_result.py new file mode 100644 index 00000000000..66e611c866f --- /dev/null +++ b/erpnext/schools/doctype/assessment_result/test_assessment_result.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest +from erpnext.schools.api import get_grade + +# test_records = frappe.get_test_records('Assessment Result') + +class TestAssessmentResult(unittest.TestCase): + def test_grade(self): + grade = get_grade("_Test Grading Scale", 80) + self.assertEquals("A", grade) + + grade = get_grade("_Test Grading Scale", 70) + self.assertEquals("B", grade) + \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_result_detail/__init__.py b/erpnext/schools/doctype/assessment_result_detail/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/assessment_result_detail/assessment_result_detail.json b/erpnext/schools/doctype/assessment_result_detail/assessment_result_detail.json new file mode 100644 index 00000000000..87ce1207cf8 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result_detail/assessment_result_detail.json @@ -0,0 +1,180 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2016-12-14 17:44:35.583123", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 4, + "fieldname": "evaluation_criteria", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Evaluation Criteria", + "length": 0, + "no_copy": 0, + "options": "Evaluation Criteria", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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": 2, + "fieldname": "maximum_score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Maximum Score", + "length": 0, + "no_copy": 0, + "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_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, + "label": "", + "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": 2, + "fieldname": "score", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Score", + "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": 2, + "fieldname": "grade", + "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", + "length": 0, + "no_copy": 0, + "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 + } + ], + "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-27 16:18:12.022257", + "modified_by": "Administrator", + "module": "Schools", + "name": "Assessment Result Detail", + "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/assessment_result_detail/assessment_result_detail.py b/erpnext/schools/doctype/assessment_result_detail/assessment_result_detail.py new file mode 100644 index 00000000000..d0515931590 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result_detail/assessment_result_detail.py @@ -0,0 +1,10 @@ +# -*- 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 AssessmentResultDetail(Document): + pass diff --git a/erpnext/schools/doctype/assessment_result_tool/__init__.py b/erpnext/schools/doctype/assessment_result_tool/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.js b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.js new file mode 100644 index 00000000000..c58304beca4 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.js @@ -0,0 +1,105 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +cur_frm.add_fetch("assessment_plan", "student_group", "student_group"); +cur_frm.add_fetch("assessment_plan", "student_batch", "student_batch"); + +frappe.ui.form.on('Assessment Result Tool', { + refresh: function(frm) { + frm.disable_save(); + frm.page.clear_indicator(); + }, + + assessment_plan: function(frm) { + if(!(frm.doc.student_batch || frm.doc.student_group)) return; + frappe.call({ + method: "erpnext.schools.api.get_assessment_students", + args: { + "assessment_plan": frm.doc.assessment_plan, + "student_batch": frm.doc.student_batch, + "student_group": frm.doc.student_group + }, + callback: function(r) { + frm.events.render_table(frm, r.message); + } + }); + }, + + render_table: function(frm, students) { + $(frm.fields_dict.result_html.wrapper).empty(); + var assessment_plan = frm.doc.assessment_plan; + var student_scores = {}; + students.forEach(function(stu) { + student_scores[stu.student] = {} + }); + + frappe.call({ + method: "erpnext.schools.api.get_assessment_details", + args: { + assessment_plan: assessment_plan + }, + callback: function(r) { + var criterias = r.message; + var max_total_score = 0; + criterias.forEach(function(c) { + max_total_score += c.maximum_score + }); + var result_table = $(frappe.render_template('assessment_result_tool', { + frm: frm, + students: students, + criterias: criterias, + max_total_score: max_total_score + })); + result_table.appendTo(frm.fields_dict.result_html.wrapper) + + result_table.on('change', 'input', function(e) { + var $input = $(e.target); + var max_score = $input.data().maxScore; + var student = $input.data().student; + var criteria = $input.data().criteria; + var value = $input.val(); + if(value < 0) { + $input.val(0); + value = 0; + } + if(value > max_score) { + $input.val(max_score); + value = max_score; + } + student_scores[student][criteria] = value; + if(Object.keys(student_scores[student]).length == criterias.length) { + frappe.call(({ + method: "erpnext.schools.api.mark_assessment_result", + args: { + "student": student, + "assessment_plan": assessment_plan, + "scores": student_scores[student] + }, + callback: function(r) { + var doc = r.message; + var student = doc.student; + result_table.find(`[data-student=${student}].total-score`) + .html(doc.total_score + ' ('+ doc.grade + ')'); + var details = doc.details; + result_table.find(`tr[data-student=${student}]`).addClass('text-muted'); + result_table.find(`input[data-student=${student}]`).each(function(el, input) { + var $input = $(input); + var criteria = $input.data().criteria; + var value = $input.val(); + var grade = details.find(function(d) { + return d.evaluation_criteria === criteria; + }).grade; + $input.val(`${value} (${grade})`); + $input.attr('disabled', true); + }); + + } + })) + } + }); + + } + }); + }, + +}); diff --git a/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.json b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.json new file mode 100644 index 00000000000..87dff4d1545 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.json @@ -0,0 +1,232 @@ +{ + "allow_copy": 1, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-01-05 12:27:48.951036", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "assessment_plan", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Assessment Plan", + "length": 0, + "no_copy": 0, + "options": "Assessment Plan", + "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": "student_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Student Group", + "length": 0, + "no_copy": 0, + "options": "Student Group", + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "student_batch", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "assessment_plan", + "fieldname": "section_break_5", + "fieldtype": "Section 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": "result_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Result HTML", + "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": 1, + "hide_toolbar": 1, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 1, + "istable": 0, + "max_attachments": 0, + "modified": "2017-01-05 15:45:59.338722", + "modified_by": "Administrator", + "module": "Schools", + "name": "Assessment Result Tool", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "is_custom": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 0, + "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", + "track_changes": 0, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.py b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.py new file mode 100644 index 00000000000..a0d286ccbe9 --- /dev/null +++ b/erpnext/schools/doctype/assessment_result_tool/assessment_result_tool.py @@ -0,0 +1,10 @@ +# -*- 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 AssessmentResultTool(Document): + pass diff --git a/erpnext/schools/doctype/course/course.js b/erpnext/schools/doctype/course/course.js index fe38806ff77..c667eca2b7b 100644 --- a/erpnext/schools/doctype/course/course.js +++ b/erpnext/schools/doctype/course/course.js @@ -21,11 +21,11 @@ frappe.ui.form.on("Course", "refresh", function(frm) { frappe.set_route("List", "Course Schedule"); }); - frm.add_custom_button(__("Assessment"), function() { + frm.add_custom_button(__("Assessment Plan"), function() { frappe.route_options = { course: frm.doc.name } - frappe.set_route("List", "Assessment"); + frappe.set_route("List", "Assessment Plan"); }); } }); \ No newline at end of file diff --git a/erpnext/schools/doctype/course/course.json b/erpnext/schools/doctype/course/course.json index 6fada19b3c1..3f166195d56 100644 --- a/erpnext/schools/doctype/course/course.json +++ b/erpnext/schools/doctype/course/course.json @@ -1,278 +1,362 @@ { - "allow_copy": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:course_name", - "beta": 0, - "creation": "2015-09-07 12:39:55.181893", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 0, - "engine": "InnoDB", - "fields": [ - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "course_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Course 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": "course_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": "Course 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": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_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": "course_abbreviation", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Course Abbreviation", - "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": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Department", - "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": "section_break_6", - "fieldtype": "Section 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": "course_intro", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Course Intro", - "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": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2016-08-08 05:26:26.442635", - "modified_by": "Administrator", - "module": "Schools", - "name": "Course", - "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 - }, - { - "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": "HR Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "department", - "sort_field": "modified", - "sort_order": "DESC", - "track_seen": 0 + "allow_copy": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:course_name", + "beta": 0, + "creation": "2015-09-07 12:39:55.181893", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 0, + "engine": "InnoDB", + "fields": [{ + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "course_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Course 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": "course_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": "Course 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": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_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": "course_abbreviation", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Course Abbreviation", + "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": "department", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "Department", + "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": "section_break_6", + "fieldtype": "Section 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": "course_intro", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Course Intro", + "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": "assessment", + "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": "Assessment", + "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": "default_grading_scale", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Grading Scale", + "length": 0, + "no_copy": 0, + "options": "Grading Scale", + "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": "evaluation_criterias", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Evaluation Criterias", + "length": 0, + "no_copy": 0, + "options": "Course Evaluation Criteria", + "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": 0, + "max_attachments": 0, + "menu_index": 0, + "modified": "2016-12-14 16:48:16.642813", + "modified_by": "Administrator", + "module": "Schools", + "name": "Course", + "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 + }, + { + "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": "HR Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "search_fields": "department", + "sort_field": "modified", + "sort_order": "DESC", + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/schools/doctype/course/course.py b/erpnext/schools/doctype/course/course.py index b590acb52a0..3baccdfca07 100644 --- a/erpnext/schools/doctype/course/course.py +++ b/erpnext/schools/doctype/course/course.py @@ -8,21 +8,13 @@ from frappe.model.document import Document from frappe import _ class Course(Document): - pass - -def get_sg_list(doctype, txt, filters, limit_start, limit_page_length=20): - user = frappe.session.user - student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) - if student: - return frappe.db.sql('''select course, academic_term, academic_year, SG.name from `tabStudent Group` - as SG, `tabStudent Group Student` as SGS where SG.name = SGS.parent and SGS.student = %s - order by SG.name asc limit {0} , {1}'''.format(limit_start, limit_page_length), student, as_dict=True) - -def get_list_context(context=None): - return { - "show_sidebar": True, - 'no_breadcrumbs': True, - "title": _("Courses"), - "get_list": get_sg_list, - "row_template": "templates/includes/course/course_row.html" - } \ No newline at end of file + def validate(self): + self.validate_evaluation_criterias() + + def validate_evaluation_criterias(self): + if self.evaluation_criterias: + total_weightage = 0 + for criteria in self.evaluation_criterias: + total_weightage += criteria.weightage + if total_weightage != 100: + frappe.throw(_("Total Weightage of all Evaluation Criterias must be 100%")) diff --git a/erpnext/schools/doctype/course_evaluation_criteria/__init__.py b/erpnext/schools/doctype/course_evaluation_criteria/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/course_evaluation_criteria/course_evaluation_criteria.json b/erpnext/schools/doctype/course_evaluation_criteria/course_evaluation_criteria.json new file mode 100644 index 00000000000..a4d3ce404e5 --- /dev/null +++ b/erpnext/schools/doctype/course_evaluation_criteria/course_evaluation_criteria.json @@ -0,0 +1,124 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2016-12-14 16:46:46.786353", + "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": "evaluation_criteria", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Evaluation Criteria", + "length": 0, + "no_copy": 0, + "options": "Evaluation Criteria", + "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, + "label": "", + "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": "weightage", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Weightage", + "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 16:59:17.353023", + "modified_by": "Administrator", + "module": "Schools", + "name": "Course Evaluation Criteria", + "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/course_evaluation_criteria/course_evaluation_criteria.py b/erpnext/schools/doctype/course_evaluation_criteria/course_evaluation_criteria.py new file mode 100644 index 00000000000..b8398a30126 --- /dev/null +++ b/erpnext/schools/doctype/course_evaluation_criteria/course_evaluation_criteria.py @@ -0,0 +1,10 @@ +# -*- 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 CourseEvaluationCriteria(Document): + pass diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.py b/erpnext/schools/doctype/course_schedule/course_schedule.py index ec30c621409..7550ab1c47f 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.py +++ b/erpnext/schools/doctype/course_schedule/course_schedule.py @@ -55,11 +55,11 @@ class CourseSchedule(Document): #validate overlapping assessment schedules. if self.student_batch: - validate_overlap_for(self, "Assessment", "student_batch") + validate_overlap_for(self, "Assessment Plan", "student_batch") if self.student_group: - validate_overlap_for(self, "Assessment", "student_group") + validate_overlap_for(self, "Assessment Plan", "student_group") - validate_overlap_for(self, "Assessment", "room") - validate_overlap_for(self, "Assessment", "supervisor", self.instructor) + validate_overlap_for(self, "Assessment Plan", "room") + validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor) diff --git a/erpnext/schools/doctype/evaluation_criteria/__init__.py b/erpnext/schools/doctype/evaluation_criteria/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.js b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.js new file mode 100644 index 00000000000..5e0269b1fdb --- /dev/null +++ b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.js @@ -0,0 +1,8 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Evaluation Criteria', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.json b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.json new file mode 100644 index 00000000000..f830abe5b1b --- /dev/null +++ b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.json @@ -0,0 +1,89 @@ +{ + "allow_copy": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "field:evaluation_criteria", + "beta": 0, + "creation": "2016-12-14 16:40:15.144115", + "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": "evaluation_criteria", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Evaluation Criteria", + "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 + } + ], + "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 16:40:36.351183", + "modified_by": "Administrator", + "module": "Schools", + "name": "Evaluation Criteria", + "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", + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.py b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.py new file mode 100644 index 00000000000..85c1b32aaa5 --- /dev/null +++ b/erpnext/schools/doctype/evaluation_criteria/evaluation_criteria.py @@ -0,0 +1,10 @@ +# -*- 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 EvaluationCriteria(Document): + pass diff --git a/erpnext/schools/doctype/evaluation_criteria/test_evaluation_criteria.py b/erpnext/schools/doctype/evaluation_criteria/test_evaluation_criteria.py new file mode 100644 index 00000000000..0182db6b0ec --- /dev/null +++ b/erpnext/schools/doctype/evaluation_criteria/test_evaluation_criteria.py @@ -0,0 +1,12 @@ +# -*- 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('Evaluation Criteria') + +class TestEvaluationCriteria(unittest.TestCase): + pass diff --git a/erpnext/schools/doctype/evaluation_criteria/test_records.json b/erpnext/schools/doctype/evaluation_criteria/test_records.json new file mode 100644 index 00000000000..64ff701cf46 --- /dev/null +++ b/erpnext/schools/doctype/evaluation_criteria/test_records.json @@ -0,0 +1,8 @@ +[ + { + "evaluation_criteria": "_Test Evaluation Criteria" + }, + { + "evaluation_criteria": "_Test Evaluation Criteria 1" + } +] \ No newline at end of file diff --git a/erpnext/schools/doctype/grade_interval/grade_interval.json b/erpnext/schools/doctype/grade_interval/grade_interval.json index 79ef9f40a6a..c9c59495d9e 100644 --- a/erpnext/schools/doctype/grade_interval/grade_interval.json +++ b/erpnext/schools/doctype/grade_interval/grade_interval.json @@ -9,11 +9,13 @@ "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, @@ -21,6 +23,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Grade Code", "length": 0, "no_copy": 0, @@ -29,6 +32,7 @@ "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, @@ -39,39 +43,16 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "from_score", - "fieldtype": "Float", + "columns": 0, + "fieldname": "min_score", + "fieldtype": "Percent", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, - "label": "From Score", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "1", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "to_score", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "To Score", + "in_standard_filter": 0, + "label": "Min Score", "length": 0, "no_copy": 0, "permlevel": 0, @@ -79,6 +60,7 @@ "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, @@ -89,6 +71,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "grade_description", "fieldtype": "Small Text", "hidden": 0, @@ -96,6 +79,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Grade Description", "length": 0, "no_copy": 0, @@ -104,6 +88,7 @@ "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, @@ -121,7 +106,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-08-27 15:45:04.657328", + "modified": "2016-12-14 12:54:56.902465", "modified_by": "Administrator", "module": "Schools", "name": "Grade Interval", diff --git a/erpnext/schools/doctype/grading_scale/__init__.py b/erpnext/schools/doctype/grading_scale/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/grading_scale/grading_scale.js b/erpnext/schools/doctype/grading_scale/grading_scale.js new file mode 100644 index 00000000000..622388c0b16 --- /dev/null +++ b/erpnext/schools/doctype/grading_scale/grading_scale.js @@ -0,0 +1,8 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Grading Scale', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/schools/doctype/grading_scale/grading_scale.json b/erpnext/schools/doctype/grading_scale/grading_scale.json new file mode 100644 index 00000000000..99c69480618 --- /dev/null +++ b/erpnext/schools/doctype/grading_scale/grading_scale.json @@ -0,0 +1,203 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 1, + "autoname": "field:grading_scale_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_scale_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Grading Scale 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": "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": "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 Scale 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": "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": "Intervals", + "length": 0, + "no_copy": 0, + "options": "Grading Scale 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 + }, + { + "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_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Grading Scale", + "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 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2016-12-14 14:35:22.907023", + "modified_by": "Administrator", + "module": "Schools", + "name": "Grading Scale", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 1, + "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": 1, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "", + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_scale/grading_scale.py b/erpnext/schools/doctype/grading_scale/grading_scale.py new file mode 100644 index 00000000000..f7f6ba9d921 --- /dev/null +++ b/erpnext/schools/doctype/grading_scale/grading_scale.py @@ -0,0 +1,19 @@ +# -*- 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 import _ +from frappe.model.document import Document + +class GradingScale(Document): + def validate(self): + thresholds = [] + for d in self.intervals: + if d.threshold in thresholds: + frappe.throw(_("Treshold {0}% appears more than once.".format(d.threshold))) + else: + thresholds.append(d.threshold) + if 0 not in thresholds: + frappe.throw(_("Please define grade for treshold 0%")) \ No newline at end of file diff --git a/erpnext/schools/doctype/assessment/test_assessment.py b/erpnext/schools/doctype/grading_scale/test_grading_scale.py similarity index 65% rename from erpnext/schools/doctype/assessment/test_assessment.py rename to erpnext/schools/doctype/grading_scale/test_grading_scale.py index ce060074a90..5364d7c8879 100644 --- a/erpnext/schools/doctype/assessment/test_assessment.py +++ b/erpnext/schools/doctype/grading_scale/test_grading_scale.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe import unittest -# test_records = frappe.get_test_records('Assessment') +# test_records = frappe.get_test_records('Grading Scale') -class TestAssessment(unittest.TestCase): +class TestGradingScale(unittest.TestCase): pass diff --git a/erpnext/schools/doctype/grading_scale/test_records.json b/erpnext/schools/doctype/grading_scale/test_records.json new file mode 100644 index 00000000000..72b69547ac6 --- /dev/null +++ b/erpnext/schools/doctype/grading_scale/test_records.json @@ -0,0 +1,19 @@ +[ + { + "grading_scale_name": "_Test Grading Scale", + "intervals": [ + { + "grade_code": "A", + "threshold": 75 + }, + { + "grade_code": "B", + "threshold": 50 + }, + { + "grade_code": "C", + "threshold": 0 + } + ] + } +] \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_scale_interval/__init__.py b/erpnext/schools/doctype/grading_scale_interval/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.json b/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.json new file mode 100644 index 00000000000..10b229c8c0c --- /dev/null +++ b/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.json @@ -0,0 +1,124 @@ +{ + "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, + "default": "0", + "fieldname": "threshold", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Threshold", + "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": "2017-01-04 15:27:56.729286", + "modified_by": "Administrator", + "module": "Schools", + "name": "Grading Scale Interval", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.py b/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.py new file mode 100644 index 00000000000..41ac5ffd5c0 --- /dev/null +++ b/erpnext/schools/doctype/grading_scale_interval/grading_scale_interval.py @@ -0,0 +1,10 @@ +# -*- 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 GradingScaleInterval(Document): + pass diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.json b/erpnext/schools/doctype/grading_structure/grading_structure.json index cda6bd4e4f2..3c30f299d2f 100644 --- a/erpnext/schools/doctype/grading_structure/grading_structure.json +++ b/erpnext/schools/doctype/grading_structure/grading_structure.json @@ -10,11 +10,13 @@ "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, @@ -22,6 +24,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Grading System Name", "length": 0, "no_copy": 0, @@ -30,6 +33,7 @@ "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, @@ -40,6 +44,34 @@ "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, @@ -47,6 +79,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Description", "length": 0, "no_copy": 0, @@ -55,6 +88,7 @@ "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, @@ -65,30 +99,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 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, @@ -96,6 +107,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Grading Intervals", "length": 0, "no_copy": 0, @@ -104,6 +116,7 @@ "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, @@ -114,6 +127,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "grade_intervals", "fieldtype": "Table", "hidden": 0, @@ -121,6 +135,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Grade Intervals", "length": 0, "no_copy": 0, @@ -130,6 +145,7 @@ "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, @@ -147,7 +163,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-08-27 14:20:50.709823", + "modified": "2016-12-14 12:35:39.690256", "modified_by": "Administrator", "module": "Schools", "name": "Grading Structure", @@ -164,6 +180,7 @@ "export": 1, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, diff --git a/erpnext/schools/doctype/student/student_dashboard.py b/erpnext/schools/doctype/student/student_dashboard.py index 8b5fb41365f..ca2a660292a 100644 --- a/erpnext/schools/doctype/student/student_dashboard.py +++ b/erpnext/schools/doctype/student/student_dashboard.py @@ -10,7 +10,7 @@ def get_data(): 'items': ['Student Log', 'Student Batch', 'Student Group', 'Program Enrollment'] }, { - 'items': ['Fees', 'Assessment', 'Student Attendance', 'Student Leave Application'] + 'items': ['Fees', 'Assessment Result', 'Student Attendance', 'Student Leave Application'] } ] } \ No newline at end of file diff --git a/erpnext/schools/doctype/student_group/student_group.js b/erpnext/schools/doctype/student_group/student_group.js index 6f4084be251..392793a1f66 100644 --- a/erpnext/schools/doctype/student_group/student_group.js +++ b/erpnext/schools/doctype/student_group/student_group.js @@ -10,11 +10,11 @@ frappe.ui.form.on("Student Group", { frappe.set_route("List", "Course Schedule"); }); - frm.add_custom_button(__("Assessment"), function() { + frm.add_custom_button(__("Assessment Plan"), function() { frappe.route_options = { student_group: frm.doc.name } - frappe.set_route("List", "Assessment"); + frappe.set_route("List", "Assessment Plan"); }); } }, diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index f961cdd1efc..7421e019470 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -8,6 +8,7 @@ import frappe import frappe.defaults from frappe.utils import cint, flt, cstr, today from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice +from erpnext import set_perpetual_inventory class TestPurchaseReceipt(unittest.TestCase): def test_make_purchase_invoice(self): @@ -26,10 +27,10 @@ class TestPurchaseReceipt(unittest.TestCase): def test_purchase_receipt_no_gl_entry(self): set_perpetual_inventory(0) - + existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, "stock_value") - + pr = make_purchase_receipt() stock_value_difference = frappe.db.get_value("Stock Ledger Entry", @@ -78,22 +79,22 @@ class TestPurchaseReceipt(unittest.TestCase): def test_subcontracting(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry - + make_stock_entry(item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100) - make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse 1 - _TC", + make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100) - + pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=500, is_subcontracted="Yes") self.assertEquals(len(pr.get("supplied_items")), 2) - + rm_supp_cost = sum([d.amount for d in pr.get("supplied_items")]) self.assertEquals(pr.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2)) def test_serial_no_supplier(self): pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1) - self.assertEquals(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"), + self.assertEquals(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"), pr.supplier) - + pr.cancel() self.assertFalse(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "warehouse")) @@ -118,21 +119,21 @@ class TestPurchaseReceipt(unittest.TestCase): for serial_no in rejected_serial_nos: self.assertEquals(frappe.db.get_value("Serial No", serial_no, "warehouse"), pr.get("items")[0].rejected_warehouse) - + def test_purchase_return(self): set_perpetual_inventory() - + pr = make_purchase_receipt() - + return_pr = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-2) # check sle - outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt", + outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt", "voucher_no": return_pr.name}, "outgoing_rate") - + self.assertEqual(outgoing_rate, 50) - - + + # check gl entries for return gl_entries = get_gl_entries("Purchase Receipt", return_pr.name) @@ -146,7 +147,7 @@ class TestPurchaseReceipt(unittest.TestCase): for gle in gl_entries: self.assertEquals(expected_values[gle.account][0], gle.debit) self.assertEquals(expected_values[gle.account][1], gle.credit) - + set_perpetual_inventory(0) def test_purchase_return_for_rejected_qty(self): @@ -158,7 +159,7 @@ class TestPurchaseReceipt(unittest.TestCase): actual_qty = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt", "voucher_no": return_pr.name, 'warehouse': return_pr.items[0].rejected_warehouse}, "actual_qty") - + self.assertEqual(actual_qty, -2) set_perpetual_inventory(0) @@ -168,87 +169,82 @@ class TestPurchaseReceipt(unittest.TestCase): serial_no = frappe.get_doc("Serial No", serial_no) for field, value in field_values.items(): self.assertEquals(cstr(serial_no.get(field)), value) - + from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos - + pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1) - + serial_no = get_serial_nos(pr.get("items")[0].serial_no)[0] - + _check_serial_no_values(serial_no, { "warehouse": "_Test Warehouse - _TC", "purchase_document_no": pr.name }) - - return_pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=-1, + + return_pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=-1, is_return=1, return_against=pr.name, serial_no=serial_no) - + _check_serial_no_values(serial_no, { "warehouse": "", "purchase_document_no": pr.name, "delivery_document_no": return_pr.name }) - + def test_closed_purchase_receipt(self): from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_purchase_receipt_status - + pr = make_purchase_receipt(do_not_submit=True) pr.submit() - + update_purchase_receipt_status(pr.name, "Closed") self.assertEquals(frappe.db.get_value("Purchase Receipt", pr.name, "status"), "Closed") - + def test_pr_billing_status(self): # PO -> PR1 -> PI and PO -> PI and PO -> PR2 from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order from erpnext.buying.doctype.purchase_order.purchase_order \ import make_purchase_receipt, make_purchase_invoice as make_purchase_invoice_from_po - + po = create_purchase_order() - + pr1 = make_purchase_receipt(po.name) pr1.posting_date = today() pr1.posting_time = "10:00" pr1.get("items")[0].received_qty = 2 pr1.get("items")[0].qty = 2 pr1.submit() - + pi1 = make_purchase_invoice(pr1.name) pi1.submit() - + pr1.load_from_db() self.assertEqual(pr1.per_billed, 100) - + pi2 = make_purchase_invoice_from_po(po.name) pi2.get("items")[0].qty = 4 pi2.submit() - + pr2 = make_purchase_receipt(po.name) pr2.posting_date = today() pr2.posting_time = "08:00" pr2.get("items")[0].received_qty = 5 pr2.get("items")[0].qty = 5 pr2.submit() - + pr1.load_from_db() self.assertEqual(pr1.get("items")[0].billed_amt, 1000) self.assertEqual(pr1.per_billed, 100) self.assertEqual(pr1.status, "Completed") - + self.assertEqual(pr2.get("items")[0].billed_amt, 2000) self.assertEqual(pr2.per_billed, 80) self.assertEqual(pr2.status, "To Bill") - + def get_gl_entries(voucher_type, voucher_no): return frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account desc""", (voucher_type, voucher_no), as_dict=1) -def set_perpetual_inventory(enable=1): - accounts_settings = frappe.get_doc("Accounts Settings") - accounts_settings.auto_accounting_for_stock = enable - accounts_settings.save() - def make_purchase_receipt(**args): pr = frappe.new_doc("Purchase Receipt") args = frappe._dict(args) diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index edc54005479..ec64bdd3bdc 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -4,59 +4,64 @@ from __future__ import unicode_literals from frappe.model.rename_doc import rename_doc from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from frappe.utils import cint -from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory +from erpnext import set_perpetual_inventory +from frappe.test_runner import make_test_records import frappe import unittest test_records = frappe.get_test_records('Warehouse') class TestWarehouse(unittest.TestCase): + def setUp(self): + if not frappe.get_value('Item', '_Test Item'): + make_test_records('Item') + def test_parent_warehouse(self): parent_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC") self.assertEquals(parent_warehouse.is_group, 1) - + def test_warehouse_hierarchy(self): p_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC") - + child_warehouses = frappe.db.sql("""select name, is_group, parent_warehouse from `tabWarehouse` wh where wh.lft > %s and wh.rgt < %s""", (p_warehouse.lft, p_warehouse.rgt), as_dict=1) - + for child_warehouse in child_warehouses: self.assertEquals(p_warehouse.name, child_warehouse.parent_warehouse) self.assertEquals(child_warehouse.is_group, 0) - + def test_warehouse_renaming(self): set_perpetual_inventory(1) create_warehouse("Test Warehouse for Renaming 1") - + self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 1 - _TC")) - self.assertTrue(frappe.db.get_value("Account", + self.assertTrue(frappe.db.get_value("Account", filters={"warehouse": "Test Warehouse for Renaming 1 - _TC"})) - + # Rename with abbr if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"): frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC") rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC") - + self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 2 - _TC")) - self.assertTrue(frappe.db.get_value("Account", + self.assertTrue(frappe.db.get_value("Account", filters={"warehouse": "Test Warehouse for Renaming 2 - _TC"})) - + self.assertFalse(frappe.db.get_value("Account", + filters={"warehouse": "Test Warehouse for Renaming 1 - _TC"})) + # Rename without abbr if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"): frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC") - + rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3") - + self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 3 - _TC")) - self.assertTrue(frappe.db.get_value("Account", + self.assertTrue(frappe.db.get_value("Account", filters={"warehouse": "Test Warehouse for Renaming 3 - _TC"})) - - set_perpetual_inventory(0) - + def test_warehouse_merging(self): set_perpetual_inventory(1) - + create_warehouse("Test Warehouse for Merging 1") create_warehouse("Test Warehouse for Merging 2") @@ -64,31 +69,29 @@ class TestWarehouse(unittest.TestCase): qty=1, rate=100) make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - _TC", qty=1, rate=100) - + existing_bin_qty = ( - cint(frappe.db.get_value("Bin", + cint(frappe.db.get_value("Bin", {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - _TC"}, "actual_qty")) - + cint(frappe.db.get_value("Bin", + + cint(frappe.db.get_value("Bin", {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty")) ) - rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC", + rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC", "Test Warehouse for Merging 2 - _TC", merge=True) self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC")) bin_qty = frappe.db.get_value("Bin", {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty") - + self.assertEqual(bin_qty, existing_bin_qty) - + self.assertFalse(frappe.db.exists("Account", "Test Warehouse for Merging 1 - _TC")) self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Merging 2 - _TC")) - self.assertTrue(frappe.db.get_value("Account", + self.assertTrue(frappe.db.get_value("Account", filters={"warehouse": "Test Warehouse for Merging 2 - _TC"})) - - set_perpetual_inventory(0) - + def create_warehouse(warehouse_name): if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"): w = frappe.new_doc("Warehouse") @@ -96,5 +99,7 @@ def create_warehouse(warehouse_name): w.parent_warehouse = "_Test Warehouse Group - _TC" w.company = "_Test Company" w.save() - - \ No newline at end of file + + if not frappe.get_value('Account', dict(warehouse=warehouse_name + ' - _TC')): + print 'Warehouse {0} not linked'.format(warehouse_name) + diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 4f5f66fdf2e..d99cdf6ff7a 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -2,7 +2,7 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe +import frappe, erpnext from frappe.utils import cint, validate_email_add from frappe import throw, msgprint, _ from frappe.utils.nestedset import NestedSet @@ -53,6 +53,8 @@ class Warehouse(NestedSet): self.update_nsm_model() def create_account_head(self): + '''Create new account head if there is no account linked to this Warehouse''' + from erpnext.accounts.doctype.account.account import BalanceMismatchError if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if not self.get_account(): if self.get("__islocal") or not frappe.db.get_value( @@ -76,10 +78,12 @@ class Warehouse(NestedSet): ac_doc.insert() msgprint(_("Account head {0} created").format(ac_doc.name), indicator='green', alert=True) - except frappe.DuplicateEntryError, e: - if not (e.args and e.args[0]=='Account'): - # if this is not due to creation of Account - raise + except frappe.DuplicateEntryError: + msgprint(_("Please create an Account for this Warehouse and link it. This cannot be done automatically as an account with name {0} already exists").format(frappe.bold(self.name)), + indicator='orange') + + except BalanceMismatchError: + msgprint(_("Cannot automatically create Account as there is already stock balance in the Account. You must create a matching account before you can make an entry on this warehouse")) def validate_parent_account(self): if not self.company: @@ -111,7 +115,7 @@ class Warehouse(NestedSet): else: frappe.db.sql("delete from `tabBin` where name = %s", d['name']) - warehouse_account = self.get_account(self.name) + warehouse_account = self.get_account() if warehouse_account: frappe.delete_doc("Account", warehouse_account) @@ -131,10 +135,9 @@ class Warehouse(NestedSet): return frappe.db.sql("""select name from `tabWarehouse` where parent_warehouse = %s""", self.name) - def before_rename(self, olddn, newdn, merge=False): + def before_rename(self, old_name, new_name, merge=False): # Add company abbr if not provided - from erpnext.setup.doctype.company.company import get_name_with_abbr - new_warehouse = get_name_with_abbr(newdn, self.company) + new_warehouse = erpnext.encode_company_abbr(new_name, self.company) if merge: if not frappe.db.exists("Warehouse", new_warehouse): @@ -143,64 +146,54 @@ class Warehouse(NestedSet): if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"): frappe.throw(_("Both Warehouse must belong to same Company")) - self.rename_account_for(olddn, new_warehouse, merge) + self.rename_account_for(old_name, new_warehouse, merge) return new_warehouse - def rename_account_for(self, olddn, newdn, merge): - if self.is_group: - old_account = self.get_account() - else: - old_account = self.get_account(olddn) + def rename_account_for(self, old_name, new_name, merge): + old_account_name = frappe.get_value('Account', dict(warehouse=old_name)) - if old_account: - new_account = None + if old_account_name: if not merge: - if old_account == self.add_abbr_if_missing(olddn): - new_account = frappe.rename_doc("Account", old_account, newdn) + # old account name is same as old name, so rename the account too + if old_account_name == erpnext.encode_company_abbr(old_name, self.company): + frappe.rename_doc("Account", old_account_name, new_name) else: - existing_new_account = self.get_account(newdn) - new_account = frappe.rename_doc("Account", old_account, - existing_new_account or newdn, merge=True if existing_new_account else False) + # merge + target_account = frappe.get_value('Account', dict(warehouse=new_name)) + if target_account: + # target warehouse has account, merge into target account + frappe.rename_doc("Account", old_account_name, + target_account, merge=True) + else: + # target warehouse does not have account, use this account + frappe.rename_doc("Account", old_account_name, + new_name, merge=False) - frappe.db.set_value("Account", new_account or old_account, "warehouse", newdn) + # rename link + frappe.db.set_value('Account', new_name, 'warehouse', new_name) - def add_abbr_if_missing(self, dn): - from erpnext.setup.doctype.company.company import get_name_with_abbr - return get_name_with_abbr(dn, self.company) + def get_account(self): + return frappe.get_value('Account', dict(warehouse=self.name)) - def get_account(self, warehouse=None): - filters = { - "account_type": "Stock", - "company": self.company, - "is_group": self.is_group - } - - if warehouse: - filters.update({"warehouse": warehouse}) - else: - filters.update({"account_name": self.warehouse_name}) - - return frappe.db.get_value("Account", filters) - - def after_rename(self, olddn, newdn, merge=False): + def after_rename(self, old_name, new_name, merge=False): if merge: - self.recalculate_bin_qty(newdn) + self.recalculate_bin_qty(new_name) - def recalculate_bin_qty(self, newdn): + def recalculate_bin_qty(self, new_name): from erpnext.stock.stock_balance import repost_stock frappe.db.auto_commit_on_many_writes = 1 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) repost_stock_for_items = frappe.db.sql_list("""select distinct item_code - from tabBin where warehouse=%s""", newdn) + from tabBin where warehouse=%s""", new_name) # Delete all existing bins to avoid duplicate bins for the same item and warehouse - frappe.db.sql("delete from `tabBin` where warehouse=%s", newdn) + frappe.db.sql("delete from `tabBin` where warehouse=%s", new_name) for item_code in repost_stock_for_items: - repost_stock(item_code, newdn) + repost_stock(item_code, new_name) frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) frappe.db.auto_commit_on_many_writes = 0 @@ -231,7 +224,7 @@ class Warehouse(NestedSet): if self.check_if_sle_exists(): throw(_("Warehouses with existing transaction can not be converted to group.")) else: - account_name = self.get_account(self.name) + account_name = self.get_account() if account_name: doc = frappe.get_doc("Account", account_name) doc.flags.exclude_account_type_check = True