Help with order of operation in server side script

Good day all,

I am trying a script to automatically load all the academic terms in a child table once an academic year has been chosen.

Here is my script.

class SchoolCalendar(Document):

def __setup__(self):
	self.onload()

def onload(self):
	self.load_terms()

def load_terms(self):
	self.terms = []
	terms = frappe.get_all("Academic Term", filters = {"academic_year": self.academic_year},  fields=["name as term", "term_start_date as start", "term_end_date as end"])
	for term in terms:
		self.append("terms", {
			"term": term.term, "start": term.start, "end": term.end, "length": 12
			})


def validate(self):
	self.terms = []

And I get an error at the frappe.get_all() lines. The self.academic_year is the tripping point.
In the console it works when I replace that self.academic_year with a specific year.
the doctype in question does have the field academic_year.

I have tried to model my script on this one:

I am wondering if it is because I am calling that field before I have even saved the doc.

Any suggestin on what should I changed?

Thanks in advance for any help.

If I replaced self.academic_year by an actual year like “2020-21 (ISS)”. Then the whole script work. What am I missing? :thinking:

I prefer frappe.db.sql with as_dict=1 it is more flexible and ignores permissions by default.

Hey @f_deryckel
Can you please post the entire traceback?
Also, try printing the value of self.academic_year before frappe.get_all is called and see if it is getting the new value

YEs. Sorry I should have posted the error straight away.

See both file.

I really think it is something with initializing that academic_year before saving first the document. Because, if i use a specific value for the academic_year, the whole script work

@f_deryckel

I don’t think the reason is this

Just to confirm can you check if the doctype SchoolCalendar has a field called academic_year?
And please share what full traceback you’re getting in the browser console

Thanks a lot @Mohammad_Hasnain for taking the time to help me figure out my problem.

See the link to the Github

Yes I have double checked that academic_year is a field.
See Json file here.

@f_deryckel
When the onload is called the academic_year is not set
You need to write a listener in your school_calendar.js to check changes in academic_years value
Then call a whitelisted function from the listener to get the students and in the callback set the students in your form

Thank you @Mohammad_Hasnain for checking up.
I did try to follow up the same model as in Guardian.py here
https://github.com/frappe/erpnext/blob/develop/erpnext/education/doctype/guardian/guardian.py

As you can see, in that doctype, there is no call in the .js file with no whitelisted method and it does seem to work. So I not getting why my script is failing.

I have decided to take another approach all together and following the model from program enrollement.
https://github.com/frappe/erpnext/tree/develop/erpnext/education/doctype/program_enrollment

I then manage to make everything work.

Server side

from future import unicode_literals
import frappe
from frappe import _
from frappe.utils import get_link_to_form, getdate, formatdate, date_diff, cint
from frappe.model.document import Document

class SchoolCalendar(Document):

def validate(self):
	if not self.terms:
		self.extend("terms", self.get_terms())
	ay = frappe.get_doc("Academic Year", self.academic_year)
	self.validate_dates()
	self.total_holiday_days = len(self.holidays)
	self.total_number_day = date_diff(ay.year_end_date, ay.year_start_date) - self.total_holiday_days

def get_terms(self):
		self.terms = []
		terms = frappe.get_list("Academic Term", filters = {"academic_year":self.academic_year}, fields=["name as term", "term_start_date as start", "term_end_date as end"])
		for term in terms:
			self.append("terms", {
				"term": term.term, "start": term.start, "end": term.end,
				"length": date_diff(term.end, term.start)
			})
		return terms

and client side

frappe.ui.form.on(‘School Calendar’, {
refresh: function(frm) {

frm.set_query('academic_year', function() {
  return {
    'filters': {
      'school': (frm.doc.school)
    }
  }
});

},

academic_year: function(frm) {
frm.events.get_terms(frm);
},

get_terms: function(frm) {
frm.set_value(‘terms’,);
frappe.call({
method: ‘get_terms’,
doc:frm.doc,
callback: function(r) {
if(r.message) {
frm.set_value(‘terms’, r.message);
}
}
})
}

});

This does seem to work.

@Mohammad_Hasnain, I really appreciated your time and effort for helping me. It is people like you who make this community. Thanks again!!!

1 Like