How to get the preferred billing address for a customer?

In a custom form in my app, I’m trying to use Javascript to get the preferred billing address for the Customer link field in the form (called ‘customer’).
I’m working on the principle that I should get all the addresses linked to the customer and select the address where is_primary_address=1.

I’ve tried the code below but I clearly haven’t got the linked document filter correct since I get an error: “Field not permitted in query: link_doctype”.

I would welcome any advice to help create the correct filter.

		frappe.db.get_list('Address', {
			pluck: 'name',
			filters: {
				link_doctype: 'Customer',
				link_name: frm.doc.customer
			},
			order_by: 'is_primary_address desc',
		}).then(records => {
			billing_address = records[0];
			frm.set_value("billing_address", billing_address);
		})

I have figured out the dynamic link part of the filter now:

		var billing_address = "";

		frappe.db.get_list('Dynamic Link', {
			filters: {'link_doctype': 'Customer', 'link_name': frm.doc.customer, 'parenttype': 'Address'},
			fields: ['parent'],
		}).then(records => {
			if( records ) {
				billing_address = records[0]['parent'];
			}

			frm.set_value("billing_address", billing_address);
		})

This allows me to get all the addresses for a customer. However, I still can’t filter on “is_primary_address” so my code is just picking the first address, which may not be the one I want. Now that I have an array of addresses, I could loop through and check each of them for the primary address flag, unless I can find a way to add it to the filter.

The problem seems to be that the query is returning only a list of document names rather than objects with the primary address flag included so "order_by: ‘is_primary_address’ " causes an error.

Hi there,

The issue here is that get_list doesn’t fetch data from child tables when polling a parent or data from parent tables when polling a child. (Also, without the parent_doctype field, your code in your second post works for me only when logged in as Administrator.)

You can do what you want to do with two api calls:

let addresses = await frappe.db.get_list('Dynamic Link', {
   filters: {'link_doctype': 'Customer', 'link_name': frm.doc.customer, 'parenttype': 'Address'},
   pluck: "parent",
   parent_doctype: "Address"
})

Then, you can get a list of the parent doctypes matched:

frappe.db.get_list('Address', {
   filters: {'name': ["in", addresses]}, 
   fields: ['*']
})

If you’d prefer to avoid the second API call, the easiest way is probably to create a new server side method to handle the processing, either in a custom app or a server script.

Thank you very much, Peter. That got me to where I wanted to be. For some reason the “await” keyword threw a syntax error in my code but using asynchronous calls worked fine.
I’m happy to use two calls. In fact, I also want to get the preferred shipping address so I can get the list of addresses just once and then use that to get the preferred shipping and billing addresses.

		frappe.db.get_list('Dynamic Link', {
			filters: {'link_doctype': 'Customer', 'link_name': frm.doc.customer, 'parenttype': 'Address'},
			fields: ['parent'],
			pluck: 'parent',
			parent_doctype: "Address"
		}).then(addresses => {
			if( addresses )
			{
				// Get preferred billing address
				frappe.db.get_list('Address', {
					filters: {'name': ["in", addresses]}, 
					fields: ['name'],
					pluck: 'name',
					order_by: 'is_primary_address desc'
				}).then(records=> {
					billing_address = records[0];
					frm.set_value("billing_address", billing_address);
				});

				// Get preferred shipping address
				frappe.db.get_list('Address', {
					filters: {'name': ["in", addresses]}, 
					fields: ['name'],
					pluck: 'name',
					order_by: 'is_shipping_address desc'
				}).then(records=> {
					shipping_address = records[0];
					frm.set_value("shipping_address", shipping_address);
				});
			}
		})

Great! Glad it worked.

The await keyword will throw an error if not in an async function. Using then works just as well or better.

In your get_list calls, it’s redundant to have both fields and pluck arguments, but I don’t think there’s any harm in it.

In any event, it would be very nice if the get_list method could include child table data, but so far that hasn’t been added.

Thanks, Peter.
Interestingly, I had tried omitting the “fields” argument but this led to get_list failing with a KeyError on “parent”. Not on “name”, though. Odd.

I’m happy with this solution. As you say, it would be nice if get_list included child table data but now I know how to do it, it isn’t a big problem.

1 Like