<add-item item-descriptor="shipItemRel" id="r14190007">
  <set-property name="quantity"><![CDATA[1]]></set-property>
  <set-property name="highBound"><![CDATA[0]]></set-property>
  <set-property name="order"><![CDATA[mf20250001]]></set-property>
  <set-property name="state"><![CDATA[PENDING_DELIVERY]]></set-property>
  <set-property name="stateDetail"><![CDATA[The item [ci1389000004] has been allocated in group [hardgoodShippingGroup] and is pending delivery]]></set-property>
  <!-- export is false   <set-property name="version"><![CDATA[15]]></set-property>  -->
  <set-property name="lowBound"><![CDATA[0]]></set-property>
  <set-property name="shippingGroup"><![CDATA[sg20290002]]></set-property>
  <set-property name="relationshipClassType"><![CDATA[shippingGroupCommerceItem]]></set-property>
  <set-property name="type"><![CDATA[shipItemRel]]></set-property>
  <set-property name="relationshipType"><![CDATA[SHIPPINGQUANTITY]]></set-property>
  <set-property name="commerceItem"><![CDATA[ci1389000004]]></set-property>
</add-item>

---------------------------------------

package com.ngp.scheduler;

import java.util.Date;
import javax.transaction.TransactionManager;

import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

import atg.service.scheduler.SchedulableService;
import atg.service.scheduler.Scheduler;
import atg.service.scheduler.ScheduledJob;
import atg.repository.Repository;
import atg.repository.RepositoryItem;
import atg.repository.RepositoryView;
import atg.repository.RepositoryException;
import atg.repository.MutableRepository;
import atg.repository.MutableRepositoryItem;
import atg.repository.RepositoryUtils;
import atg.repository.rql.RqlStatement;
import atg.dtm.TransactionDemarcation;
import atg.dtm.TransactionDemarcationException;
import atg.userprofiling.email.TemplateEmailException;
import atg.userprofiling.email.TemplateEmailSender;
import atg.userprofiling.email.TemplateEmailInfoImpl;
import atg.userprofiling.ProfileTools;
import atg.commerce.CommerceException;

import com.ngp.commerce.catalog.NGPCatalogService;
import com.ngp.configuration.NGPStoreConfiguration;
import com.ngp.configuration.NGPStoreConfigurationContainer;
import com.ngp.userprofiling.email.NGPGenericEmailSender;

public class AlertScheduler extends SchedulableService {
    private NGPCatalogService catalogService;
    private Repository profileRepository;
    private TransactionManager transactionManager;
    private TemplateEmailSender emailSender;
    private TemplateEmailInfoImpl emailTemplate;
    private TemplateEmailInfoImpl textTemplate;
    private ProfileTools profileTools;
    private NGPStoreConfigurationContainer storeConfigurationContainer;
       
    private final static String PRICE_DROP_TYPE = "Price Drop";
    private final static String REBATE_ADDED_TYPE = "Rebate Added";
    private final static String GIFT_ADDED_TYPE = "Gift Added";
    private final static String ON_SALE_TYPE = "On Sale";
    private final static String IN_STOCK_TYPE = "In Stock";
    private final static String MOVED_TO_CLEARENCE_TYPE = "Moved To Clearence";
   
    public void performScheduledTask(Scheduler pScheduler, ScheduledJob pJob) {
        createAlertEmails();
    }

    public void createAlertEmails() {
        if (isLoggingDebug()) {
            logDebug("AlertScheduler starting");
        }
        // Clear data from the last run
        emailAlertMessages = new HashMap <String, Map<String, List<Map<String, RepositoryItem>>>>();
        textAlertMessages  = new HashMap <String, List<Map<String, RepositoryItem>>>();

        // Get all enabled notifications in the system.
        RqlStatement findEnabledAlerts;
        RepositoryView alertView;
        RepositoryItem[] activeAlerts;
        try {
            findEnabledAlerts = RqlStatement.parseRqlStatement("enabled = true");
            alertView = profileRepository.getView("alert-item");
            activeAlerts = findEnabledAlerts.executeQuery(alertView, null);
        } catch (RepositoryException e) {
            if (isLoggingError()) {
                logError("Unable to get alert-item report, aborting", e);
            }
            return;
        }
       
        if (isLoggingDebug()) {
            logDebug("Working on alerts, active alerts: " + activeAlerts);
        }
        List<String> alertsToRemove = new LinkedList<String>();
       
       
        if (activeAlerts != null ) {
            for (RepositoryItem alert : activeAlerts) {
                String type = (String) alert.getPropertyValue("type");
                String skuId = (String) alert.getPropertyValue("commerceItemId");
                if (skuId == null ) {
                    if (isLoggingError()) {
                        logError("Error Getting item Id from alert, null sku found for alert " + alert.getRepositoryId() + " removing alert");
                    }
                    alertsToRemove.add(alert.getRepositoryId());
                    continue;
                }
                RepositoryItem sku = catalogService.retrieveSkuItemBySkuId(skuId);
                if (sku == null ) {
                    if (isLoggingError()) {
                        logError(new StringBuilder("createAlertEmails: Unable to find SKU ")
                                .append(skuId)
                                .append(" for alert ")
                                .append(alert.getRepositoryId())
                                .append(" removing alert ")
                                .toString());
                    }
                    alertsToRemove.add(alert.getRepositoryId());
                    continue;
                }
                boolean alerted = false;
                if (isLoggingDebug()) {
                    logDebug("Alert " + alert.getRepositoryId() + " Type: " + type + " Sku: " + skuId + " alerted? " + alerted) ;
                }

                try {
                    if (PRICE_DROP_TYPE.equals(type)) {
                        if (catalogService.isPriceDropSku(sku)) {
                            alerted = addAlertMessage(sku, alert);
                        }
                    }
                    else if (REBATE_ADDED_TYPE.equals(type)) {
                        RepositoryItem parentProduct = catalogService.getParentProduct(sku);
                        if (catalogService.productHasRebate(parentProduct)) {
                            alerted = addAlertMessage(sku, alert);
                        }
                    }
                    else if (GIFT_ADDED_TYPE.equals(type)) {
                        RepositoryItem parentProduct = catalogService.getParentProduct(sku);
                        if (catalogService.hasGiftItem(parentProduct)) {
                            alerted = addAlertMessage(sku, alert);
                        }

                    }
                    else if (ON_SALE_TYPE.equals(type)) {
                        if (isLoggingDebug()) {
                            logDebug("Testing on sale sku " + catalogService.isOnsaleSku(sku));
                        }

                        if (catalogService.isOnsaleSku(sku)) {
                            alerted = addAlertMessage(sku, alert);
                        }
                    }
                    else if (IN_STOCK_TYPE.equals(type)) {
                        if (catalogService.isInStock(sku)) {
                            alerted = addAlertMessage(sku, alert);
                        }
                    }
                    else if (MOVED_TO_CLEARENCE_TYPE.equals(type)) {
                        if (catalogService.isClearanceSku(sku)) {
                            alerted = addAlertMessage(sku, alert);
                        }
                    }
                } catch (Exception e) {
                    if (isLoggingError()) {
                        logError(new StringBuilder("createAlertEmails: Exception caught while testing alert conditions for alert ")
                                .append(alert.getRepositoryId())
                                .append(". The exception was ")
                                .append(e.getClass().toString())
                                .append(":")
                                .append(e.getMessage())                               
                                .toString());
                    }
                }
                if (isLoggingDebug()) {
                    logDebug("Alert " + alert.getRepositoryId() + " Type: " + type + " Sku: " + skuId + " alerted? " + alerted) ;
                }
               
            }
            sendAlerts();


        }
        if (isLoggingDebug()) {
            logDebug("createAlertEmails Deleting problem alerts");
        }
        for (String alertId : alertsToRemove ) {
            MutableRepository mutProfileRepository = (MutableRepository) profileRepository;
            try {
                mutProfileRepository.removeItem(alertId, "alert-item");
            } catch (RepositoryException e) {
                if (isLoggingError()) {
                    logError(new StringBuilder("createAlertEmails: Attempting to remove alert ")
                            .append(alertId)
                            .append(" resulted in an exception ")
                            .append(e.toString())
                            .toString());
                }
            }
           
        }
       
       
        if (isLoggingDebug()) {
            logDebug("AlertScheduler exiting");
        }

       
    }
    Map<String, Map<String, List<Map<String, RepositoryItem>>>> emailAlertMessages
        = new HashMap <String, Map<String, List<Map<String, RepositoryItem>>>>();

    Map<String, List<Map<String, RepositoryItem>>> textAlertMessages
        = new HashMap<String, List<Map<String, RepositoryItem>>>();

    Map<String, RepositoryItem> profileMap = new HashMap<String, RepositoryItem>();
    public boolean addAlertMessage(RepositoryItem sku, RepositoryItem alert) {
        if (isLoggingDebug()) {
            logDebug("AlertSecheduler.addAlertMessage starting" );
        }
       
        String method = (String) alert.getPropertyValue("alertMethod");
        String type   = (String) alert.getPropertyValue("type");
        String email  = (String) alert.getPropertyValue("email");
                   
        List<Map<String, RepositoryItem>> alertList;
        if ("Email".equals(method)) {
 
            if (emailAlertMessages.get(email) == null) {
                if (isLoggingDebug())
                    logDebug("Email list does not exist, adding");
                emailAlertMessages.put(email,  new HashMap<String, List<Map<String, RepositoryItem>>>());
                profileMap.put(email, (RepositoryItem) alert.getPropertyValue("profile"));
            }
            if (emailAlertMessages.get(email).get(type) == null) {
                if (isLoggingDebug())
                    logDebug("Type does not exist for email addres, adding" );
                emailAlertMessages.get(email).put(type, new ArrayList<Map<String, RepositoryItem>>());
            }
            if (isLoggingDebug())
                logDebug("Fetching alertlist for email " + email + "and type " + type);
            alertList = emailAlertMessages.get(email).get(type);
           
           
        }
        else if ("Text".equals(method)) {
            if (textAlertMessages.get(email) == null) {
                textAlertMessages.put(email, new ArrayList<Map<String, RepositoryItem>>());
                profileMap.put(email, (RepositoryItem) alert.getPropertyValue("profile"));
            }
            alertList = textAlertMessages.get(email);

        }
        else {
            return false;
        }

        HashMap<String, RepositoryItem> alertData = new HashMap<String,RepositoryItem>();
        if (isLoggingDebug()) {
            logDebug("Adding alert message of type " + type + " and method " + method + " to address " + email);

        }

        alertData.put("sku", sku);
        alertData.put("alert", alert);
        alertList.add(alertData);


        return true;

    }

    public void sendAlerts() {
       
        for (Map.Entry <String, Map<String, List<Map<String, RepositoryItem>>>> emailEntry : emailAlertMessages.entrySet()) {
            if (isLoggingDebug()) {
                logDebug("Sending alert for " + emailEntry.getKey() + " with " + emailEntry.getValue() +  " types" );
            }

            if (sendAlertMessage(emailEntry.getKey(), emailEntry.getValue(), false, null)) {
                for (List<Map<String, RepositoryItem>> alertList : emailEntry.getValue().values() ) {
                    for (Map<String,RepositoryItem> alertData : alertList ) {
                        markAlert(alertData.get("alert"));
                    }
                }
            }
           
        }


        // Send text messages
        for (Map.Entry<String, List<Map<String, RepositoryItem>>> textEntry : textAlertMessages.entrySet()) {
            if (isLoggingDebug()) {
                logDebug("Sending text alert for " + textEntry.getKey() + " with " + textEntry.getValue() );
            }
            for(Map<String, RepositoryItem> messageDetails : textEntry.getValue()) {
                String type = (String) messageDetails.get("alert").getPropertyValue("type");
                Map<String, List<Map<String, RepositoryItem>>> message = new HashMap<String, List<Map<String, RepositoryItem>>>();
                message.put(type, new ArrayList<Map<String, RepositoryItem>>());
                message.get(type).add(messageDetails);
                if (sendAlertMessage(textEntry.getKey(), message, true, null) ) {
                    markAlert(messageDetails.get("alert"));
                }
               
            }

        }

    }

   
    public boolean sendAlertMessage(String email, Map<String, List<Map<String, RepositoryItem>>> message, Boolean isText, String messageId) {
        if (isLoggingDebug()) {
            logDebug("AlertScheduler.sendEmail starting for alert");
        }
        RepositoryItem profile = profileMap.get(email);
       
      
        MutableRepositoryItem mutProfile = (MutableRepositoryItem) profile;
        try {
            String profileEmail = (String) profile.getPropertyValue("email");
          
            if(null == profileEmail || ! profileEmail.equals(email) ) {
                if (isLoggingDebug()) {
                    logDebug("Profile emails do not match, alert is going to a different email");
                }
                mutProfile = ((MutableRepository) profileRepository).createItem("user");
                mutProfile.setPropertyValue("firstName", profile.getPropertyValue("firstName"));
                mutProfile.setPropertyValue("lastName", profile.getPropertyValue("lastName"));
                mutProfile.setPropertyValue("salePriceList", profile.getPropertyValue("salePriceList"));
                mutProfile.setPropertyValue("priceList", profile.getPropertyValue("priceList"));
                if (isLoggingDebug())
                    logDebug("Setting site in temporary profile to " + profile.getPropertyValue("site"));
                mutProfile.setPropertyValue("site", profile.getPropertyValue("site"));
               
                try {
                    mutProfile.setPropertyValue("email", email);
                } catch (Exception e) {
                    if (isLoggingError()) {
                        logError("Unable to send alert data to email " + email, e);
                    }
                    return false;
                }
            }
           
           
        HashMap<String, Object> argMap = new HashMap<String,Object>();
        if (messageId == null) {
            messageId = mutProfile.getRepositoryId();
        }
        String datakey = "alertData:" + messageId;
        argMap.put(datakey, message);
       
        if (isLoggingDebug()) {
            logDebug("Alert message contains " + message.size() + " type " + message.values().size() );   
            logDebug("Alert data key is " + datakey);
            logDebug("Sending alert for " + email + " with " + message +  " types" );
        }
       
        if(message.size() == 0)
        {
            if (isLoggingError()) {
                logError("alert message size is Zero for " + email + " , not sending email at the moment");
            }
            return false;
        }

        TemplateEmailInfoImpl template = emailTemplate;
        if (isText) {
            template = textTemplate;
        }
       
        RepositoryItem site = (RepositoryItem) mutProfile.getPropertyValue("site");
        String siteId = (String) site.getPropertyValue("id");
        template.setMessageFrom(getDefaultEmailFrom(siteId));
        if (isLoggingDebug())
            logDebug("Setting site in arg map to " + siteId);
        argMap.put("site", siteId);
            profileTools.sendEmailToUser(mutProfile, false, false, emailSender, template, argMap);
        } catch (Exception e) {
            if (isLoggingError()) {
                logError("Cannot send email for alert to " +email , e);
            }
            return false;
        }
        return true;
    }

    public void markAlert(RepositoryItem alert) {

        TransactionDemarcation td = new TransactionDemarcation();
        TransactionManager tm = getTransactionManager();
                   
        try {
            td.begin(tm);
            try {
                MutableRepository mutProfileRepository = (MutableRepository) profileRepository;
           
                MutableRepositoryItem mutAlertHistory = mutProfileRepository.createItem("alert-history");
                mutAlertHistory.setPropertyValue("alertDate" , new Date());
                mutAlertHistory.setPropertyValue("alertMethod", alert.getPropertyValue("alertMethod"));
                mutProfileRepository.addItem(mutAlertHistory);
                   
                MutableRepositoryItem mutAlert = mutProfileRepository.getItemForUpdate(alert.getRepositoryId(), "alert-item");
                mutAlert.setPropertyValue("enabled", false);
                ((java.util.List) mutAlert.getPropertyValue("alertHistory")).add(mutAlertHistory);
                mutProfileRepository.updateItem(mutAlert);
            } catch (RepositoryException e) {
                if (isLoggingError()) {
                    logError("AlertScheduler unable to update alert with history, and disable " + alert.getRepositoryId(), e);
                }
            }
           
        } catch (TransactionDemarcationException e) {
            if (isLoggingError()) {
                logError("AlertScheduler unable to update alert with history, and disable " + alert.getRepositoryId(), e);
            }
        } finally {
            try {
                td.end();
            } catch (TransactionDemarcationException e) {
                if (isLoggingError()) {
                    logError("AlertScheduler unable to update alert with history, and disable " + alert.getRepositoryId(), e);
                }
               
            }
       
        }
    }
   
    private String getDefaultEmailFrom(String siteId) {

        String defaultEmailFrom = "";
        NGPStoreConfiguration storeConfig = getStoreConfigurationContainer().getStoreConfiguration(siteId);
        if (storeConfig != null) {
            defaultEmailFrom = storeConfig.getDefaultEmailFrom();
            if (isLoggingDebug())
                logDebug("defaultEmailFrom : " + defaultEmailFrom);
        }

        return defaultEmailFrom;
    }
   
    public void setProfileRepository(Repository profileRepo) {
        this.profileRepository = profileRepo;
    }
   
    public Repository getProfileRepository() {
        return profileRepository;
    }

    public void setCatalogService(NGPCatalogService catalogService) {
        this.catalogService = catalogService;
    }
   
    public NGPCatalogService getCatalogService() {
        return catalogService;
    }                                                          

    public void setTransactionManager(TransactionManager tm) {
        this.transactionManager = tm;
    }

    public TransactionManager getTransactionManager() {
        return  transactionManager;
    }
   
    public void setEmailSender(TemplateEmailSender emailSender) {
        this.emailSender = emailSender;
    }

    public TemplateEmailSender getEmailSender() {
        return emailSender;
    }
   
    public void setEmailTemplate(TemplateEmailInfoImpl emailTemplate) {
        this.emailTemplate = emailTemplate;
    }

    public TemplateEmailInfoImpl getEmailTemplate() {
        return this.emailTemplate;
    }

    public void setTextTemplate(TemplateEmailInfoImpl textTemplate) {
        this.textTemplate = textTemplate;
    }

    public TemplateEmailInfoImpl getTextTemplate() {
        return this.textTemplate;
    }

    public void setProfileTools(ProfileTools profileTools) {
        this.profileTools = profileTools;
    }

    public ProfileTools  getProfiieTools() {
        return profileTools;
    }
   
    public NGPStoreConfigurationContainer getStoreConfigurationContainer() {

        return storeConfigurationContainer;
    }

    public void setStoreConfigurationContainer(NGPStoreConfigurationContainer storeConfigurationContainer) {

        this.storeConfigurationContainer = storeConfigurationContainer;
    }

}
  ----------------------------