package com.jasamedika.medifirst2000.service.impl;

import com.jasamedika.medifirst2000.base.BaseTransaction;
import com.jasamedika.medifirst2000.constants.Master;
import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.*;
import com.jasamedika.medifirst2000.dto.BatalPaketProdukDto;
import com.jasamedika.medifirst2000.dto.RemunHargaJasa;
import com.jasamedika.medifirst2000.dto.TagihanPendaftaranDto;
import com.jasamedika.medifirst2000.entities.*;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.LoginUserService;
import com.jasamedika.medifirst2000.service.PelayananPasienService;
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 org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.*;
import java.time.*;
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.FeeForService.HK_02_04_III_558_2015_4_B_1;
import static com.jasamedika.medifirst2000.constants.Master.FeeForService.HK_02_04_III_558_2015_5_B_C_D;
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.JenisPegawai.DOKTER;
import static com.jasamedika.medifirst2000.constants.Master.JenisPetugasPelaksana.*;
import static com.jasamedika.medifirst2000.constants.Master.JenisProduk.NONLOGBOOK;
import static com.jasamedika.medifirst2000.constants.Master.JenisProduk.OBAT_ALKES;
import static com.jasamedika.medifirst2000.constants.Master.KONSUL_VISIT;
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.KelompokUser.TATA_REKENING;
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.TipePegawai.PURNA_WAKTU;
import static com.jasamedika.medifirst2000.constants.Master.UnitKerja.KSM_OBGYN;
import static com.jasamedika.medifirst2000.entities.constant.TipePaket.PERSALINAN;
import static com.jasamedika.medifirst2000.enums.JenisMappingProdukPaket.PERAWAT;
import static com.jasamedika.medifirst2000.enums.JenisMappingProdukPaket.TINDAKAN_UTAMA;

/**
 * Implement class for PelayananPasienService
 *
 * @author Generator
 */
@Service("pelayananPasienService")
@Transactional
public class PelayananPasienServiceImpl extends BaseVoServiceImpl implements PelayananPasienService {

	@Autowired
	private BaseConverterImpl<PelayananPasienVO, PelayananPasien> pelayananPasienConverter;

	@Autowired
	private BaseConverterImpl<PelayananPasienDetailVO, PelayananPasienDetail> pelayananPasienDetailConverter;

	@Autowired
	private BaseConverterImpl<PelayananPasienPetugasVO, PelayananPasienPetugas> pelayananPasienPetugasConverter;

	@Autowired
	private BaseConverterImpl<MapPelayananPasienPetugasToPegawaiVO, MapPelayananPasienPetugasToPegawai> mapPelayananPasienPetugasToPegawaiConverter;

	@Autowired
	private BaseConverterImpl<PelayananPasienTidakTerklaimVO, PelayananPasienTidakTerklaim> pelayananPasienTidakTerklaimConverter;

	@Autowired
	private BaseConverterImpl<RacikanDetailVO, RacikanDetail> racikanDetailConverter;

	@Autowired
	private BaseConverterImpl<JenisObatVO, JenisObat> jenisObatConverter;

	@Autowired
	private BaseConverterImpl<ProdukVO, Produk> produkConverter;

	@Autowired
	private LoginUserService loginUserService;

	@Autowired
	private PasienDaftarDao pasienDaftarDao;

	@Autowired
	private PelayananPasienDao pelayananPasienDao;

	@Autowired
	private PelayananPasienDetailDao pelayananPasienDetailDao;

	@Autowired
	private AntrianPasienDiPeriksaDao antrianPasienDiPeriksaDao;

	@Autowired
	private LogAccDao logAccDao;

	@Autowired
	private StrukPelayananDao strukPelayananDao;

	@Autowired
	private PegawaiJadwalKerjaDao pegawaiJadwalKerjaDao;

	@Autowired
	private TargetRemunDokterDetailDao targetRemunDokterDetailDao;

	@Autowired
	private MapPegawaiJabatanToUnitKerjaDao mapPegawaiJabatanToUnitKerjaDao;

	@Autowired
	private PegawaiDao pegawaiDao;

	@Autowired
	private MapPegawaiLaboratRadiologiDao mapPegawaiLaboratRadiologiDao;

	@Autowired
	private VoucherPaketDao voucherPaketDao;

	@Autowired
	private MapProdukPaketDao mapProdukPaketDao;

	@Autowired
	private MapProdukPaketToProdukDao mapProdukPaketToProdukDao;

	@Autowired
	private HargaNettoProdukByKelasDao hargaNettoProdukByKelasDao;

	@Autowired
	private HargaNettoProdukByKelasDDao hargaNettoProdukByKelasDDao;

	@Autowired
	private PelayananPasienPetugasDao pelayananPasienPetugasDao;

	@Autowired
	private PelayananPasienTidakTerklaimDao pelayananPasienTidakTerklaimDao;

	@Autowired
	private RacikanDetailDao racikanDetailDao;

	@Autowired
	private MapPelayananPasienPetugasToPegawaiDao mapPelayananPasienPetugasToPegawaiDao;

	@Autowired
	private PasienDao pasienDao;

	@Autowired
	private MapJabatanProfesiDao mapJabatanProfesiDao;

	@Autowired
	private ProdukPaketDao produkPaketDao;

	@Override
	public Map<String, Object> savePelayananPasien(PelayananPasienVO vo) {
		Map<String, Object> result = new HashMap<>();
		PelayananPasien model = new PelayananPasien();
		model = pelayananPasienConverter.transferVOToModel(vo, model);
		model.setPasienDaftar(antrianPasienDiPeriksaDao.finByNoIdAndTglRegistrasi((short) 0, vo.getPasien().getId(),
				vo.getTglRegistrasi()));
		if (CommonUtil.isNotNullOrEmpty(vo.getJenisObat())) {
			model.setJenisObat(jenisObatConverter.transferVOToModel(vo.getJenisObat(), new JenisObat()));
		}
		if (CommonUtil.isNotNullOrEmpty(vo.getProduk())) {
			model.setProduk(produkConverter.transferVOToModel(vo.getProduk(), new Produk()));
		}

		PelayananPasien resultDomain = pelayananPasienDao.save(model);
		if (CommonUtil.isNotNullOrEmpty(resultDomain)) {
			result.put("noRec", resultDomain.getNoRec());
		}

		return result;
	}

	@Override
	public Map<String, Object> deletePelayanan(List<Map<String, Object>> listVO) {
		Map<String, Object> result = new HashMap<>();

		if (CommonUtil.isNotNullOrEmpty(listVO)) {

			for (Map<String, Object> vo : listVO) {
				Map<String, Object> check = strukPelayananDao.checkDeletePelayanan((String) vo.get("noRecStruk"));

				if (CommonUtil.isNullOrEmpty(check)) {
					PelayananPasien pelayananPasien = pelayananPasienDao.findOne((String) vo.get("noRec"));
					String norec = pelayananPasien.getNoRec();
					if (CommonUtil.isNotNullOrEmpty(pelayananPasien)) {
						pelayananPasienDao.delete(pelayananPasien);

						LogAcc log = new LogAcc();
						log.setTanggal(new Date());
						if (CommonUtil.isNotNullOrEmpty(norec)) {
							log.setNoReff(norec);
						}
						if (CommonUtil.isNotNullOrEmpty(log)) {
							log.setJenisTransaksi("hapus pelayanan");
							if (CommonUtil.isNotNullOrEmpty(log)) {
								logAccDao.save(log);
							}
						}
					}
				}
			}
		}

		return result;
	}

	@Override
	public Map<String, Object> findTindakanPasienMeninggal(Integer noCm) {
		Map<String, Object> result = new HashMap<>();

		List<Integer> listDetailProdukJenazah = splitDataSettingDatafixed("listDetailProdukJenazah");

		List<Map<String, Object>> tindakanPasienMeninggal = pelayananPasienDao.getTindakanPasienMeninggal(noCm,
				listDetailProdukJenazah);
		Double totalHargaTindakanPasienMeninggal = pelayananPasienDao.getTotalHargaTindakanPasienMeninggal(noCm,
				listDetailProdukJenazah);
		Map<String, Object> dataPasienMeninggal = pelayananPasienDao.getDataPasienMeninggal(noCm);

		result.put("tindakan", tindakanPasienMeninggal);
		result.put("totalHarga", totalHargaTindakanPasienMeninggal);
		result.put("namaPasien", dataPasienMeninggal.get("namaPasien"));
		result.put("alamat", dataPasienMeninggal.get("alamat"));

		return result;
	}

	public Double calculateRemunWithFfs(Integer idKelPasien, Integer idDepartemen, Integer idLayanan,
			String namaLayanan, Integer tipePegawai, Double hargaJual, Double hargaDiskon, Double jumlahLayanan) {
		double result;

		List<Integer> idsKonsultasiDokterJaga = splitDataSettingDatafixed("pr_konsultasi_dokter_jaga");

		if (Arrays.asList(KELOMPOK_BPJS).contains(idKelPasien)) {
			if (idDepartemen.equals(IGD)) {
				if (idsKonsultasiDokterJaga.contains(idLayanan)) {
					result = 30000.0;
				} else {
					result = (hargaJual - hargaDiskon) * jumlahLayanan * HK_02_04_III_558_2015_5_B_C_D;
				}
			} else if (idDepartemen.equals(RAWAT_INAP)) {
				if (tipePegawai.equals(PURNA_WAKTU)) {
					result = (hargaJual - hargaDiskon) * jumlahLayanan * HK_02_04_III_558_2015_5_B_C_D;
				} else {
					result = 0.0;
				}
			} else {
				result = (hargaJual - hargaDiskon) * jumlahLayanan * HK_02_04_III_558_2015_5_B_C_D;
			}
		} else {
			if (idDepartemen.equals(IGD)) {
				if (idsKonsultasiDokterJaga.contains(idLayanan)) {
					result = 30000.0;
				} else {
					result = (hargaJual - hargaDiskon) * jumlahLayanan;
				}
			} else if (idDepartemen.equals(RAWAT_INAP)) {
				if (Arrays.stream(KONSUL_VISIT).anyMatch(namaLayanan.toLowerCase()::contains)) {
					if (tipePegawai.equals(PURNA_WAKTU)) {
						if ((hargaJual - hargaDiskon) < HK_02_04_III_558_2015_4_B_1) {
							result = (hargaJual - hargaDiskon) * jumlahLayanan;
						} else {
							result = HK_02_04_III_558_2015_4_B_1 * jumlahLayanan;
						}
					} else {
						result = (hargaJual - hargaDiskon) * jumlahLayanan;
					}
				} else {
					result = (hargaJual - hargaDiskon) * jumlahLayanan;
				}
			} else {
				result = (hargaJual - hargaDiskon) * jumlahLayanan;
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> hitungRemunerasiDokterDenganFfs(String tglAwal, String tglAkhir) {
		List<Map<String, Object>> result = new ArrayList<>();
		List<Integer> listIdPegawai = new ArrayList<>();

		DecimalFormatSymbols formatRp = new DecimalFormatSymbols();
		formatRp.setCurrencySymbol("Rp");
		formatRp.setMonetaryDecimalSeparator(',');
		formatRp.setGroupingSeparator('.');

		DecimalFormat kursINA = (DecimalFormat) DecimalFormat.getCurrencyInstance();
		kursINA.setDecimalFormatSymbols(formatRp);

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

		Date dateAwal = new Date();
		Date dateAkhir = new Date();
		try {
			dateAwal = sdf.parse(tglAwal);
			dateAkhir = sdf.parse(tglAkhir);
		} catch (ParseException e) {
			System.out.println(e.getMessage());
		}

		List<Map<String, Object>> data = pelayananPasienDao.getDataPendapatan(DOKTER, dateAwal, dateAkhir);

		for (Map<String, Object> map : data) {
			if (!listIdPegawai.contains(Integer.parseInt(map.get("idPegawai").toString()))
					&& !map.get("namaPegawai").equals("-")) {
				listIdPegawai.add(Integer.parseInt(map.get("idPegawai").toString()));
			}
		}

		for (Integer idPegawai : listIdPegawai) {
			Double remun = 0.0;
			Map<String, Object> mapRes = new HashMap<>();
			for (Map<String, Object> map : data) {
				if (idPegawai.equals(Integer.parseInt(map.get("idPegawai").toString()))) {
					Integer idKelPasien = Integer.parseInt(map.get("idKelPasien").toString());
					Integer idDepartemen = Integer.parseInt(map.get("idDepartemen").toString());
					Integer idLayanan = Integer.parseInt(map.get("idLayanan").toString());
					String namaLayanan = map.get("namaLayanan").toString();
					Integer tipePegawai = Integer.parseInt(map.get("tipePegawai").toString());
					Double hargaJual = Double.parseDouble(map.get("hargaJual").toString());
					Double hargaDiskon = Double.parseDouble(map.get("hargaDiskon").toString());
					Double jumlahLayanan = Double.parseDouble(map.get("jumlahLayanan").toString());

					if (!map.get("idJenisProduk").equals(OBAT_ALKES)) {
						remun += calculateRemunWithFfs(idKelPasien, idDepartemen, idLayanan, namaLayanan, tipePegawai,
								hargaJual, hargaDiskon, jumlahLayanan);
					}

					mapRes.put("namaPegawai", map.get("namaPegawai"));
				}
			}
			if (!remun.equals(0.0)) {
				mapRes.put("remunValue", remun);
				mapRes.put("remunKurs", kursINA.format(remun));
				result.add(mapRes);
			}
		}

		return result;
	}

	@Override
	public List<String> updateKlaimDiskon(String noRegistrasi, Double totalKlaim, Integer jenisDiskon) {
		List<String> result = new ArrayList<>();

		List<Integer> labRadiologi = new ArrayList<>();
		labRadiologi.add(LABORATORIUM_PATOLOGI_ANATOMI);
		labRadiologi.add(LABORATORIUM_PATOLOGI_KLINIK);
		labRadiologi.add(Master.Ruangan.RADIOLOGI);

		List<Integer> listProdukKlinik = splitDataSettingDatafixed("listProdukDiskonPegawai");
		List<Integer> listProdukTht = splitDataSettingDatafixed("listProdukDiskonThtPegawai");
		List<Integer> listProdukMata = splitDataSettingDatafixed("listProdukDiskonMataPegawai");
		List<Integer> listProdukGigi = splitDataSettingDatafixed("listProdukDiskonGigiPegawai");
		List<Integer> listProdukLabRadiologi = splitDataSettingDatafixed("listProdukDiskonLabRadiologiPasien");
		List<Integer> listProdukFarmasi = splitDataSettingDatafixed("listProdukDiskonObatPegawai");
		List<Integer> listProdukMpp = splitDataSettingDatafixed("listProdukDiskonPasien");

		List<Map<String, Object>> data = pelayananPasienDao.findLayananTagihan(noRegistrasi, jenisDiskon,
				KLINIK_KARYAWAN, listProdukKlinik, POLI_THT, listProdukTht, POLI_MATA, listProdukMata,
				KLINIK_GIGI_KARYAWAN, listProdukGigi, labRadiologi, listProdukLabRadiologi, listProdukFarmasi,
				listProdukMpp);

		List<PelayananPasien> models = new ArrayList<>();
		for (Map<String, Object> map : data) {
			PelayananPasien pp = pelayananPasienDao.findOne(map.get("noRec").toString());
			pp.setHargaDiscount(Double.valueOf(map.get("hargaDiskon").toString()));
			if (CommonUtil.isNotNullOrEmpty(map.get("jasa"))) {
				pp.setJasa(Double.valueOf(map.get("jasa").toString()));
			}
			models.add(pp);
		}

		Iterable<PelayananPasien> resultModels = pelayananPasienDao.save(models);
		if (CommonUtil.isNotNullOrEmpty(resultModels)) {
			for (PelayananPasien pp : resultModels) {
				result.add(pp.getNoRec());
			}
		}

		return result;
	}

	@Override
	public String resetKlaimDiskon(String noRegistrasi) {
		String result = "";

		List<PelayananPasienDetail> detailLayanan = pelayananPasienDao.findDetail(noRegistrasi);
		List<PelayananPasien> layanan = pelayananPasienDao.findAll(noRegistrasi);
		List<PasienDaftar> pendaftaran = pasienDaftarDao.findAll(noRegistrasi);

		boolean exception = false;
		for (PasienDaftar pd : pendaftaran) {
			if (CommonUtil.isNotNullOrEmpty(pd.getStrukPelayanan())
					&& CommonUtil.isNotNullOrEmpty(pd.getStrukPelayanan().getNoRec())
					&& CommonUtil.isNotNullOrEmpty(pd.getStrukBuktiPenerimaan())
					&& CommonUtil.isNotNullOrEmpty(pd.getStrukBuktiPenerimaan().getNoRec())) {
				exception = true;

				result = "Batal diskon gagal, tagihan layanan sudah lunas!";
				break;
			} else if (CommonUtil.isNotNullOrEmpty(pd.getStrukPelayanan())
					&& CommonUtil.isNotNullOrEmpty(pd.getStrukPelayanan().getNoRec())
					&& CommonUtil.isNullOrEmpty(pd.getStrukBuktiPenerimaan())) {
				exception = true;

				result = "Batal diskon gagal, pelayanan sudah terverifikasi!";
				break;
			} else if (CommonUtil.isNullOrEmpty(pd.getDiskonPegawai())
					|| (CommonUtil.isNotNullOrEmpty(pd.getDiskonPegawai()) && pd.getDiskonPegawai() == 0)) {
				exception = true;

				result = "Belum dilakukan diskon!";
				break;
			}
		}

		if (!exception) {
			/*
			 * Update Pelayanan Pasien
			 */
			double jasaObat = 0.00;
			for (PelayananPasien pp : layanan) {
				/*
				 * Get diskon jasamedis
				 */
				double diskonJasamedis = 0.0;
				for (PelayananPasienDetail ppd : detailLayanan) {
					if (pp.getNoRec().equals(ppd.getPelayananPasien().getNoRec())
							&& CommonUtil.isNotNullOrEmpty(ppd.getHargaDiscount()) && ppd.getHargaDiscount() > 0.0) {
						diskonJasamedis += ppd.getHargaDiscount();
					}
				}

				if (CommonUtil.isNotNullOrEmpty(pp.getHargaDiscount()) && pp.getHargaDiscount() > 0.0) {
					/*
					 * Set diskon layanan
					 */
					if (diskonJasamedis > 0.0 && pp.getHargaDiscount() >= diskonJasamedis) {
						pp.setHargaDiscount(diskonJasamedis);
					} else {
						pp.setHargaDiscount(0.0);
					}
					/*
					 * Set diskon obat
					 */
					if (CommonUtil.isNotNullOrEmpty(pp.getStrukResep())
							&& CommonUtil.isNotNullOrEmpty(pp.getStrukResep().getNoRec())) {
						pp.setJasa(jasaObat);
					}
				}
			}
			pelayananPasienDao.save(layanan);

			/*
			 * Update Flag Jenis Diskon Pasien Daftar
			 */
			for (PasienDaftar pd : pendaftaran) {
				pd.setDiskonPegawai(0);
			}
			pasienDaftarDao.save(pendaftaran);

			result = "SUKSES";
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> rekapLogbook(Integer idPegawai, String bulan) {
		List<Map<String, Object>> result = new ArrayList<>();
		Map<String, Object> data = this.splitRemunFfs(idPegawai, bulan);
		Map<String, Object> jkn = rekapLogbookJkn(idPegawai, bulan, data);
		Map<String, Object> nonJknDalamJamKerja = rekapLogbookNonJknDalamJamKerja(idPegawai, bulan, data);
		Map<String, Object> nonJknLuarJamKerja = rekapLogbookNonJknLuarJamKerja(idPegawai, bulan, data);
		Map<String, Object> fixedPay = rekapLogbookFixedPay(idPegawai, bulan, data);

		result.add(jkn);
		result.add(nonJknDalamJamKerja);
		result.add(nonJknLuarJamKerja);
		result.add(fixedPay);
		return result;
	}

	private List<Map<String, Object>> detailRekapLogbook(List<Map<String, Object>> data, String bulan) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
		DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		DateTimeFormatter tanggalFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
		YearMonth localMonth = YearMonth.parse(bulan, monthFormatter);
		List<Map<String, Object>> detailTanggal = new ArrayList<>();
		data.forEach(d -> {
			List<Map<String, Object>> detail = (List<Map<String, Object>>) d.get("detail");
			detail.forEach(tail -> tail.put("hargaJasa", Double.parseDouble(d.get("hargaJasa").toString())));
			detailTanggal.addAll(detail);
		});
		LocalDate startDate = localMonth.atDay(1);
		LocalDate endDate = localMonth.atEndOfMonth();
		List<Map<String, Object>> result = new ArrayList<>();
		for (LocalDate date = startDate; date.isBefore(endDate) || date.isEqual(endDate); date = date.plusDays(1)) {
			String tanggal = dateFormatter.format(date);
			double jumlahHargaJasa = detailTanggal.stream()
					.filter(tail -> tail.get("tanggal").toString().equals(tanggal))
					.mapToDouble(tail -> Double.parseDouble(tail.get("hargaJasa").toString())
							* Double.parseDouble(tail.get("jumlah").toString()))
					.sum();
			if (jumlahHargaJasa > 0.0) {
				Map<String, Object> capaianTanggal = new HashMap<>();
				capaianTanggal.put("tanggal", tanggalFormatter.format(date));
				capaianTanggal.put("capaian", nf.format(jumlahHargaJasa));
				{
					List<Map<String, Object>> deskripsi = new ArrayList<>();
					data.forEach(d -> {
						Map<String, Object> detailDeskripsi = new HashMap<>();
						List<Map<String, Object>> detailData = (List<Map<String, Object>>) d.get("detail");
						detailData.stream().filter(tail -> tail.get("tanggal").toString().equals(tanggal)).findFirst()
								.ifPresent(tail -> {
									detailDeskripsi.put("layanan", d.get("namaProduk").toString());
									if (CommonUtil.isNotNullOrEmpty(d.get("persenJasa"))) {
										detailDeskripsi.put("tarifJasa",
												nf.format(Double.parseDouble(d.get("hargaJual").toString())) + "/"
														+ d.get("persenJasa").toString());
									} else {
										detailDeskripsi.put("tarifJasa",
												nf.format(Double.parseDouble(d.get("hargaJual").toString())));
									}
									detailDeskripsi.put("remun",
											nf.format(Double.parseDouble(d.get("hargaJasa").toString())));
									detailDeskripsi.put("jumlah", tail.get("jumlah").toString());
									detailDeskripsi.put("keterangan", d.get("keterangan").toString());
								});
						if (CommonUtil.isNotNullOrEmpty(detailDeskripsi))
							deskripsi.add(detailDeskripsi);
					});
					capaianTanggal.put("deskripsi", deskripsi);
				}
				result.add(capaianTanggal);
			}
		}
		return result;
	}

	private Map<String, Object> rekapLogbookJkn(Integer idPegawai, String bulan, Map<String, Object> remun) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		String def = nf.format(0.0);
		Map<String, Object> result = new HashMap<>();
		result.put("id", "JKN");
		result.put("capaian", def);
		Map<String, Object> logbook = logbookRemunTarifDokter(idPegawai, bulan, remun);
		if (!logbook.isEmpty() && CommonUtil.isNotNullOrEmpty(logbook.get("data"))) {
			List<Map<String, Object>> data = (List<Map<String, Object>>) logbook.get("data");
			{
				double jumlahHargaJasa = data.stream()
						.mapToDouble(d -> Double.parseDouble(d.get("jumlahHargaJasa").toString())).sum();
				result.put("capaian", nf.format(jumlahHargaJasa));
			}
			{
				List<Map<String, Object>> detail = detailRekapLogbook(data, bulan);
				result.put("detail", detail);
			}
		}
		return result;
	}

	private Map<String, Object> rekapLogbookNonJknDalamJamKerja(Integer idPegawai, String bulan,
			Map<String, Object> remun) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		String def = nf.format(0.0);
		Map<String, Object> result = new HashMap<>();
		result.put("id", "NON_JKN_DALAM");
		result.put("capaian", def);
		List<Map<String, Object>> data = logbookFfsTarifDokter(idPegawai, bulan, remun);
		if (!data.isEmpty()) {
			{
				double jumlahHargaJasa = data.stream()
						.mapToDouble(d -> Double.parseDouble(d.get("jumlahHargaJasa").toString())).sum();
				result.put("capaian", nf.format(jumlahHargaJasa));
			}
			{
				List<Map<String, Object>> detail = detailRekapLogbook(data, bulan);
				result.put("detail", detail);
			}
		}
		return result;
	}

	private Map<String, Object> rekapLogbookNonJknLuarJamKerja(Integer idPegawai, String bulan,
			Map<String, Object> remun) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		String def = nf.format(0.0);
		Map<String, Object> result = new HashMap<>();
		result.put("id", "NON_JKN_LUAR");
		result.put("capaian", def);
		List<Map<String, Object>> data = logbookFfsLuarTarifDokter(idPegawai, bulan, remun);
		if (!data.isEmpty()) {
			{
				double jumlahHargaJasa = data.stream()
						.mapToDouble(d -> Double.parseDouble(d.get("jumlahHargaJasa").toString())).sum();
				result.put("capaian", nf.format(jumlahHargaJasa));
			}
			{
				List<Map<String, Object>> detail = detailRekapLogbook(data, bulan);
				result.put("detail", detail);
			}
		}
		return result;
	}

	private Map<String, Object> rekapLogbookFixedPay(Integer idPegawai, String bulan, Map<String, Object> remun) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		String def = nf.format(0.0);
		Map<String, Object> result = new HashMap<>();
		result.put("id", "FIXED_PAY");
		result.put("capaian", def);
		List<Map<String, Object>> data = logbookFixedPayDokter(idPegawai, bulan, remun);
		if (!data.isEmpty()) {
			{
				double jumlahHargaJasa = data.stream()
						.mapToDouble(d -> Double.parseDouble(d.get("jumlahHargaJasa").toString())).sum();
				result.put("capaian", nf.format(jumlahHargaJasa));
			}
			{
				List<Map<String, Object>> detail = detailRekapLogbook(data, bulan);
				result.put("detail", detail);
			}
		}
		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) {
			System.out.println(e.getMessage());
			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"));
		/*
		 * 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> 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> 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
		 */
		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 (Boolean.parseBoolean(d.get("isSelisihPaket").toString()))
				hargaJual -= Double.parseDouble(d.get("hargaDiskon").toString());
			if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterUmumHD / 100, hargaJual, d, false);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunTerapis / 100, hargaJual, d, false);
				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, false);
				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, false);
				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, false);
				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,
						false);
				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,
						false);
				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,
						false);
				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, false);
				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, false);
				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, false);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (RADIOLOGI.equals(d.get("idDepartemen"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRadiologi / 100, hargaJual, d, false);
				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, false);
				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, false);
				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, false);
				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, false);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (drAnastesiList.contains(idPegawai) && DOKTER_ANASTESI.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenAnestesi / 100, hargaJual, d, false);
				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, false);
				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, false);
				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, false);
				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, false);
				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, false);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d, false);
				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)) {
			/*
			 * 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)) {
						/*
						 * 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 (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.isNotNullOrEmpty(listDetailJenisProdukException)
								&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
								&& listDetailJenisProdukException
										.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							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)) {
						/*
						 * 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 (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.isNotNullOrEmpty(listDetailJenisProdukException)
								&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
								&& listDetailJenisProdukException
										.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							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)) {
						/*
						 * 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 (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.isNotNullOrEmpty(listDetailJenisProdukException)
								&& CommonUtil.isNotNullOrEmpty(next.get("idDetailJenisProduk"))
								&& listDetailJenisProdukException
										.contains(Integer.parseInt(next.get("idDetailJenisProduk").toString()))) {
							/*
							 * Diluar pembatasan jenis produk
							 */
							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);
			if (terapisRehabMedik.contains(idPegawai))
				result.put("fixed-pay", new ArrayList<>());
		}
		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>> 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>> 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>> transformPelayananPaket(Integer idPegawai, List<Map<String, Object>> listData) {
		List<Integer> drKsmObgyn = pegawaiDao.getDokterByKsm(KSM_OBGYN);
		SimpleDateFormat month = new SimpleDateFormat("MMM-yyyy", new Locale("in", "ID"));
		listData.forEach(d -> {
			if (CommonUtil.isNotNullOrEmpty(d.get("idSayatan")))
				d.put("keterangan", "Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString()))
						+ "% komponen tarif, sayatan ke-" + d.get("urutanSayatan").toString());
		});
		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 (!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()));
			}
		});
		return listData;
	}

	private List<Map<String, Object>> transformPelayananKepalaPaketFixedPay(List<Map<String, Object>> listData) {
		listData.forEach(d -> {
			if (CommonUtil.isNotNullOrEmpty(d.get("idSayatan")))
				d.put("keterangan", "Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString()))
						+ "% komponen tarif, sayatan ke-" + d.get("urutanSayatan").toString());
		});
		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);
		});
		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;
		}
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		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"));
		/*
		 * 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);
		/*
		 * Set persen jasa dan harga jasa pasien bpjs di ibs, icu
		 */
		double persenTarifIBS = persenTarifJasaBedah / 100;
		double persenTarifICU = persenTarifJasaICU / 100;
		/*
		 * Mapping persentase jasa remunerasi
		 */
		for (Map<String, Object> d : listData) {
			double hargaJual = Double.parseDouble(d.get("hargaJual").toString());
			String keteranganTambahan = "";
			if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
				hargaJual -= Double.parseDouble(d.get("hargaDiskon").toString());
				keteranganTambahan = " dan selisih paket karena diskon "
						+ nf.format(Double.parseDouble(d.get("hargaDiskon").toString()));
			}
			if (drKsmUmumList.contains(idPegawai) && ASISTEN_SPESIALIS.equals(d.get("idJenisPelaksana"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenRemunDokterUmumHD / 100, hargaJual, d, true);
				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, true);
				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, false);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan",
						"Dari " + persenTarifJasaBedah + "% tarif" + hargaJasa.getKeterangan() + keteranganTambahan);
				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, false);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan",
						"Dari " + persenTarifJasaBedah + "% tarif" + hargaJasa.getKeterangan() + keteranganTambahan);
				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, false);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan",
						"Dari " + persenTarifJasaBedah + "% tarif" + hargaJasa.getKeterangan() + keteranganTambahan);
				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,
						false);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, false);
				d.put("persenJasa", persenTindakan + "%");
				d.put("keterangan",
						"Dari " + persenTarifJasaICU + "% tarif" + hargaJasa.getKeterangan() + keteranganTambahan);
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d, true);
				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;
		}
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		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"));
		/*
		 * 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());
			String keteranganTambahan = "";
			if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
				hargaJual -= Double.parseDouble(d.get("hargaDiskon").toString());
				keteranganTambahan = " dan selisih paket karena diskon "
						+ nf.format(Double.parseDouble(d.get("hargaDiskon").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, true);
				/*
				 * 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, true);
				d.put("persenJasa", persenJasaDokterUmumHD + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d, true);
				d.put("persenJasa", persenJasaTerapis + "%");
				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,
						false);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d, true);
				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>> 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;
		}
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		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 persenJasaLuarTerapis = Double.parseDouble(getSettingDataFixed("persenJasaLuarTerapis"));
		/*
		 * 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());
			String keteranganTambahan = "";
			if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
				hargaJual -= Double.parseDouble(d.get("hargaDiskon").toString());
				keteranganTambahan = " dan selisih paket karena diskon "
						+ nf.format(Double.parseDouble(d.get("hargaDiskon").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, true);
				/*
				 * 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, true);
				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, true);
				d.put("persenJasa", persenJasaLuarTerapis + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else if (terapisRehabMedik.contains(idPegawai)) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d, true);
				d.put("persenJasa", persenJasaTerapis + "%");
				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,
						false);
				d.put("persenJasa", persenOperator + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d, true);
				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>> 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;
		}
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		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"));
		/*
		 * 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());
			String keteranganTambahan = "";
			if (Boolean.parseBoolean(d.get("isSelisihPaket").toString())) {
				hargaJual -= Double.parseDouble(d.get("hargaDiskon").toString());
				keteranganTambahan = " dan selisih paket karena diskon "
						+ nf.format(Double.parseDouble(d.get("hargaDiskon").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, true);
				/*
				 * 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, true);
				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,
						false);
				d.put("persenJasa", persenOperatorIBS + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAsistenIBS + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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,
						false);
				d.put("persenJasa", persenAnestesi + "%");
				d.put("keterangan",
						"Dari " + (100.0 - Double.parseDouble(d.get("persenSayatan").toString())) + "% tarif"
								+ keteranganTambahan + ", sayatan ke-" + d.get("urutanSayatan").toString()
								+ 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, true);
				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, true);
				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, true);
				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, true);
				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"))) {
				RemunHargaJasa hargaJasa = hargaJasa(persenJasaTerapis / 100, hargaJual, d, true);
				d.put("persenJasa", persenJasaTerapis + "%");
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				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, true);
				d.put("persenJasa", persenLaboratorium + "%");
				d.put("keterangan", hargaJasa.getKeterangan());
				d.put("hargaJasa", hargaJasa.getNilai());
			} else {
				RemunHargaJasa hargaJasa = hargaJasa(persenTindakan / 100, hargaJual, d, true);
				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;
	}

	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;
	}

	@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;
	}

	@Override
	public List<TagihanPendaftaranDto> tagihan(String noRegistrasi) {
		List<TagihanPendaftaranDto> result = new ArrayList<>();
		TagihanPendaftaranDto.TagihanPendaftaranDtoBuilder dtoBuilder = TagihanPendaftaranDto.builder();
		List<Map<String, Object>> tagihan = pelayananPasienDao.findPelayananPasienByTagihanPendaftaran(noRegistrasi);
		List<String> noRec = tagihan.stream().map(t -> t.get("noRec").toString()).collect(Collectors.toList());
		List<Map<String, Object>> listPetugas = pelayananPasienPetugasDao.findAllByPelayananPasienNoRecIn(noRec);
		tagihan.forEach(t -> {
			dtoBuilder.noRec(t.get("noRec").toString()).idRuangan(Integer.parseInt(t.get("idRuangan").toString()))
					.namaRuangan(t.get("namaRuangan").toString()).tglPelayanan((Date) t.get("tglPelayanan"))
					.tglPelayananStr(t.get("tglPelayananStr").toString())
					.idProduk(Integer.parseInt(t.get("idProduk").toString())).namaProduk(t.get("namaProduk").toString())
					.idKelas(Integer.parseInt(t.get("idKelas").toString())).namaKelas(t.get("namaKelas").toString())
					.jumlah(Double.parseDouble(t.get("jumlah").toString()))
					.hargaJual(Double.parseDouble(t.get("hargaJual").toString()))
					.hargaDiskon(Double.parseDouble(t.get("hargaDiskon").toString()))
					.hargaJasa(Double.parseDouble(t.get("hargaJasa").toString()))
					.isPaket(Boolean.parseBoolean(t.get("isPaket").toString()))
					.isSelisihPaket(Boolean.parseBoolean(t.get("isSelisihPaket").toString()));
			Optional<Map<String, Object>> petugas = listPetugas.stream()
					.filter(p -> CommonUtil.isNotNullOrEmpty(p.get("noRecLayanan"))
							&& t.get("noRec").toString().equals(p.get("noRecLayanan"))
							&& CommonUtil.isNotNullOrEmpty(p.get("idJenisPelaksana"))
							&& DOKTER_PEMERIKSA.equals(p.get("idJenisPelaksana")))
					.findFirst();
			petugas.ifPresent(p -> {
				if (CommonUtil.isNotNullOrEmpty(p.get("idPegawai")))
					dtoBuilder.idPegawai(Integer.parseInt(p.get("idPegawai").toString()));
				if (CommonUtil.isNotNullOrEmpty(p.get("namaPegawai")))
					dtoBuilder.namaPegawai(p.get("namaPegawai").toString());
			});
			result.add(dtoBuilder.build());
		});
		return result;
	}

	@Override
	public void diskonTagihan(String kodeVoucher, List<TagihanPendaftaranDto> dtoList) {
		List<Integer> unitKerjaDiskonTarek = splitDataSettingDatafixed("unitKerjaDiskonTarek");
		List<Integer> jabatanDiskonTarek = splitDataSettingDatafixed("jabatanDiskonTarek");
		List<Integer> listIdPegawai = mapPegawaiJabatanToUnitKerjaDao
				.findPegawaiIdByUnitKerjaIdAndJabatanId(unitKerjaDiskonTarek, jabatanDiskonTarek);
		LoginUser loginUser = loginUserService.getLoginUser();
		boolean accessGranted = loginUserService.accessGranted(loginUser, listIdPegawai);
		if (!accessGranted && kodeVoucher.isEmpty()
				|| !accessGranted && !loginUser.getKelompokUser().getId().equals(TATA_REKENING))
			throw new ServiceVOException("Tidak memiliki akses melakukan diskon");
		if (CommonUtil.isNotNullOrEmpty(kodeVoucher)) {
			diskonPaket(kodeVoucher, dtoList);
		} else {
			List<String> listNoRec = dtoList.stream().map(TagihanPendaftaranDto::getNoRec).collect(Collectors.toList());
			List<PelayananPasien> listPelayanan = pelayananPasienDao.findAll(listNoRec);
			listPelayanan.forEach(p -> {
				Optional<TagihanPendaftaranDto> dto = dtoList.stream().filter(d -> d.getNoRec().equals(p.getNoRec()))
						.findFirst();
				dto.ifPresent(tagihanPendaftaranDto -> {
					p.setHargaDiscount(tagihanPendaftaranDto.getHargaDiskon());
					p.setJasa(tagihanPendaftaranDto.getHargaJasa());
					p.setIsSelisihPaket(tagihanPendaftaranDto.getIsSelisihPaket());
				});
			});
			pelayananPasienDao.save(listPelayanan);
		}
	}

	private void diskonPaket(String kodeVoucher, List<TagihanPendaftaranDto> dtoList) {
		VoucherPaket voucher = getVoucher(kodeVoucher, false);
		Optional<ProdukPaket> produkPaket = produkPaketDao.findById(voucher.getPaketId());
		List<String> norecPelayanan = dtoList.stream().map(TagihanPendaftaranDto::getNoRec)
				.collect(Collectors.toList());
		List<PelayananPasien> byNorecPelayanan = pelayananPasienDao.findAll(norecPelayanan);
		{
			Optional<PasienDaftar> pendaftaran = byNorecPelayanan.stream()
					.map(p -> p.getPasienDaftar().getPasienDaftar()).findFirst();
			pendaftaran.ifPresent(p -> {
				Integer pasienId = p.getPasien().getId();
				String ibuNoCm = p.getPasien().getReportDisplay();
				Integer ibuId = null;
				if (CommonUtil.isNotNullOrEmpty(ibuNoCm))
					ibuId = pasienDao.findIdByNoCm(ibuNoCm);
				if (CommonUtil.isNotNullOrEmpty(produkPaket) && produkPaket.isPresent()
						&& PERSALINAN.equals(produkPaket.get().getTipePaket())) {
					if ((CommonUtil.isNotNullOrEmpty(ibuId) && !voucher.getPasienId().equals(ibuId))
							|| (CommonUtil.isNullOrEmpty(ibuId) && !voucher.getPasienId().equals(pasienId)))
						throw new ServiceVOException("Kode voucher tidak sesuai dengan pasien yang diperuntukkan");
					p.setVoucherPaket(voucher);
					pasienDaftarDao.save(p);
				}
			});
		}
		{
			List<MapProdukPaketToProduk> mappingProdukPaket = mapProdukPaketToProdukDao
					.findByPaketId(voucher.getPaket().getId());
			List<Integer> idProdukMapping = mappingProdukPaket.stream()
					.map(mproduk -> mproduk.getMapProdukPaket().getProdukEntriId()).collect(Collectors.toList());
			Optional<TagihanPendaftaranDto> dtoPaket = dtoList.stream().filter(TagihanPendaftaranDto::getIsPaket)
					.filter(dto -> !idProdukMapping.contains(dto.getIdProduk()))
					.filter(dto -> !dto.getIdProduk().equals(voucher.getPaketId())).findFirst();
			if (dtoPaket.isPresent())
				throw new ServiceVOException(
						"Produk: " + dtoPaket.get().getNamaProduk() + " - Paket: " + voucher.getPaket().getNamaProduk()
								+ " belum dilakukan mapping /" + " tidak dapat dilakukan diskon");
			List<Integer> idProdukPaketDto = dtoList.stream().map(TagihanPendaftaranDto::getIdProduk)
					.filter(dto -> !dto.equals(voucher.getPaketId())).collect(Collectors.toList());
			mappingProdukPaket.stream()
					.filter(mproduk -> idProdukPaketDto.contains(mproduk.getMapProdukPaket().getProdukEntriId()))
					.forEach(mproduk -> {
						Produk produkReguler = mproduk.getProdukReguler();
						List<Map<String, Object>> tarifProdukReguler = hargaNettoProdukByKelasDao
								.checkExisting(voucher.getKelasId(), produkReguler.getId());
						if (CommonUtil.isNullOrEmpty(tarifProdukReguler) && tarifProdukReguler.isEmpty()) {
							tarifProdukReguler = hargaNettoProdukByKelasDao.checkExisting(NON_KELAS,
									produkReguler.getId());
							if (CommonUtil.isNullOrEmpty(tarifProdukReguler) && tarifProdukReguler.isEmpty())
								throw new ServiceVOException(
										"Referensi harga tarif reguler tidak ditemukan untuk produk "
												+ mproduk.getMapProdukPaket().getProdukEntri().getNamaProduk() + " -> "
												+ produkReguler.getNamaProduk() + " dan kelas "
												+ voucher.getKelas().getNamaKelas());
						}
					});
		}
		{
			List<PelayananPasienDetail> detailPelayanan = new ArrayList<>();
			List<String> norecPelayananPaket = dtoList.stream()
					.filter(d -> voucher.getPaketId().equals(d.getIdProduk())).map(TagihanPendaftaranDto::getNoRec)
					.collect(Collectors.toList());
			if (CommonUtil.isNotNullOrEmpty(norecPelayananPaket)) {
				List<PelayananPasien> pelayananPaket = pelayananPasienDao.findAll(norecPelayananPaket);
				pelayananPaket.forEach(p -> {
					Double hargaDiscount = p.getHargaDiscount();
					if (CommonUtil.isNotNullOrEmpty(hargaDiscount) && hargaDiscount > 0.0) {
						// Cek Detail Diskon
						List<PelayananPasienDetail> detailPelayananPaket = pelayananPasienDetailDao
								.findByPelayananPasien(p.getNoRec());
						List<PelayananPasienDetail> detailDiskon = detailPelayananPaket.stream()
								.filter(d -> d.getHargaDiscount() > 0.0).collect(Collectors.toList());
						if (CommonUtil.isNotNullOrEmpty(detailDiskon) && !detailDiskon.isEmpty()) {
							// Reset Diskon
							detailDiskon.forEach(d -> d.setHargaDiscount(0.0));
							detailPelayanan.addAll(detailDiskon);
						}
					}
					p.setVoucherPaket(voucher);
					p.setHargaDiscount(0.0);
				});
			}
			if (CommonUtil.isNotNullOrEmpty(detailPelayanan))
				pelayananPasienDetailDao.save(detailPelayanan);
		}
		{
			List<PelayananPasien> pelayanan = new ArrayList<>();
			dtoList.forEach(dto -> {
				Optional<PelayananPasien> pelayananFixedQty = byNorecPelayanan.stream()
						.filter(p -> p.getNoRec().equals(dto.getNoRec()))
						.filter(p -> p.getJumlah().equals(dto.getJumlah())).findFirst();
				pelayananFixedQty.ifPresent(p -> {
					p.setHargaDiscount(dto.getHargaDiskon());
					p.setJasa(dto.getHargaJasa());
					p.setIsPaket(dto.getIsPaket());
					if (dto.getIsPaket())
						p.setVoucherPaket(voucher);
					pelayanan.add(p);
				});
			});
			if (CommonUtil.isNotNullOrEmpty(pelayanan))
				pelayananPasienDao.save(pelayanan);
		}
		{
			List<PelayananPasien> pelayanan = new ArrayList<>();
			List<PelayananPasienDetail> detailPelayanan = new ArrayList<>();
			List<PelayananPasienPetugas> petugasPelayanan = new ArrayList<>();
			List<PelayananPasienTidakTerklaim> pelayananPasienTidakTerklaim = new ArrayList<>();
			List<RacikanDetail> racikanDetail = new ArrayList<>();
			List<MapPelayananPasienPetugasToPegawai> mapPetugasPegawai = new ArrayList<>();
			dtoList.forEach(dto -> {
				Optional<PelayananPasien> pelayananReducedQty = byNorecPelayanan.stream()
						.filter(p -> p.getNoRec().equals(dto.getNoRec()))
						.filter(p -> !p.getJumlah().equals(dto.getJumlah())).findFirst();
				pelayananReducedQty.ifPresent(p -> {
					if (!dto.getIsPaket())
						throw new ServiceVOException("Pemisahan layanan " + dto.getNamaProduk()
								+ " tanpa tanda diskon tidak dapat dilakukan!");
					List<PelayananPasienDetail> splitDetailPelayanan = new ArrayList<>();
					List<PelayananPasienPetugas> splitPetugasPelayanan = new ArrayList<>();
					List<PelayananPasienTidakTerklaim> splitPelayananTidakTerklaim = new ArrayList<>();
					List<RacikanDetail> splitRacikanDetail = new ArrayList<>();
					List<MapPelayananPasienPetugasToPegawai> splitMapPetugasPegawai = new ArrayList<>();
					List<PelayananPasien> splitPelayanan = copyPelayananSplitQty(p);
					Optional<PelayananPasien> origin = splitPelayanan.stream().filter(cp -> cp.getNoRec() != null)
							.findFirst();
					if (origin.isPresent()) {
						origin.get().setJumlah(dto.getJumlah());
						origin.get().setHargaDiscount(dto.getHargaDiskon());
						origin.get().setJasa(dto.getHargaJasa());
						origin.get().setIsPaket(dto.getIsPaket());
						if (dto.getIsPaket())
							origin.get().setVoucherPaket(voucher);
						{
							List<PelayananPasienDetail> detailOrigin = pelayananPasienDetailDao
									.findByPelayananPasien(origin.get().getNoRec());
							splitDetailPelayanan = copyPelayananDetailSplitQty(detailOrigin);
							List<PelayananPasienDetail> originDetail = splitDetailPelayanan.stream()
									.filter(d -> d.getNoRec() != null).collect(Collectors.toList());
							detailPelayanan.addAll(originDetail);
						}
						{
							List<PelayananPasienPetugas> petugasOrigin = pelayananPasienPetugasDao
									.findByPelayananPasien(origin.get().getNoRec());
							splitPetugasPelayanan = copyPelayananPasienPetugasSplitQty(petugasOrigin);
							List<PelayananPasienPetugas> originPetugas = splitPetugasPelayanan.stream()
									.filter(pt -> pt.getNoRec() != null).collect(Collectors.toList());
							petugasPelayanan.addAll(originPetugas);
							{
								List<String> norecs = petugasOrigin.stream().map(BaseTransaction::getNoRec)
										.collect(Collectors.toList());
								List<MapPelayananPasienPetugasToPegawai> mapPetugasPegawaiOrigin = mapPelayananPasienPetugasToPegawaiDao
										.findByPelayananPasienPetugas(norecs);
								splitMapPetugasPegawai = copyMapPetugasPegawaiSplitQty(mapPetugasPegawaiOrigin);
								List<MapPelayananPasienPetugasToPegawai> originMapPetugasPegawai = splitMapPetugasPegawai
										.stream().filter(mpp -> mpp.getNoRec() != null).collect(Collectors.toList());
								mapPetugasPegawai.addAll(originMapPetugasPegawai);
							}
						}
						{
							List<PelayananPasienTidakTerklaim> pelayananTidakTerklaimOrigin = pelayananPasienTidakTerklaimDao
									.findByPelayananPasien(origin.get().getNoRec());
							splitPelayananTidakTerklaim = copyPelayananTidakTerklaimSplitQty(
									pelayananTidakTerklaimOrigin);
							List<PelayananPasienTidakTerklaim> originPelayananTidakTerklaim = splitPelayananTidakTerklaim
									.stream().filter(ptt -> ptt.getNoRec() != null).collect(Collectors.toList());
							pelayananPasienTidakTerklaim.addAll(originPelayananTidakTerklaim);
						}
						{
							List<RacikanDetail> racikanDetailOrigin = racikanDetailDao
									.findByPelayananPasien(origin.get().getNoRec());
							splitRacikanDetail = copyDetailRacikanSplitQty(racikanDetailOrigin);
							List<RacikanDetail> originRacikanDetail = splitRacikanDetail.stream()
									.filter(rd -> rd.getNoRec() != null).collect(Collectors.toList());
							racikanDetail.addAll(originRacikanDetail);
						}
						pelayanan.add(origin.get());
					}
					Optional<PelayananPasien> duplicate = splitPelayanan.stream().filter(cp -> cp.getNoRec() == null)
							.findFirst();
					if (duplicate.isPresent() && origin.isPresent()) {
						duplicate.get().setJumlah(duplicate.get().getJumlah() - origin.get().getJumlah());
						duplicate.get().setHargaDiscount(0.0);
						duplicate.get().setIsPaket(false);
						{
							List<PelayananPasienDetail> duplicateDetail = splitDetailPelayanan.stream()
									.filter(d -> d.getNoRec() == null).collect(Collectors.toList());
							duplicateDetail.forEach(d -> d.setPelayananPasien(duplicate.get()));
							detailPelayanan.addAll(duplicateDetail);
						}
						{
							List<PelayananPasienPetugas> duplicatePetugas = splitPetugasPelayanan.stream()
									.filter(pt -> pt.getNoRec() == null).collect(Collectors.toList());
							List<MapPelayananPasienPetugasToPegawai> finalSplitMapPetugasPegawai = splitMapPetugasPegawai;
							duplicatePetugas.forEach(dp -> {
								dp.setPelayananPasien(duplicate.get());
								{
									List<MapPelayananPasienPetugasToPegawai> duplicateMapPetugasPegawai = finalSplitMapPetugasPegawai
											.stream().filter(mpp -> mpp.getNoRec() == null)
											.collect(Collectors.toList());
									duplicateMapPetugasPegawai.forEach(dm -> dm.setPelayananPasienPetugas(dp));
									mapPetugasPegawai.addAll(duplicateMapPetugasPegawai);
								}
							});
							petugasPelayanan.addAll(duplicatePetugas);
						}
						{
							List<PelayananPasienTidakTerklaim> duplicatePelayananTidakTerklaim = splitPelayananTidakTerklaim
									.stream().filter(pt -> pt.getNoRec() == null).collect(Collectors.toList());
							duplicatePelayananTidakTerklaim.forEach(dp -> dp.setPelayananPasien(duplicate.get()));
							pelayananPasienTidakTerklaim.addAll(duplicatePelayananTidakTerklaim);
						}
						{
							List<RacikanDetail> duplicateRacikanDetail = splitRacikanDetail.stream()
									.filter(rd -> rd.getNoRec() == null).collect(Collectors.toList());
							duplicateRacikanDetail.forEach(drd -> drd.setPelayananPasien(duplicate.get()));
							racikanDetail.addAll(duplicateRacikanDetail);
						}
						pelayanan.add(duplicate.get());
					}
				});
			});
			if (CommonUtil.isNotNullOrEmpty(pelayanan)) {
				pelayananPasienDao.save(pelayanan);
				pelayananPasienDetailDao.save(detailPelayanan);
				pelayananPasienPetugasDao.save(petugasPelayanan);
				pelayananPasienTidakTerklaimDao.save(pelayananPasienTidakTerklaim);
				racikanDetailDao.save(racikanDetail);
				mapPelayananPasienPetugasToPegawaiDao.save(mapPetugasPegawai);
			}
		}
	}

	@Override
	public boolean isValidVoucher(String kodeVoucher, String noRegistrasi) {
		VoucherPaket voucher = getVoucher(kodeVoucher, noRegistrasi, false);
		if (voucher.getIsSelesai())
			throw new ServiceVOException("Kode voucher sudah selesai digunakan");
		List<PasienDaftar> listPendaftaranLain = pasienDaftarDao
				.findByPasienAndVoucherAndNoRegistrasiNot(voucher.getPasienId(), kodeVoucher, noRegistrasi);
		listPendaftaranLain.forEach(p -> {
			if (p.getIsBatalPaket() == null)
				p.setIsBatalPaket(false);
		});
		Optional<PasienDaftar> first = listPendaftaranLain.stream().filter(PasienDaftar::getIsBatalPaket).findFirst();
		if (CommonUtil.isNotNullOrEmpty(first) && first.isPresent())
			throw new ServiceVOException("Paket dengan menggunakan kode voucher ini sudah dibatalkan");
		return !CommonUtil.isNullOrEmpty(voucher);
	}

	@Override
	public void batalPaketProduk(HttpServletRequest request, BatalPaketProdukDto dto) {
		VoucherPaket voucher = getVoucher(dto.getKodeVoucher(), dto.getNoRegistrasi(), true);
		{
			voucher.setIsBatal(true);
			LoginUser loginUser = loginUserService.getLoginUser();
			Pegawai pegawai = new Pegawai();
			pegawai.setId(loginUser.getPegawai().getId());
			voucher.setPegawai(pegawai);
			voucher.setModifiedDate(new Date());
			voucherPaketDao.save(voucher);
		}
		List<PasienDaftar> listPendaftaran = pasienDaftarDao.findByPasienIdAndVoucherPaketId(voucher.getPasienId(),
				voucher.getNoRec());
		{
			listPendaftaran.forEach(p -> p.setIsBatalPaket(true));
			pasienDaftarDao.save(listPendaftaran);
		}
		List<String> idDaftarList = listPendaftaran.stream().map(PasienDaftar::getNoRec).collect(Collectors.toList());
		if (CommonUtil.isNotNullOrEmpty(idDaftarList)) {
			List<PelayananPasien> listPelayanan = pelayananPasienDao
					.findByPasienDaftarPasienDaftarNoRecIn(idDaftarList);
			List<MapProdukPaketToProduk> produkMapping = mapProdukPaketToProdukDao.findByPaketId(voucher.getPaketId());
			List<Integer> idProdukMapping = produkMapping.stream()
					.map(mproduk -> mproduk.getMapProdukPaket().getProdukEntriId()).collect(Collectors.toList());
			listPelayanan.forEach(p -> p.setIsPaket(false));
			listPelayanan.stream().filter(p -> idProdukMapping.contains(p.getProdukId()))
					.forEach(p -> p.setHargaDiscount(0.0));
			listPelayanan.stream().filter(p -> voucher.getPaketId().equals(p.getProdukId()))
					.forEach(p -> p.setHargaDiscount(p.getHargaJual()));
			pelayananPasienDao.save(listPelayanan);
		}
	}

	private VoucherPaket getVoucher(String kodeVoucher, String noRegistrasi, Boolean basicValidation) {
		if (noRegistrasi.isEmpty())
			throw new ServiceVOException("Nomor registrasi harus diisi");
		VoucherPaket voucher = getVoucher(kodeVoucher, basicValidation);
		Optional<ProdukPaket> produkPaket = produkPaketDao.findById(voucher.getPaketId());
		PasienDaftar pendaftaran = pasienDaftarDao.findByNoRegistrasi(noRegistrasi);
		String ibuNoCm = pendaftaran.getPasien().getReportDisplay();
		Integer ibuId = null;
		if (CommonUtil.isNotNullOrEmpty(ibuNoCm))
			ibuId = pasienDao.findIdByNoCm(ibuNoCm);
		if (CommonUtil.isNotNullOrEmpty(produkPaket) && produkPaket.isPresent()
				&& PERSALINAN.equals(produkPaket.get().getTipePaket())) {
			if ((CommonUtil.isNotNullOrEmpty(ibuId) && !voucher.getPasienId().equals(ibuId))
					|| (CommonUtil.isNullOrEmpty(ibuId) && CommonUtil.isNotNullOrEmpty(pendaftaran)
							&& !pendaftaran.getPasien().getId().equals(voucher.getPasienId())))
				throw new ServiceVOException("Kode voucher tidak sesuai dengan pasien yang diperuntukkan");
		}
		return voucher;
	}

	private VoucherPaket getVoucher(String kodeVoucher, Boolean basicValidation) {
		if (kodeVoucher.isEmpty())
			throw new ServiceVOException("Kode voucher harus diisi");
		VoucherPaket voucher = voucherPaketDao.findByKode(kodeVoucher);
		if (CommonUtil.isNullOrEmpty(voucher))
			throw new ServiceVOException("Kode voucher tidak ditemukan");
		if (basicValidation)
			return voucher;
		{
			// Advance Validation
			if (voucher.getTmt().after(new Date()))
				throw new ServiceVOException("Kode voucher baru dapat dipakai mulai "
						+ new SimpleDateFormat("dd MMMM yyyy HH:mm:ss", new Locale("in", "ID"))
								.format(voucher.getTmt()));
			if (voucher.getTglKedaluwarsa().before(new Date()))
				throw new ServiceVOException("Kode voucher sudah kedaluwarsa pada "
						+ new SimpleDateFormat("dd MMMM yyyy HH:mm:ss", new Locale("in", "ID"))
								.format(voucher.getTglKedaluwarsa()));
			return voucher;
		}
	}

	private List<PelayananPasien> copyPelayananSplitQty(PelayananPasien originPelayanan) {
		List<PelayananPasien> result = new ArrayList<>();
		PelayananPasien duplicatePelayanan = new PelayananPasien();
		try {
			duplicatePelayanan = pelayananPasienConverter.clone(originPelayanan, duplicatePelayanan, new String[] {
					"serialVersionUID", "noRec", "pelayananPasienPetugasSet", "racikan", "pelayananPasienDetailSet" });
		} catch (IllegalAccessException e) {
			throw new ServiceVOException(e.getMessage());
		}
		{
			AntrianPasienDiPeriksa antrian = originPelayanan.getPasienDaftar();
			if (CommonUtil.isNotNullOrEmpty(antrian))
				duplicatePelayanan.setPasienDaftar(antrian);
		}
		{
			JenisKemasan jenisKemasan = originPelayanan.getJenisKemasan();
			if (CommonUtil.isNotNullOrEmpty(jenisKemasan))
				duplicatePelayanan.setJenisKemasan(jenisKemasan);
		}
		{
			Kelas kelas = originPelayanan.getKelas();
			if (CommonUtil.isNotNullOrEmpty(kelas))
				duplicatePelayanan.setKelas(kelas);
		}
		{
			KelompokTransaksi kelompokTransaksi = originPelayanan.getKelompokTransaksi();
			if (CommonUtil.isNotNullOrEmpty(kelompokTransaksi))
				duplicatePelayanan.setKelompokTransaksi(kelompokTransaksi);
		}
		{
			Produk produk = originPelayanan.getProduk();
			if (CommonUtil.isNotNullOrEmpty(produk))
				duplicatePelayanan.setProduk(produk);
		}
		{
			Generik generik = originPelayanan.getGenerik();
			if (CommonUtil.isNotNullOrEmpty(generik))
				duplicatePelayanan.setGenerik(generik);
		}
		{
			JenisObat jenisObat = originPelayanan.getJenisObat();
			if (CommonUtil.isNotNullOrEmpty(jenisObat))
				duplicatePelayanan.setJenisObat(jenisObat);
		}
		{
			RouteFarmasi route = originPelayanan.getRoute();
			if (CommonUtil.isNotNullOrEmpty(route))
				duplicatePelayanan.setRoute(route);
		}
		{
			SatuanStandar satuanView = originPelayanan.getSatuanView();
			if (CommonUtil.isNotNullOrEmpty(satuanView))
				duplicatePelayanan.setSatuanView(satuanView);
		}
		{
			Stigma keteranganPakai = originPelayanan.getKeteranganPakai();
			if (CommonUtil.isNotNullOrEmpty(keteranganPakai))
				duplicatePelayanan.setKeteranganPakai(keteranganPakai);
		}
		{
			StrukOrder strukOrder = originPelayanan.getStrukOrder();
			if (CommonUtil.isNotNullOrEmpty(strukOrder))
				duplicatePelayanan.setStrukOrder(strukOrder);
		}
		{
			StrukPelayanan strukPelayanan = originPelayanan.getStrukPelayanan();
			if (CommonUtil.isNotNullOrEmpty(strukPelayanan))
				duplicatePelayanan.setStrukPelayanan(strukPelayanan);
		}
		{
			StrukPelayanan strukTerima = originPelayanan.getStrukTerima();
			if (CommonUtil.isNotNullOrEmpty(strukTerima))
				duplicatePelayanan.setStrukTerima(strukTerima);
		}
		{
			StrukPelayananDNoBatch noBatch = originPelayanan.getNoBatch();
			if (CommonUtil.isNotNullOrEmpty(noBatch))
				duplicatePelayanan.setNoBatch(noBatch);
		}
		{
			StrukResep strukResep = originPelayanan.getStrukResep();
			if (CommonUtil.isNotNullOrEmpty(strukResep))
				duplicatePelayanan.setStrukResep(strukResep);
		}
		{
			VoucherPaket voucherPaket = originPelayanan.getVoucherPaket();
			if (CommonUtil.isNotNullOrEmpty(voucherPaket))
				duplicatePelayanan.setVoucherPaket(voucherPaket);
		}
		result.add(duplicatePelayanan);
		result.add(originPelayanan);
		return result;
	}

	private List<PelayananPasienDetail> copyPelayananDetailSplitQty(List<PelayananPasienDetail> originDetail) {
		List<PelayananPasienDetail> duplicateDetail = new ArrayList<>();
		originDetail.forEach(origin -> {
			PelayananPasienDetail duplicate = new PelayananPasienDetail();
			try {
				duplicate = pelayananPasienDetailConverter.clone(origin, duplicate,
						new String[] { "serialVersionUID", "noRec" });
			} catch (IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
			{
				AntrianPasienDiPeriksa pasien = origin.getPasienDaftar();
				if (CommonUtil.isNotNullOrEmpty(pasien))
					duplicate.setPasienDaftar(pasien);
			}
			{
				KomponenHarga komponenHarga = origin.getKomponenHarga();
				if (CommonUtil.isNotNullOrEmpty(komponenHarga))
					duplicate.setKomponenHarga(komponenHarga);
			}
			{
				Produk produk = origin.getProduk();
				if (CommonUtil.isNotNullOrEmpty(produk))
					duplicate.setProduk(produk);
			}
			{
				Generik generik = origin.getGenerik();
				if (CommonUtil.isNotNullOrEmpty(generik))
					duplicate.setGenerik(generik);
			}
			{
				JenisObat jenisObat = origin.getJenisObat();
				if (CommonUtil.isNotNullOrEmpty(jenisObat))
					duplicate.setJenisObat(jenisObat);
			}
			{
				RouteFarmasi route = origin.getRoute();
				if (CommonUtil.isNotNullOrEmpty(route))
					duplicate.setRoute(route);
			}
			{
				Stigma keteranganPakai = origin.getKeteranganPakai();
				if (CommonUtil.isNotNullOrEmpty(keteranganPakai))
					duplicate.setKeteranganPakai(keteranganPakai);
			}
			{
				StrukOrder strukOrder = origin.getStrukOrder();
				if (CommonUtil.isNotNullOrEmpty(strukOrder))
					duplicate.setStrukOrder(strukOrder);
			}
			duplicateDetail.add(duplicate);
			duplicateDetail.add(origin);
		});
		return duplicateDetail;
	}

	private List<PelayananPasienPetugas> copyPelayananPasienPetugasSplitQty(
			List<PelayananPasienPetugas> originPetugas) {
		List<PelayananPasienPetugas> duplicatePetugas = new ArrayList<>();
		originPetugas.forEach(origin -> {
			PelayananPasienPetugas duplicate = new PelayananPasienPetugas();
			try {
				duplicate = pelayananPasienPetugasConverter.clone(origin, duplicate,
						new String[] { "serialVersionUID", "noRec" });
			} catch (IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
			{
				AntrianPasienDiPeriksa nomasuk = origin.getNomasuk();
				if (CommonUtil.isNotNullOrEmpty(nomasuk))
					duplicate.setNomasuk(nomasuk);
			}
			{
				AsalProduk kdasalproduk = origin.getKdasalproduk();
				if (CommonUtil.isNotNullOrEmpty(kdasalproduk))
					duplicate.setKdasalproduk(kdasalproduk);
			}
			{
				JenisPetugasPelaksana kdjenispetugaspe = origin.getKdjenispetugaspe();
				if (CommonUtil.isNotNullOrEmpty(kdjenispetugaspe))
					duplicate.setKdjenispetugaspe(kdjenispetugaspe);
			}
			{
				Pegawai kdpegawai = origin.getKdpegawai();
				if (CommonUtil.isNotNullOrEmpty(kdpegawai))
					duplicate.setKdpegawai(kdpegawai);
			}
			{
				Produk kdproduk = origin.getKdproduk();
				if (CommonUtil.isNotNullOrEmpty(kdproduk))
					duplicate.setKdproduk(kdproduk);
			}
			{
				Ruangan kdruangan = origin.getKdruangan();
				if (CommonUtil.isNotNullOrEmpty(kdruangan))
					duplicate.setKdruangan(kdruangan);
			}
			duplicatePetugas.add(duplicate);
			duplicatePetugas.add(origin);
		});
		return duplicatePetugas;
	}

	private List<PelayananPasienTidakTerklaim> copyPelayananTidakTerklaimSplitQty(
			List<PelayananPasienTidakTerklaim> originPelayananTidakTerklaim) {
		List<PelayananPasienTidakTerklaim> duplicatePelayananTidakTerklaim = new ArrayList<>();
		originPelayananTidakTerklaim.forEach(origin -> {
			PelayananPasienTidakTerklaim duplicate = new PelayananPasienTidakTerklaim();
			try {
				duplicate = pelayananPasienTidakTerklaimConverter.clone(origin, duplicate,
						new String[] { "serialVersionUID", "noRec" });
			} catch (IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
			{
				AntrianPasienDiPeriksa antrian = origin.getPasienDaftar();
				if (CommonUtil.isNotNullOrEmpty(antrian))
					duplicate.setPasienDaftar(antrian);
			}
			{
				JenisKemasan jenisKemasan = origin.getJenisKemasan();
				if (CommonUtil.isNotNullOrEmpty(jenisKemasan))
					duplicate.setJenisKemasan(jenisKemasan);
			}
			{
				Kelas kelas = origin.getKelas();
				if (CommonUtil.isNotNullOrEmpty(kelas))
					duplicate.setKelas(kelas);
			}
			{
				KelompokTransaksi kelompokTransaksi = origin.getKelompokTransaksi();
				if (CommonUtil.isNotNullOrEmpty(kelompokTransaksi))
					duplicate.setKelompokTransaksi(kelompokTransaksi);
			}
			{
				Produk produk = origin.getProduk();
				if (CommonUtil.isNotNullOrEmpty(produk))
					duplicate.setProduk(produk);
			}
			{
				Generik generik = origin.getGenerik();
				if (CommonUtil.isNotNullOrEmpty(generik))
					duplicate.setGenerik(generik);
			}
			{
				JenisObat jenisObat = origin.getJenisObat();
				if (CommonUtil.isNotNullOrEmpty(jenisObat))
					duplicate.setJenisObat(jenisObat);
			}
			{
				RouteFarmasi route = origin.getRoute();
				if (CommonUtil.isNotNullOrEmpty(route))
					duplicate.setRoute(route);
			}
			{
				SatuanStandar satuanView = origin.getSatuanView();
				if (CommonUtil.isNotNullOrEmpty(satuanView))
					duplicate.setSatuanView(satuanView);
			}
			{
				Stigma keteranganPakai = origin.getKeteranganPakai();
				if (CommonUtil.isNotNullOrEmpty(keteranganPakai))
					duplicate.setKeteranganPakai(keteranganPakai);
			}
			{
				StrukOrder strukOrder = origin.getStrukOrder();
				if (CommonUtil.isNotNullOrEmpty(strukOrder))
					duplicate.setStrukOrder(strukOrder);
			}
			{
				StrukPelayanan strukPelayanan = origin.getStrukPelayanan();
				if (CommonUtil.isNotNullOrEmpty(strukPelayanan))
					duplicate.setStrukPelayanan(strukPelayanan);
			}
			{
				StrukPelayanan strukTerima = origin.getStrukTerima();
				if (CommonUtil.isNotNullOrEmpty(strukTerima))
					duplicate.setStrukTerima(strukTerima);
			}
			{
				StrukPelayananDNoBatch noBatch = origin.getNoBatch();
				if (CommonUtil.isNotNullOrEmpty(noBatch))
					duplicate.setNoBatch(noBatch);
			}
			{
				StrukResep strukResep = origin.getStrukResep();
				if (CommonUtil.isNotNullOrEmpty(strukResep))
					duplicate.setStrukResep(strukResep);
			}
			duplicatePelayananTidakTerklaim.add(duplicate);
			duplicatePelayananTidakTerklaim.add(origin);
		});
		return duplicatePelayananTidakTerklaim;
	}

	List<RacikanDetail> copyDetailRacikanSplitQty(List<RacikanDetail> originRacikanDetail) {
		List<RacikanDetail> duplicateRacikanDetail = new ArrayList<>();
		originRacikanDetail.forEach(origin -> {
			RacikanDetail duplicate = new RacikanDetail();
			try {
				duplicate = racikanDetailConverter.clone(origin, duplicate,
						new String[] { "serialVersionUID", "noRec" });
			} catch (IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
			{
				Produk produk = origin.getProduk();
				if (CommonUtil.isNotNullOrEmpty(produk))
					duplicate.setProduk(produk);
			}
			{
				Generik generik = origin.getGenerik();
				if (CommonUtil.isNotNullOrEmpty(generik))
					duplicate.setGenerik(generik);
			}
			{
				StrukRacikan strukRacikan = origin.getStrukRacikan();
				if (CommonUtil.isNotNullOrEmpty(strukRacikan))
					duplicate.setStrukRacikan(strukRacikan);
			}
			duplicateRacikanDetail.add(duplicate);
			duplicateRacikanDetail.add(origin);
		});
		return duplicateRacikanDetail;
	}

	List<MapPelayananPasienPetugasToPegawai> copyMapPetugasPegawaiSplitQty(
			List<MapPelayananPasienPetugasToPegawai> originMapPetugasPegawai) {
		List<MapPelayananPasienPetugasToPegawai> duplicateMapPetugasPegawai = new ArrayList<>();
		originMapPetugasPegawai.forEach(origin -> {
			MapPelayananPasienPetugasToPegawai duplicate = new MapPelayananPasienPetugasToPegawai();
			try {
				duplicate = mapPelayananPasienPetugasToPegawaiConverter.clone(origin, duplicate,
						new String[] { "serialVersionUID", "noRec" });
			} catch (IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
			{
				Pegawai pegawai = origin.getPegawai();
				if (CommonUtil.isNotNullOrEmpty(pegawai))
					duplicate.setPegawai(pegawai);
			}
			duplicateMapPetugasPegawai.add(duplicate);
			duplicateMapPetugasPegawai.add(origin);
		});
		return duplicateMapPetugasPegawai;
	}

	private RemunHargaJasa hargaJasa(double persenRemunerasi, double hargaJual, Map<String, Object> d,
			boolean isFrontNote) {
		Locale indonesia = new Locale("in", "ID");
		NumberFormat nf = NumberFormat.getCurrencyInstance(indonesia);
		RemunHargaJasa.RemunHargaJasaBuilder builder = RemunHargaJasa.builder();
		if (KLINIK_KARYAWAN.equals(d.get("idRuangan")) || KLINIK_GIGI_KARYAWAN.equals(d.get("idRuangan"))) {
			builder.nilai(0.0);
			if (isFrontNote) {
				builder.keterangan("Dari diskon klinik karyawan/klinik gigi karyawan");
			} else {
				builder.keterangan(" dan dari diskon klinik karyawan/klinik gigi karyawan");
			}
			return builder.build();
		}
		double totalDiskonD = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalDiskonD")))
			totalDiskonD = Double.parseDouble(d.get("totalDiskonD").toString());
		double totalPersenDiskonSayatanD = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonSayatanD")))
			totalPersenDiskonSayatanD = Double.parseDouble(d.get("totalPersenDiskonSayatanD").toString());
		double totalHargaD = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalHargaD")))
			totalHargaD = Double.parseDouble(d.get("totalHargaD").toString());
		double totalDiskonAs = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalDiskonAs")))
			totalDiskonAs = Double.parseDouble(d.get("totalDiskonAs").toString());
		double totalPersenDiskonSayatanAs = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonSayatanAs")))
			totalPersenDiskonSayatanAs = Double.parseDouble(d.get("totalPersenDiskonSayatanAs").toString());
		double totalHargaAs = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalHargaAs")))
			totalHargaAs = Double.parseDouble(d.get("totalHargaAs").toString());
		double totalDiskonAn = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalDiskonAn")))
			totalDiskonAn = Double.parseDouble(d.get("totalDiskonAn").toString());
		double totalPersenDiskonSayatanAn = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonSayatanAn")))
			totalPersenDiskonSayatanAn = Double.parseDouble(d.get("totalPersenDiskonSayatanAn").toString());
		double totalHargaAn = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalHargaAn")))
			totalHargaAn = Double.parseDouble(d.get("totalHargaAn").toString());
		double totalDiskon = 0.0;
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonD"))
				&& Double.parseDouble(d.get("totalPersenDiskonD").toString()) > 0)
			totalDiskon += totalDiskonD - (totalPersenDiskonSayatanD * totalHargaD / 100);
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonAs"))
				&& Double.parseDouble(d.get("totalPersenDiskonAs").toString()) > 0)
			totalDiskon += totalDiskonAs - (totalPersenDiskonSayatanAs * totalHargaAs / 100);
		if (CommonUtil.isNotNullOrEmpty(d.get("totalPersenDiskonAn"))
				&& Double.parseDouble(d.get("totalPersenDiskonAn").toString()) > 0)
			totalDiskon += totalDiskonAn - (totalPersenDiskonSayatanAn * totalHargaAn / 100);
		double hargaJualSetelahDiskon = hargaJual - totalDiskon;
		double hargaJasa = persenRemunerasi * hargaJualSetelahDiskon;
		if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) >= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanD"))
						&& Double.parseDouble(d.get("persenDiskonSayatanD").toString()) >= 0
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAs"))
						&& Double.parseDouble(d.get("persenDiskonSayatanAs").toString()) >= 0
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAn"))
						&& Double.parseDouble(d.get("persenDiskonSayatanAn").toString()) >= 0))) {
			double persenRemunOperator = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0);
			double persenRemunAsisten = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0);
			double persenRemunAnestesi = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0);
			double hargaJasaOperator = persenRemunOperator * hargaJasa / 100;
			double hargaJasaAsisten = persenRemunAsisten * hargaJasa / 100;
			double hargaJasaAnestesi = persenRemunAnestesi * hargaJasa / 100;
			double hargaJasaRemun = hargaJasaOperator + hargaJasaAsisten + hargaJasaAnestesi;
			builder.nilai(hargaJasaRemun);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAsisten + "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen operator, asisten, dan anestesi berturut-turut "
						+ d.get("persenDiskonD").toString() + "%, " + d.get("persenDiskonAs").toString() + "%, dan "
						+ d.get("persenDiskonAn").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAsisten + "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen operator, asisten, dan anestesi berturut-turut "
						+ d.get("persenDiskonD").toString() + "%, " + d.get("persenDiskonAs").toString() + "%, dan "
						+ d.get("persenDiskonAn").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanD")) && Double
								.parseDouble(d.get("persenDiskonSayatanD").toString()) >= 0
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAs"))
						&& Double.parseDouble(d.get("persenDiskonSayatanAs").toString()) >= 0))) {
			double persenRemunOperator = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0);
			double persenRemunAsisten = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0);
			double hargaJasaOperator = persenRemunOperator * hargaJasa / 100;
			double hargaJasaAsisten = persenRemunAsisten * hargaJasa / 100;
			double hargaJasaRemun = hargaJasaOperator + hargaJasaAsisten;
			builder.nilai(hargaJasaRemun);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAsisten
						+ "% karena diskon komponen operator dan asisten berturut-turut "
						+ d.get("persenDiskonD").toString() + "% dan " + d.get("persenDiskonAs").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAsisten
						+ "% karena diskon komponen operator dan asisten berturut-turut "
						+ d.get("persenDiskonD").toString() + "% dan " + d.get("persenDiskonAs").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanD")) && Double
								.parseDouble(d.get("persenDiskonSayatanD").toString()) >= 0
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAn"))
						&& Double.parseDouble(d.get("persenDiskonSayatanAn").toString()) >= 0))) {
			double persenRemunOperator = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0);
			double persenRemunAnestesi = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0);
			double hargaJasaOperator = persenRemunOperator * hargaJasa / 100;
			double hargaJasaAnestesi = persenRemunAnestesi * hargaJasa / 100;
			double hargaJasaRemun = hargaJasaOperator + hargaJasaAnestesi;
			builder.nilai(hargaJasaRemun);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen operator dan anestesi berturut-turut "
						+ d.get("persenDiskonD").toString() + "% dan " + d.get("persenDiskonAn").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen operator dan anestesi berturut-turut "
						+ d.get("persenDiskonD").toString() + "% dan " + d.get("persenDiskonAn").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAs")) && Double
								.parseDouble(d.get("persenDiskonSayatanAs").toString()) >= 0
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAn"))
						&& Double.parseDouble(d.get("persenDiskonSayatanAn").toString()) >= 0))) {
			double persenRemunAsisten = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0);
			double persenRemunAnestesi = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0);
			double hargaJasaAsisten = persenRemunAsisten * hargaJasa / 100;
			double hargaJasaAnestesi = persenRemunAnestesi * hargaJasa / 100;
			double hargaJasaRemun = hargaJasaAsisten + hargaJasaAnestesi;
			builder.nilai(hargaJasaRemun);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAsisten
						+ "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen asisten dan anestesi berturut-turut "
						+ d.get("persenDiskonAs").toString() + "% dan " + d.get("persenDiskonAn").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAsisten
						+ "% ditambah pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen asisten dan anestesi berturut-turut "
						+ d.get("persenDiskonAs").toString() + "% dan " + d.get("persenDiskonAn").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) <= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanD")) && Double
								.parseDouble(d.get("persenDiskonSayatanD").toString()) >= 0))) {
			double persenRemunOperator = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
					? Double.parseDouble(d.get("persenDiskonD").toString()) : 0.0);
			builder.nilai(persenRemunOperator * hargaJasa / 100);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% karena diskon komponen operator " + d.get("persenDiskonD").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunOperator
						+ "% karena diskon komponen operator " + d.get("persenDiskonD").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) <= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAs")) && Double
								.parseDouble(d.get("persenDiskonSayatanAs").toString()) >= 0))) {
			double persenRemunAsisten = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
					? Double.parseDouble(d.get("persenDiskonAs").toString()) : 0.0);
			builder.nilai(persenRemunAsisten * hargaJasa / 100);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAsisten
						+ "% karena diskon komponen asisten " + d.get("persenDiskonAs").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAsisten
						+ "% karena diskon komponen asisten " + d.get("persenDiskonAs").toString() + "%");
			}
		} else if (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
				&& Double.parseDouble(d.get("persenDiskonAn").toString()) > 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAn"))
				&& Double.parseDouble(d.get("diskonAn").toString()) >= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonD"))
				&& Double.parseDouble(d.get("persenDiskonD").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonD"))
				&& Double.parseDouble(d.get("diskonD").toString()) <= 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAs"))
				&& Double.parseDouble(d.get("persenDiskonAs").toString()) == 0.0
				&& CommonUtil.isNotNullOrEmpty(d.get("diskonAs"))
				&& Double.parseDouble(d.get("diskonAs").toString()) <= 0.0
				&& (CommonUtil.isNullOrEmpty(d.get("idSayatan")) || (CommonUtil.isNotNullOrEmpty(d.get("idSayatan"))
						&& CommonUtil.isNotNullOrEmpty(d.get("persenDiskonSayatanAn")) && Double
								.parseDouble(d.get("persenDiskonSayatanAn").toString()) >= 0))) {
			double persenRemunAnestesi = 100.00 - (CommonUtil.isNotNullOrEmpty(d.get("persenDiskonAn"))
					? Double.parseDouble(d.get("persenDiskonAn").toString()) : 0.0);
			builder.nilai(persenRemunAnestesi * hargaJasa / 100);
			if (isFrontNote) {
				builder.keterangan("Dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen anestesi " + d.get("persenDiskonAn").toString() + "%");
			} else {
				builder.keterangan(" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon)
						+ " terlebih dahulu dan diakhiri dengan pengalian " + persenRemunAnestesi
						+ "% karena diskon komponen anestesi " + d.get("persenDiskonAn").toString() + "%");
			}
		} else {
			builder.nilai(persenRemunerasi * hargaJualSetelahDiskon);
			if (totalDiskon > 0.0) {
				builder.keterangan(
						" dan dari pengurangan tarif dengan diskon " + nf.format(totalDiskon) + " terlebih dahulu");
			} else {
				builder.keterangan("");
			}

		}
		return builder.build();
	}
}