Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ frappe.ui.form.on('Program Enrollment', {
}
}


// frm.set_query('student', function() {
// return{
// query: 'education.education.doctype.program_enrollment.program_enrollment.get_students',
Expand All @@ -39,9 +38,9 @@ frappe.ui.form.on('Program Enrollment', {
// });
},

refresh: function(frm) {
refresh: function (frm) {
if (!frm.program_courses?.length && frm.doc.program) {
frm.events.set_program_courses(frm);
frm.events.set_program_courses(frm)
}
},

Expand Down Expand Up @@ -84,16 +83,16 @@ frappe.ui.form.on('Program Enrollment', {
})
},

set_program_courses:function(frm) {
frm.program_courses = [];
set_program_courses: function (frm) {
frm.program_courses = []
frappe.call({
method: 'get_courses',
doc: frm.doc,
callback: function(r) {
callback: function (r) {
if (r.message) {
frm.program_courses = r.message
}
}
},
})
},
})
Expand All @@ -108,13 +107,17 @@ frappe.ui.form.on('Program Enrollment Course', {
if (val.course) course_list.push(val.course)
})

let program_courses = (frm.program_courses || []).map(e => e.course)
let program_courses = (frm.program_courses || []).map((e) => e.course)

if (!program_courses.length) {
return { filters: [['Course', 'name', 'not in', course_list]] };
return { filters: [['Course', 'name', 'not in', course_list]] }
} else {
return { filters: [['Course', 'name', 'not in', course_list],
['Course', 'name', 'in', program_courses]] }
return {
filters: [
['Course', 'name', 'not in', course_list],
['Course', 'name', 'in', program_courses],
],
}
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion education/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# include js, css files in header of desk.html
# app_include_css = "/assets/education/css/education.css"
# app_include_js = "/assets/education/js/education.js"
app_include_js = "education.bundle.js"
app_include_js = ["education.bundle.js", "/assets/education/js/html5-qrcode.min.js"]

# include js, css files in header of web template
# web_include_css = "/assets/education/css/education.css"
Expand Down
Empty file added education/library/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions education/library/apis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import frappe
from library.utils import create_media_copies


@frappe.whitelist()
def create_copies(media, count=1, force=0):
try:
force = int(force or 0)

result = create_media_copies(media=media, count=int(count or 1), force=bool(force))

return result

except Exception as e:
frappe.log_error(frappe.get_traceback(), "Create Copies API Error")
frappe.throw(str(e))
Empty file.
Empty file.
78 changes: 78 additions & 0 deletions education/library/doctype/author/author.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
frappe.ui.form.on('Author', {
refresh(frm) {
load_books(frm)
},
})

function load_books(frm) {
if (!frm.doc.name || frm.is_new()) return

frappe.call({
method: 'frappe.client.get_list',
args: {
doctype: 'Library Media',
fields: ['name', 'title'],
limit_page_length: 100,
},
callback: function (r) {
let media_list = r.message || []

let results = []

let promises = media_list.map((m) => {
return frappe.db.get_doc('Library Media', m.name)
})

Promise.all(promises).then((docs) => {
docs.forEach((doc) => {
;(doc.authors || []).forEach((a) => {
if (a.author === frm.doc.name) {
results.push({
parent: doc.name,
title: doc.title,
role: a.role,
})
}
})
})

if (!results.length) {
frm
.get_field('books_written')
.$wrapper.html(
`<p style="color: grey;">No media found for this author</p>`
)
return
}

let html = `
<table class="table table-bordered">
<thead>
<tr>
<th>Media</th>
<th>Role</th>
</tr>
</thead>
<tbody>
`

results.forEach((row) => {
html += `
<tr>
<td>
<a href="/app/library-media/${row.parent}">
${row.title || row.parent}
</a>
</td>
<td>${row.role || '—'}</td>
</tr>
`
})

html += `</tbody></table>`

frm.get_field('books_written').$wrapper.html(html)
})
},
})
}
74 changes: 74 additions & 0 deletions education/library/doctype/author/author.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:author_name",
"creation": "2026-04-29 15:28:02.536442",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"author_name",
"address",
"section_break_sxtg",
"books_written_html",
"books_written"
],
"fields": [
{
"fieldname": "address",
"fieldtype": "Link",
"label": "Address",
"options": "Address"
},
{
"fieldname": "section_break_sxtg",
"fieldtype": "Section Break"
},
{
"fieldname": "author_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Author Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "books_written_html",
"fieldtype": "Column Break"
},
{
"fieldname": "books_written",
"fieldtype": "HTML",
"label": "Books Written"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2026-05-05 20:42:00.125082",
"modified_by": "Administrator",
"module": "Library",
"name": "Author",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"row_format": "Dynamic",
"rows_threshold_for_grid_search": 20,
"show_title_field_in_link": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "author_name"
}
9 changes: 9 additions & 0 deletions education/library/doctype/author/author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

# import frappe
from frappe.model.document import Document


class Author(Document):
pass
Empty file.
Loading
Loading