@@ -0,0 +1,74 @@ | |||
[flake8] | |||
ignore = | |||
B001, | |||
B007, | |||
B009, | |||
B010, | |||
B950, | |||
E101, | |||
E111, | |||
E114, | |||
E116, | |||
E117, | |||
E121, | |||
E122, | |||
E123, | |||
E124, | |||
E125, | |||
E126, | |||
E127, | |||
E128, | |||
E131, | |||
E201, | |||
E202, | |||
E203, | |||
E211, | |||
E221, | |||
E222, | |||
E223, | |||
E224, | |||
E225, | |||
E226, | |||
E228, | |||
E231, | |||
E241, | |||
E242, | |||
E251, | |||
E261, | |||
E262, | |||
E265, | |||
E266, | |||
E271, | |||
E272, | |||
E273, | |||
E274, | |||
E301, | |||
E302, | |||
E303, | |||
E305, | |||
E306, | |||
E402, | |||
E501, | |||
E502, | |||
E701, | |||
E702, | |||
E703, | |||
E741, | |||
F401, | |||
F403, | |||
F405, | |||
W191, | |||
W291, | |||
W292, | |||
W293, | |||
W391, | |||
W503, | |||
W504, | |||
E711, | |||
E129, | |||
F841, | |||
E713, | |||
E712, | |||
max-line-length = 200 |
@@ -0,0 +1,8 @@ | |||
.DS_Store | |||
*.pyc | |||
*.egg-info | |||
*.swp | |||
tags | |||
education/docs/current | |||
dist/ | |||
__pycache__/ |
@@ -0,0 +1,8 @@ | |||
# Default ignored files | |||
/shelf/ | |||
/workspace.xml | |||
# Editor-based HTTP Client requests | |||
/httpRequests/ | |||
# Datasource local storage ignored files | |||
/dataSources/ | |||
/dataSources.local.xml |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<module type="WEB_MODULE" version="4"> | |||
<component name="NewModuleRootManager"> | |||
<content url="file://$MODULE_DIR$" /> | |||
<orderEntry type="inheritedJdk" /> | |||
<orderEntry type="sourceFolder" forTests="false" /> | |||
</component> | |||
</module> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="ProjectModuleManager"> | |||
<modules> | |||
<module fileurl="file://$PROJECT_DIR$/.idea/education.iml" filepath="$PROJECT_DIR$/.idea/education.iml" /> | |||
</modules> | |||
</component> | |||
</project> |
@@ -0,0 +1,19 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="MessDetectorOptionsConfiguration"> | |||
<option name="transferred" value="true" /> | |||
</component> | |||
<component name="PHPCSFixerOptionsConfiguration"> | |||
<option name="transferred" value="true" /> | |||
</component> | |||
<component name="PHPCodeSnifferOptionsConfiguration"> | |||
<option name="highlightLevel" value="WARNING" /> | |||
<option name="transferred" value="true" /> | |||
</component> | |||
<component name="PhpStanOptionsConfiguration"> | |||
<option name="transferred" value="true" /> | |||
</component> | |||
<component name="PsalmOptionsConfiguration"> | |||
<option name="transferred" value="true" /> | |||
</component> | |||
</project> |
@@ -0,0 +1,6 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="VcsDirectoryMappings"> | |||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> | |||
</component> | |||
</project> |
@@ -0,0 +1,35 @@ | |||
exclude: 'node_modules|.git' | |||
default_stages: [commit] | |||
fail_fast: false | |||
repos: | |||
- repo: https://github.com/pre-commit/pre-commit-hooks | |||
rev: v4.0.1 | |||
hooks: | |||
- id: trailing-whitespace | |||
files: "education.*" | |||
exclude: ".*json$|.*txt$|.*csv|.*md|.*svg" | |||
- id: check-yaml | |||
- id: no-commit-to-branch | |||
args: ['--branch', 'develop'] | |||
- id: check-merge-conflict | |||
- id: check-ast | |||
- repo: https://github.com/adityahase/black | |||
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119 | |||
hooks: | |||
- id: black | |||
additional_dependencies: ['click==8.0.4'] | |||
- repo: https://github.com/PyCQA/flake8 | |||
rev: 5.0.4 | |||
hooks: | |||
- id: flake8 | |||
additional_dependencies: ["flake8-bugbear"] | |||
args: ["--config", ".github/helper/flake8.conf"] | |||
ci: | |||
autoupdate_schedule: weekly | |||
skip: [] | |||
submodules: false |
@@ -0,0 +1,18 @@ | |||
include MANIFEST.in | |||
include requirements.txt | |||
include *.json | |||
include *.md | |||
include *.py | |||
include *.txt | |||
recursive-include education *.css | |||
recursive-include education *.csv | |||
recursive-include education *.html | |||
recursive-include education *.ico | |||
recursive-include education *.js | |||
recursive-include education *.json | |||
recursive-include education *.md | |||
recursive-include education *.png | |||
recursive-include education *.py | |||
recursive-include education *.svg | |||
recursive-include education *.txt | |||
recursive-exclude education *.pyc |
@@ -0,0 +1,81 @@ | |||
<p align="center"> | |||
<img src="https://github-production-user-asset-6210df.s3.amazonaws.com/65544983/284810651-4625cf57-077d-4a79-b47f-9b989e27e41b.png" alt="XhiveFramework Education Logo" width="220px" height="30px"> | |||
<p align="center">Open Source, Easy to Use, Education management system.</p> | |||
</p> | |||
<p align="center"> | |||
<a href="https://docs.xhiveerp.com/docs/v14/user/manual/en/education"> | |||
Documentation | |||
</a> | |||
</p> | |||
XhiveFramework Education is an open-source and user-friendly Education Management System designed to streamline the administrative and academic processes of educational institutions. It is a powerful module based on the XhiveERP software. | |||
XhiveFramework Education is dedicated to making education management more efficient and less time-consuming. The module offers a range of features that cater to the needs of educators and administrators, facilitating a more organized and effective learning environment. | |||
<img width="1200" alt="Screenshot 2023-11-22 at 11 42 46 AM" src="https://github.com/xhiveframework/education/assets/65544983/11524744-de95-4b4a-8cb9-55479ae7aa60"> | |||
## Table of Contents | |||
- [Key Features](#key-features) | |||
- [Installation](#installation) | |||
- [Deployment](#deployment) | |||
- [Contribution & Community](#contributions--community) | |||
- [Links](#links) | |||
- [License](#license) | |||
## Key Features | |||
Here are some of the standout features of the XhiveFramework Education module: | |||
- **Student Admission**: Streamline the admission process for new students. 🎓 | |||
- **Program Enrollment**: Manage and keep track of student enrollments in various programs. 📋 | |||
- **Guardian, Student & Sibling Management**: Maintain comprehensive profiles for students, guardians, and siblings. 👨👩👧👦 | |||
- **Fee Structure and Scheduling**: Organize and manage the fee structure and schedule payments. 💰 | |||
- **Course Scheduling**: Efficiently schedule courses and manage course calendars. 🗓️ | |||
- **Attendance Management**: Track and manage student attendance records. ✔️ | |||
- **Assessment Planning & Results**: Plan assessments and manage results effectively. 📝 | |||
- **Reports**: Generate various reports including final grades, course-wise assessment, student absent report, attendance report, and fee collection. 📊 | |||
## Installation | |||
1. [Install bench on your local machine](https://github.com/xhiveframework/bench#installation) | |||
2. [Install XhiveERP](https://github.com/xhiveframework/xhiveerp#installation) | |||
3. Once XhiveERP is installed, install the Education App by using: | |||
```jsx | |||
$ bench get-app education | |||
``` | |||
4. After that, you can install the Education app on the required site by running | |||
```jsx | |||
$ bench --site sitename install-app education | |||
``` | |||
## Deployment | |||
XhiveFramework Education is an app built on top of the XhiveFramework Framework & XhiveERP. | |||
**Managed Hosting** | |||
XhiveFramework Education can be deployed in few clicks by using [XhiveFramework Cloud](https://xhiveframeworkcloud.com/marketplace/apps/education). | |||
**Self Hosting** | |||
You can self host the module by following [XhiveFramework Bench Installation Instructions](https://github.com/xhiveframework/bench#installation). | |||
## Contributions & Community | |||
1. If you find any bugs while using the app or have a feature request for the app, you can report/add them here [Github Issues](https://github.com/xhiveframework/education/issues). Make sure to add proper information and screenshots. | |||
2. Follow the [Contribution Guidelines](https://github.com/xhiveframework/xhiveerp/wiki/Issue-Guidelines) & [Issue Guidelines](https://github.com/xhiveframework/xhiveerp/wiki/Issue-Guidelines) - [create an issue](https://github.com/xhiveframework/education/issues/new). | |||
## Links | |||
1. **[Telegram Group](https://t.me/+DcKb53WLxTw2OGM1)** - Join our Telegram group to connect with us where can discuss everything regarding the Education Module. Feel free to share ideas and issues you face while using the Education Module. | |||
2. **[Documentation](https://docs.xhiveerp.com/docs/v14/user/manual/en/education)** - This link will take you to our comprehensive documentation, where you can find all the information you need to understand and use the Education Module effectively. It includes all the workflows, masters and DocTypes which currently Exists | |||
## License | |||
GNU GPL V3. See [license.txt](https://github.com/xhiveframework/agriculture/blob/develop/license.txt) for more information. |
@@ -0,0 +1 @@ | |||
__version__ = "0.0.1" |
@@ -0,0 +1,13 @@ | |||
from xhiveframework import _ | |||
def get_data(): | |||
return [ | |||
{ | |||
"module_name": "Education", | |||
"color": "grey", | |||
"icon": "octicon octicon-file-directory", | |||
"type": "module", | |||
"label": _("Education"), | |||
} | |||
] |
@@ -0,0 +1,11 @@ | |||
""" | |||
Configuration for docs | |||
""" | |||
# source_link = "https://github.com/[org_name]/education" | |||
# headline = "App that does everything" | |||
# sub_heading = "Yes, you got that right the first time, everything" | |||
def get_context(context): | |||
context.brand_html = "Education" |
@@ -0,0 +1,19 @@ | |||
import xhiveframework | |||
from xhiveframework import _ | |||
class StudentNotInGroupError(xhiveframework.ValidationError): | |||
pass | |||
def validate_student_belongs_to_group(student, student_group): | |||
groups = xhiveframework.db.get_all( | |||
"Student Group Student", ["parent"], dict(student=student, active=1) | |||
) | |||
if not student_group in [d.parent for d in groups]: | |||
xhiveframework.throw( | |||
_("Student {0} does not belong to group {1}").format( | |||
xhiveframework.bold(student), xhiveframework.bold(student_group) | |||
), | |||
StudentNotInGroupError, | |||
) |
@@ -0,0 +1,498 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import json | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.email.doctype.email_group.email_group import add_subscribers | |||
from xhiveframework.model.mapper import get_mapped_doc | |||
from xhiveframework.utils import cstr, flt, getdate | |||
def get_course(program): | |||
"""Return list of courses for a particular program | |||
:param program: Program | |||
""" | |||
courses = xhiveframework.db.sql( | |||
"""select course, course_name from `tabProgram Course` where parent=%s""", | |||
(program), | |||
as_dict=1, | |||
) | |||
return courses | |||
@xhiveframework.whitelist() | |||
def enroll_student(source_name): | |||
"""Creates a Student Record and returns a Program Enrollment. | |||
:param source_name: Student Applicant. | |||
""" | |||
xhiveframework.publish_realtime( | |||
"enroll_student_progress", {"progress": [1, 4]}, user=xhiveframework.session.user | |||
) | |||
student = get_mapped_doc( | |||
"Student Applicant", | |||
source_name, | |||
{ | |||
"Student Applicant": { | |||
"doctype": "Student", | |||
"field_map": { | |||
"name": "student_applicant", | |||
}, | |||
} | |||
}, | |||
ignore_permissions=True, | |||
) | |||
student.save() | |||
student_applicant = xhiveframework.db.get_value( | |||
"Student Applicant", | |||
source_name, | |||
["student_category", "program", "academic_year"], | |||
as_dict=True, | |||
) | |||
program_enrollment = xhiveframework.new_doc("Program Enrollment") | |||
program_enrollment.student = student.name | |||
program_enrollment.student_category = student_applicant.student_category | |||
program_enrollment.student_name = student.student_name | |||
program_enrollment.program = student_applicant.program | |||
program_enrollment.academic_year = student_applicant.academic_year | |||
program_enrollment.save() | |||
xhiveframework.publish_realtime( | |||
"enroll_student_progress", {"progress": [2, 4]}, user=xhiveframework.session.user | |||
) | |||
return program_enrollment | |||
@xhiveframework.whitelist() | |||
def check_attendance_records_exist(course_schedule=None, student_group=None, date=None): | |||
"""Check if Attendance Records are made against the specified Course Schedule or Student Group for given date. | |||
:param course_schedule: Course Schedule. | |||
:param student_group: Student Group. | |||
:param date: Date. | |||
""" | |||
if course_schedule: | |||
return xhiveframework.get_list( | |||
"Student Attendance", filters={"course_schedule": course_schedule} | |||
) | |||
else: | |||
return xhiveframework.get_list( | |||
"Student Attendance", filters={"student_group": student_group, "date": date} | |||
) | |||
@xhiveframework.whitelist() | |||
def mark_attendance( | |||
students_present, students_absent, course_schedule=None, student_group=None, date=None | |||
): | |||
"""Creates Multiple Attendance Records. | |||
:param students_present: Students Present JSON. | |||
:param students_absent: Students Absent JSON. | |||
:param course_schedule: Course Schedule. | |||
:param student_group: Student Group. | |||
:param date: Date. | |||
""" | |||
if student_group: | |||
academic_year = xhiveframework.db.get_value("Student Group", student_group, "academic_year") | |||
if academic_year: | |||
year_start_date, year_end_date = xhiveframework.db.get_value( | |||
"Academic Year", academic_year, ["year_start_date", "year_end_date"] | |||
) | |||
if getdate(date) < getdate(year_start_date) or getdate(date) > getdate( | |||
year_end_date | |||
): | |||
xhiveframework.throw( | |||
_("Attendance cannot be marked outside of Academic Year {0}").format(academic_year) | |||
) | |||
present = json.loads(students_present) | |||
absent = json.loads(students_absent) | |||
for d in present: | |||
make_attendance_records( | |||
d["student"], d["student_name"], "Present", course_schedule, student_group, date | |||
) | |||
for d in absent: | |||
make_attendance_records( | |||
d["student"], d["student_name"], "Absent", course_schedule, student_group, date | |||
) | |||
xhiveframework.db.commit() | |||
xhiveframework.msgprint(_("Attendance has been marked successfully.")) | |||
def make_attendance_records( | |||
student, student_name, status, course_schedule=None, student_group=None, date=None | |||
): | |||
"""Creates/Update Attendance Record. | |||
:param student: Student. | |||
:param student_name: Student Name. | |||
:param course_schedule: Course Schedule. | |||
:param status: Status (Present/Absent) | |||
""" | |||
student_attendance = xhiveframework.get_doc( | |||
{ | |||
"doctype": "Student Attendance", | |||
"student": student, | |||
"course_schedule": course_schedule, | |||
"student_group": student_group, | |||
"date": date, | |||
} | |||
) | |||
if not student_attendance: | |||
student_attendance = xhiveframework.new_doc("Student Attendance") | |||
student_attendance.student = student | |||
student_attendance.student_name = student_name | |||
student_attendance.course_schedule = course_schedule | |||
student_attendance.student_group = student_group | |||
student_attendance.date = date | |||
student_attendance.status = status | |||
student_attendance.save() | |||
student_attendance.submit() | |||
@xhiveframework.whitelist() | |||
def get_student_guardians(student): | |||
"""Returns List of Guardians of a Student. | |||
:param student: Student. | |||
""" | |||
guardians = xhiveframework.get_all( | |||
"Student Guardian", fields=["guardian"], filters={"parent": student} | |||
) | |||
return guardians | |||
@xhiveframework.whitelist() | |||
def get_student_group_students(student_group, include_inactive=0): | |||
"""Returns List of student, student_name in Student Group. | |||
:param student_group: Student Group. | |||
""" | |||
if include_inactive: | |||
students = xhiveframework.get_all( | |||
"Student Group Student", | |||
fields=["student", "student_name"], | |||
filters={"parent": student_group}, | |||
order_by="group_roll_number", | |||
) | |||
else: | |||
students = xhiveframework.get_all( | |||
"Student Group Student", | |||
fields=["student", "student_name"], | |||
filters={"parent": student_group, "active": 1}, | |||
order_by="group_roll_number", | |||
) | |||
return students | |||
@xhiveframework.whitelist() | |||
def get_fee_structure(program, academic_term=None): | |||
"""Returns Fee Structure. | |||
:param program: Program. | |||
:param academic_term: Academic Term. | |||
""" | |||
fee_structure = xhiveframework.db.get_values( | |||
"Fee Structure", | |||
{"program": program, "academic_term": academic_term}, | |||
"name", | |||
as_dict=True, | |||
) | |||
return fee_structure[0].name if fee_structure else None | |||
@xhiveframework.whitelist() | |||
def get_fee_components(fee_structure): | |||
"""Returns Fee Components. | |||
:param fee_structure: Fee Structure. | |||
""" | |||
if fee_structure: | |||
fs = xhiveframework.get_all( | |||
"Fee Component", | |||
fields=["fees_category", "description", "amount"], | |||
filters={"parent": fee_structure}, | |||
order_by="idx", | |||
) | |||
return fs | |||
@xhiveframework.whitelist() | |||
def get_fee_schedule(program, student_category=None): | |||
"""Returns Fee Schedule. | |||
:param program: Program. | |||
:param student_category: Student Category | |||
""" | |||
fs = xhiveframework.get_all( | |||
"Program Fee", | |||
fields=["academic_term", "fee_structure", "due_date", "amount"], | |||
filters={"parent": program, "student_category": student_category}, | |||
order_by="idx", | |||
) | |||
return fs | |||
@xhiveframework.whitelist() | |||
def collect_fees(fees, amt): | |||
paid_amount = flt(amt) + flt(xhiveframework.db.get_value("Fees", fees, "paid_amount")) | |||
total_amount = flt(xhiveframework.db.get_value("Fees", fees, "total_amount")) | |||
xhiveframework.db.set_value("Fees", fees, "paid_amount", paid_amount) | |||
xhiveframework.db.set_value("Fees", fees, "outstanding_amount", (total_amount - paid_amount)) | |||
return paid_amount | |||
@xhiveframework.whitelist() | |||
def get_course_schedule_events(start, end, filters=None): | |||
"""Returns events for Course Schedule Calendar view rendering. | |||
:param start: Start date-time. | |||
:param end: End date-time. | |||
:param filters: Filters (JSON). | |||
""" | |||
from xhiveframework.desk.calendar import get_event_conditions | |||
conditions = get_event_conditions("Course Schedule", filters) | |||
data = xhiveframework.db.sql( | |||
"""select name, course, color, | |||
timestamp(schedule_date, from_time) as from_time, | |||
timestamp(schedule_date, to_time) as to_time, | |||
room, student_group, 0 as 'allDay' | |||
from `tabCourse Schedule` | |||
where ( schedule_date between %(start)s and %(end)s ) | |||
{conditions}""".format( | |||
conditions=conditions | |||
), | |||
{"start": start, "end": end}, | |||
as_dict=True, | |||
update={"allDay": 0}, | |||
) | |||
return data | |||
@xhiveframework.whitelist() | |||
def get_assessment_criteria(course): | |||
"""Returns Assessmemt Criteria and their Weightage from Course Master. | |||
:param Course: Course | |||
""" | |||
return xhiveframework.get_all( | |||
"Course Assessment Criteria", | |||
fields=["assessment_criteria", "weightage"], | |||
filters={"parent": course}, | |||
order_by="idx", | |||
) | |||
@xhiveframework.whitelist() | |||
def get_assessment_students(assessment_plan, student_group): | |||
student_list = get_student_group_students(student_group) | |||
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.assessment_criteria: [cstr(d.score), d.grade]}) | |||
student_result.update( | |||
{"total_score": [cstr(result.total_score), result.grade], "comment": result.comment} | |||
) | |||
student.update( | |||
{ | |||
"assessment_details": student_result, | |||
"docstatus": result.docstatus, | |||
"name": result.name, | |||
} | |||
) | |||
else: | |||
student.update({"assessment_details": None}) | |||
return student_list | |||
@xhiveframework.whitelist() | |||
def get_assessment_details(assessment_plan): | |||
"""Returns Assessment Criteria and Maximum Score from Assessment Plan Master. | |||
:param Assessment Plan: Assessment Plan | |||
""" | |||
return xhiveframework.get_all( | |||
"Assessment Plan Criteria", | |||
fields=["assessment_criteria", "maximum_score", "docstatus"], | |||
filters={"parent": assessment_plan}, | |||
order_by="idx", | |||
) | |||
@xhiveframework.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 = xhiveframework.get_all( | |||
"Assessment Result", | |||
filters={ | |||
"student": student, | |||
"assessment_plan": assessment_plan, | |||
"docstatus": ("!=", 2), | |||
}, | |||
) | |||
if results: | |||
return xhiveframework.get_doc("Assessment Result", results[0]) | |||
else: | |||
return None | |||
@xhiveframework.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 = {} | |||
if not hasattr(xhiveframework.local, "grading_scale"): | |||
grading_scale = xhiveframework.get_all( | |||
"Grading Scale Interval", | |||
fields=["grade_code", "threshold"], | |||
filters={"parent": grading_scale}, | |||
) | |||
xhiveframework.local.grading_scale = grading_scale | |||
for d in xhiveframework.local.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 | |||
@xhiveframework.whitelist() | |||
def mark_assessment_result(assessment_plan, scores): | |||
student_score = json.loads(scores) | |||
assessment_details = [] | |||
for criteria in student_score.get("assessment_details"): | |||
assessment_details.append( | |||
{ | |||
"assessment_criteria": criteria, | |||
"score": flt(student_score["assessment_details"][criteria]), | |||
} | |||
) | |||
assessment_result = get_assessment_result_doc( | |||
student_score["student"], assessment_plan | |||
) | |||
assessment_result.update( | |||
{ | |||
"student": student_score.get("student"), | |||
"assessment_plan": assessment_plan, | |||
"comment": student_score.get("comment"), | |||
"total_score": student_score.get("total_score"), | |||
"details": assessment_details, | |||
} | |||
) | |||
assessment_result.save() | |||
details = {} | |||
for d in assessment_result.details: | |||
details.update({d.assessment_criteria: d.grade}) | |||
assessment_result_dict = { | |||
"name": assessment_result.name, | |||
"student": assessment_result.student, | |||
"total_score": assessment_result.total_score, | |||
"grade": assessment_result.grade, | |||
"details": details, | |||
} | |||
return assessment_result_dict | |||
@xhiveframework.whitelist() | |||
def submit_assessment_results(assessment_plan, student_group): | |||
total_result = 0 | |||
student_list = get_student_group_students(student_group) | |||
for i, student in enumerate(student_list): | |||
doc = get_result(student.student, assessment_plan) | |||
if doc and doc.docstatus == 0: | |||
total_result += 1 | |||
doc.submit() | |||
return total_result | |||
def get_assessment_result_doc(student, assessment_plan): | |||
assessment_result = xhiveframework.get_all( | |||
"Assessment Result", | |||
filters={ | |||
"student": student, | |||
"assessment_plan": assessment_plan, | |||
"docstatus": ("!=", 2), | |||
}, | |||
) | |||
if assessment_result: | |||
doc = xhiveframework.get_doc("Assessment Result", assessment_result[0]) | |||
if doc.docstatus == 0: | |||
return doc | |||
elif doc.docstatus == 1: | |||
xhiveframework.msgprint(_("Result already Submitted")) | |||
return None | |||
else: | |||
return xhiveframework.new_doc("Assessment Result") | |||
@xhiveframework.whitelist() | |||
def update_email_group(doctype, name): | |||
if not xhiveframework.db.exists("Email Group", name): | |||
email_group = xhiveframework.new_doc("Email Group") | |||
email_group.title = name | |||
email_group.save() | |||
email_list = [] | |||
students = [] | |||
if doctype == "Student Group": | |||
students = get_student_group_students(name) | |||
for stud in students: | |||
for guard in get_student_guardians(stud.student): | |||
email = xhiveframework.db.get_value("Guardian", guard.guardian, "email_address") | |||
if email: | |||
email_list.append(email) | |||
add_subscribers(name, email_list) | |||
@xhiveframework.whitelist() | |||
def get_current_enrollment(student, academic_year=None): | |||
current_academic_year = academic_year or xhiveframework.defaults.get_defaults().academic_year | |||
program_enrollment_list = xhiveframework.db.sql( | |||
""" | |||
select | |||
name as program_enrollment, student_name, program, student_batch_name as student_batch, | |||
student_category, academic_term, academic_year | |||
from | |||
`tabProgram Enrollment` | |||
where | |||
student = %s and academic_year = %s | |||
order by creation""", | |||
(student, current_academic_year), | |||
as_dict=1, | |||
) | |||
if program_enrollment_list: | |||
return program_enrollment_list[0] | |||
else: | |||
return None | |||
@xhiveframework.whitelist() | |||
def get_instructors(student_group): | |||
return xhiveframework.get_all( | |||
"Student Group Instructor", {"parent": student_group}, pluck="instructor" | |||
) |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Academic Term', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,94 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
"autoname": "field:title", | |||
"creation": "2015-09-08 17:19:19.158228", | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"academic_year", | |||
"term_name", | |||
"column_break_jhzu", | |||
"term_start_date", | |||
"term_end_date", | |||
"title", | |||
"connections_tab" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "academic_year", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Academic Year", | |||
"options": "Academic Year", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "term_name", | |||
"fieldtype": "Data", | |||
"label": "Term Name", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "term_start_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Term Start Date", | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"fieldname": "term_end_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Term End Date", | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
"label": "Title", | |||
"unique": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_jhzu", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "connections_tab", | |||
"fieldtype": "Tab Break", | |||
"label": "Connections", | |||
"show_dashboard": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2023-02-14 13:13:40.419268", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Academic Term", | |||
"naming_rule": "By fieldname", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"sort_field": "name", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"title_field": "title" | |||
} |
@@ -0,0 +1,83 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
from xhiveframework.utils import getdate | |||
class AcademicTerm(Document): | |||
def autoname(self): | |||
self.name = ( | |||
self.academic_year + " ({})".format(self.term_name) if self.term_name else "" | |||
) | |||
def validate(self): | |||
self.set_title() | |||
self.validate_duplication() | |||
self.validate_dates() | |||
self.validate_term_against_year() | |||
def set_title(self): | |||
self.title = ( | |||
self.academic_year + " ({})".format(self.term_name) if self.term_name else "" | |||
) | |||
def validate_duplication(self): | |||
# Check if entry with same academic_year and the term_name already exists | |||
term = xhiveframework.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: | |||
xhiveframework.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) | |||
) | |||
def validate_dates(self): | |||
# Check that start of academic year is earlier than end of academic year | |||
if ( | |||
self.term_start_date | |||
and self.term_end_date | |||
and getdate(self.term_start_date) > getdate(self.term_end_date) | |||
): | |||
xhiveframework.throw( | |||
_( | |||
"The Term End Date cannot be before the Term Start Date. Please correct the dates and try again." | |||
) | |||
) | |||
def validate_term_against_year(self): | |||
# 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 = xhiveframework.db.get_value( | |||
"Academic Year", self.academic_year, ["year_start_date", "year_end_date"], as_dict=1 | |||
) | |||
if ( | |||
self.term_start_date | |||
and getdate(year.year_start_date) | |||
and (getdate(self.term_start_date) < getdate(year.year_start_date)) | |||
): | |||
xhiveframework.throw( | |||
_("The Term cannot start before the Academic Year {0}").format( | |||
xhiveframework.bold(self.academic_year) | |||
) | |||
) | |||
if ( | |||
self.term_end_date | |||
and getdate(year.year_end_date) | |||
and (getdate(self.term_end_date) > getdate(year.year_end_date)) | |||
): | |||
xhiveframework.throw( | |||
_("The Term cannot end after the Academic Year {0}").format( | |||
xhiveframework.bold(self.academic_year) | |||
) | |||
) |
@@ -0,0 +1,16 @@ | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"fieldname": "academic_term", | |||
"transactions": [ | |||
{ | |||
"label": _("Student"), | |||
"items": ["Student Applicant", "Student Group", "Student Log"], | |||
}, | |||
{"label": _("Fee"), "items": ["Fees", "Fee Schedule", "Fee Structure"]}, | |||
{"label": _("Program"), "items": ["Program Enrollment"]}, | |||
{"label": _("Assessment"), "items": ["Assessment Plan", "Assessment Result"]}, | |||
], | |||
} |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
# test_records = xhiveframework.get_test_records('Academic Term') | |||
class TestAcademicTerm(unittest.TestCase): | |||
pass |
@@ -0,0 +1,27 @@ | |||
[ | |||
{ | |||
"doctype": "Academic Term", | |||
"academic_year": "2014-2015", | |||
"term_name": "_Test Academic Term" | |||
}, | |||
{ | |||
"doctype": "Academic Term", | |||
"academic_year": "2014-2015", | |||
"term_name": "_Test Academic Term 1" | |||
}, | |||
{ | |||
"doctype": "Academic Term", | |||
"academic_year": "2014-2015", | |||
"term_name": "_Test Academic Term 2" | |||
}, | |||
{ | |||
"doctype": "Academic Term", | |||
"academic_year": "2017-2018", | |||
"term_name": "_Test AT1" | |||
}, | |||
{ | |||
"doctype": "Academic Term", | |||
"academic_year": "2017-2018", | |||
"term_name": "_Test AT2" | |||
} | |||
] |
@@ -0,0 +1,2 @@ | |||
xhiveframework.ui.form.on("Academic Year", { | |||
}); |
@@ -0,0 +1,70 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"autoname": "field:academic_year_name", | |||
"creation": "2015-09-07 12:49:51.303026", | |||
"doctype": "DocType", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"academic_year_name", | |||
"year_start_date", | |||
"year_end_date", | |||
"connections_tab" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "academic_year_name", | |||
"fieldtype": "Data", | |||
"label": "Academic Year Name", | |||
"reqd": 1, | |||
"unique": 1 | |||
}, | |||
{ | |||
"allow_in_quick_entry": 1, | |||
"fieldname": "year_start_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Year Start Date", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_in_quick_entry": 1, | |||
"fieldname": "year_end_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Year End Date", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "connections_tab", | |||
"fieldtype": "Tab Break", | |||
"label": "Connections", | |||
"show_dashboard": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2023-10-30 16:34:17.354467", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Academic Year", | |||
"naming_rule": "By fieldname", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [] | |||
} |
@@ -0,0 +1,22 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
class AcademicYear(Document): | |||
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 | |||
): | |||
xhiveframework.throw( | |||
_( | |||
"The Year End Date cannot be earlier than the Year Start Date. Please correct the dates and try again." | |||
) | |||
) |
@@ -0,0 +1,19 @@ | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"fieldname": "academic_year", | |||
"transactions": [ | |||
{ | |||
"label": _("Student"), | |||
"items": ["Student Admission", "Student Applicant", "Student Group", "Student Log"], | |||
}, | |||
{"label": _("Fee"), "items": ["Fees", "Fee Schedule", "Fee Structure"]}, | |||
{ | |||
"label": _("Academic Term and Program"), | |||
"items": ["Academic Term", "Program Enrollment"], | |||
}, | |||
{"label": _("Assessment"), "items": ["Assessment Plan", "Assessment Result"]}, | |||
], | |||
} |
@@ -0,0 +1,18 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
import xhiveframework | |||
class TestAcademicYear(unittest.TestCase): | |||
def test_date_validation(self): | |||
year = xhiveframework.get_doc( | |||
{ | |||
"doctype": "Academic Year", | |||
"year_start_date": "13-02-2023", | |||
"year_end_date": "27-01-2023", | |||
} | |||
) | |||
self.assertRaises(xhiveframework.ValidationError, year.insert) |
@@ -0,0 +1,18 @@ | |||
[ | |||
{ | |||
"doctype": "Academic Year", | |||
"academic_year_name": "2014-2015" | |||
}, | |||
{ | |||
"doctype": "Academic Year", | |||
"academic_year_name": "2015-2016" | |||
}, | |||
{ | |||
"doctype": "Academic Year", | |||
"academic_year_name": "2016-2017" | |||
}, | |||
{ | |||
"doctype": "Academic Year", | |||
"academic_year_name": "2017-2018" | |||
} | |||
] |
@@ -0,0 +1,56 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Article', { | |||
refresh: function(frm) { | |||
if (!frm.doc.__islocal) { | |||
frm.add_custom_button(__('Add to Topics'), function() { | |||
frm.trigger('add_article_to_topics'); | |||
}, __('Action')); | |||
} | |||
}, | |||
add_article_to_topics: function(frm) { | |||
get_topics_without_article(frm.doc.name).then(r => { | |||
if (r.message.length) { | |||
xhiveframework.prompt([ | |||
{ | |||
fieldname: 'topics', | |||
label: __('Topics'), | |||
fieldtype: 'MultiSelectPills', | |||
get_data: function() { | |||
return r.message; | |||
} | |||
} | |||
], | |||
function(data) { | |||
xhiveframework.call({ | |||
method: 'education.education.doctype.topic.topic.add_content_to_topics', | |||
args: { | |||
'content_type': 'Article', | |||
'content': frm.doc.name, | |||
'topics': data.topics, | |||
}, | |||
callback: function(r) { | |||
if (!r.exc) { | |||
frm.reload_doc(); | |||
} | |||
}, | |||
freeze: true, | |||
freeze_message: __('...Adding Article to Topics') | |||
}); | |||
}, __('Add Article to Topics'), __('Add')); | |||
} else { | |||
xhiveframework.msgprint(__('This article is already added to the existing topics')); | |||
} | |||
}); | |||
} | |||
}); | |||
let get_topics_without_article = function(article) { | |||
return xhiveframework.call({ | |||
type: 'GET', | |||
method: 'education.education.doctype.article.article.get_topics_without_article', | |||
args: {'article': article} | |||
}); | |||
}; |
@@ -0,0 +1,76 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
"autoname": "field:title", | |||
"creation": "2018-10-17 05:45:38.471670", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"title", | |||
"author", | |||
"content", | |||
"publish_date" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"label": "Title", | |||
"unique": 1 | |||
}, | |||
{ | |||
"fieldname": "author", | |||
"fieldtype": "Data", | |||
"label": "Author" | |||
}, | |||
{ | |||
"fieldname": "content", | |||
"fieldtype": "Text Editor", | |||
"label": "Content" | |||
}, | |||
{ | |||
"fieldname": "publish_date", | |||
"fieldtype": "Date", | |||
"label": "Publish Date" | |||
} | |||
], | |||
"links": [], | |||
"modified": "2023-02-06 12:23:28.330556", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Article", | |||
"naming_rule": "By fieldname", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Instructor", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,22 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework.model.document import Document | |||
class Article(Document): | |||
def get_article(self): | |||
pass | |||
@xhiveframework.whitelist() | |||
def get_topics_without_article(article): | |||
data = [] | |||
for entry in xhiveframework.db.get_all("Topic"): | |||
topic = xhiveframework.get_doc("Topic", entry.name) | |||
topic_contents = [tc.content for tc in topic.topic_content] | |||
if not topic_contents or article not in topic_contents: | |||
data.append(topic.name) | |||
return data |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
class TestArticle(unittest.TestCase): | |||
pass |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Criteria', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,125 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 1, | |||
"allow_rename": 0, | |||
"autoname": "field:assessment_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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Assessment 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 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "assessment_criteria_group", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Assessment Criteria Group", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Assessment Criteria 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 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-11-10 19:08:11.311304", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment 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, | |||
"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, | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,22 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
STD_CRITERIA = [ | |||
"total", | |||
"total score", | |||
"total grade", | |||
"maximum score", | |||
"score", | |||
"grade", | |||
] | |||
class AssessmentCriteria(Document): | |||
def validate(self): | |||
if self.assessment_criteria.lower() in STD_CRITERIA: | |||
xhiveframework.throw(_("Can't create standard criteria. Please rename the criteria")) |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
# test_records = xhiveframework.get_test_records('Assessment Criteria') | |||
class TestAssessmentCriteria(unittest.TestCase): | |||
pass |
@@ -0,0 +1,8 @@ | |||
[ | |||
{ | |||
"assessment_criteria": "_Test Assessment Criteria" | |||
}, | |||
{ | |||
"assessment_criteria": "_Test Assessment Criteria 1" | |||
} | |||
] |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Criteria Group', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,94 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
"autoname": "field:assessment_criteria_group", | |||
"beta": 0, | |||
"creation": "2017-01-27 15:17:38.855910", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "assessment_criteria_group", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Assessment Criteria Group", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-11-10 19:11:45.334917", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Criteria Group", | |||
"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, | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class AssessmentCriteriaGroup(Document): | |||
pass |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
# test_records = xhiveframework.get_test_records('Assessment Criteria Group') | |||
class TestAssessmentCriteriaGroup(unittest.TestCase): | |||
pass |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Group', { | |||
onload: function(frm) { | |||
frm.list_route = "Tree/Assessment Group"; | |||
} | |||
}); |
@@ -0,0 +1,97 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
"autoname": "field:assessment_group_name", | |||
"creation": "2016-08-04 04:42:48.319388", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"assessment_group_name", | |||
"parent_assessment_group", | |||
"is_group", | |||
"section_break_2", | |||
"lft", | |||
"rgt", | |||
"old_parent" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "assessment_group_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Assessment Group Name", | |||
"reqd": 1, | |||
"unique": 1 | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "is_group", | |||
"fieldtype": "Check", | |||
"label": "Is Group" | |||
}, | |||
{ | |||
"fieldname": "section_break_2", | |||
"fieldtype": "Section Break" | |||
}, | |||
{ | |||
"fieldname": "parent_assessment_group", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Parent Assessment Group", | |||
"options": "Assessment Group", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "lft", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
"label": "lft", | |||
"print_hide": 1 | |||
}, | |||
{ | |||
"fieldname": "rgt", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
"label": "rgt", | |||
"print_hide": 1 | |||
}, | |||
{ | |||
"fieldname": "old_parent", | |||
"fieldtype": "Link", | |||
"hidden": 1, | |||
"ignore_user_permissions": 1, | |||
"label": "old_parent", | |||
"options": "Assessment Group", | |||
"print_hide": 1 | |||
} | |||
], | |||
"is_tree": 1, | |||
"links": [], | |||
"modified": "2022-12-01 18:02:17.869988", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Group", | |||
"naming_rule": "By fieldname", | |||
"nsm_parent_field": "parent_assessment_group", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"restrict_to_domain": "", | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [] | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class AssessmentGroup(Document): | |||
pass |
@@ -0,0 +1,13 @@ | |||
# Copyright (c) 2015, Xhive | |||
# License: GNU General Public License v3. See license.txt | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"fieldname": "assessment_group", | |||
"transactions": [ | |||
{"label": _("Assessment"), "items": ["Assessment Plan", "Assessment Result"]} | |||
], | |||
} |
@@ -0,0 +1,3 @@ | |||
xhiveframework.treeview_settings["Assessment Group"] = { | |||
} |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
# test_records = xhiveframework.get_test_records('Assessment Group') | |||
class TestAssessmentGroup(unittest.TestCase): | |||
pass |
@@ -0,0 +1,78 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Plan', { | |||
onload: function(frm) { | |||
frm.set_query('assessment_group', function(doc, cdt, cdn) { | |||
return{ | |||
filters: { | |||
'is_group': 0 | |||
} | |||
}; | |||
}); | |||
frm.set_query('grading_scale', function(){ | |||
return { | |||
filters: { | |||
docstatus: 1 | |||
} | |||
}; | |||
}); | |||
}, | |||
refresh: function(frm) { | |||
if (frm.doc.docstatus == 1) { | |||
frm.add_custom_button(__('Assessment Result Tool'), function() { | |||
xhiveframework.route_options = { | |||
assessment_plan: frm.doc.name, | |||
student_group: frm.doc.student_group | |||
} | |||
xhiveframework.set_route('Form', 'Assessment Result Tool'); | |||
}, __('Tools')); | |||
} | |||
frm.set_query('course', function() { | |||
return { | |||
query: 'education.education.doctype.program_enrollment.program_enrollment.get_program_courses', | |||
filters: { | |||
'program': frm.doc.program | |||
} | |||
}; | |||
}); | |||
frm.set_query('academic_term', function() { | |||
return { | |||
filters: { | |||
'academic_year': frm.doc.academic_year | |||
} | |||
}; | |||
}); | |||
}, | |||
course: function(frm) { | |||
if (frm.doc.course && frm.doc.maximum_assessment_score) { | |||
xhiveframework.call({ | |||
method: 'education.education.api.get_assessment_criteria', | |||
args: { | |||
course: frm.doc.course | |||
}, | |||
callback: function(r) { | |||
if (r.message) { | |||
frm.doc.assessment_criteria = []; | |||
$.each(r.message, function(i, d) { | |||
var row = xhiveframework.model.add_child(frm.doc, 'Assessment Plan Criteria', 'assessment_criteria'); | |||
row.assessment_criteria = d.assessment_criteria; | |||
row.maximum_score = d.weightage / 100 * frm.doc.maximum_assessment_score; | |||
}); | |||
} | |||
refresh_field('assessment_criteria'); | |||
} | |||
}); | |||
} | |||
}, | |||
maximum_assessment_score: function(frm) { | |||
frm.trigger('course'); | |||
} | |||
}); |
@@ -0,0 +1,227 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"autoname": "EDU-ASP-.YYYY.-.#####", | |||
"creation": "2015-11-12 16:34:34.658092", | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"student_group", | |||
"assessment_name", | |||
"assessment_group", | |||
"grading_scale", | |||
"column_break_2", | |||
"program", | |||
"course", | |||
"academic_year", | |||
"academic_term", | |||
"section_break_5", | |||
"schedule_date", | |||
"room", | |||
"examiner", | |||
"examiner_name", | |||
"column_break_4", | |||
"from_time", | |||
"to_time", | |||
"supervisor", | |||
"supervisor_name", | |||
"section_break_20", | |||
"maximum_assessment_score", | |||
"assessment_criteria", | |||
"amended_from" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "student_group", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Student Group", | |||
"options": "Student Group", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "assessment_name", | |||
"fieldtype": "Data", | |||
"in_global_search": 1, | |||
"label": "Assessment Name" | |||
}, | |||
{ | |||
"fieldname": "assessment_group", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Assessment Group", | |||
"options": "Assessment Group", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fetch_from": "course.default_grading_scale", | |||
"fetch_if_empty": 1, | |||
"fieldname": "grading_scale", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Grading Scale", | |||
"options": "Grading Scale", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fetch_from": "student_group.course", | |||
"fetch_if_empty": 1, | |||
"fieldname": "course", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"in_standard_filter": 1, | |||
"label": "Course", | |||
"options": "Course", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fetch_from": "student_group.program", | |||
"fieldname": "program", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"label": "Program", | |||
"options": "Program" | |||
}, | |||
{ | |||
"fetch_from": "student_group.academic_year", | |||
"fieldname": "academic_year", | |||
"fieldtype": "Link", | |||
"label": "Academic Year", | |||
"options": "Academic Year" | |||
}, | |||
{ | |||
"fetch_from": "student_group.academic_term", | |||
"fieldname": "academic_term", | |||
"fieldtype": "Link", | |||
"label": "Academic Term", | |||
"options": "Academic Term" | |||
}, | |||
{ | |||
"fieldname": "section_break_5", | |||
"fieldtype": "Section Break", | |||
"label": "Schedule" | |||
}, | |||
{ | |||
"default": "Today", | |||
"fieldname": "schedule_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Schedule Date", | |||
"no_copy": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "room", | |||
"fieldtype": "Link", | |||
"label": "Room", | |||
"options": "Room" | |||
}, | |||
{ | |||
"fieldname": "examiner", | |||
"fieldtype": "Link", | |||
"label": "Examiner", | |||
"options": "Instructor" | |||
}, | |||
{ | |||
"fetch_from": "examiner.instructor_name", | |||
"fieldname": "examiner_name", | |||
"fieldtype": "Data", | |||
"label": "Examiner Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_4", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "from_time", | |||
"fieldtype": "Time", | |||
"label": "From Time", | |||
"no_copy": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "to_time", | |||
"fieldtype": "Time", | |||
"label": "To Time", | |||
"no_copy": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "supervisor", | |||
"fieldtype": "Link", | |||
"label": "Supervisor", | |||
"options": "Instructor" | |||
}, | |||
{ | |||
"fetch_from": "supervisor.instructor_name", | |||
"fieldname": "supervisor_name", | |||
"fieldtype": "Data", | |||
"in_global_search": 1, | |||
"label": "Supervisor Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_20", | |||
"fieldtype": "Section Break", | |||
"label": "Evaluate" | |||
}, | |||
{ | |||
"fieldname": "maximum_assessment_score", | |||
"fieldtype": "Float", | |||
"label": "Maximum Assessment Score", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Table", | |||
"label": "Assessment Criteria", | |||
"options": "Assessment Plan Criteria", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "amended_from", | |||
"fieldtype": "Link", | |||
"label": "Amended From", | |||
"no_copy": 1, | |||
"options": "Assessment Plan", | |||
"print_hide": 1, | |||
"read_only": 1 | |||
} | |||
], | |||
"is_submittable": 1, | |||
"links": [], | |||
"modified": "2020-10-23 15:55:35.076251", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Plan", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 1, | |||
"cancel": 1, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"submit": 1, | |||
"write": 1 | |||
} | |||
], | |||
"restrict_to_domain": "", | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "assessment_name" | |||
} |
@@ -0,0 +1,60 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
class AssessmentPlan(Document): | |||
def validate(self): | |||
self.validate_overlap() | |||
self.validate_max_score() | |||
self.validate_assessment_criteria() | |||
def validate_overlap(self): | |||
"""Validates overlap for Student Group, Instructor, Room""" | |||
from education.education.utils import validate_overlap_for | |||
# Validate overlapping course schedules. | |||
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_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_max_score(self): | |||
max_score = 0 | |||
for d in self.assessment_criteria: | |||
max_score += d.maximum_score | |||
if self.maximum_assessment_score != max_score: | |||
xhiveframework.throw( | |||
_("Sum of Scores of Assessment Criteria needs to be {0}.").format( | |||
self.maximum_assessment_score | |||
) | |||
) | |||
def validate_assessment_criteria(self): | |||
assessment_criteria_list = xhiveframework.db.sql_list( | |||
""" select apc.assessment_criteria | |||
from `tabAssessment Plan` ap , `tabAssessment Plan Criteria` apc | |||
where ap.name = apc.parent and ap.course=%s and ap.student_group=%s and ap.assessment_group=%s | |||
and ap.name != %s and ap.docstatus=1""", | |||
(self.course, self.student_group, self.assessment_group, self.name), | |||
) | |||
for d in self.assessment_criteria: | |||
if d.assessment_criteria in assessment_criteria_list: | |||
xhiveframework.throw( | |||
_("You have already assessed for the assessment criteria {}.").format( | |||
xhiveframework.bold(d.assessment_criteria) | |||
) | |||
) |
@@ -0,0 +1,12 @@ | |||
# Copyright (c) 2015, Xhive | |||
# License: GNU General Public License v3. See license.txt | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"fieldname": "assessment_plan", | |||
"transactions": [{"label": _("Assessment"), "items": ["Assessment Result"]}], | |||
"reports": [{"label": _("Report"), "items": ["Assessment Plan Status"]}], | |||
} |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
# test_records = xhiveframework.get_test_records('Assessment Plan') | |||
class TestAssessmentPlan(unittest.TestCase): | |||
pass |
@@ -0,0 +1,134 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Assessment Criteria", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Assessment 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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"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_bulk_edit": 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_global_search": 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 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2017-11-10 19:10:50.560006", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Plan Criteria", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class AssessmentPlanCriteria(Document): | |||
pass |
@@ -0,0 +1,125 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Result', { | |||
refresh: function(frm) { | |||
if (!frm.doc.__islocal) { | |||
frm.trigger('setup_chart'); | |||
} | |||
frm.get_field('details').grid.cannot_add_rows = true; | |||
frm.set_query('course', function() { | |||
return { | |||
query: 'education.education.doctype.program_enrollment.program_enrollment.get_program_courses', | |||
filters: { | |||
'program': frm.doc.program | |||
} | |||
}; | |||
}); | |||
frm.set_query('academic_term', function() { | |||
return { | |||
filters: { | |||
'academic_year': frm.doc.academic_year | |||
} | |||
}; | |||
}); | |||
}, | |||
onload: function(frm) { | |||
frm.set_query('assessment_plan', function() { | |||
return { | |||
filters: { | |||
docstatus: 1 | |||
} | |||
}; | |||
}); | |||
}, | |||
assessment_plan: function(frm) { | |||
if (frm.doc.assessment_plan) { | |||
xhiveframework.call({ | |||
method: 'education.education.api.get_assessment_details', | |||
args: { | |||
assessment_plan: frm.doc.assessment_plan | |||
}, | |||
callback: function(r) { | |||
if (r.message) { | |||
xhiveframework.model.clear_table(frm.doc, 'details'); | |||
$.each(r.message, function(i, d) { | |||
var row = frm.add_child('details'); | |||
row.assessment_criteria = d.assessment_criteria; | |||
row.maximum_score = d.maximum_score; | |||
}); | |||
frm.refresh_field('details'); | |||
} | |||
} | |||
}); | |||
} | |||
}, | |||
setup_chart: function(frm) { | |||
let labels = []; | |||
let maximum_scores = []; | |||
let scores = []; | |||
$.each(frm.doc.details, function(_i, e) { | |||
labels.push(e.assessment_criteria); | |||
maximum_scores.push(e.maximum_score); | |||
scores.push(e.score); | |||
}); | |||
if (labels.length && maximum_scores.length && scores.length) { | |||
frm.dashboard.chart_area.empty().removeClass('hidden'); | |||
new xhiveframework.Chart('.form-graph', { | |||
title: 'Assessment Results', | |||
data: { | |||
labels: labels, | |||
datasets: [ | |||
{ | |||
name: 'Maximum Score', | |||
chartType: 'bar', | |||
values: maximum_scores, | |||
}, | |||
{ | |||
name: 'Score Obtained', | |||
chartType: 'bar', | |||
values: scores, | |||
} | |||
] | |||
}, | |||
colors: ['#4CA746', '#98D85B'], | |||
type: 'bar' | |||
}); | |||
} | |||
} | |||
}); | |||
xhiveframework.ui.form.on('Assessment Result Detail', { | |||
score: function(frm, cdt, cdn) { | |||
var d = locals[cdt][cdn]; | |||
if (!d.maximum_score || !frm.doc.grading_scale) { | |||
d.score = ''; | |||
xhiveframework.throw(__('Please fill in all the details to generate Assessment Result.')); | |||
} | |||
if (d.score > d.maximum_score) { | |||
xhiveframework.throw(__('Score cannot be greater than Maximum Score')); | |||
} | |||
else { | |||
xhiveframework.call({ | |||
method: 'education.education.api.get_grade', | |||
args: { | |||
grading_scale: frm.doc.grading_scale, | |||
percentage: ((d.score/d.maximum_score) * 100) | |||
}, | |||
callback: function(r) { | |||
if (r.message) { | |||
xhiveframework.model.set_value(cdt, cdn, 'grade', r.message); | |||
} | |||
} | |||
}); | |||
} | |||
} | |||
}); |
@@ -0,0 +1,203 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"autoname": "EDU-RES-.YYYY.-.#####", | |||
"creation": "2015-11-13 17:18:06.468332", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"assessment_plan", | |||
"program", | |||
"course", | |||
"academic_year", | |||
"academic_term", | |||
"column_break_3", | |||
"student", | |||
"student_name", | |||
"student_group", | |||
"assessment_group", | |||
"grading_scale", | |||
"section_break_5", | |||
"details", | |||
"section_break_8", | |||
"maximum_score", | |||
"column_break_11", | |||
"total_score", | |||
"grade", | |||
"section_break_13", | |||
"comment", | |||
"amended_from" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "assessment_plan", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Assessment Plan", | |||
"options": "Assessment Plan", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.program", | |||
"fieldname": "program", | |||
"fieldtype": "Link", | |||
"label": "Program", | |||
"options": "Program" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.course", | |||
"fieldname": "course", | |||
"fieldtype": "Link", | |||
"label": "Course", | |||
"options": "Course" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.academic_year", | |||
"fieldname": "academic_year", | |||
"fieldtype": "Link", | |||
"label": "Academic Year", | |||
"options": "Academic Year" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.academic_term", | |||
"fieldname": "academic_term", | |||
"fieldtype": "Link", | |||
"label": "Academic Term", | |||
"options": "Academic Term" | |||
}, | |||
{ | |||
"fieldname": "column_break_3", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "student", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"label": "Student", | |||
"options": "Student", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fetch_from": "student.student_name", | |||
"fieldname": "student_name", | |||
"fieldtype": "Data", | |||
"in_global_search": 1, | |||
"in_list_view": 1, | |||
"label": "Student Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.student_group", | |||
"fieldname": "student_group", | |||
"fieldtype": "Link", | |||
"label": "Student Group", | |||
"options": "Student Group" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.assessment_group", | |||
"fieldname": "assessment_group", | |||
"fieldtype": "Link", | |||
"label": "Assessment Group", | |||
"options": "Assessment Group" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.grading_scale", | |||
"fieldname": "grading_scale", | |||
"fieldtype": "Link", | |||
"label": "Grading Scale", | |||
"options": "Grading Scale", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_5", | |||
"fieldtype": "Section Break", | |||
"label": "Result" | |||
}, | |||
{ | |||
"fieldname": "details", | |||
"fieldtype": "Table", | |||
"label": "Details", | |||
"options": "Assessment Result Detail", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_8", | |||
"fieldtype": "Section Break" | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.maximum_assessment_score", | |||
"fieldname": "maximum_score", | |||
"fieldtype": "Float", | |||
"label": "Maximum Score", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fetch_from": "assessment_plan.maximum_assessment_score", | |||
"fieldname": "column_break_11", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "total_score", | |||
"fieldtype": "Float", | |||
"in_list_view": 1, | |||
"label": "Total Score", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "grade", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Grade", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_13", | |||
"fieldtype": "Section Break", | |||
"label": "Summary" | |||
}, | |||
{ | |||
"fieldname": "comment", | |||
"fieldtype": "Small Text", | |||
"label": "Comment" | |||
}, | |||
{ | |||
"fieldname": "amended_from", | |||
"fieldtype": "Link", | |||
"label": "Amended From", | |||
"no_copy": 1, | |||
"options": "Assessment Result", | |||
"print_hide": 1, | |||
"read_only": 1 | |||
} | |||
], | |||
"is_submittable": 1, | |||
"links": [], | |||
"modified": "2020-08-03 11:47:54.119489", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Result", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 1, | |||
"cancel": 1, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"submit": 1, | |||
"write": 1 | |||
} | |||
], | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "student_name" | |||
} |
@@ -0,0 +1,59 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
from xhiveframework.utils import flt | |||
from xhiveframework.utils.csvutils import getlink | |||
import education.education | |||
from education.education.api import get_assessment_details, get_grade | |||
class AssessmentResult(Document): | |||
def validate(self): | |||
education.education.validate_student_belongs_to_group( | |||
self.student, self.student_group | |||
) | |||
self.validate_maximum_score() | |||
self.validate_grade() | |||
self.validate_duplicate() | |||
def validate_maximum_score(self): | |||
assessment_details = get_assessment_details(self.assessment_plan) | |||
max_scores = {} | |||
for d in assessment_details: | |||
max_scores.update({d.assessment_criteria: d.maximum_score}) | |||
for d in self.details: | |||
d.maximum_score = max_scores.get(d.assessment_criteria) | |||
if d.score > d.maximum_score: | |||
xhiveframework.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 | |||
) | |||
def validate_duplicate(self): | |||
assessment_result = xhiveframework.get_list( | |||
"Assessment Result", | |||
filters={ | |||
"name": ("not in", [self.name]), | |||
"student": self.student, | |||
"assessment_plan": self.assessment_plan, | |||
"docstatus": ("!=", 2), | |||
}, | |||
) | |||
if assessment_result: | |||
xhiveframework.throw( | |||
_("Assessment Result record {0} already exists.").format( | |||
getlink("Assessment Result", assessment_result[0].name) | |||
) | |||
) |
@@ -0,0 +1,15 @@ | |||
# Copyright (c) 2015, Xhive | |||
# License: GNU General Public License v3. See license.txt | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"reports": [ | |||
{ | |||
"label": _("Reports"), | |||
"items": ["Final Assessment Grades", "Course wise Assessment Report"], | |||
} | |||
] | |||
} |
@@ -0,0 +1,17 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
from education.education.api import get_grade | |||
# test_records = xhiveframework.get_test_records('Assessment Result') | |||
class TestAssessmentResult(unittest.TestCase): | |||
def test_grade(self): | |||
grade = get_grade("_Test Grading Scale", 80) | |||
self.assertEqual("A", grade) | |||
grade = get_grade("_Test Grading Scale", 70) | |||
self.assertEqual("B", grade) |
@@ -0,0 +1,66 @@ | |||
{ | |||
"actions": [], | |||
"creation": "2016-12-14 17:44:35.583123", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"assessment_criteria", | |||
"maximum_score", | |||
"column_break_2", | |||
"score", | |||
"grade" | |||
], | |||
"fields": [ | |||
{ | |||
"columns": 4, | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Assessment Criteria", | |||
"options": "Assessment Criteria", | |||
"read_only": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"columns": 2, | |||
"fieldname": "maximum_score", | |||
"fieldtype": "Float", | |||
"in_list_view": 1, | |||
"label": "Maximum Score", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"columns": 2, | |||
"fieldname": "score", | |||
"fieldtype": "Float", | |||
"in_list_view": 1, | |||
"label": "Score", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"columns": 2, | |||
"fieldname": "grade", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Grade", | |||
"read_only": 1 | |||
} | |||
], | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-07-31 13:27:17.699022", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Result Detail", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"restrict_to_domain": "", | |||
"sort_field": "modified", | |||
"sort_order": "DESC" | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class AssessmentResultDetail(Document): | |||
pass |
@@ -0,0 +1,162 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Assessment Result Tool', { | |||
setup: function(frm) { | |||
frm.add_fetch("assessment_plan", "student_group", "student_group"); | |||
}, | |||
refresh: function(frm) { | |||
if (xhiveframework.route_options) { | |||
frm.set_value("student_group", xhiveframework.route_options.student_group); | |||
frm.set_value("assessment_plan", xhiveframework.route_options.assessment_plan); | |||
xhiveframework.route_options = null; | |||
} else { | |||
frm.trigger("assessment_plan"); | |||
} | |||
frm.disable_save(); | |||
frm.page.clear_indicator(); | |||
}, | |||
assessment_plan: function(frm) { | |||
frm.doc.show_submit = false; | |||
if(frm.doc.assessment_plan) { | |||
if (!frm.doc.student_group) | |||
return | |||
xhiveframework.call({ | |||
method: "education.education.api.get_assessment_students", | |||
args: { | |||
"assessment_plan": frm.doc.assessment_plan, | |||
"student_group": frm.doc.student_group | |||
}, | |||
callback: function(r) { | |||
if (r.message) { | |||
frm.doc.students = r.message; | |||
frm.events.render_table(frm); | |||
for (let value of r.message) { | |||
if (!value.docstatus) { | |||
frm.doc.show_submit = true; | |||
break; | |||
} | |||
} | |||
frm.events.submit_result(frm); | |||
} | |||
} | |||
}); | |||
} | |||
}, | |||
render_table: function(frm) { | |||
$(frm.fields_dict.result_html.wrapper).empty(); | |||
let assessment_plan = frm.doc.assessment_plan; | |||
xhiveframework.call({ | |||
method: "education.education.api.get_assessment_details", | |||
args: { | |||
assessment_plan: assessment_plan | |||
}, | |||
callback: function(r) { | |||
frm.events.get_marks(frm, r.message); | |||
} | |||
}); | |||
}, | |||
get_marks: function(frm, criteria_list) { | |||
let max_total_score = 0; | |||
criteria_list.forEach(function(c) { | |||
max_total_score += c.maximum_score | |||
}); | |||
var result_table = $(xhiveframework.render_template('assessment_result_tool', { | |||
frm: frm, | |||
students: frm.doc.students, | |||
criteria: criteria_list, | |||
max_total_score: max_total_score | |||
})); | |||
result_table.appendTo(frm.fields_dict.result_html.wrapper); | |||
result_table.on('change', 'input', function(e) { | |||
let $input = $(e.target); | |||
let student = $input.data().student; | |||
let max_score = $input.data().maxScore; | |||
let value = $input.val(); | |||
if(value < 0) { | |||
$input.val(0); | |||
} else if(value > max_score) { | |||
$input.val(max_score); | |||
} | |||
let total_score = 0; | |||
let student_scores = {}; | |||
student_scores["assessment_details"] = {} | |||
result_table.find(`input[data-student=${student}].student-result-data`) | |||
.each(function(el, input) { | |||
let $input = $(input); | |||
let criteria = $input.data().criteria; | |||
let value = parseFloat($input.val()); | |||
if (!Number.isNaN(value)) { | |||
student_scores["assessment_details"][criteria] = value; | |||
} | |||
total_score += value; | |||
}); | |||
if(!Number.isNaN(total_score)) { | |||
result_table.find(`span[data-student=${student}].total-score`).html(total_score); | |||
} | |||
if (Object.keys(student_scores["assessment_details"]).length === criteria_list.length) { | |||
student_scores["student"] = student; | |||
student_scores["total_score"] = total_score; | |||
result_table.find(`[data-student=${student}].result-comment`) | |||
.each(function(el, input){ | |||
student_scores["comment"] = $(input).val(); | |||
}); | |||
xhiveframework.call({ | |||
method: "education.education.api.mark_assessment_result", | |||
args: { | |||
"assessment_plan": frm.doc.assessment_plan, | |||
"scores": student_scores | |||
}, | |||
callback: function(r) { | |||
let assessment_result = r.message; | |||
if (!frm.doc.show_submit) { | |||
frm.doc.show_submit = true; | |||
frm.events.submit_result; | |||
} | |||
for (var criteria of Object.keys(assessment_result.details)) { | |||
result_table.find(`[data-criteria=${criteria}][data-student=${assessment_result | |||
.student}].student-result-grade`).each(function(e1, input) { | |||
$(input).html(assessment_result.details[criteria]); | |||
}); | |||
} | |||
result_table.find(`span[data-student=${assessment_result.student}].total-score-grade`).html(assessment_result.grade); | |||
let link_span = result_table.find(`span[data-student=${assessment_result.student}].total-result-link`); | |||
$(link_span).css("display", "block"); | |||
$(link_span).find("a").attr("href", "/app/assessment-result/"+assessment_result.name); | |||
} | |||
}); | |||
} | |||
}); | |||
}, | |||
submit_result: function(frm) { | |||
if (frm.doc.show_submit) { | |||
frm.page.set_primary_action(__("Submit"), function() { | |||
xhiveframework.call({ | |||
method: "education.education.api.submit_assessment_results", | |||
args: { | |||
"assessment_plan": frm.doc.assessment_plan, | |||
"student_group": frm.doc.student_group | |||
}, | |||
callback: function(r) { | |||
if (r.message) { | |||
xhiveframework.msgprint(__("{0} Result submittted", [r.message])); | |||
} else { | |||
xhiveframework.msgprint(__("No Result to submit")); | |||
} | |||
frm.events.assessment_plan(frm); | |||
} | |||
}); | |||
}); | |||
} | |||
else { | |||
frm.page.clear_primary_action(); | |||
} | |||
} | |||
}); |
@@ -0,0 +1,235 @@ | |||
{ | |||
"allow_copy": 1, | |||
"allow_guest_to_view": 0, | |||
"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_bulk_edit": 0, | |||
"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_global_search": 0, | |||
"in_list_view": 1, | |||
"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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 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_global_search": 0, | |||
"in_list_view": 1, | |||
"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": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 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_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 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_global_search": 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 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 1, | |||
"hide_toolbar": 1, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-12-27 09:36:37.155890", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Assessment Result Tool", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 0, | |||
"email": 0, | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 0, | |||
"read": 1, | |||
"report": 0, | |||
"role": "Academics User", | |||
"set_user_permissions": 0, | |||
"share": 0, | |||
"submit": 0, | |||
"write": 1 | |||
}, | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 0, | |||
"email": 0, | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 0, | |||
"read": 1, | |||
"report": 0, | |||
"role": "Instructor", | |||
"set_user_permissions": 0, | |||
"share": 0, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class AssessmentResultTool(Document): | |||
pass |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
class TestAssessmentResultTool(unittest.TestCase): | |||
pass |
@@ -0,0 +1,79 @@ | |||
xhiveframework.ui.form.on('Course', { | |||
refresh: function(frm) { | |||
if (!cur_frm.doc.__islocal) { | |||
frm.add_custom_button(__('Add to Programs'), function() { | |||
frm.trigger('add_course_to_programs') | |||
}); | |||
} | |||
frm.set_query('default_grading_scale', function(){ | |||
return { | |||
filters: { | |||
docstatus: 1 | |||
} | |||
} | |||
}); | |||
}, | |||
add_course_to_programs: function(frm) { | |||
get_programs_without_course(frm.doc.name).then(r => { | |||
if (r.message.length) { | |||
xhiveframework.prompt([ | |||
{ | |||
fieldname: 'programs', | |||
label: __('Programs'), | |||
fieldtype: 'MultiSelectPills', | |||
get_data: function() { | |||
return r.message; | |||
} | |||
}, | |||
{ | |||
fieldtype: 'Check', | |||
label: __('Is Mandatory'), | |||
fieldname: 'mandatory', | |||
} | |||
], | |||
function(data) { | |||
xhiveframework.call({ | |||
method: 'education.education.doctype.course.course.add_course_to_programs', | |||
args: { | |||
'course': frm.doc.name, | |||
'programs': data.programs, | |||
'mandatory': data.mandatory | |||
}, | |||
callback: function(r) { | |||
if (!r.exc) { | |||
frm.reload_doc(); | |||
} | |||
}, | |||
freeze: true, | |||
freeze_message: __('...Adding Course to Programs') | |||
}) | |||
}, __('Add Course to Programs'), __('Add')); | |||
} else { | |||
xhiveframework.msgprint(__('This course is already added to the existing programs')); | |||
} | |||
}); | |||
} | |||
}); | |||
xhiveframework.ui.form.on('Course Topic', { | |||
topics_add: function(frm){ | |||
frm.fields_dict['topics'].grid.get_field('topic').get_query = function(doc){ | |||
var topics_list = []; | |||
if(!doc.__islocal) topics_list.push(doc.name); | |||
$.each(doc.topics, function(idx, val){ | |||
if (val.topic) topics_list.push(val.topic); | |||
}); | |||
return { filters: [['Topic', 'name', 'not in', topics_list]] }; | |||
}; | |||
} | |||
}); | |||
let get_programs_without_course = function(course) { | |||
return xhiveframework.call({ | |||
type: 'GET', | |||
method: 'education.education.doctype.course.course.get_programs_without_course', | |||
args: {'course': course} | |||
}); | |||
} |
@@ -0,0 +1,155 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
"autoname": "field:course_name", | |||
"creation": "2015-09-07 12:39:55.181893", | |||
"doctype": "DocType", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"course_name", | |||
"department", | |||
"hero_image", | |||
"column_break_tflc", | |||
"description", | |||
"section_break_6", | |||
"topics", | |||
"assessment_tab", | |||
"assessment", | |||
"default_grading_scale", | |||
"assessment_criteria", | |||
"connections_tab" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "course_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Course Name", | |||
"reqd": 1, | |||
"unique": 1 | |||
}, | |||
{ | |||
"fieldname": "department", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Department", | |||
"options": "Department" | |||
}, | |||
{ | |||
"fieldname": "section_break_6", | |||
"fieldtype": "Section Break" | |||
}, | |||
{ | |||
"fieldname": "topics", | |||
"fieldtype": "Table", | |||
"label": "Topics", | |||
"options": "Course Topic" | |||
}, | |||
{ | |||
"fieldname": "hero_image", | |||
"fieldtype": "Attach Image", | |||
"hidden": 1, | |||
"label": "Hero Image" | |||
}, | |||
{ | |||
"fieldname": "assessment", | |||
"fieldtype": "Section Break" | |||
}, | |||
{ | |||
"fieldname": "default_grading_scale", | |||
"fieldtype": "Link", | |||
"label": "Default Grading Scale", | |||
"options": "Grading Scale" | |||
}, | |||
{ | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Table", | |||
"label": "Assessment Criteria", | |||
"options": "Course Assessment Criteria" | |||
}, | |||
{ | |||
"fieldname": "description", | |||
"fieldtype": "Small Text", | |||
"label": "Description" | |||
}, | |||
{ | |||
"fieldname": "column_break_tflc", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "assessment_tab", | |||
"fieldtype": "Tab Break", | |||
"label": "Assessment" | |||
}, | |||
{ | |||
"fieldname": "connections_tab", | |||
"fieldtype": "Tab Break", | |||
"label": "Connections", | |||
"show_dashboard": 1 | |||
} | |||
], | |||
"image_field": "hero_image", | |||
"links": [], | |||
"modified": "2023-01-13 17:12:58.871929", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Course", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Instructor", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Administrator", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Education Manager", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"search_fields": "course_name", | |||
"show_name_in_global_search": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [] | |||
} |
@@ -0,0 +1,60 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import json | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
class Course(Document): | |||
def validate(self): | |||
self.validate_assessment_criteria() | |||
def validate_assessment_criteria(self): | |||
if self.assessment_criteria: | |||
total_weightage = 0 | |||
for criteria in self.assessment_criteria: | |||
total_weightage += criteria.weightage or 0 | |||
if total_weightage != 100: | |||
xhiveframework.throw(_("Total Weightage of all Assessment Criteria must be 100%")) | |||
def get_topics(self): | |||
topic_data = [] | |||
for topic in self.topics: | |||
topic_doc = xhiveframework.get_doc("Topic", topic.topic) | |||
if topic_doc.topic_content: | |||
topic_data.append(topic_doc) | |||
return topic_data | |||
@xhiveframework.whitelist() | |||
def add_course_to_programs(course, programs, mandatory=False): | |||
programs = json.loads(programs) | |||
for entry in programs: | |||
program = xhiveframework.get_doc("Program", entry) | |||
program.append( | |||
"courses", {"course": course, "course_name": course, "mandatory": mandatory} | |||
) | |||
program.flags.ignore_mandatory = True | |||
program.save() | |||
xhiveframework.msgprint( | |||
_("Course {0} has been added to all the selected programs successfully.").format( | |||
xhiveframework.bold(course) | |||
), | |||
title=_("Programs updated"), | |||
indicator="green", | |||
) | |||
@xhiveframework.whitelist() | |||
def get_programs_without_course(course): | |||
data = [] | |||
for entry in xhiveframework.db.get_all("Program"): | |||
program = xhiveframework.get_doc("Program", entry.name) | |||
courses = [c.course for c in program.courses] | |||
if not courses or course not in courses: | |||
data.append(program.name) | |||
return data |
@@ -0,0 +1,18 @@ | |||
# Copyright (c) 2015, Xhive | |||
# License: GNU General Public License v3. See license.txt | |||
from xhiveframework import _ | |||
def get_data(): | |||
return { | |||
"fieldname": "course", | |||
"transactions": [ | |||
{ | |||
"label": _("Program and Course"), | |||
"items": ["Program", "Course Enrollment", "Course Schedule"], | |||
}, | |||
{"label": _("Student"), "items": ["Student Group"]}, | |||
{"label": _("Assessment"), "items": ["Assessment Plan", "Assessment Result"]}, | |||
], | |||
} |
@@ -0,0 +1,52 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
import xhiveframework | |||
from education.education.doctype.topic.test_topic import ( | |||
make_topic, make_topic_and_linked_content) | |||
# test_records = xhiveframework.get_test_records('Course') | |||
class TestCourse(unittest.TestCase): | |||
def setUp(self): | |||
make_topic_and_linked_content( | |||
"_Test Topic 1", [{"type": "Article", "name": "_Test Article 1"}] | |||
) | |||
make_topic_and_linked_content( | |||
"_Test Topic 2", [{"type": "Article", "name": "_Test Article 2"}] | |||
) | |||
make_course_and_linked_topic("_Test Course 1", ["_Test Topic 1", "_Test Topic 2"]) | |||
def test_get_topics(self): | |||
course = xhiveframework.get_doc("Course", "_Test Course 1") | |||
topics = course.get_topics() | |||
self.assertEqual(topics[0].name, "_Test Topic 1") | |||
self.assertEqual(topics[1].name, "_Test Topic 2") | |||
xhiveframework.db.rollback() | |||
def make_course(name): | |||
try: | |||
course = xhiveframework.get_doc("Course", name) | |||
except xhiveframework.DoesNotExistError: | |||
course = xhiveframework.get_doc( | |||
{"doctype": "Course", "course_name": name, "course_code": name} | |||
).insert() | |||
return course.name | |||
def make_course_and_linked_topic(course_name, topic_name_list): | |||
try: | |||
course = xhiveframework.get_doc("Course", course_name) | |||
except xhiveframework.DoesNotExistError: | |||
make_course(course_name) | |||
course = xhiveframework.get_doc("Course", course_name) | |||
topic_list = [make_topic(topic_name) for topic_name in topic_name_list] | |||
for topic in topic_list: | |||
course.append("topics", {"topic": topic}) | |||
course.save() | |||
return course |
@@ -0,0 +1,14 @@ | |||
[ | |||
{ | |||
"course_name": "TC100", | |||
"course_abbreviation": "TC" | |||
}, | |||
{ | |||
"course_name": "TC101", | |||
"course_abbreviation": "TC1" | |||
}, | |||
{ | |||
"course_name": "TC102", | |||
"course_abbreviation": "TC2" | |||
} | |||
] |
@@ -0,0 +1,8 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Course Activity', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,108 @@ | |||
{ | |||
"actions": [], | |||
"autoname": "format:EDU-CA-{YYYY}-{#####}", | |||
"beta": 1, | |||
"creation": "2018-10-01 17:35:54.391413", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"enrollment", | |||
"course", | |||
"student", | |||
"content_type", | |||
"content", | |||
"activity_date" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "enrollment", | |||
"fieldtype": "Link", | |||
"label": "Course Enrollment", | |||
"options": "Course Enrollment", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fetch_from": "enrollment.course", | |||
"fieldname": "course", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Course", | |||
"read_only": 1, | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fetch_from": "enrollment.student", | |||
"fieldname": "student", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Student", | |||
"read_only": 1, | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "content_type", | |||
"fieldtype": "Select", | |||
"label": "Content Type", | |||
"options": "\nArticle\nVideo", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "content", | |||
"fieldtype": "Dynamic Link", | |||
"in_list_view": 1, | |||
"label": "Content", | |||
"options": "content_type", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "activity_date", | |||
"fieldtype": "Datetime", | |||
"label": "Activity Date", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2023-02-06 12:23:47.047301", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Course Activity", | |||
"naming_rule": "Expression", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Instructor", | |||
"share": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,18 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
class CourseActivity(Document): | |||
def validate(self): | |||
self.check_if_enrolled() | |||
def check_if_enrolled(self): | |||
if xhiveframework.db.exists("Course Enrollment", self.enrollment): | |||
return True | |||
else: | |||
xhiveframework.throw(_("Course Enrollment {0} does not exists").format(self.enrollment)) |
@@ -0,0 +1,30 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
import xhiveframework | |||
class TestCourseActivity(unittest.TestCase): | |||
pass | |||
def make_course_activity(enrollment, content_type, content): | |||
activity = xhiveframework.get_all( | |||
"Course Activity", | |||
filters={"enrollment": enrollment, "content_type": content_type, "content": content}, | |||
) | |||
try: | |||
activity = xhiveframework.get_doc("Course Activity", activity[0]["name"]) | |||
except (IndexError, xhiveframework.DoesNotExistError): | |||
activity = xhiveframework.get_doc( | |||
{ | |||
"doctype": "Course Activity", | |||
"enrollment": enrollment, | |||
"content_type": content_type, | |||
"content": content, | |||
"activity_date": xhiveframework.utils.datetime.datetime.now(), | |||
} | |||
).insert() | |||
return activity |
@@ -0,0 +1,134 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "assessment_criteria", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Assessment Criteria", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Assessment 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_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"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_bulk_edit": 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_global_search": 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": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2017-11-10 19:10:44.710837", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Course Assessment Criteria", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"restrict_to_domain": "", | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,9 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from xhiveframework.model.document import Document | |||
class CourseAssessmentCriteria(Document): | |||
pass |
@@ -0,0 +1,15 @@ | |||
# Copyright (c) 2015, Xhive | |||
// For license information, please see license.txt | |||
xhiveframework.ui.form.on('Course Enrollment', { | |||
onload: function(frm) { | |||
frm.set_query('course', function() { | |||
return { | |||
query: 'education.education.doctype.program_enrollment.program_enrollment.get_program_courses', | |||
filters: { | |||
'program': frm.doc.program | |||
} | |||
}; | |||
}); | |||
} | |||
}); |
@@ -0,0 +1,107 @@ | |||
{ | |||
"actions": [], | |||
"autoname": "format:EDU-CE-{YYYY}-{#####}", | |||
"beta": 1, | |||
"creation": "2018-10-15 15:35:39.375161", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"program_enrollment", | |||
"program", | |||
"enrollment_date", | |||
"column_break_uisg", | |||
"course", | |||
"student", | |||
"student_name" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "program_enrollment", | |||
"fieldtype": "Link", | |||
"label": "Program Enrollment", | |||
"options": "Program Enrollment", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "student", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Student", | |||
"options": "Student", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "course", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Course", | |||
"options": "Course", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "enrollment_date", | |||
"fieldtype": "Date", | |||
"label": "Enrollment Date", | |||
"reqd": 1, | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fetch_from": "student.student_name", | |||
"fieldname": "student_name", | |||
"fieldtype": "Data", | |||
"label": "Student Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_uisg", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"allow_in_quick_entry": 1, | |||
"fetch_from": "program_enrollment.program", | |||
"fieldname": "program", | |||
"fieldtype": "Data", | |||
"label": "Program", | |||
"read_only": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2023-02-06 12:24:04.816603", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Course Enrollment", | |||
"naming_rule": "Expression", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Instructor", | |||
"share": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,114 @@ | |||
# Copyright (c) 2015, Xhive | |||
# For license information, please see license.txt | |||
from functools import reduce | |||
import xhiveframework | |||
from xhiveframework import _ | |||
from xhiveframework.model.document import Document | |||
from xhiveframework.utils import get_link_to_form | |||
class CourseEnrollment(Document): | |||
def validate(self): | |||
self.validate_duplication() | |||
def get_progress(self, student): | |||
""" | |||
Returns Progress of given student for a particular course enrollment | |||
:param self: Course Enrollment Object | |||
:param student: Student Object | |||
""" | |||
course = xhiveframework.get_doc("Course", self.course) | |||
topics = course.get_topics() | |||
progress = [] | |||
for topic in topics: | |||
progress.append(student.get_topic_progress(self.name, topic)) | |||
if progress: | |||
return reduce(lambda x, y: x + y, progress) # Flatten out the List | |||
else: | |||
return [] | |||
def validate_duplication(self): | |||
enrollment = xhiveframework.db.exists( | |||
"Course Enrollment", | |||
{ | |||
"student": self.student, | |||
"course": self.course, | |||
"program_enrollment": self.program_enrollment, | |||
"name": ("!=", self.name), | |||
}, | |||
) | |||
if enrollment: | |||
xhiveframework.throw( | |||
_("Student is already enrolled via Course Enrollment {0}").format( | |||
get_link_to_form("Course Enrollment", enrollment) | |||
), | |||
title=_("Duplicate Entry"), | |||
) | |||
def add_quiz_activity( | |||
self, quiz_name, quiz_response, answers, score, status, time_taken | |||
): | |||
result = {k: ("Correct" if v else "Wrong") for k, v in answers.items()} | |||
result_data = [] | |||
for key in answers: | |||
item = {} | |||
item["question"] = key | |||
item["quiz_result"] = result[key] | |||
try: | |||
if not quiz_response[key]: | |||
item["selected_option"] = "Unattempted" | |||
elif isinstance(quiz_response[key], list): | |||
item["selected_option"] = ", ".join( | |||
xhiveframework.get_value("Options", res, "option") for res in quiz_response[key] | |||
) | |||
else: | |||
item["selected_option"] = xhiveframework.get_value("Options", quiz_response[key], "option") | |||
except KeyError: | |||
item["selected_option"] = "Unattempted" | |||
result_data.append(item) | |||
quiz_activity = xhiveframework.get_doc( | |||
{ | |||
"doctype": "Quiz Activity", | |||
"enrollment": self.name, | |||
"quiz": quiz_name, | |||
"activity_date": xhiveframework.utils.datetime.datetime.now(), | |||
"result": result_data, | |||
"score": score, | |||
"status": status, | |||
"time_taken": time_taken, | |||
} | |||
).insert(ignore_permissions=True) | |||
def add_activity(self, content_type, content): | |||
activity = check_activity_exists(self.name, content_type, content) | |||
if activity: | |||
return activity | |||
else: | |||
activity = xhiveframework.get_doc( | |||
{ | |||
"doctype": "Course Activity", | |||
"enrollment": self.name, | |||
"content_type": content_type, | |||
"content": content, | |||
"activity_date": xhiveframework.utils.datetime.datetime.now(), | |||
} | |||
) | |||
activity.insert(ignore_permissions=True) | |||
return activity.name | |||
def check_activity_exists(enrollment, content_type, content): | |||
activity = xhiveframework.get_all( | |||
"Course Activity", | |||
filters={"enrollment": enrollment, "content_type": content_type, "content": content}, | |||
) | |||
if activity: | |||
return activity[0].name | |||
else: | |||
return None |
@@ -0,0 +1,67 @@ | |||
# Copyright (c) 2015, Xhive | |||
# See license.txt | |||
import unittest | |||
import xhiveframework | |||
from education.education.doctype.course_activity.test_course_activity import \ | |||
make_course_activity | |||
from education.education.doctype.program.test_program import setup_program | |||
from education.education.doctype.student.test_student import (create_student, | |||
get_student) | |||
class TestCourseEnrollment(unittest.TestCase): | |||
def setUp(self): | |||
setup_program() | |||
student = create_student( | |||
{ | |||
"first_name": "_Test First", | |||
"last_name": "_Test Last", | |||
"email": "_test_student_1@example.com", | |||
} | |||
) | |||
program_enrollment = student.enroll_in_program("_Test Program") | |||
course_enrollment = xhiveframework.db.get_value( | |||
"Course Enrollment", | |||
{ | |||
"course": "_Test Course 1", | |||
"student": student.name, | |||
"program_enrollment": program_enrollment.name, | |||
}, | |||
"name", | |||
) | |||
make_course_activity(course_enrollment, "Article", "_Test Article 1-1") | |||
def test_get_progress(self): | |||
student = get_student("_test_student_1@example.com") | |||
program_enrollment_name = xhiveframework.get_list( | |||
"Program Enrollment", filters={"student": student.name, "Program": "_Test Program"} | |||
)[0].name | |||
course_enrollment_name = xhiveframework.get_list( | |||
"Course Enrollment", | |||
filters={ | |||
"student": student.name, | |||
"course": "_Test Course 1", | |||
"program_enrollment": program_enrollment_name, | |||
}, | |||
)[0].name | |||
course_enrollment = xhiveframework.get_doc("Course Enrollment", course_enrollment_name) | |||
progress = course_enrollment.get_progress(student) | |||
finished = { | |||
"content": "_Test Article 1-1", | |||
"content_type": "Article", | |||
"is_complete": True, | |||
} | |||
self.assertTrue(finished in progress) | |||
xhiveframework.db.rollback() | |||
def tearDown(self): | |||
for entry in xhiveframework.db.get_all("Course Enrollment"): | |||
xhiveframework.delete_doc("Course Enrollment", entry.name) | |||
for entry in xhiveframework.db.get_all("Program Enrollment"): | |||
doc = xhiveframework.get_doc("Program Enrollment", entry.name) | |||
doc.cancel() | |||
doc.delete() |
@@ -0,0 +1,58 @@ | |||
xhiveframework.ui.form.on("Course Schedule", { | |||
refresh: function(frm) { | |||
if (!frm.doc.__islocal) { | |||
frm.add_custom_button(__("Mark Attendance"), function() { | |||
xhiveframework.route_options = { | |||
based_on: "Course Schedule", | |||
course_schedule: frm.doc.name | |||
} | |||
xhiveframework.set_route("Form", "Student Attendance Tool"); | |||
}); | |||
} | |||
if (frm.doc.student_group) { | |||
frm.events.get_instructors(frm); | |||
} | |||
}, | |||
onload: (frm) => { | |||
frm.set_query('instructor', () => { | |||
if (frm.instructors.length) { | |||
return { | |||
'filters':{ | |||
'instructor_name': ["in", frm.instructors] | |||
} | |||
}; | |||
} | |||
else | |||
return; | |||
}); | |||
frm.set_query('course', function() { | |||
return { | |||
query: 'education.education.doctype.program_enrollment.program_enrollment.get_program_courses', | |||
filters: { | |||
'program': frm.doc.program | |||
} | |||
}; | |||
}); | |||
}, | |||
student_group: (frm) => { | |||
frm.events.get_instructors(frm); | |||
}, | |||
get_instructors: (frm) => { | |||
frm.instructors = []; | |||
xhiveframework.call({ | |||
method: 'education.education.api.get_instructors', | |||
args: { | |||
"student_group": frm.doc.student_group | |||
}, | |||
callback: function(data) { | |||
frm.instructors = data.message | |||
} | |||
}) | |||
} | |||
}); |
@@ -0,0 +1,153 @@ | |||
{ | |||
"actions": [], | |||
"allow_import": 1, | |||
"autoname": "naming_series:", | |||
"creation": "2015-09-09 16:34:04.960369", | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"student_group", | |||
"instructor", | |||
"instructor_name", | |||
"column_break_2", | |||
"naming_series", | |||
"program", | |||
"course", | |||
"color", | |||
"section_break_6", | |||
"schedule_date", | |||
"room", | |||
"column_break_9", | |||
"from_time", | |||
"to_time", | |||
"title" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "student_group", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"in_standard_filter": 1, | |||
"label": "Student Group", | |||
"options": "Student Group", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "instructor", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Instructor", | |||
"options": "Instructor", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fetch_from": "instructor.instructor_name", | |||
"fieldname": "instructor_name", | |||
"fieldtype": "Read Only", | |||
"in_global_search": 1, | |||
"label": "Instructor Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "naming_series", | |||
"fieldtype": "Select", | |||
"label": "Naming Series", | |||
"options": "EDU-CSH-.YYYY.-", | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"fieldname": "course", | |||
"fieldtype": "Link", | |||
"in_global_search": 1, | |||
"label": "Course", | |||
"options": "Course", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "color", | |||
"fieldtype": "Color", | |||
"label": "Color", | |||
"print_hide": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_6", | |||
"fieldtype": "Section Break" | |||
}, | |||
{ | |||
"default": "Today", | |||
"fieldname": "schedule_date", | |||
"fieldtype": "Date", | |||
"label": "Schedule Date" | |||
}, | |||
{ | |||
"fieldname": "room", | |||
"fieldtype": "Link", | |||
"label": "Room", | |||
"options": "Room", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "column_break_9", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "from_time", | |||
"fieldtype": "Time", | |||
"in_list_view": 1, | |||
"label": "From Time", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "to_time", | |||
"fieldtype": "Time", | |||
"in_list_view": 1, | |||
"label": "To Time", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
"label": "Title" | |||
}, | |||
{ | |||
"fetch_from": "student_group.program", | |||
"fieldname": "program", | |||
"fieldtype": "Link", | |||
"label": "Program", | |||
"options": "Program", | |||
"read_only": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2022-12-13 15:49:43.766325", | |||
"modified_by": "Administrator", | |||
"module": "Education", | |||
"name": "Course Schedule", | |||
"naming_rule": "By \"Naming Series\" field", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Academics User", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"restrict_to_domain": "", | |||
"sort_field": "schedule_date", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"title_field": "title" | |||
} |