Adding customization in separated java script file

Hello;

I need to add some customization for sales invoice document, but I do not need to add it for sales_invoice.js or in custom script, I need to add this customization in separated file. How I can do this?

Can I add this script in a file and place it under public/js directory?
Or can I add this script in a file in separated application?

But I need this addition to effect the sales invoice document.
Appreciate the kindly help.

Regards
Bilal

1 Like

Hey ,
If you want to customize the sales invoice doctype. You need to follow these steps

  1. Inside frappe-bench/apps/[app_name]/[app_name] here you can create a folder of Custom

  2. Inside custom folder, Create a folder of sale invoice and then you need to create the files sales_invoice.js, sales_invoice.py and init.py file

  3. Andyou can do customization over here.

  4. Apart from this, you have to add these in hooks.py

For JS File
doctype_js = {
“sales_invoice” : “custom/sales_invoice/sales_invoice.js”,
}

For PY file
doc_events ={
“sales_invoice”:{
“validate”:"project_name.custom.sales_invoice.sales_invoice.validate_project”
}
}

2 Likes

Hello @pooja.m
Thanks a lot for your kindly help and reply, it helped me. But really I need some more clarification to be able to understand it more accurate if possible.

Let us talk about sales invoice doctype as we took it as example. As you know that sales invoice is existed under account module under erpnext, so do you mean that I have to create the Custom directory under this path:
frappe-bench/apps/erpnext/erpnext??
Or I can create a new application (let us name it gold) and then I have to create the Custom directory under: frappe-bench/apps/gold/gold?

  • Why you mentioned the validate? Is it just example?
  • These lines need to be added in the erpnext hook.py or in the hook.py of the new added project?

Regards
Bilal

Hey Bilal,

  1. First you don’t need to make changes in erpnext/hooks.py . For that you have to create app in you site.

  2. For creating application you can follow this link
    https://frappe.io/docs/user/en/tutorial/new-app

  3. And then follow my previous comment

1 Like

I will check them and come back to you. Thank you.

Hello @pooja.m

Wonderful, it worked fine and thanks a lot for you.

Still I need help in two parts:

  1. The same thing: how I can add field for Sales Invoice doctype but not from doctype customization, I need it to be from separate application.

  2. How to customize the dashboard (sales_invoice_dashboard.py) but without losing this customization when doing upgrade?

Regards
Bilal

Hey,

A. There are mainly two ways of adding fields in doctype

  1. By Doctype list
  2. By Customization form

From end users point, it looks nothing different in functionality… But actually its different in terms of how you manage frappe/erpnext in long term.
Its highly recommend to always use Customize form to add custom fields… Its database site specific and you can update frappe and erpnext smoothly.
The reason is… editing doctype directly will affect its repo files e.g. Json files etc… And it can cause conflicts when you update frappe and erpnext.
Unless you want to add custom doctype for custom cases … For this you have to maintain it under custom app to avoid hassles in long term maintenance

Apart from this you can create new doctype same as sales invoice and use it
A good read of the docs and tutorial will clarify all this for you, for example
https://erpnext.org/docs/user/manual/en/customize-erpnext/custom-doctype
https://erpnext.org/docs/user/manual/en/customize-erpnext/customize-form

B. For dashboard, you can refer this

And for linking in dashboard

Hello @pooja.m

So the dashboard can be customized from java script file of separated application (other than erpnext) but using jinja, right?

Regarding to adding field: as it is only possible via Customization Form or Doctype List and it is not possible to have any script in separated application that can add the field through JSON file, then I am thinking in the following and I need your advise (opinion) if possible:
How about building sql script to add all the required fields, so instead of adding the required fields (one after one), then it is possible to run the sql script to add these fields by single command.
What do you think?

Regards
Bilal

Hey,
For dashboard, if you want to make changes in already existed doctype like sales order , quotation. You need to customize it, like if you save quotation doctype as custom_quotation, then you need to add custom_quotation_dashboard.py file .
And about sql script, which added fields , even i have to explore it.:slightly_smiling_face:

Hello @pooja.m

Thank you a lot for your kindly help.
If using custom_quotation_dashboard.py, then it will take the code in the custom_quotation_dashboard.py or it will take the code in the quotation_dashboard.py?

From the other side: there is not inheritance and overwrite feature that can be used in the code to do extending and changing part of the code from another custom file (in custom application) without changing in the original file and without having a problem when doing upgrade. Can you please advise?

Regards
Bilal

Hello @pooja.m

If there is a validate method in the original (default) python file of the doctype, which method will be applied (or which on be applied before the other)? Those in the original python file of the doctype or those in the hook?

Regards
Bilal

Hello @pooja.m
Please I need your help in the following:
I create custom application with the following files:

custom_application/custom/sales_invoice/sales_invoice.py
custom_application/custom/sales_invoice/sales_invoice.js
custom_application/custom/sales_invoice/__ init__.py

The hooks.py of the custom_app is containing the following:
doctype_js = {"Sales Invoice" : "custom/sales_invoice/sales_invoice.js"}

The sales_invoice.py is containing the following:

from __ future__ import unicode_literals
import frappe
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.general_ledger import delete_gl_entries
from erpnext.controllers.accounts_controller import AccountsController
from frappe import utils

@frappe.whitelist()
def get_jewelry_price(jewelry_type):
gold_price = frappe.db.get_single_value(‘Jewelry Settings’, ‘gold_price’)
return gold_price

I need to call this whitelist method from the sales_invoice.js, so what is the correct path for the frappe.call method? I tried a lot of paths but it always give me: The resource you are looking for is not available

Do I need to do anything in the hooks.py?
Or I am calling the method wrongly using wrong path because I am using the following path:

            if (item.item_code) {
                    frappe.call({
                            method: "jewelry.custom.sales_invoice.sales_invoice.get_jewelry_price",
                            args: {jewelry_type: item.jewelry_type},
                            callback: function(r) {
                                    if (r.message) {
                                            item.gold_price = r.message;
                                    }
                                    else {
                                            item.gold_price = 0;
                                    }
                                    refresh_field('items');
                            }
                    });

Regards
Bilal

I believe that because the javascript is related to the Sales Invoice doctype and that is why it is not able to understand the following method path:

method: "jewelry.custom.sales_invoice.sales_invoice.get_jewelry_price",

So do I have to add configuration to the hooks.py (something related to sales_invoice.py same as we did for sales_invoice.js, but I do not know what it could be) or my problem in the path?

Regards
Bilal

Any help of this please?

Hello;

I tried the below command:

bench execute jewelry.custom.sales_invoice.sales_invoice.get_jewelry_price

But it is giving the following error:

ImportError: No module named custom.sales_invoice.sales_invoice

As following:

frappe@Bilal:~/frappe-bench$ bench execute jewelry.custom.sales_invoice.sales_invoice.get_jewelry_price
Traceback (most recent call last):
File “/usr/lib/python2.7/runpy.py”, line 174, in _run_module_as_main
main”, fname, loader, pkg_name)
File “/usr/lib/python2.7/runpy.py”, line 72, in _run_code
exec code in run_globals
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 94, in
main()
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 18, in main
click.Group(commands=commands)(prog_name=‘bench’)
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 764, in call
return self.main(*args, **kwargs)
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 717, in main
rv = self.invoke(ctx)
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py”, line 555, in invoke
return callback(*args, **kwargs)
File “/home/frappe/frappe-bench/env/local/lib/python2.7/site-packages/click/decorators.py”, line 17, in new_func
return f(get_current_context(), *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/commands/init.py”, line 24, in _func
ret = f(frappe._dict(ctx.obj), *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/commands/utils.py”, line 117, in execute
ret = frappe.get_attr(method)(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 919, in get_attr
return getattr(get_module(modulename), methodname)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 704, in get_module
return importlib.import_module(modulename)
File “/usr/lib/python2.7/importlib/init.py”, line 37, in import_module
import(name)
ImportError: No module named custom.sales_invoice.sales_invoice

Below is the files that are contained in the path apps/jewelry/jewelry/custom/sales_invoice/

frappe@Bilal:~/frappe-bench/apps/jewelry/jewelry/custom/sales_invoice$ ls -ltr
total 8
-rw-rw-r-- 1 frappe frappe    0 Mar 13 18:58 __init__.py
-rw-rw-r-- 1 frappe frappe 1418 Mar 16 14:27 sales_invoice.js
-rw-rw-r-- 1 frappe frappe  296 Mar 16 15:06 sales_invoice.py

Appreciate if someone can help me how to do this customization and thanks for the help in advance.

Regards
Bilal

@root13F

Can you please help me in this issue?
I added you because we had post before and you have very good experience in the customization and maintaining it properly.

Regards
Bilal

hello !

This post seems to be solved. Do you still need help ?

Thank you @root13F

Yes it is resolved by adding __init__.py under the custom directory.

Regards
Bilal

1 Like