如何使用Apex开发批量更新任务以实现合同Uplift操作?
Apex入门与Batch Apex实现方案
一、Apex开发入口
- 登录Salesforce后台,进入Setup,在快速搜索框输入
Developer Console,点击进入即可编写、调试Apex代码,这是最基础的开发入口。 - 习惯用IDE的话,安装VS Code并搭配Salesforce Extension Pack插件,配置好组织连接后,能更高效地写代码、部署和排查问题。
二、Apex入门路径(针对Java开发者)
- 先梳理Apex与Java的核心差异:Apex是强类型语言但基于SObject数据模型,用SOQL/SOSL查询数据,自带批处理、触发器等Salesforce专属机制,优先看官方基础文档快速掌握这些特性。
- 从匿名代码块练手:比如查询几条Account记录、做简单的SObject增删改,快速熟悉Salesforce的数据结构。
- 重点理解Batch Apex的核心规则:必须实现
Database.Batchable<SObject>接口,包含start(查询待处理数据)、execute(处理批次数据)、finish(收尾操作)三个核心方法。
三、需求对应的Batch Apex实现
核心逻辑
筛选出Uplift_Start_Date__c与StartDate间隔正好10个月的合同,为其生成修订报价;调整报价行项(旧行项数量设0、结束日期设为Uplift Start Date;新增行项沿用原产品/结束日期、起始日期设为Uplift Start Date);最后跳过验证完成报价。
代码实现
global class ContractUpliftBatch implements Database.Batchable<SObject>, Database.Stateful { // 定义查询逻辑,筛选符合条件的合同 global Database.QueryLocator start(Database.BatchableContext bc) { String soql = 'SELECT Id, StartDate, Uplift_Start_Date__c, Uplift_Date__c, AccountId, ContractNumber ' + 'FROM Contract ' + 'WHERE Uplift_Start_Date__c = ADD_MONTHS(StartDate, 10) ' + 'AND Uplift_Start_Date__c != NULL AND StartDate != NULL'; return Database.getQueryLocator(soql); } // 处理每个批次的合同数据 global void execute(Database.BatchableContext bc, List<Contract> contractList) { List<Quote> newAmendmentQuotes = new List<Quote>(); List<QuoteLineItem> oldQLIUpdates = new List<QuoteLineItem>(); List<QuoteLineItem> newQLICreates = new List<QuoteLineItem>(); // 收集合同ID,批量查询关联的原报价行项 Set<Id> contractIds = new Set<Id>(); for(Contract c : contractList) { contractIds.add(c.Id); } // 注意:此处关联关系需根据实际数据模型调整,比如Quote与Contract的关联字段 List<QuoteLineItem> originalQLIs = [SELECT Id, QuoteId, Product2Id, Quantity, StartDate, EndDate, UnitPrice, Quote.ContractId__c FROM QuoteLineItem WHERE Quote.ContractId__c IN :contractIds]; // 为每个符合条件的合同创建修订报价 for(Contract c : contractList) { Quote amendmentQuote = new Quote(); amendmentQuote.ContractId__c = c.Id; // 替换为实际的合同关联字段API名 amendmentQuote.AccountId = c.AccountId; amendmentQuote.Name = 'Amendment - ' + c.ContractNumber; amendmentQuote.Amendment_Date__c = c.Uplift_Date__c; amendmentQuote.Status = 'Draft'; newAmendmentQuotes.add(amendmentQuote); } // 插入新报价,获取ID用于后续行项关联 if(!newAmendmentQuotes.isEmpty()) { insert newAmendmentQuotes; } // 构建合同到新报价的映射,方便后续处理 Map<Id, Quote> contractToQuoteMap = new Map<Id, Quote>(); for(Quote q : newAmendmentQuotes) { contractToQuoteMap.put(q.ContractId__c, q); } // 处理报价行项:更新旧行项,创建新行项 for(QuoteLineItem originalQLI : originalQLIs) { Quote targetQuote = contractToQuoteMap.get(originalQLI.Quote.ContractId__c); if(targetQuote == null) continue; // 更新原行项:数量设0,结束日期设为Uplift Start Date QuoteLineItem updatedQLI = new QuoteLineItem(Id = originalQLI.Id); updatedQLI.Quantity = 0; updatedQLI.EndDate = targetQuote.ContractId__r.Uplift_Start_Date__c; oldQLIUpdates.add(updatedQLI); // 创建新行项:沿用原产品、价格、结束日期,起始日期设为Uplift Start Date QuoteLineItem newQLI = new QuoteLineItem(); newQLI.QuoteId = targetQuote.Id; newQLI.Product2Id = originalQLI.Product2Id; newQLI.Quantity = originalQLI.Quantity; newQLI.StartDate = targetQuote.ContractId__r.Uplift_Start_Date__c; newQLI.EndDate = originalQLI.EndDate; newQLI.UnitPrice = originalQLI.UnitPrice; newQLICreates.add(newQLI); } // 批量更新和插入行项 if(!oldQLIUpdates.isEmpty()) { update oldQLIUpdates; } if(!newQLICreates.isEmpty()) { insert newQLICreates; } // 跳过验证完成报价 List<Quote> quotesToFinalize = new List<Quote>(); for(Quote q : newAmendmentQuotes) { Quote finalQuote = new Quote(Id = q.Id); finalQuote.Status = 'Approved'; // 替换为实际的完成状态值 quotesToFinalize.add(finalQuote); } if(!quotesToFinalize.isEmpty()) { Database.update(quotesToFinalize, false); // false表示跳过验证规则 } } // 收尾方法,可选:比如发送批处理结果通知 global void finish(Database.BatchableContext bc) { AsyncApexJob jobInfo = [SELECT Id, Status, NumberOfErrors, TotalJobItems FROM AsyncApexJob WHERE Id = :bc.getJobId()]; // 此处可添加邮件通知逻辑,比如发给管理员告知任务状态 } }
关键注意点
- 所有自定义字段的API名称(如
Uplift_Start_Date__c)需替换为你实际环境中的字段名,可在Setup的字段详情页查看。 - 合同与Quote的关联关系要根据业务模型调整,代码中
Quote.ContractId__c为假设的关联字段,若结构不同需修改SOQL和赋值逻辑。 Database.update(..., false)会跳过验证规则,生产环境需谨慎使用,建议先在沙盒测试确认不会破坏业务规则。- 必须编写测试类覆盖至少75%的代码才能部署到生产环境,测试类需模拟符合条件的合同、报价行项,执行批处理并验证结果是否符合预期。
四、运行Batch Apex的方式
在Developer Console的匿名窗口中执行以下代码:
ContractUpliftBatch batchJob = new ContractUpliftBatch(); Database.executeBatch(batchJob, 200); // 200为每个批次的记录数,可根据需求调整
执行后,可在Setup的Apex Jobs中查看任务运行状态。
内容的提问来源于stack exchange,提问作者Symbiote Scorns
相关产品推荐
相关产品推荐

