IDEMPIERE-4173 Wrong GL postings for matched invoice in RMA/Vendor Re… (#239)
* IDEMPIERE-4173 Wrong GL postings for matched invoice in RMA/Vendor Return/Credit Memo * IDEMPIERE-4173 Wrong GL postings for matched invoice in RMA/Vendor Return/Credit Memo - Added test case
This commit is contained in:
parent
970936d08c
commit
236729e3f5
|
@ -162,6 +162,9 @@ public class Doc_MatchInv extends Doc
|
|||
return createCreditMemoFacts(as);
|
||||
}
|
||||
|
||||
if (m_receiptLine.getParent().getC_DocType().getDocBaseType().equals(DOCTYPE_MatShipment))
|
||||
return createMatShipmentFacts(as);
|
||||
|
||||
// create Fact Header
|
||||
Fact fact = new Fact(this, as, Fact.POST_Actual);
|
||||
setC_Currency_ID (as.getC_Currency_ID());
|
||||
|
@ -582,6 +585,214 @@ public class Doc_MatchInv extends Doc
|
|||
return "";
|
||||
}
|
||||
|
||||
private ArrayList<Fact> createMatShipmentFacts(MAcctSchema as) {
|
||||
ArrayList<Fact> facts = new ArrayList<Fact>();
|
||||
|
||||
// create Fact Header
|
||||
Fact fact = new Fact(this, as, Fact.POST_Actual);
|
||||
setC_Currency_ID (as.getC_Currency_ID());
|
||||
boolean isInterOrg = isInterOrg(as);
|
||||
|
||||
// NotInvoicedReceipt DR
|
||||
// From Receipt
|
||||
BigDecimal multiplier = getQty()
|
||||
.divide(m_receiptLine.getMovementQty(), 12, RoundingMode.HALF_UP);
|
||||
multiplier = multiplier.negate();
|
||||
FactLine dr = fact.createLine (null,
|
||||
getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as),
|
||||
as.getC_Currency_ID(), null, Env.ONE); // updated below
|
||||
if (dr == null)
|
||||
{
|
||||
p_Error = "No Product Costs";
|
||||
return null;
|
||||
}
|
||||
dr.setQty(getQty());
|
||||
BigDecimal temp = dr.getAcctBalance();
|
||||
// Set AmtAcctCr/Dr from Receipt (sets also Project)
|
||||
if (m_matchInv.getReversal_ID() > 0)
|
||||
{
|
||||
if (!dr.updateReverseLine (MMatchInv.Table_ID, // Amt updated
|
||||
m_matchInv.getReversal_ID(), 0, BigDecimal.ONE))
|
||||
{
|
||||
p_Error = "Failed to create reversal entry";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dr.updateReverseLine (MInOut.Table_ID, // Amt updated
|
||||
m_receiptLine.getM_InOut_ID(), m_receiptLine.getM_InOutLine_ID(),
|
||||
multiplier))
|
||||
{
|
||||
p_Error = "Mat.Shipment not posted yet";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (log.isLoggable(Level.FINE)) log.fine("CR - Amt(" + temp + "->" + dr.getAcctBalance()
|
||||
+ ") - " + dr.toString());
|
||||
|
||||
// InventoryClearing CR
|
||||
// From Invoice
|
||||
MAccount expense = m_pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
|
||||
if (m_pc.isService())
|
||||
expense = m_pc.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
|
||||
BigDecimal LineNetAmt = m_invoiceLine.getLineNetAmt();
|
||||
multiplier = getQty()
|
||||
.divide(m_invoiceLine.getQtyInvoiced(), 12, RoundingMode.HALF_UP);
|
||||
multiplier = multiplier.negate();
|
||||
if (multiplier.compareTo(Env.ONE) != 0)
|
||||
LineNetAmt = LineNetAmt.multiply(multiplier);
|
||||
if (m_pc.isService())
|
||||
LineNetAmt = dr.getAcctBalance(); // book out exact receipt amt
|
||||
FactLine cr = null;
|
||||
if (as.isAccrual())
|
||||
{
|
||||
cr = fact.createLine (null, expense,
|
||||
as.getC_Currency_ID(), LineNetAmt, null); // updated below
|
||||
if (cr == null)
|
||||
{
|
||||
if (log.isLoggable(Level.FINE)) log.fine("Line Net Amt=0 - M_Product_ID=" + getM_Product_ID()
|
||||
+ ",Qty=" + getQty() + ",InOutQty=" + m_receiptLine.getMovementQty());
|
||||
|
||||
cr = fact.createLine (null, expense, as.getC_Currency_ID(), Env.ONE, null);
|
||||
cr.setAmtAcctCr(BigDecimal.ZERO);
|
||||
cr.setAmtSourceCr(BigDecimal.ZERO);
|
||||
}
|
||||
temp = cr.getAcctBalance();
|
||||
if (m_matchInv.getReversal_ID() > 0)
|
||||
{
|
||||
if (!cr.updateReverseLine (MMatchInv.Table_ID, // Amt updated
|
||||
m_matchInv.getReversal_ID(), 0, BigDecimal.ONE))
|
||||
{
|
||||
p_Error = "Failed to create reversal entry";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cr.setQty(getQty().negate());
|
||||
|
||||
// Set AmtAcctCr/Dr from Invoice (sets also Project)
|
||||
if (!cr.updateReverseLine (MInvoice.Table_ID, // Amt updated
|
||||
m_invoiceLine.getC_Invoice_ID(), m_invoiceLine.getC_InvoiceLine_ID(), multiplier))
|
||||
{
|
||||
p_Error = "Invoice not posted yet";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (log.isLoggable(Level.FINE)) log.fine("DR - Amt(" + temp + "->" + cr.getAcctBalance()
|
||||
+ ") - " + cr.toString());
|
||||
}
|
||||
else // Cash Acct
|
||||
{
|
||||
MInvoice invoice = m_invoiceLine.getParent();
|
||||
if (as.getC_Currency_ID() != invoice.getC_Currency_ID())
|
||||
LineNetAmt = MConversionRate.convert(getCtx(), LineNetAmt,
|
||||
invoice.getC_Currency_ID(), as.getC_Currency_ID(),
|
||||
invoice.getDateAcct(), invoice.getC_ConversionType_ID(),
|
||||
invoice.getAD_Client_ID(), invoice.getAD_Org_ID());
|
||||
cr = fact.createLine (null, expense,
|
||||
as.getC_Currency_ID(), LineNetAmt, null);
|
||||
if (m_matchInv.getReversal_ID() > 0)
|
||||
{
|
||||
if (!cr.updateReverseLine (MMatchInv.Table_ID, // Amt updated
|
||||
m_matchInv.getReversal_ID(), 0, BigDecimal.ONE))
|
||||
{
|
||||
p_Error = "Failed to create reversal entry";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cr.setQty(getQty().multiply(multiplier).negate());
|
||||
}
|
||||
}
|
||||
|
||||
// Rounding correction
|
||||
if (m_receiptLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
|
||||
{
|
||||
p_Error = createReceiptGainLoss(as, fact, getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as), m_receiptLine.getParent(), dr.getAmtSourceCr(), dr.getAmtAcctCr());
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
if (m_invoiceLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
|
||||
{
|
||||
p_Error = createInvoiceGainLoss(as, fact, expense, m_invoiceLine.getParent(), cr.getAmtSourceDr(), cr.getAmtAcctDr());
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_matchInv.getReversal_ID() == 0)
|
||||
{
|
||||
cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
|
||||
cr.setC_Campaign_ID(m_invoiceLine.getC_Campaign_ID());
|
||||
cr.setC_Project_ID(m_invoiceLine.getC_Project_ID());
|
||||
cr.setC_ProjectPhase_ID(m_invoiceLine.getC_ProjectPhase_ID());
|
||||
cr.setC_ProjectTask_ID(m_invoiceLine.getC_ProjectTask_ID());
|
||||
cr.setC_UOM_ID(m_invoiceLine.getC_UOM_ID());
|
||||
cr.setUser1_ID(m_invoiceLine.getUser1_ID());
|
||||
cr.setUser2_ID(m_invoiceLine.getUser2_ID());
|
||||
}
|
||||
else
|
||||
{
|
||||
updateFactLine(cr);
|
||||
}
|
||||
|
||||
//AZ Goodwill
|
||||
//Desc: Source Not Balanced problem because Currency is Difference - PO=CNY but AP=USD
|
||||
//see also Fact.java: checking for isMultiCurrency()
|
||||
if (dr.getC_Currency_ID() != cr.getC_Currency_ID())
|
||||
setIsMultiCurrency(true);
|
||||
//end AZ
|
||||
|
||||
// Avoid usage of clearing accounts
|
||||
// If both accounts Not Invoiced Receipts and Inventory Clearing are equal
|
||||
// then remove the posting
|
||||
|
||||
MAccount acct_db = dr.getAccount(); // not_invoiced_receipts
|
||||
MAccount acct_cr = cr.getAccount(); // inventory_clearing
|
||||
|
||||
if ((!as.isPostIfClearingEqual()) && acct_db.equals(acct_cr) && (!isInterOrg)) {
|
||||
|
||||
BigDecimal debit = dr.getAmtSourceDr();
|
||||
BigDecimal credit = cr.getAmtSourceCr();
|
||||
|
||||
if (debit.compareTo(credit) == 0) {
|
||||
fact.remove(dr);
|
||||
fact.remove(cr);
|
||||
}
|
||||
|
||||
}
|
||||
// End Avoid usage of clearing accounts
|
||||
|
||||
|
||||
// Invoice Price Variance difference
|
||||
BigDecimal ipv = cr.getAcctBalance().add(dr.getAcctBalance()).negate();
|
||||
processInvoicePriceVariance(as, fact, ipv);
|
||||
if (log.isLoggable(Level.FINE)) log.fine("IPV=" + ipv + "; Balance=" + fact.getSourceBalance());
|
||||
|
||||
String error = createMatchInvCostDetail(as);
|
||||
if (error != null && error.trim().length() > 0)
|
||||
{
|
||||
p_Error = error;
|
||||
return null;
|
||||
}
|
||||
//
|
||||
facts.add(fact);
|
||||
|
||||
/** Commitment release ****/
|
||||
if (as.isAccrual() && as.isCreatePOCommitment())
|
||||
{
|
||||
fact = Doc_Order.getCommitmentRelease(as, this,
|
||||
getQty(), m_invoiceLine.getC_InvoiceLine_ID(), Env.ONE);
|
||||
if (fact == null)
|
||||
return null;
|
||||
facts.add(fact);
|
||||
} // Commitment
|
||||
|
||||
return facts;
|
||||
}
|
||||
|
||||
public ArrayList<Fact> createCreditMemoFacts(MAcctSchema as) {
|
||||
ArrayList<Fact> facts = new ArrayList<Fact>();
|
||||
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
/***********************************************************************
|
||||
* This file is part of iDempiere ERP Open Source *
|
||||
* http://www.idempiere.org *
|
||||
* *
|
||||
* Copyright (C) Contributors *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301, USA. *
|
||||
* *
|
||||
* Contributors: *
|
||||
* - Elaine Tan - etantg *
|
||||
**********************************************************************/
|
||||
package org.idempiere.test.base;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.compiere.acct.Doc;
|
||||
import org.compiere.acct.DocManager;
|
||||
import org.compiere.model.MAccount;
|
||||
import org.compiere.model.MAcctSchema;
|
||||
import org.compiere.model.MBPartner;
|
||||
import org.compiere.model.MClientInfo;
|
||||
import org.compiere.model.MDocType;
|
||||
import org.compiere.model.MFactAcct;
|
||||
import org.compiere.model.MInOut;
|
||||
import org.compiere.model.MInOutLine;
|
||||
import org.compiere.model.MInvoice;
|
||||
import org.compiere.model.MInvoiceLine;
|
||||
import org.compiere.model.MMatchInv;
|
||||
import org.compiere.model.MOrder;
|
||||
import org.compiere.model.MOrderLine;
|
||||
import org.compiere.model.MProduct;
|
||||
import org.compiere.model.MRMA;
|
||||
import org.compiere.model.MRMALine;
|
||||
import org.compiere.model.MWarehouse;
|
||||
import org.compiere.model.ProductCost;
|
||||
import org.compiere.process.DocAction;
|
||||
import org.compiere.process.DocumentEngine;
|
||||
import org.compiere.process.ProcessInfo;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.wf.MWorkflow;
|
||||
import org.idempiere.test.AbstractTestCase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Elaine Tan - etantg
|
||||
*/
|
||||
public class MatchInvTest extends AbstractTestCase {
|
||||
|
||||
public MatchInvTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* https://idempiere.atlassian.net/browse/IDEMPIERE-4173
|
||||
*/
|
||||
public void testMatShipmentPosting() {
|
||||
MBPartner bpartner = MBPartner.get(Env.getCtx(), 114); // Tree Farm Inc.
|
||||
MProduct product = MProduct.get(Env.getCtx(), 124); // Elm Tree
|
||||
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
order.setBPartner(bpartner);
|
||||
order.setIsSOTrx(false);
|
||||
order.setC_DocTypeTarget_ID();
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
order.saveEx();
|
||||
|
||||
MOrderLine orderLine = new MOrderLine(order);
|
||||
orderLine.setLine(10);
|
||||
orderLine.setProduct(product);
|
||||
orderLine.setQty(BigDecimal.ONE);
|
||||
orderLine.saveEx();
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
order.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
|
||||
MInOut receipt = new MInOut(order, 122, order.getDateOrdered()); // MM Receipt
|
||||
receipt.saveEx();
|
||||
|
||||
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||
receiptLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||
receiptLine.setLine(10);
|
||||
receiptLine.setProduct(product);
|
||||
receiptLine.setQty(BigDecimal.ONE);
|
||||
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||
receiptLine.setM_Locator_ID(M_Locator_ID);
|
||||
receiptLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||
receipt.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||
|
||||
if (!receipt.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), receipt.getAD_Client_ID(), MInOut.Table_ID, receipt.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
receipt.load(getTrxName());
|
||||
assertTrue(receipt.isPosted());
|
||||
|
||||
MRMA rma = new MRMA(Env.getCtx(), 0, getTrxName());
|
||||
rma.setName(order.getDocumentNo());
|
||||
rma.setC_DocType_ID(150); // Vendor Return Material
|
||||
rma.setM_RMAType_ID(100); // Damaged on Arrival
|
||||
rma.setM_InOut_ID(receipt.get_ID());
|
||||
rma.setIsSOTrx(false);
|
||||
rma.setSalesRep_ID(100); // SuperUser
|
||||
rma.saveEx();
|
||||
|
||||
MRMALine rmaLine = new MRMALine(Env.getCtx(), 0, getTrxName());
|
||||
rmaLine.setLine(10);
|
||||
rmaLine.setM_RMA_ID(rma.get_ID());
|
||||
rmaLine.setM_InOutLine_ID(receiptLine.get_ID());
|
||||
rmaLine.setQty(BigDecimal.ONE);
|
||||
rmaLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(rma, DocAction.ACTION_Complete);
|
||||
rma.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, rma.getDocStatus());
|
||||
|
||||
MInOut delivery = new MInOut(Env.getCtx(), 0, getTrxName());
|
||||
delivery.setM_RMA_ID(rma.get_ID());
|
||||
delivery.setBPartner(bpartner);
|
||||
delivery.setIsSOTrx(false);
|
||||
delivery.setMovementType(MInOut.MOVEMENTTYPE_VendorReturns);
|
||||
delivery.setC_DocType_ID(151); // MM Vendor Return
|
||||
delivery.setDocStatus(DocAction.STATUS_Drafted);
|
||||
delivery.setDocAction(DocAction.ACTION_Complete);
|
||||
delivery.setM_Warehouse_ID(receipt.getM_Warehouse_ID());
|
||||
delivery.saveEx();
|
||||
|
||||
MInOutLine deliveryLine = new MInOutLine(delivery);
|
||||
deliveryLine.setM_RMALine_ID(rmaLine.get_ID());
|
||||
deliveryLine.setLine(10);
|
||||
deliveryLine.setProduct(product);
|
||||
deliveryLine.setQty(BigDecimal.ONE);
|
||||
deliveryLine.setM_Locator_ID(receiptLine.getM_Locator_ID());
|
||||
deliveryLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(delivery, DocAction.ACTION_Complete);
|
||||
delivery.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, delivery.getDocStatus());
|
||||
|
||||
if (!delivery.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), delivery.getAD_Client_ID(), MInOut.Table_ID, delivery.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
delivery.load(getTrxName());
|
||||
assertTrue(delivery.isPosted());
|
||||
|
||||
MInvoice creditMemo = new MInvoice(delivery, delivery.getMovementDate());
|
||||
creditMemo.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APCreditMemo);
|
||||
creditMemo.setDocStatus(DocAction.STATUS_Drafted);
|
||||
creditMemo.setDocAction(DocAction.ACTION_Complete);
|
||||
creditMemo.saveEx();
|
||||
|
||||
MInvoiceLine creditMemoLine = new MInvoiceLine(creditMemo);
|
||||
creditMemoLine.setM_InOutLine_ID(deliveryLine.get_ID());
|
||||
creditMemoLine.setLine(10);
|
||||
creditMemoLine.setProduct(product);
|
||||
creditMemoLine.setQty(BigDecimal.ONE);
|
||||
creditMemoLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(creditMemo, DocAction.ACTION_Complete);
|
||||
creditMemo.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, creditMemo.getDocStatus());
|
||||
|
||||
if (!creditMemo.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), creditMemo.getAD_Client_ID(), MInvoice.Table_ID, creditMemo.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
creditMemo.load(getTrxName());
|
||||
assertTrue(creditMemo.isPosted());
|
||||
|
||||
int C_AcctSchema_ID = MClientInfo.get(Env.getCtx()).getC_AcctSchema1_ID();
|
||||
MAcctSchema as = MAcctSchema.get(Env.getCtx(), C_AcctSchema_ID);
|
||||
MMatchInv[] miList = MMatchInv.getInvoiceLine(Env.getCtx(), creditMemoLine.get_ID(), getTrxName());
|
||||
for (MMatchInv mi : miList) {
|
||||
if (!mi.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), mi.getAD_Client_ID(), MMatchInv.Table_ID, mi.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
mi.load(getTrxName());
|
||||
assertTrue(mi.isPosted());
|
||||
|
||||
Doc doc = DocManager.getDocument(as, MMatchInv.Table_ID, mi.get_ID(), getTrxName());
|
||||
doc.setC_BPartner_ID(mi.getC_InvoiceLine().getC_Invoice().getC_BPartner_ID());
|
||||
MAccount acctNIR = doc.getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as);
|
||||
|
||||
ProductCost pc = new ProductCost (Env.getCtx(), mi.getM_Product_ID(), mi.getM_AttributeSetInstance_ID(), getTrxName());
|
||||
MAccount acctInvClr = pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
|
||||
|
||||
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MMatchInv.Table_ID
|
||||
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + mi.get_ID()
|
||||
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + C_AcctSchema_ID;
|
||||
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
|
||||
for (int id : ids) {
|
||||
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
|
||||
if (fa.getAccount_ID() == acctNIR.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctCr().compareTo(Env.ZERO) >= 0);
|
||||
else if (fa.getAccount_ID() == acctInvClr.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctDr().compareTo(Env.ZERO) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
rollback();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* https://idempiere.atlassian.net/browse/IDEMPIERE-4173
|
||||
*/
|
||||
public void testMatReceiptPosting() {
|
||||
MBPartner bpartner = MBPartner.get(Env.getCtx(), 114); // Tree Farm Inc.
|
||||
MProduct product = MProduct.get(Env.getCtx(), 124); // Elm Tree
|
||||
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
order.setBPartner(bpartner);
|
||||
order.setIsSOTrx(false);
|
||||
order.setC_DocTypeTarget_ID();
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
order.saveEx();
|
||||
|
||||
MOrderLine orderLine = new MOrderLine(order);
|
||||
orderLine.setLine(10);
|
||||
orderLine.setProduct(product);
|
||||
orderLine.setQty(BigDecimal.ONE);
|
||||
orderLine.saveEx();
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
order.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
|
||||
MInOut receipt = new MInOut(order, 122, order.getDateOrdered()); // MM Receipt
|
||||
receipt.saveEx();
|
||||
|
||||
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||
receiptLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||
receiptLine.setLine(10);
|
||||
receiptLine.setProduct(product);
|
||||
receiptLine.setQty(BigDecimal.ONE);
|
||||
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||
receiptLine.setM_Locator_ID(M_Locator_ID);
|
||||
receiptLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||
receipt.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||
|
||||
if (!receipt.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), receipt.getAD_Client_ID(), MInOut.Table_ID, receipt.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
receipt.load(getTrxName());
|
||||
assertTrue(receipt.isPosted());
|
||||
|
||||
MInvoice invoice = new MInvoice(receipt, receipt.getMovementDate());
|
||||
invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APInvoice);
|
||||
invoice.setDocStatus(DocAction.STATUS_Drafted);
|
||||
invoice.setDocAction(DocAction.ACTION_Complete);
|
||||
invoice.saveEx();
|
||||
|
||||
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
|
||||
invoiceLine.setM_InOutLine_ID(receiptLine.get_ID());
|
||||
invoiceLine.setLine(10);
|
||||
invoiceLine.setProduct(product);
|
||||
invoiceLine.setQty(BigDecimal.ONE);
|
||||
invoiceLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
|
||||
invoice.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
|
||||
|
||||
if (!invoice.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), invoice.getAD_Client_ID(), MInvoice.Table_ID, invoice.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
invoice.load(getTrxName());
|
||||
assertTrue(invoice.isPosted());
|
||||
|
||||
int C_AcctSchema_ID = MClientInfo.get(Env.getCtx()).getC_AcctSchema1_ID();
|
||||
MAcctSchema as = MAcctSchema.get(Env.getCtx(), C_AcctSchema_ID);
|
||||
MMatchInv[] miList = MMatchInv.getInvoiceLine(Env.getCtx(), invoiceLine.get_ID(), getTrxName());
|
||||
for (MMatchInv mi : miList) {
|
||||
if (!mi.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), mi.getAD_Client_ID(), MMatchInv.Table_ID, mi.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
mi.load(getTrxName());
|
||||
assertTrue(mi.isPosted());
|
||||
|
||||
Doc doc = DocManager.getDocument(as, MMatchInv.Table_ID, mi.get_ID(), getTrxName());
|
||||
doc.setC_BPartner_ID(mi.getC_InvoiceLine().getC_Invoice().getC_BPartner_ID());
|
||||
MAccount acctNIR = doc.getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as);
|
||||
|
||||
ProductCost pc = new ProductCost (Env.getCtx(), mi.getM_Product_ID(), mi.getM_AttributeSetInstance_ID(), getTrxName());
|
||||
MAccount acctInvClr = pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
|
||||
|
||||
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MMatchInv.Table_ID
|
||||
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + mi.get_ID()
|
||||
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + C_AcctSchema_ID;
|
||||
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
|
||||
for (int id : ids) {
|
||||
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
|
||||
if (fa.getAccount_ID() == acctNIR.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctDr().compareTo(Env.ZERO) >= 0);
|
||||
else if (fa.getAccount_ID() == acctInvClr.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctCr().compareTo(Env.ZERO) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
rollback();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue