{"id":408,"date":"2019-10-07T20:28:18","date_gmt":"2019-10-07T20:28:18","guid":{"rendered":"http:\/\/morecpq.com\/?p=408"},"modified":"2020-04-10T20:59:27","modified_gmt":"2020-04-10T20:59:27","slug":"error-message-in-qle-apex-cpq-time-limit-exceeded","status":"publish","type":"post","link":"https:\/\/morecpq.com\/index.php\/2019\/10\/07\/error-message-in-qle-apex-cpq-time-limit-exceeded\/","title":{"rendered":"Error Message in QLE: Apex CPQ Time Limit Exceeded"},"content":{"rendered":"\n<p><strong>Whaaaaaat is going on with this error message??<br><\/strong>Sometimes, when you click save on the Quote Line Editor, you get a message saying it timed out!  Why would this happen, you ask?  There are plenty of reasons and some of them are listed below.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Too many Price Rules\/Product Rules<ul><li>Price Rules<\/li><li>Product Rules<\/li><li>Summary Variables<\/li><\/ul><\/li><li>Too many pieces of automation<ul><li>Workflow Rules<\/li><li>Process Builder<\/li><li>Flows<\/li><li>APEX Trigger<\/li><\/ul><\/li><li>Too many records<ul><li>Quote Lines<\/li><li>Opportunity Products<\/li><li>Order Lines<\/li><li>Subscriptions<\/li><\/ul><\/li><li>Too much data on the above objects<ul><li>Custom fields<\/li><li>Large\/Complex Bundle Products<\/li><\/ul><\/li><li>Too much processing is happening in the background.<ul><li>Timed Batch processes<\/li><\/ul><\/li><li>You\u2019re in a slow sandbox<\/li><\/ul>\n\n\n\n<p>How to figure out what\u2019s causing the problem<br>Here is a sequence of testing events you can employ to figure out which of the above is causing the issue.  Make a dummy quote with a thousand lines.  Try each of the below and try saving the dummy quote after each step.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Turn off Price\/Product Rules<\/li><li>Turn off Workflow\/Process Builder\/Flow\/APEX Trigger<\/li><li>Turn on Large Quoting Experience<\/li><li>Simplify a complex bundle product<\/li><li>Remove unused custom fields<\/li><li>Reduce number of quote lines<\/li><\/ul>\n\n\n\n<p><strong>How to FIX IT<br><\/strong>There are a few best practice things you can do to mitigate this issue.  Here\u2019s another list!<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Price\/Product Rules<br><\/strong>If you are noticing you have a lot of Price Rules or Product Rules, look for the below things you can optimize.Combine Rules.  If you have 10 rules that all fire on Before Calculate, and there are no Price Conditions of any of the rules, you can combine all of these rules into one rule that has many actions.<br><br>Remove Calculator Events.  Sometimes, there are rules that are fired on all Calculator Events.  This is generally bad practice and means you should look into reengineering your Price Rules so that they do not need to be fired so often.<br><br>Write a QCP.  Often times, rules that fire on all calculation events or that require a double calculate are better functioning if they exist inside a QCP.  Simple JavaScript can sometimes make complex rules very very simple.  See below for an example rollup.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/QuoteCalculatorJS\nexport const CONSTANTS = {\n\tDEBUG: true,\n\tDS01: 'DS01'\n};\n\nexport function onAfterCalculate(quote, lines, conn) {\n\tvar sumMatrix = new Array();\n\t\n\tsumMatrix = sumUpHours(quote, lines, conn, sumMatrix);\n\t\n\treturn Promise.resolve();\n}\n\nexport function sumUpHours(quote, lines, conn, sumMatrix) {\n\tif (lines.length > 0) {\n\t\tconsole.log('Zeroing Bundle Hours... Setting Matrix...');\n\t\tlines.forEach(function(line) {\n\t\t\tif (line.record != null) {\n\t\t\t\tline.record&#91;'SBQQ__Source__c'] = null;\n\t\t\t\tif (line.record&#91;'SBQQ__Bundle__c'] == true) {\n\t\t\t\t\tline.record&#91;'Hours__c'] = 0;\n\t\t\t\t\tline.record&#91;'Price__c'] = 0;\n\t\t\t\t\t\/\/sumMatrix&#91;line.record&#91;'SBQQ__Product__c']] = line;\n\t\t\t\t\tsumMatrix&#91;line.record&#91;'Id']] = line;\n\t\t\t\t} else if (line.record&#91;'Hours__c'] != '' &amp;&amp; line.record&#91;'Hours__c'] != null &amp;&amp; line.record&#91;'Hours__c'] > 0) {\n\t\t\t\t\tline.record&#91;'Price__c'] = line.record&#91;'SBQQ__ListPrice__c'] * line.record&#91;'Hours__c'];\n\t\t\t\t} else if (line.record&#91;'Hours__c'] == '' || line.record&#91;'Hours__c'] == null || line.record&#91;'Hours__c'] == 0) {\n\t\t\t\t\tline.record&#91;'Price__c'] = null;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tconsole.log('Zeroing Hours... Setting Matrix... Done!');\n\t\n\t\tconsole.log('Filling Sum Matrix...');\n\t\t\/\/ loop through option levels starting from largest.\n\t\tvar optionLevel = 0;\n\t\tfor (optionLevel = 4; optionLevel > 0; optionLevel--) {\n\t\t\t\/\/ loop through quote lines with this option level.\n\t\t\tlines.forEach(function(line) {\n\t\t\t\tif (line.record != null &amp;&amp; line.record&#91;'SBQQ__OptionLevel__c'] == optionLevel) {\n\t\t\t\t\t\/\/ get this line's hours.\n\t\t\t\t\tvar lineHours = line.record&#91;'Hours__c'];\n\t\t\t\t\tvar linePrice = line.record&#91;'Price__c'];\n\t\t\t\t\t\n\t\t\t\t\t\/\/ if this quote line's hours is not null and is > 0,\n\t\t\t\t\tif (lineHours != null &amp;&amp; lineHours != 0) {\n\t\t\t\t\t\t\/\/ get this quote line's parent.\n\t\t\t\t\t\tvar lineParProdID = line.record&#91;'SBQQ__RequiredBy__c'];\n\t\t\t\t\t\t\/\/var lineParProdID = line.record&#91;'Required_By_Product_ID__c'];\n\t\t\t\t\t\t\/\/if (lineParProdID == null || lineParProdID == '') {\n\t\t\t\t\t\t\/\/\tlineParProdID = line.record&#91;'Parent_Product_ID__c'];\n\t\t\t\t\t\t\/\/}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (lineParProdID != null &amp;&amp; lineParProdID != '') {\n\t\t\t\t\t\t\t\/\/ add this quote line's hours to the parent hours count in the matrix for this parent.\n\t\t\t\t\t\t\tsumMatrix&#91;lineParProdID].record&#91;'Hours__c'] += lineHours;\n\t\t\t\t\t\t\tsumMatrix&#91;lineParProdID].record&#91;'Price__c'] += linePrice;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\t\/\/ resolve promise.\n\t\t\t\/\/Promise.resolve();\n\t\t}\n\t}\n\tconsole.log('Filling Sum Matrix... Done.');\n\treturn sumMatrix;\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Automation<br><\/strong>Move any automation that exists on the Quote, Quote Line, and Quote Line Group to being on somewhere else like Opportunity Stage = Closed Won.  Another thing you can do is use Price Rules or a QCP (Quote Calculator Plug-in).  This will speed things up and also help consolidate.  Keep in mind that when you have a primary quote, and have many quote lines, and click save, CPQ will insert\/update\/delete Opportunity Products at the same time.  It will also update Order Lines or Subscriptions which will also fire the automation you have on those objects.<ul><li>Quote and Quote Lines<ul><li>Move as much of this automation to Price Rules as possible.<\/li><\/ul><\/li><li>Opportunity Products<ul><li>Move as much of this automation to Opportunity Stage = Closed Won as possible.<\/li><\/ul><\/li><li>Subscriptions<ul><li>Move as much of this automation to Contract Status = Activated as possible.<\/li><\/ul><\/li><li>Order Lines<ul><li>Move as much of this automation to Order Status = Active as possible.<\/li><\/ul><\/li><\/ul><\/li><li><strong>Large Quoting Experience<br><\/strong>Enabling this feature in the CPQ package settings is highly recommended if you are expecting to have lots of Quote Lines.  Make sure to set your Quote Batch Size to a reasonable number to chunk things up in manageable groups of Quote Lines.<\/li><li><strong>Custom Fields<br><\/strong>Remove as many custom fields as possible from the CPQ Objects.  (Quote, Quote Line, Opportunity, Opportunity Product, Order, Order Line, Contract, Subscription, Asset, Contracted Price)<\/li><li><strong>Large Bundles<br><\/strong>Look into redesigning your bundles such that there are less Features, Options, Constraints, and other complexities.<\/li><li><strong>Timed Batch Processing<br><\/strong>If you have processes that kick off in a timed manner, especially processes that touch the objects that CPQ uses, move this processing to off hours.  That way it will not be running at the time the users are in there making quotes.<\/li><li><strong>Sandboxes<br><\/strong>If none of the things above are happening, sometimes the sandbox you\u2019re developing in is VERY slow.  In this case, back up your data and refresh the sandbox.  In most cases, this resolves the issue.<\/li><li><strong>Asynchronous Calculation<br><\/strong>Another way to help resolve the timeout issue is to enable asynchronous calculation.  This is a way to elongate the timeout limit for calculations that happen outside the line editor.<\/li><\/ul>\n\n\n\n<p>Debugging Article: <a href=\"https:\/\/help.salesforce.com\/articleView?id=000317375&amp;language=en_US&amp;type=1&amp;mode=1\">https:\/\/help.salesforce.com\/articleView?id=000317375&amp;language=en_US&amp;type=1&amp;mode=1<\/a><br>QCP Documentation: <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.cpq_dev_plugins.meta\/cpq_dev_plugins\/cpq_dev_jsqcp_parent.htm\">https:\/\/developer.salesforce.com\/docs\/atlas.en-us.cpq_dev_plugins.meta\/cpq_dev_plugins\/cpq_dev_jsqcp_parent.htm<\/a><br>This Error SFDC Article: <a href=\"https:\/\/help.salesforce.com\/articleView?id=000317385&amp;language=en_US&amp;type=1&amp;mode=1\">https:\/\/help.salesforce.com\/articleView?id=000317385&amp;language=en_US&amp;type=1&amp;mode=1<\/a><br>Asynchronous Calculation Article: <a href=\"https:\/\/help.salesforce.com\/articleView?id=cpq_enable_async_calculation.htm&amp;type=5\">https:\/\/help.salesforce.com\/articleView?id=cpq_enable_async_calculation.htm&amp;type=5<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Whaaaaaat is going on with this error message??Sometimes, when you click save on the Quote Line Editor, you get a message saying it timed out! Why would this happen, you ask? There are plenty of reasons and some of them are listed below. Too many Price Rules\/Product Rules Price Rules Product Rules Summary Variables Too &hellip;<br \/><a href=\"https:\/\/morecpq.com\/index.php\/2019\/10\/07\/error-message-in-qle-apex-cpq-time-limit-exceeded\/\" class=\"more-link pen_button pen_element_default pen_icon_arrow_double\">Continue reading <span class=\"screen-reader-text\">Error Message in QLE: Apex CPQ Time Limit Exceeded<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-408","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/comments?post=408"}],"version-history":[{"count":21,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/408\/revisions"}],"predecessor-version":[{"id":591,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/408\/revisions\/591"}],"wp:attachment":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/media?parent=408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/categories?post=408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/tags?post=408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}