Try ERPNext Buy Support Partners Foundation

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

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.

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® {
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