diff --git a/migration/i5.1/oracle/201807240936_IDEMPIERE-3757.sql b/migration/i5.1/oracle/201807240936_IDEMPIERE-3757.sql new file mode 100644 index 0000000000..2e7ba299e2 --- /dev/null +++ b/migration/i5.1/oracle/201807240936_IDEMPIERE-3757.sql @@ -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 +; + diff --git a/migration/i5.1/oracle/201807271000_IDEMPIERE-3762.sql b/migration/i5.1/oracle/201807271000_IDEMPIERE-3762.sql new file mode 100644 index 0000000000..e363a3d44d --- /dev/null +++ b/migration/i5.1/oracle/201807271000_IDEMPIERE-3762.sql @@ -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 +; diff --git a/migration/i5.1/oracle/201808010900_IDEMPIERE-3769.sql b/migration/i5.1/oracle/201808010900_IDEMPIERE-3769.sql new file mode 100644 index 0000000000..87f4f8063d --- /dev/null +++ b/migration/i5.1/oracle/201808010900_IDEMPIERE-3769.sql @@ -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 +; \ No newline at end of file diff --git a/migration/i5.1/oracle/201808071226_IDEMPIERE-2442.sql b/migration/i5.1/oracle/201808071226_IDEMPIERE-2442.sql new file mode 100644 index 0000000000..cd38771a40 --- /dev/null +++ b/migration/i5.1/oracle/201808071226_IDEMPIERE-2442.sql @@ -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 +; + diff --git a/migration/i5.1/postgresql/201807240936_IDEMPIERE-3757.sql b/migration/i5.1/postgresql/201807240936_IDEMPIERE-3757.sql new file mode 100644 index 0000000000..427a6235d3 --- /dev/null +++ b/migration/i5.1/postgresql/201807240936_IDEMPIERE-3757.sql @@ -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 +; + diff --git a/migration/i5.1/postgresql/201807271000_IDEMPIERE-3762.sql b/migration/i5.1/postgresql/201807271000_IDEMPIERE-3762.sql new file mode 100644 index 0000000000..38ffc0168b --- /dev/null +++ b/migration/i5.1/postgresql/201807271000_IDEMPIERE-3762.sql @@ -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 +; diff --git a/migration/i5.1/postgresql/201808010900_IDEMPIERE-3769.sql b/migration/i5.1/postgresql/201808010900_IDEMPIERE-3769.sql new file mode 100644 index 0000000000..80650157a4 --- /dev/null +++ b/migration/i5.1/postgresql/201808010900_IDEMPIERE-3769.sql @@ -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 +; \ No newline at end of file diff --git a/migration/i5.1/postgresql/201808071226_IDEMPIERE-2442.sql b/migration/i5.1/postgresql/201808071226_IDEMPIERE-2442.sql new file mode 100644 index 0000000000..7b4334e166 --- /dev/null +++ b/migration/i5.1/postgresql/201808071226_IDEMPIERE-2442.sql @@ -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 +; + diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java index 9776dff0ef..63a68e61fc 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java @@ -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 ""; diff --git a/org.adempiere.base.process/src/org/compiere/process/ExpenseAPInvoice.java b/org.adempiere.base.process/src/org/compiere/process/ExpenseAPInvoice.java index be286a8349..55b6ebb36b 100644 --- a/org.adempiere.base.process/src/org/compiere/process/ExpenseAPInvoice.java +++ b/org.adempiere.base.process/src/org/compiere/process/ExpenseAPInvoice.java @@ -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"); diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java index a82746bc1a..6780f17807 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java @@ -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 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 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; diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_GLJournal.java b/org.adempiere.base/src/org/compiere/acct/Doc_GLJournal.java index 176aad9013..4400b5e625 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_GLJournal.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_GLJournal.java @@ -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 ()); } diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_MatchPO.java b/org.adempiere.base/src/org/compiere/acct/Doc_MatchPO.java index 0d5475dc11..7580ec3e1c 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_MatchPO.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_MatchPO.java @@ -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()); diff --git a/org.adempiere.base/src/org/compiere/acct/FactLine.java b/org.adempiere.base/src/org/compiere/acct/FactLine.java index 45c2bc6318..45b92d7a51 100644 --- a/org.adempiere.base/src/org/compiere/acct/FactLine.java +++ b/org.adempiere.base/src/org/compiere/acct/FactLine.java @@ -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(); diff --git a/org.adempiere.base/src/org/compiere/model/MBPBankAccount.java b/org.adempiere.base/src/org/compiere/model/MBPBankAccount.java index 5d7cbcb9e8..4a5ea08b21 100644 --- a/org.adempiere.base/src/org/compiere/model/MBPBankAccount.java +++ b/org.adempiere.base/src/org/compiere/model/MBPBankAccount.java @@ -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; } } diff --git a/org.adempiere.base/src/org/compiere/model/MBankAccount.java b/org.adempiere.base/src/org/compiere/model/MBankAccount.java index eac26ff408..9bb98fca78 100644 --- a/org.adempiere.base/src/org/compiere/model/MBankAccount.java +++ b/org.adempiere.base/src/org/compiere/model/MBankAccount.java @@ -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; } } diff --git a/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java b/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java index 9c75155fc9..eddde90d68 100644 --- a/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java +++ b/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java @@ -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); diff --git a/org.adempiere.base/src/org/compiere/model/MJournal.java b/org.adempiere.base/src/org/compiere/model/MJournal.java index 24b00150a0..36d16eeedd 100644 --- a/org.adempiere.base/src/org/compiere/model/MJournal.java +++ b/org.adempiere.base/src/org/compiere/model/MJournal.java @@ -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); diff --git a/org.adempiere.base/src/org/compiere/model/MPayment.java b/org.adempiere.base/src/org/compiere/model/MPayment.java index cd547695e9..33f16025b5 100644 --- a/org.adempiere.base/src/org/compiere/model/MPayment.java +++ b/org.adempiere.base/src/org/compiere/model/MPayment.java @@ -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; } } diff --git a/org.adempiere.base/src/org/compiere/model/MPaymentTransaction.java b/org.adempiere.base/src/org/compiere/model/MPaymentTransaction.java index c367709afa..1cd3bb7a6e 100644 --- a/org.adempiere.base/src/org/compiere/model/MPaymentTransaction.java +++ b/org.adempiere.base/src/org/compiere/model/MPaymentTransaction.java @@ -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; } } diff --git a/org.adempiere.base/src/org/compiere/model/MPeriod.java b/org.adempiere.base/src/org/compiere/model/MPeriod.java index 4119c20286..b518226da9 100644 --- a/org.adempiere.base/src/org/compiere/model/MPeriod.java +++ b/org.adempiere.base/src/org/compiere/model/MPeriod.java @@ -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; diff --git a/org.adempiere.base/src/org/compiere/model/MRequisitionLine.java b/org.adempiere.base/src/org/compiere/model/MRequisitionLine.java index b6449be440..b34eb87010 100644 --- a/org.adempiere.base/src/org/compiere/model/MRequisitionLine.java +++ b/org.adempiere.base/src/org/compiere/model/MRequisitionLine.java @@ -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; } diff --git a/org.adempiere.base/src/org/compiere/util/Env.java b/org.adempiere.base/src/org/compiere/util/Env.java index 6309c53922..09d1ba5a66 100644 --- a/org.adempiere.base/src/org/compiere/util/Env.java +++ b/org.adempiere.base/src/org/compiere/util/Env.java @@ -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 /* diff --git a/org.adempiere.base/src/org/compiere/util/IBAN.java b/org.adempiere.base/src/org/compiere/util/IBAN.java index 3cbb374fc4..212f80b742 100644 --- a/org.adempiere.base/src/org/compiere/util/IBAN.java +++ b/org.adempiere.base/src/org/compiere/util/IBAN.java @@ -26,7 +26,7 @@ public class IBAN { { if (iban!=null) { - return iban.trim().replace(" ", "") ; + return iban.trim().replace(" ", "").toUpperCase() ; } return null ; } diff --git a/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java b/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java index 7482c8be4f..d7c923e764 100644 --- a/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java +++ b/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java @@ -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; } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java index 4c4fe21f15..ae6aa3f3c9 100755 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java @@ -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); } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPayPrint.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPayPrint.java index 89b769bf6f..c67c55cb63 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPayPrint.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPayPrint.java @@ -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 diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WAccountEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WAccountEditor.java index c9aec426d2..2796cd1889 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WAccountEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WAccountEditor.java @@ -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) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java index 064ed7aed5..f5f558cf30 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java @@ -2649,7 +2649,7 @@ public class FindWindow extends Window implements EventListener, 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 **/ diff --git a/org.adempiere.ui.zk/js/ckeditor/config-min.js b/org.adempiere.ui.zk/js/ckeditor/config-min.js index 43eba578da..2f3b8f3a35 100644 --- a/org.adempiere.ui.zk/js/ckeditor/config-min.js +++ b/org.adempiere.ui.zk/js/ckeditor/config-min.js @@ -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' ] }, diff --git a/org.adempiere.ui.zk/js/ckeditor/config.js b/org.adempiere.ui.zk/js/ckeditor/config.js index 4df386cf60..b58eb628f6 100644 --- a/org.adempiere.ui.zk/js/ckeditor/config.js +++ b/org.adempiere.ui.zk/js/ckeditor/config.js @@ -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' ] }, diff --git a/org.idempiere.webservices/WEB-INF/src/com/trekglobal/ws/CompositeServiceImpl.java b/org.idempiere.webservices/WEB-INF/src/com/trekglobal/ws/CompositeServiceImpl.java index c4fc137139..8fce4c19f5 100644 --- a/org.idempiere.webservices/WEB-INF/src/com/trekglobal/ws/CompositeServiceImpl.java +++ b/org.idempiere.webservices/WEB-INF/src/com/trekglobal/ws/CompositeServiceImpl.java @@ -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(); } } diff --git a/org.idempiere.webservices/WEB-INF/src/org/compiere/model/MWebService.java b/org.idempiere.webservices/WEB-INF/src/org/compiere/model/MWebService.java index 2c40dfbc0a..f50feaa996 100644 --- a/org.idempiere.webservices/WEB-INF/src/org/compiere/model/MWebService.java +++ b/org.idempiere.webservices/WEB-INF/src/org/compiere/model/MWebService.java @@ -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; diff --git a/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/CompiereService.java b/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/CompiereService.java index 826b5c6b35..abf161d2c1 100644 --- a/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/CompiereService.java +++ b/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/CompiereService.java @@ -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; } diff --git a/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/ModelADServiceImpl.java b/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/ModelADServiceImpl.java index f672b8ba90..4cbee03b6b 100644 --- a/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/ModelADServiceImpl.java +++ b/org.idempiere.webservices/WEB-INF/src/org/idempiere/adinterface/ModelADServiceImpl.java @@ -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(); } } } \ No newline at end of file diff --git a/org.idempiere.webservices/WEB-INF/src/org/idempiere/webservices/AbstractService.java b/org.idempiere.webservices/WEB-INF/src/org/idempiere/webservices/AbstractService.java index d3ba783cff..c4736a974b 100644 --- a/org.idempiere.webservices/WEB-INF/src/org/idempiere/webservices/AbstractService.java +++ b/org.idempiere.webservices/WEB-INF/src/org/idempiere/webservices/AbstractService.java @@ -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 s_WebServiceTypeCache = new CCache(MWebServiceType.Table_Name, 10, 60); //60 minutes + private static CCache 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)