Suggested Changes to School (#6223)

* Linkage of academic term to academic year

* School improvements. Modifications to Academic Term, Assessment, Fees, Student Batch, Student Group. Addition of Grading System.

* Removed Grading System from Assessment and put it on Program

* Removed the field Grading System from Program and added it back to Assessment. Added some validations for dates in controller of Academic Term and Academic Year

* Added validation comparing term start dates with academic year start dates and term end dates with academic year end dates where both are available.

* Renamed Grading System to Grading Structure. Implemented the code in Assessment.js to derive the Grade Code from the result entered for the student. Assumes that result is always a number. Will rename the field result in Results to score.

* Added validation to check if any grade intervals were overlapping when a Grading Structure is being saved.

* Corrections to error in autonaming for Academic Term

* Correction in white_list method get_grade in Assessment. Solves problem with grades not being derived when the score is at the boundaries of a grade interval

* Correction to setup_wizard.py to make sure that creation of academic terms in create_academic_term includes the academic_year which is now mandatory

* Corrections to test_records.json for doctype Academic Term

* Correction of test_records.json in doctype Student Groups

* Correction of test_records.json for doctype Student Group 2

* Correction to test_course_schedule.py in doctype Course Schedule

* More corrections to test_course_schedule.py in doctype Course Schedule

* Corrections to test_course_schedule.py

* Updates to Student DocType. Enrollment date, Nationality

* Linkage of academic term to academic year

* School improvements. Modifications to Academic Term, Assessment, Fees, Student Batch, Student Group. Addition of Grading System.

* Removed Grading System from Assessment and put it on Program

* Removed the field Grading System from Program and added it back to Assessment. Added some validations for dates in controller of Academic Term and Academic Year

* Added validation comparing term start dates with academic year start dates and term end dates with academic year end dates where both are available.

* Renamed Grading System to Grading Structure. Implemented the code in Assessment.js to derive the Grade Code from the result entered for the student. Assumes that result is always a number. Will rename the field result in Results to score.

* Added validation to check if any grade intervals were overlapping when a Grading Structure is being saved.

* Corrections to error in autonaming for Academic Term
This commit is contained in:
manqala 2016-09-03 16:35:06 +01:00 committed by Rushabh Mehta
parent 23d79b7059
commit b2b238323b
33 changed files with 1201 additions and 512 deletions

View File

@ -120,6 +120,10 @@ def get_data():
"type": "doctype", "type": "doctype",
"name": "Course" "name": "Course"
}, },
{
"type": "doctype",
"name": "Grading Structure"
},
{ {
"type": "doctype", "type": "doctype",
"name": "Program" "name": "Program"

View File

@ -2,7 +2,7 @@
"allow_copy": 0, "allow_copy": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:term_name", "autoname": "field:title",
"beta": 0, "beta": 0,
"creation": "2015-09-08 17:19:19.158228", "creation": "2015-09-08 17:19:19.158228",
"custom": 0, "custom": 0,
@ -11,6 +11,32 @@
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 0, "editable_grid": 0,
"fields": [ "fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "academic_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Academic Year",
"length": 0,
"no_copy": 0,
"options": "Academic Year",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -31,6 +57,81 @@
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "term_start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Term Start Date",
"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": 1,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "term_end_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Term End Date",
"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": 1,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Title",
"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, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
@ -47,7 +148,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-07-25 05:24:23.032319", "modified": "2016-08-27 23:02:03.565866",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Academic Term", "name": "Academic Term",
@ -78,7 +179,8 @@
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"sort_field": "modified", "sort_field": "name",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "title",
"track_seen": 0 "track_seen": 0
} }

View File

@ -4,7 +4,35 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import msgprint, _
from frappe.utils import get_datetime, get_datetime_str
from frappe.model.document import Document from frappe.model.document import Document
class AcademicTerm(Document): class AcademicTerm(Document):
pass def autoname(self):
self.name = self.academic_year + " ({})".format(self.term_name) if self.term_name else ""
def validate(self):
#Check if entry with same academic_year and the term_name already exists
validate_duplication(self)
self.title = self.academic_year + " ({})".format(self.term_name) if self.term_name else ""
#Check that start of academic year is earlier than end of academic year
if self.term_start_date and self.term_end_date and self.term_start_date > self.term_end_date:
frappe.throw(_("The Term End Date cannot be earlier than the Term Start Date. Please correct the dates and try again."))
"""Check that the start of the term is not before the start of the academic year and end of term is not after
the end of the academic year"""
year = frappe.get_doc("Academic Year",self.academic_year)
if self.term_start_date and get_datetime_str(year.year_start_date) and (self.term_start_date < get_datetime_str(year.year_start_date)):
frappe.throw(_("The Term Start Date cannot be earlier than the Year Start Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
if self.term_end_date and get_datetime_str(year.year_end_date) and (self.term_end_date > get_datetime_str(year.year_end_date)):
frappe.throw(_("The Term End Date cannot be later than the Year End Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
def validate_duplication(self):
term = frappe.db.sql("""select name from `tabAcademic Term` where academic_year= %s and term_name= %s
and docstatus<2 and name != %s""", (self.academic_year, self.term_name, self.name))
if term:
frappe.throw(_("An academic term with this 'Academic Year' {0} and 'Term Name' {1} already exists. Please modify these entries and try again.").format(self.academic_year,self.term_name))

View File

@ -1,11 +1,17 @@
[ [
{ {
"term_name": "_Test Academic Term" "doctype": "Academic Term",
}, "academic_year": "2014-2015",
{ "term_name": "_Test Academic Term"
"term_name": "_Test Academic Term 1" },
}, {
{ "doctype": "Academic Term",
"term_name": "_Test Academic Term 2" "academic_year": "2014-2015",
} "term_name": "_Test Academic Term 1"
] },
{
"doctype": "Academic Term",
"academic_year": "2014-2015",
"term_name": "_Test Academic Term 2"
}
]

View File

@ -4,7 +4,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import msgprint, _
from frappe.model.document import Document from frappe.model.document import Document
class AcademicYear(Document): class AcademicYear(Document):
pass def validate(self):
#Check that start of academic year is earlier than end of academic year
if self.year_start_date and self.year_end_date and self.year_start_date > self.year_end_date:
frappe.throw(_("The Year End Date cannot be earlier than the Year Start Date. Please correct the dates and try again."))

View File

@ -28,4 +28,24 @@ frappe.ui.form.on("Assessment" ,{
}); });
} }
} }
});
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);
}
}
});
}
}
}); });

View File

@ -87,6 +87,32 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "grading_structure",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"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,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -506,7 +532,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-08-05 04:57:41.018614", "modified": "2016-08-27 14:18:51.852078",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Assessment", "name": "Assessment",

View File

@ -8,39 +8,56 @@ import frappe
from frappe import _ from frappe import _
class Assessment(Document): class Assessment(Document):
def validate(self): def validate(self):
self.validate_overlap() self.validate_overlap()
def validate_overlap(self): def validate_overlap(self):
"""Validates overlap for Student Group, Supervisor, Room""" """Validates overlap for Student Group, Supervisor, Room"""
from erpnext.schools.utils import validate_overlap_for from erpnext.schools.utils import validate_overlap_for
validate_overlap_for(self, "Assessment", "student_group") validate_overlap_for(self, "Assessment", "student_group")
validate_overlap_for(self, "Course Schedule", "student_group" ) validate_overlap_for(self, "Course Schedule", "student_group" )
if self.room: if self.room:
validate_overlap_for(self, "Assessment", "room") validate_overlap_for(self, "Assessment", "room")
validate_overlap_for(self, "Course Schedule", "room") validate_overlap_for(self, "Course Schedule", "room")
if self.supervisor: if self.supervisor:
validate_overlap_for(self, "Assessment", "supervisor") validate_overlap_for(self, "Assessment", "supervisor")
validate_overlap_for(self, "Course Schedule", "instructor", self.supervisor) validate_overlap_for(self, "Course Schedule", "instructor", self.supervisor)
def get_assessment_list(doctype, txt, filters, limit_start, limit_page_length=20): def get_assessment_list(doctype, txt, filters, limit_start, limit_page_length=20):
user = frappe.session.user user = frappe.session.user
student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
if student: if student:
return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, 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 `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}''' order by assessment.name asc limit {0} , {1}'''
.format(limit_start, limit_page_length), student, as_dict = True) .format(limit_start, limit_page_length), student, as_dict = True)
def get_list_context(context=None): def get_list_context(context=None):
return { return {
"show_sidebar": True, "show_sidebar": True,
'no_breadcrumbs': True, 'no_breadcrumbs': True,
"title": _("Assessment Schedule"), "title": _("Assessment Schedule"),
"get_list": get_assessment_list, "get_list": get_assessment_list,
"row_template": "templates/includes/assessment/assessment_row.html" "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

View File

@ -109,6 +109,31 @@
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "grade",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Grade",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
} }
], ],
"hide_heading": 0, "hide_heading": 0,
@ -121,7 +146,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-08-01 10:37:23.571679", "modified": "2016-08-27 12:15:01.923000",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Assessment Result", "name": "Assessment Result",

View File

@ -24,27 +24,27 @@ class TestCourseSchedule(unittest.TestCase):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="TC2-TP-2014-2015-_Test Academic Term", room="RM0002", do_not_save= 1) student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", room="RM0002", do_not_save= 1)
self.assertRaises(OverlapError, cs2.save) self.assertRaises(OverlapError, cs2.save)
def test_room_conflict(self): def test_room_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="TC2-TP-2014-2015-_Test Academic Term", instructor="_T-Instructor-00002", do_not_save= 1) student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", do_not_save= 1)
self.assertRaises(OverlapError, cs2.save) self.assertRaises(OverlapError, cs2.save)
def test_no_conflict(self): def test_no_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="TC2-TP-2014-2015-_Test Academic Term", instructor="_T-Instructor-00002", room="RM0002") student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", room="RM0002")
def make_course_schedule_test_record(**args): def make_course_schedule_test_record(**args):
args = frappe._dict(args) args = frappe._dict(args)
course_schedule = frappe.new_doc("Course Schedule") course_schedule = frappe.new_doc("Course Schedule")
course_schedule.student_group = args.student_group or "TC-TP-2014-2015-_Test Academic Term" course_schedule.student_group = args.student_group or "TC-TP-2014-2015-2014-2015 (_Test Academic Term)"
course_schedule.course = args.course or "_Test Course" course_schedule.course = args.course or "_Test Course"
course_schedule.instructor = args.instructor or "_T-Instructor-00001" course_schedule.instructor = args.instructor or "_T-Instructor-00001"
course_schedule.room = args.room or "RM0001" course_schedule.room = args.room or "RM0001"

View File

@ -2,6 +2,25 @@
cur_frm.add_fetch("student", "title", "student_name"); cur_frm.add_fetch("student", "title", "student_name");
frappe.ui.form.on("Fees", { frappe.ui.form.on("Fees", {
onload: function(frm){
cur_frm.set_query("academic_term",function(){
return{
"filters":{
"academic_year": (frm.doc.academic_year)
}
};
});
cur_frm.set_query("fee_structure",function(){
return{
"filters":{
"academic_term": (frm.doc.academic_term)
}
};
});
},
refresh: function(frm) { refresh: function(frm) {
if (frm.doc.docstatus === 1 && (frm.doc.total_amount > frm.doc.paid_amount)) { if (frm.doc.docstatus === 1 && (frm.doc.total_amount > frm.doc.paid_amount)) {
frm.add_custom_button(__("Collect Fees"), function() { frm.add_custom_button(__("Collect Fees"), function() {

View File

@ -41,17 +41,17 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "academic_term", "fieldname": "academic_year",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Academic Term", "label": "Academic Year",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Academic Term", "options": "Academic Year",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -67,17 +67,17 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "academic_year", "fieldname": "academic_term",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Academic Year", "label": "Academic Term",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Academic Year", "options": "Academic Term",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -480,7 +480,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-07-27 03:52:28.509757", "modified": "2016-08-26 02:28:48.877990",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Fees", "name": "Fees",

View File

@ -0,0 +1,137 @@
{
"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,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "grade_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Grade Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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": "from_score",
"fieldtype": "Float",
"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",
"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": "grade_description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Grade Description",
"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
}
],
"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-08-27 15:45:04.657328",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grade Interval",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class GradeInterval(Document):
def validate(self):
pass

View File

@ -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 Structure', {
refresh: function(frm) {
}
});

View File

@ -0,0 +1,185 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:grading_system_name",
"beta": 0,
"creation": "2016-08-26 03:06:53.922972",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "grading_system_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Grading System Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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": "description",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Description",
"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,
"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,
"fieldname": "grading_intervals_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Grading Intervals",
"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,
"fieldname": "grade_intervals",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Grade Intervals",
"length": 0,
"no_copy": 0,
"options": "Grade Interval",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"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-08-27 14:20:50.709823",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grading Structure",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "grading_system_name",
"track_seen": 0
}

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
from frappe.utils import cstr
class GradingStructure(Document):
def validate(self):
grade_intervals = self.get("grade_intervals")
check_overlap(grade_intervals, self)
#Check if any of the grade intervals for this grading structure overlap
def check_overlap(grade_intervals, parent_doc):
for interval1 in grade_intervals:
for interval2 in grade_intervals:
if interval1.name == interval2.name:
pass
else:
if (interval1.from_score <= interval2.from_score and interval1.to_score >= interval2.from_score) or (interval1.from_score <= interval2.to_score and interval1.to_score >= interval2.to_score):
frappe.throw(_("""The intervals for Grade Code {0} overlaps with the grade intervals for other grades.
Please check intervals {0} and {1} and try again""".format(interval1.grade_code, interval2.grade_code)))

View File

@ -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('Grading Structure')
class TestGradingStructure(unittest.TestCase):
pass

View File

@ -250,7 +250,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-07-25 01:33:56.912243", "modified": "2016-08-27 03:21:35.806511",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Program", "name": "Program",

View File

@ -18,5 +18,23 @@ frappe.ui.form.on("Program Enrollment", {
} }
}); });
} }
},
onload: function(frm, cdt, cdn){
cur_frm.set_query("academic_term", "fees", function(){
return{
"filters":{
"academic_year": (frm.doc.academic_year)
}
};
});
cur_frm.fields_dict['fees'].grid.get_field('fee_structure').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: {'academic_term': d.academic_term}
}
};
} }
}); });

View File

@ -165,7 +165,7 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"default": "Today", "default": "",
"fieldname": "joining_date", "fieldname": "joining_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@ -180,7 +180,7 @@
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 1, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -371,7 +371,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "nationality", "fieldname": "nationality",
"fieldtype": "Data", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -380,6 +380,7 @@
"label": "Nationality", "label": "Nationality",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Country",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -456,7 +457,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-07-25 07:22:57.581638", "modified": "2016-08-21 05:41:34.091353",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Student", "name": "Student",

View File

@ -525,7 +525,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "nationality", "fieldname": "nationality",
"fieldtype": "Data", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -534,6 +534,7 @@
"label": "Nationality", "label": "Nationality",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Country",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -633,7 +634,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-07-25 01:24:27.384647", "modified": "2016-08-26 01:01:45.669665",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Student Applicant", "name": "Student Applicant",

View File

@ -4,7 +4,18 @@
frappe.ui.form.on('Student Batch', { frappe.ui.form.on('Student Batch', {
refresh: function(frm) { refresh: function(frm) {
},
onload: function(frm){
cur_frm.set_query("academic_term",function(){
return{
"filters":{
"academic_year": (frm.doc.academic_year)
}
};
});
} }
}); });
cur_frm.add_fetch("student", "title", "student_name"); cur_frm.add_fetch("student", "title", "student_name");

View File

@ -199,7 +199,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-07-22 09:19:51.141234", "modified": "2016-08-24 05:32:00.585277",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Student Batch", "name": "Student Batch",

View File

@ -8,12 +8,12 @@ from erpnext.schools.utils import validate_duplicate_student
import frappe import frappe
class StudentBatch(Document): class StudentBatch(Document):
def autoname(self): def autoname(self):
prog_abb = frappe.db.get_value("Program", self.program, "program_abbreviation") prog_abb = frappe.db.get_value("Program", self.program, "program_abbreviation")
if not prog_abb: if not prog_abb:
prog_abb = self.program prog_abb = self.program
self.name = prog_abb + "-"+ self.student_batch_name + "-" + self.academic_year self.name = prog_abb + "-"+ self.student_batch_name + "-" + self.academic_year
def validate(self): def validate(self):
validate_duplicate_student(self.students) validate_duplicate_student(self.students)

View File

@ -16,4 +16,19 @@ frappe.ui.form.on("Student Group", "refresh", function(frm) {
frappe.set_route("List", "Assessment"); frappe.set_route("List", "Assessment");
}); });
} }
}); });
frappe.ui.form.on("Student Group", "onload", function(frm){
cur_frm.set_query("academic_term",function(){
return{
"filters":{
"academic_year": (frm.doc.academic_year)
}
};
});
});
//If Student Batch is entered, deduce program, academic_year and academic term from it
cur_frm.add_fetch("student_batch", "program", "program");
cur_frm.add_fetch("student_batch", "academic_term", "academic_term");
cur_frm.add_fetch("student_batch", "academic_year", "academic_year");

View File

@ -41,17 +41,17 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "academic_term", "fieldname": "academic_year",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Academic Term", "label": "Academic Year",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Academic Term", "options": "Academic Year",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -67,17 +67,17 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "academic_year", "fieldname": "academic_term",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Academic Year", "label": "Academic Term",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Academic Year", "options": "Academic Term",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -280,7 +280,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-07-25 06:23:43.903111", "modified": "2016-08-24 05:21:05.058875",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Student Group", "name": "Student Group",

View File

@ -3,12 +3,12 @@
"program": "_Test Program", "program": "_Test Program",
"course": "_Test Course", "course": "_Test Course",
"academic_year": "2014-2015", "academic_year": "2014-2015",
"academic_term": "_Test Academic Term" "academic_term": "2014-2015 (_Test Academic Term)"
}, },
{ {
"program": "_Test Program", "program": "_Test Program",
"course": "_Test Course 2", "course": "_Test Course 2",
"academic_year": "2014-2015", "academic_year": "2014-2015",
"academic_term": "_Test Academic Term" "academic_term": "2014-2015 (_Test Academic Term)"
} }
] ]

View File

@ -20,4 +20,14 @@ frappe.ui.form.on("Student Group Creation Tool", "get_courses", function(frm) {
} }
} }
}) })
});
frappe.ui.form.on("Student Group Creation Tool", "onload", function(frm){
cur_frm.set_query("academic_term",function(){
return{
"filters":{
"academic_year": (frm.doc.academic_year)
}
};
});
}); });

View File

@ -15,538 +15,541 @@ from frappe.core.doctype.communication.comment import add_info_comment
from erpnext.setup.setup_wizard.domainify import setup_domain from erpnext.setup.setup_wizard.domainify import setup_domain
def setup_complete(args=None): def setup_complete(args=None):
if frappe.db.sql("select name from tabCompany"): if frappe.db.sql("select name from tabCompany"):
frappe.throw(_("Setup Already Complete!!")) frappe.throw(_("Setup Already Complete!!"))
install_fixtures.install(args.get("country")) install_fixtures.install(args.get("country"))
create_price_lists(args) create_price_lists(args)
create_fiscal_year_and_company(args) create_fiscal_year_and_company(args)
create_users(args) create_users(args)
set_defaults(args) set_defaults(args)
create_territories() create_territories()
create_feed_and_todo() create_feed_and_todo()
create_email_digest() create_email_digest()
create_letter_head(args) create_letter_head(args)
create_taxes(args) create_taxes(args)
create_items(args) create_items(args)
create_customers(args) create_customers(args)
create_suppliers(args) create_suppliers(args)
if args.domain.lower() == 'education': if args.domain.lower() == 'education':
create_academic_term() create_academic_year()
create_academic_year() create_academic_term()
create_program(args) create_program(args)
create_course(args) create_course(args)
create_instructor(args) create_instructor(args)
create_room(args) create_room(args)
if args.get('setup_website'): if args.get('setup_website'):
website_maker(args) website_maker(args)
create_logo(args) create_logo(args)
frappe.local.message_log = [] frappe.local.message_log = []
setup_domain(args.get('domain')) setup_domain(args.get('domain'))
frappe.db.commit() frappe.db.commit()
login_as_first_user(args) login_as_first_user(args)
frappe.db.commit() frappe.db.commit()
frappe.clear_cache() frappe.clear_cache()
if args.get("add_sample_data"): if args.get("add_sample_data"):
try: try:
make_sample_data() make_sample_data()
frappe.clear_cache() frappe.clear_cache()
except: except:
# clear message # clear message
if frappe.message_log: if frappe.message_log:
frappe.message_log.pop() frappe.message_log.pop()
pass pass
def create_fiscal_year_and_company(args): def create_fiscal_year_and_company(args):
if (args.get('fy_start_date')): if (args.get('fy_start_date')):
curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date')) curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date'))
frappe.get_doc({ frappe.get_doc({
"doctype":"Fiscal Year", "doctype":"Fiscal Year",
'year': curr_fiscal_year, 'year': curr_fiscal_year,
'year_start_date': args.get('fy_start_date'), 'year_start_date': args.get('fy_start_date'),
'year_end_date': args.get('fy_end_date'), 'year_end_date': args.get('fy_end_date'),
}).insert() }).insert()
args["curr_fiscal_year"] = curr_fiscal_year args["curr_fiscal_year"] = curr_fiscal_year
# Company # Company
if (args.get('company_name')): if (args.get('company_name')):
frappe.get_doc({ frappe.get_doc({
"doctype":"Company", "doctype":"Company",
'company_name':args.get('company_name').strip(), 'company_name':args.get('company_name').strip(),
'abbr':args.get('company_abbr'), 'abbr':args.get('company_abbr'),
'default_currency':args.get('currency'), 'default_currency':args.get('currency'),
'country': args.get('country'), 'country': args.get('country'),
'chart_of_accounts': args.get(('chart_of_accounts')), 'chart_of_accounts': args.get(('chart_of_accounts')),
'domain': args.get('domain') 'domain': args.get('domain')
}).insert() }).insert()
#Enable shopping cart #Enable shopping cart
enable_shopping_cart(args) enable_shopping_cart(args)
# Bank Account # Bank Account
create_bank_account(args) create_bank_account(args)
def enable_shopping_cart(args): def enable_shopping_cart(args):
frappe.get_doc({ frappe.get_doc({
"doctype": "Shopping Cart Settings", "doctype": "Shopping Cart Settings",
"enabled": 1, "enabled": 1,
'company': args.get('company_name').strip(), 'company': args.get('company_name').strip(),
'price_list': frappe.db.get_value("Price List", {"selling": 1}), 'price_list': frappe.db.get_value("Price List", {"selling": 1}),
'default_customer_group': _("Individual"), 'default_customer_group': _("Individual"),
'quotation_series': "QTN-", 'quotation_series': "QTN-",
}).insert() }).insert()
def create_bank_account(args): def create_bank_account(args):
if args.get("bank_account"): if args.get("bank_account"):
company_name = args.get('company_name').strip() company_name = args.get('company_name').strip()
bank_account_group = frappe.db.get_value("Account", bank_account_group = frappe.db.get_value("Account",
{"account_type": "Bank", "is_group": 1, "root_type": "Asset", {"account_type": "Bank", "is_group": 1, "root_type": "Asset",
"company": company_name}) "company": company_name})
if bank_account_group: if bank_account_group:
bank_account = frappe.get_doc({ bank_account = frappe.get_doc({
"doctype": "Account", "doctype": "Account",
'account_name': args.get("bank_account"), 'account_name': args.get("bank_account"),
'parent_account': bank_account_group, 'parent_account': bank_account_group,
'is_group':0, 'is_group':0,
'company': company_name, 'company': company_name,
"account_type": "Bank", "account_type": "Bank",
}) })
try: try:
return bank_account.insert() return bank_account.insert()
except RootNotEditable: except RootNotEditable:
frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account"))) frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account")))
except frappe.DuplicateEntryError: except frappe.DuplicateEntryError:
# bank account same as a CoA entry # bank account same as a CoA entry
pass pass
def create_price_lists(args): def create_price_lists(args):
for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))): for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))):
frappe.get_doc({ frappe.get_doc({
"doctype": "Price List", "doctype": "Price List",
"price_list_name": pl_name, "price_list_name": pl_name,
"enabled": 1, "enabled": 1,
"buying": 1 if pl_type == "Buying" else 0, "buying": 1 if pl_type == "Buying" else 0,
"selling": 1 if pl_type == "Selling" else 0, "selling": 1 if pl_type == "Selling" else 0,
"currency": args["currency"] "currency": args["currency"]
}).insert() }).insert()
def set_defaults(args): def set_defaults(args):
# enable default currency # enable default currency
frappe.db.set_value("Currency", args.get("currency"), "enabled", 1) frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
global_defaults = frappe.get_doc("Global Defaults", "Global Defaults") global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
global_defaults.update({ global_defaults.update({
'current_fiscal_year': args.curr_fiscal_year, 'current_fiscal_year': args.curr_fiscal_year,
'default_currency': args.get('currency'), 'default_currency': args.get('currency'),
'default_company':args.get('company_name').strip(), 'default_company':args.get('company_name').strip(),
"country": args.get("country"), "country": args.get("country"),
}) })
global_defaults.save() global_defaults.save()
frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company")) frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company"))
accounts_settings = frappe.get_doc("Accounts Settings") accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.auto_accounting_for_stock = 1 accounts_settings.auto_accounting_for_stock = 1
accounts_settings.save() accounts_settings.save()
stock_settings = frappe.get_doc("Stock Settings") stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code" stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO" stock_settings.valuation_method = "FIFO"
stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')}) stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})
stock_settings.stock_uom = _("Nos") stock_settings.stock_uom = _("Nos")
stock_settings.auto_indent = 1 stock_settings.auto_indent = 1
stock_settings.auto_insert_price_list_rate_if_missing = 1 stock_settings.auto_insert_price_list_rate_if_missing = 1
stock_settings.automatically_set_serial_nos_based_on_fifo = 1 stock_settings.automatically_set_serial_nos_based_on_fifo = 1
stock_settings.save() stock_settings.save()
selling_settings = frappe.get_doc("Selling Settings") selling_settings = frappe.get_doc("Selling Settings")
selling_settings.cust_master_name = "Customer Name" selling_settings.cust_master_name = "Customer Name"
selling_settings.so_required = "No" selling_settings.so_required = "No"
selling_settings.dn_required = "No" selling_settings.dn_required = "No"
selling_settings.save() selling_settings.save()
buying_settings = frappe.get_doc("Buying Settings") buying_settings = frappe.get_doc("Buying Settings")
buying_settings.supp_master_name = "Supplier Name" buying_settings.supp_master_name = "Supplier Name"
buying_settings.po_required = "No" buying_settings.po_required = "No"
buying_settings.pr_required = "No" buying_settings.pr_required = "No"
buying_settings.maintain_same_rate = 1 buying_settings.maintain_same_rate = 1
buying_settings.save() buying_settings.save()
notification_control = frappe.get_doc("Notification Control") notification_control = frappe.get_doc("Notification Control")
notification_control.quotation = 1 notification_control.quotation = 1
notification_control.sales_invoice = 1 notification_control.sales_invoice = 1
notification_control.purchase_order = 1 notification_control.purchase_order = 1
notification_control.save() notification_control.save()
hr_settings = frappe.get_doc("HR Settings") hr_settings = frappe.get_doc("HR Settings")
hr_settings.emp_created_by = "Naming Series" hr_settings.emp_created_by = "Naming Series"
hr_settings.save() hr_settings.save()
def create_feed_and_todo(): def create_feed_and_todo():
"""update Activity feed and create todo for creation of item, customer, vendor""" """update Activity feed and create todo for creation of item, customer, vendor"""
add_info_comment(**{ add_info_comment(**{
"subject": _("ERPNext Setup Complete!") "subject": _("ERPNext Setup Complete!")
}) })
def create_email_digest(): def create_email_digest():
from frappe.utils.user import get_system_managers from frappe.utils.user import get_system_managers
system_managers = get_system_managers(only_name=True) system_managers = get_system_managers(only_name=True)
if not system_managers: if not system_managers:
return return
companies = frappe.db.sql_list("select name FROM `tabCompany`") companies = frappe.db.sql_list("select name FROM `tabCompany`")
for company in companies: for company in companies:
if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company): if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
edigest = frappe.get_doc({ edigest = frappe.get_doc({
"doctype": "Email Digest", "doctype": "Email Digest",
"name": "Default Weekly Digest - " + company, "name": "Default Weekly Digest - " + company,
"company": company, "company": company,
"frequency": "Weekly", "frequency": "Weekly",
"recipient_list": "\n".join(system_managers) "recipient_list": "\n".join(system_managers)
}) })
for df in edigest.meta.get("fields", {"fieldtype": "Check"}): for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
if df.fieldname != "scheduler_errors": if df.fieldname != "scheduler_errors":
edigest.set(df.fieldname, 1) edigest.set(df.fieldname, 1)
edigest.insert() edigest.insert()
# scheduler errors digest # scheduler errors digest
if companies: if companies:
edigest = frappe.new_doc("Email Digest") edigest = frappe.new_doc("Email Digest")
edigest.update({ edigest.update({
"name": "Scheduler Errors", "name": "Scheduler Errors",
"company": companies[0], "company": companies[0],
"frequency": "Daily", "frequency": "Daily",
"recipient_list": "\n".join(system_managers), "recipient_list": "\n".join(system_managers),
"scheduler_errors": 1, "scheduler_errors": 1,
"enabled": 1 "enabled": 1
}) })
edigest.insert() edigest.insert()
def get_fy_details(fy_start_date, fy_end_date): def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year start_year = getdate(fy_start_date).year
if start_year == getdate(fy_end_date).year: if start_year == getdate(fy_end_date).year:
fy = cstr(start_year) fy = cstr(start_year)
else: else:
fy = cstr(start_year) + '-' + cstr(start_year + 1) fy = cstr(start_year) + '-' + cstr(start_year + 1)
return fy return fy
def create_taxes(args): def create_taxes(args):
for i in xrange(1,6): for i in xrange(1,6):
if args.get("tax_" + str(i)): if args.get("tax_" + str(i)):
# replace % in case someone also enters the % symbol # replace % in case someone also enters the % symbol
tax_rate = cstr(args.get("tax_rate_" + str(i)) or "").replace("%", "") tax_rate = cstr(args.get("tax_rate_" + str(i)) or "").replace("%", "")
try: try:
tax_group = frappe.db.get_value("Account", {"company": args.get("company_name"), tax_group = frappe.db.get_value("Account", {"company": args.get("company_name"),
"is_group": 1, "account_type": "Tax", "root_type": "Liability"}) "is_group": 1, "account_type": "Tax", "root_type": "Liability"})
if tax_group: if tax_group:
account = make_tax_head(args, i, tax_group, tax_rate) account = make_tax_head(args, i, tax_group, tax_rate)
make_sales_and_purchase_tax_templates(account) make_sales_and_purchase_tax_templates(account)
except frappe.NameError, e: except frappe.NameError, e:
if e.args[2][0]==1062: if e.args[2][0]==1062:
pass pass
else: else:
raise raise
except RootNotEditable, e: except RootNotEditable, e:
pass pass
def make_tax_head(args, i, tax_group, tax_rate): def make_tax_head(args, i, tax_group, tax_rate):
return frappe.get_doc({ return frappe.get_doc({
"doctype":"Account", "doctype":"Account",
"company": args.get("company_name").strip(), "company": args.get("company_name").strip(),
"parent_account": tax_group, "parent_account": tax_group,
"account_name": args.get("tax_" + str(i)), "account_name": args.get("tax_" + str(i)),
"is_group": 0, "is_group": 0,
"report_type": "Balance Sheet", "report_type": "Balance Sheet",
"account_type": "Tax", "account_type": "Tax",
"tax_rate": flt(tax_rate) if tax_rate else None "tax_rate": flt(tax_rate) if tax_rate else None
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True)
def make_sales_and_purchase_tax_templates(account): def make_sales_and_purchase_tax_templates(account):
doc = { doc = {
"doctype": "Sales Taxes and Charges Template", "doctype": "Sales Taxes and Charges Template",
"title": account.name, "title": account.name,
"taxes": [{ "taxes": [{
"category": "Valuation and Total", "category": "Valuation and Total",
"charge_type": "On Net Total", "charge_type": "On Net Total",
"account_head": account.name, "account_head": account.name,
"description": "{0} @ {1}".format(account.account_name, account.tax_rate), "description": "{0} @ {1}".format(account.account_name, account.tax_rate),
"rate": account.tax_rate "rate": account.tax_rate
}] }]
} }
# Sales # Sales
frappe.get_doc(copy.deepcopy(doc)).insert() frappe.get_doc(copy.deepcopy(doc)).insert()
# Purchase # Purchase
doc["doctype"] = "Purchase Taxes and Charges Template" doc["doctype"] = "Purchase Taxes and Charges Template"
frappe.get_doc(copy.deepcopy(doc)).insert() frappe.get_doc(copy.deepcopy(doc)).insert()
def create_items(args): def create_items(args):
for i in xrange(1,6): for i in xrange(1,6):
item = args.get("item_" + str(i)) item = args.get("item_" + str(i))
if item: if item:
item_group = args.get("item_group_" + str(i)) item_group = args.get("item_group_" + str(i))
is_sales_item = args.get("is_sales_item_" + str(i)) is_sales_item = args.get("is_sales_item_" + str(i))
is_purchase_item = args.get("is_purchase_item_" + str(i)) is_purchase_item = args.get("is_purchase_item_" + str(i))
is_stock_item = item_group!=_("Services") is_stock_item = item_group!=_("Services")
default_warehouse = "" default_warehouse = ""
if is_stock_item: if is_stock_item:
default_warehouse = frappe.db.get_value("Warehouse", filters={ default_warehouse = frappe.db.get_value("Warehouse", filters={
"warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"), "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"),
"company": args.get("company_name").strip() "company": args.get("company_name").strip()
}) })
try: try:
frappe.get_doc({ frappe.get_doc({
"doctype":"Item", "doctype":"Item",
"item_code": item, "item_code": item,
"item_name": item, "item_name": item,
"description": item, "description": item,
"show_in_website": 1, "show_in_website": 1,
"is_sales_item": is_sales_item, "is_sales_item": is_sales_item,
"is_purchase_item": is_purchase_item, "is_purchase_item": is_purchase_item,
"is_stock_item": is_stock_item and 1 or 0, "is_stock_item": is_stock_item and 1 or 0,
"item_group": item_group, "item_group": item_group,
"stock_uom": args.get("item_uom_" + str(i)), "stock_uom": args.get("item_uom_" + str(i)),
"default_warehouse": default_warehouse "default_warehouse": default_warehouse
}).insert() }).insert()
if args.get("item_img_" + str(i)): if args.get("item_img_" + str(i)):
item_image = args.get("item_img_" + str(i)).split(",") item_image = args.get("item_img_" + str(i)).split(",")
if len(item_image)==3: if len(item_image)==3:
filename, filetype, content = item_image filename, filetype, content = item_image
fileurl = save_file(filename, content, "Item", item, decode=True).file_url fileurl = save_file(filename, content, "Item", item, decode=True).file_url
frappe.db.set_value("Item", item, "image", fileurl) frappe.db.set_value("Item", item, "image", fileurl)
if args.get("item_price_" + str(i)): if args.get("item_price_" + str(i)):
item_price = flt(args.get("item_price_" + str(i))) item_price = flt(args.get("item_price_" + str(i)))
if is_sales_item: if is_sales_item:
price_list_name = frappe.db.get_value("Price List", {"selling": 1}) price_list_name = frappe.db.get_value("Price List", {"selling": 1})
make_item_price(item, price_list_name, item_price) make_item_price(item, price_list_name, item_price)
if is_purchase_item: if is_purchase_item:
price_list_name = frappe.db.get_value("Price List", {"buying": 1}) price_list_name = frappe.db.get_value("Price List", {"buying": 1})
make_item_price(item, price_list_name, item_price) make_item_price(item, price_list_name, item_price)
except frappe.NameError: except frappe.NameError:
pass pass
def make_item_price(item, price_list_name, item_price): def make_item_price(item, price_list_name, item_price):
frappe.get_doc({ frappe.get_doc({
"doctype": "Item Price", "doctype": "Item Price",
"price_list": price_list_name, "price_list": price_list_name,
"item_code": item, "item_code": item,
"price_list_rate": item_price "price_list_rate": item_price
}).insert() }).insert()
def create_customers(args): def create_customers(args):
for i in xrange(1,6): for i in xrange(1,6):
customer = args.get("customer_" + str(i)) customer = args.get("customer_" + str(i))
if customer: if customer:
try: try:
doc = frappe.get_doc({ doc = frappe.get_doc({
"doctype":"Customer", "doctype":"Customer",
"customer_name": customer, "customer_name": customer,
"customer_type": "Company", "customer_type": "Company",
"customer_group": _("Commercial"), "customer_group": _("Commercial"),
"territory": args.get("country"), "territory": args.get("country"),
"company": args.get("company_name").strip() "company": args.get("company_name").strip()
}).insert() }).insert()
if args.get("customer_contact_" + str(i)): if args.get("customer_contact_" + str(i)):
create_contact(args.get("customer_contact_" + str(i)), create_contact(args.get("customer_contact_" + str(i)),
"customer", doc.name) "customer", doc.name)
except frappe.NameError: except frappe.NameError:
pass pass
def create_suppliers(args): def create_suppliers(args):
for i in xrange(1,6): for i in xrange(1,6):
supplier = args.get("supplier_" + str(i)) supplier = args.get("supplier_" + str(i))
if supplier: if supplier:
try: try:
doc = frappe.get_doc({ doc = frappe.get_doc({
"doctype":"Supplier", "doctype":"Supplier",
"supplier_name": supplier, "supplier_name": supplier,
"supplier_type": _("Local"), "supplier_type": _("Local"),
"company": args.get("company_name").strip() "company": args.get("company_name").strip()
}).insert() }).insert()
if args.get("supplier_contact_" + str(i)): if args.get("supplier_contact_" + str(i)):
create_contact(args.get("supplier_contact_" + str(i)), create_contact(args.get("supplier_contact_" + str(i)),
"supplier", doc.name) "supplier", doc.name)
except frappe.NameError: except frappe.NameError:
pass pass
def create_contact(contact, party_type, party): def create_contact(contact, party_type, party):
"""Create contact based on given contact name""" """Create contact based on given contact name"""
contact = contact.strip().split(" ") contact = contact.strip().split(" ")
frappe.get_doc({ frappe.get_doc({
"doctype":"Contact", "doctype":"Contact",
party_type: party, party_type: party,
"first_name":contact[0], "first_name":contact[0],
"last_name": len(contact) > 1 and contact[1] or "" "last_name": len(contact) > 1 and contact[1] or ""
}).insert() }).insert()
def create_letter_head(args): def create_letter_head(args):
if args.get("attach_letterhead"): if args.get("attach_letterhead"):
frappe.get_doc({ frappe.get_doc({
"doctype":"Letter Head", "doctype":"Letter Head",
"letter_head_name": _("Standard"), "letter_head_name": _("Standard"),
"is_default": 1 "is_default": 1
}).insert() }).insert()
attach_letterhead = args.get("attach_letterhead").split(",") attach_letterhead = args.get("attach_letterhead").split(",")
if len(attach_letterhead)==3: if len(attach_letterhead)==3:
filename, filetype, content = attach_letterhead filename, filetype, content = attach_letterhead
fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url
frappe.db.set_value("Letter Head", _("Standard"), "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl) frappe.db.set_value("Letter Head", _("Standard"), "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
def create_logo(args): def create_logo(args):
if args.get("attach_logo"): if args.get("attach_logo"):
attach_logo = args.get("attach_logo").split(",") attach_logo = args.get("attach_logo").split(",")
if len(attach_logo)==3: if len(attach_logo)==3:
filename, filetype, content = attach_logo filename, filetype, content = attach_logo
fileurl = save_file(filename, content, "Website Settings", "Website Settings", fileurl = save_file(filename, content, "Website Settings", "Website Settings",
decode=True).file_url decode=True).file_url
frappe.db.set_value("Website Settings", "Website Settings", "brand_html", frappe.db.set_value("Website Settings", "Website Settings", "brand_html",
"<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name").strip())) "<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name").strip()))
def create_territories(): def create_territories():
"""create two default territories, one for home country and one named Rest of the World""" """create two default territories, one for home country and one named Rest of the World"""
from frappe.utils.nestedset import get_root_of from frappe.utils.nestedset import get_root_of
country = frappe.db.get_default("country") country = frappe.db.get_default("country")
root_territory = get_root_of("Territory") root_territory = get_root_of("Territory")
for name in (country, _("Rest Of The World")): for name in (country, _("Rest Of The World")):
if name and not frappe.db.exists("Territory", name): if name and not frappe.db.exists("Territory", name):
frappe.get_doc({ frappe.get_doc({
"doctype": "Territory", "doctype": "Territory",
"territory_name": name.replace("'", ""), "territory_name": name.replace("'", ""),
"parent_territory": root_territory, "parent_territory": root_territory,
"is_group": "No" "is_group": "No"
}).insert() }).insert()
def login_as_first_user(args): def login_as_first_user(args):
if args.get("email") and hasattr(frappe.local, "login_manager"): if args.get("email") and hasattr(frappe.local, "login_manager"):
frappe.local.login_manager.login_as(args.get("email")) frappe.local.login_manager.login_as(args.get("email"))
def create_users(args): def create_users(args):
if frappe.session.user == 'Administrator': if frappe.session.user == 'Administrator':
return return
# create employee for self # create employee for self
emp = frappe.get_doc({ emp = frappe.get_doc({
"doctype": "Employee", "doctype": "Employee",
"employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])), "employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])),
"user_id": frappe.session.user, "user_id": frappe.session.user,
"status": "Active", "status": "Active",
"company": args.get("company_name") "company": args.get("company_name")
}) })
emp.flags.ignore_mandatory = True emp.flags.ignore_mandatory = True
emp.insert(ignore_permissions = True) emp.insert(ignore_permissions = True)
for i in xrange(1,5): for i in xrange(1,5):
email = args.get("user_email_" + str(i)) email = args.get("user_email_" + str(i))
fullname = args.get("user_fullname_" + str(i)) fullname = args.get("user_fullname_" + str(i))
if email: if email:
if not fullname: if not fullname:
fullname = email.split("@")[0] fullname = email.split("@")[0]
parts = fullname.split(" ", 1) parts = fullname.split(" ", 1)
user = frappe.get_doc({ user = frappe.get_doc({
"doctype": "User", "doctype": "User",
"email": email, "email": email,
"first_name": parts[0], "first_name": parts[0],
"last_name": parts[1] if len(parts) > 1 else "", "last_name": parts[1] if len(parts) > 1 else "",
"enabled": 1, "enabled": 1,
"user_type": "System User" "user_type": "System User"
}) })
# default roles # default roles
user.append_roles("Projects User", "Stock User", "Support Team") user.append_roles("Projects User", "Stock User", "Support Team")
if args.get("user_sales_" + str(i)): if args.get("user_sales_" + str(i)):
user.append_roles("Sales User", "Sales Manager", "Accounts User") user.append_roles("Sales User", "Sales Manager", "Accounts User")
if args.get("user_purchaser_" + str(i)): if args.get("user_purchaser_" + str(i)):
user.append_roles("Purchase User", "Purchase Manager", "Accounts User") user.append_roles("Purchase User", "Purchase Manager", "Accounts User")
if args.get("user_accountant_" + str(i)): if args.get("user_accountant_" + str(i)):
user.append_roles("Accounts Manager", "Accounts User") user.append_roles("Accounts Manager", "Accounts User")
user.flags.delay_emails = True user.flags.delay_emails = True
if not frappe.db.get_value("User", email): if not frappe.db.get_value("User", email):
user.insert(ignore_permissions=True) user.insert(ignore_permissions=True)
# create employee # create employee
emp = frappe.get_doc({ emp = frappe.get_doc({
"doctype": "Employee", "doctype": "Employee",
"employee_name": fullname, "employee_name": fullname,
"user_id": email, "user_id": email,
"status": "Active", "status": "Active",
"company": args.get("company_name") "company": args.get("company_name")
}) })
emp.flags.ignore_mandatory = True emp.flags.ignore_mandatory = True
emp.insert(ignore_permissions = True) emp.insert(ignore_permissions = True)
def create_academic_term(): def create_academic_term():
at = ["Semester 1", "Semester 2", "Semester 3"] at = ["Semester 1", "Semester 2", "Semester 3"]
for d in at: ay = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
academic_term = frappe.new_doc("Academic Term") for y in ay:
academic_term.term_name = d for t in at:
academic_term.save() academic_term = frappe.new_doc("Academic Term")
academic_term.academic_year = y
academic_term.term_name = t
academic_term.save()
def create_academic_year(): def create_academic_year():
ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"] ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
for d in ac: for d in ac:
academic_year = frappe.new_doc("Academic Year") academic_year = frappe.new_doc("Academic Year")
academic_year.academic_year_name = d academic_year.academic_year_name = d
academic_year.save() academic_year.save()
def create_program(args): def create_program(args):
for i in xrange(1,6): for i in xrange(1,6):
if args.get("program_" + str(i)): if args.get("program_" + str(i)):
program = frappe.new_doc("Program") program = frappe.new_doc("Program")
program.program_name = args.get("program_" + str(i)) program.program_name = args.get("program_" + str(i))
program.save() program.save()
def create_course(args): def create_course(args):
for i in xrange(1,6): for i in xrange(1,6):
if args.get("course_" + str(i)): if args.get("course_" + str(i)):
course = frappe.new_doc("Course") course = frappe.new_doc("Course")
course.course_name = args.get("course_" + str(i)) course.course_name = args.get("course_" + str(i))
course.save() course.save()
def create_instructor(args): def create_instructor(args):
for i in xrange(1,6): for i in xrange(1,6):
if args.get("instructor_" + str(i)): if args.get("instructor_" + str(i)):
instructor = frappe.new_doc("Instructor") instructor = frappe.new_doc("Instructor")
instructor.instructor_name = args.get("instructor_" + str(i)) instructor.instructor_name = args.get("instructor_" + str(i))
instructor.save() instructor.save()
def create_room(args): def create_room(args):
for i in xrange(1,6): for i in xrange(1,6):
if args.get("room_" + str(i)): if args.get("room_" + str(i)):
room = frappe.new_doc("Room") room = frappe.new_doc("Room")
room.room_name = args.get("room_" + str(i)) room.room_name = args.get("room_" + str(i))
room.seating_capacity = args.get("room_capacity_" + str(i)) room.seating_capacity = args.get("room_capacity_" + str(i))
room.save() room.save()

1
patches.txt Normal file
View File

@ -0,0 +1 @@
bench.patches.v3.deprecate_old_config