package ch.elexis.core.data.service; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elexis.core.constants.StringConstants; import ch.elexis.core.data.activator.CoreHub; import ch.elexis.core.data.events.ElexisEventDispatcher; import ch.elexis.core.lock.types.LockResponse; import ch.elexis.core.model.IStock; import ch.elexis.core.model.IStockEntry; import ch.elexis.core.model.article.IArticle; import ch.elexis.core.services.IStockService; import ch.elexis.data.Artikel; import ch.elexis.data.DBConnection; import ch.elexis.data.Mandant; import ch.elexis.data.PersistentObject; import ch.elexis.data.Query; import ch.elexis.data.Stock; import ch.elexis.data.StockEntry; import ch.rgw.tools.ExHandler; /** * Do not create an instance, use {@link CoreHub#getStockService()}. */ public class StockService implements IStockService { private static Logger log = LoggerFactory.getLogger(StockService.class); private static final String PS_SUM_CURRENT = "SELECT SUM(CURRENT) FROM STOCK_ENTRY WHERE ARTICLE_ID = ? AND ARTICLE_TYPE = ? AND DELETED = '0'"; private static final String PS_AVAIL_CURRENT = "SELECT MAX(CASE WHEN CURRENT <= 0 THEN 0 WHEN (ABS(MIN)-CURRENT) >=0 THEN 1 ELSE 2 END) FROM STOCK_ENTRY WHERE ARTICLE_ID = ? AND ARTICLE_TYPE = ? AND DELETED = '0'"; @Override public Integer getCumulatedStockForArticle(IArticle article){ Artikel art = (Artikel) article; DBConnection dbConnection = PersistentObject.getDefaultConnection(); PreparedStatement ps = dbConnection.getPreparedStatement(PS_SUM_CURRENT); try { ps.setString(1, art.getId()); ps.setString(2, art.getClass().getName()); ResultSet res = ps.executeQuery(); Integer ret = null; if (res.next()) { Object object = res.getObject(1); if (object != null) { ret = res.getInt(1); } } res.close(); return ret; } catch (Exception ex) { ExHandler.handle(ex); return null; } finally { try { ps.close(); } catch (SQLException e) {} dbConnection.releasePreparedStatement(ps); } } public void performSingleDisposal(IArticle article, int count){ Mandant mandator = ElexisEventDispatcher.getSelectedMandator(); performSingleDisposal(article, count, (mandator != null) ? mandator.getId() : null); } @Override public IStatus performSingleDisposal(IArticle article, int count, String mandatorId){ if (article == null) { return new Status(Status.ERROR, CoreHub.PLUGIN_ID, "Article is null"); } IStockEntry se = findPreferredStockEntryForArticle(((Artikel) article).storeToString(), mandatorId); if (se == null) { return new Status(Status.WARNING, CoreHub.PLUGIN_ID, "No stock entry for article found"); } if (se.getStock().isCommissioningSystem()) { return CoreHub.getStockCommissioningSystemService().performArticleOutlay(se, count, null); } else { LockResponse lr = CoreHub.getLocalLockService().acquireLockBlocking((StockEntry) se, 1, new NullProgressMonitor()); if (lr.isOk()) { int fractionUnits = se.getFractionUnits(); int ve = article.getSellingUnit(); int vk = article.getPackageUnit(); if (vk == 0) { if (ve != 0) { vk = ve; } } if (ve == 0) { if (vk != 0) { ve = vk; } } int num = count * ve; int cs = se.getCurrentStock(); if (vk == ve) { se.setCurrentStock(cs - count); } else { int rest = fractionUnits - num; while (rest < 0) { rest = rest + vk; se.setCurrentStock(cs - 1); } se.setFractionUnits(rest); } CoreHub.getLocalLockService().releaseLock((StockEntry) se); return Status.OK_STATUS; } } return new Status(Status.WARNING, CoreHub.PLUGIN_ID, "Could not acquire lock"); } public void performSingleReturn(IArticle article, int count){ Mandant mandator = ElexisEventDispatcher.getSelectedMandator(); performSingleReturn(article, count, (mandator != null) ? mandator.getId() : null); } @Override public IStatus performSingleReturn(IArticle article, int count, String mandatorId){ if (article == null) { return new Status(Status.ERROR, CoreHub.PLUGIN_ID, "Article is null"); } IStockEntry se = findPreferredStockEntryForArticle(((Artikel) article).storeToString(), null); if (se == null) { return new Status(Status.WARNING, CoreHub.PLUGIN_ID, "No stock entry for article found"); } if (se.getStock().isCommissioningSystem()) { // updates must happen via manual inputs in the machine return Status.OK_STATUS; } LockResponse lr = CoreHub.getLocalLockService().acquireLockBlocking((StockEntry) se, 1, new NullProgressMonitor()); if (lr.isOk()) { int fractionUnits = se.getFractionUnits(); int ve = article.getSellingUnit(); int vk = article.getPackageUnit(); if (vk == 0) { if (ve != 0) { vk = ve; } } if (ve == 0) { if (vk != 0) { ve = vk; } } int num = count * ve; int cs = se.getCurrentStock(); if (vk == ve) { se.setCurrentStock(cs + count); } else { int rest = fractionUnits + num; while (rest > vk) { rest = rest - vk; se.setCurrentStock(cs + 1); } se.setFractionUnits(rest); } CoreHub.getLocalLockService().releaseLock((StockEntry) se); return Status.OK_STATUS; } return new Status(Status.WARNING, CoreHub.PLUGIN_ID, "Could not acquire lock"); } @Override public Availability getCumulatedAvailabilityForArticle(IArticle article){ Artikel art = (Artikel) article; DBConnection dbConnection = PersistentObject.getDefaultConnection(); PreparedStatement ps = dbConnection.getPreparedStatement(PS_AVAIL_CURRENT); try { ps.setString(1, art.getId()); ps.setString(2, art.getClass().getName()); ResultSet res = ps.executeQuery(); if (res.next()) { Object object = res.getObject(1); if (object != null) { int value = res.getInt(1); if (value > 1) { return Availability.IN_STOCK; } else if (value == 1) { return Availability.CRITICAL_STOCK; } return Availability.OUT_OF_STOCK; } } res.close(); return null; } catch (Exception ex) { ExHandler.handle(ex); return null; } finally { try { ps.close(); } catch (SQLException e) {} dbConnection.releasePreparedStatement(ps); } } public static Availability determineAvailability(IStockEntry se){ String[] values = ((StockEntry) se).get(false, StockEntry.FLD_MIN, StockEntry.FLD_CURRENT); int min = Integer.valueOf(values[0]); int current = Integer.valueOf(values[1]); return IStockService.determineAvailability(current, min); } public List<StockEntry> getAllStockEntries(){ return new Query<StockEntry>(StockEntry.class).execute(); } @Override public IStockEntry findPreferredStockEntryForArticle(String storeToString, String mandatorId){ List<? extends IStockEntry> entries = findAllStockEntriesForArticle(storeToString); int val = Integer.MAX_VALUE; IStockEntry ret = null; for (IStockEntry iStockEntry : entries) { Stock stock = (Stock) iStockEntry.getStock(); Integer priority = stock.getPriority(); if (priority < val) { val = priority; ret = iStockEntry; } if (mandatorId != null) { Mandant owner = stock.getOwner(); if (owner != null && owner.getId().equals(mandatorId)) { return iStockEntry; } } } return ret; } private Artikel loadArticle(String article){ if (article == null) { log.warn("performSingleReturn for null article", new Throwable("Diagnosis")); return null; } PersistentObject po = CoreHub.poFactory.createFromString(article); if (po != null && po instanceof Artikel) { return (Artikel) po; } return null; } public List<Stock> getAllStocks(boolean includeCommissioningSystems){ Query<Stock> qbe = new Query<Stock>(Stock.class); if(!includeCommissioningSystems) { qbe.add(Stock.FLD_DRIVER_UUID, Query.EQUALS, null); } qbe.orderBy(false, Stock.FLD_PRIORITY); return qbe.execute(); } public Availability getArticleAvailabilityForStock(IStock stock, String article){ IStockEntry se = findStockEntryForArticleInStock(stock, article); return IStockService.determineAvailability(se.getCurrentStock(), se.getMinimumStock()); } @Override public IStockEntry findStockEntryForArticleInStock(IStock iStock, String storeToString){ Stock stock = (Stock) iStock; String[] vals = storeToString.split(StringConstants.DOUBLECOLON); Query<StockEntry> qre = new Query<StockEntry>(StockEntry.class); qre.add(StockEntry.FLD_STOCK, Query.EQUALS, stock.getId()); qre.add(StockEntry.FLD_ARTICLE_TYPE, Query.EQUALS, vals[0]); qre.add(StockEntry.FLD_ARTICLE_ID, Query.EQUALS, vals[1]); List<StockEntry> qbe = qre.execute(); if (qbe.isEmpty()) { return null; } return qbe.get(0); } @Override public IStockEntry storeArticleInStock(IStock stock, String article){ IStockEntry stockEntry = findStockEntryForArticleInStock((Stock) stock, article); if (stockEntry != null) { return stockEntry; } Artikel loadArticle = loadArticle(article); if (loadArticle == null) { return null; } StockEntry se = new StockEntry((Stock) stock, loadArticle); CoreHub.getLocalLockService().acquireLock(se); CoreHub.getLocalLockService().releaseLock(se); return se; } @Override public void unstoreArticleFromStock(IStock stock, String article){ IStockEntry stockEntry = findStockEntryForArticleInStock((Stock) stock, article); if (stockEntry != null) { LockResponse lr = CoreHub.getLocalLockService() .acquireLockBlocking((StockEntry) stockEntry, 1, new NullProgressMonitor()); if (lr.isOk()) { ((StockEntry) stockEntry).delete(); CoreHub.getLocalLockService().releaseLock(((StockEntry) stockEntry)); } else { log.warn("Could not unstore article [{}]", article); } } } @Override public List<? extends IStockEntry> findAllStockEntriesForArticle(String storeToString){ String[] vals = storeToString.split(StringConstants.DOUBLECOLON); Query<StockEntry> qre = new Query<StockEntry>(StockEntry.class); qre.add(StockEntry.FLD_ARTICLE_TYPE, Query.EQUALS, vals[0]); qre.add(StockEntry.FLD_ARTICLE_ID, Query.EQUALS, vals[1]); return qre.execute(); } @Override public List<? extends IStockEntry> findAllStockEntriesForStock(IStock stock){ // TODO Auto-generated method stub return null; } }