Java tutorial
/* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.0 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************* */ package org.openbravo.costing; import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.servlet.ServletException; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.hibernate.Query; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import org.openbravo.base.exception.OBException; import org.openbravo.base.provider.OBProvider; import org.openbravo.base.weld.WeldUtils; import org.openbravo.client.kernel.ComponentProvider; import org.openbravo.dal.core.OBContext; import org.openbravo.dal.service.OBCriteria; import org.openbravo.dal.service.OBDal; import org.openbravo.erpCommon.utility.OBMessageUtils; import org.openbravo.financial.FinancialUtils; import org.openbravo.model.financialmgmt.calendar.Period; import org.openbravo.model.materialmgmt.cost.CostAdjustment; import org.openbravo.model.materialmgmt.cost.CostAdjustmentLine; import org.openbravo.model.materialmgmt.cost.TransactionCost; import org.openbravo.model.materialmgmt.transaction.MaterialTransaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CostAdjustmentProcess { private static final Logger log = LoggerFactory.getLogger(CostAdjustmentProcess.class); @Inject @Any private Instance<CostingAlgorithmAdjustmentImp> costAdjustmentAlgorithms; @Inject @Any private Instance<CostAdjusmentProcessCheck> costAdjustmentProcessChecks; /** * Method to process a cost adjustment. * * @param _costAdjustment * the cost adjustment to be processed. * @return the message to be shown to the user properly formatted and translated to the user * language. * @throws OBException * when there is an error that prevents the cost adjustment to be processed. */ private JSONObject processCostAdjustment(CostAdjustment _costAdjustment) throws OBException { CostAdjustment costAdjustment = _costAdjustment; JSONObject message = new JSONObject(); OBContext.setAdminMode(true); try { message.put("severity", "success"); message.put("title", ""); message.put("text", OBMessageUtils.messageBD("Success")); doChecks(costAdjustment.getId(), message); initializeLines(costAdjustment); calculateAdjustmentAmount(costAdjustment.getId()); doPostProcessChecks(costAdjustment.getId(), message); costAdjustment = OBDal.getInstance().get(CostAdjustment.class, costAdjustment.getId()); costAdjustment.setProcessed(true); costAdjustment.setDocumentStatus("CO"); OBDal.getInstance().save(costAdjustment); } catch (JSONException ignore) { } finally { OBContext.restorePreviousMode(); } return message; } private void doChecks(String strCostAdjId, JSONObject message) { CostAdjustment costAdjustment = OBDal.getInstance().get(CostAdjustment.class, strCostAdjId); // check if there is period closed between reference date and max transaction date StringBuffer query = new StringBuffer(); query.append(" select min(" + CostAdjustmentLine.PROPERTY_ACCOUNTINGDATE + ") as mindate"); query.append(" from " + CostAdjustmentLine.ENTITY_NAME); query.append(" where " + CostAdjustmentLine.PROPERTY_COSTADJUSTMENT + " = :ca"); query.append(" and " + CostAdjustmentLine.PROPERTY_ISSOURCE + " = true"); Query qryMinDate = OBDal.getInstance().getSession().createQuery(query.toString()); qryMinDate.setParameter("ca", costAdjustment); Date minDate = (Date) qryMinDate.uniqueResult(); try { Date maxDate = CostingUtils.getMaxTransactionDate(costAdjustment.getOrganization()); Period periodClosed = CostingUtils.periodClosed(costAdjustment.getOrganization(), minDate, maxDate, "CAD"); if (periodClosed != null) { String errorMsg = OBMessageUtils.getI18NMessage("DocumentTypePeriodClosed", new String[] { "CAD", periodClosed.getIdentifier() }); throw new OBException(errorMsg); } } catch (ServletException e) { throw new OBException(e.getMessage()); } // Check that there are not permanently adjusted transactions in the sources. checkPermanentelyAdjustedTrx(strCostAdjId); // Execute checks added implementing costAdjustmentProcess interface. for (CostAdjusmentProcessCheck checksInstance : costAdjustmentProcessChecks) { checksInstance.doCheck(costAdjustment, message); } } private void doPostProcessChecks(String strCostAdjId, JSONObject message) { // Check there are not permanently adjusted transactions in the cost adjustment checkPermanentelyAdjustedTrx(strCostAdjId); // Execute checks added implementing costAdjustmentProcess interface. CostAdjustment costAdjustment = OBDal.getInstance().get(CostAdjustment.class, strCostAdjId); for (CostAdjusmentProcessCheck checksInstance : costAdjustmentProcessChecks) { checksInstance.doPostProcessCheck(costAdjustment, message); } } private void checkPermanentelyAdjustedTrx(String strCostAdjId) throws OBException { OBCriteria<CostAdjustmentLine> critLines = OBDal.getInstance().createCriteria(CostAdjustmentLine.class); critLines.createAlias(CostAdjustmentLine.PROPERTY_INVENTORYTRANSACTION, "trx"); critLines.createAlias(CostAdjustmentLine.PROPERTY_COSTADJUSTMENT, "ca"); critLines.add(Restrictions.eq("ca.id", strCostAdjId)); critLines.add(Restrictions.eq("trx." + MaterialTransaction.PROPERTY_ISCOSTPERMANENT, Boolean.TRUE)); critLines.add(Restrictions.ne(CostAdjustmentLine.PROPERTY_ADJUSTMENTAMOUNT, BigDecimal.ZERO)); critLines.add(Restrictions.eq(CostAdjustmentLine.PROPERTY_UNITCOST, Boolean.TRUE)); critLines.addOrder(Order.asc(CostAdjustmentLine.PROPERTY_LINENO)); ScrollableResults lines = critLines.scroll(ScrollMode.FORWARD_ONLY); long count = 1L; try { String strLines = ""; while (lines.next()) { CostAdjustmentLine line = (CostAdjustmentLine) lines.get()[0]; strLines += line.getLineNo() + ", "; if (count % 10000 == 0) { OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); } count++; } if (!strLines.isEmpty()) { strLines = strLines.substring(0, strLines.length() - 2); String errorMessage = OBMessageUtils.messageBD("CostAdjustmentWithPermanentLines"); HashMap<String, String> map = new HashMap<String, String>(); map.put("lines", strLines); throw new OBException(OBMessageUtils.parseTranslation(errorMessage, map)); } OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); } finally { lines.close(); } } private void initializeLines(CostAdjustment costAdjustment) { // initialize is related transaction adjusted flag to false OBCriteria<CostAdjustmentLine> critLines = OBDal.getInstance().createCriteria(CostAdjustmentLine.class); critLines.add(Restrictions.eq(CostAdjustmentLine.PROPERTY_COSTADJUSTMENT, costAdjustment)); critLines.add(Restrictions.eq(CostAdjustmentLine.PROPERTY_ISRELATEDTRANSACTIONADJUSTED, true)); ScrollableResults lines = critLines.scroll(ScrollMode.FORWARD_ONLY); long count = 1L; try { while (lines.next()) { CostAdjustmentLine line = (CostAdjustmentLine) lines.get(0); line.setRelatedTransactionAdjusted(false); OBDal.getInstance().save(line); if (count % 1000 == 0) { OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); } count++; } OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); } finally { lines.close(); } } private void calculateAdjustmentAmount(String strCostAdjustmentId) { CostAdjustmentLine line = getNextLine(strCostAdjustmentId); while (line != null) { MaterialTransaction trx = line.getInventoryTransaction(); log.debug("Start processing line: {}, transaction: {}", line.getLineNo(), trx.getIdentifier()); if (trx.getCostingAlgorithm() == null) { log.error("Transaction is cost calculated with legacy cost engine."); throw new OBException(OBMessageUtils.messageBD("NotAdjustLegacyEngineTrx")); } final String strCostAdjLineId = line.getId(); // Add transactions that depend on the transaction being adjusted. CostingAlgorithmAdjustmentImp costAdjImp = getAlgorithmAdjustmentImp( trx.getCostingAlgorithm().getJavaClassName()); if (costAdjImp == null) { throw new OBException(OBMessageUtils.messageBD("CostAlgorithmWithoutAdjustment")); } log.debug("costing algorithm imp loaded {}", costAdjImp.getClass().getName()); costAdjImp.init(line); costAdjImp.searchRelatedTransactionCosts(null); // Reload cost adjustment object in case the costing algorithm has cleared the session. line = OBDal.getInstance().get(CostAdjustmentLine.class, strCostAdjLineId); line.setRelatedTransactionAdjusted(true); OBDal.getInstance().save(line); OBDal.getInstance().flush(); generateTransactionCosts(line); OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); line = getNextLine(strCostAdjustmentId); } } private CostAdjustmentLine getNextLine(String strCostAdjustmentId) { OBCriteria<CostAdjustmentLine> critLines = OBDal.getInstance().createCriteria(CostAdjustmentLine.class); critLines.createAlias(CostAdjustmentLine.PROPERTY_INVENTORYTRANSACTION, "trx"); critLines.createAlias(CostAdjustmentLine.PROPERTY_COSTADJUSTMENT, "ca"); critLines.add(Restrictions.eq("ca.id", strCostAdjustmentId)); critLines.add(Restrictions.eq(CostAdjustmentLine.PROPERTY_ISRELATEDTRANSACTIONADJUSTED, false)); critLines.addOrder(Order.asc("trx." + MaterialTransaction.PROPERTY_TRANSACTIONPROCESSDATE)); critLines.addOrder(Order.asc(CostAdjustmentLine.PROPERTY_ADJUSTMENTAMOUNT)); critLines.addOrder(Order.asc("trx." + MaterialTransaction.PROPERTY_MOVEMENTDATE)); critLines.setMaxResults(1); return (CostAdjustmentLine) critLines.uniqueResult(); } private void generateTransactionCosts(CostAdjustmentLine costAdjustmentLine) { log.debug("Generate transaction costs of line: {}", costAdjustmentLine.getLineNo()); long t1 = System.currentTimeMillis(); OBCriteria<CostAdjustmentLine> critLines = OBDal.getInstance().createCriteria(CostAdjustmentLine.class); Date referenceDate = costAdjustmentLine.getCostAdjustment().getReferenceDate(); critLines.add(Restrictions.or( Restrictions.eq(CostAdjustmentLine.PROPERTY_PARENTCOSTADJUSTMENTLINE, costAdjustmentLine), Restrictions.eq("id", costAdjustmentLine.getId()))); ScrollableResults lines = critLines.scroll(ScrollMode.FORWARD_ONLY); try { while (lines.next()) { CostAdjustmentLine line = (CostAdjustmentLine) lines.get(0); if (!line.getTransactionCostList().isEmpty()) { continue; } TransactionCost trxCost = OBProvider.getInstance().get(TransactionCost.class); // TODO: Review this // trxCost.setNewOBObject(true); MaterialTransaction trx = line.getInventoryTransaction(); trxCost.setInventoryTransaction(trx); trxCost.setOrganization(trx.getOrganization()); trxCost.setCostDate(referenceDate); trxCost.setCostAdjustmentLine(line); trxCost.setUnitCost(line.isUnitCost()); Date accountingDate = line.getAccountingDate(); if (accountingDate == null) { accountingDate = trx.getMovementDate(); } trxCost.setAccountingDate(accountingDate); BigDecimal convertedAmt = line.getAdjustmentAmount(); if (!line.getCurrency().getId().equals(trx.getCurrency().getId())) { convertedAmt = FinancialUtils.getConvertedAmount(convertedAmt, line.getCurrency(), trx.getCurrency(), accountingDate, trx.getOrganization(), "C"); } trxCost.setCost(convertedAmt); trxCost.setCurrency(trx.getCurrency()); OBDal.getInstance().save(trxCost); OBDal.getInstance().flush(); OBDal.getInstance().getSession().clear(); } } finally { lines.close(); } log.debug("Transaction costs created. Time {}", System.currentTimeMillis() - t1); } private CostingAlgorithmAdjustmentImp getAlgorithmAdjustmentImp(String strJavaClass) { CostingAlgorithmAdjustmentImp implementor = null; for (CostingAlgorithmAdjustmentImp nextImplementor : costAdjustmentAlgorithms .select(new ComponentProvider.Selector(strJavaClass))) { if (implementor == null) { implementor = nextImplementor; } else { log.warn("More than one class found implementing cost adjustment for algorithm with java class {}", strJavaClass); } } return implementor; } public static synchronized JSONObject doProcessCostAdjustment(CostAdjustment costAdjustment) throws OBException { String docNo = costAdjustment.getDocumentNo(); log.debug("Starts process cost adjustment: {}", docNo); long t1 = System.currentTimeMillis(); CostAdjustmentProcess cap = WeldUtils.getInstanceFromStaticBeanManager(CostAdjustmentProcess.class); JSONObject message = cap.processCostAdjustment(costAdjustment); log.debug("Ends process cost adjustment: {}, took {} ms.", docNo, (System.currentTimeMillis() - t1)); return message; } }