frappe / erpnext

Free and Open Source Enterprise Resource Planning (ERP)
https://erpnext.com
GNU General Public License v3.0
21.76k stars 7.31k forks source link

billing_address not set in Purchase Order generated from Sales Order #25473

Open gdbaldw opened 3 years ago

gdbaldw commented 3 years ago

A new Purchase Order automatically sets billing_address, #22950, @deepeshgarg007. However, a Purchase Order generated from a Sales Order, does not. Specifically, I submitted a dropship Sales Order, and from that created a dropship Purchase Order.

As a fix, I copied the following code block into a clientside script for Purchase Order (deleting this. and me.):

https://github.com/frappe/erpnext/blob/4a805b5622cde87a9436113e1d7f9d1dcf71172b/erpnext/public/js/controllers/transaction.js#L886-L895

Shouldn't the above code block automatically execute when Purchase Order is generated from Sales Order?

gdbaldw commented 3 years ago

A better fix is a Server Script, so that value is set without needing to open the document:

#
# Bug: PO created from SO does not set the Billing Address
# Impact: If draft PO is submitted without an update, the Billing Address is incorrect.
# Without this fix: User must open and save the automatically updated PO, before submit.
# With this fix: User may submit from the PO list, without ever opening the PO.
#

def get_default_address(doctype, name, sort_key='is_primary_address'):
    '''Returns default Address name for the given doctype, name'''
    if sort_key not in ['is_shipping_address', 'is_primary_address']:
        return None

    out = frappe.db.sql(""" SELECT
            addr.name, addr.%s
        FROM
            `tabAddress` addr, `tabDynamic Link` dl
        WHERE
            dl.parent = addr.name and dl.link_doctype = %s and
            dl.link_name = %s and ifnull(addr.disabled, 0) = 0
        """ %(sort_key, '%s', '%s'), (doctype, name))

    if out:
        return sorted(out, key = lambda x: x[1])[0][0]
        # return min(out, key = lambda x: x[1])[0]
        # min is a restricted function
    else:
        return None

def get_address_template(address):
    result = frappe.db.get_value("Address Template", \
        {"country": address.get("country")}, "template")

    if not result:
        result = frappe.db.get_value("Address Template", \
            {"is_default": 1}, "template")

    if not result:
        frappe.throw(_("No default Address Template found. Please create a new one from Setup > Printing and Branding > Address Template."))
    else:
        return result

doc.billing_address = get_default_address('Company', doc.company)

if doc.billing_address:
    address = frappe.get_doc('Address', doc.billing_address)
    template = get_address_template(address)
    doc.billing_address_display = frappe.render_template(template, address.as_dict())