Sistematika’s Journal

Diberkati untuk memberkati

Multi Accounting Schema #3

Posted by: Bayu Cahya P on: August 8, 2008

As explained in our previous journal, we were facing to wrong calculation result within cost details records for our USD currency. As per our test, this error result firstly came from matching PO/Invoice regarding its Purchase Orders documents. Cause our transaction within IDR currency and the wrong calculation was within USD currency, it seems that we had problem with conversion rate area. Digging into source codes, this is our culprit createMatchPOCostDetail method which called by completeIt in M_InOut files

private String createMatchPOCostDetail(MMatchPO po, MOrderLine m_oLine)
        {
                // Get Account Schemas to create MCostDetail
                MAcctSchema[] acctschemas = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
                for(int asn = 0; asn < acctschemas.length; asn++)
                {
                        MAcctSchema as = acctschemas[asn];

                        boolean skip = false;
                        if (as.getAD_OrgOnly_ID() != 0)
                        {
                                if (as.getOnlyOrgs() == null)
                                        as.setOnlyOrgs(MReportTree.getChildIDs(getCtx(),
                                                0, MAcctSchemaElement.ELEMENTTYPE_Organization,
                                                as.getAD_OrgOnly_ID()));

                                //      Header Level Org
                                skip = as.isSkipOrg(getAD_Org_ID());
                                //      Line Level Org
                                skip = as.isSkipOrg(m_oLine.getAD_Org_ID());
                        }
                        if (skip)
                                continue;

                        // Purchase Order Line
                        BigDecimal poCost = m_oLine.getPriceCost();
                        if (poCost == null || poCost.signum() == 0)
                                poCost = m_oLine.getPriceActual();
                        poCost = poCost.multiply(po.getQty());                  //      Delivered so far
                        //      Different currency
                        if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID())
                        {
                                MOrder order = m_oLine.getParent();
                                BigDecimal rate = MConversionRate.getRate(
                                        order.getC_Currency_ID(), as.getC_Currency_ID(),
                                        order.getDateAcct(), order.getC_ConversionType_ID(),
                                        m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID());
                                if (rate == null)
                                {
                                        return "Purchase Order not convertible - " + as.getName();
                                }
                                poCost = poCost.multiply(rate);
                                if (poCost.scale() > as.getCostingPrecision())
                                        poCost = poCost.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
                        }

                        // Source from Doc_MatchPO.createFacts(MAcctSchema)
                        MInOutLine receiptLine = new MInOutLine (getCtx(), po.getM_InOutLine_ID(), po.get_TrxName());
                        MInOut inOut = receiptLine.getParent();
                        boolean isReturnTrx = inOut.getMovementType().equals(X_M_InOut.MOVEMENTTYPE_VendorReturns);

                        //      Create PO Cost Detail Record first
                        // MZ Goodwill
                        // Create Cost Detail Matched PO using Total Amount and Total Qty based on OrderLine
                        MMatchPO[] mPO = MMatchPO.getOrderLine(getCtx(), m_oLine.getC_OrderLine_ID(), po.get_TrxName());
                        BigDecimal tQty = Env.ZERO;
                        BigDecimal tAmt = Env.ZERO;
                        for (int i = 0 ; i < mPO.length ; i++)
                        {
                                if (mPO[i].isPosted()
                                        && mPO[i].getM_AttributeSetInstance_ID() == po.getM_AttributeSetInstance_ID()
                                        && mPO[i].getM_MatchPO_ID() != get_ID())
                                {
                                        BigDecimal qty = (isReturnTrx ? mPO[i].getQty().negate() : mPO[i].getQty());
                                        tQty = tQty.add(qty);
                                        tAmt = tAmt.add(poCost.multiply(qty));
                                }
                        }
                        tAmt = tAmt.add(isReturnTrx ? poCost.negate() : poCost);
                        tQty = tQty.add(isReturnTrx ? po.getQty().negate() : po.getQty());
                        poCost = poCost.multiply(po.getQty());                  //      Delivered so far

                        //      Different currency
                        String costingMethod = as.getCostingMethod();
                        if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID())
                        {
                                MOrder order = m_oLine.getParent();
                                Timestamp dateAcct = order.getDateAcct();
                                if (MAcctSchema.COSTINGMETHOD_AveragePO.equals(costingMethod) ||
                                                MAcctSchema.COSTINGMETHOD_LastPOPrice.equals(costingMethod) )
                                        dateAcct = po.getDateAcct();    //Movement Date
                                BigDecimal rate = MConversionRate.getRate(
                                        order.getC_Currency_ID(), as.getC_Currency_ID(),
                                        dateAcct, order.getC_ConversionType_ID(),
                                        m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID());
                                if (rate == null)
                                {
                                        return "Purchase Order not convertible - " + as.getName();
                                }
                                poCost = poCost.multiply(rate);
                                if (poCost.scale() > as.getCostingPrecision())
                                        poCost = poCost.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
                                tAmt = tAmt.multiply(rate);
                                if (tAmt.scale() > as.getCostingPrecision())
                                        tAmt = tAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
                        }

                        // Set Total Amount and Total Quantity from Matched PO
                        MCostDetail.createOrder(as, m_oLine.getAD_Org_ID(),
                                        po.getM_Product_ID(), po.getM_AttributeSetInstance_ID(),
                                        m_oLine.getC_OrderLine_ID(), 0,         //      no cost element
                                        tAmt, tQty,                     //      Delivered
                                        m_oLine.getDescription(), po.get_TrxName());
                        // end MZ
                        // end
                }

                return "";
        }

Oh dear, with this source, Adempiere tells to me that they converted some value which already converted. It means they converted IDR values to USD and then converted again. Well, its okay. While we have Adempiere source code, we can remove re-converted codes by my self. Creating some fixes and then, we were doing cross check with the createMatchPOCostDetail method codes within Adempiere trunk for M_InOut.

That was good. Fortunately, while comparing our fix codes with the codes within trunk, this codes already fixed. Here is the fixed codes for those methods within Adempiere 352a patches, revision 6135

private String createMatchPOCostDetail(MMatchPO po, MOrderLine m_oLine)
        {
                // Get Account Schemas to create MCostDetail
                MAcctSchema[] acctschemas = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
                for(int asn = 0; asn < acctschemas.length; asn++)
                {
                        MAcctSchema as = acctschemas[asn];

                        boolean skip = false;
                        if (as.getAD_OrgOnly_ID() != 0)
                        {
                                if (as.getOnlyOrgs() == null)
                                        as.setOnlyOrgs(MReportTree.getChildIDs(getCtx(),
                                                0, MAcctSchemaElement.ELEMENTTYPE_Organization,
                                                as.getAD_OrgOnly_ID()));

                                //      Header Level Org
                                skip = as.isSkipOrg(getAD_Org_ID());
                                //      Line Level Org
                                skip = as.isSkipOrg(m_oLine.getAD_Org_ID());
                        }
                        if (skip)
                                continue;

                        // Purchase Order Line
                        BigDecimal poCost = m_oLine.getPriceCost();
                        if (poCost == null || poCost.signum() == 0)
                                poCost = m_oLine.getPriceActual();

                        // Source from Doc_MatchPO.createFacts(MAcctSchema)
                        MInOutLine receiptLine = new MInOutLine (getCtx(), po.getM_InOutLine_ID(), po.get_TrxName());
                        MInOut inOut = receiptLine.getParent();
                        boolean isReturnTrx = inOut.getMovementType().equals(X_M_InOut.MOVEMENTTYPE_VendorReturns);

                        //      Create PO Cost Detail Record first
                        // MZ Goodwill
                        // Create Cost Detail Matched PO using Total Amount and Total Qty based on OrderLine
                        MMatchPO[] mPO = MMatchPO.getOrderLine(getCtx(), m_oLine.getC_OrderLine_ID(), po.get_TrxName());
                        BigDecimal tQty = Env.ZERO;
                        BigDecimal tAmt = Env.ZERO;
                        for (int i = 0 ; i < mPO.length ; i++)
                        {
                                if (mPO[i].isPosted()
                                        && mPO[i].getM_AttributeSetInstance_ID() == po.getM_AttributeSetInstance_ID()
                                        && mPO[i].getM_MatchPO_ID() != get_ID())
                                {
                                        BigDecimal qty = (isReturnTrx ? mPO[i].getQty().negate() : mPO[i].getQty());
                                        tQty = tQty.add(qty);
                                        tAmt = tAmt.add(poCost.multiply(qty));
                                }
                        }

                        poCost = poCost.multiply(po.getQty());                  //      Delivered so far
                        tAmt = tAmt.add(isReturnTrx ? poCost.negate() : poCost);
                        tQty = tQty.add(isReturnTrx ? po.getQty().negate() : po.getQty());

                        //      Different currency
                        String costingMethod = as.getCostingMethod();
                        if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID())
                        {
                                MOrder order = m_oLine.getParent();
                                Timestamp dateAcct = order.getDateAcct();
                                if (MAcctSchema.COSTINGMETHOD_AveragePO.equals(costingMethod) ||
                                                MAcctSchema.COSTINGMETHOD_LastPOPrice.equals(costingMethod) )
                                        dateAcct = po.getDateAcct();    //Movement Date
                                BigDecimal rate = MConversionRate.getRate(
                                        order.getC_Currency_ID(), as.getC_Currency_ID(),
                                        dateAcct, order.getC_ConversionType_ID(),
                                        m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID());
                                if (rate == null)
                                {
                                        return "Purchase Order not convertible - " + as.getName();
                                }
                                poCost = poCost.multiply(rate);
                                if (poCost.scale() > as.getCostingPrecision())
                                        poCost = poCost.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
                                tAmt = tAmt.multiply(rate);
                                if (tAmt.scale() > as.getCostingPrecision())
                                        tAmt = tAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
                        }

                        // Set Total Amount and Total Quantity from Matched PO
                        MCostDetail.createOrder(as, m_oLine.getAD_Org_ID(),
                                        po.getM_Product_ID(), po.getM_AttributeSetInstance_ID(),
                                        m_oLine.getC_OrderLine_ID(), 0,         //      no cost element
                                        tAmt, tQty,                     //      Delivered
                                        m_oLine.getDescription(), po.get_TrxName());
                        // end MZ
                        // end
                }

                return "";
        }

 

Thanks to Adempiere community with this fixes of codes. For now, what will we do after rectified this code? You absolutely right, we have to build our patch within customization. (Note: while we can built this codes by our self, you can directly download Adempiere patches for 352a version. As far as I know, Adempiere provides regular weekly patches, which containing the last fixed/improvement codes from Adempiere trunk). Run silent setup to merged this patch/customization within our Adempiere core and test your transaction again.

Okay, it seems working for now. Take a look within below figure

idr-usd-cost-detail

It is enough for now. And hope this helpful.

1 Response to "Multi Accounting Schema #3"

1 | RYErnest

December 1st, 2008 at 10:56 pm

Nice post u have here :D Added to my RSS reader

Comment Form

SEO Powered by Platinum SEO from Techblissonline