From bb2bbc710c77e6a9ccac335a4a7d92a4a547d52b Mon Sep 17 00:00:00 2001 From: Patric Massing <65012954+pmassing@users.noreply.github.com> Date: Mon, 5 Jul 2021 21:02:44 +0200 Subject: [PATCH] =?UTF-8?q?IDEMPIERE-4828-posting=20of=20Allocation=20with?= =?UTF-8?q?=20a=20AR=20Credit=20Memos=20with=20disc=E2=80=A6=20(#745)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IDEMPIERE-4828-posting of Allocation with a AR Credit Memos with discount, the tax-correction has the wrong sign * IDEMPIERE-4828 - posting of Allocation with a AR Credit Memos with discount, the tax-correction has the wrong sign check for DocBaseType --- .../org/compiere/acct/Doc_AllocationHdr.java | 128 +- .../idempiere/test/model/AllocationTest.java | 1393 ++++++++++++++++- 2 files changed, 1488 insertions(+), 33 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java index 3e6b8ac9ec..0166d4e2ef 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java @@ -32,6 +32,7 @@ import org.compiere.model.MAllocationHdr; import org.compiere.model.MAllocationLine; import org.compiere.model.MCashLine; import org.compiere.model.MConversionRate; +import org.compiere.model.MDocType; import org.compiere.model.MFactAcct; import org.compiere.model.MInvoice; import org.compiere.model.MInvoiceLine; @@ -1856,6 +1857,9 @@ class Doc_AllocationTax return false; } + Doc doc = DocManager.getDocument(as, MInvoice.Table_ID, factAcct.getRecord_ID(), line.getPO().get_TrxName()); + MDocType dt = new MDocType(Env.getCtx(), (doc!=null)?doc.getC_DocType_ID():-1, line.getPO().get_TrxName()); + String docBaseType=(dt.getC_DocType_ID()>0)?dt.getDocBaseType():""; // Discount Amount if (m_DiscountAmt.signum() != 0) @@ -1865,22 +1869,37 @@ class Doc_AllocationTax { BigDecimal amount = calcAmount(factAcct.getAmtSourceDr(), total, m_DiscountAmt, precision); + if (amount.signum() != 0) { //for sales actions if (m_IsSOTrx) { - fact.createLine (line, m_DiscountAccount, - as.getC_Currency_ID(), amount, null); - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), null, amount); + if(docBaseType.equals(MDocType.DOCBASETYPE_ARCreditMemo)) { + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount.negate()); + }else { + + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount); + } } else { //for purchase actions - fact.createLine (line, m_DiscountAccount, - as.getC_Currency_ID(), amount.negate(), null); - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), null, amount.negate()); + if(docBaseType.equals(MDocType.DOCBASETYPE_APCreditMemo)) { + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount); + } else { + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount.negate()); + } } - } } // Original Tax is CR - need to correct it DR @@ -1892,15 +1911,33 @@ class Doc_AllocationTax { // for sales actions if (m_IsSOTrx) { - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), amount, null); - fact.createLine (line, m_DiscountAccount, - as.getC_Currency_ID(), null, amount); + if(docBaseType.equals(MDocType.DOCBASETYPE_ARCreditMemo)) { + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), null, amount.negate()); + }else { + + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), null, amount); + } + } else { - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), amount.negate(), null); - fact.createLine (line, m_DiscountAccount, - as.getC_Currency_ID(), null, amount.negate()); + if(docBaseType.equals(MDocType.DOCBASETYPE_APCreditMemo)) { + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), null, amount); + }else { + + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, m_DiscountAccount, + as.getC_Currency_ID(), null, amount.negate()); + } + } } } @@ -1917,15 +1954,29 @@ class Doc_AllocationTax if (amount.signum() != 0) { if (m_IsSOTrx) { - fact.createLine (line, m_WriteOffAccount, - as.getC_Currency_ID(), amount, null); - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), null, amount); - } else { - fact.createLine (line, m_WriteOffAccount, + if(docBaseType.equals(MDocType.DOCBASETYPE_ARCreditMemo)) { + fact.createLine (line, m_WriteOffAccount, as.getC_Currency_ID(), amount.negate(), null); - fact.createLine (line, taxAcct, + fact.createLine (line, taxAcct, as.getC_Currency_ID(), null, amount.negate()); + } else { + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount); + } + } else { + if(docBaseType.equals(MDocType.DOCBASETYPE_APCreditMemo)) { + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount); + } else { + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), null, amount.negate()); + } } } } @@ -1937,20 +1988,33 @@ class Doc_AllocationTax if (amount.signum() != 0) { if(m_IsSOTrx) { - fact.createLine (line, taxAcct, - as.getC_Currency_ID(), amount, null); - fact.createLine (line, m_WriteOffAccount, - as.getC_Currency_ID(), null, amount); - } else { - fact.createLine (line, taxAcct, + if(docBaseType.equals(MDocType.DOCBASETYPE_ARCreditMemo)) { + fact.createLine (line, taxAcct, as.getC_Currency_ID(), amount.negate(), null); - fact.createLine (line, m_WriteOffAccount, + fact.createLine (line, m_WriteOffAccount, as.getC_Currency_ID(), null, amount.negate()); + } else { + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), null, amount); + } + } else { + if(docBaseType.equals(MDocType.DOCBASETYPE_APCreditMemo)) { + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount, null); + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), null, amount); + } else { + fact.createLine (line, taxAcct, + as.getC_Currency_ID(), amount.negate(), null); + fact.createLine (line, m_WriteOffAccount, + as.getC_Currency_ID(), null, amount.negate()); + } } } } } // WriteOff - } // for all lines return true; } // createEntries diff --git a/org.idempiere.test/src/org/idempiere/test/model/AllocationTest.java b/org.idempiere.test/src/org/idempiere/test/model/AllocationTest.java index c08058f33e..b0854d9353 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/AllocationTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/AllocationTest.java @@ -29,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; +import java.math.RoundingMode; import java.sql.Timestamp; import java.util.Calendar; import java.util.Properties; @@ -584,7 +585,26 @@ public class AllocationTest extends AbstractTestCase { payment.saveEx(); return payment; } - + + + private MPayment createPayment(int C_BPartner_ID, int C_BankAccount_ID, Timestamp date, int C_Currency_ID, int C_ConversionType_ID, BigDecimal payAmt) { + MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName()); + payment.setC_BankAccount_ID(C_BankAccount_ID); + payment.setC_DocType_ID(false); + payment.setDateTrx(date); + payment.setDateAcct(date); + payment.setC_BPartner_ID(C_BPartner_ID); + payment.setPayAmt(payAmt); + payment.setC_Currency_ID(C_Currency_ID); + payment.setC_ConversionType_ID(C_ConversionType_ID); + payment.setTenderType(MPayment.TENDERTYPE_Check); + payment.setDocStatus(DocAction.STATUS_Drafted); + payment.setDocAction(DocAction.ACTION_Complete); + payment.saveEx(); + return payment; + } + + private void completeDocument(PO po) { ProcessInfo info = MWorkflow.runDocumentActionWorkflow(po, DocAction.ACTION_Complete); po.load(getTrxName()); @@ -609,4 +629,1375 @@ public class AllocationTest extends AbstractTestCase { po.load(getTrxName()); assertTrue(po.get_ValueAsBoolean("Posted")); } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AR Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm 2%10 Net 30) + // #2 Create Payment received + // #3 Allocate with discount 2.00$ and write-off 2.00$ + // #4 Check accounts + public void testAllocatePaymentPostingWithWriteOffandDiscountARInv() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 118); // Joe Block + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 106; //(2%10 Net 30) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(true,false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102"); + MPayment payment = createReceiptPayment(bpartner.getC_BPartner_ID(), ba.getC_BankAccount_ID(), date, usd.getC_Currency_ID(), 0, payAmt); + completeDocument(payment); + postDocument(payment); + + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(payment.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(payment.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2"); + BigDecimal writeoff = new BigDecimal("2"); + MAllocationLine aLine1 = new MAllocationLine(alloc, payment.getPayAmt(), discount, writeoff, Env.ZERO); + aLine1.setDocInfo(payment.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(payment.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 11130 Checking Unallocated Receipts | 102.00 | 0.00 + // 59201_Payment discount revenue | 2.00 | 0.00 + // 78100_Bad Debts Write-off | 2.00 | 0.00 + // 12110 Accounts Receivable - Trade | 0.00 | 106.00 + // 21610 Tax due | 0.11 | 0.00 + // 59201_Payment discount revenue | 0.00 | 0.11 + // 21610 Tax due | 0.11 | 0.00 + // 78100_Bad Debts Write-off | 0.00 | 0.11 + // -------------------------------------------------------------------- + MAccount acctUC = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_UnallocatedCash_Acct(), getTrxName()); + MAccount acctDEP = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Exp_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctART = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getC_Receivable_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Due_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctUC.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDEP.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } else if(fa.getAccount_ID() == acctART.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AR Credit Memo (TotalLines 100,GrandTotal 106) (PaymentTerm 2%10 Net 30) + // #2 Create Payment + // #3 Allocate with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testAllocatePaymentPostingWithWriteOffandDiscountARCredMemo() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 118); // Joe Block + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 106; //(2%10 Net 30) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(true, true, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102"); + MPayment payment = createPayment(bpartner.getC_BPartner_ID(), ba.getC_BankAccount_ID(), date, usd.getC_Currency_ID(), 0, payAmt); + completeDocument(payment); + postDocument(payment); + + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(payment.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(payment.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2").negate(); + BigDecimal writeoff = new BigDecimal("2").negate(); + MAllocationLine aLine1 = new MAllocationLine(alloc, payment.getPayAmt().negate(), discount, writeoff, Env.ZERO); + aLine1.setDocInfo(payment.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(payment.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21300_Payment selection | -102.00 | 0.00 + // 59201_Payment discount revenue | -2.00 | 0.00 + // 78100_Bad Debts Write-off | -2.00 | 0.00 + // 12110 Accounts Receivable - Trade | 0.00 | -106.00 + // 59201_Payment discount revenue | 0.11 | 0.00 + // 21610 Tax due | 0.00 | 0.11 + // 78100_Bad Debts Write-off | 0.11 | 0.00 + // 21610 Tax due | 0.00 | 0.11 + // -------------------------------------------------------------------- + MAccount acctPS = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_PaymentSelect_Acct(), getTrxName()); + MAccount acctDEP = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Exp_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctART = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getC_Receivable_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Due_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPS.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDEP.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctART.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00").negate()); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AP Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm Immediate) + // #2 Create Payment + // #3 Allocate with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testAllocatePaymentPostingWithWriteOffandDiscountAPInv() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 121); // Patio + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 105; //(Immediate) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(false, false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102"); + MPayment payment = createPayment(bpartner.getC_BPartner_ID(), ba.getC_BankAccount_ID(), date, usd.getC_Currency_ID(), 0, payAmt); + completeDocument(payment); + postDocument(payment); + + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(payment.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(payment.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2").negate(); + BigDecimal writeoff = new BigDecimal("2").negate(); + MAllocationLine aLine1 = new MAllocationLine(alloc, payment.getPayAmt().negate(), discount, writeoff, Env.ZERO); + aLine1.setDocInfo(payment.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(payment.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21100_Accounts Payable Trade 106,00 0,00 + // 59200_Payment discount revenue 0,00 2,00 + // 78100_Bad Debts Write-off 0,00 2,00 + // 21300_Payment selection 0,00 102,00 + // 59200_Payment discount revenue 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // 78100_Bad Debts Write-off 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // -------------------------------------------------------------------- + MAccount acctPT = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getV_Liability_Acct(), getTrxName()); + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctPS = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_PaymentSelect_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Credit_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPT.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctPS.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00")); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AP Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm Immediate) + // #2 Create Payment + // #3 Allocate with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testAllocatePaymentPostingWithWriteOffandDiscountAPCrMe() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 121); // Patio + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 105; //(Immediate) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(false, true, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102"); + MPayment payment = createReceiptPayment(bpartner.getC_BPartner_ID(), ba.getC_BankAccount_ID(), date, usd.getC_Currency_ID(), 0, payAmt); + completeDocument(payment); + postDocument(payment); + + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(payment.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(payment.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2"); + BigDecimal writeoff = new BigDecimal("2"); + MAllocationLine aLine1 = new MAllocationLine(alloc, payment.getPayAmt(), discount, writeoff, Env.ZERO); + aLine1.setDocInfo(payment.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(payment.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21100_Accounts Payable Trade -106,00 0,00 + // 59200_Payment discount revenue 0,00 -2,00 + // 78100_Bad Debts Write-off 0,00 -2,00 + // 21300_Payment selection 0,00 -102,00 + // 59200_Payment discount revenue 0,00 0,11 + // 12610_Tax credit A/R 0,11 0,00 + // 78100_Bad Debts Write-off 0,00 0,11 + // 12610_Tax credit A/R 0,11 0,00 + // -------------------------------------------------------------------- + MAccount acctPT = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getV_Liability_Acct(), getTrxName()); + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctUC = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_UnallocatedCash_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Credit_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPT.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctUC.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00").negate()); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // AR Invoice in payment + // #1 Create AR Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm Immediate) + // #2 Create Payment with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testPaymentPostingWithWriteOffandDiscountARInv() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 118); // Joe Block + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 106; //(2%10 Net 30) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(true,false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102"); + BigDecimal discount = new BigDecimal("2"); + BigDecimal writeoff = new BigDecimal("2"); + MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName()); + payment.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + payment.setC_DocType_ID(true); + payment.setDateTrx(date); + payment.setDateAcct(date); + payment.setC_BPartner_ID(bpartner.getC_BPartner_ID()); + payment.setC_Invoice_ID(invoice.getC_Invoice_ID()); + payment.setPayAmt(payAmt); + payment.setDiscountAmt(discount); + payment.setWriteOffAmt(writeoff); + payment.setC_Currency_ID(usd.getC_Currency_ID()); + payment.setC_ConversionType_ID(0); + payment.setTenderType(MPayment.TENDERTYPE_Check); + payment.setDocStatus(DocAction.STATUS_Drafted); + payment.setDocAction(DocAction.ACTION_Complete); + payment.saveEx(); + + completeDocument(payment); + postDocument(payment); + + MAllocationHdr[] allocationa = MAllocationHdr.getOfInvoice(Env.getCtx(), invoice.getC_Invoice_ID(), getTrxName()); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, allocationa[0].get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 11130 Checking Unallocated Receipts | 102.00 | 0.00 + // 59201_Payment discount revenue | 2.00 | 0.00 + // 78100_Bad Debts Write-off | 2.00 | 0.00 + // 12110 Accounts Receivable - Trade | 0.00 | 106.00 + // 21610 Tax due | 0.11 | 0.00 + // 59201_Payment discount revenue | 0.00 | 0.11 + // 21610 Tax due | 0.11 | 0.00 + // 78100_Bad Debts Write-off | 0.00 | 0.11 + // -------------------------------------------------------------------- + MAccount acctUC = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_UnallocatedCash_Acct(), getTrxName()); + MAccount acctDEP = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Exp_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctART = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getC_Receivable_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Due_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + allocationa[0].get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctUC.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDEP.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } else if(fa.getAccount_ID() == acctART.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // AR Credit Memo in payment + // #1 Create AR Credit Memo (TotalLines 100,GrandTotal 106) (PaymentTerm 2%10 Net 30) + // #2 Create Payment with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testPaymentPostingWithWriteOffandDiscountARCredMemo() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 118); // Joe Block + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 106; //(2%10 Net 30) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(true, true, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102").negate(); + BigDecimal discount = new BigDecimal("2").negate(); + BigDecimal writeoff = new BigDecimal("2").negate(); + MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName()); + payment.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + payment.setC_DocType_ID(true); + payment.setDateTrx(date); + payment.setDateAcct(date); + payment.setC_BPartner_ID(bpartner.getC_BPartner_ID()); + payment.setC_Invoice_ID(invoice.getC_Invoice_ID()); + payment.setPayAmt(payAmt); + payment.setDiscountAmt(discount); + payment.setWriteOffAmt(writeoff); + payment.setC_Currency_ID(usd.getC_Currency_ID()); + payment.setC_ConversionType_ID(0); + payment.setTenderType(MPayment.TENDERTYPE_Check); + payment.setDocStatus(DocAction.STATUS_Drafted); + payment.setDocAction(DocAction.ACTION_Complete); + payment.saveEx(); + + completeDocument(payment); + postDocument(payment); + + MAllocationHdr[] allocationa = MAllocationHdr.getOfInvoice(Env.getCtx(), invoice.getC_Invoice_ID(), getTrxName()); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, allocationa[0].get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 11130_Checking Unallocated Receipts | -102.00 | 0.00 + // 59201_Payment discount revenue | -2.00 | 0.00 + // 78100_Bad Debts Write-off | -2.00 | 0.00 + // 12110 Accounts Receivable - Trade | 0.00 | -106.00 + // 59201_Payment discount revenue | 0.11 | 0.00 + // 21610 Tax due | 0.00 | 0.11 + // 78100_Bad Debts Write-off | 0.11 | 0.00 + // 21610 Tax due | 0.00 | 0.11 + // -------------------------------------------------------------------- + MAccount acctPS = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_PaymentSelect_Acct(), getTrxName()); + MAccount acctDEP = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Exp_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctART = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getC_Receivable_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Due_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + allocationa[0].get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPS.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDEP.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctART.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00").negate()); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // AP Invoice in payment + // #1 Create AP Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm Immediate) + // #2 Create Payment with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testPaymentPostingWithWriteOffandDiscountAPInv() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 121); // Patio + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 105; //(Immediate) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(false, false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + + BigDecimal payAmt = new BigDecimal("102"); + BigDecimal discount = new BigDecimal("2"); + BigDecimal writeoff = new BigDecimal("2"); + MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName()); + payment.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + payment.setC_DocType_ID(false); + payment.setDateTrx(date); + payment.setDateAcct(date); + payment.setC_BPartner_ID(bpartner.getC_BPartner_ID()); + payment.setC_Invoice_ID(invoice.getC_Invoice_ID()); + payment.setPayAmt(payAmt); + payment.setDiscountAmt(discount); + payment.setWriteOffAmt(writeoff); + payment.setC_Currency_ID(usd.getC_Currency_ID()); + payment.setC_ConversionType_ID(0); + payment.setTenderType(MPayment.TENDERTYPE_Check); + payment.setDocStatus(DocAction.STATUS_Drafted); + payment.setDocAction(DocAction.ACTION_Complete); + payment.saveEx(); + + completeDocument(payment); + postDocument(payment); + + MAllocationHdr[] allocationa = MAllocationHdr.getOfInvoice(Env.getCtx(), invoice.getC_Invoice_ID(), getTrxName()); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, allocationa[0].get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21100_Accounts Payable Trade 106,00 0,00 + // 59200_Payment discount revenue 0,00 2,00 + // 78100_Bad Debts Write-off 0,00 2,00 + // 21300_Payment selection 0,00 102,00 + // 59200_Payment discount revenue 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // 78100_Bad Debts Write-off 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // -------------------------------------------------------------------- + MAccount acctPT = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getV_Liability_Acct(), getTrxName()); + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctPS = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_PaymentSelect_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Credit_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + allocationa[0].get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPT.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctPS.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("102.00")); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // AP Credit Memo in payment + // #1 Create AP Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm Immediate) + // #2 Create Payment with discount 2.00$ and write-off 2.00$ + // #4 check accounts + public void testPaymentPostingWithWriteOffandDiscountAPCrMe() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 121); // Patio + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 105; //(Immediate) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(false, true, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + // Payamt with discount + BigDecimal payAmt = new BigDecimal("102").negate(); + BigDecimal discount = new BigDecimal("2").negate(); + BigDecimal writeoff = new BigDecimal("2").negate(); + MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName()); + payment.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + payment.setC_DocType_ID(false); + payment.setDateTrx(date); + payment.setDateAcct(date); + payment.setC_BPartner_ID(bpartner.getC_BPartner_ID()); + payment.setC_Invoice_ID(invoice.getC_Invoice_ID()); + payment.setPayAmt(payAmt); + payment.setDiscountAmt(discount); + payment.setWriteOffAmt(writeoff); + payment.setC_Currency_ID(usd.getC_Currency_ID()); + payment.setC_ConversionType_ID(0); + payment.setTenderType(MPayment.TENDERTYPE_Check); + payment.setDocStatus(DocAction.STATUS_Drafted); + payment.setDocAction(DocAction.ACTION_Complete); + payment.saveEx(); + + completeDocument(payment); + postDocument(payment); + + MAllocationHdr[] allocationa = MAllocationHdr.getOfInvoice(Env.getCtx(), invoice.getC_Invoice_ID(), getTrxName()); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, allocationa[0].get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21100_Accounts Payable Trade -106,00 0,00 + // 59200_Payment discount revenue 0,00 -2,00 + // 78100_Bad Debts Write-off 0,00 -2,00 + // 21300_Payment selection 0,00 -102,00 + // 59200_Payment discount revenue 0,00 0,11 + // 12610_Tax credit A/R 0,11 0,00 + // 78100_Bad Debts Write-off 0,00 0,11 + // 12610_Tax credit A/R 0,11 0,00 + // -------------------------------------------------------------------- + MAccount acctPT = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getV_Liability_Acct(), getTrxName()); + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctUC = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getB_UnallocatedCash_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Credit_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + allocationa[0].get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPT.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00").negate()); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else if(fa.getAccount_ID() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)<0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00").negate()); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctUC.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("104.00").negate()); + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AR Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm 2%10 Net 30) + // #1 Create AR CreditMemo (TotalLines 96,32,GrandTotal 102) (PaymentTerm Immediate) + // #3 Allocate of Invoice with discount 2.00$ and write-off 2.00$ + // #4 Check accounts + public void testAllocatePostingWithWriteOffandDiscountARInvARCrMe() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 118); // Joe Block + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 106; //(2%10 Net 30) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(true,false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + Integer paytermcm = 105; //(Immediate) + MInvoice creditmemo = createInvoice(true,true, date, date, + bpartner.getC_BPartner_ID(), paytermcm, taxid, new BigDecimal("96.23")); + assertEquals(creditmemo.getTotalLines(), new BigDecimal("96.23")); + assertEquals(creditmemo.getGrandTotal(), new BigDecimal("102.00")); + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(invoice.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(invoice.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2"); + BigDecimal writeoff = new BigDecimal("2"); + MAllocationLine aLine1 = new MAllocationLine(alloc, invoice.getGrandTotal().subtract(discount.add(writeoff)), discount, writeoff, Env.ZERO); + aLine1.setDocInfo(invoice.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(invoice.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + MAllocationLine aLine2 = new MAllocationLine(alloc, creditmemo.getGrandTotal().negate(), Env.ZERO, Env.ZERO, Env.ZERO); + aLine2.setDocInfo(invoice.getC_BPartner_ID(), 0, 0); + aLine2.setPaymentInfo(invoice.getC_Payment_ID(), 0); + aLine2.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine2.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 59201_Payment discount revenue | 2.00 | 0.00 + // 78100_Bad Debts Write-off | 2.00 | 0.00 + // 12110 Accounts Receivable - Trade | 0.00 | 106.00 + // 21610 Tax due | 0.11 | 0.00 + // 59201_Payment discount revenue | 0.00 | 0.11 + // 21610 Tax due | 0.11 | 0.00 + // 78100_Bad Debts Write-off | 0.00 | 0.11 + // 12110_Accounts Receivable - Trade | 0.00 | -102.00 + // -------------------------------------------------------------------- + // ToDo: set Account + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctART = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getC_Receivable_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Due_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + + } else if(fa.getAccount_ID() == acctART.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("-102.00")); + } + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + + } + } + + } finally { + + rollback(); + } + } + + + @Test + //* Test Allocation with write-off and discount + // #1 Create AP Invoice (TotalLines 100,GrandTotal 106) (PaymentTerm 2%10 Net 30) + // #1 Create AP CreditMemo (TotalLines 96,32,GrandTotal 102) (PaymentTerm Immediate) + // #3 Allocate of Invoice with discount 2.00$ and write-off 2.00$ + // #4 Check accounts + public void testAllocatePostingWithWriteOffandDiscountAPInvAPCrMe() { + + MBPartner bpartner = MBPartner.get(Env.getCtx(), 121); // Patio + Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date"); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(currentDate.getTime()); + Timestamp date = new Timestamp(cal.getTimeInMillis()); + + MCurrency usd = MCurrency.get(100); // USD + + try { + String whereClause = "AD_Org_ID=? AND C_Currency_ID=?"; + MBankAccount ba = new Query(Env.getCtx(),MBankAccount.Table_Name, whereClause, getTrxName()) + .setParameters(Env.getAD_Org_ID(Env.getCtx()), usd.getC_Currency_ID()) + .setOrderBy("IsDefault DESC") + .first(); + assertTrue(ba != null, "@NoAccountOrgCurrency@"); + + // Invoice (totallines 100, grandtotal 106) + Integer payterm = 105; //(Immediate) + Integer taxid = 105; // (CT Sales, Rate 6) + MInvoice invoice = createInvoice(false, false, date, date, + bpartner.getC_BPartner_ID(), payterm, taxid, Env.ONEHUNDRED); + assertEquals(invoice.getTotalLines(), new BigDecimal("100.0")); + assertEquals(invoice.getGrandTotal(), new BigDecimal("106.00")); + + Integer paytermcm = 105; //(Immediate) + MInvoice creditmemo = createInvoice(false,true, date, date, + bpartner.getC_BPartner_ID(), paytermcm, taxid, new BigDecimal("96.23")); + assertEquals(creditmemo.getTotalLines(), new BigDecimal("96.23")); + assertEquals(creditmemo.getGrandTotal(), new BigDecimal("102.00")); + + + MAllocationHdr alloc = new MAllocationHdr(Env.getCtx(), true, date, usd.getC_Currency_ID(), Env.getContext(Env.getCtx(), "#AD_User_Name"), getTrxName()); + alloc.setAD_Org_ID(invoice.getAD_Org_ID()); + int doctypeAlloc = MDocType.getDocType("CMA"); + alloc.setC_DocType_ID(doctypeAlloc); + alloc.setDescription(alloc.getDescriptionForManualAllocation(invoice.getC_BPartner_ID(), getTrxName())); + alloc.saveEx(); + + BigDecimal discount = new BigDecimal("2").negate(); + BigDecimal writeoff = new BigDecimal("2").negate(); + BigDecimal amtinv = invoice.getGrandTotal().negate().subtract(discount.add(writeoff)); + MAllocationLine aLine1 = new MAllocationLine(alloc, amtinv, discount, writeoff, Env.ZERO); + aLine1.setDocInfo(invoice.getC_BPartner_ID(), 0, 0); + aLine1.setPaymentInfo(invoice.getC_Payment_ID(), 0); + aLine1.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine1.saveEx(); + MAllocationLine aLine2 = new MAllocationLine(alloc, creditmemo.getGrandTotal(), Env.ZERO, Env.ZERO, Env.ZERO); + aLine2.setDocInfo(invoice.getC_BPartner_ID(), 0, 0); + aLine2.setPaymentInfo(invoice.getC_Payment_ID(), 0); + aLine2.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine2.saveEx(); + + completeDocument(alloc); + postDocument(alloc); + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx())); + + for (MAcctSchema as : ass) { + + if (as.getC_Currency_ID() != usd.getC_Currency_ID()) + continue; + + Doc doc = DocManager.getDocument(as, MAllocationHdr.Table_ID, alloc.get_ID(), getTrxName()); + doc.setC_BankAccount_ID(ba.getC_BankAccount_ID()); + + // Account | Acct Debit | Acct Credit + // -------------------------------------------------------------------- + // 21100_Accounts Payable Trade 106,00 0,00 + // 59200_Payment discount revenue 0,00 2,00 + // 78100_Bad Debts Write-off 0,00 2,00 + // 59200_Payment discount revenue 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // 78100_Bad Debts Write-off 0,11 0,00 + // 12610_Tax credit A/R 0,00 0,11 + // 21100_Accounts Payable Trade -102,00 0,00 + // -------------------------------------------------------------------- + MAccount acctPT = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getV_Liability_Acct(), getTrxName()); + MAccount acctDRE = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getPayDiscount_Rev_Acct(), getTrxName()); + MAccount acctWO = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getWriteOff_Acct(), getTrxName()); + MAccount acctTD = new MAccount(Env.getCtx(), as.getAcctSchemaDefault().getT_Credit_Acct(), getTrxName()); + + whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MAllocationHdr.Table_ID + + " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + alloc.get_ID() + + " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + as.getC_AcctSchema_ID() + + " ORDER BY Created"; + 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() == acctPT.getAccount_ID()) { + if(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("106.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("-102.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctDRE.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctWO.getAccount_ID()) { + if(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP).compareTo(Env.ZERO)>0) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("2.00")); + } else { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + } + } else if(fa.getAccount_ID() == acctTD.getAccount_ID()) { + assertEquals(fa.getAmtAcctDr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.00")); + assertEquals(fa.getAmtAcctCr().setScale(2, RoundingMode.HALF_UP), new BigDecimal("0.11")); + } + } + } + + } finally { + + rollback(); + } + } + + private MInvoice createInvoice(Boolean isAR, Boolean isCreditMemo, Timestamp dateinvoiced, Timestamp dateacct, + Integer bpartnerid, Integer payterm, Integer taxid, BigDecimal totallines) { + + + MInvoice invoice = new MInvoice(Env.getCtx(), 0, getTrxName()); + + if(isAR) { + if(isCreditMemo) { + invoice.setC_DocType_ID(118); //AR Credit Memo + invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_ARCreditMemo); + + } else { + invoice.setC_DocType_ID(116); //AR Invoice + invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_ARInvoice); + } + } else { + if(isCreditMemo) { + invoice.setC_DocType_ID(124); //AP CreditMemo + invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APCreditMemo); + } else { + invoice.setC_DocType_ID(123); //AP Invoice + invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APInvoice); + } + } + + invoice.setC_BPartner_ID(bpartnerid); + invoice.setDateInvoiced(dateinvoiced); + invoice.setDateAcct(dateacct); + invoice.setC_PaymentTerm_ID(payterm); + invoice.setDocStatus(DocAction.STATUS_Drafted); + invoice.setDocAction(DocAction.ACTION_Complete); + invoice.saveEx(); + + MInvoiceLine line1 = new MInvoiceLine(invoice); + + + line1.setLine(10); + line1.setC_Charge_ID(CHARGE_FREIGHT); + line1.setQty(new BigDecimal("1")); + line1.setPrice(totallines); + line1.setC_Tax_ID(taxid); + line1.saveEx(); + + + completeDocument(invoice); + postDocument(invoice); + + return invoice; + } + + }