Archived
214 lines
9.4 KiB
JavaScript
214 lines
9.4 KiB
JavaScript
// helper: format currency (Indonesia style) - untuk fallback client-side rendering
|
|
function fmtMoney(n) {
|
|
n = Number(n) || 0;
|
|
var parts = n.toFixed(2).split('.');
|
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
return parts[0] + ',' + parts[1];
|
|
}
|
|
|
|
// Function: build HTML client-side (same logic as template) - dipakai ketika doc belum disimpan
|
|
function build_message_html_client(doc, ref_doc) {
|
|
var amount = Number(doc.grand_total || doc.amount || 0);
|
|
var netto = amount ? (amount / 1.11) : 0;
|
|
var ppn = amount - netto;
|
|
|
|
var qty = 0;
|
|
if (ref_doc) {
|
|
qty = Number(ref_doc.total_qty || 0);
|
|
if (!qty && ref_doc.items) {
|
|
for (var i = 0; i < ref_doc.items.length; i++) {
|
|
qty += Number(ref_doc.items[i].qty || 0);
|
|
}
|
|
}
|
|
}
|
|
if (!qty) qty = 1;
|
|
|
|
var per_unit = netto / qty;
|
|
|
|
var html = '';
|
|
html += '<div style="font-family: Arial, sans-serif; font-size: 13px; line-height: 1.6;">';
|
|
html += '<table border="1" cellspacing="0" cellpadding="6" width="100%" style="border-collapse: collapse;">';
|
|
html += '<thead style="background:#f2f2f2;"><tr><th style="width:5%">No</th><th style="width:55%">Nama Barang</th><th style="width:10%;text-align:center">Banyaknya</th><th style="text-align:right;width:15%">Harga Satuan</th><th style="text-align:right;width:15%">Jumlah Satuan</th></tr></thead>';
|
|
html += '<tbody>';
|
|
html += '<tr>';
|
|
html += '<td style="text-align:center;">1</td>';
|
|
var name = (ref_doc && ref_doc.items && ref_doc.items.length>0) ? (ref_doc.items[0].item_name || "Nama Barang / Uraian") : "Nama Barang / Uraian";
|
|
html += '<td>' + name + '</td>';
|
|
html += '<td style="text-align:center;">' + (qty.toFixed(2)) + '</td>';
|
|
html += '<td style="text-align:right;">Rp ' + fmtMoney(per_unit) + '</td>';
|
|
html += '<td style="text-align:right;">Rp ' + fmtMoney(netto) + '</td>';
|
|
html += '</tr>';
|
|
|
|
html += '<tr><td colspan="4" style="text-align:right;">Diskon</td><td style="text-align:right;">Rp ' + fmtMoney(0) + '</td></tr>';
|
|
html += '<tr><td colspan="4" style="text-align:right;">PPN 11%</td><td style="text-align:right;">Rp ' + fmtMoney(ppn) + '</td></tr>';
|
|
html += '<tr><td colspan="4" style="text-align:right;font-weight:bold;">Total</td><td style="text-align:right;font-weight:bold;">Rp ' + fmtMoney(amount) + '</td></tr>';
|
|
|
|
html += '</tbody></table>';
|
|
|
|
html += '<p style="margin-top:10px;">Terbilang : <b>' + ( (typeof frappe !== 'undefined' && frappe.utils && frappe.utils.money_in_words) ? frappe.utils.money_in_words(amount, (doc.currency || "IDR")) : "") + '</b></p>';
|
|
|
|
html += '<p style="margin-top:30px; text-align:right;">Jakarta, ' + ((doc.transaction_date) ? doc.transaction_date : ( (typeof frappe !== 'undefined' && frappe.utils && frappe.utils.nowdate) ? frappe.utils.nowdate() : "" )) + '<br>Hormat kami,</p>';
|
|
|
|
html += '</div>';
|
|
return html;
|
|
}
|
|
|
|
// Function: update message - uses server render if docname exists, otherwise client-side render
|
|
function update_message(frm) {
|
|
// If there's a reference document, fetch it (for client-side rendering)
|
|
var ref_doctype = frm.doc.reference_doctype;
|
|
var ref_name = frm.doc.reference_name;
|
|
|
|
var do_server_render = !!frm.doc.name; // prefer server render when doc saved (has name)
|
|
|
|
if (ref_doctype && ref_name) {
|
|
frappe.call({
|
|
method: "frappe.client.get",
|
|
args: { doctype: ref_doctype, name: ref_name },
|
|
callback: function(r) {
|
|
var ref_doc = r.message || null;
|
|
if (do_server_render) {
|
|
// server render (uses api.get_payment_message)
|
|
frappe.call({
|
|
method: "editor_override.api.get_payment_message",
|
|
args: { docname: frm.doc.name },
|
|
callback: function(res) {
|
|
if (res.message) {
|
|
frm.set_value("message", res.message);
|
|
frm.refresh_field("message");
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
// client-side render for unsaved doc
|
|
var html = build_message_html_client(frm.doc, ref_doc);
|
|
frm.set_value("message", html);
|
|
frm.refresh_field("message");
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
// no reference doc
|
|
if (do_server_render) {
|
|
frappe.call({
|
|
method: "editor_override.api.get_payment_message",
|
|
args: { docname: frm.doc.name },
|
|
callback: function(res) {
|
|
if (res.message) {
|
|
frm.set_value("message", res.message);
|
|
frm.refresh_field("message");
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
var html = build_message_html_client(frm.doc, null);
|
|
frm.set_value("message", html);
|
|
frm.refresh_field("message");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===========================
|
|
// Payment Term logic (existing) + tie to update_message
|
|
// ===========================
|
|
frappe.ui.form.on("Payment Request", {
|
|
onload: function(frm) {
|
|
// set default or initial behaviours if needed
|
|
// e.g. df property toggles, default percent, etc. (adapt from your original code)
|
|
if (!frm.doc.custom_payment_term_percentage) {
|
|
frm.set_value("custom_payment_term_percentage", 100);
|
|
}
|
|
},
|
|
|
|
refresh: function(frm) {
|
|
// always update message UI on refresh (safe)
|
|
update_message(frm);
|
|
},
|
|
|
|
reference_name: function(frm) {
|
|
// when reference changes, fetch base amount and refresh message
|
|
if (frm.doc.reference_doctype === "Sales Order" && frm.doc.reference_name) {
|
|
// fetch SO grand_total and set as amount (default 100% portion)
|
|
frappe.call({
|
|
method: "frappe.client.get",
|
|
args: { doctype: "Sales Order", name: frm.doc.reference_name },
|
|
callback: function(r) {
|
|
if (r.message && r.message.grand_total) {
|
|
// if no custom percent set, set amount to full SO
|
|
var portion = frm.doc.custom_payment_term_percentage || 100;
|
|
var final_amount = (r.message.grand_total * portion) / 100;
|
|
frm.set_value("grand_total", final_amount);
|
|
frm.refresh_field("grand_total");
|
|
// now update message
|
|
update_message(frm);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
update_message(frm);
|
|
}
|
|
},
|
|
|
|
custom_payment_term: function(frm) {
|
|
var value = frm.doc.custom_payment_term;
|
|
if (!value) {
|
|
frm.set_value("custom_payment_term_percentage", 100);
|
|
// get original amount from SO and refresh message
|
|
if (frm.doc.reference_doctype === "Sales Order" && frm.doc.reference_name) {
|
|
frappe.call({
|
|
method: "frappe.client.get",
|
|
args: { doctype: "Sales Order", name: frm.doc.reference_name },
|
|
callback: function(r) {
|
|
if (r.message && r.message.grand_total) {
|
|
frm.set_value("grand_total", r.message.grand_total);
|
|
frm.refresh_field("grand_total");
|
|
update_message(frm);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
update_message(frm);
|
|
}
|
|
} else {
|
|
// fetch selected Payment Term invoice_portion
|
|
frappe.call({
|
|
method: "frappe.client.get",
|
|
args: {
|
|
doctype: "Payment Term",
|
|
name: value
|
|
},
|
|
callback: function(r) {
|
|
if (r.message && r.message.invoice_portion !== undefined) {
|
|
var portion = r.message.invoice_portion;
|
|
frm.set_value("custom_payment_term_percentage", portion);
|
|
// calc final amount based on sales order base
|
|
if (frm.doc.reference_doctype === "Sales Order" && frm.doc.reference_name) {
|
|
frappe.call({
|
|
method: "frappe.client.get",
|
|
args: { doctype: "Sales Order", name: frm.doc.reference_name },
|
|
callback: function(rr) {
|
|
if (rr.message && rr.message.grand_total) {
|
|
var final_amount = (rr.message.grand_total * portion) / 100;
|
|
frm.set_value("grand_total", final_amount);
|
|
frm.refresh_field("grand_total");
|
|
// Immediately update message to reflect new grand_total
|
|
update_message(frm);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
update_message(frm);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// in case grand_total is edited manually
|
|
grand_total: function(frm) {
|
|
update_message(frm);
|
|
}
|
|
|
|
});
|