- % Pagu 51/52/53 : Persentase Porsi Pagu per jenis belanja
- % DeviasiT 51/52/53 : Persentase Deviasi Tertimbang per jenis belanja (% Deviasi × % Pagu)
- % Deviasi Total : % DeviasiT 51 + 52 + 53
- Rata2 DeviasiT : Rata-Rata Deviasi Tertimbang dari Jan s.d. bulan berkenaan
- Nilai IKPA :100 - Rata2 DeviasiT
Khusus Kurang Serap (Penyerapan < Rencana)
Daftar Satker dengan Deviasi Belanja > Rp100 Juta
Menampilkan Satker dengan Penyerapan di bawah Rencana (Rencana − Penyerapan > Rp100.000.000). Deviasi karena Overspending (Penyerapan > Rencana) dipisahkan ke menu OVERSPENDING.
Periode:
Deviasi Kurang Serap Belanja 51 > 100 Juta (Rencana − Penyerapan)
No
Kode
Nama Satker
Rencana 51
Penyerapan 51
Kurang Serap (Rencana − Penyerapan)
Deviasi Kurang Serap Belanja 52 > 100 Juta (Rencana − Penyerapan)
No
Kode
Nama Satker
Rencana 52
Penyerapan 52
Kurang Serap (Rencana − Penyerapan)
Deviasi Kurang Serap Belanja 53 > 100 Juta (Rencana − Penyerapan)
No
Kode
Nama Satker
Rencana 53
Penyerapan 53
Kurang Serap (Rencana − Penyerapan)
EWS Gatekeeper
Monitoring Overspending (Penyerapan > Rencana)
Daftar Satker yang realisasi penyerapannya melampaui RPD. Klik judul kolom tabel untuk mengurutkan (sort) besaran nilai yang overspending.
Matriks Pengaturan Relaksasi IKPA Per Bulan & Per Jenis Belanja
Atur secara spesifik jenis belanja mana saja (51, 52, 53, 57) yang mendapatkan relaksasi (dihitung deviasi = 0%) pada masing-masing periode bulan.
Ringkasan Matriks Relaksasi Aktif Saat Ini
Feb (51, 52) • Mar (51, 52)
Setiap bulan dapat memiliki kombinasi relaksasi jenis belanja (51/52/53/57) yang berbeda sesuai kebijakan DJPb.
Rata-Rata Nilai IKPA KPPN (Bulan Ini)
86.14
Otomatis memperbarui seluruh menu & grafik
Matriks Relaksasi Per Periode Bulan (Januari s.d. Desember)
Klik tombol 51, 52, 53, atau 57 pada kartu bulan yang diinginkan. Anda juga bisa klik Semua atau Kosongkan di tiap bulan:
Tersimpan di Database
Pratinjau Dampak Nilai IKPA Satker (Periode Bulan Berjalan)
Klik baris Satker untuk melihat grafik detail di menu IKPA_SATKER
Kode
Nama Satker
Rata2 DeviasiT (Tanpa Relaksasi)
Rata2 DeviasiT (Dengan Relaksasi Aktif)
Nilai IKPA (Tanpa Relaksasi)
Nilai IKPA (Aktif Saat Ini)
Selisih Dampak
Notifikasi
Konektor Backend Google Apps Script (Code.gs)
Tempelkan fungsi-fungsi di bawah ini ke bagian paling bawah file Code.gs Anda (tanpa menghapus kode yang sudah ada). Script ini sudah mendukung REST API JSON (doGet & doPost) untuk dihubungkan ke Vercel sekaligus tetap mendukung Web App GAS:
// ====================================================================================
// FUNGSI HYBRID API (VERCEL REST API + GOOGLE APPS SCRIPT WEB APP)
// ====================================================================================
function doGet(e) {
// Jika dipanggil dari Vercel menggunakan parameter ?action=getData, kembalikan JSON (CORS-ready)
if (e && e.parameter && e.parameter.action === "getData") {
var payload = getMokokawaData();
return ContentService.createTextOutput(JSON.stringify(payload))
.setMimeType(ContentService.MimeType.JSON);
}
// Fallback jika dibuka langsung dari link Web App Google Apps Script
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('MOKOKAWA 2.1 - KPPN Luwuk')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
// Endpoint POST untuk menyimpan konfigurasi Relaksasi IKPA dari Vercel ke Spreadsheet
function doPost(e) {
try {
var body = JSON.parse(e.postData.contents);
if (body && body.action === "saveRelaksasi") {
var res = saveRelaksasiConfigToSheet(body.config);
return ContentService.createTextOutput(JSON.stringify(res))
.setMimeType(ContentService.MimeType.JSON);
}
return ContentService.createTextOutput(JSON.stringify({ success: false, error: "Invalid action" }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService.createTextOutput(JSON.stringify({ success: false, error: err.message }))
.setMimeType(ContentService.MimeType.JSON);
}
}
function getMokokawaData() {
var masterSheetId = "19zzOnuz0gU0fVwmMMIM_P0RDFi3wxekY1Dc9OuOG-KU";
var ss = SpreadsheetApp.openById(masterSheetId);
var sheet1 = ss.getSheets()[0];
var ikpaDevSheet = ss.getSheetByName("IKPA Deviasi");
var ikpaKppnSheet = ss.getSheetByName("IKPA KPPN");
var logSheet = ss.getSheetByName("Log_Update");
var configSheet = ss.getSheetByName("Config_Relaksasi");
var logTime = logSheet ? logSheet.getRange(2, 1).getDisplayValue() : "-";
var savedRelaksasiConfig = null;
if (configSheet) {
var rawJson = configSheet.getRange(2, 1).getValue();
if (rawJson) {
try {
savedRelaksasiConfig = JSON.parse(rawJson);
} catch (err) {
savedRelaksasiConfig = null;
}
}
}
function sheetToObjects(sheet) {
if (!sheet) return [];
var vals = sheet.getDataRange().getDisplayValues();
if (vals.length < 2) return [];
var headers = vals[0];
var result = [];
for (var r = 1; r < vals.length; r++) {
var obj = {};
for (var c = 0; c < headers.length; c++) {
obj[headers[c]] = vals[r][c];
}
result.push(obj);
}
return result;
}
return {
logUpdate: logTime,
currentMonth: new Date().getMonth() + 1,
relaksasiConfig: savedRelaksasiConfig,
sheet1: sheetToObjects(sheet1),
ikpaDeviasi: sheetToObjects(ikpaDevSheet),
ikpaKppn: sheetToObjects(ikpaKppnSheet)
};
}
function saveRelaksasiConfigToSheet(configObj) {
var masterSheetId = "19zzOnuz0gU0fVwmMMIM_P0RDFi3wxekY1Dc9OuOG-KU";
var ss = SpreadsheetApp.openById(masterSheetId);
var configSheet = ss.getSheetByName("Config_Relaksasi");
if (!configSheet) {
configSheet = ss.insertSheet("Config_Relaksasi");
}
configSheet.clear();
configSheet.getRange(1, 1).setValue("JSON_Config_Relaksasi");
configSheet.getRange(1, 2).setValue("Terakhir_Diubah");
configSheet.getRange(2, 1).setValue(JSON.stringify(configObj));
configSheet.getRange(2, 2).setValue(Utilities.formatDate(new Date(), "Asia/Makassar", "yyyy-MM-dd HH:mm:ss"));
return { success: true };
}
// ====================================================================================
// FUNGSI INSTALASI TRIGGER INSTAN SAAT UPLOAD FILE DI GOOGLE FORM (JALANKAN 1 KALI)
// ====================================================================================
function pasangTriggerOtomatisForm() {
var formIdTarget = "1g7GOig7UL29TV-NT3hidYuLdmFWgXDh3wl4r-bEBJB8";
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
ScriptApp.deleteTrigger(triggers[i]);
}
var form = FormApp.openById(formIdTarget);
ScriptApp.newTrigger("prosesSaatFormDiSubmit")
.forForm(form)
.onFormSubmit()
.create();
Logger.log("Trigger otomatis saat upload Google Form berhasil dipasang!");
}
function prosesSaatFormDiSubmit(e) {
var folderTujuanId = "1DkY1aMqEBxK_pRCYgjysy96wpa-cli5t";
var folderTujuan = DriveApp.getFolderById(folderTujuanId);
var adaFile = false;
if (e && e.response) {
var itemResponses = e.response.getItemResponses();
for (var i = 0; i < itemResponses.length; i++) {
var jawaban = itemResponses[i].getResponse();
var fileIds = Array.isArray(jawaban) ? jawaban : [jawaban];
for (var j = 0; j < fileIds.length; j++) {
var fId = String(fileIds[j]).trim();
if (fId.length >= 20) {
try {
DriveApp.getFileById(fId).moveTo(folderTujuan);
adaFile = true;
} catch (err) {
Logger.log("Gagal memindahkan file: " + err.message);
}
}
}
}
}
updateMasterSheetFromExcel();
}