package entity.prescription; import entity.info.Resident; import op.OPDE; import op.tools.SYSConst; import op.tools.SYSTools; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.NoResultException; import javax.persistence.Query; import javax.swing.*; import java.awt.*; import java.math.BigDecimal; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; /** * Created by IntelliJ IDEA. * User: tloehr * Date: 18.11.11 * Time: 16:25 * To change this template use File | Settings | File Templates. */ public class MedInventoryTools { public static ListCellRenderer getInventoryRenderer() { return (jList, o, i, isSelected, cellHasFocus) -> { String text; if (o == null) { text = SYSTools.toHTML("<i>Keine Auswahl</i>"); } else if (o instanceof MedInventory) { MedInventory inventory = (MedInventory) o; text = inventory.getText(); } else { text = o.toString(); } return new DefaultListCellRenderer().getListCellRendererComponent(jList, text, i, isSelected, cellHasFocus); }; } public static String getInventoryAsHTML(MedInventory inventory) { String result = ""; String htmlcolor = inventory.isClosed() ? "gray" : "blue"; result += "<font face =\"" + SYSConst.ARIAL14.getFamily() + "\">"; result += "<font color=\"" + htmlcolor + "\"><b><u>" + inventory.getID() + "</u></b></font>  "; result += inventory.getText(); DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); result += "<br/><font color=\"blue\">Eingang: " + df.format(inventory.getFrom()) + "</font>"; if (inventory.isClosed()) { result += "<br/><font color=\"green\">Abschluss: " + df.format(inventory.getTo()) + "</font>"; } result += "</font>"; return result; } // public static BigDecimal getSum(MedInventory inventory) { //// long timeStart = System.currentTimeMillis(); // BigDecimal result = BigDecimal.ZERO; // for (MedStock bestand : inventory.getMedStocks()) { // BigDecimal summe = MedStockTools.getSum(bestand); // result = result.add(summe); // } //// long time2 = System.currentTimeMillis(); //// OPDE.debug("MedInventoryTools.getSumme(): " + (time2 - timeStart) + " millis"); // return result; // } public static BigDecimal getSum(MedInventory inventory) throws Exception { BigDecimal result = BigDecimal.ZERO; for (MedStock stock : inventory.getMedStocks()) { if (!stock.isClosed()) { BigDecimal summe = MedStockTools.getSum(stock); result = result.add(summe); } } return result; } /** * Bucht eine Menge aus einem Vorrat aus, ggf. zugehörig zu einer BHP. Übersteigt die Entnahme-Menge den * Restbestband, dann wird entweder * <ul> * <li>wenn der nächste Bestand <b>nicht</b> bekannt ist (<code>bestand.hasNext2Open() = <b>false</b></code>) → der Bestand trotzdem weiter gebucht. Bis ins negative.</li> * <li>wenn der nächste Bestand <b>doch schon</b> bekannt ist (<code>bestand.hasNext2Open() = <b>true</b></code>) → ein neuer Bestand wird angebrochen.</li> * </ul> * Ist <b>keine</b> Packung im Anbruch, dann wird eine Exception geworfen. Das kann aber eingentlich nicht passieren. Es sei denn jemand hat von Hand * an den Datenbank rumgespielt. * * @param em der EntityManager der verwendet wird * @param quantity die gewünschte Entnahmemenge * @param bhp BHP aufgrund dere dieser Buchungsvorgang erfolgt. */ public static void withdraw(EntityManager em, MedInventory inventory, BigDecimal quantity, BigDecimal weight, BHP bhp) throws Exception { OPDE.debug("withdraw/5: inventory: " + inventory); if (inventory == null) { throw new Exception("No MedStock is currently in use"); } MedStock stock = MedStockTools.getStockInUse(inventory); if (stock.getTradeForm().getDosageForm().isDontCALC()) { OPDE.debug("withdraw/5: no calculation necessary. is ointment or something like that"); return; } if (stock.getTradeForm().getDosageForm().isUPRn()) { BigDecimal upr = stock.getTradeForm().getConstantUPRn() != null ? stock.getTradeForm().getConstantUPRn() : stock.getUPR(); // #16 quantity = quantity.divide(upr, 4, BigDecimal.ROUND_HALF_UP); // GitHub #16 Exception tritt hier auf. Weiter prüfen. } OPDE.debug("withdraw/5: amount: " + quantity); withdraw(em, stock, quantity, weight, bhp); } /** * Bricht von allen geschlossenen das nächste (im Sinne des Einbuchdatums) an. Funktioniert nur bei Vorräten, die z.Zt. keine * angebrochenen Bestände haben. * * @param inventory * @return der neu angebrochene Bestand. null, wenns nicht geklappt hat. */ public static MedStock openNext(MedInventory inventory) { MedStock result = null; java.util.List<MedStock> list = new ArrayList(inventory.getMedStocks()); Collections.sort(list); for (MedStock medStock : list) { if (medStock.getOut().equals(SYSConst.DATE_UNTIL_FURTHER_NOTICE) && medStock.getOpened().equals(SYSConst.DATE_UNTIL_FURTHER_NOTICE)) { medStock.setOpened(new Date()); result = medStock; break; } } return result; } public static BigDecimal getSum(EntityManager em, MedInventory inventory) throws Exception { BigDecimal result = BigDecimal.ZERO; for (MedStock stock : MedStockTools.getAll(inventory)) { if (!stock.isClosed()) { BigDecimal summe = MedStockTools.getSum(em, stock); result = result.add(summe); } } return result; } /** * <ul> * <li><i>If there is more than we need in this package,</i> then we simply withdraw whats needed.</li> * <li><i>We need more than we have in this package,</i> * <ol> * <li><i>but we already know that there is another one to be used.</i> Then we use up the current package, open the next one and take the rest from there.</li> * <li><i>but we dont know about a new one yet.</i> Then we take from the current package, even if we risk a negative balance.</li> * <li><i>and we know, that this package should be the last one.</i> Then we take from the current package, even if we risk a negative balance. The package is closed automatically afterwards.</li> * </ol> * </li> * <li><i>The package contains the exact amount of whats needed,</i> * <ol> * <li><i>and we already know that there is another one to be used.</i> Then we use up the current package and open the next one.</li> * <li><i>but we dont know about a new one yet.</i> Nothing to be done now.</li> * <li><i>and we know, that this package should be the last one.</i> Then we take from the current package, using it up. The package is closed automatically afterwards.</li> * </ol> * </li> * </ul> * * @param em * @param activeStock * @param quantity * @param bhp * @throws Exception */ private static void withdraw(EntityManager em, MedStock activeStock, BigDecimal quantity, BigDecimal weight, BHP bhp) throws Exception { if (quantity.compareTo(BigDecimal.ZERO) < 0) { OPDE.fatal(new NumberFormatException("withdraw/4: negative quantity")); } MedStock stock = em.merge(activeStock); em.lock(stock, LockModeType.OPTIMISTIC); OPDE.debug("withdraw/4: MedStock: " + stock); BigDecimal stockSum = MedStockTools.getSum(stock); // wieviel der angebrochene Bestand noch hergibt. BigDecimal withdrawal = quantity; if (stockSum.compareTo(quantity) < 0 && stock.hasNext2Open()) { withdrawal = stockSum; } // The TX for this turn MedStockTransaction tx = em.merge(new MedStockTransaction(stock, withdrawal.negate(), weight, bhp)); stock.getStockTransaction().add(tx); bhp.getStockTransaction().add(tx); OPDE.debug("withdraw/4: tx: " + tx); if (stockSum.compareTo(quantity) == 0) { if (stock.isToBeClosedSoon()) { MedStockTools.close(em, stock, SYSTools.xx("nursingrecords.prescription.dlgCloseStock.TX.AUTOCLOSED_EMPTY_PACKAGE"), MedStockTransactionTools.STATE_EDIT_EMPTY_NOW); } } else if (stockSum.compareTo(quantity) < 0) { if (!stock.hasNext2Open() && stock.isToBeClosedSoon()) { MedStockTools.close(em, stock, SYSTools.xx("nursingrecords.prescription.dlgCloseStock.TX.AUTOCLOSED_EMPTY_PACKAGE"), MedStockTransactionTools.STATE_EDIT_EMPTY_NOW); } else if (stock.hasNext2Open()) { MedStock nextStock = MedStockTools.close(em, stock, SYSTools.xx("nursingrecords.prescription.dlgCloseStock.TX.AUTOCLOSED_EMPTY_PACKAGE"), MedStockTransactionTools.STATE_EDIT_EMPTY_NOW); withdraw(em, nextStock, quantity.subtract(stockSum), weight, bhp); } } } // /** // * Diese Methode bucht ein Medikament in einen Vorrat ein. // * Dabei wird ein passendes APV ermittelt, eine Buchung angelegt und der neue MedBestand zurück gegeben. // * Der muss dann nur noch persistiert werden. // * // * @param inventory // * @param aPackage // * @param tradeForm // * @param text // * @param menge // * @return // * @throws Exception // */ // public static MedStock addTo(MedInventory inventory, MedPackage aPackage, TradeForm tradeForm, String text, BigDecimal menge) { // MedStock stock = null; // if (menge.compareTo(BigDecimal.ZERO) > 0) { // BigDecimal estimatedUPR = MedStockTools.getEstimatedUPR(tradeForm, inventory.getResident()); // stock = new MedStock(inventory, tradeForm, aPackage, text, estimatedUPR); // MedStockTransaction buchung = new MedStockTransaction(stock, menge); // stock.getStockTransaction().add(buchung); // } // return stock; // } public static MedStock getNextToOpen(MedInventory inventory) { MedStock bestand = null; if (inventory == null) return null; java.util.List<MedStock> listStocks = inventory.getMedStocks(); if (inventory != null && !listStocks.isEmpty()) { for (MedStock myBestand : listStocks) { if (myBestand.isNew()) { bestand = myBestand; break; } } } return bestand; } /** * @param inventory * @return returns the currently opened stock of an inventory. <b>null</b>, if there are no open stocks. */ public static MedStock getCurrentOpened(MedInventory inventory) { MedStock stock = null; java.util.List<MedStock> listStocks = inventory.getMedStocks(); if (!listStocks.isEmpty()) { for (MedStock mystock : listStocks) { if (mystock.isOpened()) { stock = mystock; break; } } } return stock; } public static DosageForm getForm(MedInventory inventory) { DosageForm form = null; try { EntityManager em = OPDE.createEM(); // OPDE.debug("MedInventoryTools.getPrinterForm: inventory: " + inventory.getID()); Query query = em.createQuery(" " + " SELECT tf.dosageForm FROM MedInventory i " + " JOIN i.medStocks s " + " JOIN s.tradeform tf " + " WHERE i = :inventory"); query.setParameter("inventory", inventory); query.setMaxResults(1); form = (DosageForm) query.getSingleResult(); em.close(); } catch (NoResultException nre) { form = null; } catch (Exception e) { OPDE.fatal(e); } return form; } public static ArrayList<MedInventory> getAllActive(Resident resident) { ArrayList<MedInventory> result; EntityManager em = OPDE.createEM(); Query query = em.createQuery("SELECT inv FROM MedInventory inv WHERE inv.resident = :resident AND inv.to = :to AND inv.resident.adminonly <> 2 ORDER BY inv.text"); query.setParameter("resident", resident); query.setParameter("to", SYSConst.DATE_UNTIL_FURTHER_NOTICE); result = new ArrayList<MedInventory>(query.getResultList()); em.close(); return result; } public static ArrayList<MedInventory> getAll(Resident resident) { ArrayList<MedInventory> result; EntityManager em = OPDE.createEM(); Query query = em.createQuery("SELECT inv FROM MedInventory inv WHERE inv.resident = :resident ORDER BY inv.to DESC, inv.text"); query.setParameter("resident", resident); result = new ArrayList<MedInventory>(query.getResultList()); em.close(); return result; } public static void closeAll(EntityManager em, Resident resident, Date enddate) throws Exception { Query query = em.createQuery("SELECT i FROM MedInventory i WHERE i.resident = :resident AND i.to >= :now"); query.setParameter("resident", resident); query.setParameter("now", enddate); java.util.List<MedInventory> inventories = query.getResultList(); for (MedInventory inventory : inventories) { MedInventory myInventory = em.merge(inventory); em.lock(myInventory, LockModeType.OPTIMISTIC); // close all stocks for (MedStock stock : inventory.getMedStocks()) { if (!stock.isClosed()) { MedStock mystock = em.merge(stock); em.lock(mystock, LockModeType.OPTIMISTIC); mystock.setNextStock(null); MedStockTools.close(em, mystock, SYSTools.xx("nursingrecords.inventory.stock.msg.allinvetories.closed"), MedStockTransactionTools.STATE_EDIT_INVENTORY_CLOSED); } } // close inventory myInventory.setTo(enddate); } } }