Merge release-7.1 into master
This commit is contained in:
commit
15707d9aac
|
@ -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
|
||||
;
|
||||
|
|
@ -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
|
||||
;
|
||||
|
|
@ -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,14 +445,31 @@ 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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
boolean allEquals = true;
|
||||
|
@ -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());
|
||||
}
|
||||
FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference);
|
||||
fl.setDescription(description.toString());
|
||||
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);
|
||||
}
|
||||
fl.setDescription(description.toString());
|
||||
fl.setAD_Org_ID(invoice.getAD_Org_ID());
|
||||
}
|
||||
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());
|
||||
|
||||
}
|
||||
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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
setIsPrepayment (getC_Charge_ID() == 0
|
||||
&& getC_BPartner_ID() != 0
|
||||
&& (getC_Order_ID() != 0
|
||||
|| (getC_Project_ID() != 0 && getC_Invoice_ID() == 0)));
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -83,9 +83,11 @@ 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);
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -2016,16 +2016,20 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
|||
return;
|
||||
|
||||
clearTitleRelatedContext();
|
||||
|
||||
onSave(false, false, new Callback<Boolean>() {
|
||||
|
||||
@Override
|
||||
public void onCallback(Boolean result) {
|
||||
if (result) {
|
||||
doOnFind();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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) {
|
||||
doOnFind();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void doOnFind() {
|
||||
|
@ -2156,11 +2160,15 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
|||
if (dirtyTabpanel != null) {
|
||||
focusToTabpanel(dirtyTabpanel);
|
||||
//ensure row indicator is not lost
|
||||
RowRenderer<Object[]> renderer = dirtyTabpanel.getGridView().getListbox().getRowRenderer();
|
||||
GridTabRowRenderer gtr = (GridTabRowRenderer)renderer;
|
||||
org.zkoss.zul.Row row = gtr.getCurrentRow();
|
||||
if (row != null)
|
||||
gtr.setCurrentRow(row);
|
||||
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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
{
|
||||
|
|
|
@ -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,17 +389,8 @@ 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();
|
||||
String script = "setTimeout(function(){try{var e = zk.Widget.$('#" + uid +
|
||||
|
@ -599,6 +589,7 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
|
|||
actionCombo (result);
|
||||
else
|
||||
actionCombo (result[0]);
|
||||
focusNext();
|
||||
}
|
||||
else if (cancelled)
|
||||
{
|
||||
|
@ -612,13 +603,14 @@ public class WSearchEditor extends WEditor implements ContextMenuListener, Value
|
|||
}else{
|
||||
getComponent().setText("");
|
||||
actionCombo(null);
|
||||
}
|
||||
}
|
||||
getComponent().getTextbox().focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log.isLoggable(Level.CONFIG)) log.config(getColumnName() + " - Result = null (not cancelled)");
|
||||
getComponent().getTextbox().focus();
|
||||
}
|
||||
getComponent().getTextbox().focus();
|
||||
}
|
||||
});
|
||||
ip.setId(ip.getTitle()+"_"+ip.getWindowNo());
|
||||
|
|
|
@ -507,6 +507,8 @@ ContextMenuListener, IZoomableEditor
|
|||
gridField.setLookupEditorSettingValue(false);
|
||||
}
|
||||
}
|
||||
if (newValue != null)
|
||||
focusNext();
|
||||
} finally {
|
||||
onselecting = false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue