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 0ad2ac60da Fixed: Mini-lang to Groovy regressions in 
QuoteServicesScript (OFBIZ-13571)
0ad2ac60da is described below

commit 0ad2ac60da34aba14719a4b595bb75f5154bb097
Author: Mridul Pathak <[email protected]>
AuthorDate: Fri Sep 11 18:49:39 2026 +0530

    Fixed: Mini-lang to Groovy regressions in QuoteServicesScript (OFBIZ-13571)
    
    Fix several regressions and bugs introduced during the migration of Quote 
services from Mini-lang to Groovy:
    - copyQuoteItem: preserve original quoteId when quoteIdTo is omitted, pass 
resolved target IDs when copying adjustments, and fix error label lookup to 
OrderErrorUiLabels.
    - createQuoteFromCustRequest: guard against NPE when CustRequest does not 
exist, exclude REQ_TAKER role when copying parties to prevent duplicate role 
creation errors, and properly scope exprdCond.
    - updateQuote: return an error if Quote is not found instead of throwing an 
NPE on quote.statusId, and properly scope quoteId.
    - createQuoteItem: query Product strictly by productId instead of passing 
the entire parameters map.
    - createQuoteNote: propagate the actual error from createNote and verify 
noteId presence before creating QuoteNote.
    - autoUpdateQuotePrice: fix error label lookup to OrderErrorUiLabels.
    - OrderErrorUiLabels.xml: define missing OrderQuoteDoesNotExists and 
OrderQuoteItemDoesNotExists labels.
---
 applications/order/config/OrderErrorUiLabels.xml   |  6 +++
 .../ofbiz/order/quote/QuoteServicesScript.groovy   | 52 +++++++++++++++-------
 2 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/applications/order/config/OrderErrorUiLabels.xml 
b/applications/order/config/OrderErrorUiLabels.xml
index dd9fc78127..8f33351267 100644
--- a/applications/order/config/OrderErrorUiLabels.xml
+++ b/applications/order/config/OrderErrorUiLabels.xml
@@ -3274,6 +3274,12 @@
         <value xml:lang="vi">Lỗi xảy ra : Công việc báo giá 
${parameters.quoteId} ${parameters.workEffortId} đã tồn tại.</value>
         <value 
xml:lang="zh">错误:已存在询价人工服务(QuoteWorkEffort)${parameters.quoteId}、${parameters.workEffortId}。</value>
     </property>
+    <property key="OrderQuoteDoesNotExists">
+        <value xml:lang="en">Quote does not exist.</value>
+    </property>
+    <property key="OrderQuoteItemDoesNotExists">
+        <value xml:lang="en">Quote Item does not exist.</value>
+    </property>
     <property key="OrderQuoteWorkEffortDoesNotExists">
         <value xml:lang="ar">خطأ: عرض سعر جهد العمل</value>
         <value xml:lang="de">FEHLER: Arbeitsaufwand für Angebot 
${parameters.quoteId} ${parameters.workEffortId} ist nicht vorhanden.</value>
diff --git 
a/applications/order/src/main/groovy/org/apache/ofbiz/order/quote/QuoteServicesScript.groovy
 
b/applications/order/src/main/groovy/org/apache/ofbiz/order/quote/QuoteServicesScript.groovy
index ede91aa81b..091713f216 100644
--- 
a/applications/order/src/main/groovy/org/apache/ofbiz/order/quote/QuoteServicesScript.groovy
+++ 
b/applications/order/src/main/groovy/org/apache/ofbiz/order/quote/QuoteServicesScript.groovy
@@ -176,8 +176,11 @@ Map updateQuote() {
     if (!security.hasEntityPermission('ORDERMGR', '_UPDATE', userLogin)) {
         return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderSecurityErrorToRunUpdateQuote', locale))
     }
-    quoteId = parameters.quoteId
+    String quoteId = parameters.quoteId
     GenericValue quote = from('Quote').where('quoteId', quoteId).queryOne()
+    if (!quote) {
+        return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderQuoteDoesNotExists', locale))
+    }
 
     parameters.statusId = parameters.statusId ?: quote.statusId
 
@@ -340,7 +343,7 @@ Map createQuoteItem() {
     }
 
     if (!parameters.quoteUnitPrice && parameters.productId) {
-        GenericValue product = 
from('Product').where(parameters).cache().queryOne()
+        GenericValue product = from('Product').where('productId', 
parameters.productId).cache().queryOne()
         if (product?.isVirtual == 'Y') {
             return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderCannotAddVirtualProductToQuote', locale))
         }
@@ -407,26 +410,32 @@ Map copyQuoteItem() {
     }
     GenericValue quoteItem = from('QuoteItem').where(parameters).queryOne()
     if (!quoteItem) {
-        return error(UtilProperties.getMessage('OrderUiLabels', 
'OrderQuoteItemDoesNotExists', locale))
+        return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderQuoteItemDoesNotExists', locale))
     }
+    String quoteIdTo = parameters.quoteIdTo ?: quoteItem.quoteId
     Map input = [
         userLogin: userLogin,
         *: quoteItem,
-        quoteId: parameters.quoteIdTo,
-        quoteItemSeqId: parameters.quoteItemSeqIdTo
+        quoteId: quoteIdTo,
+        quoteItemSeqId: parameters.quoteItemSeqIdTo ?: quoteItem.quoteItemSeqId
     ]
     if (!parameters.quoteIdTo && !parameters.quoteItemSeqIdTo) {
         input.quoteItemSeqId = null
     }
     Map serviceResult = run service: 'createQuoteItem', with: input
+    if (ServiceUtil.isError(serviceResult)) {
+        return serviceResult
+    }
+    String targetQuoteId = serviceResult.quoteId
+    String targetQuoteItemSeqId = serviceResult.quoteItemSeqId
     if (parameters.copyQuoteAdjustments == 'Y') {
         List quoteAdjustments = quoteItem.getRelated('QuoteAdjustment', null, 
null, false)
         for (GenericValue quoteAdjustment : quoteAdjustments) {
             Map serviceContext = 
dctx.makeValidContext('createQuoteAdjustment', ModelService.IN_PARAM,
-                    [*: quoteAdjustment, quoteId: parameters.quoteIdTo, 
quoteItemSeqId: parameters.quoteItemSeqIdTo, userLogin: userLogin])
-            serviceResult = dispatcher.runSync('createQuoteAdjustment', 
serviceContext)
-            if (ServiceUtil.isError(serviceResult)) {
-                return serviceResult
+                    [*: quoteAdjustment, quoteId: targetQuoteId, 
quoteItemSeqId: targetQuoteItemSeqId, userLogin: userLogin])
+            Map adjResult = dispatcher.runSync('createQuoteAdjustment', 
serviceContext)
+            if (ServiceUtil.isError(adjResult)) {
+                return adjResult
             }
         }
     }
@@ -566,7 +575,7 @@ Map autoUpdateQuotePrice() {
     }
     GenericValue quoteItem = from('QuoteItem').where(parameters).queryOne()
     if (!quoteItem) {
-        return error(UtilProperties.getMessage('OrderUiLabels', 
'OrderQuoteItemDoesNotExists', locale))
+        return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderQuoteItemDoesNotExists', locale))
     }
     if (parameters.manualQuoteUnitPrice) {
         quoteItem.quoteUnitPrice = parameters.manualQuoteUnitPrice
@@ -586,6 +595,10 @@ Map createQuoteFromCustRequest() {
     }
 
     GenericValue custRequest = from('CustRequest').where('custRequestId', 
parameters.custRequestId).queryOne()
+    if (!custRequest) {
+        return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderErrorCustRequestWithIdDoesntExist',
+                [custRequestId: parameters.custRequestId], locale))
+    }
 
     // Error if request type not equals to RF_QUOTE or RF_PUR_QUOTE
     if (custRequest.custRequestTypeId != 'RF_QUOTE' && 
custRequest.custRequestTypeId != 'RF_PUR_QUOTE') {
@@ -614,7 +627,7 @@ Map createQuoteFromCustRequest() {
     Map serviceResult = run service: 'createQuote', with: createQuoteInMap
     String quoteId = serviceResult.quoteId
 
-    exprdCond = [
+    List exprdCond = [
             EntityCondition.makeCondition('custRequestId', 
custRequest.custRequestId),
             EntityCondition.makeCondition('statusId', 
EntityOperator.NOT_EQUAL, 'CRQ_CANCELLED'),
             EntityCondition.makeCondition('statusId', 
EntityOperator.NOT_EQUAL, 'CRQ_REJECTED')
@@ -625,13 +638,15 @@ Map createQuoteFromCustRequest() {
         run service: 'createQuoteItem', with: [*:custRequestItem, quoteId: 
quoteId]
     }
 
-    // Roles
+    // Roles (The REQ_TAKER role is automatically added by the createQuote 
service)
     custRequest.getRelated('CustRequestParty', null, null, false)?.each { 
GenericValue custRequestParty ->
-        run service: 'createQuoteRole', with: [
-                quoteId: quoteId,
-                partyId: custRequestParty.partyId,
-                roleTypeId: custRequestParty.roleTypeId
-        ]
+        if (custRequestParty.roleTypeId != 'REQ_TAKER') {
+            run service: 'createQuoteRole', with: [
+                    quoteId: quoteId,
+                    partyId: custRequestParty.partyId,
+                    roleTypeId: custRequestParty.roleTypeId
+            ]
+        }
     }
 
     return [successMessage: null, quoteId: quoteId]
@@ -706,6 +721,9 @@ Map createQuoteNote() {
     Map serviceContext = dctx.makeValidContext('createNote', 
ModelService.IN_PARAM, [*: parameters, note: parameters.noteInfo])
     Map serviceResult = dispatcher.runSync('createNote', serviceContext)
     if (ServiceUtil.isError(serviceResult)) {
+        return serviceResult
+    }
+    if (!serviceResult.noteId) {
         return error(UtilProperties.getMessage('OrderErrorUiLabels', 
'OrderProblemCreatingTheNoteNoNoteIdReturned', locale))
     }
     GenericValue quoteNote = makeValue('QuoteNote')

Reply via email to