Customization in New customer - QUICK ENTRY FORM

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.

  1. GST number
  2. Place of Supply

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… :grin:

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! :slight_smile:

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.

2 Likes

It is possible and relatively not hard to customize quick entry form.

  1. Add custom js to app using 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'
    }
}
  1. Add custom js to appname/appname/public/js/customer_quick_entry.js to override quick entry function. Field with same name will get copied to customer data
frappe.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;
	},
});
  1. Write address data
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()

4 Likes

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:

  1. Add first_name and last_name fields to Customer and Supplier doctype
  2. Change this in my app’s hooks.py (replace custom_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"
  1. Create a 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"
	]
}
  1. Create the JavaScript quickentry file for customer in 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