Developer Resources
Create Quote & Create Order Gl...
Multi-Attribute Pricing
19 min
nue supports multiple pricebookentries ( https //docs nue io/price books ) per product, each with different pricing based on attributes this enables scenarios like region specific pricing, partner tier discounts, or hardware configuration variants — all resolved automatically at quote creation time how https //docs nue io/multi attribute pricing price book entry resolution works when a product has multiple pricebookentries in the same pricebook at the same uom, the pricing engine resolves the correct price book entry using two mechanisms pricingattribute auto resolution — a pricingattribute mapping (e g , pricingattribute 1 mapped to account type ) tells the engine to read a field value from the account and match it against price book entry attribute columns this happens automatically with no api input required https //docs nue io/manage custom attributes in price book entries — custom fields added to the pricebookentry object serve as additional pricing dimensions these are specified explicitly via productinput custompricingattributes example price book entry setup for a product nue on salesforce with pricingattribute 1 mapped to account type pricingattribute 1 unitprice (null/default) $49 90 channel partner / reseller $29 90 customer channel $39 90 the engine selects the price book entry whose pricingattribute 1 matches the account's type field the any wildcard a price book entry with pricingattribute 1 = ' any ' matches any attribute value, acting as a universal/catch all entry this is useful for products that should have the same price regardless of account type use case 1 auto resolution from account type when the account's type field matches a price book entry's pricingattribute 1 value, the engine automatically selects that price book entry no special api input is needed // account type = 'channel partner / reseller' // price book entry with pricingattribute 1 = 'channel partner / reseller' exists at $29 90 opportunity opp = \[select id, accountid from opportunity where account type = 'channel partner / reseller' limit 1]; ruby globalapitypes createquoterequest request = new ruby globalapitypes createquoterequest(); request quote = new quote( opportunityid = opp id, name = 'partner pricing quote', pricebook2id = stdpricebookid, ruby subscriptionstartdate c = date today(), ruby subscriptionterm c = 12, ruby subscriptiontermdimension c = 'month' ); ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'nue on salesforce'; product uom = 'user/month'; product quantity = 10; // no custompricingattributes needed — account type is auto resolved request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(29 90, qli ruby listprice c); // partner price auto selected // listtotalprice = $29 90 x 10 x 12 = $3,588 00 use case 2 different account type changing the account type changes which price book entry is selected // account type = 'customer channel' // price book entry with pricingattribute 1 = 'customer channel' exists at $39 90 opportunity opp = \[select id, accountid from opportunity where account type = 'customer channel' limit 1]; ruby globalapitypes createquoterequest request = new ruby globalapitypes createquoterequest(); request quote = new quote( opportunityid = opp id, name = 'channel customer quote', pricebook2id = stdpricebookid, ruby subscriptionstartdate c = date today(), ruby subscriptionterm c = 12, ruby subscriptiontermdimension c = 'month' ); ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'nue on salesforce'; product uom = 'user/month'; product quantity = 10; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(39 90, qli ruby listprice c); // channel customer price use case 3 null account type (default price book entry) when the account's type field is null or does not match any price book entry attribute value, the engine falls back to the price book entry with a null/default pricingattribute 1 // account type = null // price book entry with pricingattribute 1 = null exists at $49 90 (default) account acc = new account(name = 'default account'); // acc type is null insert acc; opportunity opp = new opportunity( name = 'default pricing opp', accountid = acc id, stagename = 'prospecting', closedate = date today() adddays(30) ); insert opp; ruby globalapitypes createquoterequest request = new ruby globalapitypes createquoterequest(); request quote = new quote( opportunityid = opp id, name = 'default pricing quote', pricebook2id = stdpricebookid, ruby subscriptionstartdate c = date today(), ruby subscriptionterm c = 12, ruby subscriptiontermdimension c = 'month' ); ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'nue on salesforce'; product uom = 'user/month'; product quantity = 10; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(49 90, qli ruby listprice c); // default price (null attribute) use case 4 https //docs nue io/product bundle parent auto resolution when a bundle parent product has multi attribute price book entries, the parent's price book entry is resolved using the same account type auto resolution logic each product in the bundle resolves its own price book entry independently // account type = 'channel partner / reseller' // nue gem edition (bundle) has multi attribute price book entries ruby globalapitypes createquoterequest request = new ruby globalapitypes createquoterequest(); request quote = new quote( opportunityid = opp id, name = 'bundle multi attr quote', pricebook2id = stdpricebookid, ruby subscriptionstartdate c = date today(), ruby subscriptionterm c = 12, ruby subscriptiontermdimension c = 'month' ); ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 10; // auto resolution applies to the bundle parent price book entry request products = new list\<ruby globalapitypes productinput>{ bundle }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); // bundle parent resolves to the 'channel partner / reseller' price book entry price use case 5 bundle + add on both auto resolve when both the bundle parent and an explicit add on have multi attribute price book entries, each product resolves its price book entry independently based on the same account type value // account type = 'channel partner / reseller' ruby globalapitypes productinput bundle = new ruby globalapitypes productinput(); bundle productsku = 'nue gem edition'; bundle uom = 'user/month'; bundle quantity = 10; // explicit add on that also has multi attribute price book entries ruby globalapitypes productinput addon = new ruby globalapitypes productinput(); addon productsku = 'nue on salesforce'; bundle addons = new list\<ruby globalapitypes productinput>{ addon }; request products = new list\<ruby globalapitypes productinput>{ bundle }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); // parent and add on each resolve to their own 'channel partner / reseller' price book entry use case 6 any universal price book entry a product with pricingattribute 1 = ' any ' matches any account type value this is commonly used for products with uniform pricing across all account types // revenue lifecycle platform has a single any price book entry at $299 00 // it matches regardless of account type ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'revenue lifecycle platform'; product uom = 'user/month'; product quantity = 5; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(299 00, qli ruby listprice c); // any price book entry always matches // works for account type = 'channel partner / reseller', 'customer channel', null, etc use case 7 custom pricing attributes (price book entry custom fields) for products with custom fields on pricebookentry used as pricing dimensions (e g , storage2 c for storage tiers), use productinput custompricingattributes to specify the desired attribute values important custompricingattributes is for price book entry custom fields — a completely separate mechanism from account type auto resolution do not use custompricingattributes for account type matching // product has price book entries with a custom field storage2 c // storage2 c = '8gb' → unitprice = $99 00 // storage2 c = '16gb' → unitprice = $149 00 // storage2 c = '32gb' → unitprice = $199 00 ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'cloud storage'; product uom = 'user/month'; product quantity = 10; ruby globalapitypes custompricingattribute storageattr = new ruby globalapitypes custompricingattribute(); storageattr name = 'storage2 c'; storageattr value = '16gb'; product custompricingattributes = new list\<ruby globalapitypes custompricingattribute>{ storageattr }; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(149 00, qli ruby listprice c); // 16gb price book entry selected use case 8 no matching price book entry (error) when the attribute values do not match any price book entry, the api returns an error // product has price book entries with storage2 c = '8gb', '16gb', '32gb' // requesting '64gb' which does not exist ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'cloud storage'; product uom = 'user/month'; product quantity = 10; ruby globalapitypes custompricingattribute storageattr = new ruby globalapitypes custompricingattribute(); storageattr name = 'storage2 c'; storageattr value = '64gb'; // no price book entry exists for this value product custompricingattributes = new list\<ruby globalapitypes custompricingattribute>{ storageattr }; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('failure', response status); // error indicates no matching price book entry was found for the given attributes use case 9 multi field custom attributes (and logic) when multiple custompricingattribute entries are provided, they are combined with and logic only price book entries matching all specified attribute values are selected // product has price book entries with two custom fields // storage2 c = '16gb', region c = 'us' → $149 00 // storage2 c = '16gb', region c = 'eu' → $169 00 ruby globalapitypes productinput product = new ruby globalapitypes productinput(); product productsku = 'cloud storage'; product uom = 'user/month'; product quantity = 10; ruby globalapitypes custompricingattribute storageattr = new ruby globalapitypes custompricingattribute(); storageattr name = 'storage2 c'; storageattr value = '16gb'; ruby globalapitypes custompricingattribute regionattr = new ruby globalapitypes custompricingattribute(); regionattr name = 'region c'; regionattr value = 'eu'; product custompricingattributes = new list\<ruby globalapitypes custompricingattribute>{ storageattr, regionattr }; request products = new list\<ruby globalapitypes productinput>{ product }; request iscommit = false; ruby globalapitypes createquoteresponse response = ruby globalquoteserviceapi createquote(request); system assertequals('succeed', response status); quotelineitem qli = response data lineitems\[0] quotelineitem; system assertequals(169 00, qli ruby listprice c); // eu + 16gb price book entry key points concept details account type auto resolution requires no api code — just ensure pricingattribute mapping is configured the engine reads account type and matches price book entries automatically custompricingattributes for price book entry custom fields only (e g , storage2 c ) this is a separate mechanism from account type independent resolution each product resolves its price book entry independently — a bundle parent and its add ons can resolve to different price book entries any wildcard a price book entry with pricingattribute 1 = ' any ' matches all attribute values (universal pricing) and logic for multiple attributes multiple custompricingattribute entries must all match for a price book entry to be selected attribute values are strings custompricingattributes value is always a string boolean fields require exact string matching (e g , 'true' not true ) null falls back to default when account type is null, the price book entry with null pricingattribute 1 is used no match = error if no price book entry matches the resolved attributes, the api returns a failure status
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.