Merge release-7.1 into master

This commit is contained in:
Carlos Ruiz 2020-02-13 01:00:46 +01:00
commit 15707d9aac
17 changed files with 1043 additions and 207 deletions

View File

@ -0,0 +1,19 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-3215 Sales Order/Proposal BP shipper, cause inability to complete
-- Feb 12, 2020, 11:14:32 PM CET
UPDATE AD_Field SET DisplayLogic='@OrderType@=''SO'' | @DeliveryViaRule@=''S'' | @DeliveryViaRule@=''''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2020-02-12 23:14:32','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=1108
;
-- Feb 12, 2020, 8:59:02 PM CET
UPDATE AD_Field SET DisplayLogic='@DeliveryViaRule@=''S''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2020-02-12 20:59:02','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=1109
;
-- Feb 12, 2020, 8:59:28 PM CET
UPDATE AD_Field SET DisplayLogic='@DeliveryViaRule@=''S''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2020-02-12 20:59:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=56446
;
SELECT register_migration_script('202002122100_IDEMPIERE-3215.sql') FROM dual
;

View File

@ -0,0 +1,17 @@
-- IDEMPIERE-3215 Sales Order/Proposal BP shipper, cause inability to complete
-- Feb 12, 2020, 8:58:51 PM CET
-- Feb 12, 2020, 11:14:32 PM CET
UPDATE AD_Field SET DisplayLogic='@OrderType@=''SO'' | @DeliveryViaRule@=''S'' | @DeliveryViaRule@=''''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2020-02-12 23:14:32','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=1108
;
-- Feb 12, 2020, 8:59:02 PM CET
UPDATE AD_Field SET DisplayLogic='@DeliveryViaRule@=''S''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2020-02-12 20:59:02','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=1109
;
-- Feb 12, 2020, 8:59:28 PM CET
UPDATE AD_Field SET DisplayLogic='@DeliveryViaRule@=''S''', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2020-02-12 20:59:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=56446
;
SELECT register_migration_script('202002122100_IDEMPIERE-3215.sql') FROM dual
;

View File

@ -31,12 +31,12 @@ import org.compiere.model.MAllocationHdr;
import org.compiere.model.MAllocationLine;
import org.compiere.model.MCashLine;
import org.compiere.model.MConversionRate;
import org.compiere.model.MCurrency;
import org.compiere.model.MFactAcct;
import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MOrder;
import org.compiere.model.MPayment;
import org.compiere.model.MPeriod;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
@ -75,6 +75,9 @@ public class Doc_AllocationHdr extends Doc
private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02);
/** Facts */
private ArrayList<Fact> m_facts = null;
BigDecimal gainLossAmt =Env.ZERO;
private BigDecimal cmGainLossAmt=Env.ZERO;
private ArrayList<FactLine> gainLossFactList;
/**
@ -174,6 +177,12 @@ public class Doc_AllocationHdr extends Doc
Fact fact = new Fact(this, as, Fact.POST_Actual);
Fact factForRGL = new Fact(this, as, Fact.POST_Actual); // dummy fact (not posted) to calculate Realized Gain & Loss
boolean isInterOrg = isInterOrg(as);
BigDecimal paymentSelectAmt = Env.ZERO;
BigDecimal totalAllocationSource = Env.ZERO;
MPayment payment = null;
int lineID = 0;
MAccount bpAcct = null; // Liability/Receivables
gainLossFactList = new ArrayList<FactLine>();
for (int i = 0; i < p_lines.length; i++)
{
@ -199,10 +208,7 @@ public class Doc_AllocationHdr extends Doc
FactLine fl = null;
FactLine flForRGL = null;
MAccount bpAcct = null; // Liability/Receivables
MAccount payAcct = null; // Payment Selection
//
MPayment payment = null;
if (line.getC_Payment_ID() != 0)
payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
MInvoice invoice = null;
@ -254,7 +260,8 @@ public class Doc_AllocationHdr extends Doc
// if not using clearing accounts, then don't post amtsource
// change the allocationsource to be writeoff + discount
allocationSource = line.getDiscountAmt().add(line.getWriteOffAmt());
payAcct = getPaymentAcct(as, line.getC_Payment_ID());
} else {
// Normal behavior -- unchanged if using clearing accounts
@ -262,11 +269,14 @@ public class Doc_AllocationHdr extends Doc
// Payment/Cash DR
if (line.getC_Payment_ID() != 0)
{
payAcct = getPaymentAcct(as, line.getC_Payment_ID());
fl = fact.createLine (line, payAcct,
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
getC_Currency_ID(), line.getAmtSource(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
if (payment.getReversal_ID() > 0 )
paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance().negate());
else
paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance());
}
else if (line.getC_CashLine_ID() != 0)
{
@ -393,11 +403,11 @@ public class Doc_AllocationHdr extends Doc
// Payment/Cash CR
if (isUsingClearing && line.getC_Payment_ID() != 0) // Avoid usage of clearing accounts
{
payAcct = getPaymentAcct(as, line.getC_Payment_ID());
fl = fact.createLine (line, payAcct,
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
getC_Currency_ID(), null, line.getAmtSource().negate());
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance().negate());
}
else if (isUsingClearing && line.getC_CashLine_ID() != 0) // Avoid usage of clearing accounts
{
@ -435,13 +445,30 @@ public class Doc_AllocationHdr extends Doc
&& (getC_Currency_ID() != as.getC_Currency_ID() // payment allocation in foreign currency
|| getC_Currency_ID() != line.getInvoiceC_Currency_ID())) // allocation <> invoice currency
{
p_Error = createRealizedGainLoss (line, as, fact, bpAcct, invoice, payAcct, payment,
allocationSourceForRGL, allocationAccounted);
p_Error = createRealizedGainLoss (line, as, fact, bpAcct, invoice,
allocationSource, allocationAccounted);
if (p_Error != null)
return null;
}
totalAllocationSource = totalAllocationSource.add(line.getAmtSource());
lineID = line.get_ID();
} // for all lines
// rounding correction
if (payment != null && getC_Currency_ID() != as.getC_Currency_ID() ) // payment allocation in foreign currency
{
p_Error = createPaymentGainLoss (as, fact, getPaymentAcct(as, payment.get_ID()), payment,
totalAllocationSource, paymentSelectAmt, lineID);
if (p_Error != null)
return null;
}
} // for all lines
if (getC_Currency_ID() != as.getC_Currency_ID())
{
p_Error = createInvoiceRounding (as, fact, bpAcct);
if (p_Error != null)
return null;
}
// FR [ 1840016 ] Avoid usage of clearing accounts - subject to C_AcctSchema.IsPostIfClearingEqual
if ( (!as.isPostIfClearingEqual()) && p_lines.length > 0 && (!isInterOrg)) {
@ -652,7 +679,7 @@ public class Doc_AllocationHdr extends Doc
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally
{
@ -697,21 +724,17 @@ public class Doc_AllocationHdr extends Doc
* Accounted Amount of the Allocation
* @param as accounting schema
* @param fact fact
* @param invAcct invoice account
* @param acct account
* @param invoice invoice
* @param payAcct payment account
* @param payment payment
* @param allocationSource source amt
* @param allocationAccounted acct amt
* @return Error Message or null if OK
*/
private String createRealizedGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount invAcct,
MInvoice invoice, MAccount payAcct, MPayment payment, BigDecimal allocationSource, BigDecimal allocationAccounted)
private String createRealizedGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount acct,
MInvoice invoice, BigDecimal allocationSource, BigDecimal allocationAccounted)
{
BigDecimal invoiceSource = null;
BigDecimal invoiceAccounted = null;
BigDecimal paymentSource = null;
BigDecimal paymentAccounted = null;
//
StringBuilder sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
@ -732,129 +755,66 @@ public class Doc_AllocationHdr extends Doc
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
// Requires that Invoice is Posted
if (invoiceSource == null || invoiceAccounted == null)
return "Gain/Loss - Invoice not posted yet";
//
String invoiceCur = MCurrency.get(getCtx(), invoice.getC_Currency_ID()).getISO_Code();
String allocCur = MCurrency.get(getCtx(), getC_Currency_ID()).getISO_Code();
StringBuilder descriptionInv = new StringBuilder("Invoice=(").append(invoiceCur).append(")").append(invoiceSource).append("/").append(invoiceAccounted)
.append(" - Allocation=(").append(allocCur).append(")").append(allocationSource).append("/").append(allocationAccounted);
if (log.isLoggable(Level.FINE)) log.fine(descriptionInv.toString());
StringBuilder description = new StringBuilder("Invoice=(").append(invoice.getC_Currency_ID()).append(")").append(invoiceSource).append("/").append(invoiceAccounted)
.append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(allocationAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
// Allocation not Invoice Currency
BigDecimal allocationInvoiceSource = allocationSource;
if (getC_Currency_ID() != invoice.getC_Currency_ID())
{
allocationInvoiceSource = MConversionRate.convert(getCtx(),
BigDecimal allocationSourceNew = MConversionRate.convert(getCtx(),
allocationSource, getC_Currency_ID(),
invoice.getC_Currency_ID(), getDateAcct(),
invoice.getC_ConversionType_ID(), invoice.getAD_Client_ID(), invoice.getAD_Org_ID());
if (allocationInvoiceSource == null)
if (allocationSourceNew == null)
return "Gain/Loss - No Conversion from Allocation->Invoice";
StringBuilder d2 = new StringBuilder("Allocation=(").append(allocCur).append(")").append(allocationSource)
.append("->(").append(invoiceCur).append(")").append(allocationInvoiceSource);
StringBuilder d2 = new StringBuilder("Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource)
.append("->(").append(invoice.getC_Currency_ID()).append(")").append(allocationSourceNew);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionInv.append(" - ").append(d2);
description.append(" - ").append(d2);
allocationSource = allocationSourceNew;
}
BigDecimal invoiceDifference = null; // gain is negative
// Full Invoice in currency
if (allocationInvoiceSource.compareTo(invoiceSource) == 0)
BigDecimal acctDifference = null; // gain is negative
//reversal entry
if (allocationSource.signum() > 0 )
{
invoiceDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(invoiceDifference);
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs());
}
// Full Payment in currency
if (allocationSource.compareTo(invoiceSource) == 0)
{
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionInv.append(" - ").append(d2);
description.append(" - ").append(d2);
}
else // partial or MC
{
// percent of total payment
double multiplier = allocationInvoiceSource.doubleValue() / invoiceSource.doubleValue();
double multiplier = allocationSource.doubleValue() / invoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
invoiceAccounted = invoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
// Difference based on percentage of Orig Invoice
invoiceDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
// ignore Tolerance
if (invoiceDifference.abs().compareTo(TOLERANCE) < 0)
invoiceDifference = Env.ZERO;
if (acctDifference.abs().compareTo(TOLERANCE) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (invoiceDifference.scale() > precision)
invoiceDifference = invoiceDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(invoiceDifference).append(" - Multiplier=").append(multiplier);
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionInv.append(" - ").append(d2);
description.append(" - ").append(d2);
}
// For Payment
BigDecimal paymentDifference = Env.ZERO;
StringBuilder descriptionPay = null;
if (payment != null && payment.getC_Payment_ID() > 0) {
List<Object> valuesPay = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MPayment.Table_ID, payment.getC_Payment_ID(), as.getC_AcctSchema_ID());
if (valuesPay != null) {
if (invoice.isSOTrx()) {
paymentSource = (BigDecimal) valuesPay.get(2); // AmtSourceCr
paymentAccounted = (BigDecimal) valuesPay.get(3); // AmtAcctCr
} else {
paymentSource = (BigDecimal) valuesPay.get(0); // AmtSourceDr
paymentAccounted = (BigDecimal) valuesPay.get(1); // AmtAcctDr
}
}
// Requires that Payment is Posted
if (paymentSource == null || paymentAccounted == null)
return "Gain/Loss - Payment not posted yet";
//
String paymentCur = MCurrency.get(getCtx(), payment.getC_Currency_ID()).getISO_Code();
descriptionPay = new StringBuilder("Payment=(").append(paymentCur).append(")").append(paymentSource).append("/").append(paymentAccounted)
.append(" - Allocation=(").append(allocCur).append(")").append(allocationSource).append("/").append(allocationAccounted);
if (log.isLoggable(Level.FINE)) log.fine(descriptionPay.toString());
// Allocation not Payment Currency
BigDecimal allocationPaymentSource = allocationSource;
if (getC_Currency_ID() != payment.getC_Currency_ID())
{
allocationPaymentSource = MConversionRate.convert(getCtx(),
allocationSource, getC_Currency_ID(),
payment.getC_Currency_ID(), getDateAcct(),
payment.getC_ConversionType_ID(), payment.getAD_Client_ID(), payment.getAD_Org_ID());
if (allocationPaymentSource == null)
return "Gain/Loss - No Conversion from Allocation->Payment";
StringBuilder d2 = new StringBuilder("Allocation=(").append(allocCur).append(")").append(allocationSource)
.append("->(").append(paymentCur).append(")").append(allocationPaymentSource);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionPay.append(" - ").append(d2);
}
// Full Payment in currency
if (allocationPaymentSource.compareTo(paymentSource) == 0)
{
paymentDifference = paymentAccounted.subtract(allocationAccounted); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(paymentDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionPay.append(" - ").append(d2);
}
else // partial or MC
{
// percent of total payment
double multiplier = allocationPaymentSource.doubleValue() / paymentSource.doubleValue();
// Reduce Orig Payment Accounted
paymentAccounted = paymentAccounted.multiply(BigDecimal.valueOf(multiplier));
// Difference based on percentage of Orig Payment
paymentDifference = paymentAccounted.subtract(allocationAccounted); // gain is negative
// ignore Tolerance
if (paymentDifference.abs().compareTo(TOLERANCE) < 0)
paymentDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (paymentDifference.scale() > precision)
paymentDifference = paymentDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(paymentDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionPay.append(" - ").append(d2);
}
}
if (invoiceDifference.signum() == 0 && paymentDifference.signum() == 0)
if (acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
@ -862,51 +822,28 @@ public class Doc_AllocationHdr extends Doc
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0)
cmGainLossAmt = cmGainLossAmt.add(acctDifference);
else
gainLossAmt = gainLossAmt.add(acctDifference);
//
BigDecimal acctDifference = invoiceDifference.subtract(paymentDifference);
if (invoice.isSOTrx())
{
if (acctDifference.signum() != 0) {
FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference);
StringBuilder description = new StringBuilder(descriptionInv);
if (paymentDifference.signum() != 0 && descriptionPay != null) {
description.append(" / ").append(descriptionPay);
}
fl.setDescription(description.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
if (invoiceDifference.signum() != 0) {
FactLine fl = fact.createLine (line, invAcct, as.getC_Currency_ID(), invoiceDifference.negate());
fl.setDescription(descriptionInv.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
if (paymentDifference.signum() != 0) {
FactLine fl = fact.createLine (line, payAcct, as.getC_Currency_ID(), paymentDifference);
fl.setDescription(descriptionPay.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference.negate());
gainLossFactList.add(fl);
}
else
{
if (invoiceDifference.signum() != 0) {
FactLine fl = fact.createLine (line, invAcct, as.getC_Currency_ID(), invoiceDifference);
fl.setDescription(descriptionInv.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
if (paymentDifference.signum() != 0) {
FactLine fl = fact.createLine (line, payAcct, as.getC_Currency_ID(), paymentDifference.negate());
fl.setDescription(descriptionPay.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
if (acctDifference.signum() != 0) {
FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference.negate());
StringBuilder description = new StringBuilder(descriptionInv);
if (paymentDifference.signum() != 0 && descriptionPay != null) {
description.append(" / ").append(descriptionPay);
}
FactLine fl = fact.createLine (line, acct,
as.getC_Currency_ID(), acctDifference);
gainLossFactList.add(fl);
fl = fact.createLine (line, loss, gain,
as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
}
return null;
} // createRealizedGainLoss
@ -947,7 +884,7 @@ public class Doc_AllocationHdr extends Doc
// Get Source Amounts with account
String sql = "SELECT * "
+ "FROM Fact_Acct "
+ "WHERE AD_Table_ID=318 AND Record_ID=?" // Invoice
+ "WHERE AD_Table_ID=? AND Record_ID=?" // Invoice
+ " AND C_AcctSchema_ID=?"
+ " AND Line_ID IS NULL"; // header lines like tax or total
PreparedStatement pstmt = null;
@ -955,15 +892,16 @@ public class Doc_AllocationHdr extends Doc
try
{
pstmt = DB.prepareStatement(sql, getTrxName());
pstmt.setInt(1, line.getC_Invoice_ID());
pstmt.setInt(2, as.getC_AcctSchema_ID());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, line.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
rs = pstmt.executeQuery();
while (rs.next())
tax.addInvoiceFact (new MFactAcct(getCtx(), rs, fact.get_TrxName()));
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally {
DB.close(rs, pstmt);
@ -982,6 +920,430 @@ public class Doc_AllocationHdr extends Doc
} // createTaxCorrection
/**************************************************************************
* Create Rounding Correction.
* Compares the Accounted Amount of the Payment to the
* Accounted Amount of the Allocation
* @param as accounting schema
* @param fact fact
* @param acct account
* @param payment payment
* @param paymentSource source amt
* @param paymentAccounted acct amt
* @return Error Message or null if OK
*/
private String createPaymentGainLoss (MAcctSchema as, Fact fact, MAccount acct,
MPayment payment, BigDecimal allocationSource, BigDecimal totalAllocationAccounted, int lineID)
{
BigDecimal paymentSource = null;
BigDecimal paymentAccounted = null;
//
StringBuilder sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID = ? ")
.append(" AND PostingType='A'");
// For Payment
List<Object> valuesPay = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MPayment.Table_ID, payment.getC_Payment_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesPay != null) {
if (payment.isReceipt()) {
paymentSource = (BigDecimal) valuesPay.get(2); // AmtSourceCr
paymentAccounted = (BigDecimal) valuesPay.get(3); // AmtAcctCr
} else {
paymentSource = (BigDecimal) valuesPay.get(0); // AmtSourceDr
paymentAccounted = (BigDecimal) valuesPay.get(1); // AmtAcctDr
}
}
// Requires that Allocation is Posted
if (paymentSource == null || paymentAccounted == null)
return null; //"Gain/Loss - Payment not posted yet";
//
StringBuilder description = new StringBuilder("Payment=(").append(payment.getC_Currency_ID()).append(")").append(paymentSource).append("/").append(paymentAccounted)
.append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(totalAllocationAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
boolean isSameSourceDiffPeriod = false;
BigDecimal acctDifference = null; // gain is negative
// Full Payment in currency
if (allocationSource.abs().compareTo(paymentSource.abs()) == 0)
{
acctDifference = totalAllocationAccounted.subtract(paymentAccounted.abs()); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
// Different period
if (MPeriod.getC_Period_ID(getCtx(), payment.getDateAcct(), payment.getAD_Org_ID()) !=
MPeriod.getC_Period_ID(getCtx(), getDateAcct(), getAD_Org_ID()))
{
BigDecimal allocationAccounted0 = MConversionRate.convert(getCtx(),
allocationSource, getC_Currency_ID(),
as.getC_Currency_ID(), payment.getDateAcct(),
payment.getC_ConversionType_ID(), payment.getAD_Client_ID(), payment.getAD_Org_ID());
BigDecimal paymentAccounted0 = MConversionRate.convert(getCtx(),
paymentSource, getC_Currency_ID(),
as.getC_Currency_ID(), getDateAcct(),
getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
isSameSourceDiffPeriod = allocationAccounted0.abs().compareTo(paymentAccounted.abs()) == 0 &&
paymentAccounted0.abs().compareTo(totalAllocationAccounted.abs()) == 0;
}
}
if (acctDifference == null || acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (payment.isReceipt())
{
FactLine fl = fact.createLine (null, acct,as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
fl.setLine_ID(lineID);
if (!fact.isAcctBalanced())
{
if (!isSameSourceDiffPeriod && as.isCurrencyBalancing() && as.getC_Currency_ID() != payment.getC_Currency_ID() )
{
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
} else
{
fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference);
}
}
}
else
{
FactLine fl = fact.createLine (null, acct,as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString());
fl.setLine_ID(lineID);
if (!fact.isAcctBalanced())
{
if (!isSameSourceDiffPeriod && as.isCurrencyBalancing() && as.getC_Currency_ID() != payment.getC_Currency_ID() )
{
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
} else {
fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference.negate());
}
}
}
return null;
}
/**************************************************************************
* Create Rounding Correction.
* Compares the Accounted Amount of the AR/AP Invoice to the
* Accounted Amount of the AR/AP Allocation
* @param as accounting schema
* @param fact fact
* @param bpAcct account
* @param payment payment
* @return Error Message or null if OK
*/
private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct) {
PreparedStatement pstmt = null;
ResultSet rs = null;
// Invoice AR/AP
BigDecimal totalInvoiceSource = BigDecimal.ZERO;
BigDecimal totalInvoiceAccounted = BigDecimal.ZERO;
boolean isCMReversal =false ;
MInvoice invoice = null;
MPayment payment = null;
ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
for (int i = 0; i < p_lines.length; i++)
{
DocLine_Allocation line = (DocLine_Allocation)p_lines[i];
if (line.getC_Invoice_ID() != 0)
invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName());
if (line.getC_Payment_ID() != 0)
payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
if (invoice != null )
{
boolean isDebit = false;
// to cater for invoice reverse-accrual.
if (invoice.isSOTrx() && !invoice.isCreditMemo())
isDebit = true;
else if (!invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 )
isDebit = true;
else if (invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() == 0)
isDebit = true;
//
StringBuilder sql = new StringBuilder("SELECT ")
.append((isDebit )
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // Invoice
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, invoice.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{
BigDecimal invoiceSource = rs.getBigDecimal(1);
BigDecimal invoiceAccounted = rs.getBigDecimal(2);
if ( !invList.contains(invoice))
{
totalInvoiceSource =totalInvoiceSource.add(invoiceSource);
totalInvoiceAccounted =totalInvoiceAccounted.add(invoiceAccounted);
}
invList.add(invoice);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
}
BigDecimal allocInvoiceSource = BigDecimal.ZERO;
BigDecimal allocInvoiceAccounted = BigDecimal.ZERO;
MAllocationLine allocationLine = null;
FactLine[] factlines = fact.getLines();
boolean isExcludeCMGainLoss = false;
for (FactLine factLine : factlines) {
if (bpAcct != null) {
if (factLine.getAccount_ID() == bpAcct.getAccount_ID() )
{
if (factLine.getLine_ID() != 0 )
allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName());
if (allocationLine != null)
invoice = allocationLine.getInvoice();
if (invoice.isSOTrx())
{
if (factLine.getC_Currency_ID() != as.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr());
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) {
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true;
}
if (invoice!=null)
{
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) {
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO;
}
if (gainLossFactList.contains(factLine)) {
isExcludeCMGainLoss = true;
}
}
if (payment != null && payment.getReversal_ID() > 0 && !gainLossFactList.contains(factLine))
{
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
}
} else
{
if (as.getC_Currency_ID() != factLine.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) {
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
// this is to cater for reverse-accrual.
if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true;
}
if (invoice!=null )
{
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) {
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO;
}
if (gainLossFactList.contains(factLine)) {
isExcludeCMGainLoss = true;
}
}
}
}
}
}
BigDecimal acctDifference = null; // gain is negative
//
StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
boolean isBPartnerAdjust = true;
if (allocInvoiceSource.abs().compareTo(totalInvoiceSource.abs()) == 0)
{
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
if (payment != null && payment.getReversal_ID() > 0 )
allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt);
else
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
if (isCMReversal)
acctDifference = totalInvoiceAccounted.subtract(allocInvoiceAccounted.abs());
else
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted.abs()); // gain is positive for receipt
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
} else{
MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName());
for (MAllocationHdr alloc : allocations)
{
StringBuilder sql = new StringBuilder("SELECT ")
.append(invoice.isSOTrx()
? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MAllocationHdr.Table_ID);
pstmt.setInt(2, alloc.get_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{
BigDecimal allocateSource = rs.getBigDecimal(1);
BigDecimal allocateAccounted = rs.getBigDecimal(2);
BigDecimal allocateCredit = rs.getBigDecimal(3);
allocInvoiceSource =allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO);
allocInvoiceAccounted =allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO);
allocInvoiceAccounted= allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
double multiplier = allocInvoiceSource.doubleValue() / totalInvoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
BigDecimal reduceOrigAccounted = totalInvoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
if (reduceOrigAccounted.compareTo(totalInvoiceAccounted) < 0 )
totalInvoiceAccounted = reduceOrigAccounted;
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
// Difference based on percentage of Orig Invoice
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted);
// ignore Tolerance
if (acctDifference.abs().compareTo(BigDecimal.valueOf(0.01)) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
if (acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (acctDifference.abs().compareTo(TOLERANCE) <= 0)
{
if (invoice.isSOTrx())
{
FactLine fl = null;
if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString());
if (!fact.isAcctBalanced())
{
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() )
{
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
} else
{
fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference.negate());
}
}
}else
{
FactLine fl = null;
if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
if (!fact.isAcctBalanced())
{
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() )
{
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
} else {
fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
}
}
}
}
return null;
} // createInvoiceRounding
} // Doc_Allocation
/**

View File

@ -24,6 +24,7 @@ import java.sql.Savepoint;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
@ -43,6 +44,7 @@ import org.compiere.model.MMatchInv;
import org.compiere.model.MOrderLandedCostAllocation;
import org.compiere.model.ProductCost;
import org.compiere.model.X_M_Cost;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Trx;
@ -286,6 +288,21 @@ public class Doc_MatchInv extends Doc
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.getAmtSourceDr(), dr.getAmtAcctDr());
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.getAmtSourceCr(), cr.getAmtAcctCr());
if (p_Error != null)
return null;
}
if (m_matchInv.getReversal_ID() == 0)
{
cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
@ -831,4 +848,361 @@ public class Doc_MatchInv extends Doc
factLine.setM_Product_ID(m_invoiceLine.getM_Product_ID());
factLine.setQty(getQty());
}
private String createInvoiceGainLoss(MAcctSchema as, Fact fact, MAccount acct,
MInvoice invoice, BigDecimal matchInvSource, BigDecimal matchInvAccounted)
{
BigDecimal invoiceSource = null;
BigDecimal invoiceAccounted = null;
//
StringBuilder sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
// For Invoice
List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null) {
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
if (invoiceSource.signum() == 0 && invoiceAccounted.signum() == 0) {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
// Requires that Invoice is Posted
if (invoiceSource == null || invoiceAccounted == null)
return null;
//
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID())
{
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE C_InvoiceLine_ID IN (SELECT C_InvoiceLine_ID FROM C_InvoiceLine WHERE C_Invoice_ID=?) "
+ "AND COALESCE(Reversal_ID,0)=0";
List<List<Object>> list = DB.getSQLArrayObjectsEx(getTrxName(), matchInvLineSql, invoice.get_ID());
StringBuffer s = new StringBuffer();
if (list == null)
return null;
for (int index=0; index < list.size(); index++)
{
List<Object> l = list.get(index);
s.append(l.get(0));
if (index != list.size()-1)
s.append(",");
}
sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(s).append(")")
.append(" AND Record_ID <> ?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
}
else
{
sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(m_matchInv.getReversal_ID()).append(")")
.append(" AND Record_ID <> ?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
}
BigDecimal acctDifference = null; // gain is negative
// For Match Invoice
valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MMatchInv.Table_ID, get_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null)
{
BigDecimal totalAmtSourceDr = (BigDecimal) valuesInv.get(0);
if (totalAmtSourceDr == null)
totalAmtSourceDr = Env.ZERO;
BigDecimal totalAmtAcctDr = (BigDecimal) valuesInv.get(1);
if (totalAmtAcctDr == null)
totalAmtAcctDr = Env.ZERO;
BigDecimal totalAmtSourceCr = (BigDecimal) valuesInv.get(2);
if (totalAmtSourceCr == null)
totalAmtSourceCr = Env.ZERO;
BigDecimal totalAmtAcctCr = (BigDecimal) valuesInv.get(3);
if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
}
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else
{
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctCr.negate();
}
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtSourceDr.negate();
}
}
}
StringBuilder description = new StringBuilder("Invoice=(").append(invoice.getC_Currency_ID()).append(")").append(invoiceSource).append("/").append(invoiceAccounted)
.append(" - MatchInv=(").append(getC_Currency_ID()).append(")").append(matchInvSource).append("/").append(matchInvAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
//
// Full Payment in currency
if (acctDifference == null && matchInvSource.compareTo(invoiceSource) == 0)
{
acctDifference = matchInvAccounted.subtract(invoiceAccounted.abs()); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
if (acctDifference == null || acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (invoice.isSOTrx())
{
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
updateFactLine(fl);
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID()) {
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference);
} else {
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
}
fl.setDescription(description.toString());
updateFactLine(fl);
}
else
{
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString());
updateFactLine(fl);
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID()) {
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference.negate());
} else {
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference.negate());
}
fl.setDescription(description.toString());
updateFactLine(fl);
}
return null;
} // createInvoiceGainLoss
private String createReceiptGainLoss(MAcctSchema as, Fact fact, MAccount acct,
MInOut receipt, BigDecimal matchInvSource, BigDecimal matchInvAccounted)
{
BigDecimal receiptSource = null;
BigDecimal receiptAccounted = null;
//
StringBuilder sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
// For Receipt
List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MInOut.Table_ID, receipt.getM_InOut_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null) {
receiptSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
receiptAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
if (receiptSource.signum() == 0 && receiptAccounted.signum() == 0) {
receiptSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
receiptAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
// Requires that Receipt is Posted
if (receiptSource == null || receiptAccounted == null)
return null;
//
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID())
{
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE M_InOutLine_ID IN (SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID=?) "
+ "AND COALESCE(Reversal_ID,0)=0";
List<List<Object>> list = DB.getSQLArrayObjectsEx(getTrxName(), matchInvLineSql, receipt.get_ID());
StringBuffer s = new StringBuffer();
if (list == null)
return null;
for (int index=0; index < list.size(); index++)
{
List<Object> l = list.get(index);
s.append(l.get(0));
if (index != list.size()-1)
s.append(",");
}
sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(s).append(")")
.append(" AND Record_ID <> ?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
}
else
{
sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(m_matchInv.getReversal_ID()).append(")")
.append(" AND Record_ID <> ?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'");
}
BigDecimal acctDifference = null; // gain is negative
// For Match Invoice
valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MMatchInv.Table_ID, get_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null)
{
BigDecimal totalAmtSourceDr = (BigDecimal) valuesInv.get(0);
if (totalAmtSourceDr == null)
totalAmtSourceDr = Env.ZERO;
BigDecimal totalAmtAcctDr = (BigDecimal) valuesInv.get(1);
if (totalAmtAcctDr == null)
totalAmtAcctDr = Env.ZERO;
BigDecimal totalAmtSourceCr = (BigDecimal) valuesInv.get(2);
if (totalAmtSourceCr == null)
totalAmtSourceCr = Env.ZERO;
BigDecimal totalAmtAcctCr = (BigDecimal) valuesInv.get(3);
if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
}
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else
{
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID())
{
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
}
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
}
}
else
{
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctCr.negate();
}
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtAcctDr.negate();
}
}
}
}
StringBuilder description = new StringBuilder("InOut=(").append(m_invoiceLine.getParent().getC_Currency_ID()).append(")").append(receiptSource).append("/").append(receiptAccounted)
.append(" - MatchInv=(").append(getC_Currency_ID()).append(")").append(matchInvSource).append("/").append(matchInvAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
// Full Payment in currency
if (acctDifference == null && matchInvSource.compareTo(receiptSource) == 0)
{
acctDifference = matchInvAccounted.subtract(receiptAccounted.abs()); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
if (acctDifference == null || acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (!receipt.isSOTrx())
{
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
updateFactLine(fl);
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != m_invoiceLine.getParent().getC_Currency_ID()) {
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference);
} else {
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
}
fl.setDescription(description.toString());
updateFactLine(fl);
}
else
{
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString());
updateFactLine(fl);
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != m_invoiceLine.getParent().getC_Currency_ID()) {
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference.negate());
} else {
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference.negate());
}
fl.setDescription(description.toString());
updateFactLine(fl);
}
return null;
} // createReceiptGainLoss
} // Doc_MatchInv

View File

@ -1124,6 +1124,8 @@ public final class FactLine extends X_Fact_Acct
if (MMovement.Table_ID == AD_Table_ID)
sql.append(" AND M_Locator_ID=?");
// end MZ
sql.append(" ORDER BY Fact_Acct_ID ");
PreparedStatement pstmt = null;
ResultSet rs = null;
try

View File

@ -104,7 +104,7 @@ public class GridTable extends AbstractTableModel
/**
*
*/
private static final long serialVersionUID = -2741647620577906242L;
private static final long serialVersionUID = 817894725729408648L;
public static final String DATA_REFRESH_MESSAGE = "Refreshed";
public static final String DATA_UPDATE_COPIED_MESSAGE = "UpdateCopied";
@ -3499,7 +3499,7 @@ public class GridTable extends AbstractTableModel
/**
*
*/
private static final long serialVersionUID = -8735217685095696892L;
private static final long serialVersionUID = -6866671239509705988L;
/**
* Construct Loader

View File

@ -726,10 +726,20 @@ public class MPayment extends X_C_Payment
if (newRecord
|| is_ValueChanged("C_Charge_ID") || is_ValueChanged("C_Invoice_ID")
|| is_ValueChanged("C_Order_ID") || is_ValueChanged("C_Project_ID"))
{
if (getReversal_ID() > 0)
{
setIsPrepayment(getReversal().isPrepayment());
}
else
{
setIsPrepayment (getC_Charge_ID() == 0
&& getC_BPartner_ID() != 0
&& (getC_Order_ID() != 0
|| (getC_Project_ID() != 0 && getC_Invoice_ID() == 0)));
}
}
if (isPrepayment())
{
if (newRecord

View File

@ -241,6 +241,19 @@ public class CLogger extends Logger
return true;
} // saveWarning
/**
* Get Warning message from stack
* @param defaultMsg default message (used when there are no warnings on stack)
* @return error message, or defaultMsg if there is not error message saved
* @see #retrieveError()
*/
public static String retrieveWarningString(String defaultMsg) {
ValueNamePair vp = retrieveWarning();
if (vp == null)
return defaultMsg;
return vp.getName();
}
/**
* Get Warning from Stack
* @return AD_Message as Value and Message as String

View File

@ -1653,7 +1653,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
if (listPanel.isVisible()) {
listPanel.refresh(gridTab);
listPanel.scrollToCurrentRow();
Clients.resize(listPanel.getListbox());
listPanel.getListbox().invalidate();
} else {
listPanel.deactivate();
}
@ -1880,7 +1880,11 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
continue;
}
if (found) {
if (editor.isVisible() && editor.isReadWrite()) {
if (editor.isVisible() && editor.isReadWrite()
// note, no auto focus on next button - if interested in
// focusing next button must implement to check if the button
// is just showin in toolbar, just focus on window fields must be auto focused
&& ! (editor instanceof WButtonEditor)) {
focusToEditor(editor, false);
break;
}

View File

@ -83,10 +83,12 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
/**
*
*/
private static final long serialVersionUID = -9183846974546235806L;
private static final long serialVersionUID = 2945672260455902597L;
public static final String BTNPREFIX = "Btn";
public static final String MNITMPREFIX = "Mnitm";
private static final CLogger log = CLogger.getCLogger(ADWindowToolbar.class);
private ToolBarButton btnIgnore;
@ -274,7 +276,6 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
tooltipKey = null;
}
ToolBarButton btn = createButton(button.getComponentName(), null, tooltipKey);
this.appendChild(btn);
btn.removeEventListener(Events.ON_CLICK, this);
btn.setId(button.getName());
btn.setDisabled(false);
@ -291,9 +292,7 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
if (ClientInfo.isMobile() && button.isShowMore())
mobileShowMoreButtons.add(btn);
else if (button.isShowMore())
createMenuitem(btn);
else {
else if (!button.isShowMore()) {
this.appendChild(btn);
action.decorate(btn);
}
@ -371,12 +370,15 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
Menuitem item = new Menuitem(button.getTooltiptext());
if (button.getImage() != null)
item.setImage(button.getImage());
else if (button.getImageContent() != null)
item.setImageContent(button.getImageContent());
else if (ThemeManager.isUseFontIconForImage()) {
item.setIconSclass(button.getIconSclass());
LayoutUtils.addSclass("font-icon-toolbar-button", item);
}
item.setId(MNITMPREFIX+button.getName());
item.setValue(button.getName());
item.addEventListener(Events.ON_CLICK, evt -> doOnClick(new Event(Events.ON_CLICK, button)));
item.addEventListener(Events.ON_CLICK, evt -> Events.sendEvent(new Event(Events.ON_CLICK, button)));
menupopup.appendChild(item);
menuItems.put(button, item);
return item;
@ -905,8 +907,10 @@ public class ADWindowToolbar extends FToolbar implements EventListener<Event>
public void dynamicDisplay() {
List<Toolbarbutton> customButtons = new ArrayList<Toolbarbutton>();
for(ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons) {
toolbarCustomBtn.dynamicDisplay();
toolbarCustomBtn.dynamicDisplay(menuItems.get(toolbarCustomBtn.getToolbarbutton()) != null);
customButtons.add(toolbarCustomBtn.getToolbarbutton());
if (menuItems.get(toolbarCustomBtn.getToolbarbutton()) != null)
menuItems.get(toolbarCustomBtn.getToolbarbutton()).setVisible(toolbarCustomBtn.getToolbarbutton().isVisible());
}
ADWindow adwindow = ADWindow.findADWindow(this);

View File

@ -2017,8 +2017,11 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
clearTitleRelatedContext();
// The record was not changed locally
if (adTabbox.getDirtyADTabpanel() == null) {
doOnFind();
} else {
onSave(false, false, new Callback<Boolean>() {
@Override
public void onCallback(Boolean result) {
if (result) {
@ -2027,6 +2030,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
}
});
}
}
private void doOnFind() {
// Gets Fields from AD_Field_v
@ -2156,12 +2160,16 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
if (dirtyTabpanel != null) {
focusToTabpanel(dirtyTabpanel);
//ensure row indicator is not lost
if (dirtyTabpanel.getGridView() != null &&
dirtyTabpanel.getGridView().getListbox() != null &&
dirtyTabpanel.getGridView().getListbox().getRowRenderer() != null) {
RowRenderer<Object[]> renderer = dirtyTabpanel.getGridView().getListbox().getRowRenderer();
GridTabRowRenderer gtr = (GridTabRowRenderer)renderer;
org.zkoss.zul.Row row = gtr.getCurrentRow();
if (row != null)
gtr.setCurrentRow(row);
}
}
else
focusToActivePanel();
@ -2379,6 +2387,14 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
//other error will be catch in the dataStatusChanged event
}
private void showLastWarning() {
String msg = CLogger.retrieveWarningString(null);
if (msg != null)
{
statusBar.setStatusLine(Msg.getMsg(Env.getCtx(), msg), true);
}
}
/**
* @see ToolbarListener#onSaveCreate()
*/
@ -2458,9 +2474,11 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
if (result)
{
//error will be catch in the dataStatusChanged event
adTabbox.getSelectedGridTab().dataDelete();
boolean success = adTabbox.getSelectedGridTab().dataDelete();
adTabbox.getSelectedGridTab().dataRefreshAll(true, true);
adTabbox.getSelectedGridTab().refreshParentTabs();
if (!success)
showLastWarning();
adTabbox.getSelectedTabpanel().dynamicDisplay(0);
focusToActivePanel();

View File

@ -356,7 +356,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
showRecordsCount();
}
if (this.isVisible())
Clients.resize(listbox);
listbox.invalidate();
}
/**
@ -729,7 +729,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
listModel.setPage(pgNo);
onSelectedRowChange(0);
gridTab.clearSelection();
Clients.resize(listbox);
listbox.invalidate();
}
}
else if (event.getTarget() == selectAll)
@ -1121,7 +1121,7 @@ public class GridView extends Vlayout implements EventListener<Event>, IdSpace,
refresh(gridTab);
scrollToCurrentRow();
Clients.resize(listbox);
listbox.invalidate();
}
/**

View File

@ -70,7 +70,11 @@ public class ToolbarCustomButton implements EventListener<Event>, Evaluatee {
}
public void dynamicDisplay() {
if (toolbarButton.getParent() == null)
dynamicDisplay(false);
}
public void dynamicDisplay(boolean forceValidation) {
if (toolbarButton.getParent() == null && !forceValidation)
return;
String displayLogic = mToolbarButton.getDisplayLogic();

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import org.adempiere.webui.AdempiereWebUI;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.adwindow.IFieldEditorContainer;
import org.adempiere.webui.component.Bandbox;
import org.adempiere.webui.component.Button;
import org.adempiere.webui.component.Datebox;
@ -813,6 +814,18 @@ public abstract class WEditor implements EventListener<Event>, PropertyChangeLis
return null;
}
protected void focusNext() {
Component comp = getComponent();
Component parent = comp.getParent();
while (parent != null) {
if (parent instanceof IFieldEditorContainer) {
((IFieldEditorContainer) parent).focusToNextEditor(this);
break;
}
parent = parent.getParent();
}
}
protected Evaluatee getStyleEvaluatee() {
return new EvaluateeWrapper(this, gridField, tableEditor);
}

View File

@ -278,6 +278,8 @@ public class WPaymentEditor extends WEditor implements ListDataListener, Context
super.fireValueChange(changeEvent);
oldValue = newValue;
}
if (newValue != null)
focusNext();
}
else if (Events.ON_BLUR.equalsIgnoreCase(event.getName()))
{

View File

@ -29,7 +29,6 @@ import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.ValuePreference;
import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.adwindow.ADWindowContent;
import org.adempiere.webui.adwindow.IFieldEditorContainer;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.Searchbox;
import org.adempiere.webui.event.ContextMenuEvent;
@ -390,16 +389,7 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
log.fine(getColumnName() + " - Unique ID=" + id);
actionCombo(Integer.valueOf(id)); // data binding
Searchbox comp = getComponent();
Component parent = comp.getParent();
while (parent != null) {
if (parent instanceof IFieldEditorContainer) {
((IFieldEditorContainer) parent).focusToNextEditor(this);
break;
}
parent = parent.getParent();
}
focusNext();
//safety check: if focus is going no where, focus back to self
String uid = getComponent().getTextbox().getUuid();
@ -599,6 +589,7 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
actionCombo (result);
else
actionCombo (result[0]);
focusNext();
}
else if (cancelled)
{
@ -613,13 +604,14 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
getComponent().setText("");
actionCombo(null);
}
getComponent().getTextbox().focus();
}
else
{
if (log.isLoggable(Level.CONFIG)) log.config(getColumnName() + " - Result = null (not cancelled)");
}
getComponent().getTextbox().focus();
}
}
});
ip.setId(ip.getTitle()+"_"+ip.getWindowNo());
AEnv.showWindow(ip);

View File

@ -507,6 +507,8 @@ ContextMenuListener, IZoomableEditor
gridField.setLookupEditorSettingValue(false);
}
}
if (newValue != null)
focusNext();
} finally {
onselecting = false;
}