details: https://code.openbravo.com/erp/devel/pi/rev/4e9e547d8199 changeset: 28585:4e9e547d8199 user: Alvaro Ferraz <alvaro.ferraz <at> openbravo.com> date: Thu Jan 28 09:24:21 2016 +0100 summary: Fixes issue 31772: Improve performance in Costing Rule validation
Update M_TRANSACTION_TRG to execute M_UPDATE_INVENTORY only when updated columns are not related to costing (like transactioncost, m_costing_algorithm_id, iscostcalculated, c_currency_id, costing_status, isprocessed, checkpricedifference, manualcostadjustment and iscostpermanent). Update some methods in CostingRuleProcess and CostingRuleProcessOnProcessHandler to use query.uniqueResult() != null instead of query.count() > 0. Update initializeOldTrx method in CostingRuleProcess to do an insert and an update in hql instead of doing a loop in java. Change second loop in updateInventoriesCostAndProcessInitInventories method in CostingRuleProcess to use a scroll instead of looping over a list. Use new getInventoryLineTransactions method in CostingRuleProcess instead of getInventoryLineTransaction method, which returns a scroll. Use trx.getPhysicalInventoryLine().getRelatedInventory() instead of getInitIcl(cri.getInitInventory(), icl) in CostingRuleProcess. Change updateInitInventoriesTrxDate method in CostingRuleProcess to do an update in hql instead of doing a loop in java. diffstat: src-db/database/model/triggers/M_TRANSACTION_TRG.xml | 50 +- src/org/openbravo/costing/CostingMigrationProcess.java | 5 +- src/org/openbravo/costing/CostingRuleProcess.java | 273 ++++++--- src/org/openbravo/costing/CostingRuleProcessOnProcessHandler.java | 6 +- 4 files changed, 216 insertions(+), 118 deletions(-) diffs (truncated from 471 to 300 lines): diff -r d2a064ba6376 -r 4e9e547d8199 src-db/database/model/triggers/M_TRANSACTION_TRG.xml --- a/src-db/database/model/triggers/M_TRANSACTION_TRG.xml Mon Feb 01 18:49:06 2016 +0100 +++ b/src-db/database/model/triggers/M_TRANSACTION_TRG.xml Thu Jan 28 09:24:21 2016 +0100 @@ -18,7 +18,7 @@ * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU -* All portions are Copyright (C) 2001-2012 Openbravo SLU +* All portions are Copyright (C) 2001-2016 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************/ @@ -127,7 +127,29 @@ END IF; -- Updating inventory - IF UPDATING OR DELETING THEN + IF DELETING OR (UPDATING AND ( + (COALESCE(:OLD.M_TRANSACTION_ID, '0') <> COALESCE(:NEW.M_TRANSACTION_ID, '0')) OR + (COALESCE(:OLD.AD_CLIENT_ID, '0') <> COALESCE(:NEW.AD_CLIENT_ID, '0')) OR + (COALESCE(:OLD.AD_ORG_ID, '0') <> COALESCE(:NEW.AD_ORG_ID, '0')) OR + (COALESCE(:OLD.ISACTIVE, 'Y') <> COALESCE(:NEW.ISACTIVE, 'Y')) OR + (COALESCE(:OLD.MOVEMENTTYPE, '.') <> COALESCE(:NEW.MOVEMENTTYPE, '.')) OR + (COALESCE(:OLD.M_LOCATOR_ID, '0') <> COALESCE(:NEW.M_LOCATOR_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCT_ID, '0') <> COALESCE(:NEW.M_PRODUCT_ID, '0')) OR + (COALESCE(:OLD.MOVEMENTDATE, v_DateNull) <> COALESCE(:NEW.MOVEMENTDATE, v_DateNull)) OR + (COALESCE(:OLD.MOVEMENTQTY, '0') <> COALESCE(:NEW.MOVEMENTQTY, '0')) OR + (COALESCE(:OLD.M_INVENTORYLINE_ID, '0') <> COALESCE(:NEW.M_INVENTORYLINE_ID, '0')) OR + (COALESCE(:OLD.M_MOVEMENTLINE_ID, '0') <> COALESCE(:NEW.M_MOVEMENTLINE_ID, '0')) OR + (COALESCE(:OLD.M_INOUTLINE_ID, '0') <> COALESCE(:NEW.M_INOUTLINE_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCTIONLINE_ID, '0') <> COALESCE(:NEW.M_PRODUCTIONLINE_ID, '0')) OR + (COALESCE(:OLD.C_PROJECTISSUE_ID, '0') <> COALESCE(:NEW.C_PROJECTISSUE_ID, '0')) OR + (COALESCE(:OLD.M_ATTRIBUTESETINSTANCE_ID, '0') <> COALESCE(:NEW.M_ATTRIBUTESETINSTANCE_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCT_UOM_ID, '0') <> COALESCE(:NEW.M_PRODUCT_UOM_ID, '0')) OR + (COALESCE(:OLD.QUANTITYORDER, '0') <> COALESCE(:NEW.QUANTITYORDER, '0')) OR + (COALESCE(:OLD.C_UOM_ID, '0') <> COALESCE(:NEW.C_UOM_ID, '0')) OR + (COALESCE(:OLD.M_INTERNAL_CONSUMPTIONLINE_ID, '0') <> COALESCE(:NEW.M_INTERNAL_CONSUMPTIONLINE_ID, '0')) OR + (COALESCE(:OLD.TRXPROCESSDATE, v_DateNull) <> COALESCE(:NEW.TRXPROCESSDATE, v_DateNull)) OR + (COALESCE(:OLD.CHECKRESERVEDQTY, 'Y') <> COALESCE(:NEW.CHECKRESERVEDQTY, 'Y')) + )) THEN M_UPDATE_INVENTORY(:OLD.AD_CLIENT_ID, :OLD.AD_ORG_ID, :OLD.UPDATEDBY, :OLD.M_PRODUCT_ID, :OLD.M_LOCATOR_ID, :OLD.M_ATTRIBUTESETINSTANCE_ID, :OLD.C_UOM_ID, :OLD.M_PRODUCT_UOM_ID, -:OLD.MOVEMENTQTY, -:OLD.QUANTITYORDER, NULL, :OLD.MOVEMENTQTY, :OLD.QUANTITYORDER) ; -- FIXME: this shall be removed/reviewed when new warehouse management is implemented IF (:OLD.M_PRODUCTIONLINE_ID IS NOT NULL) THEN @@ -140,7 +162,29 @@ END IF; -- END FIXME END IF; - IF INSERTING OR UPDATING THEN + IF INSERTING OR (UPDATING AND ( + (COALESCE(:OLD.M_TRANSACTION_ID, '0') <> COALESCE(:NEW.M_TRANSACTION_ID, '0')) OR + (COALESCE(:OLD.AD_CLIENT_ID, '0') <> COALESCE(:NEW.AD_CLIENT_ID, '0')) OR + (COALESCE(:OLD.AD_ORG_ID, '0') <> COALESCE(:NEW.AD_ORG_ID, '0')) OR + (COALESCE(:OLD.ISACTIVE, 'Y') <> COALESCE(:NEW.ISACTIVE, 'Y')) OR + (COALESCE(:OLD.MOVEMENTTYPE, '.') <> COALESCE(:NEW.MOVEMENTTYPE, '.')) OR + (COALESCE(:OLD.M_LOCATOR_ID, '0') <> COALESCE(:NEW.M_LOCATOR_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCT_ID, '0') <> COALESCE(:NEW.M_PRODUCT_ID, '0')) OR + (COALESCE(:OLD.MOVEMENTDATE, v_DateNull) <> COALESCE(:NEW.MOVEMENTDATE, v_DateNull)) OR + (COALESCE(:OLD.MOVEMENTQTY, '0') <> COALESCE(:NEW.MOVEMENTQTY, '0')) OR + (COALESCE(:OLD.M_INVENTORYLINE_ID, '0') <> COALESCE(:NEW.M_INVENTORYLINE_ID, '0')) OR + (COALESCE(:OLD.M_MOVEMENTLINE_ID, '0') <> COALESCE(:NEW.M_MOVEMENTLINE_ID, '0')) OR + (COALESCE(:OLD.M_INOUTLINE_ID, '0') <> COALESCE(:NEW.M_INOUTLINE_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCTIONLINE_ID, '0') <> COALESCE(:NEW.M_PRODUCTIONLINE_ID, '0')) OR + (COALESCE(:OLD.C_PROJECTISSUE_ID, '0') <> COALESCE(:NEW.C_PROJECTISSUE_ID, '0')) OR + (COALESCE(:OLD.M_ATTRIBUTESETINSTANCE_ID, '0') <> COALESCE(:NEW.M_ATTRIBUTESETINSTANCE_ID, '0')) OR + (COALESCE(:OLD.M_PRODUCT_UOM_ID, '0') <> COALESCE(:NEW.M_PRODUCT_UOM_ID, '0')) OR + (COALESCE(:OLD.QUANTITYORDER, '0') <> COALESCE(:NEW.QUANTITYORDER, '0')) OR + (COALESCE(:OLD.C_UOM_ID, '0') <> COALESCE(:NEW.C_UOM_ID, '0')) OR + (COALESCE(:OLD.M_INTERNAL_CONSUMPTIONLINE_ID, '0') <> COALESCE(:NEW.M_INTERNAL_CONSUMPTIONLINE_ID, '0')) OR + (COALESCE(:OLD.TRXPROCESSDATE, v_DateNull) <> COALESCE(:NEW.TRXPROCESSDATE, v_DateNull)) OR + (COALESCE(:OLD.CHECKRESERVEDQTY, 'Y') <> COALESCE(:NEW.CHECKRESERVEDQTY, 'Y')) + )) THEN SELECT MAX(MOVEMENTDATE) INTO v_DATEINVENTORY FROM M_INVENTORY I, diff -r d2a064ba6376 -r 4e9e547d8199 src/org/openbravo/costing/CostingMigrationProcess.java --- a/src/org/openbravo/costing/CostingMigrationProcess.java Mon Feb 01 18:49:06 2016 +0100 +++ b/src/org/openbravo/costing/CostingMigrationProcess.java Thu Jan 28 09:24:21 2016 +0100 @@ -11,7 +11,7 @@ * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU - * All portions are Copyright (C) 2012-2015 Openbravo SLU + * All portions are Copyright (C) 2012-2016 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************* @@ -495,7 +495,6 @@ int costPrecision = cur.getCostingPrecision().intValue(); int stdPrecision = cur.getStandardPrecision().intValue(); - CostingRuleProcess crp = new CostingRuleProcess(); // Update cost of inventories and process starting physical inventories. ScrollableResults icls = getCloseInventoryLines(orgs); String productId = ""; @@ -512,7 +511,7 @@ totalStock = stock.get("stock"); } - MaterialTransaction trx = crp.getInventoryLineTransaction(icl); + MaterialTransaction trx = icl.getMaterialMgmtMaterialTransactionList().get(0); trx.setTransactionProcessDate(DateUtils.addSeconds(trx.getTransactionProcessDate(), -1)); trx.setCurrency(OBDal.getInstance().get(Currency.class, curId)); diff -r d2a064ba6376 -r 4e9e547d8199 src/org/openbravo/costing/CostingRuleProcess.java --- a/src/org/openbravo/costing/CostingRuleProcess.java Mon Feb 01 18:49:06 2016 +0100 +++ b/src/org/openbravo/costing/CostingRuleProcess.java Thu Jan 28 09:24:21 2016 +0100 @@ -20,6 +20,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; +import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -58,6 +59,8 @@ import org.openbravo.model.materialmgmt.transaction.InventoryCount; import org.openbravo.model.materialmgmt.transaction.InventoryCountLine; import org.openbravo.model.materialmgmt.transaction.MaterialTransaction; +import org.openbravo.model.materialmgmt.transaction.ShipmentInOut; +import org.openbravo.model.materialmgmt.transaction.ShipmentInOutLine; import org.openbravo.scheduling.Process; import org.openbravo.scheduling.ProcessBundle; import org.openbravo.scheduling.ProcessLogger; @@ -200,7 +203,8 @@ pQry.setFilterOnReadableOrganization(false); pQry.setNamedParameter("porgs", naturalOrgs); pQry.setNamedParameter("childOrgs", childOrgs); - return pQry.count() > 0; + pQry.setMaxResult(1); + return pQry.uniqueResult() != null; } private void checkAllTrxCalculated(Set<String> naturalOrgs, Set<String> childOrgs) { @@ -219,7 +223,8 @@ pQry.setFilterOnReadableOrganization(false); pQry.setNamedParameter("porgs", naturalOrgs); pQry.setNamedParameter("childOrgs", childOrgs); - if (pQry.count() > 0) { + pQry.setMaxResult(1); + if (pQry.uniqueResult() != null) { throw new OBException("@TrxWithCostNoCalculated@"); } } @@ -240,57 +245,83 @@ pQry.setFilterOnReadableOrganization(false); pQry.setNamedParameter("porgs", naturalOrgs); pQry.setNamedParameter("childOrgs", childOrgs); - if (pQry.count() > 0) { + pQry.setMaxResult(1); + if (pQry.uniqueResult() != null) { throw new OBException("@ProductsWithTrxCalculated@"); } } - private void initializeOldTrx(Set<String> childOrgs, Date date) { - StringBuffer where = new StringBuffer(); - where.append(" where " + MaterialTransaction.PROPERTY_ORGANIZATION + ".id in (:orgs)"); - where.append(" and " + MaterialTransaction.PROPERTY_MOVEMENTDATE + " < :date"); - OBQuery<MaterialTransaction> trxQry = OBDal.getInstance().createQuery( - MaterialTransaction.class, where.toString()); - trxQry.setFilterOnReadableOrganization(false); - trxQry.setNamedParameter("orgs", childOrgs); - trxQry.setNamedParameter("date", date); - trxQry.setFetchSize(1000); - ScrollableResults trxs = trxQry.scroll(ScrollMode.FORWARD_ONLY); - int i = 1; - try { - while (trxs.next()) { - MaterialTransaction trx = (MaterialTransaction) trxs.get(0); + private void initializeOldTrx(Set<String> childOrgs, Date date) throws SQLException { + Client client = OBDal.getInstance().get(Client.class, + OBContext.getOBContext().getCurrentClient().getId()); - TransactionCost transactionCost = OBProvider.getInstance().get(TransactionCost.class); - transactionCost.setInventoryTransaction(trx); - transactionCost.setCostDate(trx.getTransactionProcessDate()); - transactionCost.setClient(trx.getClient()); - transactionCost.setOrganization(trx.getOrganization()); - transactionCost.setCost(BigDecimal.ZERO); - transactionCost.setCurrency(trx.getClient().getCurrency()); - transactionCost.setAccountingDate(trx.getGoodsShipmentLine() != null ? trx - .getGoodsShipmentLine().getShipmentReceipt().getAccountingDate() : trx - .getMovementDate()); - List<TransactionCost> trxCosts = trx.getTransactionCostList(); - trxCosts.add(transactionCost); - trx.setTransactionCostList(trxCosts); + StringBuffer insert = new StringBuffer(); + insert.append(" insert into " + TransactionCost.ENTITY_NAME); + insert.append(" (" + TransactionCost.PROPERTY_ID); + insert.append(", " + TransactionCost.PROPERTY_CLIENT); + insert.append(", " + TransactionCost.PROPERTY_ORGANIZATION); + insert.append(", " + TransactionCost.PROPERTY_CREATIONDATE); + insert.append(", " + TransactionCost.PROPERTY_CREATEDBY); + insert.append(", " + TransactionCost.PROPERTY_UPDATED); + insert.append(", " + TransactionCost.PROPERTY_UPDATEDBY); + insert.append(", " + TransactionCost.PROPERTY_ACTIVE); + insert.append(", " + TransactionCost.PROPERTY_INVENTORYTRANSACTION); + insert.append(", " + TransactionCost.PROPERTY_COST); + insert.append(", " + TransactionCost.PROPERTY_COSTDATE); + insert.append(", " + TransactionCost.PROPERTY_CURRENCY); + insert.append(", " + TransactionCost.PROPERTY_ACCOUNTINGDATE); + insert.append(")"); + insert.append(" select get_uuid()"); + insert.append(", t." + MaterialTransaction.PROPERTY_CLIENT); + insert.append(", t." + MaterialTransaction.PROPERTY_ORGANIZATION); + insert.append(", now()"); + insert.append(", t." + MaterialTransaction.PROPERTY_CREATEDBY); + insert.append(", now()"); + insert.append(", t." + MaterialTransaction.PROPERTY_UPDATEDBY); + insert.append(", t." + MaterialTransaction.PROPERTY_ACTIVE); + insert.append(", t"); + insert.append(", cast(0 as big_decimal)"); + insert.append(", t." + MaterialTransaction.PROPERTY_TRANSACTIONPROCESSDATE); + insert.append(", t." + MaterialTransaction.PROPERTY_CLIENT + "." + Client.PROPERTY_CURRENCY); + insert.append(", coalesce(io." + ShipmentInOut.PROPERTY_ACCOUNTINGDATE + ", t." + + MaterialTransaction.PROPERTY_MOVEMENTDATE + ")"); + insert.append(" from " + MaterialTransaction.ENTITY_NAME + " as t"); + insert.append(" left join t." + MaterialTransaction.PROPERTY_GOODSSHIPMENTLINE + " as iol"); + insert.append(" left join iol." + ShipmentInOutLine.PROPERTY_SHIPMENTRECEIPT + " as io"); + insert.append(" where t." + MaterialTransaction.PROPERTY_ORGANIZATION + ".id in (:orgs)"); + insert.append(" and t." + MaterialTransaction.PROPERTY_MOVEMENTDATE + " < :date"); + insert.append(" and t." + MaterialTransaction.PROPERTY_ISPROCESSED + " = false"); + insert.append(" and t." + MaterialTransaction.PROPERTY_ACTIVE + " = true"); + insert.append(" and t." + MaterialTransaction.PROPERTY_CLIENT + ".id = :client"); - trx.setCostCalculated(true); - trx.setCostingStatus("CC"); - trx.setTransactionCost(BigDecimal.ZERO); - trx.setCurrency(trx.getClient().getCurrency()); - trx.setProcessed(true); - OBDal.getInstance().save(trx); + Query queryInsert = OBDal.getInstance().getSession().createQuery(insert.toString()); + queryInsert.setParameterList("orgs", childOrgs); + queryInsert.setDate("date", date); + queryInsert.setString("client", client.getId()); + queryInsert.executeUpdate(); - if ((i % 100) == 0) { - OBDal.getInstance().flush(); - OBDal.getInstance().getSession().clear(); - } - i++; - } - } finally { - trxs.close(); - } + StringBuffer update = new StringBuffer(); + update.append(" update " + MaterialTransaction.ENTITY_NAME); + update.append(" set " + MaterialTransaction.PROPERTY_ISCOSTCALCULATED + " = true"); + update.append(", " + MaterialTransaction.PROPERTY_COSTINGSTATUS + " = 'CC'"); + update.append(", " + MaterialTransaction.PROPERTY_TRANSACTIONCOST + " = " + BigDecimal.ZERO); + update.append(", " + MaterialTransaction.PROPERTY_CURRENCY + " = :currency"); + update.append(", " + MaterialTransaction.PROPERTY_ISPROCESSED + " = true"); + update.append(" where " + MaterialTransaction.PROPERTY_ORGANIZATION + ".id in (:orgs)"); + update.append(" and " + MaterialTransaction.PROPERTY_MOVEMENTDATE + " < :date"); + update.append(" and " + MaterialTransaction.PROPERTY_ISPROCESSED + " = false"); + update.append(" and " + MaterialTransaction.PROPERTY_ACTIVE + " = true"); + update.append(" and " + MaterialTransaction.PROPERTY_CLIENT + ".id = :client"); + + Query queryUpdate = OBDal.getInstance().getSession().createQuery(update.toString()); + queryUpdate.setParameter("currency", client.getCurrency()); + queryUpdate.setParameterList("orgs", childOrgs); + queryUpdate.setDate("date", date); + queryUpdate.setString("client", client.getId()); + queryUpdate.executeUpdate(); + + OBDal.getInstance().getSession().flush(); + OBDal.getInstance().getSession().clear(); } @Deprecated @@ -366,6 +397,7 @@ stockLines.close(); } // Process closing physical inventories. + rule = OBDal.getInstance().get(CostingRule.class, ruleId); for (CostingRuleInit cri : rule.getCostingRuleInitList()) { new InventoryCountProcess().processInventory(cri.getCloseInventory(), false); } @@ -496,52 +528,67 @@ boolean existsPreviousRule) { CostingRule rule = OBDal.getInstance().get(CostingRule.class, ruleId); for (CostingRuleInit cri : rule.getCostingRuleInitList()) { - for (InventoryCountLine icl : cri.getCloseInventory().getMaterialMgmtInventoryCountLineList()) { - MaterialTransaction trx = getInventoryLineTransaction(icl); - // Remove 1 second from transaction date to ensure that cost is calculated with previous - // costing rule. - trx.setTransactionProcessDate(DateUtils.addSeconds(startingDate, -1)); - BigDecimal trxCost = BigDecimal.ZERO; - BigDecimal cost = null; - Currency cur = FinancialUtils.getLegalEntityCurrency(trx.getOrganization()); - if (existsPreviousRule) { - trxCost = CostingUtils.getTransactionCost(trx, startingDate, true, cur); - if (trx.getMovementQuantity().compareTo(BigDecimal.ZERO) != 0) { - cost = trxCost.divide(trx.getMovementQuantity().abs(), cur.getCostingPrecision() - .intValue(), RoundingMode.HALF_UP); - trx = OBDal.getInstance().get(MaterialTransaction.class, trx.getId()); + ScrollableResults trxs = getInventoryLineTransactions(cri.getCloseInventory()); + int i = 1; + try { ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 _______________________________________________ Openbravo-commits mailing list Openbravo-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openbravo-commits