Elektronische Unternehmenskommunikation und die damit verbundenen Prozesse haben viel Optimierungspotenzial. Das am häufigsten genutzte Werkzeug in meisten Fällen ist die E-Mail. Insbesondere im Support-Bereich ist die E-Mail-Kommunikation ein integraler Bestandteil des Aufgabenbereichs. Mit Einsatz von VisualForce lassen sich Prozesse gerade in diesem Bereich deutlich optimieren (mehr dazu im Firmen-Blog: http://blog.factory42.com/blog/bid/341807/Neues-Rezept-f%C3%BCr-mehr-Effizienz ).
Entwicklung einer neuen VisualForce Seite zum Erfassen und Versenden von Emails ist kein Hexenwerk. Es wird aber dann etwas tricky, wenn Anhänge mitgesendet werden müssen.
Im aktuellen Projekt habe ich folgende Ansätze ausprobiert und nur eine funktionierende und in diesem Projekt akzeptable Lösung gefunden.
Ansätze:
1) Darstellung des Attachment-Blocks als Related List, ungefähr so
3) Die Attachments-Funktionalität wird ausgelagert. Es gibt eine zweite VisualForce Seite, die sich ausschließlich um Attachments kümmert, die als iFrame auf der ersten Seite erscheint.
Vorteil: keine Beeinträchtigung des Gesamtkonstrukts.
Nachteil: das iFrame hat eine feste Größe. Bedeutet, ich muss scrollen, falls viele Attachments angehängt werden. Aber auch dafür gibt es eine Lösung auf Basis von JavaScript. Aus Zeitgründen habe ich auf die Implementierung dieser Funktion verzichtet.
Beachte: die E-Mail wird als Entwurf gespeichert, bevor Dateien angehängt werden (da Attachments eine ParentID erwarten).
Hauptseite mit iFrame. Aufruf der Attachment-Seite im iFrame mit Übergabe der E-Mail ID als Parameter:
Entwicklung einer neuen VisualForce Seite zum Erfassen und Versenden von Emails ist kein Hexenwerk. Es wird aber dann etwas tricky, wenn Anhänge mitgesendet werden müssen.
Im aktuellen Projekt habe ich folgende Ansätze ausprobiert und nur eine funktionierende und in diesem Projekt akzeptable Lösung gefunden.
Ansätze:
1) Darstellung des Attachment-Blocks als Related List, ungefähr so
<apex:relatedList
id="Attachments"
subject="{!myObject}"
list="NotesAndAttachments"
title="Attached
Documents"/>
endete mit einem "Internal Server Error".
2) Das Einbinden des entsprechenden Feldes direkt auf der VisualForce Seite,
<apex:inputFile value="{!newAtt.body}" filename="{!newAtt.name}" id="file"/>
hat zwar funktioniert, erfordert aber den Refresh der gesamten Seite, was in einem komplexen Konstrukt zum Datenverlust führt. Versucht man statt dessen die Aktualisierung eines bestimmten Bereiches mit rerender="idAttachmentBlock"zu erzwingen, kommt die folgende Fehlermeldung zum Vorschein:
apex:inputFile can not be used in conjunction with an action component, apex:commandButton or apex:commandLink that specifies a rerender or oncomplete attribute3) Die Attachments-Funktionalität wird ausgelagert. Es gibt eine zweite VisualForce Seite, die sich ausschließlich um Attachments kümmert, die als iFrame auf der ersten Seite erscheint.
Vorteil: keine Beeinträchtigung des Gesamtkonstrukts.
Nachteil: das iFrame hat eine feste Größe. Bedeutet, ich muss scrollen, falls viele Attachments angehängt werden. Aber auch dafür gibt es eine Lösung auf Basis von JavaScript. Aus Zeitgründen habe ich auf die Implementierung dieser Funktion verzichtet.
Beachte: die E-Mail wird als Entwurf gespeichert, bevor Dateien angehängt werden (da Attachments eine ParentID erwarten).
Hauptseite mit iFrame. Aufruf der Attachment-Seite im iFrame mit Übergabe der E-Mail ID als Parameter:
<apex:outputPanel
id="attachBlock">
<apex:outputPanel
id="attachBlockInside"
rendered="{!IF(attachmentParentId==null,
false, true)}">
<iframe
src="/apex/f42_MultiAttachment?emailid={!attachmentParentId}"
height="120"
width="100%"
border="0"
frameborder="0"
style="overflow-x:
hidden;overflow-y:
scroll;"></iframe>
</apex:outputPanel>
</apex:outputPanel>
Seite mit Attachments:
<apex:page
controller="f42_MultiAttachmentController"
showHeader="false"
sidebar="false"
tabStyle="Case">
<apex:stylesheet
value="{!$Resource.SendEmailPageStyle}"
/>
<style>
body{background-color:#F8F8F8
!important; margin:0;
padding:0;}
.btn
{margin:0
!important;}
.inputText{width:250px
!important;}
</style>
<apex:form
>
<apex:pageBlock
>
<apex:repeat
value="{!newAttachments}"
var="newAtt">
<apex:pageBlockSection
columns="3"
>
<apex:pageBlockSectionItem
labelStyleClass="fieldBlockTopLabel"
dataStyleClass="fieldBlockTopData">
<apex:outputLabel
value="{!$Label.SendEmail_lblFile}"
for="file"/>
<apex:inputFile
value="{!newAtt.body}"
filename="{!newAtt.name}"
id="file"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem
labelStyleClass="fieldBlockTopLabel"
dataStyleClass="fieldBlockTopData">
<apex:outputLabel
value="{!$Label.SendEmail_lblFileDescription}"/>
<apex:inputText
value="{!newAtt.Description}"
styleClass="inputText"
/>
</apex:pageBlockSectionItem>
<apex:commandButton
value="{!$Label.SendEmail_btnUpload}"
action="{!saveAttachment}"
style="margin:0;
padding:0;"/>
</apex:pageBlockSection>
</apex:repeat>
<apex:pageBlockSection
columns="1"
id="blockViewAttachments">
<apex:pageBlockTable
value="{!attachments}"
var="attachment">
<apex:column
>
<apex:outputLink
value="{!URLFOR($Action.Attachment.Download,
attachment.Id)}" style="color:#015ba7;
text-decoration:none;"
target="_blank">{!$Label.SendEmail_lblView}</apex:outputLink>
<apex:outputLabel
style="color:#999999"
value="
| " />
<apex:commandLink
action="{!deleteAttachment}"
style="color:#015ba7;
text-decoration:none;">{!$Label.SendEmail_lblDelete}
<apex:param
value="{!attachment.Id}"
name="idToDelete"
assignTo="{!idAttachmentDelete}"/>
</apex:commandLink>
</apex:column>
<apex:column
value="{!attachment.Name}"/>
<apex:column
value="{!attachment.Description}"/>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
Attachment-Controller:
public
without
sharing
class
f42_MultiAttachmentController {
public
Id sobjId {get;
set;} //
the parent object id
public
List<Attachment>
attachments; // list of existing
attachments - populated on demand
public
List<Attachment>
newAttachments {get;
set;} //
list of new attachments to add
public
static
final
Integer NUM_ATTACHMENTS_TO_ADD=5; // the
number of new attachments to add to the list when the user clicks
'Add More'
public
id idAttachmentDelete{get;set;}
//
constructor
public
f42_MultiAttachmentController(){
//
instantiate the list with a single attachment
newAttachments=new
List<Attachment>{new
Attachment()};
sobjId
= ApexPages.currentPage().getParameters().get('emailid');
}
//
retrieve the existing attachments
public
List<Attachment>
getAttachments(){
//
only execute the SOQL if the list hasn't been initialised
if
(null==attachments){
attachments=[select
Id, ParentId, Name,
Description from
Attachment
where
parentId=:sobjId];
}
return
attachments;
}
//
Add more attachments action method
public
void
addMore(){
//
append NUM_ATTACHMENTS_TO_ADD to the new attachments list
for
(Integer idx=0; idx<NUM_ATTACHMENTS_TO_ADD; idx++){
newAttachments.add(new
Attachment());
}
}
//
Save action method
public
void
saveAttachment(){
List<Attachment>
toInsert=new
List<Attachment>();
for
(Attachment
newAtt : newAttachments){
if
(newAtt.Body!=null){
newAtt.parentId=sobjId;
toInsert.add(newAtt);
}
}
insert
toInsert;
newAttachments.clear();
newAttachments.add(new
Attachment());
//
null the list of existing attachments - this will be rebuilt when the
page is refreshed
attachments=null;
}
public
void
deleteAttachment(){
List<Attachment>
lstAttDelete = [Select
id from
Attachment
where
id = :idAttachmentDelete];
if(!lstAttDelete.isEmpty())
delete
lstAttDelete;
attachments=null;
}
//
Action method when the user is done
public
PageReference done(){
//
send the user to the detail page for the sobject
return
new
PageReference('/'
+ sobjId);
}
/******************************************************
*
* Unit Tests
*
******************************************************/
private
static
testMethod
void
testController(){
Account
acc=Test_Data_Generator.createTestAccount(1, true);
f42_MultiAttachmentController
controller=new
f42_MultiAttachmentController();
controller.sobjId=acc.id;
System.assertEquals(0,
controller.getAttachments().size());
System.assertEquals(1,
controller.newAttachments.size());
controller.addMore();
System.assertEquals(1
+ NUM_ATTACHMENTS_TO_ADD, controller.newAttachments.size());
//
populate the first and third new attachments
List<Attachment>
newAtts=controller.newAttachments;
newAtts[0].Name='Unit
Test 1';
newAtts[0].Description='Unit
Test 1';
newAtts[0].Body=Blob.valueOf('Unit
Test 1');
newAtts[2].Name='Unit
Test 2';
newAtts[2].Description='Unit
Test 2';
newAtts[2].Body=Blob.valueOf('Unit
Test 2');
controller.saveAttachment();
System.assertEquals(2,
controller.getAttachments().size());
System.assertNotEquals(null,
controller.done());
}
}
Kommentare
Kommentar veröffentlichen