Script error Tutorial ERPNext

I’m on the part of create button to send e-mail of the tutorial of app development.

File “/home/frappe/frappe-bench/apps/frappe/frappe/desk/form/save.py”, line 22, in savedocs
doc.save()
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 230, in save
return self._save(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 263, in _save
self.run_before_save_methods()
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 771, in run_before_save_methods
self.run_method(“validate”)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 666, in run_method
out = Document.hook(fn)(self, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 891, in composer
return composed(self, method, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 874, in runner
add_to_return_value(self, fn(self, *args, **kwargs))
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 660, in
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/meeting/meeting/meeting/doctype/meeting/meeting.py”, line 16, in validate
if attendee.attendee in found:
NameError: global name ‘found’ is not defined

Traceback (most recent call last):
File “/home/frappe/frappe-bench/apps/frappe/frappe/app.py”, line 55, in application
response = frappe.handler.handle()
File “/home/frappe/frappe-bench/apps/frappe/frappe/handler.py”, line 21, in handle
data = execute_cmd(cmd)
File “/home/frappe/frappe-bench/apps/frappe/frappe/handler.py”, line 52, in execute_cmd
return frappe.call(method, **frappe.form_dict)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 907, in call
return fn(*args, **newargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/desk/form/save.py”, line 22, in savedocs
doc.save()
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 230, in save
return self._save(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 263, in _save
self.run_before_save_methods()
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 771, in run_before_save_methods
self.run_method(“validate”)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 666, in run_method
out = Document.hook(fn)(self, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 891, in composer
return composed(self, method, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 874, in runner
add_to_return_value(self, fn(self, *args, **kwargs))
File “/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py”, line 660, in
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/meeting/meeting/meeting/doctype/meeting/meeting.py”, line 16, in validate
if attendee.attendee in found:
NameError: global name ‘found’ is not defined

Can you share your meeting.py code? Looks like found isn’t declared before line 16.

Sure!

frappe.ui.form.on(“meeting”, {
send_email: function(frm) {
if (frm.doc.status === “Planned”) {
frappe.call({
method: “meeting.api.send_invitation_emails”,
args: {
meeting: frm.doc.name
}
});
}
},
});

frappe.ui.form.on(“meeting attendee”, {
attendee: function(frm, cdt, cdn) {
var attendee = frappe.model.get_doc(cdt, cdn);
if (attendee.attendee){
//if attendee, get full name
frappe.call({
method: “meeting.meeting.doctype.meeting.meeting.get_full_name”,
args: {
attendee: attendee.attendee
},
callback: function(r){
frappe.model.set_value(cdt, cdn, “full_name”, r.message);
}
});
}
else {
//if no attendee clear full name
frappe.model.set_value(cdt, cdn, “full_name”, null);
}
},
});

This is the meeting.js file that you have posted. Please post the meeting.py file. That’s where the error points to.

meeting.py:
class meeting(Document):
def validate(self):
for attendee in self.attendees:
if not attendee.full_name:
attendee.full_name = get_full_name(attendee.attendee)

        if attendee.attendee in found:
            frappe.throw(_("Attendee {0} entered twice").format(attendee.attendee))

        found.append(attendee.attendee)

#mark this function
@frappe.whitelist()
def get_full_name(attendee):
user = frappe.get_doc(“User”, attendee)

#concatenate by name if it has value
return " ".join(filter(None, [user.first_name, user.middle_name, user.last_name]))

api.py:
import frappe

@frappe.whitelist()
def send_invitation_email(meeting):
meeting = frappe.get_doc(“meeting”, meeting)
meeting.check_permission(“email”)
if meeting.status == “Planned”:
frappe.sendmail(
recipients = [d.attendee for d in meeting.attendees],
sender = frappe.session.user,
subject = meeting.title,
message = meeting.invitation_message,
reference_doctype = meeting.doctype,
reference_name = meeting.name,
as_bulk = True
)

    meeting.status = "Invitation Sent"
    meeting.save()

    frappe.msgprint(_("Invitation Sent"))

else:
    frappe.msgprint(_("Meeting Status must be Planned"))

What’s @frappe.whitelist() ?

Hi
whitelisted methods allows you to call them from client side.
https://frappe.github.io/frappe/user/en/guides/basics/frappe_ajax_call

For your issue, simply add a found list

found = []

That should fix the first error you had.

Where i add this?

Anywhere before line 16 in the same method validate

The same error…
Code:
class meeting(Document):
def validate(self):
for attendee in self.attendees:
if not attendee.full_name:
attendee.full_name = get_full_name(attendee.attendee)

        if attendee.attendee in found:
            frappe.throw(_("Attendee {0} entered twice").format(attendee.attendee))
            found = []

        found.append(attendee.attendee)

'#mark this function
@frappe.whitelist()
def get_full_name(attendee):
user = frappe.get_doc(“User”, attendee)

#concatenate by name if it has value
return " ".join(filter(None, [user.first_name, user.middle_name, user.last_name]))'

It needs to be before found is previously referenced. Put it after the for attendee in self.attendee:

I’d suggest you take a course in python programming. It looks like a lot of the errors you’re having a related to python syntax.The forum here is a really good resource for working with the frappe and erpnext libraries, but isn’t meant to be for debugging everyones python or javascript code.

Actually, thats not the place to add!
You are accessing the variable before its declared.
Add found right after def validate

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

Remove found = [] after the frappe.throw statement.

Hope it helps!