Skip to content
Snippets Groups Projects
process.js 33.6 KiB
Newer Older
import("system.logging");
import("system.entities");
import("MarketingCondition_lib");
Johannes Hörmann's avatar
Johannes Hörmann committed
import("system.translate");
import("ActivityTask_lib");
import("system.util");
import("Contact_lib");
import("system.datetime");
import("system.neon");
import("Employee_lib");
import("system.vars");
import("KeywordRegistry_basic");
import("Sql_lib");
import("system.db");
import("DocumentTemplate_lib");
import("Communication_lib");
import("Email_lib");
import("system.process");
import("system.notification");
import("Document_lib");
import("system.workflow");
import("system.logging");
Johannes Hörmann's avatar
Johannes Hörmann committed

/**
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
function BulkMailUtils () {}

/**
 * Executes a process to send bulk mails on the server and creates a notification when finished.
 * 
 * @param {String} pBulkMailId                      <p>
 *                                                  Id of the bulk mail.<br>
 * @param {Bool} pTestRun (optional)                <p>
 *                                                  True indicates a Testrun<br>
 * @param {String} pUser=currentUser (optional)     <p>
 *                                                  User that will get the notification, <br>
 *                                                  if null (not undefined!), no notification<br>
 *                                                  will be created.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.sendBulkMailOnServer = function (pBulkMailId, pTestRun, pUser)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
    if (pUser === undefined)
        pUser = EmployeeUtils.getCurrentUserId();
    
    var processConfig = process.createStartAsyncConfig()
        .setName("sendBulkMail_serverProcess")
        .setLocalVariables({
Johannes Hörmann's avatar
Johannes Hörmann committed
            bulkMailId : pBulkMailId,
Johannes Hörmann's avatar
Johannes Hörmann committed
            user : pUser || ""
    process.startAsync(processConfig);
Johannes Hörmann's avatar
Johannes Hörmann committed
}

/**
 * Sends a bulk mail. You should only call this function on the server because it
 * can take some time to execute, use BulkMailUtils.sendBulkMailOnServer instead.
 * 
 * @param {String} pBulkMailId                  <p>
 *                                              Id of the bulk mail.<br>
 * @param {Bool} pIsTestRun (optional)            <p>
 * @return {Object}                             <p>
 *                                              Count of sucessful and failed mails.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.sendBulkMail = function (pBulkMailId, pIsTestRun)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
    if (pIsTestRun == undefined)
    {
        pIsTestRun = false;
    }
    
    var [templateId, subject, emailSender, createActivity, bulkMailName, useTemplateAttachments] = 
                newSelect("DOCUMENTTEMPLATE_ID, SUBJECT, SENDER_EMAIL_ADDRESS, CREATEACTIVITIES, NAME, USE_TEMPLATE_ATTACHMENTS")
                    .from("BULKMAIL")
                    .where("BULKMAIL.BULKMAILID", pBulkMailId)
                    .arrayRow();

    useTemplateAttachments = Utils.toBoolean(useTemplateAttachments);
        
    var template = BulkMailUtils.getBulkMailTemplate(pBulkMailId, templateId, true, useTemplateAttachments);
Johannes Hörmann's avatar
Johannes Hörmann committed
    var recipientData;
    var recipientLoadConfig = entities.createConfigForLoadingRows()
        .fields(["BULKMAILRECIPIENTID", "CONTACT_ID", "EMAIL_ADDRESS", "PERSON_ID", "ORGANISATION_ID"])
        .entity("BulkmailRecipient_entity")
        .provider("RecipientsToBeMailed")
        .addParameter("BulkMailId_param", pBulkMailId)
        .addParameter("IsTestMail_param", pIsTestRun);
    
    var recipientData = entities.getRows(recipientLoadConfig);
    
    if (pIsTestRun)
Johannes Hörmann's avatar
Johannes Hörmann committed
    {
        recipientData = newSelect("BULKMAILRECIPIENTID, BULKMAILRECIPIENT.CONTACT_ID, BULKMAILRECIPIENT.EMAIL_ADDRESS, PERSON_ID, ORGANISATION_ID")
            .from("CONTACT")
            .join("BULKMAILRECIPIENT", "BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
            .where("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
            .and("BULKMAILRECIPIENT.TEST_RECIPIENT",1)
            .table();
            
        testRecipientData = newSelect("BULKMAILTESTRECIPIENT.CONTACT_ID, BULKMAILTESTRECIPIENT.EMAIL_ADDRESS")
            .from("BULKMAILTESTRECIPIENT")
            .where("BULKMAILTESTRECIPIENT.BULKMAIL_ID", pBulkMailId)
Johannes Hörmann's avatar
Johannes Hörmann committed
    }
    new SqlBuilder()
        .tableName("MAIL_RUN")
        .insertFields({
            "MAIL_RUNID": mailrunId,
            "OBJECT_ROWID": pBulkMailId,
            "OBJECT_TYPE": "Bulkmail",
            "DATE_RUN_START": vars.get("$sys.date"),
            "STATUS": $KeywordRegistry.bulkMailStatus$beingSent(),
            "TESTRUN": pIsTestRun ? 1 : 0
        });
    var contactIds = recipientData.map(function (recipient) {return recipient["CONTACT_ID"];});
Johannes Hörmann's avatar
Johannes Hörmann committed
    var successIds = [];
    var failedIds = [];
    var sentDate = vars.get("$sys.date");
S.Listl's avatar
S.Listl committed
    var mails = template.getReplacedEmailsByContactIds(contactIds);
Johannes Hörmann's avatar
Johannes Hörmann committed
    
    var subjectTemplate = new DocumentTemplate(subject, DocumentTemplate.types.PLAIN);
    var subjects = subjectTemplate.getReplacedContentByContactIds(contactIds);
    
    var bulkMailLink = [["BulkMail", pBulkMailId]];
    var activitySubject = translate.withArguments("Bulk mail \"%0\" sent", [bulkMailName]);
    if (!pIsTestRun)
    {
        recipientData.forEach(function (recipient)
        {
            let isSuccess = false;
            let recipientId = recipient["BULKMAILRECIPIENTID"];
            let contactId = recipient["CONTACT_ID"];
            let emailAddress = recipient["EMAIL_ADDRESS"];
            let personId = recipient["PERSON_ID"];
            let organisationId = recipient["ORGANISATION_ID"];
            let email = mails[contactId];
            let mailLogId = util.getNewUUID();
            if (email !== undefined && emailAddress)
                email.toRecipients = [emailAddress];
                email.sender = emailSender;
                email.subject = subjects[contactId];

                BulkMailUtils.storeEmlFile(pBulkMailId, mailrunId, mailLogId,email.getEML());
                isSuccess = email.send();
Johannes Hörmann's avatar
Johannes Hörmann committed
            }

            //set the recipient status to 'sent' or 'failed'
            new SqlBuilder()
                .tableName("MAIL_LOG")
                .insertFields({
                    "MAIL_LOGID": mailLogId,
                    "MAIL_RUN_ID": mailrunId,
                    "CONTACT_ID": contactId,
                    "STATUS": isSuccess ? $KeywordRegistry.bulkMailRecipientStatus$sent() : $KeywordRegistry.bulkMailRecipientStatus$failed(),
                    "SENDER_EMAIL": emailSender,
                    "RECIPIENT_EMAIL": emailAddress,
                    "MAILING_SUBJECT": subjects[contactId],
                    "DATE_SEND": vars.get("$sys.date")
                });
            //TODO: Klären was von alter Logik noch bleiben soll. Status macht nur Sinn wenn jede Bulkmail nur einmal gesendet wird. Bleiben Activitys?
            Array.prototype.push.call(isSuccess ? successIds : failedIds, recipientId);
            if (isSuccess && createActivity == "1")
            {
                let activityData = {
                    categoryKeywordId : $KeywordRegistry.activityCategory$mail(),
                    directionKeywordId : $KeywordRegistry.activityDirection$outgoing(),
                    subject : activitySubject,
                    content : email.body
                };
                let contactLink = [[ContactUtils.getContextByPersOrg(personId, organisationid), contactId]];
                ActivityUtils.insertNewActivity(activityData, bulkMailLink.concat(contactLink));
            }
        });

        newWhereIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", successIds, SqlBuilder.IN())
            .updateFields({
                "STATUS": $KeywordRegistry.bulkMailRecipientStatus$sent(),
                "SENTDATE": sentDate
            });

        newWhereIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", failedIds, SqlBuilder.IN())
            .updateFields({
                "STATUS": $KeywordRegistry.bulkMailRecipientStatus$failed(),
                "SENTDATE": sentDate
            });

        newWhere("MAIL_RUN.MAIL_RUNID", mailrunId)
            .updateFields({
                "STATUS": $KeywordRegistry.bulkMailStatus$sent(),
                "DATE_RUN_FINISHED": vars.get("$sys.date")
            });

        newWhere("BULKMAIL.BULKMAILID", pBulkMailId)
            .updateFields({
                "STATUS": $KeywordRegistry.bulkMailStatus$sent()
            });
    }
    else
    {
        for (let i = 0, l = recipientData.length; i < l; i++)
        {
            
            let isSuccess = false;
            let contactId = recipientData[i][1];
            let email = mails[contactId];

            if (email !== undefined)
            {
                email.sender = emailSender;
                email.subject = "Test: "+subjects[contactId];
                for (let j =0; j<testRecipientData.length;j++){
                    if(testRecipientData[j][1]){
                        email.toRecipients = [testRecipientData[j][1]];
                        isSuccess = email.send();

                        Array.prototype.push.call(isSuccess ? successIds : failedIds, recipientData[i][0]);

                        if (testRecipientData[j][0])
                        {
                            let mailLogId = util.getNewUUID();
                            db.insertData("MAIL_LOG", ["MAIL_LOGID","MAIL_RUN_ID","CONTACT_ID","STATUS","SENDER_EMAIL","RECIPIENT_EMAIL","MAILING_SUBJECT","DATE_SEND"], null, [mailLogId,mailrunId,testRecipientData[j][0],(isSuccess ?$KeywordRegistry.bulkMailRecipientStatus$sent(): $KeywordRegistry.bulkMailRecipientStatus$failed()),emailSender,testRecipientData[j][1],email.subject,vars.get("$sys.date")]);
                            this.storeEmlFile(pBulkMailId, mailrunId, mailLogId,email.getEML());
        newWhere("MAIL_RUN.MAIL_RUNID",mailrunId)
            .updateData(true,"MAIL_RUN",["STATUS","DATE_RUN_FINISHED"],null,[$KeywordRegistry.bulkMailStatus$sent(),vars.get("$sys.date")]);

    }
Johannes Hörmann's avatar
Johannes Hörmann committed
        
    return {
        sucessful : successIds.length,
        failed : failedIds.length
    };
}

/**
 * Opens a context to select a bulk mail to add recipients to.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pContext             the context of the contacts (Person or Organisation)
 * @param {String[]} pContactIds        Recipients that should be added.<br>
 * @param {String|Object} pFilter       the filter for the contacts that should be used if no contact is selected
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.openAddRecipientView = function (pContext, pContactIds, pFilter)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
    if (!Utils.isString(pContactIds))
        pContactIds = JSON.stringify(pContactIds);
    if (!Utils.isString(pFilter))
        pFilter = JSON.stringify(pFilter);
    
    neon.openContext("BulkMailAddRecipients", "BulkMailAddRecipientsEdit_view", null, neon.OPERATINGSTATE_VIEW, {
        "ObjectType_param": pContext,
        "ContactIds_param": pContactIds,
        "ContactFilter_param": pFilter
    });
 * Deletes all bulk mail recipients that have a commrestriction for emails.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pBulkMailId          <p>
 *                                      The mail id.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.removeCommRestrictionRecipients = function (pBulkMailId)
{
    var recipientIds = newSelect("BULKMAILRECIPIENTID")
Johannes Hörmann's avatar
Johannes Hörmann committed
        .from("BULKMAILRECIPIENT")
        .join("CONTACT", newWhere()
                .and("BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
                .and(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail())))
        .where("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
        .arrayColumn();
S.Listl's avatar
S.Listl committed
    newWhereIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", recipientIds, SqlBuilder.IN())
        .deleteData();
 * Adds recipients to a bulkmail.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pBulkMailId              <p>
 *                                          Bulk mail id.<br>
 * @param {String[]} pContactIds            <p>
 *                                          Contact ids of the recipients.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.addRecipients = function (pBulkMailId, pContactIds)
{
    if (pContactIds.length > 0)
Johannes Hörmann's avatar
Johannes Hörmann committed
    {
        var contactData = newSelect(["CONTACTID", "(" + CommUtil.getStandardSubSqlMail(newWhere("COMMUNICATION.CONTACT_ID = CONTACTID")) + ")"])
            .from("CONTACT")
            .where("CONTACT.CONTACTID", pContactIds, SqlBuilder.IN())
            .table();
        
        var sqlBuilder = new SqlBuilder();
        
        var inserts = contactData.map(function([contactId, standardMail])
            return sqlBuilder.buildInsertStatement({
                "BULKMAIL_ID": pBulkMailId,
                "CONTACT_ID": contactId,
                "STATUS": $KeywordRegistry.bulkMailRecipientStatus$pending(),
                "EMAIL_ADDRESS": standardMail
            }, "BULKMAILRECIPIENT", "BULKMAILRECIPIENTID");
        });
        
        db.inserts(inserts);
 * Loads the document template of a bulk mail. If the bulk mail
 * itself has a template, it is preferred over the documentTemplate-id.
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pBulkMailId                                  <p>
 *                                                              The id of the bulk mail.<br>
 * @param {String} pDocumentTemplateId                          <p>
 *                                                              The id of the document template.<br>
 * @param {Boolean} pResolveSubtemplates=true (optional)        <p>
 *                                                              If true subtemplates are resolved (if the type is html)
 * @param {Boolean} pUseTemplateAttachments=false               <p>
 *                                                              If true the attachments from the document template is always used
 * @param {FileUpload} pUpload (optional)                       <p>
 *                                                              The upload value if a custom template is used.<br>
 * @return {DocumentTemplate}                                   <p>
 *                                                              The document template, null if no content was found.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.getBulkMailTemplate = function (pBulkMailId, pDocumentTemplateId, pResolveSubtemplates, pUseTemplateAttachments, pUpload)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
S.Listl's avatar
S.Listl committed
    if (pUpload && pUpload.isFilled() && BulkMailUtils.isValidMimeType(pUpload.mimeType))
        return DocumentTemplate.fromUpload(pUpload);
        
    var bulkTemplate = DocumentTemplate.loadTemplate(pBulkMailId, "BULKMAIL", pResolveSubtemplates);
    var documentTemplate = DocumentTemplate.loadTemplate(pDocumentTemplateId, undefined, pResolveSubtemplates);

    if (!bulkTemplate.content)
    {
        return documentTemplate;
    }
    else
    {
        if (pUseTemplateAttachments)
            bulkTemplate.setAttachments(documentTemplate.getAttachments());
        
        return bulkTemplate;
    }
 * Checks if a contact is a recipient of a bulk mail.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pBulkMailId                      <p>
 *                                                  The id of the bulk mail.<br>
 * @param {String} pContactId                       <p>
 *                                                  The contact id.<br>
 * @param {String} pRecipientId                     <p>
 *                                                  The contact id of the contact where,<br>
 *                                                  the bulk mail shall sent to.<br>
 * @return {boolean}                                <p>
 *                                                  True, if the contact is a recipient.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.isRecipient = function (pBulkMailId, pContactId, pRecipientId)
{
    return newSelect("count(*)")
                .from("BULKMAILRECIPIENT")
                .where("BULKMAILRECIPIENT.CONTACT_ID", pContactId)
                .and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
                .andIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", pRecipientId, SqlBuilder.NOT_EQUAL())
                .cell() != "0"; //TODO: is there a way exists could be used?
 * Opens the BulkMail context in new mode.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String[]} pRecipients (optional)         <p>
 *                                                  Recipients that should be added after creation.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.newBulkMail = function (pRecipients)
{
    var params = {
        "PresetRecipients_param" : JSON.stringify(pRecipients)
    };
    neon.openContext("BulkMail", "BulkMailEdit_view", null, neon.OPERATINGSTATE_NEW, params);
}

/**
 * Filters the given contactIds if they can be added as new recipients.
 * Checks if a contact is already a recipient or if there is a advertising ban.
 * 
 * @param {String} pBulkMailId id of the bulk mail the contacts should be added to
 * @param {String[]} pContactIds contacts to filter
 * @return {String[]} contacts that can be added as recipients
 */
BulkMailUtils.filterNewRecipients = function (pBulkMailId, pContactIds)
{
    return newSelect("CONTACTID")
                .from("CONTACT")
                .whereIfSet("CONTACT.CONTACTID", pContactIds, SqlBuilder.IN())
                // only add contacts that aren't already recipients
                .and(null, newSelect("BULKMAILRECIPIENTID")
                                .from("BULKMAILRECIPIENT")
                                .where("BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
                                .and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
                        , SqlBuilder.NOT_EXISTS())
                // check if there's a commrestriction
                .and(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail(), true))  
 * Opens the given bulk mail.
 * 
 * @param {String} pBulkMailId          <p>
 *                                      The id of the bulk mail.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.openBulkMail = function (pBulkMailId)
{
    neon.openContext("BulkMail", "BulkMailMain_view", [pBulkMailId], neon.OPERATINGSTATE_VIEW, null);
}

/**
 * Checks is the given mime type can be used for a bulk mail.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pMimeType                <p>
 *                                          The mime type.<br>
 * @return {Boolean}                        <p>
 *                                          Whether the type is usable or not.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
BulkMailUtils.isValidMimeType = function (pMimeType)
{
    var templateType = DocumentTemplate.types.fromMimeType(pMimeType);
    return BulkMailUtils.isValidTemplateType(templateType)
}

/**
 * Checks is the given template type can be used for a bulk mail.<br>
 * @param {String} pTemplateType            <p>
 *                                          Template type.<br>
 * @return {Boolean}                        <p>
 *                                          Whether the type is usable or not.<br>
 */
BulkMailUtils.isValidTemplateType = function (pTemplateType)
{
    switch (pTemplateType)
Johannes Hörmann's avatar
Johannes Hörmann committed
    {
        case DocumentTemplate.types.EML:
        case DocumentTemplate.types.HTML:
        case DocumentTemplate.types.TXT:
            return true;
        default:
            return false;
    }
}

 * Checks whether the given status id matches,<br>
 * to the status of a bulk mail which is sent or<br>
 * not.
 *
 * @param {String} pStatus              <p>
 *                                      The key id of the current status.<br>
 * @return {Boolean}                    <p>
 *                                      True if the status is "sent" or "sending".<br> 
 */
BulkMailUtils.isStatusSendingOrSent = function (pStatus)
{
    return pStatus == $KeywordRegistry.bulkMailStatus$sent() || pStatus == $KeywordRegistry.bulkMailStatus$beingSent()
}

/**
 * Opens BulkMail context in new mode, with the given bulk mail id.<br>
 * 
 * @param {String} pBulkMailId          <p>
 *                                      The id of the bulk mail.<br>
 */
Johannes Hörmann's avatar
Johannes Hörmann committed
BulkMailUtils.copy = function(pBulkMailId)
{
    var params = {
        "CopyBulkMailId_param" : pBulkMailId
    };
    neon.openContext("BulkMail", null, null, neon.OPERATINGSTATE_NEW, params);
}
/*
 *Stores the Eml file for a bulkmailrecipient in the Filesystem
 *
 * @param {String} pBulkMailId          <p>
 *                                      The id of the bulk mail.<br>
 * @param {String} pMailRunId          <p>
 *                                      The id of the bulk mail run.<br>
 * @param {String} pMailLogId          <p>
 *                                      The id of the corresponding mail log entry.<br>                                                                           
 **/
BulkMailUtils.storeEmlFile = function(pBulkMailId,pMailRunId, pMailLogId,pFile){
    var locationoption = project.getPreferenceValue("bulkmail.fileStorage","/bulkMailFiles/");
    var path = vars.get("$sys.serverdata")+locationoption +pBulkMailId+"/"+pMailRunId+"/";
    var filename = pMailLogId+".eml"
    var fullPath = path + filename;
    fileIO.storeData(fullPath, pFile, util.DATA_BINARY, false);
}
/*
 *Loads the Eml file for a bulkmailrecipient from the Filesystem
 *
 * @param {String} pBulkMailId          <p>
 *                                      The id of the bulk mail.<br>
 * @param {String} pMailRunId          <p>
 *                                      The id of the bulk mail run.<br>
 * @param {String} pMailLogId          <p>
 *                                      The id of the corresponding mail log entry.<br>   
 * @return {String}                     <p>
 *                                      The file as base64 String<br>                                                                                                              
 **/
BulkMailUtils.getEmlFile = function(pBulkMailId,pMailRunId, pMailLogId){
    var locationoption = project.getPreferenceValue("bulkmail.fileStorage","/bulkMailFiles/");
    var path = vars.get("$sys.serverdata")+locationoption +pBulkMailId+"/"+pMailRunId+"/";
    var filename = pMailLogId+".eml"
    var fullPath = path + filename;
    return (fileIO.getData(fullPath,util.DATA_BINARY));
}

/*
 *Gets the redirecturl for a link in a bulkmail
 *
 * @param {String} pLinkId          <p>
 *                                      The id of the link.<br>
 *                                      
 * @return {String}                 <p>
 *                                      The url<br>                                          
 **/
BulkMailUtils.getRedirectLink = function(pLinkId){
    var url ;
    if (pLinkId){
        url =newSelect("LINK.URL").from("LINK").where("LINK.LINKID", pLinkId).cell();
    }
    return url;
}
/*
 *Inserts the Redirect into the link_click table.
 *
 *If its the first Click the Id gets put as opener in mail_log
 *
 * @param {String} pMailLogId (required)<p>
 *                                      The id of the mail log.<br>
 * @param {String} pIpAddress           <p>
 *                                      the ip address of the client.<br>                                     
 * @param {String} pLinkId              <p>
 *                                      The id of link.<br>             
 * @param {String} pBrowsername         <p>
 *                                      The browser that was used to open the link.<br>
 * @param {String} pOperatingSystemName <p>
 *                                      The Operating System that was used to open the link.<br>
 * @param {String} pDeviceType          <p>
 *                                      The device type that was used to open the link.<br>                                                 
 **/

BulkMailUtils.insertClick = function(pMailLogId,pIpAddress,pLinkId,pBrowsername,pOperatingSystemName,pDeviceType){
    if (!pMailLogId || !pLinkId) {
        return
    }
    
    var link_clickid = util.getNewUUID();
    db.insertData("LINK_CLICK"
        , ["LINK_CLICKID","LINK_ID","DEVICE_TYPE","OPERATING_SYSTEM","BROWSER","IP_ADDRESS","MAIL_LOG_ID","DATE_OPENED"]
        ,null 
        , [link_clickid,pLinkId,pDeviceType||"desktop",pOperatingSystemName||"",pBrowsername||"",pIpAddress,pMailLogId,vars.get("$sys.date")]  
        );
    

    newWhere("MAIL_LOG.MAIL_LOGID", pMailLogId)
    .and("MAIL_LOG.OPENER_LINK_CLICK_ID is null")
    .updateData(true, "MAIL_LOG", ["MAIL_LOG.OPENER_LINK_CLICK_ID"], null, [link_clickid]);
}

/*@TODO: Abändern nachdem geklärt ist wie wir IP-Adresse erhalten. Momentan bekommen wir nur Loadbalancer Ip.
 *
 **/

BulkMailUtils.getIpAddressFromHeader = function(pHttpHeader){

    var ipAddress; 

    ipAddress = pHttpHeader["X-forwarded-for"].split(",")[0];

    return ipAddress;
}

BulkMailUtils.startBulkmailWorkFlow = function(pMailLogId,pLinkId){
    if (!pMailLogId || !pLinkId) {
        return
    }
    var workFlowKey = newSelect("WORKFLOWPROCESSDEFINITION_KEY").from("LINK").where("LINK.LINKID",pLinkId).cell();
    if (workFlowKey){
        var variables = {
            "MAILLOGID": pMailLogId
        };
        workflow.startProcessByKey(workFlowKey, variables);
    }
    
}



Johannes Hörmann's avatar
Johannes Hörmann committed
function SerialLetterUtils () {}

/**
 * Adds recipients to a serial letter.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pSerialLetterId      <p>
 *                                      The id of the serial letter.<br>
 * @param {String[]} pContactIds        <p>
 *                                      Contact ids of the recipients.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
SerialLetterUtils.addRecipients = function (pSerialLetterId, pContactIds)
{
    var columns = [
        "LETTERRECIPIENTID",
        "SERIALLETTER_ID",
        "CONTACT_ID"
    ];
    var inserts = [];
    for (let i = 0, l = pContactIds.length; i < l; i++)
    {
        inserts.push(["LETTERRECIPIENT", columns, null, [util.getNewUUID(), pSerialLetterId, pContactIds[i]]]);
    }
    db.inserts(inserts);
}

/**
 * Opens a context to select a serial letter to add recipients to.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pContext             the context of the contacts (Person or Organisation)
 * @param {String[]} pContactIds        Recipients that should be added.<br>
 * @param {String|Object} pFilter       the filter for the contacts that should be used if no contact is selected
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
SerialLetterUtils.openAddRecipientView = function (pContext, pContactIds, pFilter)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
    if (!Utils.isString(pContactIds))
        pContactIds = JSON.stringify(pContactIds);
    if (!Utils.isString(pFilter))
        pFilter = JSON.stringify(pFilter);
    
    neon.openContext("SerialLetterAddRecipients", "SerialLetterAddRecipientsEdit_view", null, neon.OPERATINGSTATE_VIEW, {
        "ObjectType_param": pContext,
        "ContactIds_param": pContactIds,
        "ContactFilter_param": pFilter
    });
 * Executes a server process that builds a serial letter.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pSerialLetterId              <p>
 *                                              The id of the serial letter.<br>
 * @param {String[]} pRecipientIds (optional)   <p>
 *                                              Letter recipient ids of that should be used.<br>
 *                                              If omitted, all recipients of the letter will be used.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
S.Listl's avatar
S.Listl committed
SerialLetterUtils.buildSerialLetterOnServer = function (pSerialLetterId, pRecipientIds)
Johannes Hörmann's avatar
Johannes Hörmann committed
{
S.Listl's avatar
S.Listl committed
    var user = EmployeeUtils.getCurrentUserId();
    var processConfig = process.createStartAsyncConfig()
        .setName("buildSerialLetter_serverProcess")
        .setLocalVariables({
            "serialLetterId" : pSerialLetterId,
            "recipientIds" : JSON.stringify(pRecipientIds),
            "user" : user
        })
        .setUser(vars.get("$sys.user"));
    process.startAsync(processConfig);
 * Executes a server process that builds a serial letter.<br>
S.Listl's avatar
S.Listl committed
 * 
 * @param {String} pSerialLetterId          <p>
 *                                          Serial letter id.<br>
 * @param {String[]} pRecipientIds          <p>
 *                                          Letter recipient ids of that should be used.<br>
 *                                          If omitted, all recipients of the letter will be used.<br>
S.Listl's avatar
S.Listl committed
 */
SerialLetterUtils.buildSerialLetter = function (pSerialLetterId, pRecipientIds)
{
    var [templateId, title] = newSelect("DOCUMENTTEMPLATE_ID, TITLE")
                        .from("SERIALLETTER")
                        .where("SERIALLETTER.SERIALLETTERID", pSerialLetterId)
                        .arrayRow(true);

    var template = SerialLetterUtils.getSerialLetterTemplate(pSerialLetterId, templateId);
    var contactIdsSelect = newSelect("CONTACT_ID")
                        .from("LETTERRECIPIENT")
                        .join("CONTACT", newWhere("LETTERRECIPIENT.CONTACT_ID = CONTACT.CONTACTID"))
                        .where("LETTERRECIPIENT.SERIALLETTER_ID", pSerialLetterId)
                        .andIfSet(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$letter(), true));

    if (pRecipientIds && pRecipientIds.length > 0)
        contactIdsSelect.and("LETTERRECIPIENT.LETTERRECIPIENTID", pRecipientIds, SqlBuilder.IN());

    var contactIds = contactIdsSelect.table();
S.Listl's avatar
S.Listl committed
    return {
S.Listl's avatar
S.Listl committed
        content : template.getSerialLetterByContactIds(contactIds),
S.Listl's avatar
S.Listl committed
        filename : template.filename,
        title : title
 * Checks if a contact is a recipient of a serial letter.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pSerialLetterId              <p>
 *                                              The id of the serial letter.<br>
 * @param {String} pContactId                   <p>
 *                                              The contact id of the contact.<br>
 * @param {String} pRecipientId (optional)      <p>
 *                                              Letter recipient id.<br>
 * @return {Boolean}                            <p>
 *                                              True, if the contact is a recipient<br>
 *                                              and otherwise false.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
SerialLetterUtils.isRecipient = function (pSerialLetterId, pContactId, pRecipientId)
{
    return newSelect("count(*)")
                .from("LETTERRECIPIENT")
                .where("LETTERRECIPIENT.CONTACT_ID", pContactId)
                .and("LETTERRECIPIENT.SERIALLETTER_ID", pSerialLetterId)
                .andIfSet("LETTERRECIPIENT.LETTERRECIPIENTID", pRecipientId, SqlBuilder.NOT_EQUAL())
                .cell() != "0"; // TODO: is there a way exists could be used?
/**
 * Opens the serial letter context in new mode, with<br>
 * the given serial letter id.<br>
 * 
 * @param {String} pSerialLetterId          <p>
 *                                          The id of the serial letter.<br>
 */
Johannes Hörmann's avatar
Johannes Hörmann committed
SerialLetterUtils.openSerialLetter = function (pSerialLetterId)
{
    neon.openContext("SerialLetter", "SerialLetterMain_view", [pSerialLetterId], neon.OPERATINGSTATE_VIEW, null);
}

/**
 * Loads the document template of a serial letter. <br>
 * If the serial letter itself has a template, it is <br>
 * preferred over the documentTemplate-id.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 * 
 * @param {String} pLetterId            <p>
 *                                      The id of the serial letter.<br>
 * @param {String} pDocumentTemplateId  <p>
 *                                      The id of the document template.<br>
 * @return {DocumentTemplate}           <p>
 *                                      The document template.<br>
Johannes Hörmann's avatar
Johannes Hörmann committed
 */
SerialLetterUtils.getSerialLetterTemplate = function (pLetterId, pDocumentTemplateId)
{
    var template = DocumentTemplate.loadTemplate(pLetterId, "SERIALLETTER");
    if (!template.type)
        template = DocumentTemplate.loadTemplate(pDocumentTemplateId);
    return template;
}

/**
 * Adds contacts or organistaions to a serial letter by contactIds.<br>
 * 
 * @param {String} pContactIds              <p>
 *                                      The contact ids as JSON array.<br>
 */
SerialLetterUtils.addParticipantsByRowIds = function(pContactIds)
{
    var params = {
        "ContactIds_param" : pContactIds
    };
    neon.openContext("SerialLetterAddRecipients", "SerialLetterAddRecipientsEdit_view", null, neon.OPERATINGSTATE_VIEW, params);
}

/**
 * Adds contacts or organistaions to a serial letter by condition (filter).<br>
 * 
 * @param {String} pCondition           <p>
 *                                      Contact ids.
 * @param {String} pSourceTableName     <p>
 *                                      The source table.<br>
 */
SerialLetterUtils.addParticipantsByCondition = function(pCondition, pSourceTableName)
{
    var params = {
        "ContactIds_param" : pCondition,
        "comingFrom_param" : pSourceTableName}
    neon.openContext("SerialLetterAddRecipients", "SerialLetterAddRecipientsEdit_view", null, neon.OPERATINGSTATE_VIEW, params);
}

/**
 * Filters the given contactIds if they can be added as new recipients.
 * Checks if a contact is already a recipient or if there is a advertising ban.
 * 
 * @param {String} pSerialLetterId id of the seroal letter the contacts should be added to
 * @param {String[]} pContactIds contacts to filter
 * @return {String[]} contacts that can be added as recipients
 */
SerialLetterUtils.filterNewRecipients = function (pSerialLetterId, pContactIds)
{
    return newSelect("CONTACTID")
                .from("CONTACT")
                .whereIfSet("CONTACT.CONTACTID", pContactIds, SqlBuilder.IN())
                // only add contacts that aren't already recipients
                .and(null, newSelect("LETTERRECIPIENTID")
                                    .from("LETTERRECIPIENT")
                                    .where("LETTERRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
                                    .and("LETTERRECIPIENT.SERIALLETTER_ID", pSerialLetterId)
                        , SqlBuilder.NOT_EXISTS())
                // check if there's a commrestriction
                .and(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail(), true))  
                .arrayColumn();
}