From 51f0f55f4ec15a3f5f4fff6f0e3f57d724f86f82 Mon Sep 17 00:00:00 2001 From: Deepak Dixit Date: Mon, 21 Jul 2025 17:33:08 +0530 Subject: [PATCH] Added support for createdStamp field on all entity definitions - Automatically appends createdStamp alongside lastUpdatedStamp during entity initialization - Sets createdStamp during record creation if not already provided --- .../groovy/org/moqui/impl/entity/EntityDefinition.groovy | 2 ++ .../main/groovy/org/moqui/impl/entity/EntityJavaUtil.java | 6 +++++- .../main/groovy/org/moqui/impl/entity/EntityValueBase.java | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/framework/src/main/groovy/org/moqui/impl/entity/EntityDefinition.groovy b/framework/src/main/groovy/org/moqui/impl/entity/EntityDefinition.groovy index 4fb38cd27..5e9fe0c89 100644 --- a/framework/src/main/groovy/org/moqui/impl/entity/EntityDefinition.groovy +++ b/framework/src/main/groovy/org/moqui/impl/entity/EntityDefinition.groovy @@ -221,6 +221,7 @@ class EntityDefinition { if (internalEntityNode.attribute("no-update-stamp") != "true") { // automatically add the lastUpdatedStamp field internalEntityNode.append("field", [name:"lastUpdatedStamp", type:"date-time"]) + internalEntityNode.append("field", [name:"createdStamp", type:"date-time"]) } ArrayList fieldNodeList = internalEntityNode.children("field") @@ -431,6 +432,7 @@ class EntityDefinition { String aliasName = fi.name // never auto-alias these if ("lastUpdatedStamp".equals(aliasName)) continue + if ("createdStamp".equals(aliasName)) continue // if specified as excluded, leave it out ArrayList excludeList = aliasAll.children("exclude") int excludeListSize = excludeList.size() diff --git a/framework/src/main/groovy/org/moqui/impl/entity/EntityJavaUtil.java b/framework/src/main/groovy/org/moqui/impl/entity/EntityJavaUtil.java index 6029e72e3..a28e569c9 100644 --- a/framework/src/main/groovy/org/moqui/impl/entity/EntityJavaUtil.java +++ b/framework/src/main/groovy/org/moqui/impl/entity/EntityJavaUtil.java @@ -276,6 +276,7 @@ public static class EntityInfo { public final FieldInfo[] pkFieldInfoArray, nonPkFieldInfoArray, allFieldInfoArray; final FieldInfo lastUpdatedStampInfo; + final FieldInfo createdStampInfo; public final String allFieldsSqlSelect; final Map pkFieldDefaults, nonPkFieldDefaults; @@ -362,7 +363,7 @@ public static class EntityInfo { boolean hasFunctionAliasTemp = false; Map pkFieldDefaultsTemp = new HashMap<>(); Map nonPkFieldDefaultsTemp = new HashMap<>(); - FieldInfo lastUpdatedTemp = null; + FieldInfo lastUpdatedTemp = null, createdStampTemp = null; for (int i = 0; i < allFieldInfoSize; i++) { FieldInfo fi = allFieldInfoList.get(i); allFieldInfoArray[i] = fi; @@ -386,6 +387,8 @@ public static class EntityInfo { else nonPkFieldDefaultsTemp.put(fi.name, defaultStr); } if ("lastUpdatedStamp".equals(fi.name)) lastUpdatedTemp = fi; + if ("createdStamp".equals(fi.name)) createdStampTemp = fi; + } createOnlyFields = createOnlyFieldsTemp; needsAuditLog = needsAuditLogTemp; @@ -395,6 +398,7 @@ public static class EntityInfo { pkFieldDefaults = pkFieldDefaultsTemp.size() > 0 ? pkFieldDefaultsTemp : null; nonPkFieldDefaults = nonPkFieldDefaultsTemp.size() > 0 ? nonPkFieldDefaultsTemp : null; lastUpdatedStampInfo = lastUpdatedTemp; + createdStampInfo = createdStampTemp; pkFieldInfoArray = new FieldInfo[pkFieldInfoList.size()]; pkFieldInfoList.toArray(pkFieldInfoArray); diff --git a/framework/src/main/groovy/org/moqui/impl/entity/EntityValueBase.java b/framework/src/main/groovy/org/moqui/impl/entity/EntityValueBase.java index 2c38f0d94..61aa08ba8 100644 --- a/framework/src/main/groovy/org/moqui/impl/entity/EntityValueBase.java +++ b/framework/src/main/groovy/org/moqui/impl/entity/EntityValueBase.java @@ -982,6 +982,7 @@ public long checkAgainstDatabaseInfo(List> diffInfoList, Lis for (String nonpkFieldName : this.getEntityDefinition().getNonPkFieldNames()) { // skip the lastUpdatedStamp field if ("lastUpdatedStamp".equals(nonpkFieldName)) continue; + if ("createdStamp".equals(nonpkFieldName)) continue; final Object checkFieldValue = this.get(nonpkFieldName); final Object dbFieldValue = dbValue.get(nonpkFieldName); @@ -1035,6 +1036,7 @@ public long checkAgainstDatabase(List messages) { for (String nonpkFieldName : this.getEntityDefinition().getNonPkFieldNames()) { // skip the lastUpdatedStamp field if ("lastUpdatedStamp".equals(nonpkFieldName)) continue; + if ("createdStamp".equals(nonpkFieldName)) continue; final Object checkFieldValue = this.get(nonpkFieldName); final Object dbFieldValue = dbValue.get(nonpkFieldName); @@ -1510,9 +1512,13 @@ public EntityValue create() { final Long time = ecfi.transactionFacade.getCurrentTransactionStartTime(); Long lastUpdatedLong = time != null && time > 0 ? time : System.currentTimeMillis(); FieldInfo lastUpdatedStampInfo = ed.entityInfo.lastUpdatedStampInfo; + FieldInfo createdStampInfo = ed.entityInfo.createdStampInfo; if (lastUpdatedStampInfo != null && valueMapInternal.getByIString(lastUpdatedStampInfo.name, lastUpdatedStampInfo.index) == null) valueMapInternal.putByIString(lastUpdatedStampInfo.name, new Timestamp(lastUpdatedLong), lastUpdatedStampInfo.index); + if (createdStampInfo != null && valueMapInternal.getByIString(createdStampInfo.name, createdStampInfo.index) == null) + valueMapInternal.putByIString(createdStampInfo.name, new Timestamp(lastUpdatedLong), createdStampInfo.index); + // do the artifact push/authz ArtifactExecutionInfoImpl aei = new ArtifactExecutionInfoImpl(entityName, ArtifactExecutionInfo.AT_ENTITY, ArtifactExecutionInfo.AUTHZA_CREATE, "create").setParameters(valueMapInternal); aefi.pushInternal(aei, !entityInfo.authorizeSkipCreate, false);