package org.sprimaudi.zkcontroller.lab;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.sprimaudi.zkspring.dto.Validation;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: lenovospy
* Date: 9/19/13
* Time: 11:40 PM
* To change this template use File | Settings | File Templates.
*/
public class TvomController extends SelectorComposer<Window> {
public static final String zulpath = "zuls/tvom.zul";
public static final String TVOM_PERIOD = "TVOM_PERIOD";
public static final String TVOM_INTEREST_FACTOR = "TVOM_INTEREST_FACTOR";
public static final String TVOM_FUTURE_VALUE = "TVOM_FUTURE_VALUE";
public static final String TVOM_EFFECTIVE = "TVOM_EFFECTIVE";
public static final String TVOM_DAY = "TVOM_DAY";
public static final String TVOM_INTEREST = "TVOM_INTEREST";
@Wire
Intbox intDiskonDue, intNormalDue, intDiskon;
@Wire
Label lblHarga, lblCerita, propHarga, propBayar,
propSukuBunga, propNilaiBunga, propDiskon,
propNilaiDiskon, propTenggat, propPeriodeBunga;
@Wire
Decimalbox decHarga, decBayar;
@Wire
Doublebox douSukuBunga;
@Wire
Button btnKalkulasi;
@Wire
Datebox datBayar;
@Override
public void doAfterCompose(Window comp) throws Exception {
super.doAfterCompose(comp); //To change body of overridden methods use File | Settings | File Templates.
lblCerita.setValue(narasi(decHarga.getValue(), intDiskon.getValue(), intDiskonDue.getValue(),
intNormalDue.getValue(), datBayar.getValue()));
}
private Validation validate() {
Validation val = new Validation();
val.setValid(true);
if (decHarga.getValue() == null) {
val.add("Field harga tidak boleh kosong");
}
if (intDiskon.getValue() == null) {
val.add("Field diskon tidak boleh kosong");
}
if (intDiskonDue.getValue() == null) {
val.add("Field tenggat diskon tidak boleh kosong");
}
if (intNormalDue.getValue() == null) {
val.add("Field tenggat waktu normal pembayaran tidak boleh kosong");
}
if (douSukuBunga.getValue() == null) {
val.add("Field suku bunga tidak boleh kosong");
}
if (datBayar.getValue() == null) {
val.add("Field tanggal pembayaran tidak boleh kosong");
}
return val;
}
DecimalFormat df = new DecimalFormat("#,###.00");
private void kalkulasi() {
Validation val = validate();
if (!val.isValid()) {
alert("Isian form simulasi TVOM tidak valid: " + val.serializedValidation("; "));
return;
}
BigDecimal harga = decHarga.getValue();
int diskon = intDiskon.getValue();
int diskonDue = intDiskonDue.getValue();
int normalDue = intNormalDue.getValue();
double rate = douSukuBunga.getValue() / 100d;
Date tanggalBayar = datBayar.getValue();
int jangka = computeSelangWaktuPembayaran(tanggalBayar);
propHarga.setValue(df.format(harga));
propPeriodeBunga.setValue(null);
if (jangka > normalDue) {
Map<String, Object> tvom = computeTvom(rate, jangka - normalDue, harga);
decBayar.setValue((BigDecimal) tvom.get(TVOM_FUTURE_VALUE));
propTenggat.setValue("" + (jangka - normalDue) + " hari setelah tenggat");
propSukuBunga.setValue("" + douSukuBunga.getValue() + " %");
propPeriodeBunga.setValue("" + tvom.get(TVOM_PERIOD));
propNilaiBunga.setValue(df.format(tvom.get(TVOM_INTEREST)));
propBayar.setValue("" + df.format(tvom.get(TVOM_FUTURE_VALUE)));
propDiskon.setValue(null);
propNilaiDiskon.setValue(null);
} else {
propSukuBunga.setValue(null);
propNilaiBunga.setValue(null);
if (jangka < diskonDue) {
//PERHITUNGAN DISKON
propTenggat.setValue("" + (jangka) + " hari masa diskon");
propDiskon.setValue("" + diskon + " %");
double bayar = (1d - (diskon / 100d)) * harga.doubleValue();
propNilaiDiskon.setValue(df.format(harga.subtract(new BigDecimal(bayar))));
decBayar.setValue(new BigDecimal(bayar));
propBayar.setValue(df.format(new BigDecimal(bayar)));
} else {
propTenggat.setValue("" + (normalDue - jangka) + " hari sebelum tenggat");
propDiskon.setValue(null);
propNilaiDiskon.setValue(null);
decBayar.setValue(harga);
propBayar.setValue(df.format(harga));
}
}
lblCerita.setValue(narasi(harga, intDiskon.getValue(), intDiskonDue.getValue(), intNormalDue.getValue(), datBayar.getValue()));
}
@Listen("onClick=#btnKalkulasi")
public void btnKalkulasiClick(Event evt) {
kalkulasi();
}
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
private final static int yeardays = 365;
private final static double dyeardays = 365d;
private String narasi(BigDecimal harga, int diskon, int diskonDue, int normalDue, Date tanggalBayar) {
String sharga = harga == null ? "tertentu" : df.format(harga);
String sdiskon = "" + diskon;
String sdiskonDue = "" + diskonDue;
String sTanggalBayar = tanggalBayar == null ? "tertentu" : sdf.format(tanggalBayar);
String narasi = String.format(
"Skenario:\nPT Cevron menjual barang kepada PT Medco seharga %s. " +
"Barang tersebut dijual secara tunai dengan term pembayaran %s/%s n/%s. " +
"PT Medco kemudian melakukan pembayaran atas transaksi tersebut pada " +
"tanggal %s. " +
"Berapa nilai pembayaran yang harus dibayarkan ? ",
sharga, diskon, diskonDue, normalDue, sTanggalBayar);
return narasi;
}
private Map<String, Object> computeTvom(double rate, int jangka, BigDecimal pokok) {
Map<String, Object> res = new HashMap<String, Object>();
int period = computePeriode(jangka);
double efective = 1d + (((double) jangka / dyeardays) * rate);
double interestFactor = Math.pow(efective, period);
double futureValue = pokok.doubleValue() * interestFactor;
res.put(TVOM_PERIOD, period);
res.put(TVOM_DAY, jangka);
res.put(TVOM_INTEREST_FACTOR, interestFactor);
res.put(TVOM_FUTURE_VALUE, new BigDecimal(futureValue));
res.put(TVOM_INTEREST, new BigDecimal(futureValue).subtract(pokok));
res.put(TVOM_EFFECTIVE, efective);
return res;
}
private int computeSelangWaktuPembayaran(Date tanggalBayar) {
DateTime dtNow = new DateTime();
int jangka = Days.daysBetween(DateTime.now(), new DateTime(tanggalBayar)).getDays();
return jangka;
}
private int computePeriode(int jangka) {
Double d = (double) jangka / 365D;
return ((Double) Math.ceil(d)).intValue();
}
}