package org.openlmis.core.model.service;
import com.google.inject.Inject;
import org.joda.time.DateTime;
import org.openlmis.core.LMISApp;
import org.openlmis.core.R;
import org.openlmis.core.exceptions.LMISException;
import org.openlmis.core.model.Period;
import org.openlmis.core.model.RnRForm;
import org.openlmis.core.model.repository.RnrFormRepository;
import org.openlmis.core.model.repository.StockMovementRepository;
import org.openlmis.core.model.repository.StockRepository;
import org.openlmis.core.utils.DateUtil;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class RequisitionPeriodService {
@Inject
RnrFormRepository rnrFormRepository;
@Inject
StockRepository stockRepository;
@Inject
private StockMovementRepository stockMovementRepository;
public Period generateNextPeriod(String programCode, Date physicalInventoryDate) throws LMISException {
List<RnRForm> rnRForms = rnrFormRepository.listInclude(RnRForm.Emergency.No, programCode);
if (rnRForms.isEmpty()) {
return generatePeriodBasedOnDefaultDates(physicalInventoryDate, programCode);
}
RnRForm lastRnR = rnRForms.get(rnRForms.size() - 1);
return generatePeriodBasedOnPreviousRnr(lastRnR, physicalInventoryDate);
}
private Period generatePeriodBasedOnPreviousRnr(RnRForm lastRnR, Date physicalInventoryDate) throws LMISException {
DateTime periodBeginDate, periodEndDate;
periodBeginDate = new DateTime(lastRnR.getPeriodEnd());
if (LMISApp.getInstance().getFeatureToggleFor(R.bool.feature_training)) {
return Period.generateForTraining(periodBeginDate.plusDays(1).toDate());
}
if (physicalInventoryDate == null) {
Calendar date = Calendar.getInstance();
date.set(periodBeginDate.getYear(), periodBeginDate.getMonthOfYear(), Period.END_DAY);
periodEndDate = DateUtil.cutTimeStamp(new DateTime(date));
} else {
periodEndDate = new DateTime(physicalInventoryDate);
}
return new Period(periodBeginDate, periodEndDate);
}
private Period generatePeriodBasedOnDefaultDates(Date physicalInventoryDate, String programCode) throws LMISException {
if (LMISApp.getInstance().getFeatureToggleFor(R.bool.feature_training)) {
return Period.generateForTraining(new Date(LMISApp.getInstance().getCurrentTimeMillis()));
}
DateTime periodBeginDate = calculatePeriodBeginDate(programCode);
DateTime periodEndDate;
if (physicalInventoryDate == null) {
periodEndDate = defaultEndDateTo20th(periodBeginDate);
} else {
periodEndDate = new DateTime(physicalInventoryDate);
}
return new Period(periodBeginDate, periodEndDate);
}
private DateTime calculatePeriodBeginDate(String programCode) throws LMISException {
DateTime initializeDateTime = new DateTime(stockMovementRepository.queryEarliestStockMovementDateByProgram(programCode));
int initializeDayOfMonth = initializeDateTime.getDayOfMonth();
Calendar currentBeginDate = Calendar.getInstance();
if (initializeDayOfMonth >= Period.INVENTORY_BEGIN_DAY && initializeDayOfMonth < Period.INVENTORY_END_DAY_NEXT) {
currentBeginDate.set(initializeDateTime.getYear(), initializeDateTime.getMonthOfYear() - 1, initializeDayOfMonth);
} else {
currentBeginDate.set(initializeDateTime.getYear(), initializeDateTime.getMonthOfYear() - 1, Period.BEGIN_DAY);
}
DateTime periodBeginDate = DateUtil.cutTimeStamp(new DateTime(currentBeginDate));
if (initializeDayOfMonth < Period.INVENTORY_BEGIN_DAY) {
periodBeginDate = periodBeginDate.minusMonths(1);
}
return periodBeginDate;
}
private DateTime defaultEndDateTo20th(DateTime periodBeginDate) {
Calendar date = Calendar.getInstance();
date.set(periodBeginDate.getYear(), periodBeginDate.getMonthOfYear(), Period.END_DAY);
return DateUtil.cutTimeStamp(new DateTime(date));
}
public boolean hasMissedPeriod(String programCode) throws LMISException {
List<RnRForm> rnRForms = rnrFormRepository.listInclude(RnRForm.Emergency.No, programCode);
if (rnRForms.size() == 0 || rnRForms.get(rnRForms.size() - 1).isAuthorized()) {
DateTime nextPeriodInScheduleEnd = generateNextPeriod(programCode, null).getEnd();
DateTime lastInventoryDateForNextPeriodInSchedule = nextPeriodInScheduleEnd
.withDate(nextPeriodInScheduleEnd.getYear(),
nextPeriodInScheduleEnd.getMonthOfYear(),
Period.INVENTORY_END_DAY_NEXT);
return lastInventoryDateForNextPeriodInSchedule.isBefore(LMISApp.getInstance().getCurrentTimeMillis());
}
Date lastRnrPeriodEndDate = rnRForms.get(rnRForms.size() - 1).getPeriodEnd();
return new DateTime(lastRnrPeriodEndDate).isBefore(LMISApp.getInstance().getCurrentTimeMillis());
}
public int getMissedPeriodOffsetMonth(String programCode) throws LMISException {
DateTime nextPeriodInScheduleBegin = generateNextPeriod(programCode, null).getBegin();
DateTime currentMonthInventoryBeginDate;
currentMonthInventoryBeginDate = getCurrentMonthInventoryBeginDate();
return DateUtil.calculateDateMonthOffset(nextPeriodInScheduleBegin.toDate(), currentMonthInventoryBeginDate.toDate());
}
public int getIncompletePeriodOffsetMonth(String programCode) throws LMISException {
List<RnRForm> rnRForms = rnrFormRepository.listInclude(RnRForm.Emergency.No, programCode);
if (rnRForms.size() == 0 || rnRForms.get(rnRForms.size() - 1).isAuthorized()) {
return getMissedPeriodOffsetMonth(programCode);
} else return getMissedPeriodOffsetMonth(programCode) + 1;
}
public DateTime getCurrentMonthInventoryBeginDate() {
DateTime currentDate = new DateTime(LMISApp.getInstance().getCurrentTimeMillis());
DateTime currentMonthInventoryBeginDate;
if (currentDate.getDayOfMonth() >= Period.INVENTORY_BEGIN_DAY) {
currentMonthInventoryBeginDate = currentDate
.withDate(currentDate.getYear(),
currentDate.getMonthOfYear(),
Period.INVENTORY_BEGIN_DAY);
} else {
if (currentDate.getMonthOfYear() == 1) {
currentMonthInventoryBeginDate = currentDate
.withDate(currentDate.getYear() - 1,
12,
Period.INVENTORY_BEGIN_DAY);
} else {
currentMonthInventoryBeginDate = currentDate
.withDate(currentDate.getYear(),
currentDate.getMonthOfYear() - 1,
Period.INVENTORY_BEGIN_DAY);
}
}
return currentMonthInventoryBeginDate;
}
}