我正在尝试更新现有代码(由其他人编写,我不是开发人员-只是想帮助朋友),以便它使用“文件”而不是旧的“附件”。
触发条件是:当Opportunity满足标准时,发送电子邮件并包含Opportunity中的相关文件。
当我测试它时,我得到以下错误:sendAttachments:执行AfterUpdate,原因是:System。VisualforceException:目前不支持从触发器中获取内容。Trigger.send附件:第172行,第1列
我在谷歌搜索中发现,如果在方法之前使用“@future(callout=true)”注释,则可以解决此问题。不管我把它放在代码的什么地方,我都不能让它编译时没有错误。想知道是不是因为逻辑都在触发器中而不是类中?非常感谢您的帮助。
这是代码:
trigger sendAttachments on Opportunity (after update,after insert) {
for(Opportunity opp : trigger.new){
if(opp.Ready_for_Billing__c == true && opp.SenttoBilling__c == false){
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
opp = [SELECT id, account.name,account.parent.name, bundledamt__c,SO_Number__c, IO_Number__c, OwnerId, Type, Contract_Start_Date__c, Expiration_Date__c,
Is_Insertion_Order__c, StageName, Note_to_Billing__c, Purchase_Order_Number__c,Billing_Country__c, Billing_Contact__c, Billing_Address__c, Bill_Email__c, Name FROM Opportunity WHERE Id = :opp.Id];
User u = [SELECT FirstName, LastName, Email FROM User WHERE Id = :opp.OwnerId];
Contact DC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'Delivery-Invoices'];
Contact MC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'Media-Invoices'];
Contact CC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'CC-Invoices'];
String Name;
if (opp.Is_Insertion_Order__c == True){
Name = opp.IO_Number__c;
}
else{
Name = opp.SO_Number__c;
}
String AccName = opp.account.name;
String subject;
String repname = u.FirstName + ' ' + u.LastName;
String ordertype;
String owneremail = u.Email;
String notes = opp.Note_to_Billing__c;
String othernotes;
if( (opp.Billing_Country__c == 'India') || (opp.Billing_Country__c == 'Egypt')||(opp.Billing_Country__c == 'China')||(opp.Billing_Country__c == 'Pakistan' ) ||
(opp.Billing_Country__c == 'Indonesia') || (opp.Billing_Country__c == 'Viet Nam')||(opp.Billing_Country__c == 'Thailand')||(opp.Billing_Country__c == 'Malaysia' ) ||
(opp.Billing_Country__c == 'United Arab Emirates') || (opp.Billing_Country__c == 'Singapore')||(opp.Billing_Country__c == 'Poland')||(opp.Billing_Country__c == 'Romania' )){
othernotes = 'IMPORTANT: Note that invoice is going to a country that may withhold taxes. Refer to history'+'\r\n';
}else{
othernotes = '';
}
// create email content
if (opp.Type == null){
ordertype = 'Not Available';
}
else{
ordertype = opp.Type;
}
String contractdates;
if (opp.Contract_Start_Date__c == null){
if(opp.Expiration_Date__c == null){
contractdates = 'Not Available';
}
else{
contractdates = 'Expiration date - '+ opp.Expiration_Date__c.month()+ '/' + opp.Expiration_Date__c.day() +'/' +opp.Expiration_Date__c.year();
}
}
else{
if(opp.Expiration_Date__c == null){
contractdates = 'Start Date - ' + opp.Contract_Start_Date__c.month()+'/'+opp.Contract_Start_Date__c.day()+'/'+ opp.Contract_Start_Date__c.year();
}
else{
contractdates = opp.Contract_Start_Date__c.month()+'/'+opp.Contract_Start_Date__c.day()+'/'+ opp.Contract_Start_Date__c.year()+' - ' + opp.Expiration_Date__c.month()+'/'+opp.Expiration_Date__c.day()+'/'+opp.Expiration_Date__c.year();
}
}
subject = 'Ready for Billing: SO/IO '+Name+ ' for ' + AccName;
List<String> ccaddress;
if (CC != Null){
ccaddress = new List<String>{CC.Email, owneremail};
}
Else{
ccaddress = new List<String>{owneremail};
}
email.setSubject(subject);
String salutation = 'Hello Accounting, '+ '\r\n'+ '\r\n';
String line1 = 'A New order is ready to be billed: '+ '\r\n';
String line2;
if (opp.Is_Insertion_Order__c == False){
line2 = ' SO #: ' + Name + '\r\n';
}
else{
line2 = ' IO #: ' + Name + '\r\n';
}
String line3 = ' Account: '+AccName+ '\r\n';
String line4;
if (opp.Is_Insertion_Order__c == False){
line4 = ' Order Type (renewal/upsell/new): '+ ordertype + '\r\n';
}
else{
line4 = '\r\n';
}
String line5 = ' Contract Dates: '+ contractdates + '\r\n'+ '\r\n';
String line6 = '\r\n'+ '\r\n'+ 'Regards,' + '\r\n';
String line7 = repname + '\r\n' + '\r\n';
String body = salutation + line1 + line2 + line3 + line4+ line5;
string BillingNotes;
string BillingNotes2;
if (opp.Is_Insertion_Order__c == True){
if ( opp.Purchase_Order_Number__c != Null){
BillingNotes2 = 'Include PO#: ' + opp.Purchase_Order_Number__c + '\r\n';
}
else{
BillingNotes2 ='\r\n';
}
if( opp.Billing_Contact__c != Null) {
Contact bc = [SELECT Name FROM Contact WHERE Id = :opp.Billing_Contact__c];
BillingNotes = 'Bill To: ' + bc.Name + '\r\n';
BillingNotes = BillingNotes + ' ' + opp.Bill_Email__c + '\r\n';
if ( opp.Purchase_Order_Number__c != Null){
BillingNotes = BillingNotes2 + BillingNotes;
}
}
if( opp.Billing_Address__c != Null) {
if( opp.Billing_Contact__c != Null){
BillingNotes = BillingNotes + ' ' + opp.Billing_Address__c.replaceAll('<br>',', ') + '\r\n' + '\r\n';
}
else {
BillingNotes = 'Billing Address: ' + opp.Billing_Address__c.replaceAll('<br>',', ') + '\r\n' + '\r\n';
}
}
else{
BillingNotes = BillingNotes + '\r\n' + '\r\n';
}
}
if (opp.Note_to_Billing__c != Null){
string cleannotes = opp.Note_to_Billing__c.replaceAll('<br>','\r\n');
cleannotes = cleannotes.replaceAll('<[^>]+>',' ');
if (BillingNotes != Null){
BillingNotes = othernotes + '\r\n' + BillingNotes + cleannotes;
}
else{
BillingNotes = othernotes + '\r\n' + cleannotes;
}
body = body + 'Notes: '+ '\r\n' + BillingNotes;
}
if (opp.bundledamt__c > 0){
OpportunityLineItem[] bundledItems = [SELECT Id, Opportunityid, PricebookEntry.Name, TotalPrice, Quantity, UnitPrice, Description, Bundled__c
from OpportunityLineItem where (Bundled__c =: 'Yes' AND Opportunityid =: opp.Id) ];
body = body + '\r\n' + '\r\n' + 'Breakdown of bundled products:' + '\r\n';
for (OpportunityLineItem oli : bundledItems){
body = body + oli.Quantity.round() + ' ' + oli.PricebookEntry.Name + ' (' + oli.Description + '); Price: ' + oli.UnitPrice+ '; Total: ' + oli.TotalPrice + '\r\n';
}
}
body = body + line6+ line7;
email.setPlainTextBody(body);
if(opp.Is_Insertion_Order__c == true){
email.setToAddresses(new String[]{MC.Email});
}
else if( opp.account.parent.name == 'XXX Group' && (opp.Contract_Start_Date__c.daysBetween(opp.Expiration_Date__c))<32) {
email.setToAddresses(new String[]{MC.Email});
}
else{
email.setToAddresses(new String[]{DC.Email});
}
email.setCcAddresses(ccaddress);
List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>();
PageReference pref = page.attachIOPDFforBilling;
/*for (Attachment a : [select Name, Body, BodyLength from Attachment where ParentId = :opp.Id]){
Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();*/
for (ContentDocumentLink a : [SELECT ContentDocumentId, LinkedEntityId FROM ContentDocumentLink where LinkedEntityId=: opp.id]){
Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();
//efa.setFileName(a.Title);
efa.setBody(pref.getContentAsPDF());
fileAttachments.add(efa);
}
email.setFileAttachments(fileAttachments);// Send email
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { email });
}
}
}
是的,这是因为它只是触发器中的一段代码。这与最佳实践背道而驰,理想情况下,您应该有一些处理程序类,其中包含逻辑的“肉”,触发器只有几行可以调用它。
如果您想尽可能少地更改,您仍然可以在1个文件中完成。这看起来绝对疯狂,但您可以在触发器中包含主代码并在其中定义方法。
对当前代码进行备份,并尝试使用类似于此的结构(我不是说它很完美,可能无法编译,可能有拼写错误。还有诸如“循环查询”(提取有关拥有此机会的用户的信息)之类的性能问题——它可能适用于单个记录,但如果您同时大量插入约20个opps,它会崩溃和烧毁......对不起,您可能需要一名程序员来正确完成它,并且可能需要一些美元来获得专业服务研究这段代码并决定什么是最好的。
trigger sendAttachments on Opportunity (after update,after insert) {
Set<Id> opportunitiesToSend = new Set<Id>();
for(Opportunity opp : trigger.new){
if(opp.Ready_for_Billing__c == true && opp.SenttoBilling__c == false){
opportunitiesToSend.add(opp.Id);
}
}
if(!opportunitiesToSend.isEmpty()){
sendEmails(opportunitiesToSend);
}
// it looks insane but it works, a method defined straight in a trigger.
// to do it properly - you should have another class you're calling
@future (callout=true)
static void sendEmails(Set<Id> opportunityIds){
Map<Id, Opportunity> opps = [SELECT id, account.name,account.parent.name,
bundledamt__c,SO_Number__c, IO_Number__c, OwnerId, Type, Contract_Start_Date__c,
Expiration_Date__c, Is_Insertion_Order__c, StageName, Note_to_Billing__c,
Purchase_Order_Number__c,Billing_Country__c, Billing_Contact__c,
Billing_Address__c, Bill_Email__c, Name
FROM Opportunity
WHERE Id IN :opportunityIds]);
for(Id i : opportunityIds){
opp = opps.get(i);
// put rest of the code here
User u = [SELECT FirstName, LastName, Email FROM User WHERE Id = :opp.OwnerId];
Contact DC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'Delivery-Invoices'];
Contact MC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'Media-Invoices'];
Contact CC = [SELECT FirstName, LastName, Email FROM Contact WHERE LastName = :'CC-Invoices'];
String Name;
// ...
}
}
}
你好 我正在Salesforce内部为trigger进行单元测试,我不断遇到一个似乎无法解决的错误,所以我希望有更多经验的人能帮助我回到正轨。我已经在Google上搜索过很多次了,我的代码结构也被弄乱了,但我找不到解决方案。 目的: 我的任务是编写一个触发器,该触发器将处理维护每个开发人员的案例排名所需的逻辑。每个开发人员都被分配了案例,这些案例可能有也可能没有由业务确定的优先级。每个开发人员在任
我在WordPress数据库中编写了一个MySQL触发器&它给出了一个错误。我的触发器代码如下: 它会给出以下错误消息: 错误 SQL查询:文档 CREATE[DEFINER={user CURRENT_USER}]trigger up_trig AFTER INSERT ON每一行BEGIN DECLARE“选择DISTINCT()INTOFROM其中='panchayat_id'和=new。(
我已经构建了一个RESTendpoint,它使用Spring和Apache CXF2.5来使用和生成Application/JSON。 配置: 当我使用不受支持的内容类型(如application/xml)发送请求(使用REST客户端应用程序)时,我会得到一个内部服务器错误。我希望是405,因为endpoint不支持任何其他内容类型。为什么我会得到这个例外?
下面是我的顶点触发器。我是一名初学者,正在尝试编写其测试类,但不断出现错误“System.DmlException:Insert失败。第0行出现第一个异常;第一个错误:REQUIRED\u FIELD\u MISSING,错误:只有在产品相关列表上为此opportunity选择了价格手册,才能选择产品。:[]”。 在Opportunity上触发TrgrOptyHighestCustmorePric
大家好, 我正在尝试为我帮助编写的触发器编写一个测试类。触发器使用名为trigger\u help\u c的字段,该字段是通过添加opportunity Type和Account ID派生的公式字段,如果在过去90天内已在该帐户上创建了该类型的opportunity,则在插入之前激发。除非配置文件是系统管理员。这是我的触发器: 我在写测试课时遇到了困难,我像往常一样不知所措。我写了以下内容,但我不
我必须做的是,我必须在给定的URL中发布JSON数据,其中JSON看起来像 和我的功能 当我张贴它的时候;我得到一个错误 “远程服务器返回错误:(415)不支持的媒体类型。” 有人知道吗;我错在哪里?