/**
* Kalkulator Faraidh - Implementasi Hukum Waris Islam
* Berdasarkan skema flowchart yang komprehensif
*
* Implementasi ini mengikuti pohon keputusan dan alur logika yang tepat
* sebagaimana digambarkan dalam flowchart faraidh_schema.png
*
* @author Dibuat berdasarkan Skema Faraidh
* @version 2.0.0
*/
class KalkulatorFaraidh {
constructor() {
this.reset();
}
/**
* Reset semua nilai ke kondisi awal
*/
reset() {
// Data harta
this.totalHarta = 0;
this.hutang = 0;
this.biayaPemakaman = 0;
this.wasiat = 0; // maksimal 1/3
this.hartaBersih = 0;
// Data ahli waris mengikuti struktur skema
this.ahliWaris = {
// Pasangan
suami: 0,
istri: 0,
// Keturunan langsung
anakLaki: 0,
anakPerempuan: 0,
cucuLakiDariAnakLaki: 0, // cucu laki dari anak laki
cucuPerempuanDariAnakLaki: 0, // cucu perempuan dari anak laki
// Orang tua dan kakek nenek
ayah: 0,
ibu: 0,
kakekDariAyah: 0, // kakek dari ayah
nenekDariIbu: 0, // nenek dari ibu
nenekDariAyah: 0, // nenek dari ayah
// Saudara
saudaraLakiKandung: 0, // saudara laki kandung
saudaraPerempuanKandung: 0, // saudara perempuan kandung
saudaraLakiSeAyah: 0, // saudara laki se-ayah
saudaraPerempuanSeAyah: 0, // saudara perempuan se-ayah
saudaraLakiSeIbu: 0, // saudara laki se-ibu
saudaraPerempuanSeIbu: 0, // saudara perempuan se-ibu
// Keponakan dan paman
anakLakiSaudaraKandung: 0, // anak laki saudara kandung
anakLakiSaudaraSeAyah: 0, // anak laki saudara se-ayah
pamanKandungAyah: 0, // paman kandung ayah
anakLakiPamanKandung: 0 // anak laki paman kandung ayah
};
// Hasil perhitungan
this.bagianFaraidh = []; // Bagian tetap (Dzawi al-Furudh)
this.bagianAshobah = []; // Bagian sisa (Asabah)
this.kasusKhusus = null; // 'aul', 'radd', atau null
this.nilaiAul = 0;
this.nilaiRadd = 0;
}
/**
* Set nilai harta
*/
setHarta(data) {
this.totalHarta = data.totalHarta || 0;
this.hutang = data.hutang || 0;
this.biayaPemakaman = data.biayaPemakaman || 0;
this.wasiat = data.wasiat || 0;
this.hartaBersih = this.totalHarta - this.hutang - this.biayaPemakaman - this.wasiat;
}
/**
* Set jumlah ahli waris
*/
setAhliWaris(dataAhliWaris) {
Object.assign(this.ahliWaris, dataAhliWaris);
}
/**
* Metode perhitungan utama mengikuti skema flowchart
*/
hitung() {
// Validasi input
this._validasiInput();
// Reset hasil
this.bagianFaraidh = [];
this.bagianAshobah = [];
this.kasusKhusus = null;
// Mulai pohon keputusan sesuai skema
this._mulaiPohonKeputusan();
// Tangani kasus khusus (Aul/Radd)
this._tanganiKasusKhusus();
return this._dapatkanHasil();
}
/**
* Validasi input sesuai hukum Islam
* @private
*/
_validasiInput() {
if (this.totalHarta <= 0) {
throw new Error("Total harta harus lebih besar dari 0");
}
if (this.hartaBersih <= 0) {
throw new Error("Harta bersih tidak mencukupi setelah dikurangi hutang, biaya pemakaman, dan wasiat");
}
if (this.wasiat > this.totalHarta / 3) {
throw new Error(`Wasiat tidak boleh melebihi 1/3 dari total harta (maksimal: ${this.totalHarta / 3})`);
}
if (this.ahliWaris.suami > 0 && this.ahliWaris.istri > 0) {
throw new Error("Tidak boleh ada suami dan istri sekaligus sebagai ahli waris");
}
if (this.ahliWaris.suami > 1) {
throw new Error("Suami tidak boleh lebih dari satu orang");
}
}
/**
* Mulai pohon keputusan utama mengikuti skema
* @private
*/
_mulaiPohonKeputusan() {
// Mengikuti langkah-langkah skema flowchart
// Langkah 1: Periksa pasangan
this._prosesPasangan();
// Langkah 2: Periksa orang tua
this._prosesOrangTua();
// Langkah 3: Periksa anak/keturunan
this._prosesKeturunan();
// Langkah 4: Proses saudara
this._prosesSaudara();
// Langkah 5: Proses asabah yang tersisa
this._prosesAshobah();
}
/**
* Proses bagian pasangan (suami/istri)
* @private
*/
_prosesPasangan() {
const adaKeturunan = this._adaKeturunan();
// Bagian suami
if (this.ahliWaris.suami > 0) {
if (adaKeturunan) {
// 1/4 jika ada keturunan
this._tambahBagianFaraidh('Suami', 1, '1/4', 0.25);
} else {
// 1/2 jika tidak ada keturunan
this._tambahBagianFaraidh('Suami', 1, '1/2', 0.5);
}
}
// Bagian istri
if (this.ahliWaris.istri > 0) {
if (adaKeturunan) {
// 1/8 jika ada keturunan
this._tambahBagianFaraidh(`Istri (${this.ahliWaris.istri} orang)`, this.ahliWaris.istri, '1/8', 0.125);
} else {
// 1/4 jika tidak ada keturunan
this._tambahBagianFaraidh(`Istri (${this.ahliWaris.istri} orang)`, this.ahliWaris.istri, '1/4', 0.25);
}
}
}
/**
* Proses bagian orang tua (ayah/ibu)
* @private
*/
_prosesOrangTua() {
const adaKeturunan = this._adaKeturunan();
const adaSaudara = this._adaSaudara();
// Bagian ibu
if (this.ahliWaris.ibu > 0) {
if (adaKeturunan || adaSaudara) {
// 1/6 jika ada keturunan atau saudara
this._tambahBagianFaraidh('Ibu', 1, '1/6', 1/6);
} else {
// 1/3 jika tidak ada keturunan dan tidak ada saudara
this._tambahBagianFaraidh('Ibu', 1, '1/3', 1/3);
}
}
// Bagian ayah
if (this.ahliWaris.ayah > 0) {
if (adaKeturunan) {
// 1/6 sebagai faraidh jika ada keturunan laki
this._tambahBagianFaraidh('Ayah', 1, '1/6', 1/6);
} else {
// Ayah menjadi asabah jika tidak ada keturunan laki
this._tambahBagianAshobah('Ayah', 1, 1, 'Asabah bi nafsihi');
}
}
// Kakek (ayah dari ayah) - hanya jika tidak ada ayah
if (this.ahliWaris.kakekDariAyah > 0 && this.ahliWaris.ayah === 0) {
if (adaKeturunan) {
this._tambahBagianFaraidh('Kakek (Ayah dari Ayah)', 1, '1/6', 1/6);
} else {
this._tambahBagianAshobah('Kakek (Ayah dari Ayah)', 1, 2, 'Asabah bi nafsihi');
}
}
// Nenek-nenek
this._prosesNenek();
}
/**
* Proses bagian nenek-nenek
* @private
*/
_prosesNenek() {
const totalNenek = this.ahliWaris.nenekDariIbu + this.ahliWaris.nenekDariAyah;
// Hanya jika ibu tidak hidup
if (totalNenek > 0 && this.ahliWaris.ibu === 0) {
this._tambahBagianFaraidh(`Nenek (${totalNenek} orang)`, totalNenek, '1/6', 1/6);
}
}
/**
* Proses keturunan (anak dan cucu)
* @private
*/
_prosesKeturunan() {
// Anak langsung dulu
if (this.ahliWaris.anakLaki > 0 || this.ahliWaris.anakPerempuan > 0) {
this._prosesAnakLangsung();
} else {
// Cucu (anak dari anak laki) hanya jika tidak ada anak langsung
this._prosesCucu();
}
}
/**
* Proses anak langsung
* @private
*/
_prosesAnakLangsung() {
if (this.ahliWaris.anakLaki > 0) {
if (this.ahliWaris.anakPerempuan > 0) {
// Ada anak laki dan perempuan - rasio 2:1 sebagai asabah
this._tambahBagianAshobah(`Anak Laki-laki (${this.ahliWaris.anakLaki} orang)`, this.ahliWaris.anakLaki, 1, 'Asabah bi nafsihi (2:1 dengan anak perempuan)');
this._tambahBagianAshobah(`Anak Perempuan (${this.ahliWaris.anakPerempuan} orang)`, this.ahliWaris.anakPerempuan, 1, 'Asabah ma\'a ghairihi (bersama anak laki-laki)');
} else {
// Hanya anak laki - semua sisa sebagai asabah
this._tambahBagianAshobah(`Anak Laki-laki (${this.ahliWaris.anakLaki} orang)`, this.ahliWaris.anakLaki, 1, 'Asabah bi nafsihi');
}
} else if (this.ahliWaris.anakPerempuan > 0) {
// Hanya anak perempuan - bagian faraidh
if (this.ahliWaris.anakPerempuan === 1) {
this._tambahBagianFaraidh('Anak Perempuan', 1, '1/2', 0.5);
} else {
this._tambahBagianFaraidh(`Anak Perempuan (${this.ahliWaris.anakPerempuan} orang)`, this.ahliWaris.anakPerempuan, '2/3', 2/3);
}
}
}
/**
* Proses cucu (anak dari anak laki)
* @private
*/
_prosesCucu() {
if (this.ahliWaris.cucuLakiDariAnakLaki > 0 || this.ahliWaris.cucuPerempuanDariAnakLaki > 0) {
if (this.ahliWaris.cucuLakiDariAnakLaki > 0) {
if (this.ahliWaris.cucuPerempuanDariAnakLaki > 0) {
// Ada cucu laki dan perempuan - rasio 2:1
this._tambahBagianAshobah(`Cucu Laki-laki (${this.ahliWaris.cucuLakiDariAnakLaki} orang)`, this.ahliWaris.cucuLakiDariAnakLaki, 1, 'Asabah bi nafsihi (2:1 dengan cucu perempuan)');
this._tambahBagianAshobah(`Cucu Perempuan (${this.ahliWaris.cucuPerempuanDariAnakLaki} orang)`, this.ahliWaris.cucuPerempuanDariAnakLaki, 1, 'Asabah ma\'a ghairihi');
} else {
// Hanya cucu laki
this._tambahBagianAshobah(`Cucu Laki-laki (${this.ahliWaris.cucuLakiDariAnakLaki} orang)`, this.ahliWaris.cucuLakiDariAnakLaki, 1, 'Asabah bi nafsihi');
}
} else if (this.ahliWaris.cucuPerempuanDariAnakLaki > 0) {
// Hanya cucu perempuan
if (this.ahliWaris.cucuPerempuanDariAnakLaki === 1) {
this._tambahBagianFaraidh('Cucu Perempuan (Anak dari Anak Laki)', 1, '1/2', 0.5);
} else {
this._tambahBagianFaraidh(`Cucu Perempuan (${this.ahliWaris.cucuPerempuanDariAnakLaki} orang)`, this.ahliWaris.cucuPerempuanDariAnakLaki, '2/3', 2/3);
}
}
}
}
/**
* Proses saudara
* @private
*/
_prosesSaudara() {
// Hanya jika tidak ada keturunan dan tidak ada ayah
if (!this._adaKeturunan() && this.ahliWaris.ayah === 0) {
// Saudara kandung (prioritas pertama)
if (this.ahliWaris.saudaraLakiKandung > 0 || this.ahliWaris.saudaraPerempuanKandung > 0) {
this._prosesSaudaraKandung();
}
// Saudara se-ayah (jika tidak ada saudara kandung)
else if (this.ahliWaris.saudaraLakiSeAyah > 0 || this.ahliWaris.saudaraPerempuanSeAyah > 0) {
this._prosesSaudaraSeAyah();
}
// Saudara se-ibu (selalu dapat bagian jika ada)
this._prosesSaudaraSeIbu();
}
}
/**
* Proses saudara kandung
* @private
*/
_prosesSaudaraKandung() {
if (this.ahliWaris.saudaraLakiKandung > 0) {
if (this.ahliWaris.saudaraPerempuanKandung > 0) {
// Ada saudara laki dan perempuan kandung - rasio 2:1
this._tambahBagianAshobah(`Saudara Laki-laki Kandung (${this.ahliWaris.saudaraLakiKandung} orang)`, this.ahliWaris.saudaraLakiKandung, 1, 'Asabah bi nafsihi (2:1 dengan saudara perempuan kandung)');
this._tambahBagianAshobah(`Saudara Perempuan Kandung (${this.ahliWaris.saudaraPerempuanKandung} orang)`, this.ahliWaris.saudaraPerempuanKandung, 1, 'Asabah ma\'a ghairihi');
} else {
// Hanya saudara laki kandung
this._tambahBagianAshobah(`Saudara Laki-laki Kandung (${this.ahliWaris.saudaraLakiKandung} orang)`, this.ahliWaris.saudaraLakiKandung, 1, 'Asabah bi nafsihi');
}
} else if (this.ahliWaris.saudaraPerempuanKandung > 0) {
// Hanya saudara perempuan kandung
if (this.ahliWaris.saudaraPerempuanKandung === 1) {
this._tambahBagianFaraidh('Saudara Perempuan Kandung', 1, '1/2', 0.5);
} else {
this._tambahBagianFaraidh(`Saudara Perempuan Kandung (${this.ahliWaris.saudaraPerempuanKandung} orang)`, this.ahliWaris.saudaraPerempuanKandung, '2/3', 2/3);
}
}
}
/**
* Proses saudara se-ayah
* @private
*/
_prosesSaudaraSeAyah() {
if (this.ahliWaris.saudaraLakiSeAyah > 0) {
if (this.ahliWaris.saudaraPerempuanSeAyah > 0) {
// Ada saudara laki dan perempuan se-ayah - rasio 2:1
this._tambahBagianAshobah(`Saudara Laki-laki Se-Ayah (${this.ahliWaris.saudaraLakiSeAyah} orang)`, this.ahliWaris.saudaraLakiSeAyah, 1, 'Asabah bi nafsihi (2:1 dengan saudara perempuan se-ayah)');
this._tambahBagianAshobah(`Saudara Perempuan Se-Ayah (${this.ahliWaris.saudaraPerempuanSeAyah} orang)`, this.ahliWaris.saudaraPerempuanSeAyah, 1, 'Asabah ma\'a ghairihi');
} else {
// Hanya saudara laki se-ayah
this._tambahBagianAshobah(`Saudara Laki-laki Se-Ayah (${this.ahliWaris.saudaraLakiSeAyah} orang)`, this.ahliWaris.saudaraLakiSeAyah, 1, 'Asabah bi nafsihi');
}
} else if (this.ahliWaris.saudaraPerempuanSeAyah > 0) {
// Hanya saudara perempuan se-ayah
if (this.ahliWaris.saudaraPerempuanSeAyah === 1) {
this._tambahBagianFaraidh('Saudara Perempuan Se-Ayah', 1, '1/2', 0.5);
} else {
this._tambahBagianFaraidh(`Saudara Perempuan Se-Ayah (${this.ahliWaris.saudaraPerempuanSeAyah} orang)`, this.ahliWaris.saudaraPerempuanSeAyah, '2/3', 2/3);
}
}
}
/**
* Proses saudara se-ibu
* @private
*/
_prosesSaudaraSeIbu() {
const totalSaudaraSeIbu = this.ahliWaris.saudaraLakiSeIbu + this.ahliWaris.saudaraPerempuanSeIbu;
if (totalSaudaraSeIbu > 0) {
// Hanya jika tidak ada keturunan, tidak ada ayah, dan tidak ada kakek
if (!this._adaKeturunan() && this.ahliWaris.ayah === 0 && this.ahliWaris.kakekDariAyah === 0) {
if (totalSaudaraSeIbu === 1) {
this._tambahBagianFaraidh('Saudara Se-Ibu', 1, '1/6', 1/6);
} else {
this._tambahBagianFaraidh(`Saudara Se-Ibu (${totalSaudaraSeIbu} orang)`, totalSaudaraSeIbu, '1/3', 1/3);
}
}
}
}
/**
* Proses asabah yang tersisa
* @private
*/
_prosesAshobah() {
// Hanya jika masih ada harta tersisa dan tidak ada asabah prioritas tinggi
const adaAshobahTinggi = this._adaAshobahTinggi();
if (!adaAshobahTinggi) {
// Anak laki saudara kandung
if (this.ahliWaris.anakLakiSaudaraKandung > 0) {
this._tambahBagianAshobah(`Anak Laki Saudara Kandung (${this.ahliWaris.anakLakiSaudaraKandung} orang)`, this.ahliWaris.anakLakiSaudaraKandung, 3, 'Asabah bi nafsihi');
}
// Anak laki saudara se-ayah (jika tidak ada anak laki saudara kandung)
else if (this.ahliWaris.anakLakiSaudaraSeAyah > 0) {
this._tambahBagianAshobah(`Anak Laki Saudara Se-Ayah (${this.ahliWaris.anakLakiSaudaraSeAyah} orang)`, this.ahliWaris.anakLakiSaudaraSeAyah, 4, 'Asabah bi nafsihi');
}
// Paman kandung ayah
else if (this.ahliWaris.pamanKandungAyah > 0) {
this._tambahBagianAshobah(`Paman Kandung Ayah (${this.ahliWaris.pamanKandungAyah} orang)`, this.ahliWaris.pamanKandungAyah, 5, 'Asabah bi nafsihi');
}
// Anak laki paman kandung
else if (this.ahliWaris.anakLakiPamanKandung > 0) {
this._tambahBagianAshobah(`Anak Laki Paman Kandung (${this.ahliWaris.anakLakiPamanKandung} orang)`, this.ahliWaris.anakLakiPamanKandung, 6, 'Asabah bi nafsihi');
}
}
}
/**
* Tangani kasus khusus (Aul dan Radd)
* @private
*/
_tanganiKasusKhusus() {
const totalBagianFaraidh = this.bagianFaraidh.reduce((jumlah, ahliWaris) => jumlah + ahliWaris.pecahan, 0);
if (totalBagianFaraidh > 1) {
// Kasus Aul - total bagian melebihi 1
this._tanganiAul(totalBagianFaraidh);
} else if (totalBagianFaraidh < 1 && this.bagianAshobah.length === 0) {
// Kasus Radd - harta tersisa dikembalikan ke ahli waris faraidh (kecuali pasangan)
this._tanganiRadd(1 - totalBagianFaraidh);
}
}
/**
* Tangani Aul (pengurangan proporsional)
* @private
*/
_tanganiAul(totalBagian) {
this.kasusKhusus = 'aul';
this.nilaiAul = totalBagian;
// Sesuaikan semua bagian faraidh secara proporsional
for (let ahliWaris of this.bagianFaraidh) {
ahliWaris.pecahanDisesuaikan = ahliWaris.pecahan / totalBagian;
ahliWaris.jumlah = Math.round(this.hartaBersih * ahliWaris.pecahanDisesuaikan);
ahliWaris.catatan = `Disesuaikan karena Aul (${this._formatPecahan(totalBagian)})`;
}
// Kosongkan asabah karena tidak ada sisa
this.bagianAshobah = [];
}
/**
* Tangani Radd (kembalikan harta tersisa ke ahli waris yang berhak)
* @private
*/
_tanganiRadd(pecahanTersisa) {
this.kasusKhusus = 'radd';
this.nilaiRadd = pecahanTersisa;
// Yang berhak Radd: semua ahli waris faraidh kecuali pasangan
const berhakRadd = this.bagianFaraidh.filter(ahliWaris =>
!ahliWaris.nama.includes('Suami') && !ahliWaris.nama.includes('Istri')
);
if (berhakRadd.length > 0) {
const totalBagianBerhak = berhakRadd.reduce((jumlah, ahliWaris) => jumlah + ahliWaris.pecahan, 0);
const jumlahTersisa = Math.round(this.hartaBersih * pecahanTersisa);
for (let ahliWaris of berhakRadd) {
const tambahanJumlah = Math.round((jumlahTersisa * ahliWaris.pecahan) / totalBagianBerhak);
ahliWaris.jumlah += tambahanJumlah;
ahliWaris.catatan = `Termasuk Radd (${this._formatPecahan(pecahanTersisa)})`;
}
}
}
/**
* Tambah bagian faraidh
* @private
*/
_tambahBagianFaraidh(nama, jumlah, stringPecahan, pecahan) {
this.bagianFaraidh.push({
nama: nama,
jumlah: Math.round(this.hartaBersih * pecahan),
jumlahOrang: jumlah,
stringPecahan: stringPecahan,
pecahan: pecahan,
jenis: 'faraidh'
});
}
/**
* Tambah bagian asabah
* @private
*/
_tambahBagianAshobah(nama, jumlah, prioritas, deskripsi) {
this.bagianAshobah.push({
nama: nama,
jumlahOrang: jumlah,
prioritas: prioritas,
deskripsi: deskripsi,
jenis: 'asabah'
});
}
/**
* Periksa apakah ada keturunan
* @private
*/
_adaKeturunan() {
return this.ahliWaris.anakLaki > 0 || this.ahliWaris.anakPerempuan > 0 ||
this.ahliWaris.cucuLakiDariAnakLaki > 0 || this.ahliWaris.cucuPerempuanDariAnakLaki > 0;
}
/**
* Periksa apakah ada saudara
* @private
*/
_adaSaudara() {
return this.ahliWaris.saudaraLakiKandung > 0 || this.ahliWaris.saudaraPerempuanKandung > 0 ||
this.ahliWaris.saudaraLakiSeAyah > 0 || this.ahliWaris.saudaraPerempuanSeAyah > 0 ||
this.ahliWaris.saudaraLakiSeIbu > 0 || this.ahliWaris.saudaraPerempuanSeIbu > 0;
}
/**
* Periksa apakah ada asabah prioritas tinggi
* @private
*/
_adaAshobahTinggi() {
// Periksa asabah yang ada dengan prioritas tinggi
return this.bagianAshobah.some(ahliWaris => ahliWaris.prioritas <= 2);
}
/**
* Hitung dan distribusikan jumlah asabah
* @private
*/
_hitungJumlahAshobah() {
if (this.bagianAshobah.length === 0) return;
// Hitung harta tersisa setelah faraidh
const totalFaraidh = this.bagianFaraidh.reduce((jumlah, ahliWaris) => jumlah + ahliWaris.jumlah, 0);
const hartaTersisa = this.hartaBersih - totalFaraidh;
if (hartaTersisa <= 0) return;
// Urutkan asabah berdasarkan prioritas
const ashobahTerurut = this.bagianAshobah.sort((a, b) => a.prioritas - b.prioritas);
// Berikan semua sisa ke grup asabah prioritas tertinggi
const prioritasTertinggi = ashobahTerurut[0].prioritas;
const ahliWarisPrioritasTertinggi = ashobahTerurut.filter(ahliWaris => ahliWaris.prioritas === prioritasTertinggi);
if (ahliWarisPrioritasTertinggi.length === 1) {
ahliWarisPrioritasTertinggi[0].jumlah = hartaTersisa;
} else {
// Distribusikan di antara ahli waris dengan prioritas sama dengan rasio 2:1 jika berlaku
this._distribusikanDiantaraAshobah(ahliWarisPrioritasTertinggi, hartaTersisa);
}
// Hapus asabah prioritas rendah
this.bagianAshobah = ahliWarisPrioritasTertinggi;
}
/**
* Distribusikan jumlah di antara asabah dengan rasio 2:1
* @private
*/
_distribusikanDiantaraAshobah(ahliWaris, jumlah) {
let totalBagian = 0;
for (let waris of ahliWaris) {
// Ahli waris laki mendapat 2 bagian, perempuan mendapat 1 bagian
const bagian = waris.nama.toLowerCase().includes('laki') ||
waris.nama.toLowerCase().includes('ayah') ||
waris.nama.toLowerCase().includes('paman') ? 2 : 1;
totalBagian += bagian * waris.jumlahOrang;
waris.bagian = bagian;
}
for (let waris of ahliWaris) {
const totalBagianWaris = waris.bagian * waris.jumlahOrang;
waris.jumlah = Math.round((jumlah * totalBagianWaris) / totalBagian);
}
}
/**
* Format pecahan untuk tampilan
* @private
*/
_formatPecahan(desimal) {
const petaPecahan = {
0.5: '1/2',
0.25: '1/4',
0.125: '1/8',
0.333333: '1/3',
0.166667: '1/6',
0.666667: '2/3',
0.75: '3/4'
};
const dibulatkan = Math.round(desimal * 1000000) / 1000000;
for (let [kunci, nilai] of Object.entries(petaPecahan)) {
if (Math.abs(dibulatkan - parseFloat(kunci)) < 0.001) {
return nilai;
}
}
return desimal.toFixed(6);
}
/**
* Format mata uang
* @private
*/
_formatMataUang(jumlah) {
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(jumlah);
}
/**
* Dapatkan hasil akhir
* @private
*/
_dapatkanHasil() {
// Hitung jumlah asabah
this._hitungJumlahAshobah();
// Hitung total
const totalFaraidh = this.bagianFaraidh.reduce((jumlah, ahliWaris) => jumlah + ahliWaris.jumlah, 0);
const totalAshobah = this.bagianAshobah.reduce((jumlah, ahliWaris) => jumlah + (ahliWaris.jumlah || 0), 0);
const totalTerdistribusi = totalFaraidh + totalAshobah;
const tersisa = this.hartaBersih - totalTerdistribusi;
return {
harta: {
totalHarta: this.totalHarta,
hutang: this.hutang,
biayaPemakaman: this.biayaPemakaman,
wasiat: this.wasiat,
hartaBersih: this.hartaBersih
},
ahliWaris: { ...this.ahliWaris },
distribusi: {
faraidh: this.bagianFaraidh.map(ahliWaris => ({
...ahliWaris,
jumlahTerformat: this._formatMataUang(ahliWaris.jumlah)
})),
asabah: this.bagianAshobah.map(ahliWaris => ({
...ahliWaris,
jumlahTerformat: this._formatMataUang(ahliWaris.jumlah || 0)
})),
kasusKhusus: this.kasusKhusus,
nilaiAul: this.nilaiAul,
nilaiRadd: this.nilaiRadd
},
ringkasan: {
totalFaraidh: totalFaraidh,
totalAshobah: totalAshobah,
totalTerdistribusi: totalTerdistribusi,
tersisa: tersisa,
totalAhliWaris: this.bagianFaraidh.length + this.bagianAshobah.length,
totalFaraidhTerformat: this._formatMataUang(totalFaraidh),
totalAshobahTerformat: this._formatMataUang(totalAshobah),
totalTerdistribusiTerformat: this._formatMataUang(totalTerdistribusi),
tersisaTerformat: this._formatMataUang(tersisa)
}
};
}
/**
* Buat laporan detail
*/
buatLaporan() {
const hasil = this._dapatkanHasil();
let laporan = "=".repeat(70) + "\n";
laporan += " LAPORAN PERHITUNGAN FARAIDH\n";
laporan += " (Berdasarkan Skema Flowchart)\n";
laporan += "=".repeat(70) + "\n\n";
// Informasi Harta
laporan += "INFORMASI HARTA:\n";
laporan += "-".repeat(35) + "\n";
laporan += `Total Harta : ${this._formatMataUang(hasil.harta.totalHarta)}\n`;
laporan += `Hutang : ${this._formatMataUang(hasil.harta.hutang)}\n`;
laporan += `Biaya Pemakaman : ${this._formatMataUang(hasil.harta.biayaPemakaman)}\n`;
laporan += `Wasiat : ${this._formatMataUang(hasil.harta.wasiat)}\n`;
laporan += `Harta Bersih : ${this._formatMataUang(hasil.harta.hartaBersih)}\n\n`;
// Bagian Faraidh
if (hasil.distribusi.faraidh.length > 0) {
laporan += "BAGIAN FARAIDH (Bagian Tetap):\n";
laporan += "-".repeat(50) + "\n";
for (let ahliWaris of hasil.distribusi.faraidh) {
laporan += `${ahliWaris.nama.padEnd(30)} : ${ahliWaris.stringPecahan.padEnd(8)} = ${ahliWaris.jumlahTerformat}\n`;
if (ahliWaris.catatan) {
laporan += ` Catatan: ${ahliWaris.catatan}\n`;
}
}
laporan += "\n";
}
// Bagian Asabah
if (hasil.distribusi.asabah.length > 0) {
laporan += "BAGIAN ASABAH (Bagian Sisa):\n";
laporan += "-".repeat(50) + "\n";
for (let ahliWaris of hasil.distribusi.asabah) {
laporan += `${ahliWaris.nama.padEnd(30)} : ${ahliWaris.jumlahTerformat}\n`;
laporan += ` ${ahliWaris.deskripsi}\n`;
}
laporan += "\n";
}
// Kasus Khusus
if (hasil.distribusi.kasusKhusus) {
laporan += "KASUS KHUSUS:\n";
laporan += "-".repeat(30) + "\n";
if (hasil.distribusi.kasusKhusus === 'aul') {
laporan += `Kasus AUL - Total bagian: ${this._formatPecahan(hasil.distribusi.nilaiAul)}\n`;
laporan += "Semua bagian faraidh disesuaikan secara proporsional.\n\n";
} else if (hasil.distribusi.kasusKhusus === 'radd') {
laporan += `Kasus RADD - Pecahan tersisa: ${this._formatPecahan(hasil.distribusi.nilaiRadd)}\n`;
laporan += "Harta tersisa dikembalikan ke ahli waris faraidh yang berhak (kecuali pasangan).\n\n";
}
}
// Ringkasan
laporan += "RINGKASAN:\n";
laporan += "-".repeat(30) + "\n";
laporan += `Total Faraidh : ${hasil.ringkasan.totalFaraidhTerformat}\n`;
laporan += `Total Asabah : ${hasil.ringkasan.totalAshobahTerformat}\n`;
laporan += `Total Terdistribusi : ${hasil.ringkasan.totalTerdistribusiTerformat}\n`;
laporan += `Tersisa : ${hasil.ringkasan.tersisaTerformat}\n`;
laporan += `Total Ahli Waris : ${hasil.ringkasan.totalAhliWaris} orang\n\n`;
laporan += "=".repeat(70) + "\n";
laporan += "Dibuat oleh Kalkulator Faraidh (Berbasis Skema)\n";
laporan += "=".repeat(70);
return laporan;
}
/**
* Ekspor hasil ke JSON
*/
eksporJSON() {
return JSON.stringify(this._dapatkanHasil(), null, 2);
}
}
// Ekspor untuk berbagai environment
if (typeof module !== 'undefined' && module.exports) {
module.exports = KalkulatorFaraidh;
} else if (typeof window !== 'undefined') {
window.KalkulatorFaraidh = KalkulatorFaraidh;
}
/**
* Contoh Penggunaan:
*
* const kalkulator = new KalkulatorFaraidh();
*
* kalkulator.setHarta({
* totalHarta: 1000000000,
* hutang: 100000000,
* biayaPemakaman: 50000000,
* wasiat: 150000000
* });
*
* kalkulator.setAhliWaris({
* istri: 1,
* anakLaki: 2,
* anakPerempuan: 1,
* ayah: 1,
* ibu: 1
* });
*
* const hasil = kalkulator.hitung();
* console.log(kalkulator.buatLaporan());
*/
// Export class untuk digunakan sebagai ES6 module
export { KalkulatorFaraidh };