Thursday, January 21, 2010

Email -> Open attachment file stored as blob data

The following code explains how to open the file attachment which is stored as blob data in database.
Parameter: emailItemId which is used to identify the attachment saved in SysOutgoingEmailData table.
This method can be called from a button click in the "Email-sending status" from from Admin-> Periodic->Email processing


void ShowAttachment(SysEmailItemId _emailItemId)
{
    SysOutgoingEmailData outgoingEmailData;
    str tempPath;
    BinData binData;
    FileIOPermission fileIOPermission;
    str filePathName;
    int retVal;
    ;

    fileIOPermission = new FileIOPermission('','r');
    fileIOPermission.assert();

    //BP Deviation Documented
    //tempPath = WinApiServer::getTempPath();

    tempPath = WinApi::getTempPath();

    CodeAccessPermission::revertAssert();

    // add embedded objects and attachments to the message
    
select outgoingEmailData
        index hint EmailDataIdx
        where outgoingEmailData.EmailItemId == _emailItemId; //OutgoingEmail.EmailItemId;

    if (SysEmailDistributor::validateFileName(outgoingEmailData.FileName))
    {
        binData = new BinData();

        binData.setData(outgoingEmailData.Data);

        if (outgoingEmailData.EmailDataType == SysEmailDataType::Embedded)
            // embedded images are renamed to ensure uniqueness
           filePathName = tempPath + int642str(outgoingEmailData.EmailItemId) + '_' + int2str(outgoingEmailData.DataId);
        else
           // attachment cannot be renamed
           filePathName = tempPath + outgoingEmailData.FileName;

        if (outgoingEmailData.FileExtension)
           filePathName = filePathName + outgoingEmailData.FileExtension;

        fileIOPermission = new FileIOPermission(filePathName,'w');
        fileIOPermission.assert();

        //BP Deviation Documented
        binData.saveFile(filePathName);

        CodeAccessPermission::revertAssert();

        if (outgoingEmailData.FileExtension == ".htm")
           retVal = WinApi::shellExecute(filePathName,"","","",1,false);
        else
        {
           retVal = WinApi::shellExecute(filePathName,"","","",1,true);

           fileIOPermission = new FileIOPermission(filePathName,'w');
           fileIOPermission.assert();

           //BP Deviation Documented
           WinApi::deleteFile(filePathName);

           CodeAccessPermission::revertAssert();
        }
    }
}

Wednesday, January 20, 2010

Lookup using temporary tables

Create lookup using temporary table. Populate the temporary table with the required data from different table or if a particular values should be shown first. In the below example, the Tmpcontactperson table can populated with required data and the lookup called using the code below.
public void lookup()
{
    Tmpcontactperson tmpContactPerson;
    //insert record into temporary table for different criteria and perform lookup
    sysTableLookup = SysTableLookup::newParameters(tableNum(Tmpcontactperson),this,false );
    sysTableLookup.addLookupField(fieldNum(Tmpcontactperson, ContactPersonId),True); sysTableLookup.addLookupField(fieldNum(Tmpcontactperson, CustAccount),false);
    sysTableLookup.addLookupField(fieldNum(Tmpcontactperson, Name),False);
    sysTableLookup.addLookupField(fieldNum(Tmpcontactperson, Email),False);
    sysTableLookup.addLookupField(fieldNum(Tmpcontactperson, Function),false);
    sysTableLookup.parmTmpBuffer(tmpContactPerson);
    sysTableLookup.performFormLookup();

}

Thursday, January 7, 2010

SO confirmation: Add email with pdf attachment to batch processing

Requirement:

  1. During sales order confirmation, if the print management settings is email and format is PDF, the system uses the client outlook to send the PDF as mail attachment. Instead, it is required to add this PDF file to the Email batch process (similar to the alerts) in SysOutgoingEmailTable & SysOutgoingEmailData tables so that when the Batch processing is performed, the email will be sent. The email template will be setup in parameters and the email id should be picked from SO.

  2. A new E-mail template shall be created according to standard functionality. This template is then set as a new parameter the form “CustFormletterParameters” named “E-mail template”.

Solution:

In the class SalesFormLetter_Confirmation, create a new method setConfirmEmailId() and call this in printJournal()

void setConfirmEmailId()
{
salesTable salesTablelocal
container conSysEmail;
boolean ok = true;
salesTablelocal = salesTable::find(custConfirmJour.SalesId);

//container: parameters 1 -> to identify if called from sales
// parameter 2 -> to get the sales email id

conSysEmail = conins(conSysEmail,1,NoYes::Yes,salesTablelocal.Email);
//set the container value in the info class. A new get/set method to store the container.
infolog.parmSOPOConfirmEmail(conSysEmail);
}

public void printJournal()
{
if (journalList.len() > 0)
{
if (printFormletter)
{
this.setConfirmEmailId();
custConfirmJour.printJournal(this, journalList);
}
if (salesParmUpdate.Proforma)
this.removeProforma();
}
}

In the Info class add the following code to reportSendMail() method to send mail using batch for pdf instead of outlook client.
void reportSendMail(PrintJobSettings p1)
{

    boolean pdfFormat;
    Map mappings;
    SysEmailParameters emailParams;
    Filename filePath;
    Filename filenamelocal;
    Filename fileExtension;
    FilenameOpen attachmentFilename;
    str attachmentsFolder;
    SysEmailId emailId;
    SysEmailTable table;
    LanguageId languageId;
    NoYes callerSales;
    int i;
    SysINetMail m = new SysINetMail();
    str fileName = 'axaptareport';
    ;

    if (p1.format() == PrintFormat::ASCII p1.format() == PrintFormat::TEXTUTF8)
        fileName = fileName + '.txt';
    else if (p1.format() == PrintFormat::RTF)
        fileName = fileName + '.rtf';
    else if (p1.format() == PrintFormat::HTML)
        fileName = fileName + '.htm';
    else if (p1.format() == PrintFormat::PDF p1.format() == PrintFormat::PDF_EMBED_FONTS)
    {
        fileName = fileName + '.pdf';
        pdfFormat = true;
    }
    //check if this is called from SO confirmation
    //conSysEmail = infolog.parmSOPOConfirmEmail();
    
if (conlen(conSysEmail)>1 && pdfFormat)
    {
        //The file name will be in the local client temp folder.
        attachmentFilename = p1.fileName();
        [filePath, filenamelocal, fileExtension] = Global::fileNameSplit(attachmentFilename);
        attachmentsFolder = Global::strReplace(emailParams.AttachmentsPath,'//','/');
        if (substr(attachmentsFolder, strlen(attachmentsFolder), 1) != '\\')
        attachmentsFolder = attachmentsFolder + "\\";
        if (attachmentsFolder)
        {
            //Copy the file to the server folder which should be shared and should
            //be on the network. This folder should be setup in the Email parameters.
            
attachmentsFolder = attachmentsFolder + filenamelocal + ".pdf";
            info::copyFile(attachmentFilename,attachmentsFolder);
            callerSales = conpeek(conSysEmail,1);
            if (callerSales == NoYes::Yes)
                emailId = CustFormletterParameters::find().CAP_ConfirmationEmailTemplate;
            else
                emailId = VendFormletterParameters::find().CAP_ConfirmationEmailTemplate;
            table = SysEmailTable::find(emailId);
            if (table)
            {
                languageId = table.DefaultLanguage;
                mappings = new Map(Types::String, Types::String);
                //mappings.insert("SubscriptionId","S001");
                
for (i = 2; i <= conlen(conSysEmail); i = i + 2)
                    SysEmailTable::sendMail(table.EmailId,languageId,conpeek(conSysEmail,i),mappings,attachmentsFolder,"",true,curuserid());
            }
            else
                    infolog.add(Exception::Error,"Email template parameter not available");
        }
        else
            infolog.add(Exception::Error,"Attachment folder for sending email is not setup in the parameters");
        }
    else
        m.sendMailAttach(p1.mailTo(),p1.mailCc(), p1.mailSubject(),'axapta report', true, p1.fileName(), fileName);
}
---------------------------

container CAP_parmSOPOConfirmEmail(container _conSysEmail = conSysEmail)
{
    conSysEmail = _conSysEmail;
    return conSysEmail;
}
---------------------------
server static void copyFile(FilenameOpen _attachmentFilename,
str _attachmentsFolder)
{
    Set permissionSet;
    ;
    // Revert permissions
    CodeAccessPermission::revertAssert();

    permissionSet = new Set(Types::Class);
    permissionSet.add(new FileIoPermission(_attachmentFilename,'r'));
    permissionSet.add(new FileIoPermission(_attachmentsFolder,'w'));

    CodeAccessPermission::assertMultiple(permissionSet);
    
// Move to processed folder
    // BP Deviation Documented

    winAPI::copyFile(_attachmentFilename,_attachmentsFolder,true);
    CodeAccessPermission::revertAssert();
}
---------------------------

How to Assert multiple file IO permission

server static void CAP_copyFile(FilenameOpen _attachmentFilename, str _attachmentsFolder)
{
Set permissionSet; ; // Revert permissions
CodeAccessPermission::revertAssert();
permissionSet = new Set(Types::Class);
permissionSet.add(new FileIoPermission(_attachmentFilename,'r'));
permissionSet.add(new FileIoPermission(_attachmentsFolder,'w'));
CodeAccessPermission::assertMultiple(permissionSet);
// Move to processed folder
// BP Deviation Documented

winAPI::copyFile(_attachmentFilename,_attachmentsFolder,true);
CodeAccessPermission::revertAssert();
}