IDEMPIERE-5878 Wrong GL posting in allocation for payment REVERSE/ACCRUAL, if payment WITH charge (#2074)

This commit is contained in:
Elaine Tan 2023-10-25 16:01:29 +08:00 committed by GitHub
parent 5379315ab3
commit a061eeedb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 2 deletions

View File

@ -32,6 +32,7 @@ import org.compiere.model.MAcctSchemaElement;
import org.compiere.model.MAllocationHdr; import org.compiere.model.MAllocationHdr;
import org.compiere.model.MAllocationLine; import org.compiere.model.MAllocationLine;
import org.compiere.model.MCashLine; import org.compiere.model.MCashLine;
import org.compiere.model.MCharge;
import org.compiere.model.MConversionRate; import org.compiere.model.MConversionRate;
import org.compiere.model.MDocType; import org.compiere.model.MDocType;
import org.compiere.model.MFactAcct; import org.compiere.model.MFactAcct;
@ -687,7 +688,9 @@ public class Doc_AllocationHdr extends Doc
// or Doc.ACCTTYPE_PaymentSelect (AP) or V_Prepayment // or Doc.ACCTTYPE_PaymentSelect (AP) or V_Prepayment
int accountType = Doc.ACCTTYPE_UnallocatedCash; int accountType = Doc.ACCTTYPE_UnallocatedCash;
// //
String sql = "SELECT p.C_BankAccount_ID, d.DocBaseType, p.IsReceipt, p.IsPrepayment " int C_Charge_ID = 0;
String sql = "SELECT p.C_BankAccount_ID, d.DocBaseType, p.IsReceipt, p.IsPrepayment, p.C_Charge_ID "
+ "FROM C_Payment p INNER JOIN C_DocType d ON (p.C_DocType_ID=d.C_DocType_ID) " + "FROM C_Payment p INNER JOIN C_DocType d ON (p.C_DocType_ID=d.C_DocType_ID) "
+ "WHERE C_Payment_ID=?"; + "WHERE C_Payment_ID=?";
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
@ -700,6 +703,7 @@ public class Doc_AllocationHdr extends Doc
if (rs.next ()) if (rs.next ())
{ {
setC_BankAccount_ID(rs.getInt(1)); setC_BankAccount_ID(rs.getInt(1));
C_Charge_ID = rs.getInt(5); // Charge
if (DOCTYPE_APPayment.equals(rs.getString(2))) if (DOCTYPE_APPayment.equals(rs.getString(2)))
accountType = Doc.ACCTTYPE_PaymentSelect; accountType = Doc.ACCTTYPE_PaymentSelect;
// Prepayment // Prepayment
@ -728,6 +732,9 @@ public class Doc_AllocationHdr extends Doc
log.log(Level.SEVERE, "NONE for C_Payment_ID=" + C_Payment_ID); log.log(Level.SEVERE, "NONE for C_Payment_ID=" + C_Payment_ID);
return null; return null;
} }
if (C_Charge_ID != 0)
return MCharge.getAccount(C_Charge_ID, as);
return getAccount (accountType, as); return getAccount (accountType, as);
} // getPaymentAcct } // getPaymentAcct

View File

@ -1881,6 +1881,68 @@ public class Allocation2ndAcctSchemaTest extends AbstractTestCase {
deleteConversionRate(cr); deleteConversionRate(cr);
} }
} }
@Test
@ResourceLock(value = MConversionRate.Table_Name)
/**
* Test the allocation posting (different period + reversal)
* Payment with Charge Total=1000, Period 1
* Payment with Charge Total=1000, Period 2 (Reversed)
* https://idempiere.atlassian.net/browse/IDEMPIERE-5878
*/
public void testAllocatePaymentPosting_5() {
MBPartner bpartner = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.AGRI_TECH.id);
Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date");
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(currentDate.getTime());
cal.add(Calendar.DAY_OF_MONTH, -1);
Timestamp date1 = new Timestamp(cal.getTimeInMillis());
Timestamp date2 = currentDate;
int C_ConversionType_ID = DictionaryIDs.C_ConversionType.COMPANY.id; // Company
MCurrency usd = MCurrency.get(DictionaryIDs.C_Currency.USD.id); // USD
MCurrency euro = MCurrency.get(DictionaryIDs.C_Currency.EUR.id); // EUR
BigDecimal eurToUsd1 = new BigDecimal(4);
MConversionRate cr1 = createConversionRate(euro.getC_Currency_ID(), usd.getC_Currency_ID(), C_ConversionType_ID, date1, eurToUsd1);
BigDecimal eurToUsd2 = new BigDecimal(5);
MConversionRate cr2 = createConversionRate(euro.getC_Currency_ID(), usd.getC_Currency_ID(), C_ConversionType_ID, date2, eurToUsd2);
try {
MBankAccount ba = getBankAccount(usd.getC_Currency_ID());
BigDecimal payAmt = new BigDecimal(1000);
MPayment payment = createPayment(true, bpartner, ba.getC_BankAccount_ID(), date1, payAmt, euro.getC_Currency_ID(), C_ConversionType_ID);
payment.setC_Charge_ID(DictionaryIDs.C_Charge.BANK.id); // Bank Charge
payment.saveEx();
completeDocument(payment);
postDocument(payment);
reverseDocument(payment, false);
MPayment reversalPayment = new MPayment(Env.getCtx(), payment.getReversal_ID(), getTrxName());
postDocument(reversalPayment);
MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx()));
MAllocationHdr[] allocList = MAllocationHdr.getOfPayment(Env.getCtx(), payment.getC_Payment_ID(), getTrxName());
BigDecimal allocAmount = payAmt;
ArrayList<PostingLine> paymentLineList = new ArrayList<PostingLine>();
ArrayList<PostingLine> gainLossLineList = new ArrayList<PostingLine>();
BigDecimal accountedDrAmt = getAccountedAmount(usd, allocAmount, cr1.getMultiplyRate());
BigDecimal accountedCrAmt = getAccountedAmount(usd, allocAmount, cr2.getMultiplyRate());
paymentLineList.add(new PostingLine(usd, accountedDrAmt, Env.ZERO));
paymentLineList.add(new PostingLine(usd, Env.ZERO, accountedCrAmt));
BigDecimal gainLossAmt = new BigDecimal(1000).setScale(usd.getStdPrecision(), RoundingMode.HALF_UP);
gainLossLineList.add(new PostingLine(usd, gainLossAmt, Env.ZERO));
testAllocationPosting(ass, allocList, paymentLineList, null, gainLossLineList, null);
} finally {
rollback();
deleteConversionRate(cr1);
deleteConversionRate(cr2);
}
}
private MConversionRate createConversionRate(int C_Currency_ID, int C_Currency_ID_To, int C_ConversionType_ID, private MConversionRate createConversionRate(int C_Currency_ID, int C_Currency_ID_To, int C_ConversionType_ID,
Timestamp date, BigDecimal rate) { Timestamp date, BigDecimal rate) {
@ -2072,11 +2134,13 @@ public class Allocation2ndAcctSchemaTest extends AbstractTestCase {
int C_BPartner_ID = 0; int C_BPartner_ID = 0;
int C_BankAccount_ID = 0; int C_BankAccount_ID = 0;
int C_Charge_ID = 0;
MAllocationLine[] lines = alloc.getLines(false); MAllocationLine[] lines = alloc.getLines(false);
for (MAllocationLine line : lines) { for (MAllocationLine line : lines) {
if (line.getC_Payment_ID() > 0) { if (line.getC_Payment_ID() > 0) {
C_BPartner_ID = line.getC_Payment().getC_BPartner_ID(); C_BPartner_ID = line.getC_Payment().getC_BPartner_ID();
C_BankAccount_ID = line.getC_Payment().getC_BankAccount_ID(); C_BankAccount_ID = line.getC_Payment().getC_BankAccount_ID();
C_Charge_ID = line.getC_Payment().getC_Charge_ID();
break; break;
} }
} }
@ -2101,6 +2165,10 @@ public class Allocation2ndAcctSchemaTest extends AbstractTestCase {
if (C_BPartner_ID > 0) if (C_BPartner_ID > 0)
doc.setC_BPartner_ID(C_BPartner_ID); doc.setC_BPartner_ID(C_BPartner_ID);
MAccount acctCharge = null;
if (C_Charge_ID != 0)
acctCharge = MCharge.getAccount(C_Charge_ID, as);
MAccount acctUnallocatedCash = doc.getAccount(Doc.ACCTTYPE_UnallocatedCash, as); MAccount acctUnallocatedCash = doc.getAccount(Doc.ACCTTYPE_UnallocatedCash, as);
MAccount acctReceivable = doc.getAccount(Doc.ACCTTYPE_C_Receivable, as); MAccount acctReceivable = doc.getAccount(Doc.ACCTTYPE_C_Receivable, as);
MAccount acctLiability = doc.getAccount(Doc.ACCTTYPE_V_Liability, as); MAccount acctLiability = doc.getAccount(Doc.ACCTTYPE_V_Liability, as);
@ -2119,7 +2187,9 @@ public class Allocation2ndAcctSchemaTest extends AbstractTestCase {
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName()); int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
for (int id : ids) { for (int id : ids) {
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName()); MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
if (acctUnallocatedCash != null && acctUnallocatedCash.getAccount_ID() == fa.getAccount_ID()) if (C_Charge_ID != 0 && acctCharge != null && acctCharge.getAccount_ID() == fa.getAccount_ID())
totalPaymentAmtAcct = totalPaymentAmtAcct.add(fa.getAmtAcctDr()).subtract(fa.getAmtAcctCr());
else if (C_Charge_ID == 0 && acctUnallocatedCash != null && acctUnallocatedCash.getAccount_ID() == fa.getAccount_ID())
totalPaymentAmtAcct = totalPaymentAmtAcct.add(fa.getAmtAcctDr()).subtract(fa.getAmtAcctCr()); totalPaymentAmtAcct = totalPaymentAmtAcct.add(fa.getAmtAcctDr()).subtract(fa.getAmtAcctCr());
else if ((acctReceivable != null && acctReceivable.getAccount_ID() == fa.getAccount_ID()) || else if ((acctReceivable != null && acctReceivable.getAccount_ID() == fa.getAccount_ID()) ||
(acctLiability != null && acctLiability.getAccount_ID() == fa.getAccount_ID())) (acctLiability != null && acctLiability.getAccount_ID() == fa.getAccount_ID()))