Пример #1
0
        /// <summary>
        /// Get Dialing parameters
        /// </summary>
        /// <param name="camp"></param>
        /// <returns></returns>
        public static DialingParameter GetDialParam(Campaign objCampaign)
        {
            CampaignService  objCampaignService  = null;
            DialingParameter objDialingParameter = null;
            XmlDocument      xDocCampaign        = null;

            try
            {
                objCampaignService = new CampaignService();
                xDocCampaign       = new XmlDocument();
                xDocCampaign.LoadXml(Serialize.SerializeObject(objCampaign, "Campaign"));
                objDialingParameter = (DialingParameter)Serialize.DeserializeObject(
                    objCampaignService.GetDialingParameter(xDocCampaign), "DialingParameter");
                if (objDialingParameter.DailingParameterID == 0)
                {
                    return(null);
                }
                // *** Temp to pull algorithm settings from app config.  to be added to db per campaign
                objDialingParameter.ActiveDialingAlgorithm = Convert.ToInt16(Utilities.GetAppSetting("ActiveDialingAlgorithm", "1"));
                objDialingParameter.CallStatisticsWindow   = Convert.ToInt16(Utilities.GetAppSetting("PredictionCallStatsWindow", "100"));
                objDialingParameter.DropRateThrottle       = Convert.ToDecimal(Utilities.GetAppSetting("dropRateThrottle", "1"));
                DialerEngine.Log.Write("|CA|{0}|{1}|Dialing parameters refreshed. Algortihm {2}, stats window {3}, throttle {4}", objCampaign.CampaignID, objCampaign.ShortDescription, objDialingParameter.ActiveDialingAlgorithm, objDialingParameter.CallStatisticsWindow, objDialingParameter.DropRateThrottle);
            }

            catch (Exception ex)
            {
                DialerEngine.Log.WriteException(ex, "Error in GetDialParam");
                throw ex;
            }
            finally
            {
                objCampaignService = null;
                //objDialingParameter = null;
                xDocCampaign = null;
            }
            return(objDialingParameter);
        }
        /// <summary>
        /// Start campaigns for dialing
        /// </summary>
        /// <param name="campaign"></param>
        /// <returns></returns>
        private void StartCampaignProcess()
        {
            Log.Write("|DE|Checking for start times for {0} new campaigns.", qCampaignQueue.Count);
            if (qCampaignQueue.Count == 0)
            {
                // no campaigns
                DialerEngine.Log.Write("No active campaigns found");
                return;
            }

            // clear
            GC.Collect();
            try
            {
                ThreadStart ts = null;

                while (qCampaignQueue.Count != 0)
                {
                    Campaign objCampaign = null;
                    lock (qCampaignQueue)
                    {
                        objCampaign = qCampaignQueue.Dequeue();
                    }
                    // add to running list
                    // m_RunningCampaignIdList.Add(campaign.CampaignID.ToString());

                    DialingParameter objDialParam   = CampaignAPI.GetDialParam(objCampaign);
                    OtherParameter   objOtherParam  = null;
                    bool             bStartCampaign = false;

                    CallType callType = CallType.AMCall;
                    DateTime dtStartTime;
                    if (DateTime.Now.Hour >= 12)
                    {
                        callType    = CallType.PMCall;
                        dtStartTime = objDialParam.PMDialingStart;
                    }
                    else
                    {
                        dtStartTime = objDialParam.AMDialingStart;
                    }

                    int iCurrHour    = DateTime.Now.Hour;
                    int iCurrMinutes = DateTime.Now.Minute;
                    int iDPhour      = dtStartTime.Hour;
                    int iDPMinutes   = dtStartTime.Minute;

                    //-------------------------------------------------
                    // We ignore time issue for anything
                    // other than unmanned campaigns.
                    //-------------------------------------------------
                    Log.Write("|DE|Campaign - Dialing Mode: {0})", objDialParam.DialingMode.ToString());
                    if (objDialParam.DialingMode != 6)
                    {
                        bStartCampaign = true;
                    }
                    else if (iCurrHour > iDPhour || ((iCurrHour == iDPhour) && (iCurrMinutes >= iDPMinutes)))
                    {
                        bStartCampaign = true;
                    }

                    try
                    {
                        if (bStartCampaign)
                        {
                            DigitalizedRecording digRecording = CampaignAPI.GetDigitizedRecordings(objCampaign);

                            objOtherParam = CampaignAPI.GetOtherParam(objCampaign);

                            CampaignProcess campProcess = new CampaignProcess(objCampaign, objDialParam, objOtherParam);
                            if (digRecording != null)
                            {
                                campProcess.RecordingsPath = digRecording.RecordingFilePath;
                                campProcess.RecordCalls    = digRecording.EnableRecording;
                                campProcess.RecordBeep     = digRecording.StartWithABeep;
                            }

                            // weekend call checking
                            if (DateTime.Now.DayOfWeek == DayOfWeek.Saturday ||
                                DateTime.Now.DayOfWeek == DayOfWeek.Sunday)
                            {
                                callType = CallType.WkendCall;
                            }

                            campProcess.CallType = callType;

                            Log.Write("|DE|Starting campaign '{0}'.", objCampaign.ShortDescription);

                            // Start campaignprocess thread.  Different startup method for normal / unmanned mode
                            if (objDialParam.DialingMode == Convert.ToInt32(DialingMode.Unmanned))
                            {
                                ts = new ThreadStart(campProcess.RunCampaignUnmannedMode);
                            }
                            else
                            {
                                ts = new ThreadStart(campProcess.RunCampaign);
                            }
                            Thread t = new Thread(ts);
                            t.Priority     = ThreadPriority.Normal;
                            t.IsBackground = true;
                            t.Name         = objCampaign.ShortDescription.ToString();

                            lock (lstCampaignThreads)
                            {
                                lstCampaignThreads.Add(t);
                            }
                            if (objDialParam.DialingMode != Convert.ToInt32(DialingMode.ManualDial))
                            {
                                t.Start();
                            }
                        }
                        else
                        {
                            Log.Write("|DE|Campaign '{0}' not started, outside of schedule range. (Start time = {1}:{2})",
                                      objCampaign.ShortDescription, iDPhour.ToString(), iDPMinutes.ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex, "Error in Starting Campaign " + objCampaign.ShortDescription);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteException(ex, "Error in StartCampaignProcess");
            }
            finally
            {
                //
            }
        }
Пример #3
0
        public int[] CalculateNextCallTime(DialingParameter dialingParameters, CampaignStats campStats, int totalAgentCount, int availableAgentCount, decimal currentDropRate, int currentlyDialingCallCount)
        {
            int[] delayOrCallCount = new int[2];
            // First calculate current Probability of Answer
            m_ProbabilityOfAnswer = GetProbabilityOfAnswer(campStats);

            // Check number of required dialing calls per throttle setting
            m_RequiredDialingCalls = (int)((1 - m_ProbabilityOfAnswer) * availableAgentCount) + availableAgentCount;

            if (currentlyDialingCallCount < m_RequiredDialingCalls)
            {
                delayOrCallCount[0] = (dialingParameters.MinimumDelayBetweenCalls * 1000);
                delayOrCallCount[1] = m_RequiredDialingCalls - currentlyDialingCallCount;
                // By throttle, we don't even have enough pending calls, fire immediate calls and exit.
                DialerEngine.Log.Write("|PR|{0}|{1}|Current POA vs agent inverse ratio of {2} requires {3} pending calls with min delay set to {4}, triggering {5} immediate calls.", objCampaign.CampaignID, objCampaign.ShortDescription, (1 - m_ProbabilityOfAnswer), m_RequiredDialingCalls, dialingParameters.MinimumDelayBetweenCalls, delayOrCallCount[1]);
                return(delayOrCallCount);
            }

            // Check current drop rate and pause accordingly
            if (currentDropRate > dialingParameters.DropRatePercent)
            {
                // Drop rate threshold exceeded, pause dialing until it falls.  Keep in mind, the throttle, etc will still function because they are Before this trap
                DialerEngine.Log.Write("|PR|{0}|{1}|Drop rate of {2}% exceeds max setting of {3}%, pausing dialing.", objCampaign.CampaignID, objCampaign.ShortDescription, currentDropRate, dialingParameters.DropRatePercent);
                delayOrCallCount[0] = -1;
                return(delayOrCallCount);
            }

            // Check acceleration towards drop rate
            decimal currentDropRateAcceleration = _dropRateTimer.IsRunning ? (_lastDropRate - currentDropRate) / (_dropRateTimer.ElapsedMilliseconds) * 60000 : 0.00m;

            _dropRateTimer.Reset();
            _dropRateTimer.Start();

            _lastDropRate = currentDropRate;

            decimal targetDropRateAcceleration =
                dialingParameters.DropRatePercent > 0
                ? (1 - currentDropRate / dialingParameters.DropRatePercent) * dialingParameters.DropRateThrottle
                : 0;

            if (currentDropRateAcceleration <= targetDropRateAcceleration)
            {
                DialerEngine.Log.Write
                (
                    "|PR|{0}|{1}|Drop rate of {2}% is under max setting of {3}%.  Drop Rate Acceleration Per Minute is Maximum: {4}, Current: {5}, Target: {6}. Keep dialing.",
                    objCampaign.CampaignID,
                    objCampaign.ShortDescription,
                    currentDropRate,
                    dialingParameters.DropRatePercent,
                    dialingParameters.DropRateThrottle,
                    currentDropRateAcceleration,
                    targetDropRateAcceleration
                );

                delayOrCallCount[0] = (dialingParameters.MinimumDelayBetweenCalls * 1000);

                return(delayOrCallCount);
            }

            // Main Algorithm calculation, all above traps have been avoided, now we do a predictive calculation of next call time and return it.

            m_AvgAgentBusyTime = campStats.GetAAIUT();
            m_AvgTimeToAnswer  = campStats.GetATTA();
            m_AvgCallTime      = campStats.GetACT();

            decimal delayToNextCall = 0;

            if (m_AvgAgentBusyTime > m_AvgTimeToAnswer)
            {
                delayToNextCall = m_AvgAgentBusyTime - m_AvgTimeToAnswer + dialingParameters.MinimumDelayBetweenCalls;
            }
            else
            {
                delayToNextCall = dialingParameters.MinimumDelayBetweenCalls;
                try
                {
                    delayToNextCall = Math.Max(delayToNextCall, m_AvgCallTime);
                }
                catch { }
            }


            if (totalAgentCount > 1)
            {
                delayToNextCall /= totalAgentCount;
            }

            delayOrCallCount[0] = Convert.ToInt32(Math.Floor(delayToNextCall * 1000));

            DialerEngine.Log.Write("|PR|{0}|{1}|Throttled algorithm calculated a delay of {5} MS: AABT - {2}, ATTA - {3}, ACT - {4}", objCampaign.CampaignID, objCampaign.ShortDescription, string.Format("{0:0.00}", m_AvgAgentBusyTime), string.Format("{0:0.00}", m_AvgTimeToAnswer), string.Format("{0:0.00}", m_AvgCallTime), delayOrCallCount[0]);

            return(delayOrCallCount);
        }
Пример #4
0
        /// <summary>
        /// Get calllist for the query
        /// </summary>
        /// <param name="camp"></param>
        /// <param name="queryCondition"></param>
        /// <returns></returns>
        public static Queue <CampaignDetails> GetCallDetailsByQuery_Recyle_Last(string strCampaignDBConn, string queryCondition, DialingParameter objDialParameter, long queryId)
        {
            DataSet ds = null;
            Queue <CampaignDetails> queryCallQueue  = null;
            CampaignService         objCampService  = null;
            CampaignDetails         campaignDetails = null;

            try
            {
                queryCallQueue = new Queue <CampaignDetails>();
                // Get calllist for this campaign
                objCampService = new CampaignService();
                ds             = objCampService.GetCampaignData_Recycle_Last(strCampaignDBConn, queryCondition, queryId);
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    campaignDetails                  = new CampaignDetails();
                    campaignDetails.UniqueKey        = Convert.ToInt64(row["UniqueKey"]);
                    campaignDetails.PhoneNum         = row["PhoneNum"] != DBNull.Value ? (row["PhoneNum"]).ToString() : string.Empty;
                    campaignDetails.NumAttemptsAM    = row["NumAttemptsAM"] != DBNull.Value ? (row["NumAttemptsAM"]).ToString() : "0";
                    campaignDetails.NumAttemptsPM    = row["NumAttemptsPM"] != DBNull.Value ? (row["NumAttemptsPM"]).ToString() : "0";
                    campaignDetails.NumAttemptsWkEnd = row["NumAttemptsWkEnd"] != DBNull.Value ? (row["NumAttemptsWkEnd"]).ToString() : "0";
                    try
                    {
                        campaignDetails.ScheduleDate = row["ScheduleDate"] != DBNull.Value ? Convert.ToDateTime(row["ScheduleDate"]) : DateTime.MinValue;
                    }
                    catch { }

                    try
                    {
                        campaignDetails.OrderIndex = Convert.ToInt32(row["OrderIndex"]);
                    }
                    catch { }


                    bool maxAttemptsOver = false;
                    try
                    {
                        if (objDialParameter.AMCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsAM) &&
                            objDialParameter.PMCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsPM) &&
                            objDialParameter.WeekendCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsWkEnd))
                        {
                            maxAttemptsOver = true;
                        }
                    }
                    catch { }

                    if (!maxAttemptsOver)
                    {
                        queryCallQueue.Enqueue(campaignDetails);
                    }
                }
            }
            catch (Exception ex)
            {
                DialerEngine.Log.WriteException(ex, "Error in GetCallDetailsByQuery");
                throw ex;
            }
            finally
            {
                ds = null;
                //queryCallQueue = null;
                objCampService  = null;
                campaignDetails = null;
            }
            return(queryCallQueue);
        }
Пример #5
0
        /// <summary>
        /// Get calllist for the query
        /// </summary>
        /// <param name="camp"></param>
        /// <param name="queryCondition"></param>
        /// <returns></returns>
        public static Queue <CampaignDetails> GetCallDetailsByQuery(Campaign objCampaign, string queryCondition, DialingParameter objDialParameter)
        {
            // *** Note : This is running on every call ending.  May not be necessary to hit that often
            DataSet ds = null;
            Queue <CampaignDetails> queryCallQueue  = null;
            CampaignService         objCampService  = null;
            CampaignDetails         campaignDetails = null;
            string strCampaignDBConn = objCampaign.CampaignDBConnString;

            try
            {
                string availableQueryCondition = string.Format("{0} {1}", queryCondition, @"AND ( NeverCallFlag=0 or NeverCallFlag IS NULL ) 
			                AND (ScheduleDate is null OR DATEDIFF(dd,getdate(),ScheduleDate) <= 0)
			                AND ((DateTimeofCall is null AND (CallResultCode is null OR CallResultCode = 0))
                                OR CallResultCode NOT IN (
				            SELECT DISTINCT ResultCodeID FROM ResultCode  
				            WHERE 
					            (Redialable = 0 OR NeverCall = 1 OR NeverCall = 2 OR DATEDIFF(dd, Campaign.DateTimeofCall ,GETDATE()) < RecycleInDays)))"                    );

                queryCallQueue = new Queue <CampaignDetails>();
                // Get calllist for this campaign
                objCampService = new CampaignService();
                ds             = objCampService.GetCampaignData(strCampaignDBConn, availableQueryCondition);
                DialerEngine.Log.Write("|CA|{0}|{1}|Query run of conditions '{2}' returns {3} records.", objCampaign.CampaignID, objCampaign.ShortDescription, availableQueryCondition, ds.Tables[0].Rows.Count);
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    campaignDetails                  = new CampaignDetails();
                    campaignDetails.UniqueKey        = Convert.ToInt64(row["UniqueKey"]);
                    campaignDetails.PhoneNum         = row["PhoneNum"] != DBNull.Value ? (row["PhoneNum"]).ToString() : string.Empty;
                    campaignDetails.NumAttemptsAM    = row["NumAttemptsAM"] != DBNull.Value ? (row["NumAttemptsAM"]).ToString() : "0";
                    campaignDetails.NumAttemptsPM    = row["NumAttemptsPM"] != DBNull.Value ? (row["NumAttemptsPM"]).ToString() : "0";
                    campaignDetails.NumAttemptsWkEnd = row["NumAttemptsWkEnd"] != DBNull.Value ? (row["NumAttemptsWkEnd"]).ToString() : "0";
                    try
                    {
                        campaignDetails.ScheduleDate = row["ScheduleDate"] != DBNull.Value ? Convert.ToDateTime(row["ScheduleDate"]) : DateTime.MinValue;
                    }
                    catch { }

                    try
                    {
                        campaignDetails.OrderIndex = 1;
                    }
                    catch { }

                    bool maxAttemptsOver = false;
                    try{
                        if (objDialParameter.AMCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsAM) &&
                            objDialParameter.PMCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsPM) &&
                            objDialParameter.WeekendCallTimes <= Convert.ToInt32(campaignDetails.NumAttemptsWkEnd))
                        {
                            maxAttemptsOver = true;
                        }
                    }
                    catch {}

                    if (!maxAttemptsOver)
                    {
                        queryCallQueue.Enqueue(campaignDetails);
                    }
                }
            }
            catch (Exception ex)
            {
                DialerEngine.Log.WriteException(ex, "Error in GetCallDetailsByQuery");
                throw ex;
            }
            finally
            {
                ds = null;
                //queryCallQueue = null;
                objCampService  = null;
                campaignDetails = null;
            }
            return(queryCallQueue);
        }