Loading
学习
目录
选择筛选器

          没有结果
          没有结果
          以下是一些搜索提示

          检查关键字的拼写。
          使用更普遍的搜索词。
          选择更少的筛选器,并扩大搜索范围。

          搜索所有 Salesforce 帮助
          使用程序计划框架

          使用程序计划框架

          为了确保您的程序以正确的顺序运行,并且定价一致地应用于报价,请创建新的程序计划。

          所需的 Edition

          适用于:Lightning Experience
          适用于:启用了 Salesforce 定价的 Revenue Cloud 的 EnterprisePerformanceUnlimitedDeveloper Edition
          所需用户权限
          创建和更新手术计划定义:

          程序计划访问权限

          Salesforce 定价设计时间用户

          创建、更新和删除定价程序:

          程序计划访问权限

          或者

          Salesforce 定价设计时间用户

          要使用定价程序: Salesforce 定价运行时用户
          定义、编辑、删除和设置 Apex 类的版本设置: 作者 Apex

          想象一下,您在一家航空公司工作,为商务旅客提供帮助。现在,让我们预订航班!我们希望我们的定价反映实时市场状况,并以客户的当地货币显示价格。

          在计算价格之前,我们会自动从外部系统获取动态基本票价,以确保定价具有竞争力。我们还将应用预订平台的折扣,并添加便利费。

          在我们构建手术计划后,我们将创建报价。然后,根据用户的位置(例如,印度),我们将总价从美元转换为印度卢比。

          在开始前,请确保:

          • 已启用 Salesforce 定价。
          • 拥有创建程序、程序计划、产品和报价的权限。
          • 了解如何创建定价程序。要了解有关定价程序的更多信息,请参阅使用 Salesforce 定价构建定价程序
          • 了解并知道如何使用上下文定义。要了解有关上下文定义的更多信息,请参见上下文定义
          • 在您的定价程序和程序计划中使用相同的上下文定义。

          程序计划定义可能很复杂,特别是当它们涉及 Apex 类和不同的定价程序时。按照这些步骤创建报价,并了解如何使定价动态准确,而不使过程本身复杂化。

          为定价打开程序计划编排

          1. 从“设置”中,在快速查找框中输入收入设置,然后选择收入设置
          2. 查找并启用定价程序计划编排
          3. 查找并启用排除默认和销售交易类型定价程序

          创建商业产品

          1. 从应用程序启动程序中,查找并选择产品
          2. 创建名为 Delhi - New York 的商业产品。
            要了解如何创建产品,请查看创建简单产品,并确保产品记录类型设置为商业
          3. 将产品添加到目录,并为其创建价格手册条目。
          4. 从“设置”中,在快速查找框中,搜索并选择 Salesforce 定价设置
          5. 在“同步定价数据”部分,单击同步

          构建定价程序

          1. 创建定价程序,并将其命名为航班预订定价程序
            要创建定价程序,请按照配置定价程序中的前 5 步操作。
          2. 创建常量。这些常量将作为定价程序中固定值的占位符。
            常量名称 数据类型 默认值
            AdjType TEXT 百分比
            AdjValue NUMBER 5
            覆盖 TEXT 覆盖
            ConvFeeAdjType TEXT 金额
            ConvFeeAdjValue NUMBER -250
          3. 添加以下元素。
            1. 定价设置
            2. 价目表价格。使用价格手册条目 V2 决策表。
            3. 手动折扣。您需要添加三个手动折扣元素。
          4. 添加第一个手动折扣元素来计算航班的动态基本票价。映射这些变量。
            • 输入变量
              • 调整类型:覆盖
              • 调整值:PartnerUnitPrice
              • 数量:LineItemQuantity
              • 输入单价:价目表价格
            • 输出变量
              • 净单价:NetUnitPrice
          5. 添加第二个手动折扣元素来计算航班预订的平台折扣。映射这些变量。
            • 输入变量
              • 调整类型:AdjType
              • 调整值:AdjValue
              • 数量:LineItemQuantity
              • 输入单价:PartnerUnitPrice
            • 输出变量
              • 净单价:NetUnitPrice
          6. 添加最后一个手动折扣元素来计算向客户收取的航班预订便利费。
            • 输入变量
              • 调整类型:ConvFeeAdjType
              • 调整值:ConvFeeAdjValue
              • 数量:LineItemQuantity
              • 输入单价:NetUnitPrice
            • 输出变量
              • 净单价:NetUnitPrice
          7. 设置首选项,以查看定价信息、简档访问权限和排名信息。
          8. 保存您的程序。
          9. 激活您的程序。

          您的程序应该如下所示。为清楚起见,我们重命名了每个手动折扣元素,以显示它将执行的定价计算。要重命名元素,单击 编辑图标并输入所需的名称。

          程序计划的定价程序

          定义 Apex 钩子的类

          1. 从“设置”的“快速查找”框中,输入Apex,然后选择 Apex 类
          2. 单击新建
          3. 第一个 Apex 类是一个预挂钩,它从定价上下文中获取所有销售交易项目,并在从外部数据库执行定价之前,用 990 到 1200 之间的动态随机基本票价覆盖它们的 PartnerUnitPrice 标签。
            public class DynamicFlightBasePriceApex implements RevSignaling.SignalingApexProcessor {
            
                public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                    System.debug('Executing PREHOOK');
                    String contextId = request.ctxInstanceId;
                    Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                    
                    //Query SalesTransactionItem nodes
                    Map<String, Object> inputQueryItem = new Map<String, Object>{
                        'contextId' => contextId,
                            'tags' => new List<String>{ 'SalesTransactionItem' }
                    };
                    Map<String, Object> itemQueryOutput = industriesContext.queryTags(inputQueryItem);
                    Map<String, Object> itemQueryResult = (Map<String, Object>)itemQueryOutput.get('queryResult');
                    List<Object> itemData = (List<Object>) itemQueryResult.get('SalesTransactionItem');
                    System.debug('QLI itemData=' + itemData);
            
                    // Generate random price between 990 and 1200
                    Decimal minPrice = 990;
                    Decimal maxPrice = 1200;
                    Decimal range = maxPrice - minPrice;
            
                    // Use Crypto.getRandomInteger() to generate a secure random number
                    Integer randomInt = Math.abs(Crypto.getRandomInteger());
                    Decimal randomPrice = minPrice + Math.mod(randomInt, range.intValue() + 1);
            
                    System.debug('Generated Random Price: ' + randomPrice);
                    
                    // STEP 3 - Build update list
                    List<Map<String, Object>> itemNodeUpdates = new List<Map<String, Object>>();
                    for (Object itemObj : itemData) {
                        Map<String, Object> itemNode = (Map<String, Object>) itemObj;
                        List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
                        System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
            			dataPath.remove(0); // Remove contextId
            			itemNodeUpdates.add(new Map<String, Object>{
                            'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                            'attributes' => new List<Object>{
                                new Map<String, Object>{
                                    'attributeName' => 'PartnerUnitPrice',
                                    'attributeValue' => randomPrice
                               }
                            }
                        });
                    }
                           
                    // STEP 4 - Submit context update
                    if (!itemNodeUpdates.isEmpty()) {
                        Map<String, Object> updateInput = new Map<String, Object>{
                            'contextId' => contextId,
                            'nodePathAndAttributes' => itemNodeUpdates
                        };
                        System.debug('--- PREHOOK: SUBMITTING CONTEXT UPDATE ---');
                        System.debug(JSON.serializePretty(updateInput));
                        industriesContext.updateContextAttributes(updateInput);
                    }
            
                    // Return the response
                    RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
                    response.status = RevSignaling.TransactionStatus.SUCCESS;
                    response.message = 'Apex executed successfully with Random Price: ' + randomPrice;
                    return response;
                }
            }
            
          4. 创建其他 Apex 类。
            该 Apex 类是一个挂钩后,它在定价后获取 NetUnitPrice 标签,并使用 85-86 之间的模拟动态兑换率将其转换为本地货币 INR(印度卢比)。然后,它使用新的 INR 票价更新销售交易项目描述,为印度客户提供本地化定价可见性。
            public class ConvertFareToINRApex implements RevSignaling.SignalingApexProcessor {
            
                public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                    System.debug('Executing POSTHOOK');
                    String contextId = request.ctxInstanceId;
                    Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                    
                    //Query SalesTransactionItem nodes
                    Map<String, Object> inputQueryItem = new Map<String, Object>{
                        'contextId' => contextId,
                            'tags' => new List<String>{ 'SalesTransactionItem' }
                    };
                    Map<String, Object> itemQueryOutput = industriesContext.queryTags(inputQueryItem);
                    Map<String, Object> itemQueryResult = (Map<String, Object>)itemQueryOutput.get('queryResult');
                    List<Object> itemData = (List<Object>) itemQueryResult.get('SalesTransactionItem');
                    System.debug('QLI itemData=' + itemData);
                    
                    //Query NetUnitPrice nodes
                    Map<String, Object> inputQueryItem2 = new Map<String, Object>{
                        'contextId' => contextId,
                            'tags' => new List<String>{ 'NetUnitPrice' }
                    };
                    Map<String, Object> itemQueryOutput2 = industriesContext.queryTags(inputQueryItem2);
                    Map<String, Object> itemQueryResult2 = (Map<String, Object>)itemQueryOutput2.get('queryResult');
                    List<Object> itemData2 = (List<Object>) itemQueryResult2.get('NetUnitPrice');
                    System.debug('NetUnitPrice itemData=' + itemData2);
                    Map<String, Object> netUnitTagData = (Map<String, Object>) itemData2.get(0);
                    Decimal netUnitPrice = (Decimal) netUnitTagData.get('tagValue');
                    netUnitPrice = netUnitPrice.setScale(2);
                    System.debug('NetUnitPrice Tag Value=' + netUnitPrice);
            
                    // Generate random price between 85.00 and 86.00 with decimals
                    Decimal minPrice = 85.00;
                    Decimal maxPrice = 86.00;
                    Decimal range = maxPrice - minPrice; 
                    Integer randomInt = Math.abs(Crypto.getRandomInteger());
                    Integer randomDecimalInt = Math.mod(randomInt, 100);
                    Decimal randomFraction = Decimal.valueOf(randomDecimalInt) / 100;
                    Decimal usdToInrRate = minPrice + randomFraction;
                    if (usdToInrRate > maxPrice) { 
                        usdToInrRate = maxPrice;
                    }
                    
                    // Calculate NetUnitPrice in INR
                    Decimal fareInInr = (netUnitPrice * usdToInrRate).setScale(2);
                    
                    String fareMessage = 'The Flight fare in INR is: ' + fareInInr + 
                                 ' (USD ' + netUnitPrice + 
                                 ' at rate ' + usdToInrRate + ')';
                    System.debug(fareMessage);
                    
                    // STEP 3 - Build update list
                    List<Map<String, Object>> itemNodeUpdates = new List<Map<String, Object>>();
                    for (Object itemObj : itemData) {
                        Map<String, Object> itemNode = (Map<String, Object>) itemObj;
                        List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
                        System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
            			dataPath.remove(0); // Remove contextId
            			itemNodeUpdates.add(new Map<String, Object>{
                            'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                            'attributes' => new List<Object>{
                                new Map<String, Object>{
                                    'attributeName' => 'SalesTrxnItemDescription',
                                    'attributeValue' => fareMessage
                               }
                            }
                        });
                    }
                        
                    
                    // STEP 4 - Submit context update
                    if (!itemNodeUpdates.isEmpty()) {
                        Map<String, Object> updateInput = new Map<String, Object>{
                            'contextId' => contextId,
                            'nodePathAndAttributes' => itemNodeUpdates
                        };
                        System.debug('--- PREHOOK: SUBMITTING CONTEXT UPDATE ---');
                        System.debug(JSON.serializePretty(updateInput));
                        industriesContext.updateContextAttributes(updateInput);
                    }
            
                    // Return the response
                    RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
                    response.status = RevSignaling.TransactionStatus.SUCCESS;
                    response.message = 'Apex executed successfully with Price in INR: ' + fareInInr;
                    return response;
                }
            }
            

          配置自定义程序计划定义

          1. 从“设置”中,在快速查找框中,搜索并选择程序计划定义
          2. 单击新建
          3. 指定这些详细信息。
            1. 标题: 航班预订程序计划
              按 Tab 键,以自动填充开发人员姓名。
            2. 进程类型: Revenue Cloud
            3. 主对象:报价
            4. 上下文定义:<上下文定义名称>
              您需要选择专为用例设计的上下文定义。但是,请确保这与您在构建定价程序时使用的上下文定义相同。
            5. 保存更改。
          4. 打开新创建的程序计划定义记录。
          5. 要在“程序计划”部分添加所需的程序,请选择添加
          6. 添加第一部分,以获取航班的动态基本价格。指定这些详细信息。
            1. 类型:标准
            2. 名称:DynamicBasePriceApex
            3. 部分类型: Apex
            4. 添加部分后,单击箭头图标并指定这些详细信息。
              1. 阶段:定价
              2. 分辨率类型:默认
              3. Apex: DynamicFlightBasePriceApex
              它看起来应该是这样的:
              程序计划部分
          7. 同样,添加另一个部分来执行定价计算,并使用我们使用 Apex 预挂钩生成的价格覆盖基本价格。指定这些值。
            1. 类型:标准
            2. 名称:FlightPriceCalculation
            3. 部分类型:定价程序
            4. 单击箭头图标并指定这些详细信息。
              1. 阶段:定价
              2. 分辨率类型:默认
              3. 程序:Flight_Booking_Pricing_Procedure
          8. 最后,通过为开单国家/地区设置为印度的用户添加此 Apex Posthook,添加将价格从美元转换为印度卢比的部分
            1. 类型:标准
            2. 名称:ConvertFareToINR
            3. 部分类型: Apex
            4. 单击箭头图标并指定这些详细信息。
              1. 阶段:定价
              2. 分辨率类型:基于规则
              3. 条件要求:满足所有条件 (AND)
              4. 资源:开单地址
              5. 运算符:等于
              6. 输出值:印度
              7. Apex: ConvertFareToINRApex
          9. 保存,然后激活手术计划定义。

          验证您的程序计划执行情况

          为了验证手术计划是否按照我们设置的顺序执行,以及定价是否正确,我们需要创建报价。

          1. 创建报价
            在开单地址国家/地区字段中,输入印度
          2. 保存更改。
          3. 单击浏览目录,并将德里 - 纽约产品添加到报价。
          4. 将鼠标悬停在净单价值上,以查看价格瀑布图详细信息。
            您将看到程序计划的应用,以及您在定价程序中配置的折扣和附加。
            报价价格瀑布图
          5. 要查看报价行项目的兑换率,单击报价行项目行查看图标中的 ,然后选择查看
          6. 行项目描述显示航班的本地化价格。
            报价行项目描述
           
          正在加载
          Salesforce Help | Article