package com.jasamedika.medifirst2000.service.impl;

import com.jasamedika.medifirst2000.constants.Master;
import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.*;
import com.jasamedika.medifirst2000.dto.RemunHargaJasa;
import com.jasamedika.medifirst2000.entities.*;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.RemunerasiService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.util.DateUtil;
import com.jasamedika.medifirst2000.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.jasamedika.medifirst2000.constants.Master.Departemen.RADIOLOGI;
import static com.jasamedika.medifirst2000.constants.Master.Departemen.*;
import static com.jasamedika.medifirst2000.constants.Master.GolonganProduk.KONSULTASI;
import static com.jasamedika.medifirst2000.constants.Master.GolonganProduk.VISIT;
import static com.jasamedika.medifirst2000.constants.Master.JenisPetugasPelaksana.*;
import static com.jasamedika.medifirst2000.constants.Master.JenisProduk.NONLOGBOOK;
import static com.jasamedika.medifirst2000.constants.Master.KategoryPegawai.DOKTER_LUAR;
import static com.jasamedika.medifirst2000.constants.Master.Kelas.NON_KELAS;
import static com.jasamedika.medifirst2000.constants.Master.KelompokPasien.KELOMPOK_BPJS;
import static com.jasamedika.medifirst2000.constants.Master.KomponenHarga.*;
import static com.jasamedika.medifirst2000.constants.Master.Profesi.TERAPI;
import static com.jasamedika.medifirst2000.constants.Master.Ruangan.*;
import static com.jasamedika.medifirst2000.constants.Master.SubUnitKerja.*;
import static com.jasamedika.medifirst2000.constants.Master.UnitKerja.KSM_OBGYN;
import static com.jasamedika.medifirst2000.enums.JenisMappingProdukPaket.PERAWAT;
import static com.jasamedika.medifirst2000.enums.JenisMappingProdukPaket.TINDAKAN_UTAMA;

@Service("RemunerasiService")
public class RemunerasiServiceImpl extends BaseVoServiceImpl implements RemunerasiService {

	@Autowired
	private BaseConverterImpl<ProgramKegiatanVO, ProgramKegiatan> programKegiatanConverter;

	@Autowired
	private BaseConverterImpl<UraianKegiatanVO, UraianKegiatan> uraianKegiatanConverter;

	@Autowired
	private BaseConverterImpl<IndikatorKualitasVO, IndikatorKualitas> indikatorKualitasConverter;

	@Autowired
	private BaseConverterImpl<KategoriPenilaianKualitasVO, KategoriPenilaianKualitas> kategoriPenilaianKualitasConverter;

	@Autowired
	private BaseConverterImpl<JabatanVO, Jabatan> jabatanConverter;

	@Autowired
	private BaseConverterImpl<PegawaiVO, Pegawai> pegawaiConverter;

	@Autowired
	private ProgramKegiatanDao programKegiatanDao;

	@Autowired
	private UraianKegiatanDao uraianKegiatanDao;

	@Autowired
	private IndikatorKualitasDao indikatorKualitasDao;

	@Autowired
	private KategoriPenilaianKualitasDao kategoriPenilaianKualitasDao;

	@Autowired
	private PegawaiJadwalKerjaDao pegawaiJadwalKerjaDao;

	@Autowired
	private PegawaiDao pegawaiDao;

	@Autowired
	private HabsenDao habsenDao;

	@Autowired
	private PelayananPasienDao pelayananPasienDao;

	@Autowired
	private PelayananPasienDetailDao pelayananPasienDetailDao;

	@Autowired
	private TargetRemunDokterDetailDao targetRemunDokterDetailDao;

	@Autowired
	private MapPegawaiLaboratRadiologiDao mapPegawaiLaboratRadiologiDao;

	@Autowired
	private MapProdukPaketDao mapProdukPaketDao;

	@Autowired
	private MapProdukPaketToProdukDao mapProdukPaketToProdukDao;

	@Autowired
	private HargaNettoProdukByKelasDDao hargaNettoProdukByKelasDDao;

	@Autowired
	private PasienDao pasienDao;

	@Autowired
	private MapJabatanProfesiDao mapJabatanProfesiDao;

	@Override
	public Map<String, Object> saveProgramKegiatan(ProgramKegiatanVO vo) {
		Map<String, Object> result = new HashMap<>();
		ProgramKegiatan model = new ProgramKegiatan();
		model = programKegiatanConverter.transferVOToModel(vo, model);
		if (CommonUtil.isNotNullOrEmpty(vo.getJabatanPelaksanaKegiatan())) {
			model.setJabatanPelaksanaKegiatan(
					jabatanConverter.transferVOToModel(vo.getJabatanPelaksanaKegiatan(), new Jabatan()));
		}
		if (CommonUtil.isNotNullOrEmpty(vo.getJabatanAtasanLangsung())) {
			model.setJabatanAtasanLangsung(
					jabatanConverter.transferVOToModel(vo.getJabatanAtasanLangsung(), new Jabatan()));
		}
		if (CommonUtil.isNotNullOrEmpty(vo.getPegawaiAtasanLangsung())) {
			model.setPegawaiAtasanLangsung(
					pegawaiConverter.transferVOToModel(vo.getPegawaiAtasanLangsung(), new Pegawai()));
		}
		ProgramKegiatan resultDomain = programKegiatanDao.save(model);
		if (CommonUtil.isNotNullOrEmpty(resultDomain)) {
			result.put("noRec", resultDomain.getNoRec());
		}
		return result;
	}

	@Override
	public Map<String, Object> saveUraianKegiatan(UraianKegiatanVO vo) {
		Map<String, Object> result = new HashMap<>();
		UraianKegiatan model = new UraianKegiatan();
		model = uraianKegiatanConverter.transferVOToModel(vo, model);
		if (CommonUtil.isNotNullOrEmpty(vo.getProgramKegiatan())) {
			model.setProgramKegiatan(
					programKegiatanConverter.transferVOToModel(vo.getProgramKegiatan(), new ProgramKegiatan()));
		}
		UraianKegiatan resultDomain = uraianKegiatanDao.save(model);
		if (CommonUtil.isNotNullOrEmpty(resultDomain)) {
			result.put("noRec", resultDomain.getNoRec());
		}
		return result;
	}

	@Override
	public Map<String, Object> saveIndikatorKualitas(IndikatorKualitasVO vo) {
		Map<String, Object> result = new HashMap<>();
		IndikatorKualitas model = new IndikatorKualitas();
		model = indikatorKualitasConverter.transferVOToModel(vo, model);
		if (CommonUtil.isNotNullOrEmpty(vo.getUraianKegiatan())) {
			model.setUraianKegiatan(
					uraianKegiatanConverter.transferVOToModel(vo.getUraianKegiatan(), new UraianKegiatan()));
		}
		IndikatorKualitas resultDomain = indikatorKualitasDao.save(model);
		if (CommonUtil.isNotNullOrEmpty(resultDomain)) {
			result.put("noRec", resultDomain.getNoRec());
		}
		return result;
	}

	@Override
	public Map<String, Object> saveKategoriPenilaianKualitas(KategoriPenilaianKualitasVO vo) {
		Map<String, Object> result = new HashMap<>();
		KategoriPenilaianKualitas model = new KategoriPenilaianKualitas();
		model = kategoriPenilaianKualitasConverter.transferVOToModel(vo, model);
		KategoriPenilaianKualitas resultDomain = kategoriPenilaianKualitasDao.save(model);
		if (CommonUtil.isNotNullOrEmpty(resultDomain)) {
			result.put("noRec", resultDomain.getNoRec());
		}
		return result;
	}

	@Override
	public Map<String, Object> getKuantitasCapaianHariKerja(Integer idPegawai, String bulan) {
		Map<String, Object> result;

		try {
			List<Map<String, Object>> data = new ArrayList<>();
			List<Map<String, Object>> detailReguler = new ArrayList<>();
			List<Map<String, Object>> detailOnSite = new ArrayList<>();

			SimpleDateFormat ddf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM");

			Date convertedDate = df.parse(bulan);

			Calendar c = Calendar.getInstance();
			c.setTime(convertedDate);
			c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));

			Date tglAwal = ddf.parse(bulan + "-01 00:00:00");
			Date tglAkhir = ddf.parse(sdf.format(c.getTime()) + " 23:59:59");

			result = pegawaiDao.getPegawaiCapaianKuantitas(idPegawai);
			List<Map<String, Object>> jadwal = pegawaiJadwalKerjaDao.getKuantitasHariKerja(idPegawai, tglAwal,
					tglAkhir);
			List<Map<String, Object>> presensi = habsenDao.getKuantitasCapaianHariKerja(idPegawai, tglAwal, tglAkhir);

			if (CommonUtil.isNotNullOrEmpty(jadwal)) {
				for (Map<String, Object> j : jadwal) {
					Map<String, Object> mapReguler = new HashMap<>();
					Map<String, Object> mapOnSite = new HashMap<>();
					for (Map<String, Object> p : presensi) {
						if (CommonUtil.isNotNullOrEmpty(result.get("shiftKerjaId"))
								&& Arrays.asList(Master.KelompokShift.ALL_NONSHIFT)
										.contains(Integer.parseInt(result.get("shiftKerjaId").toString()))
								&& result.get("jenisPegawaiId").equals(Master.JenisPegawai.DOKTER)
								&& CommonUtil.isNotNullOrEmpty(j.get("idKode"))
								&& Arrays.asList(Master.ShiftKerja.PSM)
										.contains(Integer.parseInt(j.get("idKode").toString()))
								&& p.get("tr_date").equals(j.get("tanggal"))
								&& CommonUtil.isNotNullOrEmpty(p.get("tr_date"))) {
							mapReguler.put("count", 1);
							mapReguler.put("tanggal", j.get("tanggal"));
							detailReguler.add(mapReguler);

							mapOnSite.put("count", 1);
							mapOnSite.put("tanggal", j.get("tanggal"));
							detailOnSite.add(mapOnSite);

							break;
						} else if (p.get("tr_date").equals(j.get("tanggal"))
								&& CommonUtil.isNotNullOrEmpty(p.get("tr_date"))) {
							mapReguler.put("count", 1);
							mapReguler.put("tanggal", j.get("tanggal"));
							detailReguler.add(mapReguler);

							break;
						}
					}
				}
			}

			for (int i = 0; i < 2; i++) {
				Map<String, Object> map = new HashMap<>();
				if (i == 0) {
					map.put("hariKerja", "Reguler");
					map.put("detail", detailReguler);
				} else {
					map.put("hariKerja", "On Site");
					map.put("detail", detailOnSite);
				}
				if (CommonUtil.isNotNullOrEmpty(map.get("detail"))) {
					data.add(map);
				}
			}

			result.put("kuantitas", data);
		} catch (ParseException e) {
			throw new ServiceVOException(e.getMessage());
		}

		return result;
	}

	@Override
	public Map<String, Object> splitRemunFfs(Integer idPegawai, String bulan) {
		Map<String, Object> result = new HashMap<>();
		DateFormat df = new SimpleDateFormat("yyyy-MM");
		DateTimeFormatter jamFormat = DateTimeFormatter.ofPattern("HH.mm");
		Date date;
		Date dateLine;
		try {
			date = df.parse(bulan);
			dateLine = df.parse(getSettingDataFixed("berlakuTargetJasaRemunDokter"));
		} catch (ParseException e) {
			return null;
		}
		/*
		 * Mendapatkan daftar jadwal kerja, tanggal dan jam kerja
		 */
		Date tglAwal = DateUtil.startMonth(date);
		Date tglAkhir = DateUtil.endMonth(date);
		List<Map<String, Object>> listJadwalKerja = pegawaiJadwalKerjaDao.findJamMasukJamPulang(idPegawai, tglAwal,
				tglAkhir);
		/*
		 * Mendapatkan nominal target remunerasi untuk simulasi
		 */
		Double targetRemun = 0.0;
		String sdTarget = getSettingDataFixed("targetRemunJasaDokter");
		if (CommonUtil.isNotNullOrEmpty(sdTarget))
			targetRemun = Double.parseDouble(sdTarget);
		/*
		 * Mendapatkan nominal target remunerasi yang telah dilakukan mapping
		 */
		TargetRemunDokterDetail target = targetRemunDokterDetailDao.findByPegawaiIdAndTmt(idPegawai, tglAwal, tglAkhir);
		if (CommonUtil.isNotNullOrEmpty(target) && CommonUtil.isNotNullOrEmpty(target.getRupiah()))
			targetRemun = target.getRupiah();
		/*
		 * Mendapatkan persentase jasa
		 */
		double persenOperator = Double.parseDouble(getSettingDataFixed("persenRemunOperatorIBS"));
		double persenAsistenIBS = Double.parseDouble(getSettingDataFixed("persenRemunAsistenIBS"));
		double persenAnestesi = Double.parseDouble(getSettingDataFixed("persenRemunAnestesiIBS"));
		double persenRadiologi = Double.parseDouble(getSettingDataFixed("persenRemunRadiologi"));
		double persenLaboratorium = Double.parseDouble(getSettingDataFixed("persenRemunLaboratorium"));
		double persenRehabMedik = Double.parseDouble(getSettingDataFixed("persenRemunRehabMedik"));
		double persenKonsultasi = Double.parseDouble(getSettingDataFixed("persenRemunKonsultasiDokter"));
		double persenVisite = Double.parseDouble(getSettingDataFixed("persenRemunVisiteDokter"));
		double persenTindakan = Double.parseDouble(getSettingDataFixed("persenRemunTindakanDokter"));
		double persenTarifJasaBedah = Double.parseDouble(getSettingDataFixed("persenTarifJasaBedah"));
		double persenTarifJasaICU = Double.parseDouble(getSettingDataFixed("persenTarifJasaICU"));
		double persenRemunDokterPA = Double.parseDouble(getSettingDataFixed("persenRemunDokterPA"));
		double persenRemunDokterUmumHD = Double.parseDouble(getSettingDataFixed("persenRemunDokterUmumHD"));
		double persenRemunLabGenetika = Double.parseDouble(getSettingDataFixed("persenRemunLabGenetika"));
		double persenRemunTerapis = Double.parseDouble(getSettingDataFixed("persenRemunTerapis"));
		double persenRemunVisiteDokterKelompokBudiRahmat = Double
				.parseDouble(getSettingDataFixed("persenRemunVisiteDokterKelompokBudiRahmat"));
		/*
		 * Persiapan filter logic remunerasi
		 */
		List<Integer> listDetailJenisProduk;
		List<Integer> listDetailJenisProdukException = new ArrayList<>();
		List<Integer> drKkPediatrikGDList = pegawaiDao.getDokterByKelompokKerja(KK_PEDIATRIK_GD);
		List<Integer> drAnastesiList = pegawaiDao.getDokterByKelompokKerja(KK_ANESTESI);
		List<Integer> drKsmUmumList = pegawaiDao.getDokterByKelompokKerja(KK_UMUM);
		List<Integer> drKkPerinatologiList = pegawaiDao.getDokterByKelompokKerja(KK_PERINATOLOGI);
		List<Integer> drKkPatologiAnatomiList = pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_ANATOMI);
		List<Integer> drKkGenetika = pegawaiDao.getDokterByKelompokKerja(KK_GENETIKA);
		List<Integer> drKkRadiologi = pegawaiDao.getDokterByKelompokKerja(KK_RADIOLOGI);
		List<Integer> laboranRadiologList = mapPegawaiLaboratRadiologiDao.findPegawaiLaboranRadiolog();
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		List<Integer> idsRegDJPAdminNonPK = getNilaiDataFixByTMT("admin_nonpk", tglAwal);
		List<Integer> idsRegDJPMedisUtama = getNilaiDataFixByTMT("medis_utama", tglAwal);
		List<Integer> idsRegDJPPenunjangPA = getNilaiDataFixByTMT("penunjang_pa", tglAwal);
		List<Integer> idsRegDJPPenunjangPK = getNilaiDataFixByTMT("penunjang_pk", tglAwal);
		List<Integer> idsRegDJPPenunjangRad = getNilaiDataFixByTMT("penunjang_radiologi", tglAwal);
		List<Integer> idsDokterUmumIGD = getNilaiDataFixByTMT("pr_dokter_umum_igd", tglAwal);
		List<Integer> idsDokterUmumExclude = getNilaiDataFixByTMT("pr_dokter_umum_exclude", tglAwal);
		List<Integer> idsDokterPerinatologi = getNilaiDataFixByTMT("pr_dokter_perinatologi", tglAwal);
		List<Integer> idsPenunjangBukanAnestesi = getNilaiDataFixByTMT("pr_penunjang_nonanestesi", tglAwal);
		List<Integer> idsDokterBPJSffs = splitDataSettingDatafixed("dokterBPJSffs");
		List<Integer> idsDokterPediatrikGD = getNilaiDataFixByTMT("pr_dokter_pediatrik_gd", tglAwal);
		List<Integer> listIdPegawaiRemunKelompokBudiRahmat = splitDataSettingDatafixed(
				"listIdPegawaiRemunKelompokBudiRahmat");
		List<Integer> idsMonitoringIntervensi = getNilaiDataFixByTMT("idMonitoringIntervensi", tglAwal);
		List<Integer> idsMonitoringHemodinamikGagalOrgan = getNilaiDataFixByTMT("idMonitoringHemodinamikGagalOrgan",
				tglAwal);
		List<Integer> idsLabGenetikaLuarRuangan = getNilaiDataFixByTMT("idProdukLabGenetikaLuarRuangan", tglAwal);
		List<Integer> idsKepalaPaketFixedPay = getNilaiDataFixByTMT("idProdukKepalaPaketFixedPay", tglAwal);
		List<Integer> paketBukanFixedPay = getNilaiDataFixByTMT("produkPaketBukanFixedPay", tglAwal);
		List<Integer> idsKarcis = getNilaiDataFixByTMT("listKarcisIdProduk", tglAwal);
		if (drKkPatologiAnatomiList.contains(idPegawai)) {
			listDetailJenisProduk = idsRegDJPPenunjangPA;
		} else if (pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_KLINIK).contains(idPegawai)) {
			listDetailJenisProduk = idsRegDJPPenunjangPK;
		} else if (drKkRadiologi.contains(idPegawai)) {
			listDetailJenisProduk = idsRegDJPPenunjangRad;
		} else {
			listDetailJenisProduk = idsRegDJPMedisUtama;
		}
		if (laboranRadiologList.contains(idPegawai)) {
			listDetailJenisProdukException = idsRegDJPAdminNonPK;
			listDetailJenisProdukException.removeAll(listDetailJenisProduk);
		}
		/*
		 * Mendapatkan data mentah pelayanan pasien
		 */
		List<Map<String, Object>> listRatedPay = pelayananPasienDao.findPelayananPasienByPetugasAndTanggal(idPegawai,
				tglAwal, tglAkhir, idsKarcis);
		/*
		 * Pemisahan produk kepala paket untuk fixed pay
		 */
		List<Map<String, Object>> listKepalaPaketFixedPay = listRatedPay.stream()
				.filter(d -> idsKepalaPaketFixedPay.contains(Integer.parseInt(d.get("idProduk").toString())))
				.collect(Collectors.toList());
		listRatedPay = listRatedPay.stream()
				.filter(d -> !idsKepalaPaketFixedPay.contains(Integer.parseInt(d.get("idProduk").toString())))
				.collect(Collectors.toList());
		List<Integer> allPaketId = mapProdukPaketDao.findProdukEntriId();
		List<Integer> revisedPaketId = allPaketId.stream().filter(p -> !paketBukanFixedPay.contains(p))
				.collect(Collectors.toList());
		List<Map<String, Object>> listFixedPay = listRatedPay.stream()
				.filter(d -> revisedPaketId.contains(Integer.parseInt(d.get("idProduk").toString())))
				.collect(Collectors.toList());
		/*
		 * Filtering selain logbook fixed pay
		 */
		revisedPaketId.addAll(mapProdukPaketDao.findPaketId());
		listRatedPay = listRatedPay.stream()
				.filter(d -> !revisedPaketId.contains(Integer.parseInt(d.get("idProduk").toString())))
				.collect(Collectors.toList());
		/*
		 * Set persen jasa dan harga jasa pasien bpjs di ibs, icu
		 */
		double persenTarifIBS = persenTarifJasaBedah / 100;
		double persenTarifICU = persenTarifJasaICU / 100;
		/*
		 * Mapping set awal persentase jasa remunerasi dan harga jasa remunerasi
		 */
		if (pegawaiDao.getPegawaiByKategoryPegawai(Arrays.asList(DOKTER_LUAR)).contains(idPegawai))
			persenVisite = persenRemunVisiteDokterKelompokBudiRahmat;
		for (Map<String, Object> d : listRatedPay) {
			if (paketBukanFixedPay.contains(Integer.parseInt(d.get("idProduk").toString())))
				d.put("hargaJual", d.get("komponenTotalTarif"));
			d.put("isTermasukProporsi", true);
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterUmumHD / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunTerapis / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenOperator / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenAsistenIBS / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenAnestesi / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (REHAB_MEDIK.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRehabMedik / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (KONSULTASI.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenKonsultasi / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (VISIT.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenVisite / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkGenetika.contains(idPegawai)
					&& idsLabGenetikaLuarRuangan.contains(Integer.parseInt(d.get("idProduk").toString()))
					&& (date.before(new Date(1690822799000L)) || date.equals(new Date(1690822799000L)))) {
				/*
				 * A rule for claimed <= Jul 31th 2023
				 */
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunLabGenetika / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (Arrays.asList(GENETIKA).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunLabGenetika / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (drKkPatologiAnatomiList.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterPA / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (LABORATORIUM.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenLaboratorium / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
				if (!DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")))
					d.put("isTermasukProporsi", false);
			} else if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
					&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				double persenJasa = persenTindakan / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifICU, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("hargaJasa", hargaJasa.getNilai());
			}
		}
		/*
		 * Filtered by proporsi jasa layanan
		 */
		listRatedPay = listRatedPay.stream().filter(d -> Boolean.parseBoolean(d.get("isTermasukProporsi").toString()))
				.collect(Collectors.toList());
		/*
		 * Inisialisasi collect logbook klaim MPP
		 */
		List<Map<String, Object>> listPelayananKlaimMpp = new ArrayList<>();
		/*
		 * Alokasi data diambil terlebih dahulu untuk kelompok BPJS, Jaminan
		 * Kemenkes
		 */
		List<Map<String, Object>> rawDataBpjs0 = listRatedPay
				.stream().filter(d -> CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien")) && Arrays
						.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				.collect(Collectors.toList());
		/*
		 * Filter tindakan operasi untuk pasien BPJS hanya diambil tarif
		 * tertinggi saja dalam satu siklus pelayanan
		 */
		List<Map<String, Object>> rawDataBpjs1 = new ArrayList<>();
		{
			List<Map<String, Object>> bpjsBedahSentral = rawDataBpjs0.stream()
					.filter(d -> BEDAH_SENTRAL.equals(d.get("idDepartemen")))
					.sorted(Comparator.comparing(o -> Double.parseDouble(o.get("jumlah").toString()),
							Comparator.reverseOrder()))
					.sorted(Comparator.comparing(o -> Double.parseDouble(o.get("hargaJual").toString()),
							Comparator.reverseOrder()))
					.sorted(Comparator.comparing(o -> o.get("idPasienDaftar").toString())).collect(Collectors.toList());
			List<String> listIdPelayananPasien = new ArrayList<>();
			List<String> listIdPasienDaftar = new ArrayList<>();
			for (Map<String, Object> b : bpjsBedahSentral)
				if (!listIdPasienDaftar.contains(b.get("idPasienDaftar").toString())) {
					listIdPasienDaftar.add(b.get("idPasienDaftar").toString());
					listIdPelayananPasien.add(b.get("idPelayananPasien").toString());
				}
			for (Map<String, Object> d : rawDataBpjs0)
				if (BEDAH_SENTRAL.equals(d.get("idDepartemen"))
						&& listIdPelayananPasien.contains(d.get("idPelayananPasien").toString())) {
					rawDataBpjs1.add(d);
				} else if (!BEDAH_SENTRAL.equals(d.get("idDepartemen"))) {
					rawDataBpjs1.add(d);
				} else {
					listPelayananKlaimMpp.add(d);
				}
		}
		/*
		 * Filter visite untuk pasien BPJS hanya diambil maksimal 1 kali per
		 * pasien di luar dokter-dokter kk eria
		 */
		List<Map<String, Object>> rawDataBpjs2 = new ArrayList<>();
		if (!drKkPediatrikGDList.contains(idPegawai)) {
			/*
			 * Dapatkan semua pendaftaran BPJS untuk visite di luar
			 * dokter-dokter kk eria
			 */
			List<Map<String, Object>> listEpisode = new ArrayList<>();
			for (Map<String, Object> d : rawDataBpjs1) {
				if (VISIT.equals(d.get("idGolonganProduk"))) {
					boolean existEpisode = false;
					for (Map<String, Object> e : listEpisode)
						if (e.get("id").toString().equals(d.get("idPasienDaftar"))
								&& Integer.valueOf(e.get("idProduk").toString()).equals(d.get("idProduk"))
								&& e.get("tanggal").toString().equals(d.get("tanggal")))
							existEpisode = true;
					if (!existEpisode) {
						Map<String, Object> episode = new HashMap<>();
						episode.put("id", d.get("idPasienDaftar"));
						episode.put("idProduk", d.get("idProduk"));
						episode.put("tanggal", d.get("tanggal"));
						episode.put("count", 1);
						listEpisode.add(episode);
					}
				}
			}
			/*
			 * Assign to next new collection
			 */
			int maxVisit = 1;
			for (Map<String, Object> d : rawDataBpjs1) {
				int count = 1;
				for (Map<String, Object> e : listEpisode)
					if (VISIT.equals(d.get("idGolonganProduk"))) {
						if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) <= maxVisit) {
							rawDataBpjs2.add(d);
							count = Integer.parseInt(e.get("count").toString());
							count++;
							e.put("count", count);
							break;
						} else if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) > maxVisit) {
							listPelayananKlaimMpp.add(d);
						}
					} else {
						break;
					}
				if (!VISIT.equals(d.get("idGolonganProduk")) && count == 1)
					rawDataBpjs2.add(d);
			}
		} else {
			rawDataBpjs2.addAll(rawDataBpjs1);
		}
		/*
		 * Filter visite untuk pasien BPJS hanya diambil maksimal 2 kali per
		 * hari per dokter per pasien kk eria
		 */
		List<Map<String, Object>> rawDataBpjs3 = new ArrayList<>();
		if (drKkPediatrikGDList.contains(idPegawai)) {
			/*
			 * Dapatkan semua pendaftaran BPJS untuk visite dokter-dokter kk
			 * eria
			 */
			List<Map<String, Object>> listEpisode = new ArrayList<>();
			for (Map<String, Object> d : rawDataBpjs2) {
				if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
						&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))
						&& VISIT.equals(d.get("idGolonganProduk"))) {
					boolean existEpisode = false;
					for (Map<String, Object> e : listEpisode)
						if (e.get("id").toString().equals(d.get("idPasienDaftar"))
								&& Integer.valueOf(e.get("idProduk").toString()).equals(d.get("idProduk"))
								&& e.get("tanggal").toString().equals(d.get("tanggal")))
							existEpisode = true;
					if (!existEpisode) {
						Map<String, Object> episode = new HashMap<>();
						episode.put("id", d.get("idPasienDaftar"));
						episode.put("idProduk", d.get("idProduk"));
						episode.put("tanggal", d.get("tanggal"));
						episode.put("count", 1);
						listEpisode.add(episode);
					}
				}
			}
			/*
			 * Assign to next new collection
			 */
			int maxVisit = 2;
			for (Map<String, Object> d : rawDataBpjs2) {
				int count = 1;
				for (Map<String, Object> e : listEpisode)
					if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
							&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))
							&& VISIT.equals(d.get("idGolonganProduk"))) {
						if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) <= maxVisit) {
							rawDataBpjs3.add(d);
							count = Integer.parseInt(e.get("count").toString());
							count++;
							e.put("count", count);
							break;
						} else if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) > maxVisit) {
							listPelayananKlaimMpp.add(d);
						}
					} else {
						break;
					}
				if ((CommonUtil.isNullOrEmpty(d.get("idRuangan")) || (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
						&& !Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))))
						|| !VISIT.equals(d.get("idGolonganProduk")) && count == 1)
					rawDataBpjs3.add(d);
			}
		} else {
			rawDataBpjs3.addAll(rawDataBpjs2);
		}
		/*
		 * Filter monitoring hemodinamik gagal organ untuk pasien BPJS hanya
		 * diambil maksimal 2 kali per hari per pasien per dokter kk eria
		 */
		List<Map<String, Object>> rawDataBpjs4 = new ArrayList<>();
		if (drKkPediatrikGDList.contains(idPegawai)) {
			/*
			 * Dapatkan semua pendaftaran BPJS untuk monitoring hemodinamik
			 * gagal organ dokter-dokter kk eria
			 */
			List<Map<String, Object>> listEpisode = new ArrayList<>();
			for (Map<String, Object> d : rawDataBpjs3) {
				if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
						&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))
						&& idsMonitoringHemodinamikGagalOrgan
								.contains(Integer.parseInt(d.get("idProduk").toString()))) {
					boolean existEpisode = false;
					for (Map<String, Object> e : listEpisode)
						if (e.get("id").toString().equals(d.get("idPasienDaftar"))
								&& Integer.valueOf(e.get("idProduk").toString()).equals(d.get("idProduk"))
								&& e.get("tanggal").toString().equals(d.get("tanggal")))
							existEpisode = true;
					if (!existEpisode) {
						Map<String, Object> episode = new HashMap<>();
						episode.put("id", d.get("idPasienDaftar"));
						episode.put("idProduk", d.get("idProduk"));
						episode.put("tanggal", d.get("tanggal"));
						episode.put("count", 1);
						listEpisode.add(episode);
					}
				}
			}
			/*
			 * Assign to next new collection
			 */
			int maxMonitoring = 2;
			for (Map<String, Object> d : rawDataBpjs3) {
				int count = 1;
				for (Map<String, Object> e : listEpisode)
					if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
							&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))
							&& idsMonitoringHemodinamikGagalOrgan
									.contains(Integer.parseInt(d.get("idProduk").toString()))) {
						if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) <= maxMonitoring) {
							rawDataBpjs4.add(d);
							count = Integer.parseInt(e.get("count").toString());
							count++;
							e.put("count", count);
							break;
						} else if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) > maxMonitoring) {
							listPelayananKlaimMpp.add(d);
						}
					} else {
						break;
					}
				if ((CommonUtil.isNullOrEmpty(d.get("idRuangan")) || (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
						&& !Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))))
						|| !idsMonitoringHemodinamikGagalOrgan.contains(Integer.parseInt(d.get("idProduk").toString()))
								&& count == 1) {
					rawDataBpjs4.add(d);
				} else if ((CommonUtil.isNullOrEmpty(d.get("idRuangan"))
						|| (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
								&& !Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))))
						|| !idsMonitoringHemodinamikGagalOrgan.contains(Integer.parseInt(d.get("idProduk").toString()))
								&& count > 1) {
					listPelayananKlaimMpp.add(d);
				}
			}
		} else {
			rawDataBpjs4.addAll(rawDataBpjs3);
		}
		/*
		 * Filter monitoring intervensi untuk pasien BPJS hanya diambil maksimal
		 * 2 kali per hari per pasien per dokter kk perinatologi
		 */
		List<Map<String, Object>> rawDataBpjs5 = new ArrayList<>();
		if (drKkPerinatologiList.contains(idPegawai)) {
			/*
			 * Dapatkan semua pendaftaran BPJS untuk monitoring intervensi
			 * dokter-dokter kk perinatologi
			 */
			List<Map<String, Object>> listEpisode = new ArrayList<>();
			for (Map<String, Object> d : rawDataBpjs4) {
				if ((NICU.equals(d.get("idRuangan")) || NICU_COVID.equals(d.get("idRuangan")))
						&& idsMonitoringIntervensi.contains(Integer.parseInt(d.get("idProduk").toString()))) {
					boolean existEpisode = false;
					for (Map<String, Object> e : listEpisode)
						if (e.get("id").toString().equals(d.get("idPasienDaftar"))
								&& Integer.valueOf(e.get("idProduk").toString()).equals(d.get("idProduk"))
								&& e.get("tanggal").toString().equals(d.get("tanggal")))
							existEpisode = true;
					if (!existEpisode) {
						Map<String, Object> episode = new HashMap<>();
						episode.put("id", d.get("idPasienDaftar"));
						episode.put("idProduk", d.get("idProduk"));
						episode.put("tanggal", d.get("tanggal"));
						episode.put("count", 1);
						listEpisode.add(episode);
					}
				}
			}
			/*
			 * Assign to next new collection
			 */
			int maxMonitoring = 2;
			for (Map<String, Object> d : rawDataBpjs4) {
				int count = 1;
				for (Map<String, Object> e : listEpisode)
					if ((NICU.equals(d.get("idRuangan")) || NICU_COVID.equals(d.get("idRuangan")))
							&& idsMonitoringIntervensi.contains(Integer.parseInt(d.get("idProduk").toString()))) {
						if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) <= maxMonitoring) {
							rawDataBpjs5.add(d);
							count = Integer.parseInt(e.get("count").toString());
							count++;
							e.put("count", count);
							break;
						} else if (d.get("idPasienDaftar").toString().equals(e.get("id"))
								&& Integer.valueOf(d.get("idProduk").toString()).equals(e.get("idProduk"))
								&& d.get("tanggal").toString().equals(e.get("tanggal"))
								&& Integer.parseInt(e.get("count").toString()) > maxMonitoring) {
							listPelayananKlaimMpp.add(d);
						}
					} else {
						break;
					}
				if (((!NICU.equals(d.get("idRuangan")) && !NICU_COVID.equals(d.get("idRuangan")))
						|| !idsMonitoringIntervensi.contains(Integer.parseInt(d.get("idProduk").toString())))
						&& count == 1) {
					rawDataBpjs5.add(d);
				} else if (((!NICU.equals(d.get("idRuangan")) && !NICU_COVID.equals(d.get("idRuangan")))
						|| !idsMonitoringIntervensi.contains(Integer.parseInt(d.get("idProduk").toString())))
						&& count > 1) {
					listPelayananKlaimMpp.add(d);
				}
			}
		} else {
			rawDataBpjs5.addAll(rawDataBpjs4);
		}
		/*
		 * Alokasi data diurutkan dulu untuk jam kerja. Asumsi jam kerja dokter
		 * nonshift
		 */
		List<Map<String, Object>> listDataJamKerja = new ArrayList<>();
		for (Map<String, Object> d : listRatedPay) {
			d.put("isJamKerja", false);
			if (CommonUtil.isNotNullOrEmpty(d.get("tglPelayanan"))) {
				LocalDate tglPelayanan = ((Date) d.get("tglPelayanan")).toInstant().atZone(ZoneId.systemDefault())
						.toLocalDate();
				LocalDateTime tglJamPelayanan = ((Date) d.get("tglPelayanan")).toInstant()
						.atZone(ZoneId.systemDefault()).toLocalDateTime();
				for (Map<String, Object> j : listJadwalKerja) {
					if ((CommonUtil.isNullOrEmpty(d.get("idKelompokPasien"))
							|| (CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien")) && !Arrays.asList(KELOMPOK_BPJS)
									.contains(Integer.parseInt(d.get("idKelompokPasien").toString()))))
							&& CommonUtil.isNotNullOrEmpty(j.get("jamMasuk"))) {
						LocalDate tglMasuk = ((Date) j.get("tanggal")).toInstant().atZone(ZoneId.systemDefault())
								.toLocalDate();
						LocalTime jamMasuk = LocalTime.from(jamFormat.parse(j.get("jamMasuk").toString()));
						LocalTime jamPulang = LocalTime.from(jamFormat.parse(j.get("jamPulang").toString()));
						LocalDateTime tglJamMasuk = LocalDateTime.of(tglMasuk, jamMasuk);
						LocalDateTime tglJamPulang = LocalDateTime.of(tglMasuk, jamPulang);
						if (tglPelayanan.isEqual(tglMasuk)
								&& (tglJamMasuk.isBefore(tglJamPelayanan) || tglJamMasuk.isEqual(tglJamPelayanan))
								&& (tglJamPelayanan.isEqual(tglJamPulang) || tglJamPelayanan.isBefore(tglJamPulang))) {
							d.put("isJamKerja", true);
							listDataJamKerja.add(d);
							break;
						}
					}
				}
			}
		}
		/*
		 * Setelah diurutkan jam kerja, alokasi urutan data di luar jam kerja.
		 * Asumsi jam kerja dokter nonshift
		 */
		List<Map<String, Object>> listDataLuarJamKerja = new ArrayList<>();
		for (Map<String, Object> d : listRatedPay) {
			if (CommonUtil.isNotNullOrEmpty(d.get("tglPelayanan"))) {
				LocalDate tglPelayanan = ((Date) d.get("tglPelayanan")).toInstant().atZone(ZoneId.systemDefault())
						.toLocalDate();
				LocalDateTime tglJamPelayanan = ((Date) d.get("tglPelayanan")).toInstant()
						.atZone(ZoneId.systemDefault()).toLocalDateTime();
				for (Map<String, Object> j : listJadwalKerja) {
					LocalDate tglMasuk = ((Date) j.get("tanggal")).toInstant().atZone(ZoneId.systemDefault())
							.toLocalDate();
					if (CommonUtil.isNullOrEmpty(d.get("idKelompokPasien"))
							|| (CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien")) && !Arrays.asList(KELOMPOK_BPJS)
									.contains(Integer.parseInt(d.get("idKelompokPasien").toString()))))
						if (CommonUtil.isNullOrEmpty(j.get("jamMasuk"))) {
							if (tglPelayanan.isEqual(tglMasuk)) {
								if ("Reguler".equals(d.get("jenisRuangan").toString()))
									d.put("isJamKerja", true);
								listDataLuarJamKerja.add(d);
								break;
							}
						} else {
							LocalTime jamMasuk = LocalTime.from(jamFormat.parse(j.get("jamMasuk").toString()));
							LocalTime jamPulang = LocalTime.from(jamFormat.parse(j.get("jamPulang").toString()));
							LocalDateTime tglJamMasuk = LocalDateTime.of(tglMasuk, jamMasuk);
							LocalDateTime tglJamPulang = LocalDateTime.of(tglMasuk, jamPulang);
							if ((tglPelayanan.isEqual(tglMasuk) && tglJamPelayanan.isBefore(tglJamMasuk))
									|| (tglPelayanan.isEqual(tglMasuk) && tglJamPelayanan.isAfter(tglJamPulang))) {
								if ("Reguler".equals(d.get("jenisRuangan").toString()))
									d.put("isJamKerja", true);
								listDataLuarJamKerja.add(d);
								break;
							}
						}
				}
			} else {
				/*
				 * Tanggal pelayanan null akan dianggap sebagai luar jam kerja
				 */
				if ("Reguler".equals(d.get("jenisRuangan").toString()))
					d.put("isJamKerja", true);
				listDataLuarJamKerja.add(d);
			}
		}
		/*
		 * Offer data yang sudah diurutkan dalam queue
		 */
		Queue<Map<String, Object>> queuePelayanan = new ArrayDeque<>();
		rawDataBpjs5.forEach(queuePelayanan::offer);
		listDataJamKerja.forEach(queuePelayanan::offer);
		listDataLuarJamKerja.forEach(queuePelayanan::offer);
		/*
		 * Memisahkan data diurutkan menjadi logbook remun dan logbook ffs
		 */
		List<Map<String, Object>> listPelayananRemun = new ArrayList<>();
		List<Map<String, Object>> listPelayananFfs = new ArrayList<>();
		List<Map<String, Object>> listPelayananNonJknLuarJamKerja = new ArrayList<>();
		double capaianRemun = 0.0;
		if (pegawaiDao.getPegawaiByKategoryPegawai(Arrays.asList(DOKTER_LUAR)).contains(idPegawai)
				&& !listIdPegawaiRemunKelompokBudiRahmat.contains(idPegawai)) {
			/*
			 * Dokter luar hanya mendapatkan ffs
			 */
			for (Map<String, Object> next = queuePelayanan.poll(); next != null; next = queuePelayanan.poll())
				if (CommonUtil.isNotNullOrEmpty(next.get("idKelompokPasien"))
						&& Arrays.asList(KELOMPOK_BPJS)
								.contains(Integer.parseInt(next.get("idKelompokPasien").toString()))
						&& idsDokterBPJSffs.contains(idPegawai)) {
					/*
					 * dokter-dokter tertentu yang hanya dapat pasien bpjs
					 */
					if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
						listPelayananFfs.add(next);
					} else {
						listPelayananNonJknLuarJamKerja.add(next);
					}
				} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
						|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk")) && !Arrays.asList(NONLOGBOOK)
								.contains(Integer.parseInt(next.get("idJenisProduk").toString())))) {
					if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
						listPelayananFfs.add(next);
					} else {
						listPelayananNonJknLuarJamKerja.add(next);
					}
				}
		} else {
			for (Map<String, Object> next = queuePelayanan.poll(); next != null; next = queuePelayanan.poll())
				if (CommonUtil.isNotNullOrEmpty(next.get("idKelompokPasien")) && Arrays.asList(KELOMPOK_BPJS)
						.contains(Integer.parseInt(next.get("idKelompokPasien").toString()))) {
					/*
					 * Urutan alokasi bpjs sebagai urutan prioritas
					 */
					if (drKkPediatrikGDList.contains(idPegawai)) {
						if (CommonUtil.isNotNullOrEmpty(next.get("kptl"))) {
							/*
							 * Tarif baru dengan KPTL
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else {
							/*
							 * Bpjs untuk dokter-dokter kk pediatrik gawat
							 * darurat
							 */
							if (idsDokterPediatrikGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Dibatasi oleh daftar tindakan tertentu
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							} else if (((CommonUtil.isNotNullOrEmpty(next.get("idDepartemen"))
									&& Arrays.asList(GRUP_RAWAT_JALAN_UTAMA)
											.contains(Integer.parseInt(next.get("idDepartemen").toString())))
									|| VISIT.equals(next.get("idGolonganProduk")))
									&& (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
											|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
													&& !Arrays.asList(NONLOGBOOK).contains(
															Integer.parseInt(next.get("idJenisProduk").toString()))))) {
								/*
								 * Dibatasi hanya di rawat jalan atau visite
								 * saja
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							}
						}
					} else if (drKkRadiologi.contains(idPegawai) && (BEDAH_SENTRAL.equals(next.get("idDepartemen"))
							|| CATHLAB.equals(next.get("idRuangan")))) {
						listPelayananRemun.add(next);
						capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
					} else {
						/*
						 * Selain dokter-dokter kk pediatrik gawat darurat
						 */
						if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk")) && listDetailJenisProduk
								.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Dibatasi oleh daftar jenis tindakan tertentu
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								}
							}
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& IGD.equals(next.get("idDepartemen")) && drKsmUmumList.contains(idPegawai)
								&& idsDokterUmumIGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter ksm umum di igd
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& drKkPerinatologiList.contains(idPegawai)
								&& idsDokterPerinatologi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter kk perinatologi dengan pembatasan
							 * tindakan tertentu
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else if (drAnastesiList.contains(idPegawai)) {
							if (idsPenunjangBukanAnestesi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Aturan dokter kk anestesi dengan pembatasan
								 * tindakan tertentu
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							} else if (RADIOLOGI.equals(next.get("idDepartemen"))
									&& DOKTER_PEMERIKSA.equals(next.get("idJenisPelaksana"))) {
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							}
						} else if (CommonUtil.isNullOrEmpty(listDetailJenisProdukException)
								|| (CommonUtil.isNotNullOrEmpty(listDetailJenisProdukException)
										&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& listDetailJenisProdukException.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString())))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								}
							}
						}
					}
				} else if (capaianRemun < targetRemun && (date.equals(dateLine) || date.after(dateLine))) {
					/*
					 * Alokasi bagian remunerasi berdasarkan target rupiah
					 * sesuai tanggal mulai berlaku
					 */
					if (drKkPediatrikGDList.contains(idPegawai)) {
						if (CommonUtil.isNotNullOrEmpty(next.get("kptl"))) {
							/*
							 * Tarif baru dengan KPTL
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else {
							/*
							 * Bpjs untuk dokter-dokter kk pediatrik gawat
							 * darurat
							 */
							if (idsDokterPediatrikGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Dibatasi oleh daftar tindakan tertentu
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							} else if ((CommonUtil.isNotNullOrEmpty(next.get("idDepartemen"))
									&& Arrays.asList(GRUP_RAWAT_JALAN_UTAMA)
											.contains(Integer.parseInt(next.get("idDepartemen").toString())))
									|| VISIT.equals(next.get("idGolonganProduk")) && (CommonUtil
											.isNullOrEmpty(next.get("idJenisProduk"))
											|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
													&& !Arrays.asList(NONLOGBOOK).contains(
															Integer.parseInt(next.get("idJenisProduk").toString()))))) {
								/*
								 * Dibatasi hanya di rawat jalan atau visite
								 * saja
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							}
						}
					} else if (drKkRadiologi.contains(idPegawai) && (BEDAH_SENTRAL.equals(next.get("idDepartemen"))
							|| CATHLAB.equals(next.get("idRuangan")))) {
						listPelayananRemun.add(next);
						capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
					} else {
						/*
						 * Selain dokter-dokter kk pediatrik gawat darurat
						 */
						if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk")) && listDetailJenisProduk
								.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Dibatasi oleh daftar jenis tindakan tertentu
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								}
							}
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& IGD.equals(next.get("idDepartemen")) && drKsmUmumList.contains(idPegawai)
								&& idsDokterUmumIGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter ksm umum di igd
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& drKkPerinatologiList.contains(idPegawai)
								&& idsDokterPerinatologi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter kk perinatologi dengan pembatasan
							 * tindakan tertentu
							 */
							listPelayananRemun.add(next);
							capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
						} else if (drAnastesiList.contains(idPegawai)) {
							if (idsPenunjangBukanAnestesi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Aturan dokter kk anestesi dengan pembatasan
								 * tindakan tertentu
								 */
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							} else if (RADIOLOGI.equals(next.get("idDepartemen"))
									&& DOKTER_PEMERIKSA.equals(next.get("idJenisPelaksana"))) {
								listPelayananRemun.add(next);
								capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
							}
						} else if (CommonUtil.isNullOrEmpty(listDetailJenisProdukException)
								|| (CommonUtil.isNotNullOrEmpty(listDetailJenisProdukException)
										&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& listDetailJenisProdukException.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString())))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									listPelayananRemun.add(next);
									capaianRemun += Double.parseDouble(next.get("hargaJasa").toString());
								}
							}
						}
					}
				} else {
					/*
					 * Alokasi untuk bagian ffs
					 */
					if (drKkPediatrikGDList.contains(idPegawai)) {
						if (CommonUtil.isNotNullOrEmpty(next.get("kptl"))) {
							/*
							 * Tarif baru dengan KPTL
							 */
							if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
								listPelayananFfs.add(next);
							} else {
								listPelayananNonJknLuarJamKerja.add(next);
							}
						} else {
							/*
							 * Ffs untuk dokter-dokter kk pediatrik gawat
							 * darurat
							 */
							if (idsDokterPediatrikGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Dibatasi oleh daftar tindakan tertentu
								 */
								if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
									listPelayananFfs.add(next);
								} else {
									listPelayananNonJknLuarJamKerja.add(next);
								}
							} else if ((CommonUtil.isNotNullOrEmpty(next.get("idDepartemen"))
									&& Arrays.asList(GRUP_RAWAT_JALAN_UTAMA)
											.contains(Integer.parseInt(next.get("idDepartemen").toString())))
									|| VISIT.equals(next.get("idGolonganProduk")) && (CommonUtil
											.isNullOrEmpty(next.get("idJenisProduk"))
											|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
													&& !Arrays.asList(NONLOGBOOK).contains(
															Integer.parseInt(next.get("idJenisProduk").toString()))))) {
								/*
								 * Dibatasi hanya di rawat jalan atau visite
								 * saja
								 */
								if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
									listPelayananFfs.add(next);
								} else {
									listPelayananNonJknLuarJamKerja.add(next);
								}
							}
						}
					} else if (drKkRadiologi.contains(idPegawai) && (BEDAH_SENTRAL.equals(next.get("idDepartemen"))
							|| CATHLAB.equals(next.get("idRuangan")))) {
						if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
							listPelayananFfs.add(next);
						} else {
							listPelayananNonJknLuarJamKerja.add(next);
						}
					} else {
						/*
						 * Selain dokter-dokter kk pediatrik gawat darurat
						 */
						if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk")) && listDetailJenisProduk
								.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Dibatasi oleh daftar jenis tindakan tertentu
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
										listPelayananFfs.add(next);
									} else {
										listPelayananNonJknLuarJamKerja.add(next);
									}
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
										listPelayananFfs.add(next);
									} else {
										listPelayananNonJknLuarJamKerja.add(next);
									}
								}
							}
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& IGD.equals(next.get("idDepartemen")) && drKsmUmumList.contains(idPegawai)
								&& idsDokterUmumIGD.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter ksm umum di igd
							 */
							if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
								listPelayananFfs.add(next);
							} else {
								listPelayananNonJknLuarJamKerja.add(next);
							}
						} else if ((CommonUtil.isNullOrEmpty(next.get("idDetailJenisProduk"))
								|| (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& !listDetailJenisProduk.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString()))))
								&& drKkPerinatologiList.contains(idPegawai)
								&& idsDokterPerinatologi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
							/*
							 * Aturan dokter kk perinatologi dengan pembatasan
							 * tindakan tertentu
							 */
							if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
								listPelayananFfs.add(next);
							} else {
								listPelayananNonJknLuarJamKerja.add(next);
							}
						} else if (drAnastesiList.contains(idPegawai)) {
							if (idsPenunjangBukanAnestesi.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								/*
								 * Aturan dokter kk anestesi dengan pembatasan
								 * tindakan tertentu
								 */
								if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
									listPelayananFfs.add(next);
								} else {
									listPelayananNonJknLuarJamKerja.add(next);
								}
							} else if (RADIOLOGI.equals(next.get("idDepartemen"))
									&& DOKTER_PEMERIKSA.equals(next.get("idJenisPelaksana"))) {
								if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
									listPelayananFfs.add(next);
								} else {
									listPelayananNonJknLuarJamKerja.add(next);
								}
							}
						} else if (CommonUtil.isNullOrEmpty(listDetailJenisProdukException)
								|| (CommonUtil.isNotNullOrEmpty(listDetailJenisProdukException)
										&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& listDetailJenisProdukException.contains(
												Integer.parseInt(next.get("idDetailJenisProduk").toString())))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							if (!drKsmUmumList.contains(idPegawai) || !idsDokterUmumExclude
									.contains(Integer.parseInt(next.get("idProduk").toString()))) {
								if (CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
										&& (idsRegDJPPenunjangPA
												.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))
												|| idsRegDJPPenunjangPK.contains(Integer
														.parseInt(next.get("idDetailJenisProduk").toString())))) {
									/*
									 * Pengecualian daftar tindakan penunjang
									 * yang bebas klaim
									 */
									if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
										listPelayananFfs.add(next);
									} else {
										listPelayananNonJknLuarJamKerja.add(next);
									}
								} else if (CommonUtil.isNullOrEmpty(next.get("idJenisProduk"))
										|| (CommonUtil.isNotNullOrEmpty(next.get("idJenisProduk"))
												&& !Arrays.asList(NONLOGBOOK).contains(
														Integer.parseInt(next.get("idJenisProduk").toString())))) {
									if (Boolean.parseBoolean(next.get("isJamKerja").toString())) {
										listPelayananFfs.add(next);
									} else {
										listPelayananNonJknLuarJamKerja.add(next);
									}
								}
							}
						}
					}
				}
		}
		{
			/*
			 * Sorting data remun jkn diurutkan
			 */
			listPelayananRemun = listPelayananRemun.stream()
					.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString())).collect(Collectors.toList());
			result.put("remun", listPelayananRemun);
			/*
			 * Informasi target
			 */
			result.put("targetRemun", targetRemun);
			result.put("targetRemunFormatted", new DecimalFormat("Rp#,##0.00").format(targetRemun));
		}
		{
			/*
			 * Sorting data remun non-jkn di dalam jam kerja diurutkan
			 */
			listPelayananFfs = listPelayananFfs.stream()
					.sorted(Comparator.comparing(o -> (Date) o.get("tglPelayanan"),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelompokPasien").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelas").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> o.get("namaProduk").toString())).collect(Collectors.toList());
			result.put("ffs", listPelayananFfs);
		}
		{
			/*
			 * Sorting data remun non-jkn di luar jam kerja diurutkan
			 */
			listPelayananNonJknLuarJamKerja = listPelayananNonJknLuarJamKerja.stream()
					.sorted(Comparator.comparing(o -> (Date) o.get("tglPelayanan"),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelompokPasien").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelas").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> o.get("namaProduk").toString())).collect(Collectors.toList());
			result.put("ffs-luar", listPelayananNonJknLuarJamKerja);
		}
		{
			/*
			 * Sorting data klaim mpp diurutkan
			 */
			listPelayananKlaimMpp = listPelayananKlaimMpp.stream()
					.sorted(Comparator.comparing(o -> (Date) o.get("tglPelayanan"),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelompokPasien").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> Integer.parseInt(o.get("sortIdKelas").toString()),
							Comparator.nullsLast(Comparator.naturalOrder())))
					.sorted(Comparator.comparing(o -> o.get("namaProduk").toString())).collect(Collectors.toList());
			result.put("klaim-mpp", listPelayananKlaimMpp);
		}
		{
			List<Map<String, Object>> listPelayananFixedPay = new ArrayList<>();
			if (CommonUtil.isNotNullOrEmpty(listFixedPay))
				listPelayananFixedPay = setPelayananPaket(idPegawai, listFixedPay);
			if (CommonUtil.isNotNullOrEmpty(listKepalaPaketFixedPay))
				listPelayananFixedPay.addAll(setKepalaPaketFixedPay(listKepalaPaketFixedPay));
			result.put("fixed-pay", listPelayananFixedPay);
		}
		return result;
	}

	private List<Map<String, Object>> setPelayananPaket(Integer idPegawai, List<Map<String, Object>> listData) {
		/*
		 * Transformasi data paket menggunakan mapprodukpaket dan
		 * mapprodukpakettoproduk
		 */
		List<Map<String, Object>> listFixedPay = transformPelayananPaket(idPegawai, listData);
		/*
		 * Populate data filter
		 */
		List<Map<String, Object>> dataTanggal = distinctGroupFixedPay(listFixedPay);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> result = groupingKategoriFixedPay(dataTanggal);
		/*
		 * Final sorting
		 */
		result = result.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString()))
				.sorted(Comparator.comparing(o5 -> o5.get("jenisRuangan").toString(), Comparator.reverseOrder()))
				.sorted(Comparator.comparing(o4 -> o4.get("bulanPulangIbu").toString())).collect(Collectors.toList());
		result.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		return result;
	}

	private List<Map<String, Object>> setKepalaPaketFixedPay(List<Map<String, Object>> listData) {
		/*
		 * Transformasi data produk kepala paket sebagai fixed pay
		 */
		List<Map<String, Object>> listFixedPay = transformPelayananKepalaPaketFixedPay(listData);
		/*
		 * Populate data filter
		 */
		List<Map<String, Object>> dataTanggal = distinctGroupFixedPay(listFixedPay);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> result = groupingKategoriFixedPay(dataTanggal);
		/*
		 * Final sorting
		 */
		result = result.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString()))
				.sorted(Comparator.comparing(o5 -> o5.get("jenisRuangan").toString(), Comparator.reverseOrder()))
				.sorted(Comparator.comparing(o4 -> o4.get("bulanPulangIbu").toString())).collect(Collectors.toList());
		result.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		return result;
	}

	private List<Map<String, Object>> transformPelayananPaket(Integer idPegawai, List<Map<String, Object>> listData) {
		List<Integer> drKsmObgyn = pegawaiDao.getDokterByKsm(KSM_OBGYN);
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		SimpleDateFormat month = new SimpleDateFormat("MMM-yyyy", new Locale("in", "ID"));
		List<MapProdukPaket> paketList = mapProdukPaketDao.findAll();
		List<Integer> allProdukEntriId = paketList.stream().map(MapProdukPaket::getProdukEntriId)
				.collect(Collectors.toList());
		listData.forEach(d -> {
			Optional<MapProdukPaket> idProduk = paketList.stream()
					.filter(mpaket -> mpaket.getProdukEntriId().equals(d.get("idProduk"))).findFirst();
			d.put("mPaketId", null);
			d.put("paketId", null);
			d.put("paketType", null);
			idProduk.ifPresent(mapProdukPaket -> {
				d.put("mPaketId", mapProdukPaket.getNoRec());
				d.put("paketId", mapProdukPaket.getPaketId());
				if (CommonUtil.isNotNullOrEmpty(mapProdukPaket.getJenisMapping()))
					d.put("paketType", mapProdukPaket.getJenisMapping().name());
			});
		});
		List<MapProdukPaketToProduk> regulerList = mapProdukPaketToProdukDao.findAll();
		listData.forEach(d -> {
			Optional<MapProdukPaketToProduk> mRefId = regulerList.stream()
					.filter(ref -> ref.getMapProdukPaketId().equals(d.get("mPaketId"))).findFirst();
			d.put("regRefId", null);
			mRefId.ifPresent(mproduk -> d.put("regRefId", mproduk.getProdukRegulerId()));
		});
		List<String> allConcatProdukKelas = listData.stream()
				.filter(d -> CommonUtil.isNotNullOrEmpty(d.get("regRefId")))
				.map(d -> d.get("regRefId").toString() + d.get("idKelas").toString()).collect(Collectors.toList());
		allConcatProdukKelas.addAll(listData.stream().filter(d -> CommonUtil.isNotNullOrEmpty(d.get("paketId")))
				.map(d -> d.get("paketId").toString() + d.get("idKelas").toString()).collect(Collectors.toList()));
		allConcatProdukKelas.addAll(listData.stream().filter(d -> CommonUtil.isNotNullOrEmpty(d.get("idProduk")))
				.map(d -> d.get("idProduk").toString() + d.get("idKelas").toString()).collect(Collectors.toList()));
		List<HargaNettoProdukByKelasD> tarifDetailReguler = hargaNettoProdukByKelasDDao
				.findByConcateProdukKelas(allConcatProdukKelas);
		List<String> allConcatProdukNonkelas = listData.stream()
				.filter(d -> CommonUtil.isNotNullOrEmpty(d.get("regRefId")))
				.map(d -> d.get("regRefId").toString() + NON_KELAS).collect(Collectors.toList());
		allConcatProdukNonkelas.addAll(listData.stream().filter(d -> CommonUtil.isNotNullOrEmpty(d.get("paketId")))
				.map(d -> d.get("paketId").toString() + NON_KELAS).collect(Collectors.toList()));
		allConcatProdukNonkelas.addAll(listData.stream().filter(d -> CommonUtil.isNotNullOrEmpty(d.get("idProduk")))
				.map(d -> d.get("idProduk").toString() + NON_KELAS).collect(Collectors.toList()));
		List<HargaNettoProdukByKelasD> tarifDetailNonKelas = hargaNettoProdukByKelasDDao
				.findByConcateProdukKelas(allConcatProdukNonkelas);
		Set<Map<String, Object>> ibuPaketDiRanapByDokter = pelayananPasienDao.findPasienPaketDiRanapByDokter(drKsmObgyn,
				allProdukEntriId, Arrays.asList(GRUP_RAWAT_INAP));
		Set<Integer> setIdIbu = ibuPaketDiRanapByDokter.stream()
				.map(pasien -> Integer.parseInt(pasien.get("pasienId").toString())).collect(Collectors.toSet());
		List<Map<String, Object>> ibuAnak = pasienDao.findIdByIdOfIbu(setIdIbu);
		listData.forEach(d -> {
			List<Integer> listIdIbu = ibuAnak.stream().filter(bn -> Integer
					.parseInt(d.get("pasienId").toString()) == Integer.parseInt(bn.get("idIbu").toString())
					|| Integer.parseInt(d.get("pasienId").toString()) == Integer.parseInt(bn.get("idAnak").toString()))
					.map(bn -> Integer.parseInt(bn.get("idIbu").toString())).collect(Collectors.toList());
			List<Integer> listIdAnak = ibuAnak.stream().filter(bn -> Integer
					.parseInt(d.get("pasienId").toString()) == Integer.parseInt(bn.get("idIbu").toString())
					|| Integer.parseInt(d.get("pasienId").toString()) == Integer.parseInt(bn.get("idAnak").toString()))
					.map(bn -> Integer.parseInt(bn.get("idAnak").toString())).collect(Collectors.toList());
			Optional<Map<String, Object>> validateIbuPaketDiRanap = ibuPaketDiRanapByDokter.stream()
					.filter(paket -> Integer.parseInt(d.get("pasienId").toString()) == Integer
							.parseInt(paket.get("pasienId").toString())
							|| (listIdAnak.contains(Integer.parseInt(d.get("pasienId").toString()))
									&& listIdIbu.contains(Integer.parseInt(paket.get("pasienId").toString()))))
					.filter(paket -> CommonUtil.isNotNullOrEmpty(d.get("paketId")) && Integer
							.parseInt(d.get("paketId").toString()) == Integer.parseInt(paket.get("paketId").toString()))
					.findFirst();
			d.put("tglPulangIbu", null);
			d.put("bulanPulangIbu", "");
			d.put("hargaJasa", 0.0);
			d.put("isBatalPaket", false);
			if (validateIbuPaketDiRanap.isPresent()
					&& CommonUtil.isNotNullOrEmpty(validateIbuPaketDiRanap.get().get("tglKeluar")))
				d.put("bulanPulangIbu", month.format((Date) validateIbuPaketDiRanap.get().get("tglKeluar")));
			validateIbuPaketDiRanap.ifPresent(f -> d.put("isBatalPaket", f.get("isBatal")));
			if (validateIbuPaketDiRanap.isPresent()
					&& CommonUtil.isNotNullOrEmpty(validateIbuPaketDiRanap.get().get("tglKeluar"))
					&& !PERAWAT.name().equals(d.get("paketType"))
					&& !Boolean.parseBoolean(d.get("isBatalPaket").toString())) {
				d.put("tglPulangIbu", validateIbuPaketDiRanap.get().get("tglKeluar"));
				if (drKsmObgyn.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
						&& TINDAKAN_UTAMA.name().equals(d.get("paketType"))) {
					Optional<HargaNettoProdukByKelasD> byDetailTarif = tarifDetailReguler.stream()
							.filter(dt -> dt.getProdukId().equals(d.get("paketId")))
							.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
							.filter(dt -> dt.getKomponenHargaId().equals(SPOG_OPERATOR)).findFirst();
					if (byDetailTarif.isPresent()) {
						d.put("hargaJasa", CommonUtil.isNotNullOrEmpty(byDetailTarif.get().getHargaNetto1())
								? byDetailTarif.get().getHargaNetto1() : byDetailTarif.get().getHargaSatuan());
					} else {
						Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
								.filter(dt -> dt.getProdukId().equals(d.get("paketId")))
								.filter(dt -> dt.getKelasId().equals(NON_KELAS))
								.filter(dt -> dt.getKomponenHargaId().equals(SPOG_OPERATOR)).findFirst();
						byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
								CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
										? byDetailTarifNonKelas.get().getHargaNetto1()
										: byDetailTarifNonKelas.get().getHargaSatuan()));
					}
				} else if (drKsmObgyn.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
						&& TINDAKAN_UTAMA.name().equals(d.get("paketType"))) {
					Optional<HargaNettoProdukByKelasD> byDetailTarif = tarifDetailReguler.stream()
							.filter(dt -> dt.getProdukId().equals(d.get("paketId")))
							.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
							.filter(dt -> dt.getKomponenHargaId().equals(SPOG_ASISTEN)).findFirst();
					if (byDetailTarif.isPresent()) {
						d.put("hargaJasa", CommonUtil.isNotNullOrEmpty(byDetailTarif.get().getHargaNetto1())
								? byDetailTarif.get().getHargaNetto1() : byDetailTarif.get().getHargaSatuan());
					} else {
						Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
								.filter(dt -> dt.getProdukId().equals(d.get("paketId")))
								.filter(dt -> dt.getKelasId().equals(NON_KELAS))
								.filter(dt -> dt.getKomponenHargaId().equals(SPOG_ASISTEN)).findFirst();
						byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
								CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
										? byDetailTarifNonKelas.get().getHargaNetto1()
										: byDetailTarifNonKelas.get().getHargaSatuan()));
					}
				} else if (!drKsmObgyn.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
					Optional<HargaNettoProdukByKelasD> byDetailTarif = tarifDetailReguler.stream()
							.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
							.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
							.filter(dt -> dt.getKomponenHargaId().equals(JASA_DOKTER)).findFirst();
					if (byDetailTarif.isPresent()) {
						d.put("hargaJasa", CommonUtil.isNotNullOrEmpty(byDetailTarif.get().getHargaNetto1())
								? byDetailTarif.get().getHargaNetto1() : byDetailTarif.get().getHargaSatuan());
					} else {
						Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
								.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
								.filter(dt -> dt.getKelasId().equals(NON_KELAS))
								.filter(dt -> dt.getKomponenHargaId().equals(JASA_DOKTER)).findFirst();
						byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
								CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
										? byDetailTarifNonKelas.get().getHargaNetto1()
										: byDetailTarifNonKelas.get().getHargaSatuan()));
					}
				} else if (!drKsmObgyn.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
					Optional<HargaNettoProdukByKelasD> byDetailTarif = tarifDetailReguler.stream()
							.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
							.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
							.filter(dt -> dt.getKomponenHargaId().equals(JASA_ASISTEN_SPESIALIS)).findFirst();
					if (byDetailTarif.isPresent()) {
						d.put("hargaJasa", CommonUtil.isNotNullOrEmpty(byDetailTarif.get().getHargaNetto1())
								? byDetailTarif.get().getHargaNetto1() : byDetailTarif.get().getHargaSatuan());
					} else {
						Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
								.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
								.filter(dt -> dt.getKelasId().equals(NON_KELAS))
								.filter(dt -> dt.getKomponenHargaId().equals(JASA_ASISTEN_SPESIALIS)).findFirst();
						byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
								CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
										? byDetailTarifNonKelas.get().getHargaNetto1()
										: byDetailTarifNonKelas.get().getHargaSatuan()));
					}
				} else if (!drKsmObgyn.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
					Optional<HargaNettoProdukByKelasD> byDetailTarif = tarifDetailReguler.stream()
							.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
							.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
							.filter(dt -> dt.getKomponenHargaId().equals(JASA_DOKTER_ANASTESI)).findFirst();
					if (byDetailTarif.isPresent()) {
						d.put("hargaJasa", CommonUtil.isNotNullOrEmpty(byDetailTarif.get().getHargaNetto1())
								? byDetailTarif.get().getHargaNetto1() : byDetailTarif.get().getHargaSatuan());
					} else {
						Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
								.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
								.filter(dt -> dt.getKelasId().equals(NON_KELAS))
								.filter(dt -> dt.getKomponenHargaId().equals(JASA_DOKTER_ANASTESI)).findFirst();
						byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
								CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
										? byDetailTarifNonKelas.get().getHargaNetto1()
										: byDetailTarifNonKelas.get().getHargaSatuan()));
					}
				}
			} else if (terapisRehabMedik.contains(idPegawai)
					&& !Arrays.asList(GRUP_RAWAT_INAP).contains(Integer.parseInt(d.get("idDepartemen").toString()))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
						.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
						.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
						.filter(dt -> dt.getKomponenHargaId().equals(JASA_TERAPIS)).findFirst();
				byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
						CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
								? byDetailTarifNonKelas.get().getHargaNetto1()
								: byDetailTarifNonKelas.get().getHargaSatuan()));
			} else if (!Arrays.asList(GRUP_RAWAT_INAP).contains(Integer.parseInt(d.get("idDepartemen").toString()))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
						.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
						.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
						.filter(dt -> dt.getKomponenHargaId().equals(JASA_DOKTER)).findFirst();
				byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
						CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
								? byDetailTarifNonKelas.get().getHargaNetto1()
								: byDetailTarifNonKelas.get().getHargaSatuan()));
			} else if (!Arrays.asList(GRUP_RAWAT_INAP).contains(Integer.parseInt(d.get("idDepartemen").toString()))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				Optional<HargaNettoProdukByKelasD> byDetailTarifNonKelas = tarifDetailNonKelas.stream()
						.filter(dt -> dt.getProdukId().equals(d.get("idProduk")))
						.filter(dt -> dt.getKelasId().equals(d.get("idKelas")))
						.filter(dt -> dt.getKomponenHargaId().equals(JASA_ASISTEN_SPESIALIS)).findFirst();
				byDetailTarifNonKelas.ifPresent(hargaNettoProdukByKelasD -> d.put("hargaJasa",
						CommonUtil.isNotNullOrEmpty(byDetailTarifNonKelas.get().getHargaNetto1())
								? byDetailTarifNonKelas.get().getHargaNetto1()
								: byDetailTarifNonKelas.get().getHargaSatuan()));
			}
		});
		listData.forEach(d -> {
			d.put("hargaJual", d.get("hargaJasa"));
			RemunHargaJasa hargaJasa = hargaJasaFixedPay(d);
			d.put("hargaJasa", hargaJasa.getNilai());
			d.put("keterangan", hargaJasa.getKeterangan());
		});
		return listData;
	}

	private List<Map<String, Object>> distinctGroupFixedPay(List<Map<String, Object>> listFixedPay) {
		List<Integer> listIdProduk = new ArrayList<>();
		List<Double> listHargaJasa = new ArrayList<>();
		List<Double> listHargaJual = new ArrayList<>();
		List<Integer> listIdKelompokPasien = new ArrayList<>();
		List<String> listTanggal = new ArrayList<>();
		List<String> listJenisRuangan = new ArrayList<>();
		List<String> listBulanPulangIbu = new ArrayList<>();
		listFixedPay.forEach(d -> {
			if (!listIdProduk.contains(Integer.parseInt(d.get("idProduk").toString())))
				listIdProduk.add(Integer.valueOf(d.get("idProduk").toString()));
			if (!listHargaJasa.contains(Double.parseDouble(d.get("hargaJasa").toString())))
				listHargaJasa.add(Double.valueOf(d.get("hargaJasa").toString()));
			if (!listHargaJual.contains(Double.parseDouble(d.get("hargaJual").toString())))
				listHargaJual.add(Double.valueOf(d.get("hargaJual").toString()));
			if (!listIdKelompokPasien.contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				listIdKelompokPasien.add(Integer.valueOf(d.get("idKelompokPasien").toString()));
			if (!listTanggal.contains(d.get("tanggal").toString()))
				listTanggal.add(d.get("tanggal").toString());
			if (!listJenisRuangan.contains(d.get("jenisRuangan").toString()))
				listJenisRuangan.add(d.get("jenisRuangan").toString());
			if (!listBulanPulangIbu.contains(d.get("bulanPulangIbu").toString()))
				listBulanPulangIbu.add(d.get("bulanPulangIbu").toString());
		});
		/*
		 * Pengelompokkan tanggal pelayanan
		 */
		return groupingTanggalFixedPay(listFixedPay);
	}

	private List<Map<String, Object>> groupingTanggalFixedPay(List<Map<String, Object>> listData) {
		Map<Integer, Map<Double, Map<Double, Map<Integer, Map<String, Map<String, Map<String, Map<String, List<Map<String, Object>>>>>>>>>> collectTanggal = listData
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()), Collectors
						.groupingBy(o2 -> Double.parseDouble(o2.get("hargaJasa").toString()), Collectors.groupingBy(
								o3 -> Double.parseDouble(o3.get("hargaJual").toString()),
								Collectors.groupingBy(o4 -> Integer.parseInt(o4.get("idKelompokPasien").toString()),
										Collectors.groupingBy(o5 -> o5.get("jenisRuangan").toString(),
												Collectors.groupingBy(o6 -> o6.get("bulanPulangIbu").toString(),
														Collectors.groupingBy(o7 -> o7.get("keterangan").toString(),
																Collectors.groupingBy(
																		o8 -> o8.get("tanggal").toString())))))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collectTanggal.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2.forEach((k3, v3) -> v3.forEach((k4, v4) -> v4
				.forEach((k5, v5) -> v5.forEach((k6, v6) -> v6.forEach((k7, v7) -> v7.forEach((k8, v8) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("hargaJasa", k2);
					map.put("hargaJual", k3);
					map.put("idKelompokPasien", k4);
					map.put("jenisRuangan", k5);
					map.put("bulanPulangIbu", k6);
					map.put("keterangan", k7);
					map.put("tanggal", k8);
					List<String> norecs = v8.stream().map(e -> e.get("idPelayananPasienPetugas").toString())
							.collect(Collectors.toList());
					map.put("norecs", norecs);
					double jumlah = v8.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					Optional<Map<String, Object>> first = v8.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
						map.put("jenisRuangan", e.get("jenisRuangan").toString());
						map.put("bulanPulangIbu", e.get("bulanPulangIbu").toString());
						map.put("keterangan", e.get("keterangan").toString());
					});
					result.add(map);
				}))))))));
		return result;
	}

	private List<Map<String, Object>> groupingKategoriFixedPay(List<Map<String, Object>> data) {
		Map<Integer, Map<Double, Map<Double, Map<Integer, Map<String, Map<String, Map<String, List<Map<String, Object>>>>>>>>> collected = data
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()), Collectors
						.groupingBy(o2 -> Double.parseDouble(o2.get("hargaJasa").toString()), Collectors.groupingBy(
								o3 -> Double.parseDouble(o3.get("hargaJual").toString()),
								Collectors.groupingBy(o4 -> Integer.parseInt(o4.get("idKelompokPasien").toString()),
										Collectors.groupingBy(o5 -> o5.get("jenisRuangan").toString(),
												Collectors.groupingBy(o6 -> o6.get("bulanPulangIbu").toString(),
														Collectors.groupingBy(
																o7 -> o7.get("keterangan").toString()))))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collected.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2.forEach((k3, v3) -> v3
				.forEach((k4, v4) -> v4.forEach((k5, v5) -> v5.forEach((k6, v6) -> v6.forEach((k7, v7) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("hargaJasa", k2);
					map.put("hargaJual", k3);
					map.put("idKelompokPasien", k4);
					map.put("jenisRuangan", k5);
					map.put("bulanPulangIbu", k6);
					map.put("keterangan", k7);
					List<Map<String, Object>> detail = new ArrayList<>();
					v7.forEach(d -> {
						Map<String, Object> mapCount = new HashMap<>();
						mapCount.put("jumlah", d.get("jumlah"));
						mapCount.put("norecs", d.get("norecs"));
						mapCount.put("tanggal", d.get("tanggal"));
						detail.add(mapCount);
					});
					map.put("detail", detail);
					double jumlah = v7.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					double jumlahHargaJasa = jumlah * Double.parseDouble(map.get("hargaJasa").toString());
					map.put("jumlahHargaJasa", jumlahHargaJasa);
					Optional<Map<String, Object>> first = v7.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
						map.put("jenisRuangan", e.get("jenisRuangan").toString());
						map.put("bulanPulangIbu", e.get("bulanPulangIbu").toString());
						map.put("keterangan", e.get("keterangan").toString());
					});
					result.add(map);
				})))))));
		return result;
	}

	private List<Map<String, Object>> transformPelayananKepalaPaketFixedPay(List<Map<String, Object>> listData) {
		listData.forEach(d -> {
			double hargaJasa = Double.parseDouble(d.get("hargaJasaD").toString())
					+ Double.parseDouble(d.get("hargaJasaAs").toString())
					+ Double.parseDouble(d.get("hargaJasaAn").toString());
			d.put("tglPulangIbu", null);
			d.put("bulanPulangIbu", "");
			d.put("hargaJasa", hargaJasa);
			d.put("isBatalPaket", false);
		});
		listData.forEach(d -> {
			d.put("hargaJual", d.get("hargaJasa"));
			RemunHargaJasa hargaJasa = hargaJasaFixedPay(d);
			d.put("hargaJasa", hargaJasa.getNilai());
			d.put("keterangan", hargaJasa.getKeterangan());
		});
		return listData;
	}

	@Override
	public Map<String, Object> logbookRemunTarifDokter(Integer idPegawai, String bulan, Map<String, Object> data) {
		Map<String, Object> result = new HashMap<>();
		List<Integer> listIdProduk = new ArrayList<>();
		List<String> listPersenJasa = new ArrayList<>();
		List<Double> listHargaJasa = new ArrayList<>();
		List<Double> listHargaJual = new ArrayList<>();
		List<Integer> listIdKelompokPasien = new ArrayList<>();
		List<String> listTanggal = new ArrayList<>();
		DateFormat df = new SimpleDateFormat("yyyy-MM");
		Date date;
		try {
			date = df.parse(bulan);
		} catch (ParseException e) {
			System.out.println(e.getMessage());
			return null;
		}
		Map<String, Object> remunFfs;
		if (CommonUtil.isNotNullOrEmpty(data)) {
			remunFfs = data;
		} else {
			remunFfs = this.splitRemunFfs(idPegawai, bulan);
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> listData = (List<Map<String, Object>>) remunFfs.get("remun");
		Double target = Double.parseDouble(remunFfs.get("targetRemun").toString());
		String targetFormatted = remunFfs.get("targetRemunFormatted").toString();
		/*
		 * Mendapatkan persentase jasa
		 */
		double persenOperator = Double.parseDouble(getSettingDataFixed("persenRemunOperatorIBS"));
		double persenAsistenIBS = Double.parseDouble(getSettingDataFixed("persenRemunAsistenIBS"));
		double persenAnestesi = Double.parseDouble(getSettingDataFixed("persenRemunAnestesiIBS"));
		double persenRadiologi = Double.parseDouble(getSettingDataFixed("persenRemunRadiologi"));
		double persenLaboratorium = Double.parseDouble(getSettingDataFixed("persenRemunLaboratorium"));
		double persenRehabMedik = Double.parseDouble(getSettingDataFixed("persenRemunRehabMedik"));
		double persenKonsultasi = Double.parseDouble(getSettingDataFixed("persenRemunKonsultasiDokter"));
		double persenVisite = Double.parseDouble(getSettingDataFixed("persenRemunVisiteDokter"));
		double persenTindakan = Double.parseDouble(getSettingDataFixed("persenRemunTindakanDokter"));
		double persenTarifJasaBedah = Double.parseDouble(getSettingDataFixed("persenTarifJasaBedah"));
		double persenTarifJasaICU = Double.parseDouble(getSettingDataFixed("persenTarifJasaICU"));
		double persenRemunDokterPA = Double.parseDouble(getSettingDataFixed("persenRemunDokterPA"));
		double persenRemunDokterUmumHD = Double.parseDouble(getSettingDataFixed("persenRemunDokterUmumHD"));
		double persenRemunLabGenetika = Double.parseDouble(getSettingDataFixed("persenRemunLabGenetika"));
		double persenRemunTerapis = Double.parseDouble(getSettingDataFixed("persenRemunTerapis"));
		double persenRemunVisiteDokterKelompokBudiRahmat = Double
				.parseDouble(getSettingDataFixed("persenRemunVisiteDokterKelompokBudiRahmat"));
		/*
		 * Persiapan filter logic remunerasi
		 */
		Date tglAwal = DateUtil.startMonth(bulan);
		List<Integer> drKkPatologiAnatomiList = pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_ANATOMI);
		List<Integer> drKsmUmumList = pegawaiDao.getDokterByKelompokKerja(KK_UMUM);
		List<Integer> drKkGenetika = pegawaiDao.getDokterByKelompokKerja(KK_GENETIKA);
		List<Integer> drAnastesiList = pegawaiDao.getDokterByKelompokKerja(KK_ANESTESI);
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		List<Integer> idsLabGenetikaLuarRuangan = getNilaiDataFixByTMT("idProdukLabGenetikaLuarRuangan", tglAwal);
		List<Integer> listIdPegawaiRemunKelompokBudiRahmat = splitDataSettingDatafixed(
				"listIdPegawaiRemunKelompokBudiRahmat");
		/*
		 * Set persen jasa dan harga jasa pasien bpjs di ibs, icu
		 */
		double persenTarifIBS = persenTarifJasaBedah / 100;
		double persenTarifICU = persenTarifJasaICU / 100;
		/*
		 * Mapping persentase jasa remunerasi
		 */
		if (pegawaiDao.getPegawaiByKategoryPegawai(Arrays.asList(DOKTER_LUAR)).contains(idPegawai)
				&& listIdPegawaiRemunKelompokBudiRahmat.contains(idPegawai))
			persenVisite = persenRemunVisiteDokterKelompokBudiRahmat;
		for (Map<String, Object> d : listData) {
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterUmumHD / 100, hargaJual, d);
				d.put("persenJasa", persenRemunDokterUmumHD + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunTerapis / 100, hargaJual, d);
				d.put("persenJasa", persenRemunTerapis + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenOperator / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", "Tarif Jasa Bedah (" + persenTarifJasaBedah + "%)" + hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenAsistenIBS / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", "Tarif Jasa Bedah (" + persenTarifJasaBedah + "%)" + hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				double persenJasa = persenAnestesi / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifIBS, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", "Tarif Jasa Bedah (" + persenTarifJasaBedah + "%)" + hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100, hargaJual, d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100, hargaJual, d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d);
				d.put("persenJasa", persenRadiologi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (REHAB_MEDIK.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRehabMedik / 100, hargaJual, d);
				d.put("persenJasa", persenRehabMedik + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (KONSULTASI.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenKonsultasi / 100, hargaJual, d);
				d.put("persenJasa", persenKonsultasi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (VISIT.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenVisite / 100, hargaJual, d);
				d.put("persenJasa", persenVisite + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkGenetika.contains(idPegawai)
					&& idsLabGenetikaLuarRuangan.contains(Integer.parseInt(d.get("idProduk").toString()))
					&& (date.before(new Date(1690822799000L)) || date.equals(new Date(1690822799000L)))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenRemunLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (Arrays.asList(GENETIKA).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenRemunLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkPatologiAnatomiList.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterPA / 100, hargaJual, d);
				d.put("persenJasa", persenRemunDokterPA + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (LABORATORIUM.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenLaboratorium / 100, hargaJual, d);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (CommonUtil.isNotNullOrEmpty(d.get("idRuangan"))
					&& Arrays.asList(ICU_NICU).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				double persenJasa = persenTindakan / 100;
				RemunHargaJasa hargaJasa = hargaJasa(persenJasa * persenTarifICU, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", "Tarif Jasa ICU (" + persenTarifJasaICU + "%)" + hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			}
		}
		/*
		 * Populate data filter
		 */
		listData.forEach(d -> {
			if (!listIdProduk.contains(Integer.parseInt(d.get("idProduk").toString())))
				listIdProduk.add(Integer.valueOf(d.get("idProduk").toString()));
			if (!listPersenJasa.contains(d.get("persenJasa").toString()))
				listPersenJasa.add(d.get("persenJasa").toString());
			if (!listHargaJasa.contains(Double.parseDouble(d.get("hargaJasa").toString())))
				listHargaJasa.add(Double.valueOf(d.get("hargaJasa").toString()));
			if (!listHargaJual.contains(Double.parseDouble(d.get("hargaJual").toString())))
				listHargaJual.add(Double.valueOf(d.get("hargaJual").toString()));
			if (!listIdKelompokPasien.contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				listIdKelompokPasien.add(Integer.valueOf(d.get("idKelompokPasien").toString()));
			if (!listTanggal.contains(d.get("tanggal").toString()))
				listTanggal.add(d.get("tanggal").toString());
		});
		/*
		 * Pengelompokkan tanggal pelayanan
		 */
		List<Map<String, Object>> dataTanggal = groupingTanggalRemun(listData);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> dataResult = groupingKategoriRemun(dataTanggal);
		/*
		 * Final sorting
		 */
		dataResult = dataResult.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString())).collect(Collectors.toList());
		dataResult.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		/*
		 * Put all result mapping
		 */
		result.put("data", dataResult);
		result.put("target", target);
		result.put("targetFormatted", targetFormatted);
		return result;
	}

	private List<Map<String, Object>> groupingTanggalRemun(List<Map<String, Object>> listData) {
		Map<Integer, Map<String, Map<Double, Map<Double, Map<Integer, Map<String, Map<String, List<Map<String, Object>>>>>>>>> collectTanggal = listData
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()),
						Collectors.groupingBy(o2 -> o2.get("persenJasa").toString(), Collectors.groupingBy(
								o3 -> Double.parseDouble(o3.get("hargaJasa").toString()), Collectors.groupingBy(
										o4 -> Double.parseDouble(o4.get("hargaJual").toString()), Collectors
												.groupingBy(
														o5 -> Integer.parseInt(
																o5.get("idKelompokPasien").toString()),
														Collectors.groupingBy(o6 -> o6.get("keterangan").toString(),
																Collectors.groupingBy(
																		o7 -> o7.get("tanggal").toString()))))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collectTanggal.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2.forEach((k3, v3) -> v3
				.forEach((k4, v4) -> v4.forEach((k5, v5) -> v5.forEach((k6, v6) -> v6.forEach((k7, v7) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("persenJasa", k2);
					map.put("hargaJasa", k3);
					map.put("hargaJual", k4);
					map.put("idKelompokPasien", k5);
					map.put("keterangan", k6);
					map.put("tanggal", k7);
					List<String> norecs = v7.stream().map(e -> e.get("idPelayananPasienPetugas").toString())
							.collect(Collectors.toList());
					map.put("norecs", norecs);
					double jumlah = v7.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					Optional<Map<String, Object>> first = v7.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("keterangan", e.get("keterangan").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
					});
					result.add(map);
				})))))));
		return result;
	}

	private List<Map<String, Object>> groupingKategoriRemun(List<Map<String, Object>> data) {
		Map<Integer, Map<String, Map<Double, Map<Double, Map<Integer, Map<String, List<Map<String, Object>>>>>>>> collected = data
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()),
						Collectors.groupingBy(o2 -> o2.get("persenJasa").toString(), Collectors.groupingBy(
								o3 -> Double.parseDouble(o3.get("hargaJasa").toString()), Collectors.groupingBy(
										o4 -> Double.parseDouble(o4.get("hargaJual").toString()), Collectors
												.groupingBy(
														o5 -> Integer.parseInt(o5.get("idKelompokPasien")
																.toString()),
														Collectors.groupingBy(
																o6 -> o6.get("keterangan").toString())))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collected.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2
				.forEach((k3, v3) -> v3.forEach((k4, v4) -> v4.forEach((k5, v5) -> v5.forEach((k6, v6) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("persenJasa", k2);
					map.put("hargaJasa", k3);
					map.put("hargaJual", k4);
					map.put("idKelompokPasien", k5);
					map.put("keterangan", k6);
					List<Map<String, Object>> detail = new ArrayList<>();
					v6.forEach(d -> {
						Map<String, Object> mapCount = new HashMap<>();
						mapCount.put("jumlah", d.get("jumlah"));
						mapCount.put("norecs", d.get("norecs"));
						mapCount.put("tanggal", d.get("tanggal"));
						detail.add(mapCount);
					});
					map.put("detail", detail);
					double jumlah = v6.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					double jumlahHargaJasa = jumlah * Double.parseDouble(map.get("hargaJasa").toString());
					map.put("jumlahHargaJasa", jumlahHargaJasa);
					Optional<Map<String, Object>> first = v6.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("keterangan", e.get("keterangan").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
					});
					result.add(map);
				}))))));
		return result;
	}

	@Override
	public List<Map<String, Object>> logbookFfsTarifDokter(Integer idPegawai, String bulan, Map<String, Object> data) {
		List<Integer> listIdProduk = new ArrayList<>();
		List<String> listPersenJasa = new ArrayList<>();
		List<Double> listHargaJasa = new ArrayList<>();
		List<Double> listHargaJual = new ArrayList<>();
		List<Integer> listIdKelompokPasien = new ArrayList<>();
		List<String> listTanggal = new ArrayList<>();
		List<String> listJenisRuangan = new ArrayList<>();
		DateFormat df = new SimpleDateFormat("yyyy-MM");
		Date date;
		try {
			date = df.parse(bulan);
		} catch (ParseException e) {
			System.out.println(e.getMessage());
			return null;
		}
		Map<String, Object> remunFfs;
		if (CommonUtil.isNotNullOrEmpty(data)) {
			remunFfs = data;
		} else {
			remunFfs = this.splitRemunFfs(idPegawai, bulan);
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> listData = (List<Map<String, Object>>) remunFfs.get("ffs");
		/*
		 * Mendapatkan persentase jasa
		 */
		double persenBPJS = Double.parseDouble(getSettingDataFixed("persenJasaBPJS"));
		double persenOperator = Double.parseDouble(getSettingDataFixed("persenJasaOperatorIBS"));
		double persenAsistenIBS = Double.parseDouble(getSettingDataFixed("persenJasaAsistenIBS"));
		double persenAnestesi = Double.parseDouble(getSettingDataFixed("persenJasaAnestesiIBS"));
		double persenRadiologi = Double.parseDouble(getSettingDataFixed("persenJasaRadiologi"));
		double persenLaboratorium = Double.parseDouble(getSettingDataFixed("persenJasaLaboratorium"));
		double persenRehabMedik = Double.parseDouble(getSettingDataFixed("persenJasaRehabMedik"));
		double persenKonsultasi = Double.parseDouble(getSettingDataFixed("persenJasaKonsultasiDokter"));
		double persenVisite = Double.parseDouble(getSettingDataFixed("persenJasaVisiteDokter"));
		double persenTindakan = Double.parseDouble(getSettingDataFixed("persenJasaTindakanDokter"));
		double persenJasaDokterPA = Double.parseDouble(getSettingDataFixed("persenJasaDokterPA"));
		double persenJasaDokterUmumHD = Double.parseDouble(getSettingDataFixed("persenJasaDokterUmumHD"));
		double persenJasaLabGenetika = Double.parseDouble(getSettingDataFixed("persenJasaLabGenetika"));
		double persenJasaTerapis = Double.parseDouble(getSettingDataFixed("persenJasaTerapis"));
		double persenJasaTerapis24 = Double.parseDouble(getSettingDataFixed("persenFfsTerapisTmt21Okt24"));
		// Custom rule persentase jasa terapis 21 Oktober 2024
		LocalDateTime tmtJasaTerapis24 = LocalDateTime.of(2024, 11, 1, 0, 0, 0, 0);
		/*
		 * Persiapan filter logic remunerasi
		 */
		Date tglAwal = DateUtil.startMonth(bulan);
		List<Integer> drKkPatologiAnatomiList = pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_ANATOMI);
		List<Integer> drKsmUmumList = pegawaiDao.getDokterByKelompokKerja(KK_UMUM);
		List<Integer> drKkGenetika = pegawaiDao.getDokterByKelompokKerja(KK_GENETIKA);
		List<Integer> drAnastesiList = pegawaiDao.getDokterByKelompokKerja(KK_ANESTESI);
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		List<Integer> idsLabGenetikaLuarRuangan = getNilaiDataFixByTMT("idProdukLabGenetikaLuarRuangan", tglAwal);
		/*
		 * Mapping persentase jasa remunerasi
		 */
		for (Map<String, Object> d : listData) {
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			if (CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenBPJS / 100, hargaJual, d);
				/*
				 * Set persen jasa dokter luar yang klaim ffs dengan persen jasa
				 * dari tarif total
				 */
				d.put("persenJasa", persenBPJS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				/*
				 * Set harga jasa klaim jasa ffs pasien bpjs oleh dokter-dokter
				 * tertentu
				 */
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterUmumHD / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterUmumHD + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				LocalDateTime tglJamPelayanan = ((Date) d.get("tglPelayanan")).toInstant()
						.atZone(ZoneId.systemDefault()).toLocalDateTime();
				RemunHargaJasa hargaJasa;
				if (tglJamPelayanan.isBefore(tmtJasaTerapis24)) {
					hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis + "%");
				} else {
					hargaJasa = hargaJasa(persenJasaTerapis24 / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis24 + "%");
				}
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100, hargaJual, d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100, hargaJual, d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d);
				d.put("persenJasa", persenRadiologi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (REHAB_MEDIK.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRehabMedik / 100, hargaJual, d);
				d.put("persenJasa", persenRehabMedik + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (KONSULTASI.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenKonsultasi / 100, hargaJual, d);
				d.put("persenJasa", persenKonsultasi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (VISIT.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenVisite / 100, hargaJual, d);
				d.put("persenJasa", persenVisite + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkGenetika.contains(idPegawai)
					&& idsLabGenetikaLuarRuangan.contains(Integer.parseInt(d.get("idProduk").toString()))
					&& (date.before(new Date(1690822799000L)) || date.equals(new Date(1690822799000L)))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (Arrays.asList(GENETIKA).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkPatologiAnatomiList.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterPA / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterPA + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (LABORATORIUM.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenLaboratorium / 100, hargaJual, d);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			}
		}
		/*
		 * Populate data filter
		 */
		listData.forEach(d -> {
			if (!listIdProduk.contains(Integer.parseInt(d.get("idProduk").toString())))
				listIdProduk.add(Integer.valueOf(d.get("idProduk").toString()));
			if (!listPersenJasa.contains(d.get("persenJasa").toString()))
				listPersenJasa.add(d.get("persenJasa").toString());
			if (!listHargaJasa.contains(Double.parseDouble(d.get("hargaJasa").toString())))
				listHargaJasa.add(Double.valueOf(d.get("hargaJasa").toString()));
			if (!listHargaJual.contains(Double.parseDouble(d.get("hargaJual").toString())))
				listHargaJual.add(Double.valueOf(d.get("hargaJual").toString()));
			if (!listIdKelompokPasien.contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				listIdKelompokPasien.add(Integer.valueOf(d.get("idKelompokPasien").toString()));
			if (!listTanggal.contains(d.get("tanggal").toString()))
				listTanggal.add(d.get("tanggal").toString());
			if (!listJenisRuangan.contains(d.get("jenisRuangan").toString()))
				listJenisRuangan.add(d.get("jenisRuangan").toString());
		});
		/*
		 * Pengelompokkan tanggal pelayanan
		 */
		List<Map<String, Object>> dataTanggal = groupingTanggalFfs(listData);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> result = groupingKategoriFfs(dataTanggal);
		/*
		 * Final sorting
		 */
		result = result.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString()))
				.sorted(Comparator.comparing(o5 -> o5.get("jenisRuangan").toString(), Comparator.reverseOrder()))
				.collect(Collectors.toList());
		result.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		return result;
	}

	private List<Map<String, Object>> groupingTanggalFfs(List<Map<String, Object>> listData) {
		Map<Integer, Map<String, Map<Double, Map<Double, Map<Integer, Map<String, Map<String, Map<String, List<Map<String, Object>>>>>>>>>> collectTanggal = listData
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()),
						Collectors.groupingBy(o2 -> o2.get("persenJasa").toString(), Collectors.groupingBy(
								o3 -> Double.parseDouble(o3.get("hargaJasa").toString()), Collectors.groupingBy(
										o4 -> Double.parseDouble(o4.get("hargaJual").toString()), Collectors
												.groupingBy(
														o5 -> Integer.parseInt(o5.get("idKelompokPasien")
																.toString()),
														Collectors.groupingBy(o6 -> o6.get("jenisRuangan").toString(),
																Collectors.groupingBy(
																		o7 -> o7.get("keterangan").toString(),
																		Collectors.groupingBy(o7 -> o7.get("tanggal")
																				.toString())))))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collectTanggal.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2.forEach((k3, v3) -> v3.forEach((k4, v4) -> v4
				.forEach((k5, v5) -> v5.forEach((k6, v6) -> v6.forEach((k7, v7) -> v7.forEach((k8, v8) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("persenJasa", k2);
					map.put("hargaJasa", k3);
					map.put("hargaJual", k4);
					map.put("idKelompokPasien", k5);
					map.put("jenisRuangan", k6);
					map.put("keterangan", k7);
					map.put("tanggal", k8);
					List<String> norecs = v8.stream().map(e -> e.get("idPelayananPasienPetugas").toString())
							.collect(Collectors.toList());
					map.put("norecs", norecs);
					double jumlah = v8.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					Optional<Map<String, Object>> first = v8.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
						map.put("jenisRuangan", e.get("jenisRuangan").toString());
						map.put("keterangan", e.get("keterangan").toString());
					});
					result.add(map);
				}))))))));
		return result;
	}

	private List<Map<String, Object>> groupingKategoriFfs(List<Map<String, Object>> data) {
		Map<Integer, Map<String, Map<Double, Map<Double, Map<Integer, Map<String, Map<String, List<Map<String, Object>>>>>>>>> collected = data
				.stream()
				.collect(Collectors.groupingBy(o1 -> Integer.parseInt(o1.get("idProduk").toString()),
						Collectors.groupingBy(o2 -> o2.get("persenJasa").toString(),
								Collectors.groupingBy(o3 -> Double.parseDouble(o3.get("hargaJasa").toString()),
										Collectors.groupingBy(o4 -> Double.parseDouble(o4.get("hargaJual").toString()),
												Collectors.groupingBy(
														o5 -> Integer.parseInt(
																o5.get("idKelompokPasien").toString()),
														Collectors.groupingBy(o6 -> o6.get("jenisRuangan").toString(),
																Collectors.groupingBy(
																		o7 -> o7.get("keterangan").toString()))))))));
		List<Map<String, Object>> result = new ArrayList<>();
		collected.forEach((k1, v1) -> v1.forEach((k2, v2) -> v2.forEach((k3, v3) -> v3
				.forEach((k4, v4) -> v4.forEach((k5, v5) -> v5.forEach((k6, v6) -> v6.forEach((k7, v7) -> {
					HashMap<String, Object> map = new HashMap<>();
					map.put("idProduk", k1);
					map.put("persenJasa", k2);
					map.put("hargaJasa", k3);
					map.put("hargaJual", k4);
					map.put("idKelompokPasien", k5);
					map.put("jenisRuangan", k6);
					map.put("keterangan", k7);
					List<Map<String, Object>> detail = new ArrayList<>();
					v7.forEach(d -> {
						Map<String, Object> mapCount = new HashMap<>();
						mapCount.put("jumlah", d.get("jumlah"));
						mapCount.put("norecs", d.get("norecs"));
						mapCount.put("tanggal", d.get("tanggal"));
						detail.add(mapCount);
					});
					map.put("detail", detail);
					double jumlah = v7.stream().mapToDouble(e -> Double.parseDouble(e.get("jumlah").toString())).sum();
					map.put("jumlah", jumlah);
					double jumlahHargaJasa = jumlah * Double.parseDouble(map.get("hargaJasa").toString());
					map.put("jumlahHargaJasa", jumlahHargaJasa);
					Optional<Map<String, Object>> first = v7.stream().findFirst();
					first.ifPresent(e -> {
						map.put("namaProduk", e.get("namaProduk").toString());
						map.put("kelompokPasien", e.get("kelompokPasien").toString());
						map.put("tglPelayanan", e.get("tglPelayanan"));
						map.put("sortIdKelompokPasien", Integer.parseInt(e.get("sortIdKelompokPasien").toString()));
						map.put("sortIdKelas", Integer.parseInt(e.get("sortIdKelas").toString()));
						map.put("jenisRuangan", e.get("jenisRuangan").toString());
						map.put("keterangan", e.get("keterangan").toString());
					});
					result.add(map);
				})))))));
		return result;
	}

	@Override
	public List<Map<String, Object>> logbookFfsLuarTarifDokter(Integer idPegawai, String bulan,
			Map<String, Object> data) {
		List<Integer> listIdProduk = new ArrayList<>();
		List<String> listPersenJasa = new ArrayList<>();
		List<Double> listHargaJasa = new ArrayList<>();
		List<Double> listHargaJual = new ArrayList<>();
		List<Integer> listIdKelompokPasien = new ArrayList<>();
		List<String> listTanggal = new ArrayList<>();
		List<String> listJenisRuangan = new ArrayList<>();
		DateFormat df = new SimpleDateFormat("yyyy-MM");
		Date date;
		try {
			date = df.parse(bulan);
		} catch (ParseException e) {
			System.out.println(e.getMessage());
			return null;
		}
		Map<String, Object> remunFfs;
		if (CommonUtil.isNotNullOrEmpty(data)) {
			remunFfs = data;
		} else {
			remunFfs = this.splitRemunFfs(idPegawai, bulan);
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> listData = (List<Map<String, Object>>) remunFfs.get("ffs-luar");
		/*
		 * Mendapatkan persentase jasa
		 */
		double persenBPJS = Double.parseDouble(getSettingDataFixed("persenJasaBPJS"));
		double persenOperator = Double.parseDouble(getSettingDataFixed("persenJasaOperatorIBS"));
		double persenAsistenIBS = Double.parseDouble(getSettingDataFixed("persenJasaAsistenIBS"));
		double persenAnestesi = Double.parseDouble(getSettingDataFixed("persenJasaAnestesiIBS"));
		double persenRadiologi = Double.parseDouble(getSettingDataFixed("persenJasaRadiologi"));
		double persenLaboratorium = Double.parseDouble(getSettingDataFixed("persenJasaLaboratorium"));
		double persenRehabMedik = Double.parseDouble(getSettingDataFixed("persenJasaRehabMedik"));
		double persenKonsultasi = Double.parseDouble(getSettingDataFixed("persenJasaKonsultasiDokter"));
		double persenVisite = Double.parseDouble(getSettingDataFixed("persenJasaVisiteDokter"));
		double persenTindakan = Double.parseDouble(getSettingDataFixed("persenJasaTindakanDokter"));
		double persenJasaDokterPA = Double.parseDouble(getSettingDataFixed("persenJasaDokterPA"));
		double persenJasaDokterUmumHD = Double.parseDouble(getSettingDataFixed("persenJasaDokterUmumHD"));
		double persenJasaLabGenetika = Double.parseDouble(getSettingDataFixed("persenJasaLabGenetika"));
		double persenJasaTerapis = Double.parseDouble(getSettingDataFixed("persenJasaTerapis"));
		double persenJasaTerapis24 = Double.parseDouble(getSettingDataFixed("persenFfsTerapisTmt21Okt24"));
		double persenJasaLuarTerapis = Double.parseDouble(getSettingDataFixed("persenJasaLuarTerapis"));
		// Custom rule persentase jasa terapis 21 Oktober 2024
		LocalDateTime tmtJasaTerapis24 = LocalDateTime.of(2024, 11, 1, 0, 0, 0, 0);
		/*
		 * Persiapan filter logic remunerasi
		 */
		Date tglAwal = DateUtil.startMonth(bulan);
		List<Integer> drKkPatologiAnatomiList = pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_ANATOMI);
		List<Integer> drKsmUmumList = pegawaiDao.getDokterByKelompokKerja(KK_UMUM);
		List<Integer> drKkGenetika = pegawaiDao.getDokterByKelompokKerja(KK_GENETIKA);
		List<Integer> drAnastesiList = pegawaiDao.getDokterByKelompokKerja(KK_ANESTESI);
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		List<Integer> idsLabGenetikaLuarRuangan = getNilaiDataFixByTMT("idProdukLabGenetikaLuarRuangan", tglAwal);
		/*
		 * Mapping persentase jasa remunerasi
		 */
		for (Map<String, Object> d : listData) {
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			if (CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenBPJS / 100, hargaJual, d);
				/*
				 * Set persen jasa dokter luar yang klaim ffs dengan persen jasa
				 * dari tarif total
				 */
				d.put("persenJasa", persenBPJS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				/*
				 * Set harga jasa klaim jasa ffs pasien bpjs oleh dokter-dokter
				 * tertentu
				 */
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterUmumHD / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterUmumHD + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai) && REHAB_MEDIK.equals(d.get("idDepartemen"))
					&& "Eksekutif".equals(d.get("jenisRuangan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLuarTerapis / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLuarTerapis + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				LocalDateTime tglJamPelayanan = ((Date) d.get("tglPelayanan")).toInstant()
						.atZone(ZoneId.systemDefault()).toLocalDateTime();
				RemunHargaJasa hargaJasa;
				if (tglJamPelayanan.isBefore(tmtJasaTerapis24)) {
					hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis + "%");
				} else {
					hargaJasa = hargaJasa(persenJasaTerapis24 / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis24 + "%");
				}
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperator / 100, hargaJual, d);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100, hargaJual, d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d);
				d.put("persenJasa", persenRadiologi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (REHAB_MEDIK.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRehabMedik / 100, hargaJual, d);
				d.put("persenJasa", persenRehabMedik + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (KONSULTASI.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenKonsultasi / 100, hargaJual, d);
				d.put("persenJasa", persenKonsultasi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (VISIT.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenVisite / 100, hargaJual, d);
				d.put("persenJasa", persenVisite + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkGenetika.contains(idPegawai)
					&& idsLabGenetikaLuarRuangan.contains(Integer.parseInt(d.get("idProduk").toString()))
					&& (date.before(new Date(1690822799000L)) || date.equals(new Date(1690822799000L)))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (Arrays.asList(GENETIKA).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkPatologiAnatomiList.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterPA / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterPA + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (LABORATORIUM.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenLaboratorium / 100, hargaJual, d);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			}
		}
		/*
		 * Populate data filter
		 */
		listData.forEach(d -> {
			if (!listIdProduk.contains(Integer.parseInt(d.get("idProduk").toString())))
				listIdProduk.add(Integer.valueOf(d.get("idProduk").toString()));
			if (!listPersenJasa.contains(d.get("persenJasa").toString()))
				listPersenJasa.add(d.get("persenJasa").toString());
			if (!listHargaJasa.contains(Double.parseDouble(d.get("hargaJasa").toString())))
				listHargaJasa.add(Double.valueOf(d.get("hargaJasa").toString()));
			if (!listHargaJual.contains(Double.parseDouble(d.get("hargaJual").toString())))
				listHargaJual.add(Double.valueOf(d.get("hargaJual").toString()));
			if (!listIdKelompokPasien.contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				listIdKelompokPasien.add(Integer.valueOf(d.get("idKelompokPasien").toString()));
			if (!listTanggal.contains(d.get("tanggal").toString()))
				listTanggal.add(d.get("tanggal").toString());
			if (!listJenisRuangan.contains(d.get("jenisRuangan").toString()))
				listJenisRuangan.add(d.get("jenisRuangan").toString());
		});
		/*
		 * Pengelompokkan tanggal pelayanan
		 */
		List<Map<String, Object>> dataTanggal = groupingTanggalFfs(listData);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> result = groupingKategoriFfs(dataTanggal);
		/*
		 * Final sorting
		 */
		result = result.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString()))
				.sorted(Comparator.comparing(o5 -> o5.get("jenisRuangan").toString(), Comparator.reverseOrder()))
				.collect(Collectors.toList());
		result.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		return result;
	}

	@Override
	public List<Map<String, Object>> logbookKlaimMppDokter(Integer idPegawai, String bulan) {
		List<Integer> listIdProduk = new ArrayList<>();
		List<String> listPersenJasa = new ArrayList<>();
		List<Double> listHargaJasa = new ArrayList<>();
		List<Double> listHargaJual = new ArrayList<>();
		List<Integer> listIdKelompokPasien = new ArrayList<>();
		List<String> listTanggal = new ArrayList<>();
		List<String> listJenisRuangan = new ArrayList<>();
		DateFormat df = new SimpleDateFormat("yyyy-MM");
		Date date;
		try {
			date = df.parse(bulan);
		} catch (ParseException e) {
			System.out.println(e.getMessage());
			return null;
		}
		Map<String, Object> remunFfs = this.splitRemunFfs(idPegawai, bulan);
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> listData = (List<Map<String, Object>>) remunFfs.get("klaim-mpp");
		/*
		 * Mendapatkan persentase jasa
		 */
		double persenBPJS = Double.parseDouble(getSettingDataFixed("persenJasaBPJS"));
		double persenOperatorIBS = Double.parseDouble(getSettingDataFixed("persenJasaOperatorIBS"));
		double persenAsistenIBS = Double.parseDouble(getSettingDataFixed("persenJasaAsistenIBS"));
		double persenAnestesi = Double.parseDouble(getSettingDataFixed("persenJasaAnestesiIBS"));
		double persenRadiologi = Double.parseDouble(getSettingDataFixed("persenJasaRadiologi"));
		double persenLaboratorium = Double.parseDouble(getSettingDataFixed("persenJasaLaboratorium"));
		double persenRehabMedik = Double.parseDouble(getSettingDataFixed("persenJasaRehabMedik"));
		double persenKonsultasi = Double.parseDouble(getSettingDataFixed("persenJasaKonsultasiDokter"));
		double persenVisite = Double.parseDouble(getSettingDataFixed("persenJasaVisiteDokter"));
		double persenTindakan = Double.parseDouble(getSettingDataFixed("persenJasaTindakanDokter"));
		double persenJasaDokterPA = Double.parseDouble(getSettingDataFixed("persenJasaDokterPA"));
		double persenJasaDokterUmumHD = Double.parseDouble(getSettingDataFixed("persenJasaDokterUmumHD"));
		double persenJasaLabGenetika = Double.parseDouble(getSettingDataFixed("persenJasaLabGenetika"));
		double persenJasaTerapis = Double.parseDouble(getSettingDataFixed("persenJasaTerapis"));
		double persenJasaTerapis24 = Double.parseDouble(getSettingDataFixed("persenFfsTerapisTmt21Okt24"));
		// Custom rule persentase jasa terapis 21 Oktober 2024
		LocalDateTime tmtJasaTerapis24 = LocalDateTime.of(2024, 11, 1, 0, 0, 0, 0);
		/*
		 * Persiapan filter logic remunerasi
		 */
		Date tglAwal = DateUtil.startMonth(bulan);
		List<Integer> drKkPatologiAnatomiList = pegawaiDao.getDokterByKelompokKerja(KK_PATOLOGI_ANATOMI);
		List<Integer> drKsmUmumList = pegawaiDao.getDokterByKelompokKerja(KK_UMUM);
		List<Integer> drKkGenetika = pegawaiDao.getDokterByKelompokKerja(KK_GENETIKA);
		List<Integer> drAnastesiList = pegawaiDao.getDokterByKelompokKerja(KK_ANESTESI);
		List<Integer> terapisRehabMedik = mapJabatanProfesiDao.findIdPegawaiByProfesiIn(Arrays.asList(TERAPI));
		List<Integer> idsLabGenetikaLuarRuangan = getNilaiDataFixByTMT("idProdukLabGenetikaLuarRuangan", tglAwal);
		if (terapisRehabMedik.contains(idPegawai))
			return new ArrayList<>();
		/*
		 * Mapping persentase jasa remunerasi
		 */
		for (Map<String, Object> d : listData) {
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			if (CommonUtil.isNotNullOrEmpty(d.get("idKelompokPasien"))
					&& Arrays.asList(KELOMPOK_BPJS).contains(Integer.parseInt(d.get("idKelompokPasien").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenBPJS / 100, hargaJual, d);
				/*
				 * Set persen jasa dokter luar yang klaim ffs dengan persen jasa
				 * dari tarif total
				 */
				d.put("persenJasa", persenBPJS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				/*
				 * Set harga jasa klaim jasa ffs pasien bpjs oleh dokter-dokter
				 * tertentu
				 */
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterUmumHD / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterUmumHD + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperatorIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenOperatorIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
					&& CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100,
						(hargaJual - (Double.parseDouble(d.get("persenSayatan").toString()) / 100 * hargaJual)), d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenOperatorIBS / 100, hargaJual, d);
				d.put("persenJasa", persenOperatorIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAsistenIBS / 100, hargaJual, d);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if ((BEDAH_SENTRAL.equals(d.get("idDepartemen"))
					|| (RADIOLOGI.equals(d.get("idDepartemen")) && CATHLAB.equals(d.get("idRuangan"))))
					&& DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d);
				d.put("persenJasa", persenRadiologi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai) && REHAB_MEDIK.equals(d.get("idDepartemen"))
					&& "Eksekutif".equals(d.get("jenisRuangan"))) {
				LocalDateTime tglJamPelayanan = ((Date) d.get("tglPelayanan")).toInstant()
						.atZone(ZoneId.systemDefault()).toLocalDateTime();
				RemunHargaJasa hargaJasa;
				if (tglJamPelayanan.isBefore(tmtJasaTerapis24)) {
					hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis + "%");
				} else {
					hargaJasa = hargaJasa(persenJasaTerapis24 / 100, hargaJual, d);
					d.put("persenJasa", persenJasaTerapis24 + "%");
				}
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (REHAB_MEDIK.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRehabMedik / 100, hargaJual, d);
				d.put("persenJasa", persenRehabMedik + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (KONSULTASI.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenKonsultasi / 100, hargaJual, d);
				d.put("persenJasa", persenKonsultasi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (VISIT.equals(d.get("idGolonganProduk"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenVisite / 100, hargaJual, d);
				d.put("persenJasa", persenVisite + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkGenetika.contains(idPegawai)
					&& idsLabGenetikaLuarRuangan.contains(Integer.parseInt(d.get("idProduk").toString()))
					&& (date.before(new Date(1690822799000L)) || date.equals(new Date(1690822799000L)))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (Arrays.asList(GENETIKA).contains(Integer.parseInt(d.get("idRuangan").toString()))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaLabGenetika / 100, hargaJual, d);
				d.put("persenJasa", persenJasaLabGenetika + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drKkPatologiAnatomiList.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaDokterPA / 100, hargaJual, d);
				d.put("persenJasa", persenJasaDokterPA + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (LABORATORIUM.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenLaboratorium / 100, hargaJual, d);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			}
		}
		/*
		 * Populate data filter
		 */
		listData.forEach(d -> {
			if (!listIdProduk.contains(Integer.parseInt(d.get("idProduk").toString())))
				listIdProduk.add(Integer.valueOf(d.get("idProduk").toString()));
			if (!listPersenJasa.contains(d.get("persenJasa").toString()))
				listPersenJasa.add(d.get("persenJasa").toString());
			if (!listHargaJasa.contains(Double.parseDouble(d.get("hargaJasa").toString())))
				listHargaJasa.add(Double.valueOf(d.get("hargaJasa").toString()));
			if (!listHargaJual.contains(Double.parseDouble(d.get("hargaJual").toString())))
				listHargaJual.add(Double.valueOf(d.get("hargaJual").toString()));
			if (!listIdKelompokPasien.contains(Integer.parseInt(d.get("idKelompokPasien").toString())))
				listIdKelompokPasien.add(Integer.valueOf(d.get("idKelompokPasien").toString()));
			if (!listTanggal.contains(d.get("tanggal").toString()))
				listTanggal.add(d.get("tanggal").toString());
			if (!listJenisRuangan.contains(d.get("jenisRuangan").toString()))
				listJenisRuangan.add(d.get("jenisRuangan").toString());
		});
		/*
		 * Pengelompokkan tanggal pelayanan
		 */
		List<Map<String, Object>> dataTanggal = groupingTanggalFfs(listData);
		/*
		 * Pengelompokkan produk layanan
		 */
		List<Map<String, Object>> result = groupingKategoriFfs(dataTanggal);
		/*
		 * Final sorting
		 */
		result = result.stream()
				.sorted(Comparator.comparing(o1 -> (Date) o1.get("tglPelayanan"),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o2 -> Integer.parseInt(o2.get("sortIdKelompokPasien").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o3 -> Integer.parseInt(o3.get("sortIdKelas").toString()),
						Comparator.nullsLast(Comparator.naturalOrder())))
				.sorted(Comparator.comparing(o4 -> o4.get("namaProduk").toString()))
				.sorted(Comparator.comparing(o5 -> o5.get("jenisRuangan").toString(), Comparator.reverseOrder()))
				.collect(Collectors.toList());
		result.forEach(r -> {
			/*
			 * Hapus informasi tidak perlu
			 */
			r.remove("idDPJP");
			r.remove("tglPelayanan");
			r.remove("tanggal");
			r.remove("idKelas");
			r.remove("namaKelas");
			r.remove("idPelayananPasienPetugas");
			r.remove("idPelayananPasien");
			r.remove("norecs");
			r.remove("idDepartemen");
			r.remove("idPasienDaftar");
			r.remove("idPegawai");
			r.remove("idAntrianPasienDiperiksa");
		});
		return result;
	}

	@Override
	public List<Map<String, Object>> logbookFixedPayDokter(Integer idPegawai, String bulan, Map<String, Object> data) {
		Map<String, Object> remunFixedPay;
		if (CommonUtil.isNotNullOrEmpty(data)) {
			remunFixedPay = data;
		} else {
			remunFixedPay = this.splitRemunFfs(idPegawai, bulan);
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> listData = (List<Map<String, Object>>) remunFixedPay.get("fixed-pay");
		return listData;
	}

	@Override
	public List<Map<String, Object>> detailLogbookTarifDokter(Integer idPegawai, List<String> norecs) {
		List<Integer> paketBukanFixedPay = getNilaiDataFixByTMT("produkPaketBukanFixedPay", new Date());
		List<Map<String, Object>> result = pelayananPasienDao.findPelayananPasienByPetugasAndPelayananPasien(idPegawai,
				norecs);
		List<String> listIdPelayananPaketBukanFixedPay = result.stream()
				.filter(r -> paketBukanFixedPay.contains(Integer.parseInt(r.get("idProduk").toString())))
				.map(r -> r.get("idPelayanan").toString()).collect(Collectors.toList());
		if (!listIdPelayananPaketBukanFixedPay.isEmpty()) {
			List<PelayananPasienDetail> detailPelayananPaketBukanFixedPay = pelayananPasienDetailDao
					.findByPelayananAndKomponenHarga(listIdPelayananPaketBukanFixedPay, TOTAL_TARIF);
			for (Map<String, Object> res : result) {
				Optional<PelayananPasienDetail> detail = detailPelayananPaketBukanFixedPay.stream()
						.filter(d -> d.getPelayananPasienId().equals(res.get("idPelayanan"))).findFirst();
				detail.ifPresent(d -> res.put("hargaJual",
						CommonUtil.isNotNullOrEmpty(d.getHargaJual()) ? d.getHargaJual() : 0.00));
			}
		}
		return result;
	}

	private RemunHargaJasa hargaJasa(double persenRemunerasi, double hargaJual, Map<String, Object> d) {
		String keterangan = "";
		RemunHargaJasa.RemunHargaJasaBuilder builder = RemunHargaJasa.builder();
		if (KLINIK_KARYAWAN.equals(d.get("idRuangan")) || KLINIK_GIGI_KARYAWAN.equals(d.get("idRuangan"))) {
			builder.nilai(0.0);
			builder.keterangan("Diskon Klinik Karyawan (100%)");
			return builder.build();
		}
		double hargaDiskon = Double.parseDouble(d.get("hargaDiskon").toString());
		double persenDiskonPegawai = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonPegawai"))
				? Double.parseDouble(d.get("persenDiskonPegawai").toString()) : 0.0;
		double persenDiskonJasa = 0.0;
		if (DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0;
		} else if (ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0;
		} else if (DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0;
		}
		if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
			builder.nilai(persenRemunerasi * (hargaJual - hargaDiskon));
		} else {
			builder.nilai(
					persenRemunerasi * hargaJual * (1 - persenDiskonPegawai / 100) * (1 - persenDiskonJasa / 100));
		}
		if (Boolean.parseBoolean(d.get("isCito").toString())) {
			keterangan = keterangan + "Cito (+" + Double.parseDouble(d.get("persenCito").toString()) + "%)";
		}
		if (CommonUtil.isNotNullOrEmpty(d.get("idSayatan")) && CommonUtil.isNotNullOrEmpty("urutanSayatan")
				&& Integer.parseInt(d.get("urutanSayatan").toString()) != 1)
			keterangan = keterangan + "Diskon Sayatan ke-" + d.get("urutanSayatan").toString() + " ("
					+ Double.parseDouble(d.get("persenSayatan").toString()) + "%)";
		if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
			if (persenDiskonPegawai > 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else if (persenDiskonPegawai > 0.0 && persenDiskonJasa <= 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				} else {
					builder.keterangan(keterangan + " + Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				}
			} else if (persenDiskonPegawai <= 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(
							keterangan + " + Selisih Paket + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else {
				builder.keterangan("");
			}
		} else {
			if (persenDiskonPegawai > 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Pegawai (" + persenDiskonPegawai + "%) + Diskon Jasa Medis Dokter ("
							+ persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else if (persenDiskonPegawai > 0.0 && persenDiskonJasa <= 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Pegawai (" + persenDiskonPegawai + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				}
			} else if (persenDiskonPegawai <= 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else {
				builder.keterangan(keterangan);
			}
		}
		return builder.build();
	}

	private RemunHargaJasa hargaJasaFixedPay(Map<String, Object> d) {
		String keterangan = "";
		RemunHargaJasa.RemunHargaJasaBuilder builder = RemunHargaJasa.builder();
		if (KLINIK_KARYAWAN.equals(d.get("idRuangan")) || KLINIK_GIGI_KARYAWAN.equals(d.get("idRuangan"))) {
			builder.nilai(0.0);
			builder.keterangan("Diskon Klinik Karyawan (100%)");
			return builder.build();
		}
		double hargaJasa = Double.parseDouble(d.get("hargaJasa").toString());
		double hargaDiskon = Double.parseDouble(d.get("hargaDiskon").toString());
		double persenDiskonPegawai = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonPegawai"))
				? Double.parseDouble(d.get("persenDiskonPegawai").toString()) : 0.0;
		double persenDiskonJasa = 0.0;
		if (DOKTER_PEMERIKSA.equals(d.get("idJenisPelaksana")) && CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0;
		} else if (ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0;
		} else if (DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))) {
			persenDiskonJasa = CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0;
		}
		if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
			builder.nilai(hargaJasa - hargaDiskon);
		} else {
			builder.nilai(hargaJasa * (1 - persenDiskonPegawai / 100) * (1 - persenDiskonJasa / 100));
		}
		if (Boolean.parseBoolean(d.get("isCito").toString())) {
			keterangan = keterangan + "Cito (+" + Double.parseDouble(d.get("persenCito").toString()) + "%)";
		}
		if (CommonUtil.isNotNullOrEmpty(d.get("idSayatan")) && CommonUtil.isNotNullOrEmpty("urutanSayatan")
				&& Integer.parseInt(d.get("urutanSayatan").toString()) != 1)
			keterangan = keterangan + "Diskon Sayatan ke-" + d.get("urutanSayatan").toString() + " ("
					+ Double.parseDouble(d.get("persenSayatan").toString()) + "%)";
		if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
			if (persenDiskonPegawai > 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else if (persenDiskonPegawai > 0.0 && persenDiskonJasa <= 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				} else {
					builder.keterangan(keterangan + " + Selisih Paket + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				}
			} else if (persenDiskonPegawai <= 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Selisih Paket + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(
							keterangan + " + Selisih Paket + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else {
				builder.keterangan(keterangan);
			}
		} else {
			if (persenDiskonPegawai > 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Pegawai (" + persenDiskonPegawai + "%) + Diskon Jasa Medis Dokter ("
							+ persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Pegawai (" + persenDiskonPegawai
							+ "%) + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else if (persenDiskonPegawai > 0.0 && persenDiskonJasa <= 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Pegawai (" + persenDiskonPegawai + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Pegawai (" + persenDiskonPegawai + "%)");
				}
			} else if (persenDiskonPegawai <= 0.0 && persenDiskonJasa > 0.0) {
				if (keterangan.isEmpty()) {
					builder.keterangan("Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				} else {
					builder.keterangan(keterangan + " + Diskon Jasa Medis Dokter (" + persenDiskonJasa + "%)");
				}
			} else {
				builder.keterangan(keterangan);
			}
		}
		return builder.build();
	}

}
