Skip to main content
注目のグループ

* Salesforce Revenue Cloud *

Welcome! This group is dedicated to your success with Salesforce Revenue Cloud. Join the conversation here to stay up to date on the product, learn best practices, and everything in between. Use this group to review resources, ask questions, help each other, and share experiences. --------------------------------------- This group is maintained and moderated by Salesforce employees. The content received in this group falls under the official Forward-Looking Statement: http://investor.salesforce.com/about-us/investor/forward-looking-statements/default.aspx

 

 

 

 

Attribute-Based Pricing adjustment removed after adding another product to Quote Line, also volume based and manual discount is not applying on product

 

 

 

image.png

 

Hi everyone,

I'm facing an issue with Product Catalog Management pricing and would appreciate any guidance. I have configured an Attribute-Based Adjustment for a product (Clear GST Core), and the adjustment is applied correctly when the product is added to a quote. The quote initially shows the expected Attribute-Based Price adjustment and the correct Net Unit Price. The corresponding records are also generated successfully in Attribute Discount Entries, the records are active, and the refresh status is completed.

However, when I add another product to the same quote that does not have any attribute-based conditions, the quote gets repriced and the previously applied Attribute-Based Adjustment on the first product is removed. The Calculation Details no longer show the Attribute-Based Price adjustment, and the line reverts back to the standard list price, even though the Attribute Discount Entry record still exists and remains active.

Additionally, I am facing issues with Manual Discount and Volume-Based Pricing. Manual discounts are not being applied as expected on quote lines, and Volume-Based Pricing tiers are also not getting applied even though the corresponding Volume Discount Entries have been generated successfully and are active. It appears that pricing recalculation is not consistently honoring Attribute-Based Pricing, Manual Discounts, or Volume-Based Pricing after quote updates.

Has anyone encountered a similar issue where adding a new quote line causes existing pricing adjustments to be removed or ignored? Are there any known limitations, configuration settings, or troubleshooting steps related to quote repricing, Attribute-Based Adjustments, Manual Discounts, or Volume-Based Pricing in Product Catalog Management? Any suggestions would be greatly appreciated. Thanks in advance!

2 件の回答
  1. 8月10日 4:31

    Hey  @TEJASHREE CHOUGULE

     

    For Attribute Adjustment Reset: Check your Context Definition, If line attributes aren't mapped properly, recalculation wipes the adjustment. 

      

    For  Volume Discount Missing: Ensure your Price Adjustment Schedule is active and the line Quantity context variable feeds into the pricing procedure tier step. 

      

     For Manual Discount Overwritten: Check your Pricing Waterfall sequence in the Pricing Procedure. If list/contract price elements run after manual discount steps, they overwrite the discount. 

      

    I recommend  run a simulation in Pricing Procedure Builder to see exactly where the waterfall drops those values. 

0/9000

Revenue Operations and Revenue Cloud at Dreamforce 2026

 

Dreamforce 2026 is here! I curated a list of Revenue Operations-related sessions, events, and parties at Dreamforce 2026. Bookmark it for Future You, and thank me later.  

 

Here are the key events to attend. View the complete list here:

https://garvensconsulting.com/revenue-operations-at-dreamforce-2026/

 

 

Revenue Cloud Keynote

See how Salesforce Revenue Cloud is the complete agentic revenue platform — one revenue engine that unifies pricing, quoting, contracting, and billing for any channel, experience, or agent.

 

Speakers include:

Day: Wednesday, September 16

Time: 12:45 PM – 1:35 PM

Location: Moscone West, L3, Keynote – Room 3001

Add To Agenda

 

Revenue Cloud Roadmap: Revenue Cloud Advanced 

 

Day: Tuesday, Sep 15

Time: 1:30 PM - 2:10 PM PDT

Location: Metreon AMC, L3, Theatre 15

Add To Agenda

 

Day: Thursday, Sep 17

Time: 9:00 AM - 9:40 AM PDT

Location: Moscone South, LL, Content Pavilion, Stage 1

Add To Agenda

 

RevOps Crawl: The Great CPQ-to-ARM Migration

Migrate from Moscone Center to The Cigar Bar & Grill with RevOps nerds in a fun, bar-crawl setting.

 

Day: Thursday, September 17

Time: 4:00 PM – 7:00 PM

Location: Moscone Center to The Cigar Bar & Grill

Register on LinkedIn

 

Sales Cloud Keynote: The #1 CRM Now Works for You

CRM was built to store what happened. Now it captures data, updates itself, and executes the next best action automatically. We turned the #1 CRM from a system you update into one that works for you. 

 

Day: Wednesday, September 16

Time: 9:00 AM – 9:50 AM

Location: Moscone South, LL, Keynote – Hall B

Add To Agenda

0/9000

Hi @* Salesforce Revenue Cloud * I  have assigned the Standard Cellular Tablet product to the Cellular Tablets category. However, I'm still getting this error. I need help understanding how to approach this.

Product Catalog Management with Revenue Cloud , Build a Simple Product

 

image.png

 

 

#Trailhead Challenges

4 件の回答
  1. Eric Burté (DEVOTEAM) Forum Ambassador
    9月15日 13:52

    Hello @Satyanarayan Naldiga & @sakshi sharma

    Please have a look at this thread on the same topic. Check the details given in the related best answer post : https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000j9ix50AA

    Eric

0/9000

I’m having trouble with a Revenue Cloud instance. Every time I try to add a bundle to a quote, I get the following error:

“Verify if fields like Component, Virtual Component, or backend configuration block it from being quoted outside of its parent bundle.”

The system works normally when I try to add a standalone product. The issue only occurs with the bundle, and I’m not trying to perform an amendment—just add a new product.

Is anyone else encountering this same error?

4 件の回答
  1. 9月8日 12:03

    @Guilherme Mattei  

    The fact that it happens only for accounts with existing Assets makes me suspect the issue may be related to the asset-to-bundle configuration or existing asset context, rather than the bundle product itself.

    I’d compare a working new account vs. an account with existing Assets, especially the asset relationships and any configuration rules/CML evaluated during bundle configuration. The “Failed to parse response” message on accounts without Assets also makes me think it would be worth checking the configuration-rule response/logs for both scenarios. 

0/9000

MocAdapter for Tax

MocAdapter Document link

 

Shipping Country and State

Tax Logic Implemented

🔹 India → 30% Tax

🔹 USA → 40% Base Country Tax + State Tax

Example State Tax Configuration:

  • Utah → 2%
  • South Dakota → 2.5%
  • Minnesota → 3%
  • North Dakota → 3.5%
  • Nebraska → 4%
  • New Hampshire → 4.5%
  • Idaho → 5%
  • Washington → 5.5%
  • Vermont → 6%

🔹 Other Countries → Default 20% Tax 

 

global virtual class MockAdapter implements commercetax.TaxEngineAdapter {

global commercetax.TaxEngineResponse processRequest(

commercetax.TaxEngineContext taxEngineContext

) {

commercetax.RequestType requestType =

taxEngineContext.getRequestType();

commercetax.CalculateTaxRequest request =

(commercetax.CalculateTaxRequest)

taxEngineContext.getRequest();

if (request.documentCode == null) {

return new commercetax.ErrorResponse(

commercetax.resultcode.TaxEngineError,

'404',

'documentCode is mandatory'

);

}

if (requestType ==

commercetax.RequestType.CalculateTax) {

commercetax.calculatetaxtype type =

request.taxtype;

String docCode = '';

if (request.DocumentCode != null) {

docCode = request.DocumentCode;

} else if (request.ReferenceEntityId != null) {

docCode = request.ReferenceEntityId;

} else {

docCode = String.valueOf(

getRandomInteger(0, 2147483647)

);

}

commercetax.CalculateTaxResponse response =

new commercetax.CalculateTaxResponse();

if (request.isCommit == true) {

response.setStatus(

commercetax.TaxTransactionStatus.Committed

);

} else {

response.setStatus(

commercetax.TaxTransactionStatus.Uncommitted

);

}

response.setDocumentCode(docCode);

response.setReferenceDocumentCode(

request.referenceDocumentCode

);

response.setTaxType(type);

response.setStatusDescription(

'statusDescription'

);

response.setDescription('description');

response.setEffectiveDate(System.now());

if (request.transactionDate == null) {

response.setTransactionDate(System.now());

} else {

response.setTransactionDate(

request.transactionDate

);

}

if (request.taxTransactionType == null) {

response.setTaxTransactionType(

commercetax.TaxTransactionType.Debit

);

} else {

response.setTaxTransactionType(

request.taxTransactionType

);

}

if (String.isBlank(request.currencyIsoCode)) {

response.setCurrencyIsoCode('USD');

} else {

response.setCurrencyIsoCode(

request.currencyIsoCode

);

}

response.setReferenceEntityId(

request.ReferenceEntityId

);

String country = '';

String shippingState = '';

try {

if (request.ReferenceEntityId != null) {

Id refId = (Id) request.ReferenceEntityId;

String objectName = refId.getSObjectType()

.getDescribe()

.getName();

if (objectName == 'Quote') {

Quote q = [

SELECT ShippingCountry,

ShippingState

FROM Quote

WHERE Id = :refId

LIMIT 1

];

country = q.ShippingCountry;

shippingState = q.ShippingState;

}

else if (objectName == 'Order') {

Order o = [

SELECT ShippingCountry,

ShippingState

FROM Order

WHERE Id = :refId

LIMIT 1

];

country = o.ShippingCountry;

shippingState = o.ShippingState;

}

else if (objectName == 'Invoice') {

try {

List<InvoiceLine> lines = [

SELECT Id,

ShippingAddressId,

ShippingAddress.Country,

ShippingAddress.State

FROM InvoiceLine

WHERE InvoiceId = :refId

AND ShippingAddressId != null

ORDER BY Name ASC

LIMIT 1

];

if (!lines.isEmpty()

&& lines[0].ShippingAddress != null) {

country =

lines[0].ShippingAddress.Country;

shippingState =

lines[0].ShippingAddress.State;

} else {

}

} catch (Exception invoiceHeaderEx) {

}

}

else if (objectName == 'InvoiceLine') {

try {

InvoiceLine il = [

SELECT Id,

ShippingAddressId,

ShippingAddress.Country,

ShippingAddress.State

FROM InvoiceLine

WHERE Id = :refId

LIMIT 1

];

if (il.ShippingAddress != null) {

country =

il.ShippingAddress.Country;

shippingState =

il.ShippingAddress.State;

}

} catch (Exception invoiceEx) {

}

}

else {

}

}

} catch (Exception e) {

}

if (!String.isBlank(country)) {

country = country.trim().toLowerCase();

}

if (!String.isBlank(shippingState)) {

shippingState = shippingState.trim().toLowerCase();

}

Double totalTax = 0.0;

Double totalAmount = 0.0;

List<commercetax.LineItemResponse>

lineItemResponses =

new List<commercetax.LineItemResponse>();

Integer lineCounter = 0;

for (commercetax.TaxLineItemRequest lineItem :

request.lineItems) {

lineCounter++;

commercetax.AddressesResponse addressesRes =

new commercetax.AddressesResponse();

commercetax.AddressResponse addRes =

new commercetax.AddressResponse();

addRes.setLocationCode('locationCode');

addressesRes.setShipFrom(addRes);

addressesRes.setShipTO(addRes);

addressesRes.setSoldTo(addRes);

commercetax.LineItemResponse lineItemResponse =

new commercetax.LineItemResponse();

Double totalLineTax = 0;

List<commercetax.TaxDetailsResponse>

taxDetailsResponses =

new List<commercetax.TaxDetailsResponse>();

for (Integer i = 0; i < 1; i++) {

Double rate = 0.20;

if (country == 'india'

|| country == 'in') {

rate = 0.30;

}

else if (

country == 'usa'

|| country == 'us'

|| country == 'united states'

|| country ==

'united states of america'

) {

Double usaCountryRate = 0.40;

Double stateTaxRate = 0.00;

if (

shippingState == 'utah'

|| shippingState == 'ut'

) {

stateTaxRate = 0.02;

}

else if (

shippingState == 'south dakota'

|| shippingState == 'sd'

) {

stateTaxRate = 0.025;

}

else if (

shippingState == 'minnesota'

|| shippingState == 'mn'

) {

stateTaxRate = 0.03;

}

else if (

shippingState == 'north dakota'

|| shippingState == 'nd'

) {

stateTaxRate = 0.035;

}

else if (

shippingState == 'nebraska'

|| shippingState == 'ne'

) {

stateTaxRate = 0.04;

}

else if (

shippingState == 'new hampshire'

|| shippingState == 'nh'

) {

stateTaxRate = 0.045;

}

else if (

shippingState == 'idaho'

|| shippingState == 'id'

) {

stateTaxRate = 0.05;

}

else if (

shippingState == 'washington'

|| shippingState == 'wa'

) {

stateTaxRate = 0.055;

}

else if (

shippingState == 'vermont'

|| shippingState == 'vt'

) {

stateTaxRate = 0.06;

}

rate =

usaCountryRate +

stateTaxRate;

}

else {

}

Double taxableAmount = lineItem.amount;

commercetax.TaxDetailsResponse

taxDetailsResponse =

new commercetax.TaxDetailsResponse();

taxDetailsResponse.setRate(rate);

taxDetailsResponse.setTaxableAmount(

taxableAmount

);

Double tax =

taxableAmount * rate;

totalLineTax += tax;

taxDetailsResponse.setTax(tax);

taxDetailsResponse.setExemptAmount(0);

taxDetailsResponse.setExemptReason(

'exemptReason'

);

taxDetailsResponse.setTaxRegionId(

'taxRegionId'

);

taxDetailsResponse.setTaxId(

String.valueOf(

getRandomInteger(

0,

2323233

)

)

);

taxDetailsResponse.setSerCode(

'serCode'

);

taxDetailsResponse.setTaxAuthorityTypeId(

'taxAuthorityTypeId'

);

commercetax.ImpositionResponse imposition =

new commercetax.ImpositionResponse();

imposition.setSubType('subtype');

imposition.setType('type');

taxDetailsResponse.setImposition(

imposition

);

commercetax.JurisdictionResponse jurisdiction =

new commercetax.JurisdictionResponse();

jurisdiction.setCountry(country);

jurisdiction.setRegion('region');

jurisdiction.setName('name');

jurisdiction.setStateAssignedNumber(

'stateAssignedNo'

);

jurisdiction.setId('id');

jurisdiction.setLevel('level');

taxDetailsResponse.setJurisdiction(

jurisdiction

);

taxDetailsResponses.add(

taxDetailsResponse

);

}

lineItemResponse.setTaxes(

taxDetailsResponses

);

totalTax += totalLineTax;

totalAmount += lineItem.amount;

commercetax.AmountDetailsResponse amountResponse =

new commercetax.AmountDetailsResponse();

amountResponse.setTotalAmountWithTax(

totalTax + totalAmount

);

amountResponse.setExemptAmount(0);

amountResponse.setTotalAmount(

totalAmount

);

amountResponse.setTaxAmount(

totalTax

);

lineItemResponse.setAmountDetails(

amountResponse

);

lineItemResponse.setEffectiveDate(

System.now()

);

lineItemResponse.setTaxCode(

lineItem.taxCode

);

lineItemResponse.setProductCode(

lineItem.ProductCode

);

lineItemResponse.setLineNumber(

lineItem.linenumber

);

lineItemResponse.setIsTaxable(true);

lineItemResponse.setQuantity(

lineItem.quantity

);

lineItemResponse.setAddresses(

addressesRes

);

lineItemResponses.add(

lineItemResponse

);

}

response.setLineItems(

lineItemResponses

);

commercetax.AmountDetailsResponse

headerAmountResponse =

new commercetax.AmountDetailsResponse();

headerAmountResponse.setTotalAmountWithTax(

totalTax + totalAmount

);

headerAmountResponse.setExemptAmount(0);

headerAmountResponse.setTotalAmount(

totalAmount

);

headerAmountResponse.setTaxAmount(

totalTax

);

response.setAmountDetails(

headerAmountResponse

);

commercetax.AddressesResponse headerAddresses =

new commercetax.AddressesResponse();

commercetax.AddressResponse headerAddRes =

new commercetax.AddressResponse();

headerAddRes.setLocationCode(

'locationCode'

);

headerAddresses.setShipFrom(

headerAddRes

);

headerAddresses.setShipTO(

headerAddRes

);

headerAddresses.setSoldTo(

headerAddRes

);

response.setAddresses(

headerAddresses

);

return response;

}

return null;

}

public static Integer getRandomInteger(

Integer min,

Integer max

) {

return min +

(Integer.valueOf(Math.random()) *

(max - min));

}

}

0/9000

Asset Creation API

 

Asset Creation Link

 

API Information:

 

ENDPOINT URL 

 

/services/data/v66.0/composite

 

METHOD: 

POST

 

 

MESSAGE BODY:

 

 

{

"allOrNone": true,

"compositeRequest": [

{

"method": "POST",

"url": "/services/data/v66.0/sobjects/Asset",

"referenceId": "refAsset1",

"body": {

"AccountId": "001f600000dZWxvAAG",

"Name": "Google Workspace",

"Product2Id": "01tf6000004GVNnAAO",

"ContactId": "003f600000JX730AAD",

"HasLifecycleManagement": true,

"LifecycleStartDate": "2026-01-01T00:00:00.000+0000",

"LifecycleEndDate": "2026-12-31T00:00:00.000+0000",

"CurrentMRR": 250,

"CurrentQuantity": 10,

"TotalLifecycleAmount": 3000

}

},

{

"method": "POST",

"url": "/services/data/v66.0/sobjects/AssetAction",

"referenceId": "refAA1",

"body": {

"AssetId": "@{refAsset1.id}",

"Type": "Generate",

"CategoryEnum": "Initial Sale",

"ActionDate": "2026-01-01T00:00:00.000+0000",

"quantityChange": 10,

"mrrChange": 250,

"amount": 12000,

"TotalInitialSaleAmount": 3000,

"TotalMrr": 250

}

},

{

"method": "POST",

"url": "/services/data/v66.0/sobjects/AssetStatePeriod",

"referenceId": "refASP1",

"body": {

"AssetId": "@{refAsset1.id}",

"startDate": "2026-01-01T00:00:00.000+0000",

"endDate": "2026-12-31T23:59:59.000+0000",

"quantity": 10,

"amount": 0,

"mrr": 250

}

},

{

"method": "POST",

"url": "/services/data/v66.0/sobjects/AssetActionSource",

"referenceId": "refAAS1",

"body": {

"AssetActionId": "@{refAA1.id}",

"transactionDate": "2026-01-01T00:00:00.000+0000",

"adjustmentAmount": 0,

"productAmount": 3000,

"estimatedTax": 0,

"actualTax": 0,

"startDate": "2026-01-01T00:00:00.000+0000",

"endDate": "2026-12-31T00:00:00.000+0000",

"quantity": 10

}

}

]

}

0/9000

We have a product rule set up as follows in Sandbox and Production. Below is the Current Product Rule Configuration.  

 

Product Rule Header: 

  • Type=Selection 
  • Conditions Met = All 
  • Scope = Product 
  • Evaluation Event = Always 
  • Evaluation Order = 10 

Error Condition: 

  • Tested Object = Quote 
  • Tested Field = Boost = True
  • Operator = equals 
  • Filter Type = Value
  •  Filter Value = TRUE 

Price Action 1

  • Product = Product A 
  • Type = Enable 

Price Action 2

  • Product = Product B 
  • Type: Enable & Add 

Price Action 3

  • Product = Product C 
  • Type = Enable & Add 
  • Required = True 

Price Action 4

  • Product = Product C 
  • Type = Hide 

Configuration Rule

:  

Product = Bundle 1  

 

Results in the Configurator

 

In Sandbox the following is occurring in the Configurator:

  • Product A is not appearing
  • Product B is not appearing
  • Product C is appearing and checked

In Production the following is occurring in the Configurator:

  • Product A is appearing
  • Product B is appearing and checked
  • Product C is not appearing

What the Sales team would like to have happen is:

  • Product A is appearing
  • Product B is appearing and checked
  • Product C is appearing and checked

What correction needs to happen to get this to occur? At a minimum I would think I would delete Product Action 4. 

 

Thank you. 

Rachel 

 

#Salesforce CPQ & Billing  #CPQ @* Salesforce Revenue Cloud *

1 件の回答
  1. 9月6日 2:36

    Your instinct to delete Price Action 4 is right, and here's why it's likely the actual root cause of the environment difference, not just a cleanup step. 

    You have two Product Actions targeting the same product (Product C) within one rule, with directly contradictory outcomes: Action 3 says Enable & Add + Required, Action 4 says Hide. Unlike Product Rules themselves (which have an explicit Evaluation Order field to control which rule "wins" when multiple rules affect the same product), individual Product Actions within a single rule don't have a documented, configurable sequence field in the UI. When two actions in the same rule conflict like this, which one is applied can come down to internal record creation order - and if this rule was built independently in Sandbox and in Production (rather than deployed as a single unit via change set/package that preserves record order), it's entirely plausible the two environments evaluate Action 3 vs. Action 4 in a different order, which would produce exactly the opposite behavior you're seeing on Product C between the two orgs. 

    Given the outcome the Sales team actually wants — Product C appearing and checked — the fix is straightforward: delete Price Action 4 (Hide on Product C) entirely, and keep only Price Action 3 (Enable & Add, Required) for Product C. That removes the ambiguity rather than relying on action-order behavior that isn't guaranteed to be consistent across orgs. 

    One more thing worth confirming before you conclude it's purely a config issue: since Product A and B's behavior also flipped between environments (not just C), double-check that the Quote.Boost__c field is actually set to TRUE in both orgs during your test — if the condition itself isn't evaluating the same way in both places (e.g., a default value difference on that field between Sandbox and Production data), that alone could explain the whole rule appearing to "not fire" in one environment before you even get to the Product C ordering issue.

0/9000

Hi everyone, Is there a way to populate the Quote field "Region__c" from the Account field "Region__c" using Context Definition only? 

I'm curious if this is achievable purely through Context Definition (without Flow or Apex) — has anyone done this before? Please help. 

Thanks! 

5 件の回答
  1. 9月4日 6:43

    @Manish Sharma

     

    Yes, it is possible using

    Context Definition alone. Map a context attribute such as Region from Account.Region__c through the Quote’s Account relationship to Quote.Region__c. No Flow or Apex is required. 

    For example: 

    Account.Region__c → Context Attribute (Region) → Quote.Region__c 

    Make sure the mapping uses supported matching data types and the context definition is active. 

0/9000

We're planning a large migration of legacy Asset records into Revenue Cloud and want to confirm we're not missing a bulk-friendly path. 

 

We've confirmed HasLifecycleManagement, LifecycleStartDate/EndDate, and the underlying AssetStatePeriod object are all read-only via standard DML - Data Loader/Bulk API reject any attempt to write them (INVALID_FIELD_FOR_INSERT_UPDATE). 

 

The only supported path we've found is the Connect REST API generate endpoint (asset-management/assets/actions/generate). It looks like a single-asset-per-call API with no bulk/batch equivalent, and the start date of the first asset state period is locked once the call completes. 

 

Has anyone done a large historical Asset migration into lifecycle management this way? Curious about: 

- Whether a bulk-friendly path exists that we're missing 

- Realistic call volumes/patterns others have used against the generate endpoint 

- Whether it's common practice to leave older/inactive assets non-lifecycle-managed and only onboard active ones 

 

  1. Appreciate any recommendations.

#Revenue Cloud

3 件の回答
  1. 8月30日 15:44

    we did it using PST api. the approach here is to bulk create Order using PST and then activate the Order, it will create Asset lifecycle managed records automatically, this is will give audit history as well.  

    PST api supports bulk record creation (1500 records in a single api call).

0/9000

Hi everyone, 

I'm currently working on attribute-based pricing in Salesforce Revenue Cloud and came across a scenario I'd like some guidance on. 

For example, I have an attribute called Color. If Color = Blue, I want to apply a 5% discount. This pricing rule should apply to every product in my product catalog. 

Using Price Adjustment Schedules , the pricing adjustment is tied to a specific product. This works well for a small catalog, but in a large product catalog with thousands of products, creating and maintaining separate Price Adjustment Schedules for each product is time-consuming and difficult to manage. 

Is there a way to define the pricing logic once and have it apply to all products instead of configuring it product by product? 

I'd appreciate any suggestions or best practices. Thanks!   

 

@* Salesforce Revenue Cloud * 

2 件の回答
  1. 9月2日 20:43

    For something like this id recommend using the Pre hook to write the Attribute value say "Colour" to a "Colour" Field on the quote line. 

     

    You could then add into your pricing procedure to add a 5% discount if that colour field = "Blue"

0/9000