Update child table values

I want to override autofilled child table values with a custom calculation.

For example, in the Payment Schedule table of a Purchase Invoice, I need to apply a custom calculation for base_payment_amount . However, the default value overrides my custom logic.

So far, the only way I’ve managed to handle this is by forcing the Python backend to set the value, but this causes issues on the frontend where the field doesn’t update or it gets overridden after saving.

How do I fix this issue?

Here’s what I’ve tried, which simply sets amount, base_payment_amount, outstanding, and payment_amount to 0. Currently, anytime I edit the payment term, it overwrites 0 by the default frappe calculation.

function debug_table(frm, cdt, cdn) {
    var data = locals[cdt][cdn];
    data.amount = 0.
    data.base_payment_amount = 0.
    data.outstanding = 0.
    data.payment_amount = 0.
    frappe.model.set_value(cdt, cdn, 'amount', 0.);
    frappe.model.set_value(cdt, cdn, 'base_payment_amount', 0.);
    frappe.model.set_value(cdt, cdn, 'outstanding', 0.);
    frappe.model.set_value(cdt, cdn, 'payment_amount', 0.);
    frm.refresh()
}

function debug_table_no_refresh(frm, cdt, cdn) {
    frappe.model.set_value(cdt, cdn, 'amount', 0.);
    frappe.model.set_value(cdt, cdn, 'base_payment_amount', 0.);
    frappe.model.set_value(cdt, cdn, 'outstanding', 0.);
    frappe.model.set_value(cdt, cdn, 'payment_amount', 0.);
}

function debug_table_parent(frm) {
    frm.doc.payment_schedule.forEach(e => {
        console.log(`hit ${e.name}`)
        var cdt = e.parentfield
        var cdn = e.name
        debug_table_no_refresh(frm, cdt, cdn)
    })
    frm.refresh_fields();
}

frappe.ui.form.on("Payment Schedule", {
    custom_item(frm, cdt, cdn) {
        console.log("HIT custom_item")
        debug_table(frm, cdt, cdn)
    },
    payment_term(frm, cdt, cdn) {
        console.log("HIT payment_term")
        debug_table(frm, cdt, cdn)
    },
})

frappe.ui.form.on("Purchase Invoice", {
    onload(frm) {
        console.log("onload")
        debug_table_parent(frm)
    },
    refresh(frm) {
        console.log("refresh")
        debug_table_parent(frm)
    },
    validate(frm) {
        console.log("validate")
        debug_table_parent(frm)
    },
    after_save(frm) {
        console.log("after_save")
        debug_table_parent(frm)
    },

    before_submit(frm) {
        console.log("before_submit")
    },
    on_submit(frm) {
        console.log("on_submit")
    },
})
1 Like

For future viewers, I’ve found where the function for updating these values occur. It’s located in accounts_controller.py.

To overwrite this, create a new python file somewhere in your application, import AccountsController, and then assign your custom function.

from erpnext.controllers.accounts_controller import AccountsController

def override_validate_payment_schedule_amount(*args, **kwargs):
    # override erpnext validation with custom, per item milestone

    def validate_payment_schedule_amount(self):
        print("CUSTOM VALIDATION!!")
        
    AccountsController.validate_payment_schedule_amount = validate_payment_schedule_amount

Then, this needs to be included into a hook to ensure it’s being called.

doc_events = {
    "*": {
        "onload": "your_app.overrides.accounts_controller.override_validate_payment_schedule_amount"
    }
}