package service; import api.v1.*; import com.avaje.ebean.*; import com.google.common.base.Strings; import dist.service.DistService; import exceptions.PoseidonException; import kundedb.service.KundedbService; import mapper.OrderMapper; import models.*; import models.OrderStatus; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import play.mvc.Http; import quba.service.QubaPositionSyncer; import validators.OrderValidator; import validators.ValidationResult; import java.util.*; import java.util.stream.Collectors; public class OrderService extends PoseidonService { private final static Logger logger = LoggerFactory.getLogger(OrderService.class); public OrderService(String username) { super(username); } public List<OrderModel> findAll() { List<OrderModel> all = OrderModel.find.all(); if (all != null) { for (OrderModel orderModel : all) { orderModel.assignStatus(getNow()); } } return all; } public OrderModel getById(long id) { OrderModel orderModel = OrderModel.find.fetch("customer").fetch("position").where().eq("id", id).findUnique(); if (orderModel != null) orderModel.assignStatus(getNow()); return orderModel; } public OrderModel getByMetref(String met_ref) { OrderModel orderModel = OrderModel.findByMetref(met_ref); if (orderModel != null) { orderModel.assignStatus(getNow()); if ( orderModel.position != null && orderModel.position.id > 0){ orderModel.position.isDeletable = (new PositionService(getUser()).isDeletable(orderModel.position.id)); } } return orderModel; } protected List<OrderModel> getOrdersForStartDate(DateTime dateTime, Integer termin) { Date date = dateTime.toDate(); List<OrderModel> result = new ArrayList<>(); logger.info("getOrdersForStartDate({},{})", dateTime, termin); // First period List<OrderModel> orders = OrderModel.find.fetch("position").where().eq("start_date1", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.start_termin1!= null && order.start_termin1.equals(termin)) { result.add(order); } else { if (order.termins1 != null && !order.termins1.isEmpty()) { String[] strOrderTermins = order.termins1.split(","); for (String t : strOrderTermins) { logger.debug("termin {}", t); Integer orderTermin = Integer.parseInt(t); if ((order.start_termin1 == null || orderTermin > order.start_termin1) && orderTermin.equals(termin)) result.add(order); } } } } // Second period orders = OrderModel.find.where().eq("start_date2", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.start_termin2 != null && order.start_termin2.equals(termin)) { result.add(order); } else { if (order.termins2 != null && !order.termins2.isEmpty()) { String[] strOrderTermins = order.termins2.split(","); for (String t : strOrderTermins) { Integer orderTermin = Integer.parseInt(t); if ((order.start_termin2 == null || orderTermin > order.start_termin2) && orderTermin.equals(termin)) result.add(order); } } } } // Third period orders = OrderModel.find.where().eq("start_date3", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.start_termin3!= null && order.start_termin3.equals(termin)) { result.add(order); } else { if (order.termins3 != null && !order.termins3.isEmpty()) { String[] strOrderTermins = order.termins3.split(","); for (String t : strOrderTermins) { Integer orderTermin = Integer.parseInt(t); if ((order.start_termin3 == null || orderTermin > order.start_termin3) && orderTermin.equals(termin)) result.add(order); } } } } return result; } protected List<OrderModel> getOrdersForEndDate(DateTime dateTime, Integer termin) { Date date = dateTime.toDate(); List<OrderModel> result = new ArrayList<>(); // First period List<OrderModel> orders = OrderModel.find.where().eq("end_date1", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.end_termin1 != null && order.end_termin1.equals(termin)) { result.add(order); } else { if (order.termins1 != null && !order.termins1.isEmpty()) { String[] strOrderTermins = order.termins1.split(","); for (String t : strOrderTermins) { Integer orderTermin = Integer.parseInt(t); if ((order.end_termin1 == null || orderTermin < order.end_termin1) && orderTermin.equals(termin)) result.add(order); } } } } // Second period orders = OrderModel.find.where().eq("end_date2", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.end_termin2 != null && order.end_termin2.equals(termin)) { result.add(order); } else { if (order.termins2 != null && !order.termins2.isEmpty()) { String[] strOrderTermins = order.termins2.split(","); for (String t : strOrderTermins) { Integer orderTermin = Integer.parseInt(t); if ((order.end_termin2 == null || orderTermin < order.end_termin2) && orderTermin.equals(termin)) result.add(order); } } } } // Third period orders = OrderModel.find.where().eq("end_date3", date).isNull("deleted").findList(); for (OrderModel order : orders) { if (order.end_termin3 != null && order.end_termin3.equals(termin)) { result.add(order); } else { if (order.termins3 != null && !order.termins3.isEmpty()) { String[] strOrderTermins = order.termins3.split(","); for (String t : strOrderTermins) { Integer orderTermin = Integer.parseInt(t); if ((order.end_termin3 == null || orderTermin < order.end_termin3) && orderTermin.equals(termin)) result.add(order); } } } } return result; } protected List<OrderModel> getOrdersForPeriod(DateTime dateTime, Integer termin) { Date date = dateTime.toDate(); return OrderModel.find.where() .and( Expr.isNull("deleted"), Expr.or( Expr.or( // First period Expr.and( Expr.and(Expr.lt("start_date1", date), Expr.or(Expr.gt("end_date1", date), Expr.isNull("end_date1"))), Expr.or( Expr.or(Expr.eq("termins1", termin.toString()), Expr.startsWith("termins1", termin + ",")), Expr.or(Expr.contains("termins1", "," + termin + ","), Expr.endsWith("termins1", "," + termin)) ) ), // Second period Expr.and( Expr.and(Expr.lt("start_date2", date), Expr.or(Expr.gt("end_date2", date), Expr.isNull("end_date2"))), Expr.or( Expr.or(Expr.eq("termins2", termin.toString()), Expr.startsWith("termins2", termin + ",")), Expr.or(Expr.contains("termins2", "," + termin + ","), Expr.endsWith("termins2", "," + termin)) ) ) ), // Third period Expr.and( Expr.and(Expr.lt("start_date3", date), Expr.or(Expr.gt("end_date3", date), Expr.isNull("end_date3"))), Expr.or( Expr.or(Expr.eq("termins3", termin.toString()), Expr.startsWith("termins3", termin + ",")), Expr.or(Expr.contains("termins3", "," + termin + ","), Expr.endsWith("termins3", "," + termin)) ) ) ) ) .findList(); } public List<OrderModel> getByDateTermin(DateTime date, Integer termin) { List<OrderModel> orders = new ArrayList<>(); orders.addAll(getOrdersForStartDate(date, termin)); orders.addAll(getOrdersForPeriod(date, termin)); orders.addAll(getOrdersForEndDate(date, termin)); for (OrderModel order : orders) { order.assignStatus(getNow()); } return orders; } public OrderModel createOrUpdate(Order apiOrder) { OrderModel mOrder; ValidationResult inputValidationResult = new OrderValidator().validateApi(apiOrder); if (!inputValidationResult.ok) { throw new PoseidonException(Http.Status.BAD_REQUEST, inputValidationResult.getMessage()); } if ((apiOrder.id != null) && (apiOrder.id > 0)) { mOrder = getById(apiOrder.id); mOrder.updated = getNow().toDate(); mOrder.updatedBy = getUser(); } else { mOrder = new OrderModel(); mOrder.created = PoseidonService.getNow().toDate(); mOrder.createdBy = getUser(); } mOrder = new OrderMapper().mapToModel(apiOrder, mOrder, getUser()); mOrder.assignStatus(getNow()); updateCustomerIfDifferent(apiOrder, mOrder); setOrCreatePosition(apiOrder, mOrder); setProduct(apiOrder, mOrder); ValidationResult validationResult = new OrderValidator().validateModel(mOrder); if (!validationResult.ok) { throw new PoseidonException(Http.Status.BAD_REQUEST, "Validering av ordre-data feilet: " + validationResult.getMessage()); } mOrder.save(); mOrder = OrderModel.find.fetch("position").where().eq("id", mOrder.id).findUnique(); mOrder.assignStatus(getNow()); // sync order to quba/kundedb/distdb if // order delivery starts today // and order is new // and order has a position if ( mOrder.position != null) { syncToQuba(apiOrder, mOrder); syncOrderToKundeDb(mOrder); syncOrderToDistDb(mOrder); } return mOrder; } private void syncToQuba(Order apiOrder, OrderModel mOrder) { // sync when there is a position to sync if ( mOrder.product.positionRequired ) { DateTime now = getNow(); DateTime dtToday = now.withTime(0, 0, 0, 0); QubaPositionSyncer syncer = new QubaPositionSyncer(); String startHourProp = PoseidonPropertyService.getProperty("qubasync.start_hour"); int startHour = Integer.valueOf(startHourProp); if (apiOrder.id == null /* new order */) { if (mOrder.start_date1 != null) { DateTime start1 = new DateTime(mOrder.start_date1, getTimeZone()).withTimeAtStartOfDay(); // does it start today? if (start1.isEqual(dtToday)) { Set<Integer> activeTermins = mOrder.getActiveTerminsForDayContainingTimestamp(dtToday); syncer.syncPosition(mOrder.position, activeTermins); } // does it start tomorrow, and it is later than 12:00? DateTime tomorrow = dtToday.plusDays(1); if (start1.isEqual(tomorrow) && now.getHourOfDay() >= startHour) { Set<Integer> activeTermins = mOrder.getActiveTerminsForDayContainingTimestamp(tomorrow); syncer.syncPosition(mOrder.position, activeTermins); } } } else /* updated order */ { DateTime tomorrow = dtToday.plusDays(1); Set<Integer> activeTerminsToday = mOrder.getActiveTerminsForDayContainingTimestamp(dtToday); Set<Integer> activeTerminsTomorrow = mOrder.getActiveTerminsForDayContainingTimestamp(tomorrow); int NUM_PERIODS = 3; Date[] startDates = new Date[NUM_PERIODS]; startDates[0] = mOrder.start_date1; startDates[1] = mOrder.start_date2; startDates[2] = mOrder.start_date3; for (int period = 1; period <= NUM_PERIODS; period++) { if (mOrder.isInPeriod(now, period)) { if (startDates[period-1] != null) { DateTime start = new DateTime(startDates[period], getTimeZone()).withTimeAtStartOfDay(); if (start.isEqual(dtToday)) { syncer.syncPosition(mOrder.position, activeTerminsToday); } if (start.isEqual(tomorrow) && now.getHourOfDay() >= startHour) { syncer.syncPosition(mOrder.position, activeTerminsTomorrow); } } } } } } } private void syncOrderToKundeDb(OrderModel mOrder) { (new KundedbService(getUser())).syncOrderImmediately(mOrder); } private void syncOrderToDistDb(OrderModel mOrder) { (new DistService(getUser())).syncOrderImmediately(mOrder); } private void updateCustomerIfDifferent(Order apiOrder, OrderModel mOrder) { if (apiOrder.customer != null && apiOrder.customer.id > 0) { CustomerModel customer = CustomerModel.find.byId(apiOrder.customer.id); if (customer != null) { mOrder.customer = customer; } } } private void setOrCreatePosition(Order apiOrder, OrderModel mOrder) { Position apiPosition = apiOrder.position; if (apiPosition == null) { return; } // set Position if position is specified if (apiPosition.id != null && apiPosition.id > 0) { PositionModel pos = PositionModel.find.byId(apiPosition.id); if (pos != null) { mOrder.position = pos; } if (positionTagsModified(pos, apiPosition)) { new PositionService(getUser()).createOrUpdate(apiPosition); } } else { // new position if (!Strings.isNullOrEmpty(apiPosition.name)) { mOrder.position = new PositionService(getUser()).createOrUpdate(apiPosition); } } } private void setProduct(Order apiOrder, OrderModel mOrder) { Product apiProduct = apiOrder.product; if (apiProduct == null) { ProductModel defaultProduct = ProductModel.findByName(PoseidonPropertyService.getProperty("order.default_productname")); if ( defaultProduct != null){ mOrder.product = defaultProduct; } return; } // set Product if specified if (apiProduct.id != null && apiProduct.id > 0) { ProductModel product = ProductModel.find.byId(apiProduct.id); if (product != null) { mOrder.product= product; } } } private boolean positionTagsModified(PositionModel pos, Position apiPosition) { if (pos.tags.size() != apiPosition.tags.length) return true; // check apiPosition.tags for new tags, where id is empty for (PositionTag tag : apiPosition.tags) { if (tag.id == null || tag.id == 0) return true; } // check positionModel.tags for deleted tags for (Iterator<PositionTagModel> itr = pos.tags.iterator(); itr.hasNext(); ) { PositionTagModel ptModel = itr.next(); boolean found = false; for (PositionTag tag : apiPosition.tags) { if (ptModel.name.equals(tag.name)) { found = true; continue; } } if (!found) return true; } return false; } public List<RecipientModel> getRecipientsForOrder(Long orderId) { return RecipientModel.find.where().eq("orders.id", orderId).findList(); } public List<OrderModel> search(OrderSearch searchParams) { String select = "select distinct o.id, " + "o.met_ref, " + "o.custref_po_calloff, " + "o.custref_contractnum, " + "o.custref_email, " + "o.customer_name, " + "o.customer_email, " + "o.customer_phone, " + "o.start_date1, " + "o.end_date1, " + "o.start_date1, " + "o.end_date2, " + "o.start_date2, " + "o.end_date3, " + "o.start_date3, " + "o.position_name, " + "p.id, " + "p.name, " + "p.latitude, " + "p.longitude "; String from = " from pos_order o " + "left outer join pos_position p on o.position_id = p.id "; String where = "where "; if ((searchParams.radius != null && searchParams.radius > 0) && (searchParams.position_alias == null || searchParams.position_alias.isEmpty()) && (searchParams.position_name == null || searchParams.position_name.isEmpty())) { throw new PoseidonException(Http.Status.BAD_REQUEST, "Søkeradius angitt uten posisjonsnavn eller alias"); } if ((searchParams.radius != null && searchParams.radius > 0) && (searchParams.position_alias != null && !searchParams.position_alias.isEmpty()) && (searchParams.position_name != null && !searchParams.position_name.isEmpty())) { throw new PoseidonException(Http.Status.BAD_REQUEST, "Søkeradius kan ikke angis når både posisjonsnavn og alias er angitt"); } if (searchParams.position_name != null && !searchParams.position_name.isEmpty()) { if (searchParams.radius != null && searchParams.radius > 0.0) { from = "from (select p.id, p.name, p.latitude, p.longitude from pos_order o join pos_position p on p.id = o.position_id where p.name like '%" + searchParams.position_name + "%' ) as p1,\n" + " pos_position p2,\n" + " pos_order o"; where += " o.position_id = p2.id\n" + "and acos( sin(radians(p1.latitude))*sin(radians(p2.latitude)) + cos(radians(p1.latitude))*cos(radians(p2.latitude))*cos(radians(p2.longitude-p1.longitude))) * 6371 < " + searchParams.radius; } else { where += "lower(p.name) like '%" + searchParams.position_name.toLowerCase() + "%'"; } } else if (searchParams.position_alias != null && !searchParams.position_alias.isEmpty()) { if (where.length() > 6) where += " and "; if (searchParams.radius != null && searchParams.radius > 0.0) { from = "from (select p.id, p.name, p.latitude, p.longitude from pos_order o join pos_position p on p.id = o.position_id where o.position_name like '%" + searchParams.position_alias + "%' ) as p1,\n" + " pos_position p2,\n" + " pos_order o"; where += " o.position_id = p2.id\n" + "and acos( sin(radians(p1.latitude))*sin(radians(p2.latitude)) + cos(radians(p1.latitude))*cos(radians(p2.latitude))*cos(radians(p2.longitude-p1.longitude))) * 6371 < " + searchParams.radius; } else { where += "lower(o.position_name) like '%" + searchParams.position_alias.toLowerCase() + "%'"; } } if (searchParams.met_ref != null && !searchParams.met_ref.isEmpty()) { if (where.length() > 6) where += " and "; where += "lower(o.met_ref) like '%" + searchParams.met_ref.toLowerCase() + "%'"; } if (searchParams.custref_po_calloff != null && !searchParams.custref_po_calloff.isEmpty()) { if (where.length() > 6) where += " and "; where += "lower(o.custref_po_calloff) like '%" + searchParams.custref_po_calloff.toLowerCase() + "%'"; } if (searchParams.custref_contractnum != null && !searchParams.custref_contractnum.isEmpty()) { if (where.length() > 6) where += " and "; where += "lower(o.custref_contractnum) like '%" + searchParams.custref_contractnum.toLowerCase() + "%'"; } if (searchParams.custref_email != null && !searchParams.custref_email.isEmpty()) { if (where.length() > 6) where += " and "; where += "lower(o.custref_email) like '%" + searchParams.custref_email.toLowerCase() + "%'"; } if (searchParams.customer_name != null && !searchParams.customer_name.isEmpty()) { if (where.length() > 6) where += " and "; where += "lower(o.customer_name) like '%" + searchParams.customer_name.toLowerCase() + "%'"; } if ( searchParams.recipient_email != null && !searchParams.recipient_email.isEmpty()){ if (where.length() > 6) where += " and "; from = " from pos_order o " + "left outer join pos_position p on o.position_id = p.id " + "left join pos_order_recipients por on por.order_id = o.id " + "left join pos_recipient pr on pr.id = por.recipient_id "; where += " pr.email like '%" + searchParams.recipient_email + "%'" ; } String sql = select + " " + from + " "; if (where.length() > 6) sql += where; RawSqlBuilder rawSqlBuilder = RawSqlBuilder.parse(sql); RawSqlBuilder columnMapping = rawSqlBuilder .columnMapping("o.id", "id") .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_name") .columnMapping("o.customer_email", "customer_email") .columnMapping("o.customer_phone", "customer_phone") .columnMapping("o.position_name", "position_name") .columnMapping("p.id", "position.id") .columnMapping("p.name", "position.name") .columnMapping("p.latitude", "position.latitude") .columnMapping("p.longitude", "position.longitude") .columnMapping("o.start_date1", "start_date1") .columnMapping("o.end_date1", "end_date1") .columnMapping("o.start_date2", "start_date2") .columnMapping("o.end_date2", "end_date2") .columnMapping("o.start_date3", "start_date3") .columnMapping("o.end_date3", "end_date3"); RawSql rawSql = columnMapping.create(); Query<OrderModel> query = Ebean.find(OrderModel.class); query.setRawSql(rawSql); if (searchParams.status != null && !searchParams.status.isEmpty()) query.setParameter("today", getNow()); List<OrderModel> orders = query.findList(); if (orders != null) { for (OrderModel orderModel : orders) { orderModel.assignStatus(getNow()); } return filterModelsByStatus(searchParams.status, orders, searchParams.invertStatus); } return orders; } private List<OrderModel> filterModelsByStatus(String status, List<OrderModel> orders, boolean invertStatus) { List<OrderModel> ordersFilteredByStatus = new ArrayList<>(); for (OrderModel orderModel : orders) { if (status != null && !status.isEmpty()) { switch (status) { case "new": if (orderModel.orderStatus.equals(OrderStatus.NEW) || invertStatus) ordersFilteredByStatus.add(orderModel); break; case "active": if (orderModel.orderStatus.equals(OrderStatus.ACTIVE)|| invertStatus) ordersFilteredByStatus.add(orderModel); break; case "dormant": if (orderModel.orderStatus.equals(OrderStatus.DORMANT)|| invertStatus) ordersFilteredByStatus.add(orderModel); break; case "expired": if (orderModel.orderStatus.equals(OrderStatus.EXPIRED)|| invertStatus) ordersFilteredByStatus.add(orderModel); break; case "deleted": if (orderModel.orderStatus.equals(OrderStatus.DELETED)|| invertStatus) ordersFilteredByStatus.add(orderModel); break; default: throw new PoseidonException(Http.Status.BAD_REQUEST, "Ugyldig statusverdi: " + status); } } else { // filter out deleted orders if (!orderModel.isDeleted()) { ordersFilteredByStatus.add(orderModel); } } } return ordersFilteredByStatus; } public boolean checkMetref(String met_ref) { OrderModel model = getByMetref(met_ref); return model != null; } public OrderModel deleteOrder(Long id) { OrderModel orderModel = getById(id); orderModel.assignStatus(getNow()); if (orderModel != null) { OrderStatus orderStatus = orderModel.orderStatus; if (orderStatus == null) { throw new PoseidonException(Http.Status.INTERNAL_SERVER_ERROR, "Angitt bestilling har ukjent status"); } if (!orderStatus.equals(OrderStatus.NEW)) { throw new PoseidonException(Http.Status.BAD_REQUEST, "Angitt bestilling har ikke status NY"); } orderModel.deleted = PoseidonService.getNow().toDate(); orderModel.deletedBy = getUser(); orderModel.save(); } return orderModel; } public List<OrderModel> getActiveOrdersTomorrowForQba(DateTime d) { List<OrderModel> orders = getOrdersForDate(TerminService.tomorrowAtMidnight(d)); // filtrer bort de som ikke har posisjon med java8 streams filter // http://zeroturnaround.com/rebellabs/java-8-explained-applying-lambdas-to-java-collections/ return orders.stream().filter(o->o.position!=null).collect(Collectors.toList()); } public List<OrderModel> getOrdersForDate(DateTime date) { return OrderModel.find.fetch("position").fetch("customer").fetch("product").where() .and( Expr.isNull("deleted"), Expr.or( Expr.or( // First period Expr.and(Expr.le("start_date1", date), Expr.or(Expr.ge("end_date1", date), Expr.isNull("end_date1"))), // Second period Expr.and(Expr.le("start_date2", date), Expr.or(Expr.ge("end_date2", date), Expr.isNull("end_date2"))) ), // Third period Expr.and(Expr.lt("start_date3", date), Expr.or(Expr.gt("end_date3", date), Expr.isNull("end_date3"))) ) ) .findList(); } public List<ForecastModel> getActiveForecastsForSms() { List<ForecastModel> forecasts = ForecastModel.find.fetch("order") .where() .and( //Expr.isNotNull("forecastedAt"), Expr.and(Expr.isNotNull("forecastedAt"),Expr.isNotNull("order.position.id")), Expr.and(Expr.isNull("failedAt"),Expr.isNull("producedAt")) ) .findList(); return forecasts; } public List<CleanableOrderModel> getCleanableQubaOrders(DateTime now) { List<CleanableOrderModel> result; // query sql is defined in conf/orm.xml // date arithmetic syntax is different between h2 and postgres, so need to // pick a named query according to database we are using String datasource = PoseidonPropertyService.getProperty("play.ebean.defaultDatasource"); Query<CleanableOrderModel> query = Ebean.createNamedQuery(CleanableOrderModel.class, "findCleanableOrders-" + datasource); query.setParameter("now", now); result = query.findList(); logger.info("result {}", result); return result; } public List<OrderModel> getOrdersForKundedb(DateTime tomorrow) { return OrderModel.find.where() .eq("start_date1", tomorrow) // starter i morgen .isNull("deleted") // er ikke slettet .isNotNull("position") // har en posisjon .findList(); } public List<OrderModel> getActiveOrdersForKundedb() { DateTime today = new DateTime(getToday(), getTimeZone()).withTimeAtStartOfDay(); DateTime endDate = today.minusDays(7); DateTime startDate = today.plusDays(1); return getActiveOrders(startDate, endDate); } public List<OrderModel> getInactiveOrdersForKundedb() { DateTime today = new DateTime(getToday(), getTimeZone()).withTimeAtStartOfDay(); DateTime endDate = today.minusDays(7); DateTime startDate = today.plusDays(1); return getInactiveOrders(startDate, endDate); } public List<OrderModel> getInactiveOrdersForDistdb() { DateTime today = new DateTime(getToday(), getTimeZone()).withTimeAtStartOfDay(); DateTime endDate = today.minusDays(1); DateTime startDate = today.plusDays(1); return getInactiveOrders(startDate, endDate); } public List<OrderModel> getActiveOrdersForDistdb() { DateTime today = new DateTime(getToday(), getTimeZone()).withTimeAtStartOfDay(); DateTime endDate = today.minusDays(1); DateTime startDate = today.plusDays(1); return getActiveOrders(startDate, endDate); } private List<OrderModel> getActiveOrders(DateTime startDate, DateTime endDate) { return OrderModel.find.where() .and( Expr.and(Expr.isNull("deleted"), Expr.isNotNull("position")), Expr.or( Expr.or( // First period Expr.and( Expr.le("start_date1", startDate), Expr.or(Expr.ge("end_date1", endDate), Expr.isNull("end_date1"))), // Second period Expr.and( Expr.le("start_date2", startDate), Expr.or(Expr.ge("end_date2", endDate), Expr.isNull("end_date2"))) ), // Third period Expr.and( Expr.le("start_date3", startDate), Expr.or(Expr.ge("end_date3", endDate), Expr.isNull("end_date3"))) ) ) .findList(); } private List<OrderModel> getInactiveOrders(DateTime startDate, DateTime endDate) { return OrderModel.find.where() .or( Expr.or( Expr.isNotNull("deleted"), Expr.isNull("start_date1")), Expr.and( Expr.and( // First period Expr.or(Expr.gt("start_date1", startDate), (Expr.lt("end_date1", endDate))), // Second period Expr.or( Expr.isNull("start_date2"), Expr.or(Expr.gt("start_date2", startDate), Expr.lt("end_date2", endDate)))), // Third period Expr.or( Expr.isNull("start_date3"), Expr.or(Expr.gt("start_date3", startDate), Expr.lt("end_date3", endDate))))) .findList(); } }