Hasil hilang/rusak tidak langsung membuat jurnal. Setelah opname diposting, proses mutasi Hilang/Rusak pada aset terkait agar nilai buku dan jurnal tetap terkontrol.
' +
lines,
);
$(".opname-line-grid").each(function (i) {
$(this).find(".actual-status").val(o.lines[i].actual_status);
});
var a =
'';
if (P.update && o.status === "draft")
a +=
'';
if (P.create && o.status === "draft")
a +=
'';
if (P.approve && o.status === "submitted")
a +=
'';
if (P.post && o.status === "approved")
a +=
'';
$("#opnameActions").html(a);
bootstrap.Modal.getOrCreateInstance(
document.getElementById("opnameModal"),
).show();
})
.catch(fail);
}
function reportUrl(kind) {
var p = new URLSearchParams({
type: $("#reportType").val(),
date_from: $("#reportFrom").val(),
date_to: $("#reportTo").val(),
});
return B + "fixedassets/" + kind + "?" + p.toString();
}
function runReport() {
request(reportUrl("report_data"))
.then(function (r) {
var data = r.data || [];
if (!data.length) {
$("#reportResult").html(
'
Tidak ada data.
',
);
return;
}
var keys = Object.keys(data[0]).filter(function (k) {
return typeof data[0][k] !== "object";
}),
h =
'
' +
keys
.map(function (k) {
return "
" + esc(k.replaceAll("_", " ")) + "
";
})
.join("") +
"
";
data.forEach(function (x) {
h +=
"
" +
keys
.map(function (k) {
return "
" + esc(x[k]) + "
";
})
.join("") +
"
";
});
$("#reportResult").html(h + "
");
})
.catch(fail);
}
$(function () {
initTable();
initSelects();
$("#btnNewAsset").on("click", function () {
resetForm();
bootstrap.Modal.getOrCreateInstance(
document.getElementById("assetFormModal"),
).show();
});
$("[name=source_type]").on("change", toggleSource);
$("[name=source_journal_mode]").on("change", toggleJournal);
$("[name=category_id]").on("change", function () {
var o = this.options[this.selectedIndex];
$("[name=masa_manfaat]").val(o.dataset.life || "");
$("[name=depreciation_method]").val(o.dataset.method || "straight_line");
$("[name=asset_account_id]").val(o.dataset.asset || "");
$("[name=accumulated_depreciation_account_id]").val(
o.dataset.accum || "",
);
$("[name=depreciation_expense_account_id]").val(o.dataset.expense || "");
});
$("#assetFileInput").on("change", function () {
Array.from(this.files).forEach(function (f) {
if (files.length < 10) files.push(f);
});
this.value = "";
renderFiles();
});
$("#assetForm").on("submit", saveAsset);
$(document)
.on("click", ".btn-detail", function () {
openDetail(this.dataset.id);
})
.on("click", ".btn-pdf", function () {
pdf(this.dataset.url);
})
.on("click", ".preview-file", function () {
pdf(this.dataset.url);
})
.on("click", ".action-post", function () {
postAction(this.dataset.action, this.dataset.id);
})
.on("click", ".asset-process", function () {
process(this.dataset.kind, this.dataset.id);
})
.on("click", "[data-master]", function () {
master(this.dataset.master);
})
.on("click", ".edit-category", function () {
master("category", JSON.parse(this.dataset.row));
})
.on("click", ".edit-location", function () {
master("location", JSON.parse(this.dataset.row));
})
.on("click", ".btn-opname", function () {
openOpname(this.dataset.id);
});
$("#masterForm").on("submit", saveMaster);
$("#btnNewOpname").on("click", newOpname);
$("#btnRunReport").on("click", runReport);
$("#btnReportPdf").on("click", function () {
pdf(reportUrl("report_pdf"));
});
$("#btnReportExcel").on("click", function () {
location.href = reportUrl("report_excel");
});
$(document)
.on("click", ".save-opname", function () {
var id = this.dataset.id,
lines = [];
$(".opname-line-grid").each(function () {
lines.push({
id: this.dataset.line,
is_found: $(this).find(".found").prop("checked") ? 1 : 0,
actual_location_id: $(this).find(".actual-location").val(),
actual_status: $(this).find(".actual-status").val(),
notes: $(this).find(".notes").val(),
});
});
request(B + "fixedassets/opname_save/" + id, {
method: "POST",
body: fd({ lines: JSON.stringify(lines) }),
})
.then(function (r) {
toast(r.message);
openOpname(id);
})
.catch(fail);
})
.on("click", ".state-opname", function () {
var id = this.dataset.id,
action = this.dataset.action;
AppAlert.confirm({
title: "Proses " + action + " opname?",
text: "Status dan audit trail akan diperbarui.",
}).then(function (x) {
if (x.isConfirmed)
request(B + "fixedassets/opname_state/" + id, {
method: "POST",
body: fd({ action: action }),
})
.then(function (r) {
toast(r.message);
location.reload();
})
.catch(fail);
});
});
});
var currentOpnameId = 0,
assetScanner = null;
var assetSwalLabels = {
"sw-date": "Tanggal proses",
"sw-location": "Lokasi tujuan",
"sw-notes": "Alasan / keterangan",
"sw-vendor": "Vendor maintenance",
"sw-description": "Pekerjaan maintenance",
"sw-cost": "Biaya maintenance",
"sw-next": "Jadwal maintenance berikutnya",
"sw-file": "Bukti maintenance",
"sw-type": "Jenis mutasi",
"sw-amount": "Nilai transaksi / hasil pelepasan",
"sw-account": "Akun lawan",
"op-location": "Lokasi yang akan diperiksa",
"op-date": "Tanggal asset opname",
"op-notes": "Ruang lingkup / catatan",
"pic-select": "Penanggung jawab baru",
"pic-date": "Tanggal efektif",
"pic-notes": "Alasan pergantian",
"rev-date": "Tanggal reversal",
"rev-reason": "Alasan reversal",
};
function styleAssetSwal(root) {
Object.keys(assetSwalLabels).forEach(function (id) {
var input = (root || document).querySelector("#" + id);
if (
!input ||
(input.previousElementSibling &&
input.previousElementSibling.classList.contains("asset-swal-label"))
)
return;
var label = document.createElement("label");
label.className = "asset-swal-label";
label.htmlFor = id;
label.textContent = assetSwalLabels[id];
input.parentNode.insertBefore(label, input);
});
}
new MutationObserver(function (records) {
records.forEach(function (record) {
Array.from(record.addedNodes || []).forEach(function (node) {
if (node.nodeType === 1) styleAssetSwal(node);
});
});
}).observe(document.body, { childList: true, subtree: true });
var baseDetailActions = detailActions;
detailActions = function (a) {
var out = baseDetailActions(a);
if (
P.update &&
a.workflow_status === "capitalized" &&
["active", "fully_depreciated"].indexOf(a.lifecycle_status) >= 0
)
out +=
'';
var latest = (a.events || [])[0];
if (
P.post &&
latest &&
latest.event_type !== "acquisition" &&
latest.event_type !== "reversal"
)
out +=
'';
return out;
};
$(document).on("click", ".change-pic", function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var id = this.dataset.id,
today = new Date().toISOString().slice(0, 10);
AppAlert.prompt({
title: "Ganti Penanggung Jawab",
html:
'',
didOpen: function () {
$("#pic-select").select2({
dropdownParent: $(".swal2-container"),
placeholder: "Cari karyawan",
ajax: {
url: B + "fixedassets/lookup_employees",
delay: 250,
data: function (p) {
return { q: p.term || "", page: p.page || 1 };
},
processResults: function (r) {
return {
results: r.results || [],
pagination: r.pagination || { more: false },
};
},
},
});
},
preConfirm: function () {
return {
employee_id: $("#pic-select").val(),
date: $("#pic-date").val(),
notes: $("#pic-notes").val(),
};
},
}).then(function (x) {
if (x.isConfirmed) doPost("responsibility", id, x.value);
});
});
$(document).on("click", ".reverse-event", function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var id = this.dataset.id,
today = new Date().toISOString().slice(0, 10);
AppAlert.prompt({
title: "Reversal Event Aset",
html:
'',
preConfirm: function () {
var reason = $("#rev-reason").val();
if (!reason) {
Swal.showValidationMessage("Alasan reversal wajib diisi.");
return false;
}
return { date: $("#rev-date").val(), reason: reason };
},
}).then(function (x) {
if (x.isConfirmed) doPost("reverse", id, x.value);
});
});
$(document).on("click", ".btn-opname", function () {
currentOpnameId = this.dataset.id || 0;
});
$("#opnameModal")
.on("shown.bs.modal", function () {
if (!currentOpnameId) return;
request(B + "fixedassets/opname_detail/" + currentOpnameId)
.then(function (r) {
var o = r.opname,
box = $(
'
Pindai & Bukti Asset Opname
',
);
if (o.status === "draft")
box.append(
'',
);
box.append(attachments(o.attachments));
if (o.status === "draft" && P.create)
box.append(
'',
);
$("#opnameProof").remove();
$("#opnameBody").append(box);
})
.catch(fail);
})
.on("hidden.bs.modal", function () {
if (assetScanner && assetScanner.clear)
assetScanner.clear().catch(function () {});
assetScanner = null;
});
function applyAssetScan(raw) {
var code = decodeURIComponent(
String(raw || "")
.trim()
.split("/")
.filter(Boolean)
.pop() || "",
).replace(/^ASSET:/i, ""),
found = false;
$(".opname-line-grid").each(function () {
var label = $(this).find("b").text().trim();
if (label.indexOf(code) === 0) {
$(this).find(".found").prop("checked", true);
this.scrollIntoView({ behavior: "smooth", block: "center" });
$(this).addClass("approval-focus");
found = true;
return false;
}
});
toast(
found
? "Aset " + code + " ditandai ditemukan."
: "Kode aset tidak ada pada dokumen opname.",
found ? "success" : "warning",
);
}
$(document)
.on("click", ".apply-asset-scan", function () {
applyAssetScan($("#assetScanValue").val());
})
.on("keydown", "#assetScanValue", function (e) {
if (e.key === "Enter") {
e.preventDefault();
applyAssetScan(this.value);
}
})
.on("click", ".start-asset-camera", function () {
if (typeof Html5QrcodeScanner === "undefined") {
toast(
"Library kamera QR belum tersedia. Gunakan scanner atau input kode.",
"warning",
);
return;
}
$("#assetQrReader").removeClass("d-none");
if (assetScanner) return;
assetScanner = new Html5QrcodeScanner(
"assetQrReader",
{ fps: 10, qrbox: { width: 220, height: 220 } },
false,
);
assetScanner.render(
function (text) {
$("#assetScanValue").val(text);
applyAssetScan(text);
},
function () {},
);
});
$(document).on("change", ".opname-upload", function () {
var input = this,
id = currentOpnameId,
list = Array.from(input.files || []);
list
.reduce(function (chain, file) {
return chain.then(function () {
return uploadEntity("asset_opname", id, file);
});
}, Promise.resolve())
.then(function () {
toast("Bukti opname berhasil diunggah.");
input.value = "";
$("#opnameModal").trigger("shown.bs.modal");
})
.catch(fail);
});
$(document).on("click", '.state-opname[data-action="reject"]', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var id = this.dataset.id;
AppAlert.prompt({
title: "Tolak Asset Opname",
input: "textarea",
inputLabel: "Alasan penolakan wajib diisi",
inputValidator: function (v) {
if (!v) return "Alasan wajib diisi.";
},
}).then(function (x) {
if (x.isConfirmed)
request(B + "fixedassets/opname_state/" + id, {
method: "POST",
body: fd({ action: "reject", reason: x.value }),
})
.then(function (r) {
toast(r.message);
location.reload();
})
.catch(fail);
});
});
$(document).on("click", ".edit-asset", editAsset);
})(jQuery);