package models; import com.fasterxml.jackson.annotation.JsonBackReference; import exceptions.PoseidonException; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import play.mvc.Http; import service.PoseidonService; import javax.persistence.*; import java.util.Date; import java.util.List; import java.util.Set; import java.util.TreeSet; @Entity @Table(name = "POS_ORDER") public class OrderModel extends AuditedModel { private final static Logger logger = LoggerFactory.getLogger(OrderModel.class); public static Finder<Long, OrderModel> find = new Finder<>(OrderModel.class); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; @Column(unique = true) public String met_ref; public String custref_po_calloff; public String custref_contractnum; public String custref_email; public String customer_name; public String customer_email; public String customer_phone; public Date start_date1; public Integer start_termin1; public Date end_date1; public Integer end_termin1; public String termins1; // comma-separated list of termin values, eg 0,3,6,18,21 public Date start_date2; public Integer start_termin2; public Date end_date2; public Integer end_termin2; public String termins2; public Date start_date3; public Integer start_termin3; public Date end_date3; public Integer end_termin3; public String termins3; public boolean startup_fee; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID") @JsonBackReference public ProductModel product; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "POSITION_ID", referencedColumnName = "ID") @JsonBackReference public PositionModel position; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "ID") @JsonBackReference public CustomerModel customer; public String position_name; @Column(name = "task_description") public String taskDescription; @ManyToMany(mappedBy = "orders", cascade = CascadeType.PERSIST) public List<RecipientModel> recipients; @Column(columnDefinition = "TEXT") public String info_for_meteorologist; @Column(columnDefinition = "TEXT") public String other_info; @Transient public OrderStatus orderStatus; public void assignStatus(DateTime now) { orderStatus = null; if (isDeleted()) { orderStatus = OrderStatus.DELETED; } else if (isNew(now)) { orderStatus = OrderStatus.NEW; } else if (isExpired(now)) { orderStatus = OrderStatus.EXPIRED; } else if (isDormant(now)) { orderStatus = OrderStatus.DORMANT; } else if (isActiveNow(now)) { orderStatus = OrderStatus.ACTIVE; } } public Date findEndDate() { if (start_date3 != null && end_date3 == null) return null; // no end if (start_date3 == null && start_date2 != null && end_date2 == null) return null; // no end if (start_date2 == null && start_date1 != null && end_date1 == null) return null; if (end_date3 != null) return end_date3; if (end_date2 != null) return end_date2; if (end_date1 != null) return end_date1; return null; } /** * Returns the set of Termins an order is active for a particular day * * @param date * @return */ public Set<Integer> getActiveTerminsForDayContainingTimestamp(DateTime date) { logger.info("start getActiveTerminsForDayContainingTimestamp()"); DateTime startOfDay = date.withTimeAtStartOfDay(); logger.info("isActiveToday {}", isActiveToday(startOfDay)); if (!isActiveToday(startOfDay)) { return null; } else { Set<Integer> result = null; DateTimeZone tz = PoseidonService.getTimeZone(); DateTime start1 = new DateTime(start_date1, tz).withTimeAtStartOfDay(); DateTime start2 = new DateTime(start_date2, tz).withTimeAtStartOfDay(); DateTime start3 = new DateTime(start_date3, tz).withTimeAtStartOfDay(); DateTime end1 = new DateTime(end_date1, tz).withTime(23, 0, 0, 0); DateTime end2 = new DateTime(end_date2, tz).withTime(23, 0, 0, 0); DateTime end3 = new DateTime(end_date3, tz).withTime(23, 0, 0, 0); boolean periodIsActiveThisDay = true; Integer startTermin = null; Integer endTermin = null; if (isInPeriod(date, 3)) { result = parseTermins(termins3); if (start3.equals(date) && start_termin3 != null && !result.contains(start_termin3)) { startTermin = start_termin3; } if (end3.equals(date) && end_termin3 != null && !result.contains(end_termin3)) { endTermin = end_termin3; } } else if (isInPeriod(date, 2)) { result = parseTermins(termins2); if (start2.equals(date) && start_termin2 != null && !result.contains(start_termin2)) { startTermin = start_termin2; } if (end2.equals(date) && end_termin2 != null && !result.contains(end_termin2)) { endTermin = end_termin2; } } else if (isInPeriod(date, 1)) { logger.info("isInPeriod(date, 1) = {}", isInPeriod(date, 1)); result = parseTermins(termins1); if (start1.equals(date) && start_termin1 != null && !result.contains(start_termin1)) { startTermin = start_termin1; } if (end1.equals(date) && end_termin1 != null && !result.contains(end_termin1)) { endTermin = end_termin2; } } if ( startTermin != null) result.add(startTermin); if ( endTermin != null) result.add(endTermin); return result; } } public Set<Integer> parseTermins(String terminString) { TreeSet<Integer> result = new TreeSet<>(); if (terminString != null && !terminString.isEmpty()) { String[] terminArray = terminString.split(","); for (int i = 0; i < terminArray.length; i++) { String termin = terminArray[i]; try { Integer terminValue = Integer.parseInt(termin); if (terminValue != null && !result.contains(terminValue)) { result.add(terminValue); } } catch (NumberFormatException nfe) { // ignore logger.warn("Ugyldig verdi for termin {} på ordre {},kan ikke konvertere til integer", termin, id); } } } return result; } /* An order is 'new' until the day delivery starts */ private boolean isNew(DateTime now) { if (start_date1 == null) return false; DateTime start = new DateTime(start_date1, PoseidonService.getTimeZone()).withTimeAtStartOfDay(); return now.isBefore(start); } /* An order is dormant if all delivery periods are unspecified, or if 'now' is outside the start and end of all of the periods */ private boolean isDormant(DateTime now) { boolean dormant = false; DateTimeZone tz = PoseidonService.getTimeZone(); DateTime start1 = start_date1 != null ? new DateTime(start_date1, tz).withTimeAtStartOfDay() : null; DateTime start2 = start_date2 != null ? new DateTime(start_date2, tz).withTimeAtStartOfDay() : null; DateTime start3 = start_date3 != null ? new DateTime(start_date3, tz).withTimeAtStartOfDay() : null; DateTime end1 = end_date1 != null ? new DateTime(end_date1, tz).plusDays(1).withTimeAtStartOfDay(): null; DateTime end2 = end_date2 != null ? new DateTime(end_date2, tz).plusDays(1).withTimeAtStartOfDay(): null; DateTime end3 = end_date3 != null ? new DateTime(end_date3, tz).plusDays(1).withTimeAtStartOfDay(): null; if (start1 == null && start2 == null && start3 == null && end1 == null && end2 == null && end3 == null) { dormant = true; } else if (end1 != null && start2 != null && now.isBefore(start2) && now.isAfter(end1)) { dormant = true; } else if (end2 != null && start3 != null && now.isBefore(start3) && now.isAfter(end2)) { dormant = true; } else if (end1 != null && start1 == null && now.isBefore(end1)) { dormant = true; } else if (end2 != null && start2 == null && now.isBefore(end2)) { dormant = true; } else if (end3 != null && start3 == null && now.isBefore(end3)) { dormant = true; } return dormant; } /* An order is active if 'now' falls within one of the delivery dates. */ private boolean isActiveNow(DateTime now) { boolean active = false; DateTimeZone tz = PoseidonService.getTimeZone(); DateTime start1 = start_date1 != null ? new DateTime(start_date1, tz).withTimeAtStartOfDay() : null; DateTime start2 = start_date2 != null ? new DateTime(start_date2, tz).withTimeAtStartOfDay() : null; DateTime start3 = start_date3 != null ? new DateTime(start_date3, tz).withTimeAtStartOfDay() : null; DateTime end1 = end_date1 != null ? new DateTime(end_date1, tz).plusDays(1).withTimeAtStartOfDay() : null; DateTime end2 = end_date2 != null ? new DateTime(end_date2, tz).plusDays(1).withTimeAtStartOfDay() : null; DateTime end3 = end_date3 != null ? new DateTime(end_date3, tz).plusDays(1).withTimeAtStartOfDay() : null; if (start3 != null && end3 == null && start3.isBefore(now)) active = true; else if (start3 != null && end3 != null && start3.isBefore(now) && end3.isAfter(now)) active = true; else if (start2 != null && end2 == null && start2.isBefore(now)) active = true; else if (start2 != null && end2 != null && start2.isBefore(now) && end2.isAfter(now)) active = true; else if (start1 != null && end1 == null && (start1.isBefore(now) || start1.isEqual(now))) active = true; else if (start1 != null && end1 != null && (start1.isBefore(now) || start1.isEqual(now) && end1.isAfter(now))) active = true; return active; } private boolean isActiveToday(DateTime now) { boolean active = false; DateTimeZone tz = PoseidonService.getTimeZone(); DateTime start1 = new DateTime(start_date1, tz).withTimeAtStartOfDay(); DateTime start2 = new DateTime(start_date2, tz).withTimeAtStartOfDay(); DateTime start3 = new DateTime(start_date3, tz).withTimeAtStartOfDay(); DateTime end1 = new DateTime(end_date1, tz).plusDays(1).withTimeAtStartOfDay(); DateTime end2 = new DateTime(end_date2, tz).plusDays(1).withTimeAtStartOfDay(); DateTime end3 = new DateTime(end_date3, tz).plusDays(1).withTimeAtStartOfDay(); if (start3 != null && end3 == null && start3.isBefore(now)) active = true; else if (start3 != null && end3 != null && (start3.isBefore(now) || start3.isEqual(now)) && end3.isAfter(now)) active = true; else if (start2 != null && end2 == null && (start2.isBefore(now) || start2.isEqual(now))) active = true; else if (start2 != null && end2 != null && (start2.isBefore(now) || (start2.isEqual(now)) && end2.isAfter(now))) active = true; else if (start1 != null && end1 == null && (start1.isBefore(now) || start1.isEqual(now))) active = true; else if (start1 != null && end1 != null && (start1.isBefore(now) || start1.isEqual(now)) && end1.isAfter(now)) active = true; return active; } /* An order is expired if 'now' is after the latest end_date An order is not expired if the last end is unspecified */ private boolean isExpired(DateTime now) { DateTimeZone tz = PoseidonService.getTimeZone(); DateTime end1 = end_date1 != null ? new DateTime(end_date1, tz).plusDays(1).withTimeAtStartOfDay():null; DateTime end2 = end_date2 != null ? new DateTime(end_date2, tz).plusDays(1).withTimeAtStartOfDay():null; DateTime end3 = end_date3 != null ? new DateTime(end_date3, tz).plusDays(1).withTimeAtStartOfDay():null; if (end3 != null && now.isAfter(end3)) return true; if (end2 != null && start_date3 == null && now.isAfter(end2)) return true; if (end1 != null && start_date2 == null && now.isAfter(end1)) return true; return false; } /** * Returns true if an order period is active at the specified point in time * * @param now * @param period 1st, 2nd or 3rd delivery period * @return */ public boolean isInPeriod(DateTime now, int period) { DateTimeZone tz = PoseidonService.getTimeZone(); boolean result = false; DateTime start; DateTime end; switch (period) { case 1: start = start_date1 != null ? new DateTime(start_date1, tz).withTimeAtStartOfDay() : null; end = end_date1 != null ? new DateTime(end_date1, tz).plusDays(1).withTimeAtStartOfDay() : null; break; case 2: start = start_date2 != null ? new DateTime(start_date2, tz).withTimeAtStartOfDay() : null; end = end_date2 != null ? new DateTime(end_date2, tz).plusDays(1).withTimeAtStartOfDay() : null; break; case 3: start = start_date3 != null ? new DateTime(start_date3, tz).withTimeAtStartOfDay() : null; end = end_date3 != null ? new DateTime(end_date3, tz).plusDays(1).withTimeAtStartOfDay() : null; break; default: throw new PoseidonException(Http.Status.INTERNAL_SERVER_ERROR, "Feilen har blitt logget."); } if (start != null) { if (end == null) { result = start.isBefore(now) || start.isEqual(now); } else { result = (start.isBefore(now) || start.isEqual(now)) && end.isAfter(now); } } return result; } public static OrderModel findByMetref(String metref) { return find.fetch("customer").fetch("product").where().ieq("met_ref", metref).findUnique(); } }