Custom script with doctype : failed to get method

Hi

Busy with my next custom app, this time with a doctype.

Procedure I followed

Developer mode is active

bench new-app custom_app
bench --site site2.local install-app custom_app

new app is listed in …/sites/apps.txt

On the Desk
goto Module Def List and create new module linked to app “custom_app”

create new doctype “BDH” linked to module “customisation”
on server, in folder … custom_app/customisation/doctype/bdh in the file bdh.py, I entered my
python code… (using file that was auto created)

import frappe
from frappe.model.document import Document

class BDH(Document):
      pass

@frappe.whitelist()
def populate_check_items(bdh_template, bdh):

   ....... rest of pythin code...........

And in my client script, I call the method like this …

frappe.call({
       method:  ' custom_app.customisation.doctype.bdh.populate_check_items',

after creating my PY-file

bench --site site2.local migrate
bench restart

I also changed permissions on …bdh.py

chmod 777 bdh.py

And the error I get is … (when I select the related field on the BDH-document )

Failed to get method for command
custom_app.customisation.doctype.bdh.populate_check_items  with module
custom_app.customisation.doctype.bdh  has no attribute
populate_check_items

Would apprecaite some assistance with this, please
Thank you

Can you share the screenshot of the error.
Also in you frappe.call Client Script I see space is there before custom_app, can you remove it and check again.

Thank you @Sandeep_Kakde for your assistance. I appreicaet you taking the time

I will have to see if I can generate the error again to take a screenshot, but it was a prompt and I copied
all the text of the prompt into the message in my previous message.

I have however, tried many other things and have got code now that does not generate any errors.
But I will have to relook at my entrire approach for this project. I will post my existing code, but perhaps
I must start at what I want to achieve…

Custom doctype : BDH
Many fields on BDH. MOst important is
BDH Template ; link to doctype BDH Template. This contains a preconfigured template of parameters
that the user can select, after pre-configuring such a template.
When choosing a BDH Template, it populates the other important item in the BDH doctype which is
a child table called “check_items”

Ultimately I would like to achieve this by writing code for the bdh.js and bdh.py in the folder
…frappe-bench/apps/custom_app/custom_app/customisation/doctype/bdh

On a previous script I did I could call a method in a file api.py in the folder
…/frappe-bench/apps/scrap_item_app/scrap_item_app

But in this case I could not call a method ithe folder
…frappe-bench/apps/custom_app/custom_app/customisation/doctype/bdh

I think one of the big problems is me. I have done a number of client scripts and I am now taking on
some server-side / custom-doctype scripting which is tripping me up.

Let me print my existing code which sort-off-works. It certainly does not have errors. THen you can
get a picture of what I want to do.

Client side code …

frappe.ui.form.on('BDH', {
    bdh_template: function(frm) {
        if (frm.doc.bdh_template) {
            frappe.show_alert("Template", 5);
            frappe.call({
                method: 'custom_app.api.get_template',
                args: {
                    template_name: frm.doc.bdh_template,
                    build: frm.doc.name
                },
                callback: function(r) {
                    if (!r.exc) {
                        frm.refresh_field('check_items');
                    }
                }
            });
            frappe.show_alert("Refresh Table", 5);
            frm.refresh();
            frm.refresh_field('check_items');
        }
    },
    refresh: function(frm) {
        frm.refresh_field('check_items');
    }
});

And now the server side code that is in api.py in the folder
…/frappe-bench/custom_app/custom_app

import frappe

@frappe.whitelist()
def get_template(template_name, build):

    template = frappe.get_doc("BDH Template", template_name)
    bdh_doc = frappe.get_doc("BDH", build)
    bdh_doc.check_items = []

    for parameter in template.bdh_parameters:
        bdh_doc.append("check_items", {
            "parameter": parameter.bdh_parameter,
            "checked": 0,
            "employee": "",
            "date": None
        })

    bdh_doc.save()

My goal is to migrate the client side code to the bdh.js
and to migrate the code in api.py to bdh.py

One big problem with the code that I have put above, is the fact that I pass the parent doc as a
argument. This implies that I have to save the doc first so that it has a proper name to be passed
as an argument. But when you save the doc, the “bdh_template” value in the dtabase table
is saved as NULL ( no selection made yet ) So when the user selects a template, the template name
does not appear in the bdh_template field.

If someone could offer some guidace I would appreciate it

It should be like this

custom_app.customisation.doctype.bdh.bdh.populate_check_items

Thank you @mohitchechani for taking the time to assist.

Update …

Thank you for the assistance. I have been trying many things and in the end I decided to go for broke and put everything
on the server side. i.e. not use client side scripting.

I put my JS in my …/doctype/bdh/bdh.js file and my PY code in …/doctype/bdh/bdh.py file.

This is my code that seems to be working …

frappe.ui.form.on('BDH', {
//  refresh: function(frm) {

//  }
    bdh_template: function(frm) {
        if (frm.doc.bdh_template) {
            return frm.call({
                method: "get_template",
                doc: frm.doc,
                callback: function() {
                    refresh_field('check_items');
                }
            });
        }
    } 
});

PY code

import frappe
from frappe.model.document import Document


def get_template_details(template):
    if not template:
        return []
    frappe.msgprint("Detail")
    return frappe.get_all(
        "BDH Template Parameter Item",
        fields=[
            "bdh_parameter",
        ],
        filters={"parenttype": "BDH Template", "parentfield": "bdh_parameters"},
        order_by="idx",
    )



class BDH(Document):

    def validate(self):
        frappe.msgprint("Validate")

    @frappe.whitelist()
    def get_template(self):
#       frappe.msgprint("Get Template")

        self.set("check_items", [])
        parameters = get_template_details(self.bdh_template)
        for d in parameters:
            child = self.append("check_items", {"parameter": d.bdh_parameter})
            child.update(d)

Thank you