package entity.prescription; import entity.building.Station; import entity.info.Resident; import entity.info.ResidentTools; import entity.system.SYSPropsTools; import op.OPDE; import op.tools.Pair; import op.tools.SYSCalendar; import op.tools.SYSConst; import op.tools.SYSTools; import org.apache.commons.collections.Closure; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.LocalDate; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.NoResultException; import javax.persistence.Query; import javax.swing.*; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; /** * Created by IntelliJ IDEA. * User: tloehr * Date: 18.11.11 * Time: 14:28 * To change this template use File | Settings | File Templates. */ public class MedStockTools { // public static boolean apvNeuberechnung = true; public static final int STATE_NOTHING = 0; public static final int STATE_WILL_BE_CLOSED_SOON = 10; // These modes work only in the beginning of the lifecyle of a new TradeForm. When the first stock (UPRn) is added, then its not yet clear which UPR to assume // so its always a dummy UPR which is replaced by the first calculated effective UPR when closing this first package. // This is also needed when fiddling with the UPRs afterwards in order to correct awkward values. public static final int ADD_TO_AVERAGES_UPR_WHEN_CLOSING = 0; public static final int REPLACE_WITH_EFFECTIVE_UPR_WHEN_CLOSING = 1; public static final int REPLACE_WITH_EFFECTIVE_UPR_WHEN_FIRST_STOCK_OF_THIS_KIND_IS_CLOSING = 2; // #16 public static final int DONT_REPLACE_UPR = 3; public static final int DAYS_TO_EXPIRE_SOON = 5; public static ListCellRenderer getBestandOnlyIDRenderer() { return (jList, o, i, isSelected, cellHasFocus) -> { String text; if (o == null) { text = "<i>Keine Auswahl</i>"; //SYSTools.toHTML("<i>Keine Auswahl</i>"); } else if (o instanceof MedStock) { text = ((MedStock) o).getID().toString(); } else { text = o.toString(); } return new DefaultListCellRenderer().getListCellRendererComponent(jList, text, i, isSelected, cellHasFocus); }; } public static List<MedStock> getAll(MedInventory inventory) { EntityManager em = OPDE.createEM(); String jpql = " " + " SELECT b FROM MedStock b " + " WHERE b.inventory = :inventory " + " ORDER BY b.in, b.id "; Query query = em.createQuery(jpql); query.setParameter("inventory", inventory); List<MedStock> list = query.getResultList(); em.close(); return list; } public static List<MedStock> getAllWeightControlled(LocalDate from, LocalDate to) { EntityManager em = OPDE.createEM(); String jpql = " " + " SELECT b FROM MedStock b " + " WHERE b.tradeform.weightControlled = TRUE " + " AND b.in >= :from AND b.opened >= :from AND b.opened <= :to " + " ORDER BY b.inventory.resident.rid, b.id "; Query query = em.createQuery(jpql); query.setParameter("from", from.toDateTimeAtStartOfDay().toDate()); query.setParameter("to", SYSCalendar.eod(to).toDate()); List<MedStock> list = query.getResultList(); em.close(); return list; } public static MedStock getStockInUse(MedInventory inventory) { EntityManager em = OPDE.createEM(); String jpql = " " + " SELECT b FROM MedStock b " + " WHERE b.inventory = :inventory " + " AND b.opened < :tfn AND b.out = :tfn"; Query query = em.createQuery(jpql); query.setParameter("inventory", inventory); query.setParameter("tfn", SYSConst.DATE_UNTIL_FURTHER_NOTICE); List<MedStock> list = query.getResultList(); em.close(); return list.isEmpty() ? null : list.get(0); } // /** // * Sucht aus den den Beständen des Vorrats den angebrochenen heraus. // * // * @param inventory // * @return der angebrochene Bestand. null, wenn es keinen gab. // */ // public static MedStock getStockInUse(MedInventory inventory) { // MedStock bestand = null; // // if (inventory != null && inventory.getMedStocks() != null) { // Iterator<MedStock> itBestand = inventory.getMedStocks().iterator(); // while (itBestand.hasNext()) { // MedStock b = itBestand.next(); // if (b.isOpened() && !b.isClosed()) { // bestand = b; // break; // } // } // } // return bestand; // } public static HashMap getStock4Printing(MedStock bestand) { OPDE.debug("StockID: " + bestand.getID()); HashMap hm = new HashMap(); hm.put("medstock.tradeform", TradeFormTools.toPrettyString(bestand.getTradeForm())); String pzn = bestand.getPackage() == null ? "??" : bestand.getPackage().getPzn(); hm.put("medstock.package.pzn", pzn); hm.put("medstock.id", bestand.getID()); hm.put("medstock.in", bestand.getIN()); // stock expires hm.put("medstock.expires", bestand.getExpires()); // expires after being opened if (bestand.getTradeForm().getDaysToExpireAfterOpened() == null) { hm.put("medstock.tradeform.expires.after.opened", null); } else { int days = bestand.getTradeForm().getDaysToExpireAfterOpened(); int weeks = 0; if (days >= 7) { weeks = days / 7; } String exp = weeks > 0 ? weeks + SYSTools.xx("misc.msg.weeks").substring(0, 1).toUpperCase() : days + SYSTools.xx("misc.msg.Days").substring(0, 1).toUpperCase(); hm.put("medstock.tradeform.expires.after.opened", "!!" + exp); } hm.put("medstock.usershort", bestand.getUser().getUID()); hm.put("medstock.userlong", bestand.getUser().getFullname()); hm.put("medstock.inventory.resident.name", ResidentTools.getNameAndFirstname(bestand.getInventory().getResident())); hm.put("medstock.inventory.resident.dob", bestand.getInventory().getResident().getDOB()); hm.put("medstock.inventory.resident.id", bestand.getInventory().getResident().getRIDAnonymous()); return hm; } public static BigDecimal getSum(MedStock stock) { BigDecimal result = BigDecimal.ZERO; for (MedStockTransaction buchung : stock.getStockTransaction()) { result = result.add(buchung.getAmount()); } return result; } /** * gets the sum of doses in the BHP (note: this figure is in usage unit) * * @param medStock * @return */ public static BigDecimal getSumOfDosesInBHP(MedStock medStock) { BigDecimal result = BigDecimal.ZERO; for (MedStockTransaction tx : medStock.getStockTransaction()) { if (!tx.isPartOfCancelPair() && tx.isBHP()) { result = result.add(tx.getBhp().getDose()); } } return result; } /** * Ermittelt die Menge, die in einer Packung noch enthalten ist. * * @param stock die entsprechende Packung * @return die Summe in der Packungs Einheit. */ public static BigDecimal getSum(EntityManager em, MedStock stock) throws Exception { BigDecimal result; // OPDE.debug("BestID: " + stock.getID()); Query query = em.createQuery(" " + " SELECT SUM(tx.amount) " + " FROM MedStock st " + " JOIN st.stockTransaction tx " + " WHERE st = :stock "); try { query.setParameter("stock", stock); result = (BigDecimal) query.getSingleResult(); } catch (NoResultException nre) { result = BigDecimal.ZERO; } return result; } /** * This method closes the given MedStock. It forces the current balance to zero by adding a system MedStockTransaction * to the existing list of TXs. * <p> * If there is a next package to be used, it will be opened. * <p> * If there are prescription (valid until the end of this package) there will be closed, too, unless * there are still unused packages in this inventory. * * @param em persistence context to be used * @param medStock to be closed * @param text for the closing TX * @param state of the closing TX * @return if there is a nextStock to be opened after this one, it will be returned here. NULL otherwise. * @throws Exception */ public static MedStock close(EntityManager em, MedStock medStock, String text, short state) throws Exception { MedStock nextStock = null; BigDecimal stocksum = getSum(medStock); MedStockTransaction finalTX = new MedStockTransaction(medStock, stocksum.negate(), state); finalTX.setText(text); medStock.getStockTransaction().add(finalTX); medStock.setState(MedStockTools.STATE_NOTHING); DateTime now = new DateTime(); medStock.setOut(now.toDate()); BigDecimal effectiveUPR = getEffectiveUPR(medStock); if (medStock.getTradeForm().getDosageForm().isUPRn()) { if (medStock.getTradeForm().getConstantUPRn() == null) { // dynamic UPRn if (medStock.getUPRDummyMode() == ADD_TO_AVERAGES_UPR_WHEN_CLOSING) { if (effectiveUPR.compareTo(BigDecimal.ZERO) > 0) { // if this stock was never used the effective UPR must be 0. we must handle this case separately // if the deviation was too high (usually more than 20%), then the new UPR is discarded BigDecimal maxDeviation = SYSTools.parseDecimal(OPDE.getProps().getProperty(SYSPropsTools.KEY_CALC_MEDI_UPR_CORRIDOR)); BigDecimal deviation = medStock.getUPR().divide(effectiveUPR, 4, BigDecimal.ROUND_HALF_UP).subtract(new BigDecimal(100)).abs(); OPDE.debug("the deviation was: " + deviation + "%"); // if the deviation is below the limit, then the new UPR will be accepted. // it must also be greater than 0 if (deviation.compareTo(maxDeviation) <= 0 && effectiveUPR.compareTo(BigDecimal.ZERO) > 0) { OPDE.debug("acceptable"); medStock.setUPR(effectiveUPR); } else { OPDE.debug("discarded"); } } else { OPDE.debug("effective UPR is 0 or less. new UPR discarded"); } } else if (medStock.getUPRDummyMode() == REPLACE_WITH_EFFECTIVE_UPR_WHEN_CLOSING) { medStock.setUPR(effectiveUPR); medStock.setUPRDummyMode(ADD_TO_AVERAGES_UPR_WHEN_CLOSING); // will be part of the calculation in future // https://github.com/tloehr/Offene-Pflege.de/issues/16 // todo: nicht nur die eignen Stocks ändern (also innerhalb des Inventories), sondern auch für alle anderen BW, bei denen APV auch noch nicht feststeht. for (MedStock dependantStocks : medStock.getInventory().getMedStocks()) { if (dependantStocks.getUPRDummyMode() == REPLACE_WITH_EFFECTIVE_UPR_WHEN_FIRST_STOCK_OF_THIS_KIND_IS_CLOSING) { dependantStocks.setUPR(effectiveUPR); dependantStocks.setUPRDummyMode(ADD_TO_AVERAGES_UPR_WHEN_CLOSING); } } } } } medStock.setUPREffective(effectiveUPR); if (medStock.hasNext2Open()) { nextStock = medStock.getNextStock(); nextStock.setOpened(now.plusSeconds(1).toDate()); OPDE.debug("NextStock: " + medStock.getNextStock().getID() + " will be opened now"); } else { // Nothing to open next ? // Are there still stocks in this inventory ? if (MedInventoryTools.getNextToOpen(medStock.getInventory()) == null) { // No ?? // Are there any prescriptions that needs to be closed now, because of the empty package ? for (Prescription prescription : PrescriptionTools.getPrescriptionsByInventory(medStock.getInventory())) { if (prescription.isUntilEndOfPackage()) { prescription = em.merge(prescription); em.lock(prescription, LockModeType.OPTIMISTIC); prescription.setTo(new Date()); prescription.setUserOFF(em.merge(OPDE.getLogin().getUser())); prescription.setDocOFF(prescription.getDocON()); prescription.setHospitalOFF(prescription.getHospitalON()); } } } } return nextStock; } public static MedStockTransaction getStartTX(MedStock medStock) { MedStockTransaction result = null; for (MedStockTransaction buchung : MedStockTransactionTools.getAll(medStock)) { if (buchung.getState() == MedStockTransactionTools.STATE_CREDIT) { result = buchung; break; } } return result; } /** * Diese Methode bucht auf einen Bestand immer genau soviel drauf oder runter, damit er auf * dem gewünschten soll landet. * * @param bestand um die es geht. * @param soll gewünschter Endbestand * @param em EntityManager in dessen Kontext das ganze abläuft * @param text für die Buchung * @param status für die Buchung * @return die Korrektur Buchung * @throws Exception */ public static MedStockTransaction setStockTo(EntityManager em, MedStock bestand, BigDecimal soll, String text, short status) throws Exception { MedStockTransaction result = null; bestand = em.merge(bestand); BigDecimal bestandSumme = getSum(em, bestand); if (!bestandSumme.equals(soll)) { BigDecimal korrektur; if (bestandSumme.compareTo(BigDecimal.ZERO) <= 0) { korrektur = bestandSumme.abs().add(soll); } else { korrektur = bestandSumme.negate().add(soll); } // passende Buchung anlegen. result = em.merge(new MedStockTransaction(bestand, korrektur, status)); result.setText(text); } return result; } public static String getTextASHTML(MedStock bestand) { String result = ""; result += "<font color=\"blue\"><b>" + bestand.getTradeForm().getMedProduct().getText() + " " + bestand.getTradeForm().getSubtext() + ", "; if (bestand.getPackage() != null && !SYSTools.catchNull(bestand.getPackage().getPzn()).isEmpty()) { result += SYSTools.xx("misc.msg.PZN") + ": " + bestand.getPackage().getPzn() + ", "; result += MedPackageTools.GROESSE[bestand.getPackage().getSize()] + ", " + bestand.getPackage().getContent() + " " + SYSConst.UNITS[bestand.getTradeForm().getDosageForm().getPackUnit()] + " "; String zubereitung = SYSTools.catchNull(bestand.getTradeForm().getDosageForm().getPreparation()); String anwtext = SYSTools.catchNull(bestand.getTradeForm().getDosageForm().getUsageText()); result += zubereitung.equals("") ? anwtext : (anwtext.equals("") ? zubereitung : zubereitung + ", " + anwtext); result += "</b></font>"; } return result; } public static String getAsHTML(MedStock stock) { String result = ""; String htmlcolor = stock.isClosed() ? "gray" : "red"; result += "<font face =\"" + SYSConst.ARIAL14.getFamily() + "\">"; result += "<font color=\"" + htmlcolor + "\"><b><u>" + stock.getID() + "</u></b></font>  "; result += TradeFormTools.toPrettyString(stock.getTradeForm()); if (stock.hasPackage()) { result += ", " + MedPackageTools.toPrettyString(stock.getPackage()); } if (stock.getTradeForm().getDosageForm().isUPRn()) { result += ", APV: "; if (stock.getTradeForm().getConstantUPRn() != null) { result += SYSTools.formatBigDecimal(stock.getTradeForm().getConstantUPRn().setScale(2, RoundingMode.HALF_UP)) + " (" + SYSTools.xx("upreditor.constant.upr") + ")"; } else { result += SYSTools.formatBigDecimal(stock.getUPR().setScale(2, RoundingMode.HALF_UP)); } result += " " + (stock.getUPRDummyMode() == REPLACE_WITH_EFFECTIVE_UPR_WHEN_CLOSING && stock.getTradeForm().getConstantUPRn() != null ? SYSTools.xx("nursingrecords.inventory.UPRwillBeReplaced") : ""); } if (stock.hasNext2Open()) { result += ", <b>" + SYSTools.xx("nursingrecords.inventory.nextstock") + ": " + stock.getNextStock().getID() + "</b>"; } else if (stock.isToBeClosedSoon()) { result += ", <b>" + SYSTools.xx("nursingrecords.inventory.stockWillBeClosedSoon") + "</b>"; } DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); result += " <font color=\"blue\">" + SYSTools.xx("misc.msg.incoming") + ": " + df.format(stock.getIN()) + "</font>"; if (stock.isOpened()) { result += " <font color=\"green\">" + SYSTools.xx("misc.msg.opening") + ": " + df.format(stock.getOpened()) + "</font>"; // variable expiry ? if (stock.getTradeForm().getDaysToExpireAfterOpened() != null) { String color = stock.isExpired() ? "red" : "black"; result += " <font color=\"" + color + "\">" + SYSTools.xx("misc.msg.expiresAfterOpened") + ": " + df.format(new DateTime(stock.getOpened()).plusDays(stock.getTradeForm().getDaysToExpireAfterOpened()).toDate()) + "</font>"; } } // fixed expiry ? if (stock.getExpires() != null && !stock.isClosed()) { DateFormat sdf = df; // if expiry is at the end of a month then it has a different format if (new LocalDate(stock.getExpires()).equals(new LocalDate(stock.getExpires()).dayOfMonth().withMaximumValue())) { sdf = new SimpleDateFormat("MM/yy"); } result += " <font color=\"" + getHTMLColor(stock) + "\">" + SYSTools.xx("misc.msg.expires") + ": " + sdf.format(stock.getExpires()) + "</font>"; } if (stock.isClosed()) { result += SYSConst.html_bold(" <font color=\"black\">" + SYSTools.xx("misc.msg.outgoing") + ": " + df.format(stock.getOut()) + "</font>"); } result += "</font>"; return result; } // public static String getCompactHTML(MedStock stock) { // String result = ""; // result += "<b>" + stock.getID() + "</b> "; // result += TradeFormTools.toPrettyString(stock.getTradeForm()); // // if (stock.hasPackage()) { // result += ", " + MedPackageTools.toPrettyString(stock.getPackage()); // } // result += ", APV: " + NumberFormat.getNumberInstance().format(stock.getConstantUPRn()) + " " + (stock.isDummyUPR() ? SYSTools.xx(PnlInventory.internalClassID + ".UPRwillBeReplaced") : ""); // return result; // } // public static void open(EntityManager em, MedStock stock) { // MedStock myStock = em.merge(stock); // myStock.setOpened(new Date()); // } // public static MedStock getPreviousStock(MedStock fromThisOne) { // MedInventory inventory = fromThisOne.getInventory(); // Collections.sort(inventory.getMedStocks()); // int index = inventory.getMedStocks().indexOf(fromThisOne); // MedStock previous = null; // if (index > 0) { // previous = inventory.getMedStocks().get(index - 1); // } // return previous; // } public static String getListForMedControl(Station station, Closure progress) { StringBuilder html = new StringBuilder(1000); int p = -1; progress.execute(new Pair<Integer, Integer>(p, 100)); Resident prevResident = null; EntityManager em = OPDE.createEM(); String jpql = " " + " SELECT b FROM MedStock b " + " WHERE b.inventory.resident.station = :station AND b.inventory.resident.adminonly <> 2 " + " AND b.opened < :opened AND b.out = :tfn " + " ORDER BY b.inventory.resident.name, b.inventory.resident.firstname, b.inventory.text, b.opened "; Query query = em.createQuery(jpql); query.setParameter("opened", new Date()); query.setParameter("tfn", SYSConst.DATE_UNTIL_FURTHER_NOTICE); query.setParameter("station", station); List<MedStock> list = query.getResultList(); em.close(); StringBuilder table = new StringBuilder(1000); DateFormat df = DateFormat.getDateInstance(); html.append(SYSConst.html_h1("opde.controlling.drugs.controllist")); html.append(SYSConst.html_h2(SYSTools.xx("misc.msg.subdivision") + ": " + station.getName())); html.append(SYSConst.html_h3("misc.msg.key")); html.append(SYSConst.html_ul( SYSConst.html_li("opde.controlling.drugs.controllist.key.1") + SYSConst.html_li("opde.controlling.drugs.controllist.key.2") + SYSConst.html_li("opde.controlling.drugs.controllist.key.3") + SYSConst.html_li("opde.controlling.drugs.controllist.key.4") + SYSConst.html_li("opde.controlling.drugs.controllist.key.5") + SYSConst.html_li("opde.controlling.drugs.controllist.key.6") + SYSConst.html_li("opde.controlling.drugs.controllist.key.7") + SYSConst.html_li("opde.controlling.drugs.controllist.key.8") )); table.append(SYSConst.html_table_tr( SYSConst.html_table_th("misc.msg.resident") + SYSConst.html_table_th("nursingrecords.inventory.search.stockid") + SYSConst.html_table_th("misc.msg.medication") + SYSConst.html_table_th("misc.msg.opened") + SYSConst.html_table_th("#1") + SYSConst.html_table_th("#2") + SYSConst.html_table_th("#3") + SYSConst.html_table_th("#4") + SYSConst.html_table_th("#5") + SYSConst.html_table_th("#6") + SYSConst.html_table_th("#7") + SYSConst.html_table_th("#8") )); p = 0; int zebra = 0; for (MedStock bestand : list) { progress.execute(new Pair<Integer, Integer>(p, list.size())); p++; if (prevResident != bestand.getInventory().getResident()) { zebra++; prevResident = bestand.getInventory().getResident(); } table.append(SYSConst.html_table_tr( SYSConst.html_table_td(ResidentTools.getTextCompact(bestand.getInventory().getResident())) + SYSConst.html_table_td(bestand.getID().toString()) + SYSConst.html_table_td(TradeFormTools.toPrettyString(bestand.getTradeForm())) + SYSConst.html_table_td(df.format(bestand.getOpened())) + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") + SYSConst.html_table_td(" ") , zebra % 2 == 0)); } html.append(SYSConst.html_table(table.toString(), "1")); return html.toString(); } /** * This method calculates the effective UPR as it acually was during the lifetime of that particular medstock. * It is vital, that this calculation is only done, when a package is empty. Otherwise the estimation * of the UPR is wrong. * <p> * Stichwort: berechnetes APVn * * @param medstock, für den das Verhältnis neu berechnet werden soll. */ public static BigDecimal getEffectiveUPR(MedStock medstock) { if (medstock.getTradeForm().getDosageForm().isUPR1()) { return BigDecimal.ONE; } if (medstock.getTradeForm().getConstantUPRn() != null) { return medstock.getTradeForm().getConstantUPRn(); } OPDE.debug("<--- recalculateUPR "); OPDE.debug("MedStock ID: " + medstock.getID()); // this is the amount of content, which was in that package before it was opened // package unit BigDecimal startContent = MedStockTools.getStartTX(medstock).getAmount(); // usage unit BigDecimal theoreticalSum = MedStockTools.getSumOfDosesInBHP(medstock); // Die Gaben aus der BHP sind immer in der Anwendungseinheit. Teilt man diese durch das // verwendete APV, erhält man das was rechnerisch in der Packung drin gewesen // sein soll. Das kann natürlich von dem realen Inhalt abweichen. Klebt noch was an // der Flaschenwand oder wurde was verworfen. Das APV steht ja für Anzahl der Anwendung im // Verhaltnis zur Packungseinheit 1. Wurden 100 Tropfen gegeben, bei einem APV von 20(:1) // Dann ergibt das einen rechnerischen Flascheninhalt von 5 ml. // The doses of the applications which have been calculated by the BHPs equals the usage unit. // // When a package is empty, we know two things for sure: // 1. The startContent has been completely used up // 2. the sum of all applications (theoreticalSum) is what we've got really out of the bottle // // hence the effective UPR must have been // // the sum of all applications in the usage unit // effective UPR = -------------------------------------------- // the startContent in the package unit // BigDecimal effectiveUPR = theoreticalSum.divide(startContent, 4, BigDecimal.ROUND_UP); return effectiveUPR; } /** * calculates a starting UPR for a newly opened stock. If there is no UPR yet, it creates a new one and marks it as dummy, * so it will be replaced by the first calculated result, when this package is closed. * For DosageForms with type STATE_UPR1, there is no calculation at all. Those values are constantly 1. */ public static BigDecimal getEstimatedUPR(TradeForm tradeForm) { OPDE.debug("<--- calcProspectiveUPR"); BigDecimal upr = null; if (tradeForm.getDosageForm().getUPRState() == DosageFormTools.STATE_DONT_CALC) { OPDE.debug("STATE_DONT_CALC"); // no calculation for gel or ointments. they wont work out anyways. upr = BigDecimal.ONE;// getEstimatedUPR_BY_RESIDENT(tradeForm, resident); } else if (tradeForm.getDosageForm().getUPRState() == DosageFormTools.STATE_UPRn) { OPDE.debug("STATE_UPRn"); if (tradeForm.getConstantUPRn() != null) { // there is a constant UPR defined for that tradeform // so there is no estimation necessary upr = tradeForm.getConstantUPRn(); OPDE.debug("constant UPRn"); } else { EntityManager em = OPDE.createEM(); try { Query query = em.createQuery("SELECT AVG(s.upr) FROM MedStock s WHERE s.tradeform = :tradeform AND s.uprDummyMode = :dummymode "); query.setParameter("dummymode", ADD_TO_AVERAGES_UPR_WHEN_CLOSING); query.setParameter("tradeform", tradeForm); Object result = query.getSingleResult(); if (result == null) { upr = BigDecimal.ONE; OPDE.debug("calculated UPRn. first of its kind. UPR: 1"); } else if (result instanceof Double) { upr = new BigDecimal((Double) result); } else { upr = (BigDecimal) query.getSingleResult(); } if (upr.equals(BigDecimal.ZERO)) { upr = BigDecimal.ONE; } upr = upr.setScale(2, BigDecimal.ROUND_HALF_UP); OPDE.debug("calculated UPRn. average so far: " + SYSTools.formatBigDecimal(upr)); } catch (NoResultException nre) { upr = BigDecimal.ONE; } catch (Exception e) { OPDE.fatal(e); } finally { em.close(); } } } else { OPDE.debug("STATE_UPR1"); upr = BigDecimal.ONE; } OPDE.debug("upr: " + upr); OPDE.debug("calcProspectiveUPR --->"); return upr; } public static boolean isNoStockYetForThis(TradeForm tradeForm) { Integer count = null; EntityManager em = OPDE.createEM(); try { Query query = em.createQuery("SELECT COUNT(s.upr) FROM MedStock s WHERE s.tradeform = :tradeform AND s.uprDummyMode = :dummymode "); query.setParameter("dummymode", ADD_TO_AVERAGES_UPR_WHEN_CLOSING); query.setParameter("tradeform", tradeForm); Object result = query.getSingleResult(); if (result == null) { count = 0; } else if (result instanceof Long) { count = ((Long) result).intValue(); } else { count = (Integer) query.getSingleResult(); } } catch (NoResultException nre) { count = 0; } catch (Exception e) { OPDE.fatal(e); } finally { em.close(); } return count == 0; } /** * this method returns true, when a given tradeform is still busy with it's first stock, and this stock is a UPRn one. This effective UPR cannot be calculated yet. * That first stock is still open. * * @param tradeForm * @return */ public static boolean stillWorkingOnTheFirstOneToCalculateUPRn(TradeForm tradeForm) { Integer count = null; EntityManager em = OPDE.createEM(); try { Query query = em.createQuery("SELECT COUNT(s.upr) FROM MedStock s WHERE s.tradeform = :tradeform AND s.uprDummyMode = :dummymode "); query.setParameter("dummymode", REPLACE_WITH_EFFECTIVE_UPR_WHEN_CLOSING); query.setParameter("tradeform", tradeForm); Object result = query.getSingleResult(); if (result == null) { count = 0; } else if (result instanceof Long) { count = ((Long) result).intValue(); } else { count = (Integer) query.getSingleResult(); } } catch (NoResultException nre) { count = 0; } catch (Exception e) { OPDE.fatal(e); } finally { em.close(); } return count == 1; } public static List<MedStock> getExpiryList(int days) { ArrayList<MedStock> list = new ArrayList<MedStock>(); EntityManager em = OPDE.createEM(); Query query1 = em.createQuery("SELECT s FROM MedStock s WHERE s.expires IS NOT NULL AND s.out = :tfn "); query1.setParameter("tfn", SYSConst.DATE_UNTIL_FURTHER_NOTICE); HashSet<MedStock> set = new HashSet<MedStock>(query1.getResultList()); Query query2 = em.createQuery("SELECT s FROM MedStock s JOIN s.tradeform t WHERE t.daysToExpireAfterOpened IS NOT NULL AND s.out = :tfn AND s.opened < :now"); query2.setParameter("tfn", SYSConst.DATE_UNTIL_FURTHER_NOTICE); query2.setParameter("now", new Date()); set.addAll(query2.getResultList()); for (MedStock stock : set) { if (stock.expiresIn(days)) { list.add(stock); } } set.clear(); em.close(); return list; } public static StringBuilder getNarcoticsWeightList(LocalDate from, LocalDate to) throws Exception { StringBuilder html = new StringBuilder(10000); ArrayList<MedStock> listStocks = new ArrayList<>(getAllWeightControlled(from, to)); DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT); // int p = -1; // progress.execute(new Pair<Integer, Integer>(p, 100)); html.append(SYSConst.html_h1("opde.controlling.prescription.narcotics.weightcontrol")); if (listStocks.isEmpty()) { html.append(SYSConst.html_italic("opde.controlling.prescription.narcotics.no.weightcontrols")); } else { listStocks.forEach(stock -> { html.append(SYSConst.html_h2("[" + stock.getID() + "] " + getAsHTML(stock) + ", " + ResidentTools.getLabelText(stock.getInventory().getResident()))); final StringBuffer tableContent = new StringBuffer(SYSConst.html_table_tr(SYSConst.html_table_th("Zeit") + SYSConst.html_table_th("Gewicht") + SYSConst.html_table_th("Diff-Gewicht") + SYSConst.html_table_th("Menge") + SYSConst.html_table_th("Diff-Menge") + SYSConst.html_table_th("Verhältnis"))); ArrayList<MedStockTransaction> listStockTransactions = new ArrayList<MedStockTransaction>(stock.getStockTransaction()); Collections.sort(listStockTransactions, (o1, o2) -> o1.getPit().compareTo(o2.getPit())); boolean iamthefirstone = true; BigDecimal previousWeight = BigDecimal.ZERO; BigDecimal previousQuantity = BigDecimal.ZERO; for (MedStockTransaction tx : listStockTransactions) { BigDecimal weight = tx.getWeight(); BigDecimal quantity = previousQuantity.add(tx.getAmount()); BigDecimal diffQuantity = previousQuantity.subtract(quantity); BigDecimal diffWeight = previousWeight.subtract(weight); BigDecimal quota = iamthefirstone ? BigDecimal.ZERO : diffWeight.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : diffQuantity.divide(diffWeight, 2, RoundingMode.HALF_UP); tableContent.append(SYSConst.html_table_tr( SYSConst.html_table_td(df.format(tx.getPit())) + SYSConst.html_table_td(SYSTools.formatBigDecimal(weight) + SYSConst.html_table_td(iamthefirstone ? "--" : SYSTools.formatBigDecimal(diffWeight)) + SYSConst.html_table_td(SYSTools.formatBigDecimal(quantity)) + SYSConst.html_table_td(iamthefirstone ? "--" : SYSTools.formatBigDecimal(diffQuantity)) + SYSConst.html_table_td(quota.compareTo(BigDecimal.ZERO) == 0 ? "--" : SYSTools.formatBigDecimal(quota)) ) )); previousWeight = weight; previousQuantity = quantity; iamthefirstone = false; } html.append(SYSConst.html_table(tableContent.toString(), "1")); }); } return html; } public static String getHTMLColor(MedStock stock) { String color; if (stock.isExpired()) color = "red"; else if (stock.expiresIn(DAYS_TO_EXPIRE_SOON)) color = "orange"; else color = "black"; return color; } }