Author: nmalin
Date: Sat Aug 18 21:23:31 2018
New Revision: 1838349

URL: http://svn.apache.org/viewvc?rev=1838349&view=rev
Log:
Improved: Refactoring ContactMechWorker.get[Entity]ContactMechValueMaps 
function to improve processing speed
(OFBIZ-10514)
ContactMechWorker.get[Entity]ContactMechValueMaps are old historic functions 
that resolve all contact mech context related to an Entity (Party, Facility, 
Order, WorkEffort).
The problem that they create too many db call during their execution that 
decrease OFBiz performance when the contactMech history grow.

A solution use to improve the process speed was replace all db call through 
*GenericValue.getRelated* function by *Delegator.makeValidValue* to instanciate 
each GenericValue needed after an unique search call on a viewEntity. For the 
four entities : Party, Facility, Order and WorkEffort, I use the same view 
structure with a sub view entity on ContactMechDetail. This offer more 
genericity and permit to slim code.

This commit introduce a regression on genericValue resolved for ContactMechType 
and ContactMechPurposeType that currently lost their description, it's actually 
not awkward because theses genericValue use the function .get("description", 
locale) to resolve the description so call directly the label system.

For Order and WorkEffort, I merged the resolving process in one function, that 
can be extend later easily for some other entity like Invoice or Quote.
The new FtpAddress wasn't managed by this worker so I introduce it to keep the 
coherence.

Last improvement, I use 
   getPartyContactMechValueMaps(Delegator delegator, String partyId, Timestamp 
date, String contactMechTypeId) 
instead of
   getPartyContactMechValueMaps(Delegator delegator, String partyId, boolean 
showOld, String contactMechTypeId) 
to offert also more possibility to resolve at date instead just use now or all.

icing on the cake, I added groovy test to control this worker

Added:
    ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/
    
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
   (with props)
Modified:
    
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/order-entitymodel.xml
    
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
    
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/product-entitymodel.xml
    
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
    
ofbiz/ofbiz-framework/trunk/applications/party/testdef/PartyContactMechTests.xml
    
ofbiz/ofbiz-framework/trunk/applications/party/testdef/data/PartyContactMechTestData.xml
    
ofbiz/ofbiz-framework/trunk/applications/workeffort/entitydef/entitymodel_view.xml

Modified: 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/order-entitymodel.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/order-entitymodel.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/order-entitymodel.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/order-entitymodel.xml
 Sat Aug 18 21:23:31 2018
@@ -298,7 +298,38 @@ under the License.
         <key-map field-name="contactMechPurposeTypeId"/>
       </relation>
     </entity>
-    <entity entity-name="OrderContent" 
package-name="org.apache.ofbiz.order.order" title="Order Data Object">
+    <view-entity entity-name="OrderAndContactMech"
+                 package-name="org.apache.ofbiz.order.order"
+                 title="Order Contact Detail View">
+        <member-entity entity-alias="OCM" entity-name="OrderContactMech"/>
+        <member-entity entity-alias="CMD" entity-name="ContactMechDetail"/>
+        <alias-all entity-alias="OCM"/>
+        <alias-all entity-alias="CMD"/>
+        <view-link entity-alias="OCM" rel-entity-alias="CMD">
+          <key-map field-name="contactMechId"/>
+        </view-link>
+        <relation type="many" rel-entity-name="OrderContactMech">
+          <key-map field-name="orderId"/>
+          <key-map field-name="contactMechPurposeTypeId"/>
+          <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="ContactMech">
+          <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="ContactMechPurposeType">
+          <key-map field-name="contactMechPurposeTypeId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="PostalAddress">
+          <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="TelecomNumber">
+          <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="FtpAddress">
+          <key-map field-name="contactMechId"/>
+        </relation>
+    </view-entity>
+  <entity entity-name="OrderContent" 
package-name="org.apache.ofbiz.order.order" title="Order Data Object">
         <field name="orderId" type="id"></field>
         <field name="orderItemSeqId" type="id"></field>
         <field name="contentId" type="id"></field>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
 Sat Aug 18 21:23:31 2018
@@ -1342,6 +1342,7 @@ under the License.
         <member-entity entity-alias="CM" entity-name="ContactMech"/>
         <member-entity entity-alias="PA" entity-name="PostalAddress"/>
         <member-entity entity-alias="TN" entity-name="TelecomNumber"/>
+        <member-entity entity-alias="FA" entity-name="FtpAddress"/>
         <alias-all entity-alias="CM"/>
         <alias-all entity-alias="PA" prefix="pa">
             <exclude field="contactMechId"/>
@@ -1349,36 +1350,32 @@ under the License.
         <alias-all entity-alias="TN" prefix="tn">
             <exclude field="contactMechId"/>
         </alias-all>
+        <alias-all entity-alias="FA" prefix="fa">
+            <exclude field="contactMechId"/>
+        </alias-all>
         <view-link entity-alias="CM" rel-entity-alias="PA" rel-optional="true">
             <key-map field-name="contactMechId"/>
         </view-link>
         <view-link entity-alias="CM" rel-entity-alias="TN" rel-optional="true">
             <key-map field-name="contactMechId"/>
         </view-link>
+        <view-link entity-alias="CM" rel-entity-alias="FA" rel-optional="true">
+            <key-map field-name="contactMechId"/>
+        </view-link>
     </view-entity>
     <view-entity entity-name="PartyAndContactMech"
         package-name="org.apache.ofbiz.party.contact"
         title="Party and Contact Mech View">
         <member-entity entity-alias="PTY" entity-name="Party"/>
         <member-entity entity-alias="PCM" entity-name="PartyContactMech"/>
-        <member-entity entity-alias="CM" entity-name="ContactMech"/>
-        <member-entity entity-alias="PA" entity-name="PostalAddress"/>
-        <member-entity entity-alias="TN" entity-name="TelecomNumber"/>
+        <member-entity entity-alias="CMD" entity-name="ContactMechDetail"/>
         <alias-all entity-alias="PTY"/>
         <alias-all entity-alias="PCM"/>
-        <alias-all entity-alias="CM"/>
-        <alias-all entity-alias="PA" prefix="pa"/>
-        <alias-all entity-alias="TN" prefix="tn"/>
+        <alias-all entity-alias="CMD"/>
         <view-link entity-alias="PTY" rel-entity-alias="PCM">
             <key-map field-name="partyId"/>
         </view-link>
-        <view-link entity-alias="PCM" rel-entity-alias="CM">
-            <key-map field-name="contactMechId"/>
-        </view-link>
-        <view-link entity-alias="PCM" rel-entity-alias="PA" 
rel-optional="true">
-            <key-map field-name="contactMechId"/>
-        </view-link>
-        <view-link entity-alias="PCM" rel-entity-alias="TN" 
rel-optional="true">
+        <view-link entity-alias="PCM" rel-entity-alias="CMD">
             <key-map field-name="contactMechId"/>
         </view-link>
         <relation type="many" rel-entity-name="PartyContactMech">
@@ -1397,6 +1394,9 @@ under the License.
         <relation type="one-nofk" rel-entity-name="TelecomNumber">
             <key-map field-name="contactMechId"/>
         </relation>
+        <relation type="one-nofk" rel-entity-name="FtpAddress">
+            <key-map field-name="contactMechId"/>
+        </relation>
     </view-entity>
     <view-entity entity-name="PartyAndPostalAddress"
         package-name="org.apache.ofbiz.party.contact"

Modified: 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/product-entitymodel.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/product-entitymodel.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/product-entitymodel.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/product-entitymodel.xml
 Sat Aug 18 21:23:31 2018
@@ -1048,17 +1048,36 @@ under the License.
     </entity>
     <view-entity entity-name="FacilityAndContactMech" 
package-name="org.apache.ofbiz.product.facility" title="Facility and Contact 
Mech View">
         <member-entity entity-alias="FA" entity-name="Facility"/>
-        <member-entity entity-alias="CM" entity-name="FacilityContactMech"/>
-        <member-entity entity-alias="MC" entity-name="ContactMech"/>
+        <member-entity entity-alias="FCM" entity-name="FacilityContactMech"/>
+        <member-entity entity-alias="CMD" entity-name="ContactMechDetail"/>
         <alias-all entity-alias="FA"/>
-        <alias-all entity-alias="CM"/>
-        <alias-all entity-alias="MC"/>
-        <view-link entity-alias="FA" rel-entity-alias="CM">
+        <alias-all entity-alias="FCM"/>
+        <alias-all entity-alias="CMD"/>
+        <view-link entity-alias="FA" rel-entity-alias="FCM">
             <key-map field-name="facilityId"/>
         </view-link>
-        <view-link entity-alias="CM" rel-entity-alias="MC">
+        <view-link entity-alias="FCM" rel-entity-alias="CMD">
             <key-map field-name="contactMechId"/>
         </view-link>
+        <relation type="many" rel-entity-name="FacilityContactMech">
+            <key-map field-name="partyId"/>
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="Facility">
+            <key-map field-name="facilityId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="ContactMech">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="PostalAddress">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="TelecomNumber">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="FtpAddress">
+            <key-map field-name="contactMechId"/>
+        </relation>
     </view-entity>
     <entity entity-name="FacilityAttribute" 
package-name="org.apache.ofbiz.product.facility" title="Facility Attribute">
         <field name="facilityId" type="id"></field>

Added: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy?rev=1838349&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
 Sat Aug 18 21:23:31 2018
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ 
*******************************************************************************/
+
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.party.contact.ContactMechWorker
+import org.apache.ofbiz.testtools.GroovyScriptTestCase
+
+class ContactMechWorkerTests extends GroovyScriptTestCase {
+
+    void testPartyContactMechResolution() {
+        //control for the DemoCustomer that postal, email, telecom and ftp 
contact are present and return correct information
+        List partyContactMechValueMaps = 
ContactMechWorker.getPartyContactMechValueMaps(delegator, "DemoCustomer", true)
+        assert partyContactMechValueMaps
+        assert partyContactMechValueMaps.size() == 7
+        boolean foundPostalAddress, foundTelecom, foundEmailAddress, 
foundFtpAddress = false
+        partyContactMechValueMaps.forEach {
+            Map partyContactMechValueMap ->
+                switch (partyContactMechValueMap?.contactMech?.contactMechId) {
+                    case '9015':
+                        foundPostalAddress = true
+                        assert 
partyContactMechValueMap.contactMech.contactMechTypeId == 'POSTAL_ADDRESS'
+                        assert partyContactMechValueMap.partyContactMech
+                        assert partyContactMechValueMap.contactMechType
+                        assert 
partyContactMechValueMap.partyContactMechPurposes
+                        assert 
partyContactMechValueMap.partyContactMechPurposes.size() == 3
+                        assert partyContactMechValueMap.postalAddress
+                        assert 
partyContactMechValueMap.postalAddress.contactMechId == '9015'
+                        assert partyContactMechValueMap.postalAddress.address1 
== '2004 Factory Blvd'
+                        break
+                    case '9027':
+                        foundTelecom = true
+                        assert 
partyContactMechValueMap.contactMech.contactMechTypeId == 'TELECOM_NUMBER'
+                        assert partyContactMechValueMap.partyContactMech
+                        assert partyContactMechValueMap.contactMechType
+                        assert 
partyContactMechValueMap.partyContactMechPurposes
+                        assert 
partyContactMechValueMap.partyContactMechPurposes.size() == 1
+                        assert partyContactMechValueMap.telecomNumber
+                        assert 
partyContactMechValueMap.telecomNumber.contactMechId == '9027'
+                        assert 
partyContactMechValueMap.telecomNumber.contactNumber == '444-4444'
+                        break
+                    case '9126':
+                        foundEmailAddress = true
+                        assert 
partyContactMechValueMap.contactMech.contactMechTypeId == 'EMAIL_ADDRESS'
+                        assert partyContactMechValueMap.contactMech.infoString 
== '[email protected]'
+                        assert partyContactMechValueMap.partyContactMech
+                        assert partyContactMechValueMap.contactMechType
+                        assert 
partyContactMechValueMap.partyContactMechPurposes
+                        assert 
partyContactMechValueMap.partyContactMechPurposes.size() == 2
+                        break
+                    case '9127':
+                        foundFtpAddress = true
+                        assert 
partyContactMechValueMap.contactMech.contactMechTypeId == 'FTP_ADDRESS'
+                        assert partyContactMechValueMap.partyContactMech
+                        assert partyContactMechValueMap.contactMechType
+                        assert 
!partyContactMechValueMap.partyContactMechPurposes
+                        assert partyContactMechValueMap.ftpAddress
+                        assert partyContactMechValueMap.ftpAddress.hostname == 
"ftp://apacheofbiz.foo.com";
+                        break
+                }
+        }
+        assert foundPostalAddress && foundTelecom && foundEmailAddress && 
foundFtpAddress
+
+        //Restart a search at now, the email 9126 need to have only one purpose
+        partyContactMechValueMaps = 
ContactMechWorker.getPartyContactMechValueMaps(delegator, "DemoCustomer", 
false, "EMAIL_ADDRESS")
+        partyContactMechValueMaps.forEach {
+            Map partyContactMechValueMap ->
+                switch (partyContactMechValueMap?.contactMech?.contactMechId) {
+                    case '9126':
+                        assert 
partyContactMechValueMap.partyContactMechPurposes.size() == 1
+                        break
+                }
+        }
+
+        //Restart a search at 05/13/2001 10:00:00.000, the email 9126 need to 
have two purposes
+        partyContactMechValueMaps = 
ContactMechWorker.getPartyContactMechValueMaps(delegator, "DemoCustomer", 
UtilDateTime.toTimestamp("05/13/2001 10:00:00.000"), "EMAIL_ADDRESS")
+        partyContactMechValueMaps.forEach {
+            Map partyContactMechValueMap ->
+                switch (partyContactMechValueMap?.contactMech?.contactMechId) {
+                    case '9126':
+                        assert 
partyContactMechValueMap.partyContactMechPurposes.size() == 2
+                        break
+                }
+        }
+    }
+
+    void testOrderContactMechResolution() {
+        List orderContactMechValueMaps = 
ContactMechWorker.getOrderContactMechValueMaps(delegator, "Demo1002")
+        assert orderContactMechValueMaps
+        assert orderContactMechValueMaps.size() == 3
+
+        boolean foundBillingAddress, foundShippingAddress, foundOrderEmail = 
false
+        orderContactMechValueMaps.forEach {
+            Map orderContactMechValueMap ->
+                switch (orderContactMechValueMap.contactMech?.contactMechId) {
+                    case '9015':
+                        assert 
orderContactMechValueMap.contactMech.contactMechTypeId == 'POSTAL_ADDRESS'
+                        assert orderContactMechValueMap.contactMechType
+                        assert orderContactMechValueMap.contactMechPurposeType
+                        assert orderContactMechValueMap.orderContactMech
+                        assert orderContactMechValueMap.postalAddress
+                        assert 
orderContactMechValueMap.postalAddress.contactMechId == '9015'
+                        assert orderContactMechValueMap.postalAddress.address1 
== '2004 Factory Blvd'
+                        foundBillingAddress = foundBillingAddress?: 
orderContactMechValueMap.contactMechPurposeType.contactMechPurposeTypeId == 
'BILLING_LOCATION'
+                        foundShippingAddress = foundShippingAddress?: 
orderContactMechValueMap.contactMechPurposeType.contactMechPurposeTypeId == 
'SHIPPING_LOCATION'
+                        break
+                    case '9026':
+                        assert 
orderContactMechValueMap.contactMech.contactMechTypeId == 'EMAIL_ADDRESS'
+                        assert orderContactMechValueMap.contactMech.infoString 
== '[email protected]'
+                        assert orderContactMechValueMap.orderContactMech
+                        assert orderContactMechValueMap.contactMechType
+                        foundOrderEmail = 
orderContactMechValueMap.contactMechPurposeType.contactMechPurposeTypeId == 
'ORDER_EMAIL'
+                        break
+                    default:
+                        assert false
+                        break
+                }
+        }
+        assert foundBillingAddress && foundShippingAddress && foundOrderEmail
+    }
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/test/ContactMechWorkerTests.groovy
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
 Sat Aug 18 21:23:31 2018
@@ -21,6 +21,8 @@ package org.apache.ofbiz.party.contact;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.sql.Timestamp;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -33,12 +35,16 @@ import javax.servlet.ServletRequest;
 
 import org.apache.ofbiz.base.util.Assert;
 import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilDateTime;
+import org.apache.ofbiz.base.util.UtilGenerics;
 import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.entity.condition.EntityCondition;
+import org.apache.ofbiz.entity.condition.EntityOperator;
+import org.apache.ofbiz.entity.model.ModelUtil;
 import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.entity.util.EntityUtil;
 import org.apache.ofbiz.entity.util.EntityUtilProperties;
@@ -52,281 +58,199 @@ public class ContactMechWorker {
 
     private ContactMechWorker() {}
 
+    /**
+     * Check the contactMechTypeId value on toAnalyzeFields map and if is a 
PostalAddress, a TelecomNumber or FtpAddress
+     * add the GenericValue related to elementMap
+     * @param delegator
+     * @param elementMap
+     */
+    private static void insertRelatedContactElement(Delegator delegator, 
Map<String, Object> elementMap, Map<String, Object> fields) {
+        String contactMechTypeId = (String) fields.get("contactMechTypeId");
+        String entityName = null;
+        String prefix = null;
+        switch (contactMechTypeId) {
+            case "POSTAL_ADDRESS":
+                entityName = "PostalAddress";
+                prefix = "pa";
+                break;
+            case "TELECOM_NUMBER":
+                entityName = "TelecomNumber";
+                prefix = "tn";
+                break;
+            case "FTP_ADDRESS":
+                entityName = "FtpAddress";
+                prefix = "fa";
+                break;
+        }
+        if (entityName != null) {
+            GenericValue element = delegator.makeValue(entityName);
+            element.setAllFields(fields, false, prefix, null);
+            element.set("contactMechId", fields.get("contactMechId"));
+            elementMap.put(ModelUtil.lowerFirstChar(entityName), element);
+        }
+    }
+
     public static List<Map<String, Object>> 
getPartyContactMechValueMaps(Delegator delegator, String partyId, boolean 
showOld) {
        return getPartyContactMechValueMaps(delegator, partyId, showOld, null);
     }
-
     public static List<Map<String, Object>> 
getPartyContactMechValueMaps(Delegator delegator, String partyId, boolean 
showOld, String contactMechTypeId) {
-        List<Map<String, Object>> partyContactMechValueMaps = new 
LinkedList<>();
+        Timestamp date = showOld? null: UtilDateTime.nowTimestamp();
+        return getPartyContactMechValueMaps(delegator, partyId, date, 
contactMechTypeId);
+    }
+    public static List<Map<String, Object>> 
getPartyContactMechValueMaps(Delegator delegator, String partyId, Timestamp 
date, String contactMechTypeId) {
+        List<Map<String, Object>> partyContactMechValueMaps = new 
ArrayList<>();
 
         List<GenericValue> allPartyContactMechs = null;
+        List<EntityCondition> conditionList = 
UtilMisc.toList(EntityCondition.makeCondition("partyId", partyId));
+        if (contactMechTypeId != null) 
conditionList.add(EntityCondition.makeCondition("contactMechTypeId", 
contactMechTypeId));
 
+        //Resolve all
         try {
-            List<GenericValue> tempCol = 
EntityQuery.use(delegator).from("PartyContactMech").where("partyId", 
partyId).queryList();
-            if (contactMechTypeId != null) {
-                List<GenericValue> tempColTemp = new LinkedList<>();
-                for (GenericValue partyContactMech: tempCol) {
-                    GenericValue contactMech = 
delegator.getRelatedOne("ContactMech", partyContactMech, false);
-                    if (contactMech != null && 
contactMechTypeId.equals(contactMech.getString("contactMechTypeId"))) {
-                        tempColTemp.add(partyContactMech);
-                    }
-
-                }
-                tempCol = tempColTemp;
-            }
-            if (!showOld) {
-                tempCol = EntityUtil.filterByDate(tempCol, true);
-            }
-            allPartyContactMechs = tempCol;
+            allPartyContactMechs = EntityQuery.use(delegator)
+                    .from("PartyAndContactMech")
+                    .where(conditionList)
+                    .filterByDate(date)
+                    .cache()
+                    .queryList();
         } catch (GenericEntityException e) {
             Debug.logWarning(e, module);
         }
 
-        if (allPartyContactMechs == null) {
+        if (UtilValidate.isEmpty(allPartyContactMechs)) {
             return partyContactMechValueMaps;
         }
+        List<String> contactMechIds = 
EntityUtil.getFieldListFromEntityList(allPartyContactMechs, "contactMechId", 
true);
+        conditionList = UtilMisc.toList(
+                EntityCondition.makeCondition("partyId", partyId),
+                EntityCondition.makeCondition("contactMechId", 
EntityOperator.IN, contactMechIds));
+        List<GenericValue> allPartyContactMechPurposes = null;
+        try {
+            allPartyContactMechPurposes = EntityQuery.use(delegator)
+                    .from("PartyContactMechPurpose")
+                    .where(conditionList)
+                    .filterByDate(date)
+                    .cache()
+                    .queryList();
+        } catch (GenericEntityException e) {
+            Debug.logWarning(e, module);
+        }
 
         for (GenericValue partyContactMech: allPartyContactMechs) {
-            GenericValue contactMech = null;
+            Map<String, Object> fields = partyContactMech.getAllFields();
 
-            try {
-                contactMech = partyContactMech.getRelatedOne("ContactMech", 
false);
-            } catch (GenericEntityException e) {
-                Debug.logWarning(e, module);
-            }
-            if (contactMech != null) {
-                Map<String, Object> partyContactMechValueMap = new HashMap<>();
-
-                partyContactMechValueMaps.add(partyContactMechValueMap);
-                partyContactMechValueMap.put("contactMech", contactMech);
-                partyContactMechValueMap.put("partyContactMech", 
partyContactMech);
-
-                try {
-                    partyContactMechValueMap.put("contactMechType", 
contactMech.getRelatedOne("ContactMechType", true));
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    List<GenericValue> partyContactMechPurposes = 
partyContactMech.getRelated("PartyContactMechPurpose", null, null, false);
-
-                    if (!showOld) {
-                        partyContactMechPurposes = 
EntityUtil.filterByDate(partyContactMechPurposes, true);
-                    }
-                    partyContactMechValueMap.put("partyContactMechPurposes", 
partyContactMechPurposes);
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    if 
("POSTAL_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
-                        partyContactMechValueMap.put("postalAddress", 
contactMech.getRelatedOne("PostalAddress", false));
-                    } else if 
("TELECOM_NUMBER".equals(contactMech.getString("contactMechTypeId"))) {
-                        partyContactMechValueMap.put("telecomNumber", 
contactMech.getRelatedOne("TelecomNumber", false));
-                    } else if 
("FTP_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
-                        partyContactMechValueMap.put("ftpAddress", 
contactMech.getRelatedOne("FtpAddress", false));
-                    }
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-            }
+            Map<String, Object> partyContactMechValueMap = new HashMap<>();
+            partyContactMechValueMaps.add(partyContactMechValueMap);
+            partyContactMechValueMap.put("contactMech", 
delegator.makeValidValue("ContactMech", fields));
+            partyContactMechValueMap.put("contactMechType", 
delegator.makeValidValue("ContactMechType", fields));
+            partyContactMechValueMap.put("partyContactMech", 
delegator.makeValidValue("PartyContactMech", fields));
+
+            ContactMechWorker.insertRelatedContactElement(delegator, 
partyContactMechValueMap, fields);
+            List<GenericValue> partyContactMechPurposes = 
EntityUtil.filterByAnd(allPartyContactMechPurposes, 
UtilMisc.toMap("contactMechId", partyContactMech.getString("contactMechId")));
+            partyContactMechValueMap.put("partyContactMechPurposes", 
partyContactMechPurposes);
         }
 
         return partyContactMechValueMaps;
     }
 
+    public static List<Map<String, Object>> 
getFacilityContactMechValueMaps(Delegator delegator, String facilityId, boolean 
showOld) {
+       return getFacilityContactMechValueMaps(delegator, facilityId, showOld, 
null);
+    }
     public static List<Map<String, Object>> 
getFacilityContactMechValueMaps(Delegator delegator, String facilityId, boolean 
showOld, String contactMechTypeId) {
-        List<Map<String, Object>> facilityContactMechValueMaps = new 
LinkedList<>();
+        Timestamp date = showOld? UtilDateTime.nowTimestamp(): null;
+        return getFacilityContactMechValueMaps(delegator, facilityId, date, 
contactMechTypeId);
+    }
+    public static List<Map<String, Object>> 
getFacilityContactMechValueMaps(Delegator delegator, String facilityId, 
Timestamp date, String contactMechTypeId) {
+        List<Map<String, Object>> facilityContactMechValueMaps = new 
ArrayList<>();
 
         List<GenericValue> allFacilityContactMechs = null;
+        List<EntityCondition> conditionList = 
UtilMisc.toList(EntityCondition.makeCondition("facilityId", facilityId));
+        if (contactMechTypeId != null) 
conditionList.add(EntityCondition.makeCondition("contactMechTypeId", 
contactMechTypeId));
 
+        //Resolve all
         try {
-            List<GenericValue> tempCol = 
EntityQuery.use(delegator).from("FacilityContactMech").where("facilityId", 
facilityId).queryList();
-            if (contactMechTypeId != null) {
-                List<GenericValue> tempColTemp = new LinkedList<>();
-                for (GenericValue partyContactMech: tempCol) {
-                    GenericValue contactMech = 
delegator.getRelatedOne("ContactMech", partyContactMech, false);
-                    if (contactMech != null && 
contactMechTypeId.equals(contactMech.getString("contactMechTypeId"))) {
-                        tempColTemp.add(partyContactMech);
-                    }
-
-                }
-                tempCol = tempColTemp;
-            }
-            if (!showOld) {
-                tempCol = EntityUtil.filterByDate(tempCol, true);
-            }
-            allFacilityContactMechs = tempCol;
+            allFacilityContactMechs = EntityQuery.use(delegator)
+                    .from("FacilityAndContactMech")
+                    .where(conditionList)
+                    .filterByDate(date)
+                    .cache()
+                    .queryList();
         } catch (GenericEntityException e) {
             Debug.logWarning(e, module);
         }
 
-        if (allFacilityContactMechs == null) {
+        if (UtilValidate.isEmpty(allFacilityContactMechs)) {
             return facilityContactMechValueMaps;
         }
+        List<String> contactMechIds = 
EntityUtil.getFieldListFromEntityList(allFacilityContactMechs, "contactMechId", 
true);
+        conditionList = UtilMisc.toList(
+                EntityCondition.makeCondition("facilityId", facilityId),
+                EntityCondition.makeCondition("contactMechId", 
EntityOperator.IN, contactMechIds));
+        List<GenericValue> allFacilityContactMechPurposes = null;
+        try {
+            allFacilityContactMechPurposes = 
EntityQuery.use(delegator).from("FacilityContactMechPurpose").where(conditionList).filterByDate(date).cache().queryList();
+        } catch (GenericEntityException e) {
+            Debug.logWarning(e, module);
+        }
 
         for (GenericValue facilityContactMech: allFacilityContactMechs) {
-            GenericValue contactMech = null;
+            Map<String, Object> fields = facilityContactMech.getAllFields();
 
-            try {
-                contactMech = facilityContactMech.getRelatedOne("ContactMech", 
false);
-            } catch (GenericEntityException e) {
-                Debug.logWarning(e, module);
-            }
-            if (contactMech != null) {
-                Map<String, Object> facilityContactMechValueMap = new 
HashMap<>();
-
-                facilityContactMechValueMaps.add(facilityContactMechValueMap);
-                facilityContactMechValueMap.put("contactMech", contactMech);
-                facilityContactMechValueMap.put("facilityContactMech", 
facilityContactMech);
-
-                try {
-                    facilityContactMechValueMap.put("contactMechType", 
contactMech.getRelatedOne("ContactMechType", true));
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    List<GenericValue> facilityContactMechPurposes = 
facilityContactMech.getRelated("FacilityContactMechPurpose", null, null, false);
-
-                    if (!showOld) {
-                        facilityContactMechPurposes = 
EntityUtil.filterByDate(facilityContactMechPurposes, true);
-                    }
-                    
facilityContactMechValueMap.put("facilityContactMechPurposes", 
facilityContactMechPurposes);
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    if 
("POSTAL_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
-                        facilityContactMechValueMap.put("postalAddress", 
contactMech.getRelatedOne("PostalAddress", false));
-                    } else if 
("TELECOM_NUMBER".equals(contactMech.getString("contactMechTypeId"))) {
-                        facilityContactMechValueMap.put("telecomNumber", 
contactMech.getRelatedOne("TelecomNumber", false));
-                    }
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-            }
+            Map<String, Object> facilityContactMechValueMap = new HashMap<>();
+            facilityContactMechValueMaps.add(facilityContactMechValueMap);
+            facilityContactMechValueMap.put("contactMech", 
delegator.makeValidValue("ContactMech", fields));
+            facilityContactMechValueMap.put("contactMechType", 
delegator.makeValidValue("ContactMechType", fields));
+            facilityContactMechValueMap.put("facilityContactMech", 
delegator.makeValidValue("FacilityContactMech", fields));
+
+            ContactMechWorker.insertRelatedContactElement(delegator, 
facilityContactMechValueMap, fields);
+            List<GenericValue> facilityContactMechPurposes = 
EntityUtil.filterByAnd(allFacilityContactMechPurposes, 
UtilMisc.toMap("contactMechId", 
facilityContactMech.getString("contactMechId")));
+            facilityContactMechValueMap.put("facilityContactMechPurposes", 
facilityContactMechPurposes);
         }
 
         return facilityContactMechValueMaps;
     }
 
-
     public static List<Map<String, GenericValue>> 
getOrderContactMechValueMaps(Delegator delegator, String orderId) {
-        List<Map<String, GenericValue>> orderContactMechValueMaps = new 
LinkedList<>();
-
-        List<GenericValue> allOrderContactMechs = null;
-
-        try {
-            allOrderContactMechs = 
EntityQuery.use(delegator).from("OrderContactMech")
-                    .where("orderId", orderId)
-                    .orderBy("contactMechPurposeTypeId")
-                    .queryList();
-        } catch (GenericEntityException e) {
-            Debug.logWarning(e, module);
-        }
-
-        if (allOrderContactMechs == null) {
-            return orderContactMechValueMaps;
-        }
-
-        for (GenericValue orderContactMech: allOrderContactMechs) {
-            GenericValue contactMech = null;
-
-            try {
-                contactMech = orderContactMech.getRelatedOne("ContactMech", 
false);
-            } catch (GenericEntityException e) {
-                Debug.logWarning(e, module);
-            }
-            if (contactMech != null) {
-                Map<String, GenericValue> orderContactMechValueMap = new 
HashMap<>();
-
-                orderContactMechValueMaps.add(orderContactMechValueMap);
-                orderContactMechValueMap.put("contactMech", contactMech);
-                orderContactMechValueMap.put("orderContactMech", 
orderContactMech);
-
-                try {
-                    orderContactMechValueMap.put("contactMechType", 
contactMech.getRelatedOne("ContactMechType", true));
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    GenericValue contactMechPurposeType = 
orderContactMech.getRelatedOne("ContactMechPurposeType", false);
-
-                    orderContactMechValueMap.put("contactMechPurposeType", 
contactMechPurposeType);
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    if 
("POSTAL_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
-                        orderContactMechValueMap.put("postalAddress", 
contactMech.getRelatedOne("PostalAddress", false));
-                    } else if 
("TELECOM_NUMBER".equals(contactMech.getString("contactMechTypeId"))) {
-                        orderContactMechValueMap.put("telecomNumber", 
contactMech.getRelatedOne("TelecomNumber", false));
-                    }
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-            }
-        }
-
-        return orderContactMechValueMaps;
+        return getEntityContactMechValueMaps(delegator, "Order", orderId, 
null);
     }
 
     public static Collection<Map<String, GenericValue>> 
getWorkEffortContactMechValueMaps(Delegator delegator, String workEffortId) {
-        Collection<Map<String, GenericValue>> workEffortContactMechValueMaps = 
new LinkedList<>();
+        Collection<Map<String, GenericValue>> workEffortContactMechValueMaps = 
getEntityContactMechValueMaps(delegator, "WorkEffort", workEffortId, 
UtilDateTime.nowTimestamp());
+        return UtilValidate.isNotEmpty(workEffortContactMechValueMaps) ? 
workEffortContactMechValueMaps : null;
+    }
 
-        List<GenericValue> allWorkEffortContactMechs = null;
+    private static List<Map<String, GenericValue>> 
getEntityContactMechValueMaps(Delegator delegator, String entityName, String 
entityId, Timestamp date) {
+        List<Map<String, GenericValue>> entityContactMechValueMaps = new 
LinkedList<>();
+        String downCaseEntityName = ModelUtil.lowerFirstChar(entityName);
+
+        List<GenericValue> allEntityContactMechs = null;
 
         try {
-            allWorkEffortContactMechs = 
EntityQuery.use(delegator).from("WorkEffortContactMech")
-                    .where("workEffortId", workEffortId)
-                    .filterByDate()
+            allEntityContactMechs = EntityQuery.use(delegator).from(entityName 
+ "AndContactMech")
+                    .where(downCaseEntityName + "Id", entityId)
+                    .orderBy("contactMechPurposeTypeId")
+                    .filterByDate(date)
                     .queryList();
         } catch (GenericEntityException e) {
             Debug.logWarning(e, module);
         }
 
-        if (allWorkEffortContactMechs == null) {
-            return null;
+        if (allEntityContactMechs == null) {
+            return entityContactMechValueMaps;
         }
 
-        for (GenericValue workEffortContactMech: allWorkEffortContactMechs) {
-            GenericValue contactMech = null;
+        for (GenericValue entityContactMech: allEntityContactMechs) {
+            Map<String, Object> fields = entityContactMech.getAllFields();
+            Map<String, GenericValue> entityContactMechValueMap = new 
HashMap<>();
 
-            try {
-                contactMech = 
workEffortContactMech.getRelatedOne("ContactMech", false);
-            } catch (GenericEntityException e) {
-                Debug.logWarning(e, module);
-            }
-            if (contactMech != null) {
-                Map<String, GenericValue> workEffortContactMechValueMap = new 
HashMap<>();
-
-                
workEffortContactMechValueMaps.add(workEffortContactMechValueMap);
-                workEffortContactMechValueMap.put("contactMech", contactMech);
-                workEffortContactMechValueMap.put("workEffortContactMech", 
workEffortContactMech);
-
-                try {
-                    workEffortContactMechValueMap.put("contactMechType", 
contactMech.getRelatedOne("ContactMechType", true));
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-
-                try {
-                    if 
("POSTAL_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
-                        workEffortContactMechValueMap.put("postalAddress", 
contactMech.getRelatedOne("PostalAddress", false));
-                    } else if 
("TELECOM_NUMBER".equals(contactMech.getString("contactMechTypeId"))) {
-                        workEffortContactMechValueMap.put("telecomNumber", 
contactMech.getRelatedOne("TelecomNumber", false));
-                    }
-                } catch (GenericEntityException e) {
-                    Debug.logWarning(e, module);
-                }
-            }
+            entityContactMechValueMaps.add(entityContactMechValueMap);
+            entityContactMechValueMap.put("contactMech", 
delegator.makeValidValue("ContactMech", fields));
+            entityContactMechValueMap.put(downCaseEntityName + "ContactMech", 
delegator.makeValidValue(entityName + "ContactMech", fields));
+            entityContactMechValueMap.put("contactMechType", 
delegator.makeValidValue("ContactMechType",fields));
+            entityContactMechValueMap.put("contactMechPurposeType", 
delegator.makeValidValue("ContactMechPurposeType", fields));
+            insertRelatedContactElement(delegator, 
UtilGenerics.checkMap(entityContactMechValueMap), fields);
         }
 
-        return workEffortContactMechValueMaps.size() > 0 ? 
workEffortContactMechValueMaps : null;
+        return entityContactMechValueMaps;
     }
 
     public static void getContactMechAndRelated(ServletRequest request, String 
partyId, Map<String, Object> target) {

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/PartyContactMechTests.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/testdef/PartyContactMechTests.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/PartyContactMechTests.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/PartyContactMechTests.xml
 Sat Aug 18 21:23:31 2018
@@ -24,9 +24,12 @@
     <test-case case-name="loadPartyContactMechTestData">
         <entity-xml action="load" 
entity-xml-url="component://party/testdef/data/PartyContactMechTestData.xml"/>
     </test-case>
-
+    <test-case case-name="ContactMechWorker-tests">
+        <groovy-test-suite name="contactMechWorker" 
location="component://party/groovyScripts/test/ContactMechWorkerTests.groovy"/>
+    </test-case>
     <test-case case-name="partyContactMech-tests">
         <simple-method-test 
location="component://party/minilang/test/PartyContactMechTests.xml"/>
     </test-case>
 
+
 </test-suite>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/data/PartyContactMechTestData.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/testdef/data/PartyContactMechTestData.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/data/PartyContactMechTestData.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/testdef/data/PartyContactMechTestData.xml
 Sat Aug 18 21:23:31 2018
@@ -27,4 +27,9 @@ under the License.
     <ContactMech contactMechId="9126" contactMechTypeId="EMAIL_ADDRESS" 
infoString="[email protected]"/>
     <PartyContactMech partyId="DemoCustomer" contactMechId="9126" 
fromDate="2001-05-13 00:00:00.000" allowSolicitation="Y"/>
     <PartyContactMechPurpose partyId="DemoCustomer" contactMechId="9126" 
contactMechPurposeTypeId="PRIMARY_EMAIL" fromDate="2001-05-13 00:00:00.000"/>
+    <PartyContactMechPurpose partyId="DemoCustomer" contactMechId="9126" 
contactMechPurposeTypeId="BILLING_EMAIL" fromDate="2001-05-13 00:00:00.000" 
thruDate="2001-05-14 00:00:00.000"/>
+
+    <ContactMech contactMechId="9127" contactMechTypeId="FTP_ADDRESS"/>
+    <FtpAddress contactMechId="9127" hostname="ftp://apacheofbiz.foo.com"; 
port="" username="ofbiz" password="apache" binaryTransfer="Y" passiveMode="Y" 
path="public"/>
+    <PartyContactMech partyId="DemoCustomer" contactMechId="9127" 
fromDate="2001-05-13 00:00:00.000" allowSolicitation="Y"/>
 </entity-engine-xml>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/workeffort/entitydef/entitymodel_view.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/workeffort/entitydef/entitymodel_view.xml?rev=1838349&r1=1838348&r2=1838349&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/workeffort/entitydef/entitymodel_view.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/workeffort/entitydef/entitymodel_view.xml
 Sat Aug 18 21:23:31 2018
@@ -940,6 +940,37 @@ under the License.
             <key-map field-name="contactMechId"/>
         </view-link>
     </view-entity>
+    <view-entity entity-name="WorkEffortAndContactMech"
+                                   
package-name="org.apache.ofbiz.workeffort.workeffort"
+                 title="Order Contact Detail View">
+        <member-entity entity-alias="WCM" entity-name="WorkEffortContactMech"/>
+        <member-entity entity-alias="CMD" entity-name="ContactMechDetail"/>
+        <alias-all entity-alias="WCM"/>
+        <alias-all entity-alias="CMD"/>
+        <view-link entity-alias="WCM" rel-entity-alias="CMD">
+            <key-map field-name="contactMechId"/>
+        </view-link>
+        <relation type="many" rel-entity-name="WorkEffortContactMech">
+            <key-map field-name="workEffortId"/>
+            <key-map field-name="contactMechPurposeTypeId"/>
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="ContactMech">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="ContactMechPurposeType">
+            <key-map field-name="contactMechPurposeTypeId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="PostalAddress">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="TelecomNumber">
+            <key-map field-name="contactMechId"/>
+        </relation>
+        <relation type="one-nofk" rel-entity-name="FtpAddress">
+            <key-map field-name="contactMechId"/>
+        </relation>
+    </view-entity>
 
     <view-entity entity-name="WorkEffortAndTimeEntry" 
package-name="org.apache.ofbiz.workeffort.workeffort"
                  title="WorkEffort and TimeEntry View Entity">


Reply via email to