package service; import api.v1.ForecastSearchParams; import api.v1.OrderForecast; import api.v1.WorklistItem; import api.v1.WorklistItemStatus; import com.avaje.ebean.Ebean; import com.avaje.ebean.Query; import com.avaje.ebean.RawSql; import com.avaje.ebean.RawSqlBuilder; import mapper.WorklistMapper; import models.ForecastModel; import models.ForecastSearchResult; import models.OrderModel; import org.joda.time.DateTime; import org.joda.time.Duration; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import quba.service.QubaService; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class ForecastService extends PoseidonService { private final static Logger logger = LoggerFactory.getLogger(ForecastService.class); public ForecastService(String username) { super(username); } public List<WorklistItem> getWorklistItems(DateTime dato, Integer termin, List<OrderModel> orderModels) { List<WorklistItem> items = new WorklistMapper().mapToApi(orderModels); for (WorklistItem item : items) { item.date = dato.toDate(); DateTimeFormatter sdf = DateTimeFormat.forPattern("MM-dd"); item.termin = sdf.print(dato) + "/" + (termin < 10 ? "0" + termin : termin); item.previousForecastDate = null; ForecastModel fm = getLatestForecast(item.metref); if (fm != null) { item.previousForecastDate = fm.forecastedAt; item.previousForecastComment = fm.comment; item.previousForecastConfidence = fm.confidence; } DateTime dateOfProduction = new DateTime(dato, getTimeZone()); ForecastModel forecastModel = ForecastModel.findByMetrefAndTermin(item.metref, item.termin); if (forecastModel != null) { // varslet før -> enten failed eller produced if (forecastModel.failedAt != null) { item.status = WorklistItemStatus.FAILED; item.error = forecastModel.failureReason; } else { if (forecastModel.producedAt != null) { item.status = WorklistItemStatus.PRODUCED; } else if (forecastModel.forecastedAt != null) { item.status = WorklistItemStatus.SENT; } } } else { // ikke varslet tidligere, -> READY, OLD_DATA eller NO_DATA item.status = item.product.positionRequired ? findItemStatus(item.position_name, dateOfProduction, termin): WorklistItemStatus.READY ; } item.strongWindWarning = item.product.positionRequired && (item.status == WorklistItemStatus.READY || item.status == WorklistItemStatus.OLD_DATA) && QubaService.fetchStrongWindWarning(item.position_name, dateOfProduction, termin); logger.info("item {}", item); } return items; } protected WorklistItemStatus findItemStatus(String position_name, DateTime dateOfProduction, Integer termin) { WorklistItemStatus status; DateTime now = getNow(); DateTime terminDateTime = dateOfProduction.withHourOfDay(termin != null ? termin : 0); Duration d = new Duration(terminDateTime, now); long hoursUntilTermin = d.getStandardHours(); logger.debug("dateOfProduction = {}, termin={}, hoursUntilTermin = {}", dateOfProduction, termin, hoursUntilTermin); boolean exists = QubaService.qubaHasDataForPositionAndTermin(position_name, dateOfProduction, termin); if (!exists) { status = WorklistItemStatus.NO_DATA; } else if (Math.abs(hoursUntilTermin) > 6) { status = WorklistItemStatus.OLD_DATA; } else { status = WorklistItemStatus.READY; } return status; } private ForecastModel getLatestForecast(String metref) { OrderModel order = OrderModel.findByMetref(metref); return findLastForecastForOrder(order); } private ForecastModel findLastForecastForOrder(OrderModel order) { return ForecastModel.findLastForecastForMetref(order.met_ref); } public List<ForecastModel> produceAndSend(OrderForecast apiOrderForecast, String forecasterName) { List<ForecastModel> forecastModels = new ArrayList<>(); for (WorklistItem item : apiOrderForecast.worklistItems) { ForecastModel forecastModel = ForecastModel.findByMetrefAndTermin(item.metref, item.termin); Date forecastedAt = PoseidonService.getNow().toDate(); if (forecastModel == null) { OrderModel order = OrderModel.findByMetref(item.metref); forecastModel = new ForecastModel( apiOrderForecast.comment, apiOrderForecast.confidence, forecasterName, forecastedAt, null, item.termin, order); forecastModel.created = forecastedAt; forecastModel.createdBy = getUser(); // bestillinger uten posisjon blir produsert umiddelbart if (order.product.positionRequired == false) { forecastModel.producedAt = forecastedAt; } } else { // this order/termin has been forecasted before... forecastModel.forecastedBy = forecasterName; forecastModel.forecastedAt = forecastedAt; forecastModel.comment = apiOrderForecast.comment; forecastModel.confidence = apiOrderForecast.confidence; forecastModel.producedAt = null; forecastModel.updated = forecastModel.forecastedAt; forecastModel.updatedBy = getUser(); forecastModel.failedAt = null; forecastModel.failureReason = null; } forecastModel.save(); forecastModels.add(forecastModel); } return forecastModels; } public List<ForecastSearchResult> search(ForecastSearchParams searchParams) { String select = " select c.name as customer_name," + " o.met_ref as met_ref ," + " o.custref_po_calloff as po_calloff," + " o.custref_contractnum as contractnum," + " o.custref_email as email," + " o.customer_name as customer_contact," + " o.position_name as position_name," + " p.name as position_alias," + " min(f.produced_at) as forecast_start," + " max(f.produced_at) as forecast_end," + " count(f.id) as forecast_count, " + " f.invoiced as invoiced "; String from = " FROM POS_FORECAST f" + " JOIN POS_ORDER o ON o.id = f.order_id" + " JOIN POS_CUSTOMER c ON o.customer_id = c.id" + " JOIN pos_position p ON o.position_id = p.id"; String where = "where (f.produced_at IS NOT NULL) "; if (searchParams.position_name != null && !searchParams.position_name.isEmpty()) { where += " and lower(p.name) like '%" + searchParams.position_name.toLowerCase() + "%'"; } else if (searchParams.position_alias != null && !searchParams.position_alias.isEmpty()) { where += " and lower(o.position_name) like '%" + searchParams.position_alias.toLowerCase() + "%'"; } if (searchParams.customer_name != null && !searchParams.customer_name.isEmpty()) { where += " and lower(c.name) like '%" + searchParams.customer_name.toLowerCase() + "%'"; } if (searchParams.met_ref != null && !searchParams.met_ref.isEmpty()) { where += "and lower(o.met_ref) like '%" + searchParams.met_ref.toLowerCase() + "%'"; } if (searchParams.custref_po_calloff != null && !searchParams.custref_po_calloff.isEmpty()) { where += " and lower(o.custref_po_calloff) like '%" + searchParams.custref_po_calloff.toLowerCase() + "%'"; } if (searchParams.custref_contractnum != null && !searchParams.custref_contractnum.isEmpty()) { where += " and lower(o.custref_contractnum) like '%" + searchParams.custref_contractnum.toLowerCase() + "%'"; } if (searchParams.custref_email != null && !searchParams.custref_email.isEmpty()) { where += " and lower(o.custref_email) like '%" + searchParams.custref_email.toLowerCase() + "%'"; } if (searchParams.customer_contactname != null && !searchParams.customer_contactname.isEmpty()) { where += " and lower(o.customer_name) like '%" + searchParams.customer_name.toLowerCase() + "%'"; } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (searchParams.start_date != null) { String date; if (searchParams.start_term != null) { DateTime start = new DateTime(searchParams.start_date).withHourOfDay(searchParams.start_term); date = sdf.format(start.toDate()); } else { date = sdf.format(searchParams.start_date); } where += " and f.produced_at >= '" + date + "'"; } if (searchParams.end_date != null) { String date; if (searchParams.end_term != null) { DateTime end = new DateTime(searchParams.end_date).withHourOfDay(searchParams.end_term); date = sdf.format(end.toDate()); } else { date = sdf.format(searchParams.end_date); } where += " and f.produced_at < '" + date + "'"; } String groupBy = " GROUP BY c.name," + " o.met_ref," + " o.custref_po_calloff," + " o.custref_contractnum," + " o.custref_email," + " o.customer_name," + " o.position_name," + " f.invoiced," + " p.name"; String sql = select + " " + from + " " + where + " " + groupBy; RawSqlBuilder rawSqlBuilder = RawSqlBuilder.parse(sql); RawSqlBuilder columnMapping = rawSqlBuilder .columnMapping("c.name", "customer_name") .columnMapping("o.met_ref", "met_ref") .columnMapping("o.custref_po_calloff", "custref_po_calloff") .columnMapping("o.custref_contractnum", "custref_contractnum") .columnMapping("o.custref_email", "custref_email") .columnMapping("o.customer_name", "customer_contactname") .columnMapping("p.name", "position_name") .columnMapping("o.position_name", "position_alias") .columnMapping("min(f.produced_at)", "start_date") .columnMapping("max(f.produced_at)", "end_date") .columnMapping("count(f.id)", "produced_forecasts") .columnMapping("f.invoiced", "invoiced"); RawSql rawSql = columnMapping.create(); Query<ForecastSearchResult> query = Ebean.find(ForecastSearchResult.class); query.setRawSql(rawSql); List<ForecastSearchResult> results = query.findList(); return results; } }