well, i was hoping for this to happen in the database though, but a client script seems to be working for me.
let me share it.
frappe.listview_settings[‘Purchase Invoice’] = {
add_fields: [“workflow_state”],
onload: function(listview) {
// Button 1: Set Individual Audit Amounts
listview.page.add_inner_button(__(‘Set Individual Audit Amounts’), function() {
// Get selected items
const selected_docs = listview.get_checked_items();
// Ensure at least one document is selected
if (!selected_docs.length) {
frappe.msgprint(__('Please select documents first.'));
return;
}
// Fetch details (grand_total, bill_no) for all selected documents
let promises = selected_docs.map(doc => {
return new Promise((resolve, reject) => {
frappe.call({
method: "frappe.client.get",
args: {
doctype: "Purchase Invoice",
name: doc.name
},
callback: function(r) {
if (r && r.message) {
resolve({
name: doc.name,
grand_total: r.message.grand_total,
bill_no: r.message.bill_no
});
} else {
reject();
}
}
});
});
});
// After fetching the details, show the dialog
Promise.all(promises).then(results => {
let fields = [];
results.forEach(doc => {
fields.push({
label: __('Bill No: {0}, Grand Total: {1}', [doc.bill_no, format_currency(doc.grand_total)]),
fieldname: `audit_amount_${doc.name}`,
fieldtype: 'Currency',
reqd: 0, // Changed to optional so we can handle missing input
default: doc.grand_total // Set default value to grand total
});
});
// Create a dialog with individual audit amount fields for each selected document
let dialog = new frappe.ui.Dialog({
title: __('Enter Audit Amounts'),
fields: fields,
primary_action_label: __('Submit'),
primary_action(values) {
// Loop through selected documents and update audit amount for each
results.forEach((doc) => {
// Get the audit amount value entered by the user or default it to the grand total
let audit_amount = values[`audit_amount_${doc.name}`] || doc.grand_total;
// First, update custom_audit_amount field for each document
frappe.call({
method: "frappe.client.set_value",
args: {
doctype: "Purchase Invoice",
name: doc.name,
fieldname: "custom_audit_amount",
value: audit_amount
},
callback: function(response) {
if (!response.exc) {
frappe.msgprint(__('Audit amount set for Bill No: {0}', [doc.bill_no]));
// Calculate the difference: grand_total - custom_audit_amount
let difference = doc.grand_total - audit_amount;
// Update custom_difference_bw_grand__audit with the calculated difference
frappe.call({
method: "frappe.client.set_value",
args: {
doctype: "Purchase Invoice",
name: doc.name,
fieldname: "custom_difference_bw_grand__audit",
value: difference
},
callback: function() {
frappe.msgprint(__('Difference set for Bill No: {0}', [doc.bill_no]));
}
});
}
}
});
});
// Close the dialog and refresh the list view after updating
dialog.hide();
listview.refresh();
}
});
// Show the dialog
dialog.show();
}).catch(() => {
frappe.msgprint(__('Failed to fetch data for some Purchase Invoices.'));
});
});
// Button 2: Update Workflow Dates
listview.page.add_inner_button(__('Update Workflow Dates'), function() {
const selected_docs = listview.get_checked_items();
if (selected_docs.length > 0) {
process_invoices(selected_docs);
} else {
frappe.msgprint(__('Please select at least one Purchase Invoice.'));
}
});
}
};
function process_invoices(invoices) {
let current_index = 0;
function show_prompt_for_invoice() {
if (current_index >= invoices.length) {
frappe.msgprint(__('All selected Purchase Invoices have been processed.'));
return;
}
const invoice = invoices[current_index];
frappe.call({
method: 'frappe.client.get',
args: {
doctype: 'Purchase Invoice',
name: invoice.name
},
callback: function(r) {
if (!r.exc) {
const doc = r.message;
frappe.prompt([
{
label: `On Hold Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_on_hold_date',
fieldtype: 'Date',
description: 'Enter On Hold Date'
},
{
label: `On Query Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_on_query_date',
fieldtype: 'Date',
description: 'Enter On Query Date'
},
{
label: `Director's Signing Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_directors_signing_date',
fieldtype: 'Date',
description: "Enter Director's Signing Date"
},
{
label: `Audit Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_audit_date',
fieldtype: 'Date',
description: 'Enter Audit Date'
},
{
label: `Signing Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_signing_date',
fieldtype: 'Date',
description: 'Enter Signing Date'
},
{
label: `Entry Date for ${doc.supplier} (Invoice: ${doc.bill_no}, Total: ${doc.grand_total})`,
fieldname: 'custom_entry_date',
fieldtype: 'Date',
description: 'Enter Entry Date'
}
], function(data) {
// Save the updated values to the document
frappe.call({
method: 'frappe.client.set_value',
args: {
doctype: 'Purchase Invoice',
name: doc.name,
fieldname: {
custom_on_hold_date: data.custom_on_hold_date,
custom_on_query_date: data.custom_on_query_date,
custom_directors_signing_date: data.custom_directors_signing_date,
custom_audit_date: data.custom_audit_date,
custom_signing_date: data.custom_signing_date,
custom_entry_date: data.custom_entry_date
}
},
callback: function() {
current_index++;
show_prompt_for_invoice(); // Proceed to the next invoice
}
});
}, __('Enter Workflow Dates for ' + doc.name), __('Next'));
}
}
});
}
show_prompt_for_invoice();
}