Hi,
Could you please help me in making a small customization?
I wanted to bring the followings fields in the QUICK ENTRY “New customer opening” Form.
- GST number
- Place of Supply
Thanks.
Hi,
Could you please help me in making a small customization?
I wanted to bring the followings fields in the QUICK ENTRY “New customer opening” Form.
Thanks.
This may not be possible as as these fields are maintained at Address level in ERPNext.
I think it is possible as the “Primary Contact” and “Primary Address” fields are also maintained in address table but they are coming in Quick entry view.
Please see the attached screen
shot.@dollar_singh,
look into erpnext/public/js/utils/customer_quick_entry.js
and create_primary_address()
function in erpnext/selling/doctype/customer/customer.py
making the relevant changes in these files should help you archive your objective.
Also, please send a PR once you make this customization.
This may be an intentional exclusion. My experience with bypassing the quick entry screen and trying to do it all in the full screen has had problems as soon as you attempt to add an address BEFORE having saved the record with it’s minimum fields. When I tried to do it in full screen mode, the address never seems to link properly.
Maybe you should try full screen before you waste much effort on adding to quick entry.
Your mileage may vary…
BKM
This is really inconsistent. If the fields are available in quick entry form, they should be made available in full form. It’s hard to make non-technical users understand this behavior. Looks like this should be made more consistent.
Check this out.
The problem is not about how to do it. The problem is with the inconsistency. The quick entry form has customer address fields while the actual customer form does not have it.
Exactly, I too don’t know why it is that way.
But, Customization Helps!
I tried that but can’t figure out a way to make address fields visible in the full form when adding a new customer.
erpnext/erpnext/public/js/utils/customer_quick_entry.js
you can edit here…and for trigger any event you need to use hook
We did the same for our customer entry form.
IT Had to be done, especially for the PRIMARY ADDRESS field.
Did you know the Customer Form holds the PRIMARY ADDRESS in a “DATA” field and you can’t even change its field type using Customize Form.
Who holds an address data inside a 140 character limited field anywway?
Not Just that, an address created with Quick Entry dialogue is classified as a billing address, and that is filtered out of the “Customer Primary Address” link field? You can’t select the address you just set on the quick entry form on the Main Customer record as it’s “Customer Primary Address”
Why? This design makes absolute no sense, It basically asked you to create two separate Address for 1 customer EVEN IF their address is the same!
In the end we customized the Customer Form and hide all those system fields and created 1 single TEXT only field to hold the Customer’s Address on the customer form.
It is possible and relatively not hard to customize quick entry form.
hook.py
app_include_js = [
'assets/appname/js/customer_quick_entry.js',
]
doc_events = {
'Customer': {
'on_update': 'appname.appname.customer_quick_entry.custom_customer_info'
}
}
appname/appname/public/js/customer_quick_entry.js
to override quick entry function. Field with same name will get copied to customer datafrappe.provide('frappe.ui.form');
frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
// copied from `erpnext/erpnext/public/js/utils/customer_quick_entry.js`
init: function(doctype, after_insert) {
this.skip_redirect_on_error = true;
this._super(doctype, after_insert);
},
render_dialog: function() {
this.mandatory = this.get_field();
this._super();
},
get_field: function() {
const variantFields = [
{
label: __('Full Name'),
fieldname: 'customer_name',
fieldtype: 'Data',
},
{
fieldtype: 'Section Break',
},
{
label: __('Email Id'),
fieldname: 'email',
fieldtype: 'Data',
options: 'Email',
},
{
label: __('Gender'),
fieldname: 'gender',
fieldtype: 'Link',
options: 'Gender',
},
{
fieldtype: 'Column Break',
},
{
label: __('Mobile Number'),
fieldname: 'mobile',
fieldtype: 'Data',
},
{
label: __('Birthdate'),
fieldname: 'birthdate',
fieldtype: 'Date',
},
{
fieldtype: 'Section Break',
label: __('Tax Details'),
},
{
label: __('Tax ID'),
fieldname: 'tax_id',
fieldtype: 'Data',
},
{
label: __('Address Line 1'),
fieldname: 'address_line1',
fieldtype: 'Data',
},
{
label: __('Address Line 2'),
fieldname: 'address_line2',
fieldtype: 'Data',
},
{
label: __('ZIP Code'),
fieldname: 'pincode',
fieldtype: 'Data',
},
{
fieldtype: 'Column Break',
},
{
label: __('Branch'),
fieldname: 'branch',
fieldtype: 'Data',
},
{
label: __('City'),
fieldname: 'city',
fieldtype: 'Data',
},
{
label: __('State'),
fieldname: 'state',
fieldtype: 'Data',
},
{
label: __('Country'),
fieldname: 'country',
fieldtype: 'Link',
options: 'Country',
default: 'Thailand',
},
{
label: __('Customer POS Id'),
fieldname: 'customer_pos_id',
fieldtype: 'Data',
hidden: 1,
},
];
return variantFields;
},
});
import frappe
from frappe.utils import cstr
from frappe import _
def custom_customer_info(doc, method):
# this function will get call `on_update` as we define in hook.py
add_address_info(doc)
def add_address_info(doc):
if doc.flags.is_new_doc and doc.get('address_line1'):
# this name construct should work
# because we just create this customer
# Billing is default type
# there shouldn't be any more address of this customer
address_name = (
cstr(doc.name).strip() + '-' + cstr(_('Billing')).strip()
)
address_doc = frappe.get_doc('Address', address_name)
# adding custom data to address
address_doc.branch = doc.get('branch')
address_doc.save()
I came across the same issue, I needed to add first_name
and last_name
fields into the quickentry for Customer and Supplier, but using a custom app for overriding them. Here is how I solved it:
first_name
and last_name
fields to Customer and Supplier doctypecustom_app
for the name of your app):
override_doctype_class = {
"Supplier": "custom_app.custom_app.customizations.SuncycleSupplier",
"Customer": "custom_app.custom_app.customizations.SuncycleCustomer"
}
app_include_js = "/assets/js/custom_app.min.js"
public/build.json
file:{
"js/custom_app.min.js": [
"public/js/custom_app_supplier_quick_entry.js",
"public/js/custom_app_customer_quick_entry.js"
]
}
public/js/custom_app_customer_quick_entry.js
for adding the fields:frappe.provide('frappe.ui.form');
frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
init: function(doctype, after_insert, init_callback, doc, force) {
this._super(doctype, after_insert, init_callback, doc, force);
this.skip_redirect_on_error = true;
},
render_dialog: function() {
this.mandatory = this.mandatory.concat(this.get_variant_fields());
this._super();
},
get_variant_fields: function() {
var variant_fields = [{
fieldtype: "Section Break",
label: __("Primary Contact Details"),
collapsible: 1
},
{
label: __("First Name"),
fieldname: "first_name",
fieldtype: "Data"
},
{
label: __("Last Name"),
fieldname: "last_name",
fieldtype: "Data"
},
{
fieldtype: "Column Break"
},
{
label: __("Email Id"),
fieldname: "email_id",
fieldtype: "Data"
},
{
label: __("Mobile Number"),
fieldname: "mobile_no",
fieldtype: "Data"
},
{
fieldtype: "Section Break",
label: __("Primary Address Details"),
collapsible: 1
},
{
label: __("Address Line 1"),
fieldname: "address_line1",
fieldtype: "Data"
},
{
label: __("Address Line 2"),
fieldname: "address_line2",
fieldtype: "Data"
},
{
label: __("ZIP Code"),
fieldname: "pincode",
fieldtype: "Data"
},
{
fieldtype: "Column Break"
},
{
label: __("City"),
fieldname: "city",
fieldtype: "Data"
},
{
label: __("State"),
fieldname: "state",
fieldtype: "Data"
},
{
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
options: "Country"
},
{
label: __("Customer POS Id"),
fieldname: "customer_pos_id",
fieldtype: "Data",
hidden: 1
}];
return variant_fields;
},
})
(do the same for supplier)
5. Create a python file in custom_app/custom_app/customizations.py
:
import frappe
from erpnext.buying.doctype.supplier.supplier import Supplier
from erpnext.selling.doctype.customer.customer import Customer
class SuncycleSupplier(Supplier):
def create_primary_contact(self):
if not self.supplier_primary_contact:
if self.mobile_no or self.email_id or self.first_name or self.last_name:
contact = make_contact(self)
self.db_set("supplier_primary_contact", contact.name)
self.db_set("mobile_no", self.mobile_no)
self.db_set("email_id", self.email_id)
self.db_set("first_name", self.first_name)
self.db_set("last_name", self.last_name)
class SuncycleCustomer(Customer):
def create_primary_contact(self):
if not self.customer_primary_contact and not self.lead_name:
if self.mobile_no or self.email_id or self.first_name or self.last_name:
contact = make_contact(self)
self.db_set("customer_primary_contact", contact.name)
self.db_set("mobile_no", self.mobile_no)
self.db_set("email_id", self.email_id)
self.db_set("first_name", self.first_name)
self.db_set("last_name", self.last_name)
def make_contact(args, is_primary_contact=1):
contact = frappe.get_doc(
{
"doctype": "Contact",
"first_name": args.get("name"),
"is_primary_contact": is_primary_contact,
"links": [{"link_doctype": args.get("doctype"), "link_name": args.get("name")}],
}
)
if args.get("email_id"):
contact.add_email(args.get("email_id"), is_primary=True)
if args.get("mobile_no"):
contact.add_phone(args.get("mobile_no"), is_primary_mobile_no=True)
if args.get("first_name"):
contact.first_name = args.get("first_name")
if args.get("last_name"):
contact.last_name = args.get("last_name")
contact.insert()
return contact
I followed these steps and set it up locally. There were no changes in the site nor did I get any error. Please help me.
All I need to do is change the mobile number data field type to phone field type from my custom app
please help me.
Hey
Additionally to what others have shared, for my quick form customisation to work, I copied the js source code into my custom app.
(i’m using v15, and the build.json isn’t necessary. Though I did create a js bundle file to include the custom js below)
something like this:
frappe.provide("frappe.ui.form")
frappe.ui.form.CustomerQuickEntryForm = class CustomerQuickEntryForm extends (
frappe.ui.form.QuickEntryForm
) {
constructor(doctype, after_insert, init_callback, doc, force) {
super(doctype, after_insert, init_callback, doc, force)
this.skip_redirect_on_error = true
}
...