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

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

commit cf23ae2e0183cd9227649f9adbef920b841fcee3
Author: diveshdut <[email protected]>
AuthorDate: Fri Aug 21 12:22:06 2026 +0530

    OFBIZ-13502 Add MRP run history read model
    
    Read durable MrpRunLog rows and return REST-compatible run history with 
status descriptions, filters, sorting, paging metadata, and duration fields.
---
 .../manufacturing/servicedef/services_mrp.xml      |  23 ++++
 .../manufacturing/mrp/MrpRunLogServices.groovy     | 145 +++++++++++++++++++++
 2 files changed, 168 insertions(+)

diff --git a/applications/manufacturing/servicedef/services_mrp.xml 
b/applications/manufacturing/servicedef/services_mrp.xml
index 3e22af4d1c..e684851de2 100644
--- a/applications/manufacturing/servicedef/services_mrp.xml
+++ b/applications/manufacturing/servicedef/services_mrp.xml
@@ -166,6 +166,29 @@ under the License.
         <attribute mode="OUT" name="links" optional="true" type="Map"/>
         <attribute mode="OUT" name="eventPlans" optional="false" 
type="java.util.List"/>
     </service>
+    <service name="findMrpRuns" engine="groovy" auth="true"
+            
location="component://manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/mrp/MrpRunLogServices.groovy"
 invoke="findMrpRuns">
+        <description>Find durable MRP run history from MRP run log 
records.</description>
+        <permission-service service-name="manufacturingPermissionService" 
main-action="VIEW"/>
+        <attribute mode="IN" name="jobId" optional="true" type="String"/>
+        <attribute mode="IN" name="mrpId" optional="true" type="String"/>
+        <attribute mode="IN" name="statusId" optional="true" type="String"/>
+        <attribute mode="IN" name="fromDate" optional="true" type="Timestamp"/>
+        <attribute mode="IN" name="daysBack" optional="true" type="Integer"/>
+        <attribute mode="IN" name="pageIndex" optional="true" type="Integer"/>
+        <attribute mode="IN" name="pageSize" optional="true" type="Integer"/>
+        <attribute mode="IN" name="sort" optional="true" type="String"/>
+        <attribute mode="IN" name="orderBy" optional="true" type="String"/>
+        <attribute mode="OUT" name="pageIndex" optional="false" 
type="Integer"/>
+        <attribute mode="OUT" name="pageSize" optional="false" type="Integer"/>
+        <attribute mode="OUT" name="totalCount" optional="false" type="Long"/>
+        <attribute mode="OUT" name="totalPages" optional="false" type="Long"/>
+        <attribute mode="OUT" name="hasNext" optional="false" type="Boolean"/>
+        <attribute mode="OUT" name="previousPageCount" optional="true" 
type="Long"/>
+        <attribute mode="OUT" name="nextPageCount" optional="true" 
type="Long"/>
+        <attribute mode="OUT" name="links" optional="true" type="Map"/>
+        <attribute mode="OUT" name="runs" optional="false" 
type="java.util.List"/>
+    </service>
     <service name="findPlanningFacilities" engine="groovy" auth="true"
             
location="component://manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/api/ManufacturingLookupServices.groovy"
 invoke="findManufacturingFacilities">
         <description>Find warehouse and plant facilities available for MRP 
planning.</description>
diff --git 
a/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/mrp/MrpRunLogServices.groovy
 
b/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/mrp/MrpRunLogServices.groovy
new file mode 100644
index 0000000000..57df180479
--- /dev/null
+++ 
b/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/mrp/MrpRunLogServices.groovy
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+package org.apache.ofbiz.manufacturing.mrp
+
+import java.sql.Timestamp
+import java.time.Duration
+
+import org.apache.ofbiz.base.util.DateRange
+import org.apache.ofbiz.base.util.UtilMisc
+import org.apache.ofbiz.base.util.UtilProperties
+import org.apache.ofbiz.base.util.UtilValidate
+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.util.EntityQuery
+import org.apache.ofbiz.entity.util.EntityUtil
+import org.apache.ofbiz.service.ServiceUtil
+import org.apache.ofbiz.ws.rs.util.RestApiUtil
+import org.apache.ofbiz.ws.rs.util.RestQueryOptions
+
+/*
+ * Builds paged MRP run history from durable MrpRunLog rows.
+ *
+ * Flow:
+ * 1. Parse REST query options and translate supported sort fields.
+ * 2. Build MrpRunLog filters for status, job, MRP id, and history window.
+ * 3. Query/count paged MrpRunLog rows and batch-load status descriptions.
+ * 4. Build response rows and return framework paging metadata.
+ */
+Map findMrpRuns() {
+    RestQueryOptions queryOptions
+    try {
+        queryOptions = RestQueryOptions.fromParameters(parameters)
+    } catch (IllegalArgumentException e) {
+        return ServiceUtil.returnError(e.message)
+    }
+    Map filters = queryOptions.filters
+    List orderBy
+    try {
+        orderBy = resolveMrpRunOrderBy(queryOptions.sort)
+    } catch (IllegalArgumentException e) {
+        return ServiceUtil.returnError(e.message)
+    }
+    List conditions = []
+    if (UtilValidate.isNotEmpty(filters.statusId)) {
+        conditions.add(EntityCondition.makeCondition('runStatusId', 
filters.statusId))
+    }
+    if (UtilValidate.isNotEmpty(filters.jobId)) {
+        conditions.add(EntityCondition.makeCondition('jobId', filters.jobId))
+    }
+    if (UtilValidate.isNotEmpty(filters.mrpId)) {
+        conditions.add(EntityCondition.makeCondition('mrpId', filters.mrpId))
+    }
+    Timestamp historyFromDate = runHistoryFromDate(filters)
+    if (historyFromDate) {
+        conditions.add(EntityCondition.makeCondition('startedAt', 
EntityOperator.GREATER_THAN_EQUAL_TO, historyFromDate))
+    }
+
+    EntityQuery query = EntityQuery.use(delegator).from('MrpRunLog')
+    if (conditions) {
+        query.where(EntityCondition.makeCondition(conditions, 
EntityOperator.AND))
+    }
+    long totalCount = query.queryCount()
+    List rows = query.orderBy(orderBy)
+            .queryPagedList(queryOptions.pageIndex, queryOptions.pageSize)
+            .getData()
+    Map statuses = rows ? EntityUtil.lookupById(delegator, 'StatusItem', 
'statusId',
+            rows*.runStatusId.findAll { it } as Set) : [:]
+    List runs = rows.collect { GenericValue runLog ->
+        buildMrpRunResponseRow(runLog, 
statuses[runLog.getString('runStatusId')])
+    }
+    String relativeRequestPath = RestApiUtil.getRelativeRequestPath(binding)
+    return ServiceUtil.returnSuccess() + RestApiUtil.getPagedResult('runs', 
runs, queryOptions, totalCount,
+            relativeRequestPath)
+}
+
+Timestamp runHistoryFromDate(Map filters) {
+    Integer daysBack = filters.daysBack instanceof Integer ? filters.daysBack 
: null
+    if (daysBack && daysBack > 0) {
+        long millisBack = Duration.ofDays(daysBack.longValue()).toMillis()
+        return new Timestamp(System.currentTimeMillis() - millisBack)
+    }
+    return filters.fromDate as Timestamp
+}
+
+Map buildMrpRunResponseRow(GenericValue runLog, GenericValue status) {
+    Locale serviceLocale = binding.hasVariable('locale') ? locale : 
Locale.ENGLISH
+    Timestamp startDateTime = runLog.getTimestamp('startedAt')
+    Timestamp finishDateTime = runLog.getTimestamp('finishedAt')
+    Long durationMillis = runLog.getLong('durationMillis')
+    if (durationMillis == null && startDateTime != null && finishDateTime != 
null) {
+        durationMillis = new DateRange(startDateTime, 
finishDateTime).durationInMillis()
+    }
+    [
+            runId: runLog.getString('mrpRunLogId'),
+            mrpRunLogId: runLog.getString('mrpRunLogId'),
+            jobId: runLog.getString('jobId'),
+            mrpId: runLog.getString('mrpId'),
+            mrpName: runLog.getString('mrpName') ?: 
UtilProperties.getMessage('ManufacturingUiLabels',
+                    'ManufacturingMrpRunDefaultName', serviceLocale),
+            facilityGroupId: runLog.getString('facilityGroupId'),
+            facilityId: runLog.getString('facilityId'),
+            defaultYearsOffset: 
UtilMisc.toIntegerObject(runLog.get('defaultYearsOffset')) ?: 1,
+            statusId: runLog.getString('runStatusId'),
+            statusDescription: status?.getString('description'),
+            failureReason: runLog.getString('failureReason'),
+            failureMessage: runLog.getString('failureMessage'),
+            runTime: durationMillis != null ? 
Duration.ofMillis(durationMillis).toString() : null,
+            durationMillis: durationMillis,
+            startDateTime: startDateTime,
+            finishDateTime: finishDateTime,
+            runAsUser: runLog.getString('runByUserLoginId')
+    ]
+}
+
+List resolveMrpRunOrderBy(String sortExpression) {
+    return RestApiUtil.resolveOrderBy(sortExpression, [
+            runId: 'mrpRunLogId',
+            mrpRunLogId: 'mrpRunLogId',
+            mrpId: 'mrpId',
+            mrpName: 'mrpName',
+            facilityId: 'facilityId',
+            statusId: 'runStatusId',
+            startDateTime: 'startedAt',
+            finishDateTime: 'finishedAt',
+            durationMillis: 'durationMillis',
+            jobId: 'jobId'
+    ], ['-startedAt', '-createdStamp'])
+}

Reply via email to