org.openbravo.costing.StandardCostAdjustment.java Source code

Java tutorial

Introduction

Here is the source code for org.openbravo.costing.StandardCostAdjustment.java

Source

/*
 *************************************************************************
 * 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-2015 Openbravo SLU
 * All Rights Reserved.
 * Contributor(s):  ______________________________________.
 *************************************************************************
 */
package org.openbravo.costing;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;

import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.openbravo.base.structure.BaseOBObject;
import org.openbravo.client.kernel.ComponentProvider;
import org.openbravo.costing.CostingAlgorithm.CostDimension;
import org.openbravo.costing.CostingServer.TrxType;
import org.openbravo.dal.core.DalUtil;
import org.openbravo.dal.core.OBContext;
import org.openbravo.dal.security.OrganizationStructureProvider;
import org.openbravo.dal.service.OBDal;
import org.openbravo.dal.service.OBQuery;
import org.openbravo.financial.FinancialUtils;
import org.openbravo.model.common.enterprise.Locator;
import org.openbravo.model.common.enterprise.Organization;
import org.openbravo.model.common.enterprise.Warehouse;
import org.openbravo.model.common.plm.Product;
import org.openbravo.model.materialmgmt.cost.CostAdjustmentLine;
import org.openbravo.model.materialmgmt.cost.Costing;
import org.openbravo.model.materialmgmt.cost.CostingRule;
import org.openbravo.model.materialmgmt.transaction.MaterialTransaction;

@ComponentProvider.Qualifier("org.openbravo.costing.StandardAlgorithm")
public class StandardCostAdjustment extends CostingAlgorithmAdjustmentImp {

    @Override
    protected void getRelatedTransactionsByAlgorithm() {
        // Inventory opening transactions are the only transaction types that can generates a new
        // Standard Cost. Having a new Standard Cost on a backdated transaction forces to adjust the
        // cost off all the transactions from the backdated transaction to the next defined standard
        // cost.
        if (trxType == TrxType.InventoryOpening) {
            // If it is a backdated transaction of an inventory opening, insert a new costing if the
            // standard cost is different than the unit cost of the inventory.
            MaterialTransaction trx = getTransaction();
            BigDecimal unitCost = trx.getPhysicalInventoryLine().getCost().setScale(costCurPrecission,
                    RoundingMode.HALF_UP);

            // Cost is effective on the beginning of the following date.
            Date backDatedTrxDate = CostAdjustmentUtils.getLastTrxDateOfMvmntDate(trx.getMovementDate(),
                    trx.getProduct(), getCostOrg(), getCostDimensions());
            if (backDatedTrxDate == null) {
                backDatedTrxDate = trx.getTransactionProcessDate();
            }

            Costing stdCost = CostingUtils.getStandardCostDefinition(trx.getProduct(), getCostOrg(),
                    backDatedTrxDate, getCostDimensions());
            // Modify isManufacturingProduct flag in case it has changed at some point.
            isManufacturingProduct = ((String) DalUtil.getId(stdCost.getOrganization())).equals("0");

            BigDecimal baseCurrentCost = stdCost.getCost();
            if (!stdCost.getCurrency().equals(strCostCurrencyId)) {
                baseCurrentCost = FinancialUtils.getConvertedAmount(baseCurrentCost, stdCost.getCurrency(),
                        getCostCurrency(), trx.getMovementDate(), getCostOrg(), "C");
            }
            if (baseCurrentCost.compareTo(unitCost) == 0) {
                // If current cost is the same than the unit cost there is no need to create a new costing
                // so it is not needed to adjust any other transaction.
                return;
            }
            Costing newCosting = insertCost(stdCost, unitCost, backDatedTrxDate);
            // Adjust all transactions calculated with the previous costing.
            ScrollableResults trxs = getRelatedTransactions(newCosting.getStartingDate(),
                    newCosting.getEndingDate());
            int i = 1;
            try {
                while (trxs.next()) {
                    MaterialTransaction relTrx = (MaterialTransaction) trxs.get()[0];
                    BigDecimal currentCost = CostAdjustmentUtils.getTrxCost(relTrx, true, trx.getCurrency());
                    BigDecimal expectedCost = relTrx.getMovementQuantity().abs().multiply(unitCost)
                            .setScale(stdCurPrecission, RoundingMode.HALF_UP);
                    if (expectedCost.compareTo(currentCost) != 0) {
                        CostAdjustmentLine newCAL = insertCostAdjustmentLine(relTrx,
                                expectedCost.subtract(currentCost), null);
                        newCAL.setRelatedTransactionAdjusted(true);
                    }

                    if (i % 100 == 0) {
                        OBDal.getInstance().flush();
                        OBDal.getInstance().getSession().clear();
                    }
                    i++;
                }
            } finally {
                trxs.close();
            }
        }
    }

    private ScrollableResults getRelatedTransactions(Date firstDate, Date endingDate) {
        OrganizationStructureProvider osp = OBContext.getOBContext()
                .getOrganizationStructureProvider((String) DalUtil.getId(getCostOrg().getClient()));
        HashMap<CostDimension, BaseOBObject> costDimensions = getCostDimensions();
        Set<String> orgs = osp.getChildTree(strCostOrgId, true);
        CostingRule costingRule = getCostingRule();
        if (isManufacturingProduct) {
            orgs = osp.getChildTree("0", false);
            costDimensions = CostingUtils.getEmptyDimensions();
        }
        Warehouse warehouse = (Warehouse) costDimensions.get(CostDimension.Warehouse);
        MaterialTransaction trx = getTransaction();

        StringBuffer where = new StringBuffer();
        where.append(" as trx");
        where.append("\n join trx." + Product.PROPERTY_ORGANIZATION + " as org");
        where.append("\n join trx." + Product.PROPERTY_STORAGEBIN + " as loc");

        where.append("\n where trx." + MaterialTransaction.PROPERTY_ISCOSTCALCULATED + " = true");
        where.append("  and trx." + MaterialTransaction.PROPERTY_PRODUCT + " = :product");
        where.append("  and trx." + MaterialTransaction.PROPERTY_MOVEMENTDATE + " >= :mvtdate");
        where.append("  and trx." + MaterialTransaction.PROPERTY_MOVEMENTDATE + " <= :enddate");
        where.append("  and org.id in (:orgs)");
        if (warehouse != null) {
            where.append("  and loc." + Locator.PROPERTY_WAREHOUSE + " = :warehouse");
        }
        where.append("  and trx." + MaterialTransaction.PROPERTY_TRANSACTIONPROCESSDATE + " > :startdate");

        OBQuery<MaterialTransaction> trxQry = OBDal.getInstance().createQuery(MaterialTransaction.class,
                where.toString());
        trxQry.setFilterOnReadableOrganization(false);
        trxQry.setNamedParameter("mvtdate", firstDate);
        trxQry.setNamedParameter("enddate", endingDate);
        trxQry.setNamedParameter("orgs", orgs);
        trxQry.setNamedParameter("product", trx.getProduct());
        if (warehouse != null) {
            trxQry.setNamedParameter("warehouse", warehouse);
        }
        trxQry.setNamedParameter("startdate", CostingUtils.getCostingRuleStartingDate(costingRule));

        return trxQry.scroll(ScrollMode.FORWARD_ONLY);

    }

    private Costing insertCost(Costing currentCosting, BigDecimal newCost, Date backDatedTrxDate) {
        MaterialTransaction transaction = getTransaction();

        Costing cost = (Costing) DalUtil.copy(currentCosting, false);
        cost.setCost(newCost);
        cost.setStartingDate(backDatedTrxDate);
        cost.setCurrency(getCostCurrency());
        cost.setInventoryTransaction(transaction);
        if (isManufacturingProduct) {
            cost.setOrganization(OBDal.getInstance().get(Organization.class, "0"));
        } else {
            cost.setOrganization(getCostOrg());
        }
        cost.setCostType("STA");
        cost.setManual(false);
        cost.setPermanent(true);
        OBDal.getInstance().save(cost);

        currentCosting.setEndingDate(backDatedTrxDate);
        OBDal.getInstance().save(currentCosting);
        return cost;
    }

    @Override
    protected BigDecimal getOutgoingBackdatedTrxAdjAmt(CostAdjustmentLine costAdjLine) {
        // Calculate the standard cost on the transaction's movement date and adjust the cost if needed.
        MaterialTransaction trx = costAdjLine.getInventoryTransaction();

        Date trxDate = CostAdjustmentUtils.getLastTrxDateOfMvmntDate(trx.getMovementDate(), trx.getProduct(),
                getCostOrg(), getCostDimensions());
        if (trxDate == null) {
            trxDate = trx.getTransactionProcessDate();
        }

        BigDecimal cost = CostingUtils.getStandardCost(trx.getProduct(), getCostOrg(), trxDate, getCostDimensions(),
                getCostCurrency());

        BigDecimal expectedCostAmt = trx.getMovementQuantity().abs().multiply(cost);
        BigDecimal currentCost = trx.getTransactionCost();
        return expectedCostAmt.subtract(currentCost);
    }

    @Override
    protected void calculateNegativeStockCorrectionAdjustmentAmount(CostAdjustmentLine costAdjLine) {
        // Do nothing
    }

    @Override
    protected void addCostDependingTrx(CostAdjustmentLine costAdjLine) {
        // Do nothing.
        // All transactions are calculated using the current standard cost so there is no need to
        // specifically search for dependent transactions.
    }
}