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));
}
}