This is an automated email from the ASF dual-hosted git repository.

nmalin pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 444d19e369 Improved: Add condition-date on entity-condition element 
(OFBIZ-13349) (#948)
444d19e369 is described below

commit 444d19e3696bd1c75a85dc879d217990d2b05228
Author: Nicolas Malin <[email protected]>
AuthorDate: Wed May 27 11:19:40 2026 +0200

    Improved: Add condition-date on entity-condition element (OFBIZ-13349) 
(#948)
    
    On screen and form actions, add a condition-date element on
    <entity-condition> to directly add historic filter from now or a date in 
context.
    
    Currently, element entity-condition can have a boolean attribute
    filter-by-date that filter your entity list with fromDate/thruDate on
    now date only.
    
    If you need to navigate on history or use some other date fields, you
    can't use it and need to add a complex condition by hand
    
    With condition-date you can select the date value to use and date fields
    for the filter.
    
    Example :
    
    Complex :
      <entity-condition entity-name="PartyContactDetailByPurpose">
          <condition-list>
    <condition-expr field-name="partyId" operator="equals"
    from-field="parameters.partyId"/>
    <condition-date from-field="order.orderDate" ignore-if-empty="true">
                  <date-field field-name="fromDate">
                  <date-field field-name="thruDate">
                  <date-field field-name="purposeFromDate">
                  <date-field field-name="purposeThruDate">
              </condition-date>
          </condition-list>
      </entity-condition>
    
     Simple :
      <entity-condition entity-name="PartyContactDetailByPurpose">
          <condition-list>
    <condition-expr field-name="partyId" operator="equals"
    from-field="parameters.partyId"/>
              <condition-date from-field="order.orderDate"/>
          </condition-list>
      </entity-condition>
    
     Default :
      <entity-condition entity-name="PartyContactDetailByPurpose">
          <condition-list>
    <condition-expr field-name="partyId" operator="equals"
    from-field="parameters.partyId"/>
              <condition-date/>
          </condition-list>
      </entity-condition>
    **********
    By the way, change some if-else block to switch case block for increase 
code read
---
 .../ofbiz/entity/finder/ByConditionFinder.java     | 19 ++---
 .../ofbiz/entity/finder/EntityFinderUtil.java      | 90 ++++++++++++++++++++++
 framework/widget/dtd/widget-common.xsd             | 31 ++++++++
 .../ofbiz/widget/model/AbstractModelAction.java    | 37 ++++-----
 .../apache/ofbiz/widget/model/ModelFormAction.java | 15 ++--
 5 files changed, 154 insertions(+), 38 deletions(-)

diff --git 
a/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/ByConditionFinder.java
 
b/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/ByConditionFinder.java
index dcc37d3754..eab01404be 100644
--- 
a/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/ByConditionFinder.java
+++ 
b/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/ByConditionFinder.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import org.apache.ofbiz.base.util.UtilXml;
 import org.apache.ofbiz.entity.condition.EntityCondition;
 import org.apache.ofbiz.entity.finder.EntityFinderUtil.Condition;
+import org.apache.ofbiz.entity.finder.EntityFinderUtil.ConditionDate;
 import org.apache.ofbiz.entity.finder.EntityFinderUtil.ConditionExpr;
 import org.apache.ofbiz.entity.finder.EntityFinderUtil.ConditionList;
 import org.apache.ofbiz.entity.finder.EntityFinderUtil.ConditionObject;
@@ -47,15 +48,15 @@ public class ByConditionFinder extends ListFinder {
         // NOTE: the whereCondition can be null, ie (condition-expr | 
condition-list) is optional; if left out, means find all,
         // or with no condition in essense
         // process condition-expr | condition-list
-        Element conditionExprElement = UtilXml.firstChildElement(element, 
"condition-expr");
-        Element conditionListElement = UtilXml.firstChildElement(element, 
"condition-list");
-        Element conditionObjectElement = UtilXml.firstChildElement(element, 
"condition-object");
-        if (conditionExprElement != null) {
-            this.whereCondition = new ConditionExpr(conditionExprElement);
-        } else if (conditionListElement != null) {
-            this.whereCondition = new ConditionList(conditionListElement);
-        } else if (conditionObjectElement != null) {
-            this.whereCondition = new ConditionObject(conditionObjectElement);
+        Element conditionElement = UtilXml.firstChildElement(element);
+        if (conditionElement != null) {
+            this.whereCondition = switch 
(UtilXml.getTagNameIgnorePrefix(conditionElement)) {
+            case "condition-expr" -> new ConditionExpr(conditionElement);
+            case "condition-date" -> new ConditionDate(conditionElement);
+            case "condition-list" -> new ConditionList(conditionElement);
+            case "condition-object" -> new ConditionObject(conditionElement);
+            default -> null;
+            };
         }
 
         Element havingConditionListElement = 
UtilXml.firstChildElement(element, "having-condition-list");
diff --git 
a/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/EntityFinderUtil.java
 
b/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/EntityFinderUtil.java
index 121ad09e1a..5ece4f7638 100644
--- 
a/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/EntityFinderUtil.java
+++ 
b/framework/entity/src/main/java/org/apache/ofbiz/entity/finder/EntityFinderUtil.java
@@ -18,6 +18,10 @@
  
*******************************************************************************/
 package org.apache.ofbiz.entity.finder;
 
+import java.sql.Timestamp;
+import java.util.Locale;
+import org.apache.ofbiz.base.util.GeneralException;
+import org.apache.ofbiz.base.util.UtilDateTime;
 import static org.apache.ofbiz.base.util.UtilGenerics.cast;
 
 import java.io.Serializable;
@@ -35,10 +39,12 @@ import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.ObjectType;
 import org.apache.ofbiz.base.util.StringUtil;
 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.base.util.UtilXml;
 import org.apache.ofbiz.base.util.collections.FlexibleMapAccessor;
 import org.apache.ofbiz.base.util.string.FlexibleStringExpander;
+import org.apache.ofbiz.entity.GenericEntity;
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.entity.condition.EntityComparisonOperator;
@@ -47,6 +53,7 @@ import org.apache.ofbiz.entity.condition.EntityFunction;
 import org.apache.ofbiz.entity.condition.EntityJoinOperator;
 import org.apache.ofbiz.entity.condition.EntityOperator;
 import org.apache.ofbiz.entity.model.ModelEntity;
+import org.apache.ofbiz.entity.model.ModelField;
 import org.apache.ofbiz.entity.model.ModelFieldTypeReader;
 import org.apache.ofbiz.entity.util.EntityListIterator;
 import org.w3c.dom.Element;
@@ -286,6 +293,9 @@ public final class EntityFinderUtil {
                     case "condition-expr":
                         conditionList.add(new ConditionExpr(subElement));
                         break;
+                    case "condition-date":
+                        conditionList.add(new ConditionDate(subElement));
+                        break;
                     case "condition-list":
                         conditionList.add(new ConditionList(subElement));
                         break;
@@ -341,6 +351,86 @@ public final class EntityFinderUtil {
         }
     }
 
+    @SuppressWarnings("serial")
+    public static final class ConditionDate implements Condition {
+        private final FlexibleMapAccessor<Object> dateField;
+        private final List<FlexibleStringExpander> compareDateFields;
+        private final FlexibleStringExpander ignoreExdr;
+        private final boolean ignoreIfNull;
+        private final boolean ignoreIfEmpty;
+
+        public ConditionDate(Element conditionDateElement) {
+            String fieldDateName = 
conditionDateElement.getAttribute("from-field");
+            this.dateField = !fieldDateName.isEmpty()
+                    ? FlexibleMapAccessor.getInstance(fieldDateName)
+                    : null;
+            List<FlexibleStringExpander> collectedCompareDateFields = 
UtilXml.childElementList(conditionDateElement).stream()
+                    .map(e -> 
FlexibleStringExpander.getInstance(e.getAttribute("field-name")))
+                    .toList();
+            compareDateFields = !(collectedCompareDateFields.isEmpty() || 
collectedCompareDateFields.size() % 2 != 0)
+                    ? collectedCompareDateFields
+                    : List.of(FlexibleStringExpander.getInstance("fromDate"),
+                    FlexibleStringExpander.getInstance("thruDate"));
+            this.ignoreIfNull = 
"true".equals(conditionDateElement.getAttribute("ignore-if-null"));
+            this.ignoreIfEmpty = 
"true".equals(conditionDateElement.getAttribute("ignore-if-empty"));
+            this.ignoreExdr = 
FlexibleStringExpander.getInstance(conditionDateElement.getAttribute("ignore"));
+        }
+
+        @Override
+        public EntityCondition createCondition(Map<String, ? extends Object> 
context, ModelEntity modelEntity, ModelFieldTypeReader
+                modelFieldTypeReader) {
+            if ("true".equals(this.ignoreExdr.expandString(context))) {
+                return null;
+            }
+            Timestamp dateFieldValue = null;
+            ModelField dateFieldFromEntity = null;
+            if (this.dateField != null) {
+                dateFieldFromEntity = 
modelEntity.getField(dateField.getOriginalName());
+                if (dateFieldFromEntity == null) {
+                    Object valueFound = dateField.get(context);
+                    if (valueFound != null) {
+                        try {
+                            dateFieldValue = (Timestamp) 
ObjectType.simpleTypeOrObjectConvert(
+                                    valueFound, "java.sql.Timestamp", "", 
(Locale) context.get("locale"));
+                        } catch (GeneralException e) {
+                            Debug.logWarning("Failed to convert value " + 
valueFound, MODULE);
+                        }
+                    }
+                }
+            }
+            if (this.ignoreIfNull && dateFieldValue == null) {
+                return null;
+            }
+            if (this.ignoreIfEmpty && ObjectType.isEmpty(dateFieldValue)) {
+                return null;
+            }
+            if (UtilValidate.isEmpty(dateFieldValue)) {
+                dateFieldValue = UtilDateTime.nowTimestamp();
+            }
+            List<EntityCondition> conditionDates = UtilMisc.toList();
+            for (int i = 0; i < compareDateFields.size() / 2; i++) {
+                String fromDateField = 
compareDateFields.get(i).expandString(context);
+                String thruDateField = compareDateFields.get(i + 
1).expandString(context);
+                if (dateFieldFromEntity != null) {
+                    ModelField fromDateModelField = 
modelEntity.getField(fromDateField);
+                    ModelField thruDateModelField = 
modelEntity.getField(thruDateField);
+                    conditionDates.add(EntityCondition.makeConditionWhere(
+                            fromDateModelField.getColName() + " <= " + 
dateFieldFromEntity.getColName()));
+                    
conditionDates.add(EntityCondition.makeCondition(EntityOperator.OR,
+                            
EntityCondition.makeConditionWhere(thruDateModelField.getColName() + " >= " + 
dateFieldFromEntity.getColName()),
+                            EntityCondition.makeCondition(thruDateField, 
EntityOperator.EQUALS, GenericEntity.NULL_FIELD)));
+                } else {
+                    
conditionDates.add(EntityCondition.makeCondition(fromDateField, 
EntityOperator.LESS_THAN_EQUAL_TO, dateFieldValue));
+                    
conditionDates.add(EntityCondition.makeCondition(EntityOperator.OR,
+                            EntityCondition.makeCondition(thruDateField, 
EntityOperator.GREATER_THAN_EQUAL_TO, dateFieldValue),
+                            EntityCondition.makeCondition(thruDateField, 
EntityOperator.EQUALS, GenericEntity.NULL_FIELD)));
+                }
+            }
+
+            return EntityCondition.makeCondition(conditionDates);
+        }
+    }
+
     public interface OutputHandler extends Serializable {
         void handleOutput(EntityListIterator eli, Map<String, Object> context, 
FlexibleMapAccessor<Object> listAcsr);
         void handleOutput(List<GenericValue> results, Map<String, Object> 
context, FlexibleMapAccessor<Object> listAcsr);
diff --git a/framework/widget/dtd/widget-common.xsd 
b/framework/widget/dtd/widget-common.xsd
index 7efc8a83a0..62218b8dc2 100644
--- a/framework/widget/dtd/widget-common.xsd
+++ b/framework/widget/dtd/widget-common.xsd
@@ -335,6 +335,7 @@ under the License.
         <xs:complexType>
             <xs:choice maxOccurs="unbounded">
                 <xs:element ref="condition-expr" />
+                <xs:element ref="condition-date" />
                 <xs:element ref="condition-list" />
                 <xs:element ref="condition-object" />
             </xs:choice>
@@ -352,6 +353,7 @@ under the License.
         <xs:complexType>
             <xs:choice maxOccurs="unbounded">
                 <xs:element ref="condition-expr" />
+                <xs:element ref="condition-date" />
                 <xs:element ref="condition-list" />
                 <xs:element ref="condition-object" />
             </xs:choice>
@@ -399,6 +401,35 @@ under the License.
             </xs:attribute>
         </xs:complexType>
     </xs:element>
+    <xs:element name="condition-date">
+        <xs:complexType>
+            <xs:choice maxOccurs="unbounded" minOccurs="0">
+                <xs:element ref="date-field" />
+            </xs:choice>
+            <xs:attribute type="xs:string" name="from-field">
+                <xs:annotation>
+                    <xs:documentation>
+                        field in context that contains the date to use for 
filter
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="ignore-if-null" type="xs:boolean" 
default="false"/>
+            <xs:attribute name="ignore-if-empty" type="xs:boolean" 
default="false"/>
+            <xs:attribute name="ignore" type="xs:boolean" default="false">
+                <xs:annotation>
+                    <xs:documentation>
+                        Ignore the condition if flag is true.
+                        Defaults to false.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="date-field">
+        <xs:complexType>
+            <xs:attribute name="field-name" type="xs:string"/>
+        </xs:complexType>
+    </xs:element>
     <xs:element name="condition-object">
         <xs:complexType>
             <xs:attribute type="xs:string" name="field" use="required" />
diff --git 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/AbstractModelAction.java
 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/AbstractModelAction.java
index c4e951623c..1e9c453473 100644
--- 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/AbstractModelAction.java
+++ 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/AbstractModelAction.java
@@ -86,30 +86,19 @@ public abstract class AbstractModelAction implements 
Serializable, ModelAction {
      * @return A new <code>ModelAction</code> instance
      */
     public static ModelAction newInstance(ModelWidget modelWidget, Element 
actionElement) {
-        String nodeName = UtilXml.getNodeNameIgnorePrefix(actionElement);
-        if ("set".equals(nodeName)) {
-            return new SetField(modelWidget, actionElement);
-        } else if ("property-map".equals(nodeName)) {
-            return new PropertyMap(modelWidget, actionElement);
-        } else if ("property-to-field".equals(nodeName)) {
-            return new PropertyToField(modelWidget, actionElement);
-        } else if ("script".equals(nodeName)) {
-            return new Script(modelWidget, actionElement);
-        } else if ("service".equals(nodeName)) {
-            return new Service(modelWidget, actionElement);
-        } else if ("entity-one".equals(nodeName)) {
-            return new EntityOne(modelWidget, actionElement);
-        } else if ("entity-and".equals(nodeName)) {
-            return new EntityAnd(modelWidget, actionElement);
-        } else if ("entity-condition".equals(nodeName)) {
-            return new EntityCondition(modelWidget, actionElement);
-        } else if ("get-related-one".equals(nodeName)) {
-            return new GetRelatedOne(modelWidget, actionElement);
-        } else if ("get-related".equals(nodeName)) {
-            return new GetRelated(modelWidget, actionElement);
-        } else {
-            throw new IllegalArgumentException("Action element not supported 
with name: " + actionElement.getNodeName());
-        }
+        return switch (UtilXml.getNodeNameIgnorePrefix(actionElement)) {
+        case "set" -> new SetField(modelWidget, actionElement);
+        case "property-map" -> new PropertyMap(modelWidget, actionElement);
+        case "property-to-field" -> new PropertyToField(modelWidget, 
actionElement);
+        case "script" -> new Script(modelWidget, actionElement);
+        case "service" -> new Service(modelWidget, actionElement);
+        case "entity-one" -> new EntityOne(modelWidget, actionElement);
+        case "entity-and" -> new EntityAnd(modelWidget, actionElement);
+        case "entity-condition" -> new EntityCondition(modelWidget, 
actionElement);
+        case "get-related-one" -> new GetRelatedOne(modelWidget, 
actionElement);
+        case "get-related" -> new GetRelated(modelWidget, actionElement);
+        default -> throw new IllegalArgumentException("Action element not 
supported with name: " + actionElement.getNodeName());
+        };
     }
 
     public static List<ModelAction> readSubActions(ModelWidget modelWidget, 
Element parentElement) {
diff --git 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormAction.java
 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormAction.java
index cf7781063e..1558b83d1a 100644
--- 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormAction.java
+++ 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormAction.java
@@ -49,10 +49,13 @@ public abstract class ModelFormAction {
         List<ModelAction> actions = new ArrayList<>(actionElementList.size());
         for (Element actionElement : UtilXml.childElementList(parentElement)) {
             String nodeName = actionElement.getLocalName();
-            if ("service".equals(nodeName)) {
+            switch (nodeName) {
+            case "service":
                 actions.add(new Service(modelForm, actionElement));
-            } else if ("entity-and".equals(nodeName) || 
"entity-condition".equals(nodeName)
-                    || "get-related".equals(nodeName)) {
+                break;
+            case "entity-and":
+            case "entity-condition":
+            case "get-related":
                 if (!actionElement.hasAttribute("list")) {
                     String listName = modelForm.getListName();
                     if (UtilValidate.isEmpty(listName)) {
@@ -61,9 +64,11 @@ public abstract class ModelFormAction {
                     actionElement.setAttribute("list", listName);
                 }
                 actions.add(AbstractModelAction.newInstance(modelForm, 
actionElement));
-            } else if ("call-parent-actions".equals(nodeName)) {
+                break;
+            case "call-parent-actions":
                 actions.add(new CallParentActions(modelForm, actionElement));
-            } else {
+                break;
+            default:
                 actions.add(AbstractModelAction.newInstance(modelForm, 
actionElement));
             }
         }

Reply via email to