Developer Resources
Create Quote & Create Order Gl...
Creating Quotes with Bundles
18 min
https //docs nue io/product bundle are configurable products that contain child products defined by ruby productoption c records when you add a bundle to a quote, the api automatically expands it into a parent line item plus child line items based on the bundle's configuration what is a bundle? a bundle is a product2 record with ruby configurable c = true its children are defined by ruby productoption c junction records that link child products to the parent each option has a type that determines how it behaves option type auto included? pricing how to add bundled yes $0 (included in parent price) automatic — always added required yes own pricing (uses child price book entry) automatic — always added optional no own pricing (uses child price book entry) must be explicitly listed in addons\[] expansion behavior when the api processes a bundle productinput bundled options are automatically included with totalprice = 0 required options are automatically included with their own pricing from the https //docs nue io/price books optional options are only included if explicitly specified in the productinput addons list if an add on is specified that does not exist in the bundle's ruby productoption c records, the api returns an invalid addon product error response structure line items in the response are flattened depth first the bundle parent appears first, followed by its children (each with parentid pointing to the parent's id ), then the next root product lineitems\[0] bundle parent (parentid = null) lineitems\[1] bundled child (parentid = lineitems\[0] id) lineitems\[2] required child (parentid = lineitems\[0] id) lineitems\[3] optional add on (parentid = lineitems\[0] id) lineitems\[4] next root product (parentid = null) for nested bundles, children of the inner bundle follow the inner bundle, creating a full depth first traversal use cases 1\ basic bundle a bundle with a single bundled (auto included at $0) child product opportunity opp = \[select id, accountid from opportunity where id = \ oppid]; ruby globalapitypes createquoterequest request = new ruby globalapitypes createquoterequest(); request iscommit = false; request accountid = opp accountid; request quote = new quote( name = 'basic bundle quote', opportunityid = opp id, ruby subscriptionstartdate c = date today(), ruby subscriptionterm c = 12, ruby subscriptiontermdimension c = 'month' ); // nue rise edition is a bundle containing price builder (bundled) ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue rise edition'; bundle uom = 'user/month'; bundle quantity = 1; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // expected 2 line items // line 0 nue rise edition (parent) — parentid = null // line 1 price builder (bundled child) — parentid = line 0's id, totalprice = $0 system assertequals('succeed', response status); system assertequals(2, response data lineitems size()); ruby globalapitypes quotelineitemdto parent = response data lineitems\[0]; ruby globalapitypes quotelineitemdto child = response data lineitems\[1]; system assertequals(null, parent parentid); system assertequals(parent id, child parentid); 2\ bundle with required items required options are automatically included with their own pricing you do not need to list them in addons // nue gem edition includes // revenue manager — bundled (auto included at $0) // nue platform — required (auto included with own pricing) ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 1; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // expected 3 line items // line 0 nue gem edition (parent) — parentid = null // line 1 revenue manager (bundled, $0) — parentid = line 0 // line 2 nue platform (required, priced) — parentid = line 0 system assertequals('succeed', response status); system assertequals(3, response data lineitems size()); 3\ adding optional add ons optional products must be explicitly added via the addons list on the bundle's productinput each add on is itself a productinput // nue gem edition with two optional add ons ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 1; // add optional products ruby globalapitypes productinput addon1 = new ruby globalapitypes productinput(); addon1 productsku = 'usb security key'; ruby globalapitypes productinput addon2 = new ruby globalapitypes productinput(); addon2 productsku = 'implementation service'; bundle addons = new list\<ruby globalapitypes productinput>{ addon1, addon2 }; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // expected 5 line items // line 0 nue gem edition (parent) // line 1 revenue manager (bundled, auto included) // line 2 nue platform (required, auto included) // line 3 usb security key (optional add on) // line 4 implementation service (optional add on) system assertequals('succeed', response status); system assertequals(5, response data lineitems size()); note for add ons, quantity is optional if omitted, it defaults to the ruby defaultquantity c or ruby minquantity c from the ruby productoption c definition the uom and pricebookentryid are also optional for add ons and are resolved from the bundle's ruby productoption c configuration 4\ invalid add on adding a product that is not defined as a ruby productoption c on the bundle returns an error ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue rise edition'; bundle uom = 'user/month'; bundle quantity = 1; // random product is not a productoption of nue rise edition ruby globalapitypes productinput invalidaddon = new ruby globalapitypes productinput(); invalidaddon productsku = 'random product'; bundle addons = new list\<ruby globalapitypes productinput>{ invalidaddon }; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // expected failure with invalid addon product error system assertequals('failure', response status); 5\ quantity mechanics perbundle vs total mode bundle quantity affects child quantities differently depending on the ruby productoption c ruby quantitymode c setting perbundle mode (default) child quantity = parent quantity x ruby defaultquantity c // nue rise edition with price builder (perbundle, defaultqty=1) ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue rise edition'; bundle uom = 'user/month'; bundle quantity = 3; // parent qty = 3 request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // price builder child qty = 3 (parent) x 1 (default) = 3 ruby globalapitypes quotelineitemdto child = response data lineitems\[1]; system assertequals(3, child quotelineitem quantity); total mode child quantity stays fixed at ruby defaultquantity c regardless of parent quantity // nue gem edition with implementation service (total mode, defaultqty=20) ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 2; // parent qty = 2 // add implementation service (total mode, defaultqty=20) ruby globalapitypes productinput addon = new ruby globalapitypes productinput(); addon productsku = 'implementation service'; bundle addons = new list\<ruby globalapitypes productinput>{ addon }; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // implementation service qty stays at 20 (total mode ignores parent qty) // find the implementation service line item for (ruby globalapitypes quotelineitemdto li response data lineitems) { if (li quotelineitem product2 stockkeepingunit == 'implementation service') { system assertequals(20, li quotelineitem quantity); } } 6\ quantity override on add on when adding an optional add on, you can specify an explicit quantity to override the default ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 1; // override the default quantity of 20 with 50 ruby globalapitypes productinput addon = new ruby globalapitypes productinput(); addon productsku = 'implementation service'; addon quantity = 50; // overrides defaultqty of 20 bundle addons = new list\<ruby globalapitypes productinput>{ addon }; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // implementation service qty = 50 (explicit override) for (ruby globalapitypes quotelineitemdto li response data lineitems) { if (li quotelineitem product2 stockkeepingunit == 'implementation service') { system assertequals(50, li quotelineitem quantity); } } 7\ nested bundles a bundle can contain another bundle as a child the inner bundle is expanded recursively, and the response is flattened depth first with parentid chains linking each level // nue star edition contains lifecycle manager, which is itself a bundle ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue star edition'; bundle uom = 'user/month'; bundle quantity = 1; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // response is flattened depth first // line 0 nue star edition (root) parentid = null // line 1 lifecycle manager (child bundle) parentid = line 0 // line 2 lcm core (child of lcm) parentid = line 1 // line 3 lcm analytics (child of lcm) parentid = line 1 // line 4 other star child (child of star) parentid = line 0 system assertequals('succeed', response status); // verify parent chain for (ruby globalapitypes quotelineitemdto li response data lineitems) { if (li parentid != null) { // every child's parentid references an existing line item id boolean foundparent = false; for (ruby globalapitypes quotelineitemdto potential response data lineitems) { if (potential id == li parentid) { foundparent = true; break; } } system assert(foundparent, 'each child must reference a valid parent'); } } 8\ pricing bundled items are $0 bundled (auto included) items always have totalprice = 0 their cost is considered included in the parent bundle's price only required and optional items contribute independently to pricing ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue rise edition'; bundle uom = 'user/month'; bundle quantity = 1; request products = new list\<ruby globalapitypes productinput>{ bundle }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // the bundled child (price builder) has $0 pricing ruby globalapitypes quotelineitemdto bundledchild = response data lineitems\[1]; system assertequals(0, bundledchild quotelineitem ruby totalprice c); system assertequals(0, bundledchild quotelineitem ruby listtotalprice c); 9\ bundle + standalone in same quote the same product can appear both as a bundle child and as a standalone product in the same quote they are treated as independent line items // nue gem edition auto includes nue platform as a required child // we also add nue platform as a standalone product ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 1; // same product as standalone ruby globalapitypes productinput standalone = new ruby globalapitypes productinput(); standalone productsku = 'nue platform'; standalone uom = 'user/month'; standalone quantity = 25; request products = new list\<ruby globalapitypes productinput>{ bundle, standalone }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // expected nue platform appears twice // once as a child of nue gem edition (parentid != null) // once as a standalone root (parentid = null) system assertequals('succeed', response status); integer platformcount = 0; for (ruby globalapitypes quotelineitemdto li response data lineitems) { if (li quotelineitem product2 stockkeepingunit == 'nue platform') { platformcount++; } } system assertequals(2, platformcount, 'nue platform should appear as both bundle child and standalone'); you can also combine multiple bundles with standalone products in a single request each is expanded and priced independently ruby globalapitypes productinput bundle1 = new ruby globalapitypes productinput(); bundle1 productsku = 'nue rise edition'; bundle1 uom = 'user/month'; bundle1 quantity = 1; ruby globalapitypes productinput bundle2 = new ruby globalapitypes productinput(); bundle2 productsku = 'nue gem edition'; bundle2 uom = 'user/month'; bundle2 quantity = 2; ruby globalapitypes productinput standalone = new ruby globalapitypes productinput(); standalone productsku = 'implementation service'; standalone uom = 'hour'; standalone quantity = 10; request products = new list\<ruby globalapitypes productinput>{ bundle1, bundle2, standalone }; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); // response contains all expanded bundle children + standalone, flattened depth first // rise children first, then gem children, then implementation service system assertequals('succeed', response status); key behaviors summary behavior details bundle detection products with ruby configurable c = true are treated as bundles auto expansion bundled and required ruby productoption c records are automatically included optional add ons must be explicitly listed in productinput addons\[] invalid add ons products not in ruby productoption c return invalid addon product bundled pricing bundled items always have totalprice = 0 quantity (perbundle) child qty = parent qty x default qty quantity (total) child qty = fixed at default qty quantity override explicit quantity on add on overrides default nested bundles recursively expanded; response flattened depth first duplicate products same product as bundle child and standalone creates independent line items
Have a question?
Get answers fast with Nue’s intelligent AI, expert support team, and a growing community of users - all here to help you succeed.
To ask a question or participate in discussions, you'll need to authenticate first.