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

mridulpathak 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 5c44d5ed17 Fixed: Five regressions in the minilang-to-Groovy 
conversion of ProductionRunServicesScript.groovy (OFBIZ-13618)
5c44d5ed17 is described below

commit 5c44d5ed179759b533a0d08a6872394b6ab7fa5a
Author: Mridul Pathak <[email protected]>
AuthorDate: Sun Sep 27 14:00:20 2026 +0530

    Fixed: Five regressions in the minilang-to-Groovy conversion of 
ProductionRunServicesScript.groovy (OFBIZ-13618)
    
    - createProductionRunPartyAssign() echoed back the internally-defaulted 
workEffortId instead of the original productionRunId, corrupting the OUT 
parameter when the two differ.
    - issueProductionRunTaskComponent() dereferenced the WorkEffort and its 
parent production run without null-checking either lookup, throwing an NPE 
instead of a clean service error for a missing task or orphaned parent.
    - issueProductionRunTaskComponentInline()'s physical-integrity guard netted 
the caller's own reservation by quantityNotAvailable, making it stricter than 
the capacity the calling pool-stock loop had already sized issuance to, which 
could wrongly abort a whole multi-item issuance instead of issuing what fits.
    - issueInventoryItemToWorkEffort() capped issuance at quantityOnHandTotal 
instead of availableToPromiseTotal, letting it issue inventory already promised 
to other tasks.
    - handleManualIssuanceOverride() discarded the result of its inline 
issuance call, reporting success even when the inline call actually failed.
---
 .../jobshopmgt/ProductionRunServicesScript.groovy  | 25 ++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git 
a/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/jobshopmgt/ProductionRunServicesScript.groovy
 
b/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/jobshopmgt/ProductionRunServicesScript.groovy
index 9fb99c703b..e8748fdcb1 100644
--- 
a/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/jobshopmgt/ProductionRunServicesScript.groovy
+++ 
b/applications/manufacturing/src/main/groovy/org/apache/ofbiz/manufacturing/jobshopmgt/ProductionRunServicesScript.groovy
@@ -34,7 +34,7 @@ Map createProductionRunPartyAssign() {
     if (ServiceUtil.isError(serviceResult)) {
         return serviceResult
     }
-    return [successMessage: null, productionRunId: parameters.workEffortId]
+    return [successMessage: null, productionRunId: parameters.productionRunId]
 }
 
 /**
@@ -174,6 +174,9 @@ Map issueProductionRunTask() {
  */
 Map issueProductionRunTaskComponent() {
     GenericValue workEffort = from('WorkEffort').where(workEffortId: 
parameters.workEffortId).queryOne()
+    if (!workEffort) {
+        return ServiceUtil.returnError("Cannot find the production run task 
with id: ${parameters.workEffortId}")
+    }
 
     // POLICY GATE: Early enforcement
     String facilityId = parameters.facilityId ?: workEffort?.facilityId
@@ -184,6 +187,9 @@ Map issueProductionRunTaskComponent() {
     }
 
     GenericValue productionRun = from('WorkEffort').where(workEffortId: 
workEffort.workEffortParentId).queryOne()
+    if (!productionRun) {
+        return ServiceUtil.returnError("Cannot find the production run with 
id: ${workEffort.workEffortParentId}")
+    }
     require(!(['PRUN_CANCELLED', 
'PRUN_CLOSED'].contains(productionRun.currentStatusId)),
             label('ManufacturingUiLabels', 
'ManufacturingAddProdCompInCompCanStatusError'))
     String productId = parameters.productId
@@ -517,7 +523,11 @@ Map issueProductionRunTaskComponentInline(Map parameters,
             GenericValue facility = task ? from('Facility').where(facilityId: 
task.facilityId).queryOne() : null
             String allowReallocation = facility?.allowInventoryReallocation ?: 
'N'
 
-            BigDecimal effectiveAvailable = 
(inventoryItem.getBigDecimal('availableToPromiseTotal') ?: BigDecimal.ZERO) + 
ourPhysicalResQty
+            // Use the un-netted reservation quantity here, matching the 
capacity formula the caller
+            // (issueProductionRunTaskComponent's pool-stock loop) already 
used to size quantityNotIssued;
+            // netting by quantityNotAvailable here would make this guard 
stricter than the caller's own
+            // sizing and could wrongly abort the whole multi-item issuance 
instead of issuing what fits.
+            BigDecimal effectiveAvailable = 
(inventoryItem.getBigDecimal('availableToPromiseTotal') ?: BigDecimal.ZERO) + 
ourResQty
             BigDecimal inventoryItemQuantity
 
             // POLICY GATE: Traditional (Strict) vs Fluid (Reallocation)
@@ -677,9 +687,9 @@ Map issueInventoryItemToWorkEffort() {
     }
 
     if (inventoryItem.inventoryItemTypeId == 'NON_SERIAL_INV_ITEM') {
-        BigDecimal qoh = inventoryItem.getBigDecimal('quantityOnHandTotal') ?: 
0.0
-        if (qoh > 0) {
-            quantityIssued = (parameters.quantity == null || 
parameters.quantity > qoh) ? qoh : parameters.quantity
+        BigDecimal atp = 
inventoryItem.getBigDecimal('availableToPromiseTotal') ?: 0.0
+        if (atp > 0) {
+            quantityIssued = (parameters.quantity == null || 
parameters.quantity > atp) ? atp : parameters.quantity
 
             Map serviceResult = run service: 'assignInventoryToWorkEffort', 
with: [workEffortId: workEffortId,
                                                                                
    inventoryItemId: inventoryItem.inventoryItemId,
@@ -817,7 +827,10 @@ Map handleManualIssuanceOverride(Map parameters) {
     BigDecimal amountToIssue = parameters.quantityNotIssued
     Map issueParams = [*:parameters, inventoryItemId: 
inventoryItem.inventoryItemId,
                        quantityNotIssued: amountToIssue, 
failIfItemsAreNotAvailable: 'N']
-    issueProductionRunTaskComponentInline(issueParams, inventoryItem, null)
+    Map inlineResult = issueProductionRunTaskComponentInline(issueParams, 
inventoryItem, null)
+    if (ServiceUtil.isError(inlineResult)) {
+        return inlineResult
+    }
 
     List impactedTasks = [] // reconcileGlobalReservationsInternal already 
called via issueProductionRunTaskComponentInline
 

Reply via email to