package com.qcadoo.mes.materialFlowResources.palletBalance;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qcadoo.model.api.DataDefinitionService;
import com.qcadoo.model.api.DictionaryService;
@Service
public class PalletBalanceReportHelper {
@Autowired
private DataDefinitionService dataDefinitionService;
@Autowired
private DictionaryService dictionaryService;
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
public List<String> getTypesOfPallet() {
return dictionaryService.getActiveKeys("typeOfPallet");
}
public Map<Date, List<PalletBalanceRowDto>> getCurrentState(Date dateTo) {
StringBuilder query = new StringBuilder();
query.append("select r.typeofpallet as typeOfPallet, count(distinct p.number) as palletsCount, current_date AS day ");
query.append(" from materialflowresources_resource r ");
query.append(" join basic_palletnumber p on r.palletnumber_id = p.id ");
query.append("group by r.typeofpallet");
List<PalletBalanceRowDto> results = jdbcTemplate.query(query.toString(), new BeanPropertyRowMapper<>(
PalletBalanceRowDto.class));
Map<Date, List<PalletBalanceRowDto>> map = Maps.newHashMap();
map.put(dateTo, results);
return map;
}
public void fillFinalAndInitialState(List<String> typesOfPallet, Map<Date, List<PalletBalanceRowDto>> finalState,
Map<Date, List<PalletBalanceRowDto>> initialState, Map<Date, List<PalletBalanceRowDto>> inbounds,
Map<Date, List<PalletBalanceRowDto>> outbounds, Date dateFrom, Date dateTo) {
DateTime currentDate = new DateTime(dateTo);
while (currentDate.toDate().compareTo(dateFrom) >= 0) {
Date current = currentDate.toDate();
Date previousDate = currentDate.plusDays(1).toDate();
List<PalletBalanceRowDto> previousInitialState = initialState.get(previousDate);
if (previousInitialState != null) {
finalState.put(current, previousInitialState);
}
initialState.put(
current,
calculateInitialState(typesOfPallet, current, finalState.get(current), inbounds.get(current),
outbounds.get(current)));
currentDate = currentDate.minusDays(1);
}
}
private List<PalletBalanceRowDto> calculateInitialState(List<String> typesOfPallet, Date date,
List<PalletBalanceRowDto> finalStateRow, List<PalletBalanceRowDto> inboundsRow, List<PalletBalanceRowDto> outboundsRow) {
List<PalletBalanceRowDto> initialStateRow = Lists.newArrayList();
typesOfPallet.forEach(type -> {
PalletBalanceRowDto finalPalletState = finalStateRow.stream().filter(dto -> type.equals(dto.getTypeOfPallet()))
.findAny().orElse(new PalletBalanceRowDto(type, date, 0));
PalletBalanceRowDto initialPalletState = new PalletBalanceRowDto();
String typeOfPallet = finalPalletState.getTypeOfPallet();
initialPalletState.setDay(finalPalletState.getDay());
initialPalletState.setTypeOfPallet(typeOfPallet);
int inboundForPallet = getPalletsCountForType(inboundsRow, typeOfPallet);
int outboundForPallet = getPalletsCountForType(outboundsRow, typeOfPallet);
int finalForPallet = finalPalletState.getPalletsCount();
initialPalletState.setPalletsCount(finalForPallet - inboundForPallet + outboundForPallet);
initialStateRow.add(initialPalletState);
});
return initialStateRow;
}
private int getPalletsCountForType(List<PalletBalanceRowDto> source, String type) {
if (source == null || source.isEmpty()) {
return 0;
}
PalletBalanceRowDto stateForDay = source.stream().filter(dto -> type.equals(dto.getTypeOfPallet())).findAny()
.orElse(new PalletBalanceRowDto());
return stateForDay.getPalletsCount();
}
public Map<Date, Integer> getMoves(final Date dateFrom) {
StringBuilder query = new StringBuilder();
query.append("select date_trunc('day',d.time) as day, count(distinct sl.number) as palletsCount");
query.append(" from materialflowresources_position p ");
query.append(" join materialflowresources_storagelocation sl on p.storagelocation_id = sl.id ");
query.append(" join materialflowresources_document d on p.document_id = d.id ");
query.append(" join basic_palletnumber pn on pn.id = p.palletnumber_id ");
query.append("where d.type in ('03internalOutbound','04release', '05transfer') and sl.highstoragelocation = true ");
query.append(" and (date_trunc('day',pn.issuedatetime) != date_trunc('day',d.time) OR pn.issuedatetime is null) ");
query.append(" and date_trunc('day', d.time) >= :dateFrom ");
query.append("group by date_trunc('day',d.time);");
Map<String, Object> params = Maps.newHashMap();
params.put("dateFrom", dateFrom);
Map<Date, Integer> result = jdbcTemplate.query(query.toString(), params, new ResultSetExtractor<Map<Date, Integer>>() {
@Override
public Map<Date, Integer> extractData(ResultSet rs) throws SQLException, DataAccessException {
Map<Date, Integer> result = Maps.newHashMap();
while (rs.next()) {
result.put(rs.getDate("day"), rs.getInt("palletsCount"));
}
return result;
}
});
return result;
}
public Map<Date, List<PalletBalanceRowDto>> getInbounds(final Date dateFrom) {
StringBuilder query = new StringBuilder();
query.append("select p.typeofpallet as typeOfPallet, date_trunc('day', d.time) as day, count(distinct pn.number) as palletsCount ");
query.append(" from materialflowresources_position p ");
query.append(" join basic_palletnumber pn on p.palletnumber_id = pn.id ");
query.append(" join materialflowresources_document d on p.document_id = d.id ");
query.append(" where d.type in ('01receipt','02internalInbound') ");
query.append(" and date_trunc('day', d.time) >= :dateFrom ");
query.append("group by p.typeofpallet, date_trunc('day',d.time)");
Map<String, Object> params = Maps.newHashMap();
params.put("dateFrom", dateFrom);
List<PalletBalanceRowDto> results = jdbcTemplate.query(query.toString(), params, new BeanPropertyRowMapper<>(
PalletBalanceRowDto.class));
return mapQueryResults(results);
}
public Map<Date, List<PalletBalanceRowDto>> getOutbounds(final Date dateFrom) {
StringBuilder query = new StringBuilder();
query.append("select date_trunc('day',pn.issuedatetime) as day, p.typeofpallet as typeOfPallet, count(distinct pn.number) as palletsCount ");
query.append(" from basic_palletnumber pn ");
query.append(" join materialflowresources_position p on p.palletnumber_id = pn.id ");
query.append(" join materialflowresources_document d on p.document_id = d.id ");
query.append(" where date_trunc('day',pn.issuedatetime) >= :dateFrom ");
query.append(" and d.type in ('03internalOutbound','04release')");
query.append("group by date_trunc('day',pn.issuedatetime), p.typeofpallet");
Map<String, Object> params = Maps.newHashMap();
params.put("dateFrom", dateFrom);
List<PalletBalanceRowDto> results = jdbcTemplate.query(query.toString(), params, new BeanPropertyRowMapper<>(
PalletBalanceRowDto.class));
return mapQueryResults(results);
}
private Map<Date, List<PalletBalanceRowDto>> mapQueryResults(List<PalletBalanceRowDto> results) {
Map<Date, List<PalletBalanceRowDto>> map = Maps.newHashMap();
for (PalletBalanceRowDto dto : results) {
Date day = dto.getDay();
if (map.containsKey(day)) {
map.get(day).add(dto);
} else {
map.put(day, Lists.newArrayList(dto));
}
}
return map;
}
}