hg merge release-5.1 (merge release5.1 into default)

This commit is contained in:
Carlos Ruiz 2018-08-29 20:42:42 +02:00
commit ac0b824eee
36 changed files with 616 additions and 346 deletions

View File

@ -0,0 +1,15 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-3757
-- Jul 24, 2018 9:30:27 AM CEST
UPDATE AD_Table SET AccessLevel='4',Updated=TO_DATE('2018-07-24 09:30:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=116
;
DELETE FROM ad_window_access WHERE ad_window_id=105
AND ad_role_id IN (SELECT ad_role_id FROM ad_role WHERE ismanual='N' AND userlevel NOT LIKE 'S%')
;
SELECT register_migration_script('201807240936_IDEMPIERE-3757.sql') FROM dual
;

View File

@ -0,0 +1,14 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-3762 : Fix AD_Column_ID / AD_Field_ID : Loader - Too many records
-- Jul 26, 2018 10:06:34 AM CEST
UPDATE AD_Field SET AD_Reference_ID=30,Updated=TO_DATE('2018-07-26 10:06:34','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=4599
;
-- Jul 26, 2018 10:06:42 AM CEST
UPDATE AD_Field SET AD_Reference_ID=30,Updated=TO_DATE('2018-07-26 10:06:42','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=59576
;
SELECT register_migration_script('201807271000_IDEMPIERE-3762.sql') FROM dual
;

View File

@ -0,0 +1,10 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-3769 : IBAN : Invalid message is not translated - force to uppercase
-- Aug 1, 2018 8:56:43 AM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','IBAN is invalid',0,0,'Y',TO_DATE('2018-08-01 08:56:42','YYYY-MM-DD HH24:MI:SS'),0,TO_DATE('2018-08-01 08:56:42','YYYY-MM-DD HH24:MI:SS'),0,200480,'InvalidIBAN','D','4cc792d9-9af0-4e37-b90a-7dcc9f5e82ec')
;
SELECT register_migration_script('201808010900_IDEMPIERE-3769.sql') FROM dual
;

View File

@ -0,0 +1,31 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-2442 Always using default conversion type in Order & Invoice window's amount summary information
-- Aug 7, 2018 12:22:32 PM CEST
UPDATE AD_StatusLine SET SQLStatement='SELECT COUNT(DISTINCT C_OrderLine_ID) AS Lines,o.TotalLines,o.GrandTotal,c.ISO_Code,
currencyConvert(o.GrandTotal,o.C_Currency_ID,ac.C_Currency_ID,o.DateAcct,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) AS ConvAmt
FROM C_Order o
INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)
LEFT JOIN C_OrderLine l ON (o.C_Order_ID=l.C_Order_ID)
LEFT JOIN AD_ClientInfo ci ON (ci.AD_Client_ID=o.AD_Client_ID)
LEFT JOIN C_AcctSchema ac ON (ci.C_AcctSchema1_ID=ac.C_AcctSchema_ID)
WHERE o.C_Order_ID=@C_Order_ID@
GROUP BY o.C_Currency_ID, ac.C_Currency_ID, o.C_ConversionType_ID, c.ISO_Code, o.TotalLines, o.GrandTotal, o.DateAcct, o.AD_Client_ID, o.AD_Org_ID',Updated=TO_DATE('2018-08-07 12:22:32','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_StatusLine_ID=200000
;
-- Aug 7, 2018 12:25:27 PM CEST
UPDATE AD_StatusLine SET SQLStatement='SELECT COUNT(DISTINCT C_InvoiceLine_ID) AS Lines,o.TotalLines,o.GrandTotal,c.ISO_Code,
currencyConvert(o.GrandTotal,o.C_Currency_ID,ac.C_Currency_ID,o.DateAcct,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) AS ConvAmt
FROM C_Invoice o
INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)
LEFT JOIN C_InvoiceLine l ON (o.C_Invoice_ID=l.C_Invoice_ID)
LEFT JOIN AD_ClientInfo ci ON (ci.AD_Client_ID=o.AD_Client_ID)
LEFT JOIN C_AcctSchema ac ON (ci.C_AcctSchema1_ID=ac.C_AcctSchema_ID)
WHERE o.C_Invoice_ID=@C_Invoice_ID@
GROUP BY o.C_Currency_ID, ac.C_Currency_ID, o.C_ConversionType_ID, c.ISO_Code, o.TotalLines, o.GrandTotal, o.DateAcct, o.AD_Client_ID, o.AD_Org_ID',Updated=TO_DATE('2018-08-07 12:25:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_StatusLine_ID=200002
;
SELECT register_migration_script('201808071226_IDEMPIERE-2442.sql') FROM dual
;

View File

@ -0,0 +1,12 @@
-- IDEMPIERE-3757
-- Jul 24, 2018 9:30:27 AM CEST
UPDATE AD_Table SET AccessLevel='4',Updated=TO_TIMESTAMP('2018-07-24 09:30:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=116
;
DELETE FROM ad_window_access WHERE ad_window_id=105
AND ad_role_id IN (SELECT ad_role_id FROM ad_role WHERE ismanual='N' AND userlevel NOT LIKE 'S%')
;
SELECT register_migration_script('201807240936_IDEMPIERE-3757.sql') FROM dual
;

View File

@ -0,0 +1,11 @@
-- IDEMPIERE-3762 : Fix AD_Column_ID / AD_Field_ID : Loader - Too many records
-- Jul 26, 2018 10:06:34 AM CEST
UPDATE AD_Field SET AD_Reference_ID=30,Updated=TO_TIMESTAMP('2018-07-26 10:06:34','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=4599
;
-- Jul 26, 2018 10:06:42 AM CEST
UPDATE AD_Field SET AD_Reference_ID=30,Updated=TO_TIMESTAMP('2018-07-26 10:06:42','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=0 WHERE AD_Field_ID=59576
;
SELECT register_migration_script('201807271000_IDEMPIERE-3762.sql') FROM dual
;

View File

@ -0,0 +1,7 @@
-- IDEMPIERE-3769 : IBAN : Invalid message is not translated - force to uppercase
-- Aug 1, 2018 8:56:43 AM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','IBAN is invalid',0,0,'Y',TO_TIMESTAMP('2018-08-01 08:56:42','YYYY-MM-DD HH24:MI:SS'),0,TO_TIMESTAMP('2018-08-01 08:56:42','YYYY-MM-DD HH24:MI:SS'),0,200480,'InvalidIBAN','D','4cc792d9-9af0-4e37-b90a-7dcc9f5e82ec')
;
SELECT register_migration_script('201808010900_IDEMPIERE-3769.sql') FROM dual
;

View File

@ -0,0 +1,28 @@
-- IDEMPIERE-2442 Always using default conversion type in Order & Invoice window's amount summary information
-- Aug 7, 2018 12:22:32 PM CEST
UPDATE AD_StatusLine SET SQLStatement='SELECT COUNT(DISTINCT C_OrderLine_ID) AS Lines,o.TotalLines,o.GrandTotal,c.ISO_Code,
currencyConvert(o.GrandTotal,o.C_Currency_ID,ac.C_Currency_ID,o.DateAcct,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) AS ConvAmt
FROM C_Order o
INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)
LEFT JOIN C_OrderLine l ON (o.C_Order_ID=l.C_Order_ID)
LEFT JOIN AD_ClientInfo ci ON (ci.AD_Client_ID=o.AD_Client_ID)
LEFT JOIN C_AcctSchema ac ON (ci.C_AcctSchema1_ID=ac.C_AcctSchema_ID)
WHERE o.C_Order_ID=@C_Order_ID@
GROUP BY o.C_Currency_ID, ac.C_Currency_ID, o.C_ConversionType_ID, c.ISO_Code, o.TotalLines, o.GrandTotal, o.DateAcct, o.AD_Client_ID, o.AD_Org_ID',Updated=TO_TIMESTAMP('2018-08-07 12:22:32','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_StatusLine_ID=200000
;
-- Aug 7, 2018 12:25:27 PM CEST
UPDATE AD_StatusLine SET SQLStatement='SELECT COUNT(DISTINCT C_InvoiceLine_ID) AS Lines,o.TotalLines,o.GrandTotal,c.ISO_Code,
currencyConvert(o.GrandTotal,o.C_Currency_ID,ac.C_Currency_ID,o.DateAcct,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) AS ConvAmt
FROM C_Invoice o
INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)
LEFT JOIN C_InvoiceLine l ON (o.C_Invoice_ID=l.C_Invoice_ID)
LEFT JOIN AD_ClientInfo ci ON (ci.AD_Client_ID=o.AD_Client_ID)
LEFT JOIN C_AcctSchema ac ON (ci.C_AcctSchema1_ID=ac.C_AcctSchema_ID)
WHERE o.C_Invoice_ID=@C_Invoice_ID@
GROUP BY o.C_Currency_ID, ac.C_Currency_ID, o.C_ConversionType_ID, c.ISO_Code, o.TotalLines, o.GrandTotal, o.DateAcct, o.AD_Client_ID, o.AD_Org_ID',Updated=TO_TIMESTAMP('2018-08-07 12:25:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_StatusLine_ID=200002
;
SELECT register_migration_script('201808071226_IDEMPIERE-2442.sql') FROM dual
;

View File

@ -453,8 +453,6 @@ public class CalloutOrder extends CalloutEngine
*/
public String bPartnerBill (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
{
if (isCalloutActive())
return "";
Integer bill_BPartner_ID = (Integer)value;
if (bill_BPartner_ID == null || bill_BPartner_ID.intValue() == 0)
return "";

View File

@ -25,6 +25,7 @@ import org.compiere.model.MBPartner;
import org.compiere.model.MDocType;
import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MPriceList;
import org.compiere.model.MTimeExpense;
import org.compiere.model.MTimeExpenseLine;
import org.compiere.util.DB;
@ -136,6 +137,10 @@ public class ExpenseAPInvoice extends SvrProcess
break;
}
invoice.setM_PriceList_ID(te.getM_PriceList_ID());
MPriceList pl = MPriceList.get(getCtx(), te.getM_PriceList_ID(), get_TrxName());
invoice.setIsTaxIncluded(pl.isTaxIncluded());
invoice.setSalesRep_ID(te.getDoc_User_ID());
StringBuilder descr = new StringBuilder().append(Msg.translate(getCtx(), "S_TimeExpense_ID"))
.append(": ").append(te.getDocumentNo()).append(" " )
@ -182,6 +187,7 @@ public class ExpenseAPInvoice extends SvrProcess
//
// il.setPrice(); // not really a list/limit price for reimbursements
il.setPrice(line.getPriceReimbursed()); //
il.setTax();
if (!il.save())
throw new IllegalStateException("Cannot save Invoice Line");

View File

@ -19,7 +19,8 @@ package org.compiere.acct;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.compiere.model.MAccount;
@ -28,7 +29,8 @@ import org.compiere.model.MAcctSchemaElement;
import org.compiere.model.MAllocationHdr;
import org.compiere.model.MAllocationLine;
import org.compiere.model.MCashLine;
import org.compiere.model.MConversionRate;
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;
@ -197,6 +199,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)
@ -258,8 +261,9 @@ public class Doc_AllocationHdr extends Doc
// Payment/Cash DR
if (line.getC_Payment_ID() != 0)
{
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
{
payAcct = getPaymentAcct(as, line.getC_Payment_ID());
fl = fact.createLine (line, payAcct,
getC_Currency_ID(), line.getAmtSource(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
@ -388,8 +392,9 @@ public class Doc_AllocationHdr extends Doc
}
// Payment/Cash CR
if (isUsingClearing && line.getC_Payment_ID() != 0) // Avoid usage of clearing accounts
{
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
{
payAcct = getPaymentAcct(as, line.getC_Payment_ID());
fl = fact.createLine (line, payAcct,
getC_Currency_ID(), null, line.getAmtSource().negate());
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
@ -430,7 +435,7 @@ 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,
p_Error = createRealizedGainLoss (line, as, fact, bpAcct, invoice, payAcct, payment,
allocationSource, allocationAccounted);
if (p_Error != null)
return null;
@ -692,102 +697,164 @@ public class Doc_AllocationHdr extends Doc
* Accounted Amount of the Allocation
* @param as accounting schema
* @param fact fact
* @param acct account
* @param invAcct invoice 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 acct,
MInvoice invoice, BigDecimal allocationSource, BigDecimal allocationAccounted)
private String createRealizedGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount invAcct,
MInvoice invoice, MAccount payAcct, MPayment payment, BigDecimal allocationSource, BigDecimal allocationAccounted)
{
BigDecimal invoiceSource = null;
BigDecimal invoiceAccounted = null;
BigDecimal paymentSource = null;
BigDecimal paymentAccounted = null;
//
StringBuilder sql = new StringBuilder("SELECT ")
.append(invoice.isSOTrx()
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
StringBuilder sql = new StringBuilder()
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=318 AND Record_ID=?") // Invoice
.append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'");
//AND C_Currency_ID=102
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, invoice.getC_Invoice_ID());
pstmt.setInt(2, as.getC_AcctSchema_ID());
rs = pstmt.executeQuery();
if (rs.next())
{
invoiceSource = rs.getBigDecimal(1);
invoiceAccounted = rs.getBigDecimal(2);
}
}
catch (Exception e)
{
log.log(Level.SEVERE, sql.toString(), e);
}
finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
.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());
if (valuesInv != null) {
if (invoice.isSOTrx()) {
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
} else {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
// Requires that Invoice is Posted
if (invoiceSource == null || invoiceAccounted == null)
return "Gain/Loss - Invoice not posted yet";
//
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
//
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());
// Allocation not Invoice Currency
BigDecimal allocationInvoiceSource = allocationSource;
if (getC_Currency_ID() != invoice.getC_Currency_ID())
{
BigDecimal allocationSourceNew = MConversionRate.convert(getCtx(),
allocationInvoiceSource = 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 (allocationSourceNew == null)
if (allocationInvoiceSource == null)
return "Gain/Loss - No Conversion from Allocation->Invoice";
StringBuilder d2 = new StringBuilder("Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource)
.append("->(").append(invoice.getC_Currency_ID()).append(")").append(allocationSourceNew);
StringBuilder d2 = new StringBuilder("Allocation=(").append(allocCur).append(")").append(allocationSource)
.append("->(").append(invoiceCur).append(")").append(allocationInvoiceSource);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
allocationSource = allocationSourceNew;
descriptionInv.append(" - ").append(d2);
}
BigDecimal acctDifference = null; // gain is negative
// Full Payment in currency
if (allocationSource.compareTo(invoiceSource) == 0)
{
acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
else // partial or MC
{
// percent of total payment
double multiplier = allocationSource.doubleValue() / invoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
invoiceAccounted = invoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
// Difference based on percentage of Orig Invoice
acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
// ignore Tolerance
if (acctDifference.abs().compareTo(TOLERANCE) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, BigDecimal.ROUND_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)
BigDecimal invoiceDifference = null; // gain is negative
// Full Invoice in currency
if (allocationInvoiceSource.compareTo(invoiceSource) == 0)
{
invoiceDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
StringBuilder d2 = new StringBuilder("(full) = ").append(invoiceDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionInv.append(" - ").append(d2);
}
else // partial or MC
{
// percent of total payment
double multiplier = allocationInvoiceSource.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
// ignore Tolerance
if (invoiceDifference.abs().compareTo(TOLERANCE) < 0)
invoiceDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (invoiceDifference.scale() > precision)
invoiceDifference = invoiceDifference.setScale(precision, BigDecimal.ROUND_HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(invoiceDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
descriptionInv.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, BigDecimal.ROUND_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)
{
log.fine("No Difference");
return null;
@ -795,23 +862,45 @@ 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());
//
//
BigDecimal acctDifference = invoiceDifference.subtract(paymentDifference);
if (invoice.isSOTrx())
{
FactLine fl = fact.createLine (line, loss, gain,
as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString());
fact.createLine (line, acct,
as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString());
{
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());
}
if (invoiceDifference.signum() != 0) {
FactLine fl = fact.createLine (line, invAcct, as.getC_Currency_ID(), invoiceDifference.negate());
fl.setDescription(descriptionInv.toString());
}
if (paymentDifference.signum() != 0) {
FactLine fl = fact.createLine (line, payAcct, as.getC_Currency_ID(), paymentDifference);
fl.setDescription(descriptionPay.toString());
}
}
else
{
fact.createLine (line, acct,
as.getC_Currency_ID(), acctDifference);
@SuppressWarnings("unused")
FactLine fl = fact.createLine (line, loss, gain,
as.getC_Currency_ID(), acctDifference.negate());
if (invoiceDifference.signum() != 0) {
FactLine fl = fact.createLine (line, invAcct, as.getC_Currency_ID(), invoiceDifference);
fl.setDescription(descriptionInv.toString());
}
if (paymentDifference.signum() != 0) {
FactLine fl = fact.createLine (line, payAcct, as.getC_Currency_ID(), paymentDifference.negate());
fl.setDescription(descriptionPay.toString());
}
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());
}
}
return null;
} // createRealizedGainLoss
@ -1040,49 +1129,49 @@ class Doc_AllocationTax
} // Discount
// WriteOff Amount
if (m_WriteOffAmt.signum() != 0)
{
// Original Tax is DR - need to correct it CR
if (Env.ZERO.compareTo(factAcct.getAmtSourceDr()) != 0)
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceDr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
if (m_IsSOTrx) {
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount);
} else {
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), amount.negate(), null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount.negate());
}
}
}
// Original Tax is CR - need to correct it DR
else
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceCr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
if(m_IsSOTrx) {
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), null, amount);
} else {
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount.negate(), null);
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), null, amount.negate());
}
}
}
} // WriteOff
if (m_WriteOffAmt.signum() != 0)
{
// Original Tax is DR - need to correct it CR
if (Env.ZERO.compareTo(factAcct.getAmtSourceDr()) != 0)
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceDr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
if (m_IsSOTrx) {
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount);
} else {
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), amount.negate(), null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount.negate());
}
}
}
// Original Tax is CR - need to correct it DR
else
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceCr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
if(m_IsSOTrx) {
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), null, amount);
} else {
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount.negate(), null);
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), null, amount.negate());
}
}
}
} // WriteOff
} // for all lines
return true;

View File

@ -93,7 +93,10 @@ public class Doc_GLJournal extends Doc
MAccount account = line.getAccount_Combi();
docLine.setAccount (account);
// -- Organization of Line was set to Org of Account
list.add(docLine);
list.add(docLine);
if (docLine.getC_Currency_ID() != getC_Currency_ID())
setIsMultiCurrency(true);
}
// Return Array
int size = list.size();
@ -154,7 +157,7 @@ public class Doc_GLJournal extends Doc
@SuppressWarnings("unused")
FactLine line = fact.createLine (p_lines[i],
p_lines[i].getAccount (),
getC_Currency_ID(),
p_lines[i].getC_Currency_ID(),
p_lines[i].getAmtSourceDr (),
p_lines[i].getAmtSourceCr ());
}

View File

@ -445,14 +445,41 @@ public class Doc_MatchPO extends Doc
&& mPO[i].getM_MatchPO_ID() != mMatchPO.getM_MatchPO_ID())
{
BigDecimal qty = (isReturnTrx ? mPO[i].getQty().negate() : mPO[i].getQty());
BigDecimal orderCost = BigDecimal.ZERO;
if (mPO[i].getM_InOutLine_ID() > 0)
{
tQty = tQty.add(qty);
tAmt = tAmt.add(poCost.multiply(qty));
//IDEMPIERE-3742 Wrong product cost for partial MR
if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID())
{
MOrder order = m_oLine.getParent();
if(MAcctSchema.COSTINGMETHOD_AveragePO.equals(as.getCostingMethod()))
{
orderCost = mPO[i].getM_InOutLine().getC_OrderLine().getPriceActual();
Timestamp dateAcct = mPO[i].getM_InOutLine().getM_InOut().getDateAcct();
BigDecimal rate = MConversionRate.getRate(
order.getC_Currency_ID(), as.getC_Currency_ID(),
dateAcct, order.getC_ConversionType_ID(),
m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID());
if (rate == null)
{
p_Error = "Purchase Order not convertible - " + as.getName();
return null;
}
orderCost = orderCost.multiply(rate);
tAmt = tAmt.add(orderCost.multiply(qty));
} else {
tAmt = tAmt.add(poCost.multiply(qty));
}
} //IDEMPIERE-3742 Wrong product cost for partial MR
else {
tAmt = tAmt.add(poCost.multiply(qty));
}
}
}
}
}
poCost = poCost.multiply(getQty()); // Delivered so far
tAmt = tAmt.add(isReturnTrx ? poCost.negate() : poCost);
tQty = tQty.add(isReturnTrx ? getQty().negate() : getQty());

View File

@ -728,7 +728,7 @@ public final class FactLine extends X_Fact_Acct
Timestamp convDate = getDateAcct();
if ( m_docLine != null && ( m_doc instanceof Doc_BankStatement || m_doc instanceof Doc_AllocationHdr ) )
if (m_docLine != null && m_doc instanceof Doc_BankStatement)
convDate = m_docLine.getDateConv();

View File

@ -24,6 +24,7 @@ import org.adempiere.util.PaymentUtil;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.IBAN;
import org.compiere.util.Msg;
import org.compiere.util.Util;
/**
@ -214,7 +215,7 @@ public class MBPBankAccount extends X_C_BP_BankAccount
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
log.saveError("Error", Msg.getMsg(getCtx(), "InvalidIBAN"));
return false;
}
}

View File

@ -22,6 +22,7 @@ import java.util.Properties;
import org.compiere.util.CCache;
import org.compiere.util.Env;
import org.compiere.util.IBAN;
import org.compiere.util.Msg;
import org.compiere.util.Util;
@ -136,7 +137,7 @@ public class MBankAccount extends X_C_BankAccount
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
log.saveError("Error", Msg.getMsg(getCtx(), "InvalidIBAN"));
return false;
}
}

View File

@ -1035,7 +1035,7 @@ public class MInvoiceLine extends X_C_InvoiceLine
{
double result = getLineNetAmt().multiply(base).doubleValue();
result /= total.doubleValue();
lca.setAmt(result, getParent().getC_Currency().getCostingPrecision());
lca.setAmt(result, getParent().getC_Currency().getStdPrecision());
}
if (!lca.save()){
msgreturn = new StringBuilder("Cannot save line Allocation = ").append(lca);
@ -1170,7 +1170,7 @@ public class MInvoiceLine extends X_C_InvoiceLine
{
double result = getLineNetAmt().multiply(base).doubleValue();
result /= total.doubleValue();
lca.setAmt(result, getParent().getC_Currency().getCostingPrecision());
lca.setAmt(result, getParent().getC_Currency().getStdPrecision());
}
if (!lca.save()){
msgreturn = new StringBuilder("Cannot save line Allocation = ").append(lca);

View File

@ -527,8 +527,8 @@ public class MJournal extends X_GL_Journal implements DocAction
}
// end BF [2789319] No check of Actual, Budget, Statistical attribute
AmtSourceDr = AmtSourceDr.add(line.getAmtSourceDr());
AmtSourceCr = AmtSourceCr.add(line.getAmtSourceCr());
AmtSourceDr = AmtSourceDr.add(line.getAmtAcctDr()); // multi-currency
AmtSourceCr = AmtSourceCr.add(line.getAmtAcctCr());
}
setTotalDr(AmtSourceDr);
setTotalCr(AmtSourceCr);

View File

@ -804,7 +804,7 @@ public class MPayment extends X_C_Payment
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
log.saveError("Error", Msg.getMsg(getCtx(), "InvalidIBAN"));
return false;
}
}

View File

@ -87,7 +87,7 @@ public class MPaymentTransaction extends X_C_PaymentTransaction implements Proce
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
log.saveError("Error", Msg.getMsg(getCtx(), "InvalidIBAN"));
return false;
}
}

View File

@ -282,7 +282,8 @@ public class MPeriod extends X_C_Period
int idxdate = -1;
if ( tableID == MInventory.Table_ID
|| tableID == MMovement.Table_ID
|| tableID == MProduction.Table_ID) {
|| tableID == MProduction.Table_ID
|| tableID == MProjectIssue.Table_ID) {
idxdate = po.get_ColumnIndex("MovementDate");
} else if ( tableID == MRequisition.Table_ID) {
idxdate = po.get_ColumnIndex("DateDoc");
@ -333,6 +334,8 @@ public class MPeriod extends X_C_Period
} else if ( tableID == MAssetDisposed.Table_ID
|| tableID == MDepreciationExp.Table_ID) {
docBaseType = MDocType.DOCBASETYPE_GLDocument; // seems like a bug of fixed assets - must use GLJournal instead of GLDocument?
} else if (tableID == MProjectIssue.Table_ID) {
docBaseType = MDocType.DOCBASETYPE_ProjectIssue;
} else {
s_log.warning("Could not find C_DocType_ID for " + table.getTableName());
return true;

View File

@ -288,7 +288,7 @@ public class MRequisitionLine extends X_M_RequisitionLine
* IDEMPIERE-178 Orders and Invoices must disallow amount lines without product/charge
*/
if (getParent().getC_DocType().isChargeOrProductMandatory()) {
if (getC_Charge_ID() == 0 && getM_Product_ID() == 0 && getPriceActual().signum() != 0) {
if (getC_Charge_ID() == 0 && getM_Product_ID() == 0 && (getPriceActual().signum() != 0 || getQty().signum() != 0)) {
log.saveError("FillMandatory", Msg.translate(getCtx(), "ChargeOrProductMandatory"));
return false;
}

View File

@ -871,14 +871,8 @@ public final class Env
throw new IllegalArgumentException ("Require Context");
String s = getContext(ctx, WindowNo, context, false);
// JDBC Format YYYY-MM-DD example 2000-09-11 00:00:00.0
if (s == null || s.equals(""))
{
if (!"#date".equalsIgnoreCase(context))
{
log.log(Level.WARNING, "No value for: " + context);
}
if (Util.isEmpty(s))
return new Timestamp(System.currentTimeMillis());
}
// BUG:3075946 KTU - Fix Thai Date
/*

View File

@ -26,7 +26,7 @@ public class IBAN {
{
if (iban!=null)
{
return iban.trim().replace(" ", "") ;
return iban.trim().replace(" ", "").toUpperCase() ;
}
return null ;
}

View File

@ -1353,7 +1353,7 @@ public class ReportStarter implements ProcessCall, ClientProcess
jasperFile.setLastModified( reportFile.lastModified()); //Synchronize Dates
compiledJasperReport = (JasperReport)JRLoader.loadObject(jasperFile);
} catch (JRException e) {
log.log(Level.SEVERE, "Error", e);
throw new AdempiereException(e);
}
return compiledJasperReport;
}

View File

@ -533,7 +533,7 @@ public class WAllocation extends Allocation
allocateButton.setEnabled(true);
if (allocation != null)
{
DocumentLink link = new DocumentLink(allocation.getDocumentNo(), allocation.get_Table_ID(), allocation.get_ID());
DocumentLink link = new DocumentLink(Msg.getElement(Env.getCtx(), MAllocationHdr.COLUMNNAME_C_AllocationHdr_ID) + ": " + allocation.getDocumentNo(), allocation.get_Table_ID(), allocation.get_ID());
statusBar.appendChild(link);
}
}

View File

@ -118,7 +118,7 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
{
log.log(Level.SEVERE, "", e);
}
} // init
} // WPayPrint
// Static Variables
protected Panel centerPanel = new Panel();
@ -234,8 +234,7 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
bExport.setDisabled(true);
bPrint.setDisabled(true);
fDepositBatch.setReadWrite(false);
fDocumentNo.setReadWrite(false);
} // VPayPrint
} // zkInit
/**
* Dynamic Init

View File

@ -85,8 +85,8 @@ public class WAccountEditor extends WEditor implements ContextMenuListener
@Override
public Object getValue()
{
//if (m_mAccount.C_ValidCombination_ID == 0)
// return null;
if (m_mAccount.C_ValidCombination_ID == 0)
return null;
return new Integer (m_mAccount.C_ValidCombination_ID);
}
@ -101,7 +101,11 @@ public class WAccountEditor extends WEditor implements ContextMenuListener
*/
public void cmd_button()
{
int C_AcctSchema_ID = Env.getContextAsInt(Env.getCtx(), gridField.getWindowNo(), "C_AcctSchema_ID");
int C_AcctSchema_ID;
if (gridField.getGridTab() != null)
C_AcctSchema_ID = Env.getContextAsInt(Env.getCtx(), gridField.getWindowNo(), gridField.getGridTab().getTabNo(), "C_AcctSchema_ID");
else
C_AcctSchema_ID = Env.getContextAsInt(Env.getCtx(), gridField.getWindowNo(), "C_AcctSchema_ID");
// Try to get C_AcctSchema_ID from global context - teo_sarca BF [ 1830531 ]
if (C_AcctSchema_ID <= 0)
{

View File

@ -2649,7 +2649,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
*/
private void setStatusDB (int currentCount)
{
StringBuilder text = new StringBuilder(" ").append(currentCount).append(" / ").append(m_total).append(" ");
StringBuilder text = new StringBuilder(" ").append(Msg.getMsg(Env.getCtx(), "Records")).append(" = ").append(m_total).append(" ");
statusBar.setStatusDB(text.toString());
} // setDtatusDB
/** END DEVCOFFEE **/

View File

@ -2,6 +2,9 @@ CKEDITOR.editorConfig = function(config) {
config.resize_enabled = false;
config.toolbarCanCollapse = true;
config.toolbar = 'MyToolbar';
config.coreStyles_bold = { element: 'b', overrides: 'strong' };
config.coreStyles_italic = { element: 'i', overrides: 'em' };
config.coreStyles_strike = { element: 'strike', overrides: 's' };
config.toolbar_MyToolbar =
[
{ name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] },

View File

@ -2,6 +2,9 @@ CKEDITOR.editorConfig = function(config) {
config.resize_enabled = false;
config.toolbarCanCollapse = true;
config.toolbar = 'MyToolbar';
config.coreStyles_bold = { element: 'b', overrides: 'strong' };
config.coreStyles_italic = { element: 'i', overrides: 'em' };
config.coreStyles_strike = { element: 'strike', overrides: 's' };
config.toolbar_MyToolbar =
[
{ name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] },

View File

@ -65,11 +65,8 @@ public class CompositeServiceImpl extends AbstractService implements CompositeSe
*/
@Override
public CompositeResponsesDocument compositeOperation(CompositeRequestDocument reqs) {
boolean connected = getCompiereService().isConnected();
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
CompositeResponsesDocument ret = CompositeResponsesDocument.Factory.newInstance();
CompositeResponses resps = ret.addNewCompositeResponses();
@ -124,8 +121,7 @@ public class CompositeServiceImpl extends AbstractService implements CompositeSe
return ret;
} finally {
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}

View File

@ -76,7 +76,7 @@ public class MWebService extends X_WS_WebService
* @param webServiceValue
* @return Table
*/
public static MWebService get (Properties ctx, String webServiceValue)
public static synchronized MWebService get (Properties ctx, String webServiceValue)
{
if (webServiceValue == null)
return null;

View File

@ -79,13 +79,13 @@ public class CompiereService {
public final String dateFormatOnlyForCtx = "yyyy-MM-dd";
private boolean m_connected;
private int m_connectCount;
/**
*
* @return AD_Client_ID of current request
*/
public int getAD_Client_ID() {
public synchronized int getAD_Client_ID() {
return m_AD_Client_ID;
}
@ -93,7 +93,7 @@ public class CompiereService {
*
* @return AD_Org_ID of current request
*/
public int getAD_Org_ID() {
public synchronized int getAD_Org_ID() {
return m_AD_Org_ID;
}
@ -101,7 +101,7 @@ public class CompiereService {
*
* @return context of current request
*/
public Properties getCtx() {
public synchronized Properties getCtx() {
return Env.getCtx();
}
@ -111,7 +111,7 @@ public class CompiereService {
public CompiereService()
{
m_loggedin = false;
m_connected = false;
m_connectCount = 0;
}
/**
@ -119,70 +119,51 @@ public class CompiereService {
*/
public void connect()
{
if (!m_connected)
{
CompiereUtil.initWeb();
m_connected = true;
ServerContext.setCurrentInstance(new Properties());
Env.setContext(getCtx(), "#AD_Language", "en_US" );
m_language = Language.getLanguage("en_US");
dateFormat = DisplayType.getDateFormat(DisplayType.Date, m_language);
dateTimeFormat = DisplayType.getDateFormat(DisplayType.DateTime, m_language);
timeFormat = DisplayType.getDateFormat(DisplayType.Time, m_language);
dateFormatJDBC = DisplayType.getDateFormat_JDBC();
dateTimeFormatJDBC = DisplayType.getTimestampFormat_Default();
timeFormatJDBC = DisplayType.getTimeFormat_Default();
}
CompiereUtil.initWeb();
ServerContext.setCurrentInstance(new Properties());
Env.setContext(getCtx(), "#AD_Language", "en_US" );
m_language = Language.getLanguage("en_US");
dateFormat = DisplayType.getDateFormat(DisplayType.Date, m_language);
dateTimeFormat = DisplayType.getDateFormat(DisplayType.DateTime, m_language);
timeFormat = DisplayType.getDateFormat(DisplayType.Time, m_language);
dateFormatJDBC = DisplayType.getDateFormat_JDBC();
dateTimeFormatJDBC = DisplayType.getTimestampFormat_Default();
timeFormatJDBC = DisplayType.getTimeFormat_Default();
m_connectCount++;
}
/**
* Increase connect count
*/
public synchronized void connectCacheInstance()
{
m_connectCount++;
}
/**
* cleanup request
*/
public void disconnect()
public synchronized void disconnect()
{
m_connectCount--;
// TODO: create a thread that checks expired connected compiereservices and log them out
if (! isExpired()) {
// do not close, save session in cache
if (! csMap.containsValue(this)) {
String key = getKey(m_AD_Client_ID,
m_AD_Org_ID,
m_userName,
m_AD_Role_ID,
m_M_Warehouse_ID,
m_locale,
m_password,
m_IPAddress);
csMap.put(key.toString(), this);
Properties savedCache = new Properties();
savedCache.putAll(Env.getCtx());
ctxMap.put(key.toString(), savedCache);
if (log.isLoggable(Level.INFO)) log.info("Saving " + this + " in cache");
}
}
}
/**
* @return true if started
*/
public boolean isConnected()
{
return m_connected;
expungeIfExpire();
}
/**
* @return Language of current request
*/
public Language getLanguage() {
public synchronized Language getLanguage() {
return m_language;
}
/**
* @return true if already logged in
*/
public boolean isLoggedIn() {
public synchronized boolean isLoggedIn() {
return m_loggedin;
}
@ -196,7 +177,7 @@ public class CompiereService {
* @param AD_Org_ID org
* @param M_Warehouse_ID warehouse
*/
private String checkLogin (Properties ctx, int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID)
private synchronized String checkLogin (Properties ctx, int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID)
{
// Get Login Info
String loginInfo = null;
@ -262,7 +243,7 @@ public class CompiereService {
* @param Lang
* @return true if login is successful
*/
public boolean login( int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID, String Lang ) {
public synchronized boolean login( int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID, String Lang ) {
m_loggedin = false;
String loginInfo = checkLogin (getCtx(), AD_User_ID, AD_Role_ID, AD_Client_ID, AD_Org_ID, M_Warehouse_ID );
if (loginInfo == null)
@ -315,6 +296,26 @@ public class CompiereService {
session.saveEx();
m_loggedin = true;
synchronized (csMap) {
//save session in cache
String key = getKey(m_AD_Client_ID,
m_AD_Org_ID,
m_userName,
m_AD_Role_ID,
m_M_Warehouse_ID,
m_locale,
m_password,
m_IPAddress);
if (! csMap.containsKey(key)) {
csMap.put(key.toString(), this);
Properties savedCache = new Properties();
savedCache.putAll(Env.getCtx());
ctxMap.put(key.toString(), savedCache);
if (log.isLoggable(Level.INFO)) log.info("Saving " + this + " in cache");
}
}
return true;
}
@ -322,7 +323,7 @@ public class CompiereService {
*
* @return AD_User_ID of current request
*/
public int getAD_User_ID() {
public synchronized int getAD_User_ID() {
return m_AD_User_ID;
}
@ -330,7 +331,7 @@ public class CompiereService {
*
* @return AD_Role_ID of current request
*/
public int getAD_Role_ID() {
public synchronized int getAD_Role_ID() {
return m_AD_Role_ID;
}
@ -338,7 +339,7 @@ public class CompiereService {
*
* @return locale code of current request
*/
public String getLocale() {
public synchronized String getLocale() {
return m_locale;
}
@ -346,7 +347,7 @@ public class CompiereService {
*
* @return M_Warehouse_ID of current request
*/
public int getM_Warehouse_ID() {
public synchronized int getM_Warehouse_ID() {
return m_M_Warehouse_ID;
}
@ -354,43 +355,43 @@ public class CompiereService {
*
* @return logged in user name of current request
*/
public String getUserName() {
public synchronized String getUserName() {
return m_userName;
}
/**
* @return set password
*/
public void setPassword(String pass) {
public synchronized void setPassword(String pass) {
m_password = pass;
}
/**
* @return logged in password of current request
*/
public String getPassword() {
public synchronized String getPassword() {
return m_password;
}
/**
* @return set expiry minutes
*/
public void setExpiryMinutes(int expiryMinutes) {
public synchronized void setExpiryMinutes(int expiryMinutes) {
m_expiryMinutes = expiryMinutes;
}
/**
* @return logged in expiry minutes of current request
*/
public int getExpiryMinutes() {
public synchronized int getExpiryMinutes() {
return m_expiryMinutes;
}
public void refreshLastAuthorizationTime() {
public synchronized void refreshLastAuthorizationTime() {
m_lastAuthorizationTime = System.currentTimeMillis();
}
public void setIPAddress(String remoteAddr) {
public synchronized void setIPAddress(String remoteAddr) {
m_IPAddress = remoteAddr;
}
@ -404,17 +405,17 @@ public class CompiereService {
loginRequest.getPass(),
req.getRemoteAddr());
CompiereService l_cs = null;
if (csMap.containsKey(key)) {
l_cs = csMap.get(key);
if (l_cs != null) {
if (l_cs.isExpired()) {
csMap.remove(key);
ctxMap.remove(key);
l_cs = null;
} else {
Properties cachedCtx = ctxMap.get(key);
Env.getCtx().putAll(cachedCtx);
if (log.isLoggable(Level.INFO)) log.info("Reusing " + l_cs);
synchronized (csMap) {
if (csMap.containsKey(key)) {
l_cs = csMap.get(key);
if (l_cs != null) {
if (l_cs.expungeIfExpire()) {
l_cs = null;
} else {
Properties cachedCtx = ctxMap.get(key);
Env.getCtx().putAll(cachedCtx);
if (log.isLoggable(Level.INFO)) log.info("Reusing " + l_cs);
}
}
}
}
@ -442,19 +443,43 @@ public class CompiereService {
return key.toString();
}
private boolean isExpired() {
private synchronized boolean expungeIfExpire() {
boolean expired =
(
(getExpiryMinutes() <= 0)
|| (m_lastAuthorizationTime + (getExpiryMinutes() * 60000) <= System.currentTimeMillis())
);
if (m_connected && expired)
if (m_connectCount==0 && expired)
{
if (log.isLoggable(Level.INFO)) log.info("Closing expired/invalid " + this);
Env.logout();
ServerContext.dispose();
m_loggedin = false;
m_connected = false;
synchronized (csMap) {
String key = getKey(m_AD_Client_ID,
m_AD_Org_ID,
m_userName,
m_AD_Role_ID,
m_M_Warehouse_ID,
m_locale,
m_password,
m_IPAddress);
if (csMap.containsKey(key)) {
csMap.remove(key);
}
if (ctxMap.containsKey(key)) {
Properties cachedCtx = ctxMap.remove(key);
Properties currentCtx = ServerContext.getCurrentInstance();
try {
ServerContext.setCurrentInstance(cachedCtx);
if (log.isLoggable(Level.INFO)) log.info("Closing expired/invalid " + this);
Env.logout();
} finally {
if (currentCtx == cachedCtx) {
ServerContext.dispose();
} else {
ServerContext.setCurrentInstance(currentCtx);
}
}
}
m_loggedin = false;
}
}
return expired;
}

View File

@ -168,13 +168,9 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
* use the runProcess web service
*/
public StandardResponseDocument setDocAction(ModelSetDocActionRequestDocument req) {
boolean connected = getCompiereService().isConnected();
boolean manageTrx = this.manageTrx;
Trx trx=null;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
StandardResponseDocument ret = StandardResponseDocument.Factory.newInstance();
StandardResponse resp = ret.addNewStandardResponse();
@ -289,9 +285,6 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && !trx.commit())
return rollbackAndSetError(trx, resp, ret, true, "Cannot commit after docAction");
if (manageTrx)
trx.close();
// resp.setError("");
resp.setIsError(false);
@ -304,9 +297,8 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
} finally {
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}
@ -390,11 +382,8 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
public RunProcessResponseDocument runProcess(ModelRunProcessRequestDocument req) {
boolean connected = getCompiereService().isConnected();
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
RunProcessResponseDocument resbadlogin = RunProcessResponseDocument.Factory.newInstance();
RunProcessResponse rbadlogin = resbadlogin.addNewRunProcessResponse();
@ -430,17 +419,13 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
requestCtx.put(serviceType+"_Summary", response.getRunProcessResponse().getSummary());
return response;
} finally {
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}
public WindowTabDataDocument getList(ModelGetListRequestDocument req) {
boolean connected = getCompiereService().isConnected();
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
WindowTabDataDocument resdoc = WindowTabDataDocument.Factory.newInstance();
WindowTabData res = resdoc.addNewWindowTabData();
@ -649,20 +634,14 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
return resdoc;
} finally {
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
} // getList
public StandardResponseDocument deleteData(ModelCRUDRequestDocument req) {
boolean connected = getCompiereService().isConnected();
Trx trx = null;
boolean manageTrx = this.manageTrx;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
StandardResponseDocument ret = StandardResponseDocument.Factory.newInstance();
StandardResponse resp = ret.addNewStandardResponse();
@ -727,8 +706,7 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}
@ -740,15 +718,9 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
}
public StandardResponseDocument createData(ModelCRUDRequestDocument req) {
boolean connected = getCompiereService().isConnected();
Trx trx = null;
boolean manageTrx = this.manageTrx;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
StandardResponseDocument ret = StandardResponseDocument.Factory.newInstance();
StandardResponse resp = ret.addNewStandardResponse();
@ -849,21 +821,15 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
} // createData
public StandardResponseDocument createUpdateData(ModelCRUDRequestDocument req) {
boolean connected = getCompiereService().isConnected();
Trx trx = null;
boolean manageTrx = this.manageTrx;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
StandardResponseDocument ret = StandardResponseDocument.Factory.newInstance();
StandardResponse resp = ret.addNewStandardResponse();
@ -1058,8 +1024,7 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
} // createUpdateData
@ -1234,14 +1199,9 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
}
public StandardResponseDocument updateData(ModelCRUDRequestDocument req){
boolean connected = getCompiereService().isConnected();
Trx trx = null;
boolean manageTrx = this.manageTrx;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
StandardResponseDocument ret = StandardResponseDocument.Factory.newInstance();
StandardResponse resp = ret.addNewStandardResponse();
@ -1323,17 +1283,13 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
} // updateData
public WindowTabDataDocument readData(ModelCRUDRequestDocument req) {
boolean connected = getCompiereService().isConnected();
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
WindowTabDataDocument ret = WindowTabDataDocument.Factory.newInstance();
WindowTabData resp = ret.addNewWindowTabData();
@ -1423,19 +1379,14 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
return ret;
} finally {
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}
public WindowTabDataDocument queryData(ModelCRUDRequestDocument req) {
boolean connected = getCompiereService().isConnected();
boolean manageTrx = this.manageTrx;
Trx trx=null;
try {
if (!connected)
getCompiereService().connect();
getCompiereService().connect();
CompiereService m_cs = getCompiereService();
WindowTabDataDocument ret = WindowTabDataDocument.Factory.newInstance();
@ -1589,8 +1540,7 @@ public class ModelADServiceImpl extends AbstractService implements ModelADServic
if (manageTrx && trx != null)
trx.close();
if (!connected)
getCompiereService().disconnect();
getCompiereService().disconnect();
}
}
}

View File

@ -14,6 +14,8 @@
package org.idempiere.webservices;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
@ -38,8 +40,9 @@ import org.compiere.model.MWebService;
import org.compiere.model.MWebServiceType;
import org.compiere.model.PO;
import org.compiere.model.POInfo;
import org.compiere.model.Query;
import org.compiere.model.X_WS_WebServiceMethod;
import org.compiere.model.X_WS_WebServiceTypeAccess;
import org.compiere.util.CCache;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
@ -64,7 +67,9 @@ import org.idempiere.webservices.fault.IdempiereServiceFault;
*/
public class AbstractService {
private static final String ROLE_ACCESS_SQL = "SELECT IsActive FROM WS_WebServiceTypeAccess WHERE AD_Role_ID=? "
private static final String ROLE_ACCESS_SQL = "SELECT IsActive FROM WS_WebServiceTypeAccess WHERE AD_Role_ID IN ("
+ "SELECT AD_Role_ID FROM AD_Role WHERE AD_Role_ID=? UNION "
+ "SELECT Included_Role_ID as AD_Role_ID FROM AD_Role_Included WHERE AD_Role_ID=?) "
+ "AND WS_WebServiceType_ID=?";
private static final String COMPIERE_SERVICE = "CompiereService";
@Resource
@ -91,6 +96,7 @@ public class AbstractService {
if (cachedCs != null) {
m_cs = cachedCs;
req.setAttribute(COMPIERE_SERVICE, cachedCs);
m_cs.connectCacheInstance();
return authenticate(webService, method, serviceType, cachedCs); // already logged with same data
}
}
@ -201,6 +207,9 @@ public class AbstractService {
return authenticate(webService, method, serviceType, m_cs);
}
private static CCache<String,MWebServiceType> s_WebServiceTypeCache = new CCache<String,MWebServiceType>(MWebServiceType.Table_Name, 10, 60); //60 minutes
private static CCache<String,Boolean> s_RoleAccessCache = new CCache<>(X_WS_WebServiceTypeAccess.Table_Name, 60, 60);
/**
* Authenticate user for requested service type
* @param webServiceValue
@ -219,28 +228,59 @@ public class AbstractService {
if (m_webservicemethod == null || !m_webservicemethod.isActive())
return "Method " + methodValue + " not registered";
MWebServiceType m_webservicetype = new Query(m_cs.getCtx(), MWebServiceType.Table_Name,
"AD_Client_ID IN (0,?) AND WS_WebService_ID=? AND WS_WebServiceMethod_ID=? AND Value=?",
null)
.setOnlyActiveRecords(true)
.setParameters(m_cs.getAD_Client_ID(), m_webservice.getWS_WebService_ID(), m_webservicemethod.getWS_WebServiceMethod_ID(), serviceTypeValue)
.setOrderBy("AD_Client_ID DESC") // IDEMPIERE-3394 give precedence to tenant defined if there are system+tenant
.first();
MWebServiceType m_webservicetype = null;
String key = m_cs.getAD_Client_ID() + "|" + m_webservice.getWS_WebService_ID() + "|"
+ m_webservicemethod.getWS_WebServiceMethod_ID() + "|" + serviceTypeValue;
synchronized (s_WebServiceTypeCache) {
m_webservicetype = s_WebServiceTypeCache.get(key);
if (m_webservicetype == null) {
final String sql = "SELECT * FROM WS_WebServiceType " + "WHERE AD_Client_ID=? " + "AND WS_WebService_ID=? "
+ "AND WS_WebServiceMethod_ID=? " + "AND Value=? " + "AND IsActive='Y'";
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, m_cs.getAD_Client_ID());
pstmt.setInt(2, m_webservice.getWS_WebService_ID());
pstmt.setInt(3, m_webservicemethod.getWS_WebServiceMethod_ID());
pstmt.setString(4, serviceTypeValue);
rs = pstmt.executeQuery();
if (rs.next()) {
m_webservicetype = new MWebServiceType(m_cs.getCtx(), rs, null);
s_WebServiceTypeCache.put(key, m_webservicetype);
}
} catch (Exception e) {
throw new IdempiereServiceFault(e.getClass().toString() + " " + e.getMessage() + " sql=" + sql, e.getCause(), new QName(
"authenticate"));
} finally {
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
}
}
if (m_webservicetype == null)
return "Service type " + serviceTypeValue + " not configured";
getHttpServletRequest().setAttribute("MWebServiceType", m_webservicetype);
// Check if role has access on web-service
String hasAccess = DB.getSQLValueStringEx(null, ROLE_ACCESS_SQL,
Env.getAD_Role_ID( m_cs.getCtx()),
m_webservicetype.get_ID());
if (!"Y".equals(hasAccess))
{
return "Web Service Error: Login role does not have access to the service type";
}
int AD_Role_ID = Env.getAD_Role_ID( m_cs.getCtx());
key = AD_Role_ID + "|" + m_webservicetype.get_ID();
synchronized (s_RoleAccessCache) {
Boolean bAccess = s_RoleAccessCache.get(key);
if (bAccess == null) {
// Check if role has access on web-service
String hasAccess = DB.getSQLValueStringEx(null, ROLE_ACCESS_SQL,
AD_Role_ID, AD_Role_ID, m_webservicetype.get_ID());
bAccess = "Y".equals(hasAccess);
s_RoleAccessCache.put(key, bAccess);
}
if (!bAccess.booleanValue())
{
return "Web Service Error: Login role does not have access to the service type";
}
}
String ret=invokeLoginValidator(null, m_cs.getCtx(), m_webservicetype, IWSValidator.TIMING_ON_AUTHORIZATION);
if(ret!=null && ret.length()>0)