示例#1
0
def update_callrequest(callrequest, opt_hangup_cause):
    #Only the aleg will update the subscriber status / Bleg is only recorded
    #Update Callrequest Status
    if opt_hangup_cause == 'NORMAL_CLEARING':
        callrequest.status = CALLREQUEST_STATUS.SUCCESS
        if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
            callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
    else:
        callrequest.status = CALLREQUEST_STATUS.FAILURE
        callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
    callrequest.hangup_cause = opt_hangup_cause

    callrequest.save()
    callrequest.subscriber.save()
    debug_query(24)
示例#2
0
def update_callrequest(callrequest, opt_hangup_cause):
    # Only the aleg will update the subscriber status / Bleg is only recorded
    # Update Callrequest Status
    if opt_hangup_cause == 'NORMAL_CLEARING':
        callrequest.status = CALLREQUEST_STATUS.SUCCESS
        if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
            callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
    else:
        callrequest.status = CALLREQUEST_STATUS.FAILURE
        callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
    callrequest.hangup_cause = opt_hangup_cause

    callrequest.save()
    callrequest.subscriber.save()
    debug_query(24)
示例#3
0
def process_callevent(record):
    """
    Process the callevent, this tasks will:
        - Retrieve the callrequest using either callrequest_id or request_uuid
        - create the voipcall, and save different data
    """
    # TODO: add method in utils parse_callevent
    app_type = 'campaign'
    event_name = record[1]
    body = record[2]
    job_uuid = record[3]
    call_uuid = record[4]
    # used_gateway_id = record[5]
    callrequest_id = record[6]
    alarm_request_id = record[7]
    callerid = record[8]
    phonenumber = record[9]
    duration = record[10]
    billsec = record[11]
    hangup_cause = record[12]
    hangup_cause_q850 = record[13]
    starting_date = record[14]
    amd_status = record[17]
    leg = record[18]

    if event_name == 'BACKGROUND_JOB':
        # hangup cause come from body
        hangup_cause = body[5:]

    if hangup_cause == '':
        hangup_cause = body[5:]

    request_uuid = job_uuid
    opt_hangup_cause = hangup_cause
    debug_query(22)

    try:
        if callrequest_id == 0:
            callrequest = Callrequest.objects \
                .select_related('aleg_gateway', 'subscriber', 'campaign') \
                .get(request_uuid=request_uuid.strip(' \t\n\r'))
        else:
            # mainly coming here
            callrequest = Callrequest.objects \
                .select_related('aleg_gateway', 'subscriber', 'campaign') \
                .get(id=callrequest_id)
    except:
        logger.error("Cannot find Callrequest job_uuid : %s" % job_uuid)
        return True

    if callrequest.alarm_request_id:
        app_type = 'alarm'
        alarm_req = AlarmRequest.objects.get(pk=callrequest.alarm_request_id)
        # Overwrite alarm_request_id as this is equal to 0 when call fails
        alarm_request_id = callrequest.alarm_request_id

    logger.debug("Find Callrequest id : %d" % callrequest.id)
    debug_query(23)

    if leg == 'aleg' and app_type == 'campaign':
        # Update callrequest
        # update_callrequest.delay(callrequest, opt_hangup_cause)
        # Disabled above tasks to reduce amount of tasks

        # Only the aleg will update the subscriber status / Bleg is only recorded
        # Update Callrequest Status
        if opt_hangup_cause == 'NORMAL_CLEARING':
            callrequest.status = CALLREQUEST_STATUS.SUCCESS
            if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
                callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
        else:
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
        callrequest.hangup_cause = opt_hangup_cause
        # ...

        callrequest.save()
        callrequest.subscriber.save()
        debug_query(24)
    elif leg == 'aleg' and app_type == 'alarm':
        try:
            caluser_profile = CalendarUserProfile.objects.get(
                user=alarm_req.alarm.event.creator)
        except CalendarUserProfile.DoesNotExist:
            logger.error("Error retrieving CalendarUserProfile")
            return False

        if opt_hangup_cause == 'NORMAL_CLEARING' and \
           amd_status == 'machine' and \
           caluser_profile.calendar_setting.voicemail and \
           caluser_profile.calendar_setting.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY:
            # Call reached AMD
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            alarm_req.status = ALARMREQUEST_STATUS.FAILURE
            alarm_req.alarm.status = ALARM_STATUS.FAILURE
        elif opt_hangup_cause == 'NORMAL_CLEARING':
            # Call is successful
            callrequest.status = CALLREQUEST_STATUS.SUCCESS
            alarm_req.status = ALARMREQUEST_STATUS.SUCCESS
            alarm_req.duration = duration
            alarm_req.alarm.status = ALARM_STATUS.SUCCESS
        else:
            # Call failed
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            alarm_req.status = ALARMREQUEST_STATUS.FAILURE
            alarm_req.alarm.status = ALARM_STATUS.FAILURE
        callrequest.hangup_cause = opt_hangup_cause

        callrequest.save()
        alarm_req.save()
        alarm_req.alarm.save()
        debug_query(24)

    if call_uuid == '':
        call_uuid = job_uuid
    if callerid == '':
        callerid = callrequest.callerid
    if phonenumber == '':
        phonenumber = callrequest.phone_number
    # Create those in Bulk - add in a buffer until reach certain number
    # buff_voipcall.save(
    #     obj_callrequest=callrequest,
    #     request_uuid=request_uuid,
    #     leg=leg,
    #     hangup_cause=opt_hangup_cause,
    #     hangup_cause_q850=hangup_cause_q850,
    #     callerid=callerid,
    #     phonenumber=phonenumber,
    #     starting_date=starting_date,
    #     call_uuid=call_uuid,
    #     duration=duration,
    #     billsec=billsec,
    #     amd_status=amd_status)

    # debug_query(25)

    voipcall_save(callrequest=callrequest,
                  request_uuid=request_uuid,
                  leg=leg,
                  hangup_cause=opt_hangup_cause,
                  hangup_cause_q850=hangup_cause_q850,
                  callerid=callerid,
                  phonenumber=phonenumber,
                  starting_date=starting_date,
                  call_uuid=call_uuid,
                  duration=duration,
                  billsec=billsec,
                  amd_status=amd_status)

    # If the call failed we will check if we want to make a retry call
    # Add condition to retry when it s machine and we want to reach a human
    if (app_type == 'campaign' and opt_hangup_cause != 'NORMAL_CLEARING'
        and callrequest.call_type == CALLREQUEST_TYPE.ALLOW_RETRY) or \
       (app_type == 'campaign' and amd_status == 'machine' and callrequest.campaign.voicemail and
            callrequest.campaign.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY):
        # Update to Retry Done
        callrequest.call_type = CALLREQUEST_TYPE.RETRY_DONE
        callrequest.save()

        debug_query(26)

        # check if we are allowed to retry on failure
        if ((callrequest.subscriber.count_attempt - 1) >=
                callrequest.campaign.maxretry
                or not callrequest.campaign.maxretry):
            logger.error("Not allowed retry - Maxretry (%d)" %
                         callrequest.campaign.maxretry)
            # Check here if we should try for completion
            check_retrycall_completion(callrequest)
            debug_query(28)
        else:
            # Allowed Retry
            logger.error("Allowed Retry - Maxretry (%d)" %
                         callrequest.campaign.maxretry)

            # Create new callrequest, Assign parent_callrequest,
            # Change callrequest_type & num_attempt
            new_callrequest = Callrequest(
                request_uuid=uuid1(),
                parent_callrequest_id=callrequest.id,
                call_type=CALLREQUEST_TYPE.ALLOW_RETRY,
                num_attempt=callrequest.num_attempt + 1,
                user=callrequest.user,
                campaign_id=callrequest.campaign_id,
                aleg_gateway_id=callrequest.aleg_gateway_id,
                content_type=callrequest.content_type,
                object_id=callrequest.object_id,
                phone_number=callrequest.phone_number,
                timelimit=callrequest.timelimit,
                callerid=callrequest.callerid,
                timeout=callrequest.timeout,
                subscriber_id=callrequest.subscriber_id)
            new_callrequest.save()
            # NOTE : implement a PID algorithm
            second_towait = callrequest.campaign.intervalretry
            debug_query(29)

            logger.debug("Init Retry CallRequest in  %d seconds" %
                         second_towait)
            init_callrequest.apply_async(args=[
                new_callrequest.id, callrequest.campaign.id,
                callrequest.campaign.callmaxduration
            ],
                                         countdown=second_towait)

    elif app_type == 'campaign':
        # The Call is Answered and it's a campaign call
        logger.info("Check for completion call")

        # Check if we should relaunch a new call to achieve completion
        check_retrycall_completion(callrequest)

    elif (opt_hangup_cause != 'NORMAL_CLEARING' and app_type == 'alarm') or \
         (amd_status == 'machine' and app_type == 'alarm' and
          caluser_profile.calendar_setting.voicemail and
          caluser_profile.calendar_setting.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY):
        # Alarm callrequest failed or Alarm callrequest reached voicemail
        logger.info("Check to retry alarm")
        check_retry_alarm(alarm_request_id)
    else:
        logger.info("Retry: No matching conditions")
示例#4
0
    def run(self, campaign_id):
        """
        This task retrieves the next outbound call to be made for a given
        campaign, and will create a new callrequest and schedule a task to
        process those calls

        **Attributes**:

            * ``campaign_id`` - Campaign ID
        """
        logger = self.get_logger()
        logger.info("TASK :: pending_call_processing = %d" % campaign_id)

        debug_query(0)

        try:
            obj_campaign = Campaign.objects\
                .select_related('user__userprofile__dialersetting', 'aleg_gateway', 'content_type')\
                .get(id=campaign_id)
        except:
            logger.error("Can't find this campaign")
            return False

        # TODO : Control the Speed
        # if there is many task pending we should slow down
        frequency = obj_campaign.frequency  # default 10 calls per minutes

        debug_query(1)

        #TODO: move this logic of setting call_type after CallRequest post_save
        # Default call_type
        call_type = CALLREQUEST_TYPE.ALLOW_RETRY
        # Check campaign's maxretry
        if obj_campaign.maxretry == 0:
            call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        # Check user's dialer setting maxretry
        try:
            obj_campaign.user.userprofile.dialersetting
            if obj_campaign.user.userprofile.dialersetting.maxretry == 0:
                call_type = CALLREQUEST_TYPE.CANNOT_RETRY
        except ObjectDoesNotExist:
            logger.error("Can't find user's dialersetting")
            return False

        debug_query(2)

        # Speed
        # Check if the other tasks send for this campaign finished to be ran

        # Get the subscriber of this campaign
        # get_pending_subscriber get Max 1000 records
        if settings.HEARTBEAT_MIN == 1:  # 1 task per minute
            callfrequency = frequency  # task run only once per minute, so we can assign frequency
        else:
            callfrequency = int(frequency / settings.HEARTBEAT_MIN) + 1  # 1000 per minutes
            #callfrequency = int(frequency) + 1  # 1000 per minutes

        (list_subscriber, no_subscriber) = obj_campaign\
            .get_pending_subscriber_update(callfrequency, SUBSCRIBER_STATUS.IN_PROCESS)
        logger.info("##subscriber=%d campaign_id=%d callfreq=%d freq=%d" %
                    (no_subscriber, campaign_id, callfrequency, frequency))
        debug_query(3)

        if no_subscriber == 0:
            return False

        # Set time to wait for balanced dispatching of calls
        time_to_wait = (60.0 / settings.HEARTBEAT_MIN) / no_subscriber
        count = 0
        loopnow = datetime.utcnow()
        loopnow + timedelta(seconds=1.55)

        for elem_camp_subscriber in list_subscriber:
            # Loop on Subscriber and start the initcall's task
            count = count + 1
            second_towait = floor(count * time_to_wait)
            # ms_addtowait now used anymore, replaced by async eta
            ms_addtowait = (count * time_to_wait) - second_towait

            eta_delta = loopnow + timedelta(seconds=(count * time_to_wait))
            # as we use eta_delta ms_addtowait is set to 0
            ms_addtowait = 0

            logger.info("Init CallRequest in %d seconds (cmpg:%d,subscr:%d:eta_delta:%s)" %
                        (second_towait, campaign_id, elem_camp_subscriber.id, eta_delta))

            phone_number = elem_camp_subscriber.duplicate_contact
            debug_query(4)

            #Verify that the contact is authorized
            if not obj_campaign.is_authorized_contact(obj_campaign.user.userprofile.dialersetting, phone_number):
                logger.error("Error : Contact not authorized")
                elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                elem_camp_subscriber.save()
                continue
            #Verify that the contact is not in the DNC list
            if obj_campaign.dnc:
                res_dnc = DNCContact.objects.filter(dnc_id=obj_campaign.dnc_id, phone_number=phone_number)
                if res_dnc:
                    logger.error("Contact (%s) in DNC list" % phone_number)
                    elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                    elem_camp_subscriber.save()
                    continue
                else:
                    logger.debug("Contact (%s) not in DNC list" % phone_number)

            debug_query(5)

            #TODO: idea to speed up, create bluck of 10(Y) and then send a list
            # of callrequest_id to init_callrequest

            # Create Callrequest
            new_callrequest = Callrequest(
                status=CALLREQUEST_STATUS.PENDING,
                call_type=call_type,
                call_time=datetime.utcnow().replace(tzinfo=utc),
                timeout=obj_campaign.calltimeout,
                callerid=obj_campaign.callerid,
                caller_name=obj_campaign.caller_name,
                phone_number=phone_number,
                campaign=obj_campaign,
                aleg_gateway=obj_campaign.aleg_gateway,
                content_type=obj_campaign.content_type,
                object_id=obj_campaign.object_id,
                user=obj_campaign.user,
                extra_data=obj_campaign.extra_data,
                timelimit=obj_campaign.callmaxduration,
                subscriber=elem_camp_subscriber)
            new_callrequest.save()

            debug_query(6)

            second_towait = second_towait + settings.DELAY_OUTBOUND

            init_callrequest.apply_async(
                args=[new_callrequest.id, obj_campaign.id, obj_campaign.callmaxduration, ms_addtowait],
                # countdown=second_towait)
                eta=eta_delta)

            # Shell_plus
            # from dialer_cdr.tasks import init_callrequest
            # from datetime import datetime
            # new_callrequest_id = 112
            # obj_campaign_id = 3
            # countdown = 1
            # init_callrequest.apply_async(args=[new_callrequest.id, obj_campaign.id, obj_campaign.callmaxduration, ms_addtowait], countdown=1)

        debug_query(7)
        return True
示例#5
0
    def run(self, campaign_id):
        """
        This will execute the outbound calls in the campaign

        **Attributes**:

            * ``campaign_id`` - Campaign ID
        """
        logger = self.get_logger()
        logger.info("TASK :: spool_pending_call = %d" % campaign_id)

        debug_query(0)

        try:
            obj_campaign = Campaign.objects.select_related('user__userprofile__dialersetting', 'aleg_gateway', 'content_type').get(id=campaign_id)
        except:
            logger.error("Can't find this campaign")
            return False

        # TODO : Control the Speed
        # if there is many task pending we should slow down
        frequency = obj_campaign.frequency  # default 10 calls per minutes

        debug_query(1)

        # Default call_type
        call_type = CALLREQUEST_TYPE.ALLOW_RETRY
        # Check campaign's maxretry
        if obj_campaign.maxretry == 0:
            call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        # Check user's dialer setting maxretry
        if obj_campaign.user.userprofile.dialersetting:
            if obj_campaign.user.userprofile.dialersetting.maxretry == 0:
                call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        debug_query(2)

        # Speed
        # Check if the other tasks send for this campaign finished to be ran

        # Get the subscriber of this campaign
        # get_pending_subscriber get Max 1000 records
        if frequency >= 10:
            callfrequency = int(frequency / DIV_MIN) + 1  # 1000 per minutes 101
            #callfrequency = int(frequency) + 1  # 1000 per minutes 101
        else:
            callfrequency = frequency
        (list_subscriber, no_subscriber) = obj_campaign.get_pending_subscriber_update(callfrequency, SUBSCRIBER_STATUS.IN_PROCESS)
        logger.info("##subscriber=%d campaign_id=%d callfrequency=%d frequency=%d" % (no_subscriber, campaign_id, callfrequency, frequency))
        debug_query(3)

        if no_subscriber == 0:
            return False

        # Set time to wait for balanced dispatching of calls
        #time_to_wait = int(60 / DIV_MIN) / no_subscriber
        time_to_wait = 6.0 / no_subscriber
        count = 0

        for elem_camp_subscriber in list_subscriber:
            """Loop on Subscriber and start the initcall task"""
            count = count + 1
            second_towait = floor(count * time_to_wait)
            ms_addtowait = (count * time_to_wait) - second_towait
            logger.info("Init CallRequest in %d seconds (cmpg:%d,subscriber:%d)" % (second_towait, campaign_id, elem_camp_subscriber.id))

            phone_number = elem_camp_subscriber.duplicate_contact
            debug_query(4)

            #Verify that the contact is authorized
            if not obj_campaign.is_authorized_contact(obj_campaign.user.userprofile.dialersetting, phone_number):
                logger.error("Error : Contact not authorized")
                elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                elem_camp_subscriber.save()
                return True
            #Verify that the contact is not in the DNC list
            if obj_campaign.dnc:
                res_dnc = DNCContact.objects.filter(dnc_id=obj_campaign.dnc_id, phone_number=phone_number)
                if res_dnc:
                    logger.error("Contact (%s) in DNC list" % phone_number)
                    elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                    elem_camp_subscriber.save()
                    return True
                else:
                    logger.debug("Contact (%s) not in DNC list" % phone_number)

            debug_query(5)

            #TODO: idea to speed up, create bluck of 10(Y) and then send a list of callrequest_id to init_callrequest

            # Create a Callrequest Instance to track the call task
            new_callrequest = Callrequest(
                status=CALLREQUEST_STATUS.PENDING,
                call_type=call_type,
                call_time=datetime.now(),
                timeout=obj_campaign.calltimeout,
                callerid=obj_campaign.callerid,
                phone_number=phone_number,
                campaign=obj_campaign,
                aleg_gateway=obj_campaign.aleg_gateway,
                content_type=obj_campaign.content_type,
                object_id=obj_campaign.object_id,
                user=obj_campaign.user,
                extra_data=obj_campaign.extra_data,
                timelimit=obj_campaign.callmaxduration,
                subscriber=elem_camp_subscriber)
            new_callrequest.save()

            debug_query(6)

            init_callrequest.apply_async(
                args=[new_callrequest.id, obj_campaign.id, obj_campaign.callmaxduration, ms_addtowait],
                countdown=second_towait)
            # Shell_plus
            # from dialer_cdr.tasks import init_callrequest
            # from datetime import datetime
            # new_callrequest_id = 112
            # obj_campaign_id = 3
            # countdown = 1
            # init_callrequest.apply_async(args=[new_callrequest_id, obj_campaign_id], countdown=1)

        debug_query(7)
        return True
示例#6
0
def init_callrequest(callrequest_id, campaign_id, callmaxduration, ms_addtowait=0, alarm_request_id=None):
    """
    This task read the callrequest, update it as 'In Process'
    then proceed on the call outbound, using the different call engine supported

    **Attributes**:

        * ``callrequest_id`` - Callrequest ID
        * ``campaign_id`` - Campaign ID
        * ``callmaxduration`` - Max duration
        * ``ms_addtowait`` - Milliseconds to wait before outbounding the call

    """
    outbound_failure = False
    subscriber_id = None
    contact_id = None
    debug_query(8)

    if ms_addtowait > 0:
        sleep(ms_addtowait)

    #Survey Call or Alarm Call
    if campaign_id:
        #TODO: use only https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.only
        obj_callrequest = Callrequest.objects\
            .select_related('aleg_gateway', 'user__userprofile', 'subscriber', 'campaign').get(id=callrequest_id)
        subscriber_id = obj_callrequest.subscriber_id
        contact_id = obj_callrequest.subscriber.contact_id
    elif alarm_request_id:
        obj_callrequest = Callrequest.objects.select_related('aleg_gateway', 'user__userprofile').get(id=callrequest_id)
        alarm_request_id = obj_callrequest.alarm_request_id
    else:
        logger.info("TASK :: init_callrequest, wrong campaign_id & alarm_request_id")
        return False

    debug_query(9)
    logger.info("TASK :: init_callrequest - status:%s;cmpg:%s;alarm:%s" %
                (obj_callrequest.status, campaign_id, alarm_request_id))

    # TODO: move method prepare_phonenumber into the model gateway
    #obj_callrequest.aleg_gatewayprepare_phonenumber()
    dialout_phone_number = prepare_phonenumber(
        obj_callrequest.phone_number,
        obj_callrequest.aleg_gateway.addprefix,
        obj_callrequest.aleg_gateway.removeprefix,
        obj_callrequest.aleg_gateway.status)
    if not dialout_phone_number:
        logger.info("Error with dialout_phone_number - phone_number:%s" % (obj_callrequest.phone_number))
        return False
    else:
        logger.debug("dialout_phone_number : %s" % dialout_phone_number)

    debug_query(10)

    if settings.DIALERDEBUG:
        dialout_phone_number = settings.DIALERDEBUG_PHONENUMBER

    #Retrieve the Gateway for the A-Leg
    gateways = obj_callrequest.aleg_gateway.gateways
    gateway_id = obj_callrequest.aleg_gateway.id
    #gateway_codecs / gateway_retries
    gateway_timeouts = obj_callrequest.aleg_gateway.gateway_timeouts
    if not gateway_timeouts:
        gateway_timeouts = '60'
    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string

    debug_query(11)

    #Sanitize gateways
    gateways = gateways.strip()
    if gateways[-1] != '/':
        gateways = gateways + '/'

    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string
    if obj_callrequest.user.userprofile and obj_callrequest.user.userprofile.accountcode:
        originate_dial_string = originate_dial_string + ',accountcode=' + \
            str(obj_callrequest.user.userprofile.accountcode)

    debug_query(12)

    if settings.NEWFIES_DIALER_ENGINE.lower() == 'esl':
        try:
            args_list = []
            send_digits = False
            time_limit = callmaxduration

            # To wait before sending DTMF to the extension, you can add leading 'w'
            # characters.
            # Each 'w' character waits 0.5 seconds instead of sending a digit.
            # Each 'W' character waits 1.0 seconds instead of sending a digit.
            # You can also add the tone duration in ms by appending @[duration] after string.
            # Eg. 1w2w3@1000
            check_senddigit = dialout_phone_number.partition('w')
            if check_senddigit[1] == 'w':
                send_digits = check_senddigit[1] + check_senddigit[2]
                dialout_phone_number = check_senddigit[0]

            args_list.append("origination_caller_id_number=%s" % obj_callrequest.callerid)
            args_list.append("origination_caller_id_name='%s'" % obj_callrequest.caller_name)

            #Add App Vars
            args_list.append("campaign_id=%s,subscriber_id=%s,alarm_request_id=%s,used_gateway_id=%s,callrequest_id=%s,contact_id=%s" %
                (campaign_id, subscriber_id, alarm_request_id, gateway_id, obj_callrequest.id, contact_id))
            args_list.append(originate_dial_string)

            #Call Vars
            callvars = "bridge_early_media=true,originate_timeout=%s,newfiesdialer=true,leg_type=1" % \
                (gateway_timeouts, )
            args_list.append(callvars)

            #Default Test
            hangup_on_ring = ''
            send_preanswer = False
            # set hangup_on_ring
            try:
                hangup_on_ring = int(hangup_on_ring)
            except ValueError:
                hangup_on_ring = -1
            exec_on_media = 1
            if hangup_on_ring >= 0:
                args_list.append("execute_on_media_%d='sched_hangup +%d ORIGINATOR_CANCEL'" %
                                 (exec_on_media, hangup_on_ring))
                exec_on_media += 1

            #TODO: look and test http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_queue_dtmf
            # Send digits
            if send_digits:
                if send_preanswer:
                    args_list.append("execute_on_media_%d='send_dtmf %s'" % (exec_on_media, send_digits))
                    exec_on_media += 1
                else:
                    args_list.append("execute_on_answer='send_dtmf %s'" % send_digits)

            # Set time_limit
            try:
                time_limit = int(time_limit)
            except ValueError:
                time_limit = -1
            #TODO : Fix time_limit - maybe implement this into Lua
            # if time_limit > 0:
            #     # create sched_hangup_id
            #     sched_hangup_id = str(uuid1())
            #     # create a new request uuid
            #     request_uuid = str(uuid1())
            #     args_list.append("api_on_answer_1='sched_api +%d %s hupall ALLOTTED_TIMEOUT'"
            #         % (time_limit, sched_hangup_id))

            # build originate string
            args_str = ','.join(args_list)

            #DEBUG
            #settings.ESL_SCRIPT = '&playback(/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-record_greeting.wav)'
            if settings.DIALERDEBUG:
                dial_command = "originate {%s}user/areski '%s'" % (args_str, settings.ESL_SCRIPT)
            else:
                dial_command = "originate {%s}%s%s '%s'" % \
                    (args_str, gateways, dialout_phone_number, settings.ESL_SCRIPT)

            # originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=10}user/areski &playback(/tmp/myfile.wav)
            # dial = "originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=,newfiesdialer=true,used_gateway_id=1,callrequest_id=38,leg_type=1,origination_caller_id_number=234234234,origination_caller_id_name=234234,effective_caller_id_number=234234234,effective_caller_id_name=234234,}user//1000 '&lua(/usr/share/newfies-lua/newfies.lua)'"
            logger.warn('dial_command : %s' % dial_command)

            request_uuid = dial_out(dial_command)

            debug_query(14)

            if request_uuid and len(request_uuid) > 0 and request_uuid[:5] == 'error':
                outbound_failure = True
            debug_query(13)
        except:
            raise
            logger.error('error : ESL')
            outbound_failure = True
        logger.debug('Received RequestUUID :> %s' % request_uuid)
    else:
        logger.error('No other method supported!')
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
        obj_callrequest.save()
        #ADD if alarm_request_id update AlarmRequest
        return False

    #Survey Call or Alarm Call
    if campaign_id:
        #Update Subscriber
        if not obj_callrequest.subscriber.count_attempt:
            obj_callrequest.subscriber.count_attempt = 1
        else:
            obj_callrequest.subscriber.count_attempt = obj_callrequest.subscriber.count_attempt + 1
        obj_callrequest.subscriber.last_attempt = datetime.utcnow().replace(tzinfo=utc)
        #check if the outbound call failed then update Subscriber
        if outbound_failure:
            obj_callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
        obj_callrequest.subscriber.save()
    elif alarm_request_id:
        if outbound_failure:
            check_retry_alarm(alarm_request_id)

    #Update CallRequest Object
    obj_callrequest.request_uuid = request_uuid
    #check if the outbound call failed
    if outbound_failure:
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
    else:
        obj_callrequest.status = CALLREQUEST_STATUS.CALLING
    obj_callrequest.save()

    debug_query(14)

    return True
示例#7
0
def callevent_processing():
    """
    Retrieve callevents and process them

    call_event table is created by listener.lua

    CREATE TABLE if not exists call_event (
        id serial NOT NULL PRIMARY KEY,
        event_name varchar(200) NOT NULL,
        body varchar(200) NOT NULL,
        job_uuid varchar(200),
        call_uuid varchar(200) NOT NULL,
        used_gateway_id integer,
        callrequest_id integer,
        alarm_request_id integer,
        callerid varchar(200),
        phonenumber varchar(200),
        duration integer DEFAULT 0,
        billsec integer DEFAULT 0,
        hangup_cause varchar(40),
        hangup_cause_q850 varchar(10),
        amd_status varchar(40),
        starting_date timestamp with time zone,
        status smallint,
        leg smallint,
        created_date timestamp with time zone NOT NULL
        );
    CREATE INDEX call_event_idx_status ON call_event (status);
    --CREATE INDEX call_event_idx_date ON call_event (created_date);
    --CREATE INDEX call_event_idx_uuid ON call_event (call_uuid);
    """
    debug_query(20)

    cursor = connection.cursor()
    #TODO (Areski)
    #Replace this for ORM with select_for_update or transaction

    sql_statement = "SELECT id, event_name, body, job_uuid, call_uuid, used_gateway_id, " \
        "callrequest_id, alarm_request_id, callerid, phonenumber, duration, billsec, hangup_cause, " \
        "hangup_cause_q850, starting_date, status, created_date, amd_status, leg " \
        "FROM call_event WHERE status=1 LIMIT 1000 OFFSET 0"

    cursor.execute(sql_statement)
    row = cursor.fetchall()

    debug_query(21)
    # buff_voipcall = BufferVoIPCall()

    for record in row:
        call_event_id = record[0]
        event_name = record[1]
        #Update Call Event
        sql_statement = "UPDATE call_event SET status=2 WHERE id=%d" % call_event_id
        cursor.execute(sql_statement)

        logger.info("Processing Event : %s" % event_name)
        process_callevent.delay(record)

    debug_query(30)
    # buff_voipcall.commit()
    # debug_query(31)
    logger.debug('End Loop : callevent_processing')
示例#8
0
    def run(self, campaign_id):
        """
        This will execute the outbound calls in the campaign

        **Attributes**:

            * ``campaign_id`` - Campaign ID
        """
        logger = self.get_logger()
        logger.info("TASK :: CheckPendingcall = %d" % campaign_id)

        debug_query(0)

        try:
            obj_campaign = Campaign.objects.select_related('user__userprofile__dialersetting', 'aleg_gateway', 'content_type').get(id=campaign_id)
        except:
            logger.error('Can\'t find this campaign')
            return False

        # TODO : Control the Speed
        # if there is many task pending we should slow down
        frequency = obj_campaign.frequency  # default 10 calls per minutes

        debug_query(1)

        # Default call_type
        call_type = CALLREQUEST_TYPE.ALLOW_RETRY
        # Check campaign's maxretry
        if obj_campaign.maxretry == 0:
            call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        # Check user's dialer setting maxretry
        if obj_campaign.user.userprofile.dialersetting:
            if obj_campaign.user.userprofile.dialersetting.maxretry == 0:
                call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        debug_query(2)

        # Speed
        # Check if the other tasks send for this campaign finished to be ran

        # Get the subscriber of this campaign
        # get_pending_subscriber get Max 1000 records
        list_subscriber = obj_campaign.get_pending_subscriber_update(
            frequency,
            SUBSCRIBER_STATUS.IN_PROCESS
        )
        if list_subscriber:
            no_subscriber = list_subscriber.count()
        else:
            no_subscriber = 0
        logger.info("campaign_id=%d #Subscriber: %d" % (campaign_id, no_subscriber))

        debug_query(3)

        if no_subscriber == 0:
            return False

        if no_subscriber == 1:
            # Not many subscriber do a fast dial
            time_to_wait = 1.0
        elif no_subscriber <= 10:
            # Not many subscriber do a fast dial
            time_to_wait = 6.0
        else:
            # Set time to wait for balanced dispatching of calls
            time_to_wait = 60.0 / no_subscriber

        count = 0
        for elem_camp_subscriber in list_subscriber:
            """Loop on Subscriber and start the initcall task"""
            count = count + 1
            logger.info("Add CallRequest for Subscriber (%d) & wait (%s) " %
                       (elem_camp_subscriber.id, str(time_to_wait)))
            phone_number = elem_camp_subscriber.duplicate_contact

            debug_query(4)

            #Verify that the contact is authorized
            if not obj_campaign.is_authorized_contact(obj_campaign.user.userprofile.dialersetting, phone_number):
                logger.error("Error : Contact not authorized")
                elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                elem_camp_subscriber.save()
                return True
            #Verify that the contact is not in the DNC list
            if obj_campaign.dnc:
                try:
                    DNCContact.objects.get(dnc_id=obj_campaign.dnc_id, phone_number=phone_number)
                    logger.error("Contact (%s) in DNC list" % phone_number)
                    elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                    elem_camp_subscriber.save()
                    return True
                except DNCContact.DoesNotExist:
                    logger.debug("Contact (%s) not in DNC list" % phone_number)

            debug_query(5)

            # Create a Callrequest Instance to track the call task
            new_callrequest = Callrequest(
                status=CALLREQUEST_STATUS.PENDING,
                call_type=call_type,
                call_time=datetime.now(),
                timeout=obj_campaign.calltimeout,
                callerid=obj_campaign.callerid,
                phone_number=phone_number,
                campaign=obj_campaign,
                aleg_gateway=obj_campaign.aleg_gateway,
                content_type=obj_campaign.content_type,
                object_id=obj_campaign.object_id,
                user=obj_campaign.user,
                extra_data=obj_campaign.extra_data,
                timelimit=obj_campaign.callmaxduration,
                subscriber=elem_camp_subscriber)
            new_callrequest.save()

            debug_query(6)

            second_towait = ceil(count * time_to_wait)
            logger.info("Init CallRequest in %d seconds (cmpg:%d)" % (second_towait, campaign_id))
            init_callrequest.apply_async(
                args=[new_callrequest.id, obj_campaign.id, obj_campaign.callmaxduration],
                countdown=second_towait)
            # Shell_plus
            # from dialer_cdr.tasks import init_callrequest
            # from datetime import datetime
            # new_callrequest_id = 112
            # obj_campaign_id = 3
            # countdown = 1
            # init_callrequest.apply_async(args=[new_callrequest_id, obj_campaign_id], countdown=1)

        debug_query(7)
        return True
示例#9
0
    def run(self, campaign_id):
        """
        This task retrieves the next outbound call to be made for a given
        campaign, and will create a new callrequest and schedule a task to
        process those calls

        **Attributes**:

            * ``campaign_id`` - Campaign ID
        """
        logger = self.get_logger()
        logger.info("TASK :: pending_call_processing = %d" % campaign_id)

        debug_query(0)

        try:
            obj_campaign = Campaign.objects\
                .select_related('user__userprofile__dialersetting', 'aleg_gateway', 'content_type')\
                .get(id=campaign_id)
        except:
            logger.error("Can't find this campaign")
            return False

        # Ensure the content_type become "survey" when campagin starts
        if not obj_campaign.has_been_started:
            # change has_been_started flag
            obj_campaign.has_been_started = True
            obj_campaign.save()

            if obj_campaign.content_type.model == 'survey_template':
                # Copy survey
                survey_template = Survey_template.objects.get(
                    user=obj_campaign.user, pk=obj_campaign.object_id)
                survey_template.copy_survey_template(obj_campaign.id)
            collect_subscriber.delay(obj_campaign.id)

        # TODO : Control the Speed
        # if there is many task pending we should slow down
        frequency = obj_campaign.frequency  # default 10 calls per minutes

        debug_query(1)

        # TODO: move this logic of setting call_type after CallRequest post_save
        # Default call_type
        call_type = CALLREQUEST_TYPE.ALLOW_RETRY
        # Check campaign's maxretry
        if obj_campaign.maxretry == 0:
            call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        # Check user's dialer setting maxretry
        try:
            obj_campaign.user.userprofile.dialersetting
            if obj_campaign.user.userprofile.dialersetting.maxretry == 0:
                call_type = CALLREQUEST_TYPE.CANNOT_RETRY
        except ObjectDoesNotExist:
            logger.error("Can't find user's dialersetting")
            return False

        debug_query(2)

        # Speed
        # Check if the other tasks send for this campaign finished to be ran

        # Get the subscriber of this campaign
        # get_pending_subscriber get Max 1000 records
        if settings.HEARTBEAT_MIN == 1:  # 1 task per minute
            callfrequency = frequency  # task run only once per minute, so we can assign frequency
        else:
            callfrequency = int(
                frequency / settings.HEARTBEAT_MIN) + 1  # 1000 per minutes
            # callfrequency = int(frequency) + 1  # 1000 per minutes

        (list_subscriber, no_subscriber) = obj_campaign\
            .get_pending_subscriber_update(callfrequency, SUBSCRIBER_STATUS.IN_PROCESS)
        logger.info("##subscriber=%d campaign_id=%d callfreq=%d freq=%d" %
                    (no_subscriber, campaign_id, callfrequency, frequency))
        debug_query(3)

        if no_subscriber == 0:
            return False

        list_cr = []
        bulk_record = []
        # this is used to tag and retrieve the id that are inserted
        bulk_uuid = str(uuid1())
        for elem_camp_subscriber in list_subscriber:
            phone_number = elem_camp_subscriber.duplicate_contact
            debug_query(4)

            # Verify that the contact is authorized
            if not obj_campaign.is_authorized_contact(
                    obj_campaign.user.userprofile.dialersetting, phone_number):
                logger.error("Error : Contact not authorized")
                elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                elem_camp_subscriber.save()
                continue
            # Verify that the contact is not in the DNC list
            if obj_campaign.dnc:
                res_dnc = DNCContact.objects.filter(dnc_id=obj_campaign.dnc_id,
                                                    phone_number=phone_number)
                if res_dnc:
                    logger.error("Contact (%s) in DNC list" % phone_number)
                    elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                    elem_camp_subscriber.save()
                    continue
                else:
                    logger.debug("Contact (%s) not in DNC list" % phone_number)

            debug_query(5)

            bulk_record.append(
                Callrequest(status=CALLREQUEST_STATUS.PENDING,
                            call_type=call_type,
                            call_time=datetime.utcnow().replace(tzinfo=utc),
                            timeout=obj_campaign.calltimeout,
                            callerid=obj_campaign.callerid,
                            caller_name=obj_campaign.caller_name,
                            phone_number=phone_number,
                            campaign=obj_campaign,
                            aleg_gateway=obj_campaign.aleg_gateway,
                            content_type=obj_campaign.content_type,
                            object_id=obj_campaign.object_id,
                            user=obj_campaign.user,
                            extra_data=obj_campaign.extra_data,
                            timelimit=obj_campaign.callmaxduration,
                            subscriber=elem_camp_subscriber,
                            request_uuid=bulk_uuid))
            debug_query(6)

        # Create Callrequests in Bulk
        logger.info("Bulk Create CallRequest => %d" % (len(bulk_record)))
        Callrequest.objects.bulk_create(bulk_record)

        # Set time to wait for balanced dispatching of calls
        time_to_wait = (60.0 / settings.HEARTBEAT_MIN) / no_subscriber
        count = 0
        loopnow = datetime.utcnow()
        loopnow + timedelta(seconds=1.55)

        # Retrienve the one we just created
        list_cr = Callrequest.objects.filter(request_uuid=bulk_uuid).all()
        for cr in list_cr:
            # Loop on Subscriber and start the initcall's task
            count = count + 1
            second_towait = floor(count * time_to_wait)
            # ms_addtowait now used anymore, replaced by async eta
            ms_addtowait = (count * time_to_wait) - second_towait

            eta_delta = loopnow + timedelta(seconds=(count * time_to_wait))
            # as we use eta_delta ms_addtowait is set to 0
            ms_addtowait = 0

            logger.info(
                "Init CallRequest in %d seconds (cmpg:%d,subscr:%d:eta_delta:%s)"
                % (second_towait, campaign_id, elem_camp_subscriber.id,
                   eta_delta))

            init_callrequest.apply_async(
                args=[
                    cr.id, obj_campaign.id, obj_campaign.callmaxduration,
                    ms_addtowait
                ],
                # countdown=second_towait)
                eta=eta_delta)

            second_towait = second_towait + settings.DELAY_OUTBOUND

            # Shell_plus
            # from dialer_cdr.tasks import init_callrequest
            # from datetime import datetime
            # new_callrequest_id = 112
            # obj_campaign_id = 3
            # countdown = 1
            # init_callrequest.apply_async(
            #     args=[new_callrequest.id, obj_campaign.id, obj_campaign.callmaxduration, ms_addtowait],
            #     countdown=1)

        debug_query(7)
        return True
示例#10
0
def init_callrequest(callrequest_id,
                     campaign_id,
                     callmaxduration,
                     ms_addtowait=0):
    """
    This task read the callrequest, update it as 'In Process'
    then proceed on the call outbound, using the different call engine supported

    **Attributes**:

        * ``callrequest_id`` - Callrequest ID
        * ``campaign_id`` - Campaign ID
        * ``callmaxduration`` - Max duration
        * ``ms_addtowait`` - Milliseconds to wait before outbounding the call

    """
    debug_query(8)

    if ms_addtowait > 0:
        sleep(ms_addtowait)

    #Get CallRequest object
    #use only https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.only
    # test2 = Callrequest.objects.only('id', 'callerid', 'phone_number', 'status', \
    #     'request_uuid', 'campaign__id', 'subscriber__id', \
    #     'aleg_gateway__id', 'aleg_gateway__addprefix', 'aleg_gateway__removeprefix', 'aleg_gateway__status', \
    #     'aleg_gateway__gateways', 'aleg_gateway__gateway_timeouts', 'aleg_gateway__originate_dial_string', \
    #     'user__userprofile__accountcode', 'campaign__caller_name', \
    #     'subscriber__id', 'subscriber__contact__id', 'subscriber__count_attempt', 'subscriber__last_attempt')\
    #     .select_related('aleg_gateway', 'user__userprofile', 'subscriber', 'campaign').get(id=4767)
    obj_callrequest = Callrequest.objects.select_related(
        'aleg_gateway', 'user__userprofile', 'subscriber',
        'campaign').get(id=callrequest_id)

    debug_query(9)

    logger.info("TASK :: init_callrequest - status:%s;cmpg:%d" %
                (str(obj_callrequest.status), campaign_id))

    debug_query(10)

    if obj_callrequest.aleg_gateway:
        dialout_phone_number = prepare_phonenumber(
            obj_callrequest.phone_number,
            obj_callrequest.aleg_gateway.addprefix,
            obj_callrequest.aleg_gateway.removeprefix,
            obj_callrequest.aleg_gateway.status)
    else:
        dialout_phone_number = obj_callrequest.phone_number
    logger.debug("dialout_phone_number : %s" % dialout_phone_number)

    if not dialout_phone_number:
        logger.info(
            "Error with dialout_phone_number - phone_number:%s;cmpg:%d" %
            (str(obj_callrequest.phone_number), campaign_id))
        return False

    debug_query(11)

    if settings.DIALERDEBUG:
        dialout_phone_number = settings.DIALERDEBUG_PHONENUMBER

    #Retrieve the Gateway for the A-Leg
    gateways = obj_callrequest.aleg_gateway.gateways
    gateway_id = obj_callrequest.aleg_gateway.id
    #gateway_codecs = obj_callrequest.aleg_gateway.gateway_codecs
    #gateway_retries = obj_callrequest.aleg_gateway.gateway_retries
    gateway_timeouts = obj_callrequest.aleg_gateway.gateway_timeouts
    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string

    debug_query(12)

    #Sanitize gateways
    gateways = gateways.strip()
    if gateways[-1] != '/':
        gateways = gateways + '/'

    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string
    if (obj_callrequest.user.userprofile.accountcode
            and obj_callrequest.user.userprofile.accountcode > 0):
        originate_dial_string = originate_dial_string + \
            ',accountcode=' + str(obj_callrequest.user.userprofile.accountcode)

    debug_query(13)

    outbound_failure = False

    #Send Call to API
    #http://ask.github.com/celery/userguide/remote-tasks.html
    """
    #this could be needed if we want to call a different API / Twilio
    import httplib, urllib
    params = urllib.urlencode({'From': '900900000', 'To': '1000',})
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Accept": "text/plain"}
    conn = httplib.HTTPConnection("127.0.0.1:8000")
    conn.request("POST", "/api/dialer_cdr/testcall/", params, headers)
    response = conn.getresponse()
    print response.status, response.reason
    data = response.read()
    conn.close()
    """

    if settings.NEWFIES_DIALER_ENGINE.lower() == 'esl':
        try:
            args_list = []
            send_digits = False
            time_limit = callmaxduration

            # To wait before sending DTMF to the extension, you can add leading 'w'
            # characters.
            # Each 'w' character waits 0.5 seconds instead of sending a digit.
            # Each 'W' character waits 1.0 seconds instead of sending a digit.
            # You can also add the tone duration in ms by appending @[duration] after string.
            # Eg. 1w2w3@1000
            check_senddigit = dialout_phone_number.partition('w')
            if check_senddigit[1] == 'w':
                send_digits = check_senddigit[1] + check_senddigit[2]
                dialout_phone_number = check_senddigit[0]

            args_list.append("origination_caller_id_number=%s" %
                             obj_callrequest.callerid)
            if obj_callrequest.campaign.caller_name:
                args_list.append("origination_caller_id_name='%s'" %
                                 obj_callrequest.campaign.caller_name)

            #Add App Vars
            args_list.append(
                "campaign_id=%d,subscriber_id=%d,used_gateway_id=%s,callrequest_id=%s,contact_id=%s"
                % (obj_callrequest.campaign_id, obj_callrequest.subscriber_id,
                   gateway_id, obj_callrequest.id,
                   obj_callrequest.subscriber.contact_id))

            args_list.append(originate_dial_string)

            #Call Vars
            callvars = "bridge_early_media=true,originate_timeout=%s,newfiesdialer=true,leg_type=1" % \
                (gateway_timeouts, )

            args_list.append(callvars)

            #Default Test
            hangup_on_ring = ''
            send_preanswer = False

            # set hangup_on_ring
            try:
                hangup_on_ring = int(hangup_on_ring)
            except ValueError:
                hangup_on_ring = -1
            exec_on_media = 1
            if hangup_on_ring >= 0:
                args_list.append(
                    "execute_on_media_%d='sched_hangup +%d ORIGINATOR_CANCEL'"
                    % (exec_on_media, hangup_on_ring))
                exec_on_media += 1

            #TODO: look and test http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_queue_dtmf

            # Send digits
            if send_digits:
                if send_preanswer:
                    args_list.append("execute_on_media_%d='send_dtmf %s'" %
                                     (exec_on_media, send_digits))
                    exec_on_media += 1
                else:
                    args_list.append("execute_on_answer='send_dtmf %s'" %
                                     send_digits)

            # set time_limit
            try:
                time_limit = int(time_limit)
            except ValueError:
                time_limit = -1
            #TODO : Fix time_limit - maybe implement this into Lua
            # if time_limit > 0:
            #     # create sched_hangup_id
            #     sched_hangup_id = str(uuid1())
            #     # create a new request uuid
            #     request_uuid = str(uuid1())
            #     args_list.append("api_on_answer_1='sched_api +%d %s hupall ALLOTTED_TIMEOUT'"
            #         % (time_limit, sched_hangup_id))

            # build originate string
            args_str = ','.join(args_list)

            #DEBUG
            #settings.ESL_SCRIPT = '&playback(/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-record_greeting.wav)'
            dial_command = "originate {%s}%s%s '%s'" % \
                (args_str, gateways, dialout_phone_number, settings.ESL_SCRIPT)
            # originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=10}user/areski &playback(/tmp/myfile.wav)
            # dial = "originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=,newfiesdialer=true,used_gateway_id=1,callrequest_id=38,leg_type=1,origination_caller_id_number=234234234,origination_caller_id_name=234234,effective_caller_id_number=234234234,effective_caller_id_name=234234,}user//1000 '&lua(/usr/share/newfies-lua/newfies.lua)'"

            request_uuid = esl_dialout(dial_command)
            debug_query(14)
        except:
            raise
            logger.error('error : ESL')
            outbound_failure = True
            return False
        logger.debug('Received RequestUUID :> ' + request_uuid)
    else:
        logger.error('No other method supported!')
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
        obj_callrequest.save()
        return False

    #Update Subscriber
    if not obj_callrequest.subscriber.count_attempt:
        obj_callrequest.subscriber.count_attempt = 1
    else:
        obj_callrequest.subscriber.count_attempt = obj_callrequest.subscriber.count_attempt + 1
    obj_callrequest.subscriber.last_attempt = datetime.now()
    #check if the outbound call failed then update Subscriber
    if outbound_failure:
        obj_callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
    obj_callrequest.subscriber.save()

    #Update CallRequest Object
    obj_callrequest.request_uuid = request_uuid
    #check if the outbound call failed
    if outbound_failure:
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
    else:
        obj_callrequest.status = CALLREQUEST_STATUS.CALLING
    obj_callrequest.save()

    #lock to limit running process, do so per campaign
    #http://ask.github.com/celery/cookbook/tasks.html

    debug_query(15)

    return True
示例#11
0
def init_callrequest(callrequest_id, campaign_id, callmaxduration):
    """
    This task read the callrequest, update it as 'In Process'
    then proceed on the call outbound, using the different call engine supported

    **Attributes**:

        * ``callrequest_id`` - Callrequest ID

    """
    debug_query(8)

    #Get CallRequest object
    # .only('id', 'callerid', 'phone_number', 'status',
    #     'request_uuid', 'campaign__id', 'subscriber__id',
    #     'aleg_gateway__id', 'aleg_gateway__addprefix', 'aleg_gateway__removeprefix', 'aleg_gateway__status',
    #     'aleg_gateway__gateways', 'aleg_gateway__gateway_timeouts', 'aleg_gateway__originate_dial_string',
    #     'user__userprofile__accountcode', 'campaign__caller_name',
    #     'subscriber__id', 'subscriber__contact__id', 'subscriber__count_attempt', 'subscriber__last_attempt')\
    obj_callrequest = Callrequest.objects.select_related('aleg_gateway', 'user__userprofile', 'subscriber', 'campaign').get(id=callrequest_id)

    debug_query(9)

    logger.info("TASK :: init_callrequest - status:%s;cmpg:%d" % (str(obj_callrequest.status), campaign_id))

    debug_query(10)

    if obj_callrequest.aleg_gateway:
        dialout_phone_number = prepare_phonenumber(
            obj_callrequest.phone_number,
            obj_callrequest.aleg_gateway.addprefix,
            obj_callrequest.aleg_gateway.removeprefix,
            obj_callrequest.aleg_gateway.status)
    else:
        dialout_phone_number = obj_callrequest.phone_number
    logger.debug("dialout_phone_number : %s" % dialout_phone_number)

    if not dialout_phone_number:
        logger.info("Error with dialout_phone_number - phone_number:%s;cmpg:%d" % (str(obj_callrequest.phone_number), campaign_id))
        return False

    debug_query(11)

    if settings.DIALERDEBUG:
        dialout_phone_number = settings.DIALERDEBUG_PHONENUMBER

    #Retrieve the Gateway for the A-Leg
    gateways = obj_callrequest.aleg_gateway.gateways
    gateway_id = obj_callrequest.aleg_gateway.id
    #gateway_codecs = obj_callrequest.aleg_gateway.gateway_codecs
    #gateway_retries = obj_callrequest.aleg_gateway.gateway_retries
    gateway_timeouts = obj_callrequest.aleg_gateway.gateway_timeouts
    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string

    debug_query(12)

    #Sanitize gateways
    gateways = gateways.strip()
    if gateways[-1] != '/':
        gateways = gateways + '/'

    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string
    if (obj_callrequest.user.userprofile.accountcode and
       obj_callrequest.user.userprofile.accountcode > 0):
        originate_dial_string = originate_dial_string + \
            ',accountcode=' + str(obj_callrequest.user.userprofile.accountcode)

    debug_query(13)

    outbound_failure = False

    #Send Call to API
    #http://ask.github.com/celery/userguide/remote-tasks.html

    """
    #this could be needed if we want to call a different API / Twilio
    import httplib, urllib
    params = urllib.urlencode({'From': '900900000', 'To': '1000',})
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Accept": "text/plain"}
    conn = httplib.HTTPConnection("127.0.0.1:8000")
    conn.request("POST", "/api/dialer_cdr/testcall/", params, headers)
    response = conn.getresponse()
    print response.status, response.reason
    data = response.read()
    conn.close()
    """

    if settings.NEWFIES_DIALER_ENGINE.lower() == 'esl':
        try:
            args_list = []
            send_digits = False
            time_limit = callmaxduration

            # To wait before sending DTMF to the extension, you can add leading 'w'
            # characters.
            # Each 'w' character waits 0.5 seconds instead of sending a digit.
            # Each 'W' character waits 1.0 seconds instead of sending a digit.
            # You can also add the tone duration in ms by appending @[duration] after string.
            # Eg. 1w2w3@1000
            check_senddigit = dialout_phone_number.partition('w')
            if check_senddigit[1] == 'w':
                send_digits = check_senddigit[1] + check_senddigit[2]
                dialout_phone_number = check_senddigit[0]

            args_list.append("origination_caller_id_number=%s" % obj_callrequest.callerid)
            if obj_callrequest.campaign.caller_name:
                args_list.append("origination_caller_id_name='%s'" % obj_callrequest.campaign.caller_name)

            #Add App Vars
            args_list.append("campaign_id=%d,subscriber_id=%d,used_gateway_id=%s,callrequest_id=%s,contact_id=%s" %
                (obj_callrequest.campaign_id, obj_callrequest.subscriber_id, gateway_id, obj_callrequest.id, obj_callrequest.subscriber.contact_id))

            args_list.append(originate_dial_string)

            #Call Vars
            callvars = "bridge_early_media=true,originate_timeout=%s,newfiesdialer=true,leg_type=1" % \
                (gateway_timeouts, )

            args_list.append(callvars)

            #Default Test
            hangup_on_ring = ''
            send_preanswer = False

            # set hangup_on_ring
            try:
                hangup_on_ring = int(hangup_on_ring)
            except ValueError:
                hangup_on_ring = -1
            exec_on_media = 1
            if hangup_on_ring >= 0:
                args_list.append("execute_on_media_%d='sched_hangup +%d ORIGINATOR_CANCEL'"
                    % (exec_on_media, hangup_on_ring))
                exec_on_media += 1

            #TODO: look and test http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_queue_dtmf

            # Send digits
            if send_digits:
                if send_preanswer:
                    args_list.append("execute_on_media_%d='send_dtmf %s'"
                        % (exec_on_media, send_digits))
                    exec_on_media += 1
                else:
                    args_list.append("execute_on_answer='send_dtmf %s'" % send_digits)

            # set time_limit
            try:
                time_limit = int(time_limit)
            except ValueError:
                time_limit = -1
            #TODO : Fix time_limit - maybe implement this into Lua
            # if time_limit > 0:
            #     # create sched_hangup_id
            #     sched_hangup_id = str(uuid1())
            #     # create a new request uuid
            #     request_uuid = str(uuid1())
            #     args_list.append("api_on_answer_1='sched_api +%d %s hupall ALLOTTED_TIMEOUT'"
            #         % (time_limit, sched_hangup_id))

            # build originate string
            args_str = ','.join(args_list)

            #DEBUG
            #settings.ESL_SCRIPT = '&playback(/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-record_greeting.wav)'
            dial = "originate {%s}%s%s '%s'" % \
                (args_str, gateways, dialout_phone_number, settings.ESL_SCRIPT)
            # originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=10}user/areski &playback(/tmp/myfile.wav)
            # dial = "originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=,newfiesdialer=true,used_gateway_id=1,callrequest_id=38,leg_type=1,origination_caller_id_number=234234234,origination_caller_id_name=234234,effective_caller_id_number=234234234,effective_caller_id_name=234234,}user//1000 '&lua(/usr/share/newfies-lua/newfies.lua)'"
            print dial

            import ESL
            c = ESL.ESLconnection(settings.ESL_HOSTNAME, settings.ESL_PORT, settings.ESL_SECRET)
            c.connected()
            ev = c.api("bgapi", str(dial))
            c.disconnect()

            debug_query(14)

            if ev:
                result = ev.serialize()
                logger.debug(result)
                pos = result.find('Job-UUID:')
                if pos:
                    request_uuid = result[pos + 10:pos + 46]
                else:
                    request_uuid = 'error'
            else:
                request_uuid = 'error'

        except:
            raise
            logger.error('error : ESL')
            outbound_failure = True
            return False
        logger.info('Received RequestUUID :> ' + request_uuid)
    else:
        logger.error('No other method supported!')
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
        obj_callrequest.save()
        return False

    #Update Subscriber
    if not obj_callrequest.subscriber.count_attempt:
        obj_callrequest.subscriber.count_attempt = 1
    else:
        obj_callrequest.subscriber.count_attempt = obj_callrequest.subscriber.count_attempt + 1
    obj_callrequest.subscriber.last_attempt = datetime.now()
    #check if the outbound call failed then update Subscriber
    if outbound_failure:
        obj_callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
    obj_callrequest.subscriber.save()

    #Update CallRequest Object
    obj_callrequest.request_uuid = request_uuid
    #check if the outbound call failed
    if outbound_failure:
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
    else:
        obj_callrequest.status = CALLREQUEST_STATUS.CALLING
    obj_callrequest.save()

    #lock to limit running process, do so per campaign
    #http://ask.github.com/celery/cookbook/tasks.html

    debug_query(15)

    return True
示例#12
0
def check_callevent():
    """
    Check callevent

    call_event table is created by listener.lua

    CREATE TABLE if not exists call_event (
        id serial NOT NULL PRIMARY KEY,
        event_name varchar(200) NOT NULL,
        body varchar(200) NOT NULL,
        job_uuid varchar(200),
        call_uuid varchar(200) NOT NULL,
        used_gateway_id integer,
        callrequest_id integer,
        callerid varchar(200),
        phonenumber varchar(200),
        duration integer DEFAULT 0,
        billsec integer DEFAULT 0,
        hangup_cause varchar(40),
        hangup_cause_q850 varchar(10),
        amd_status varchar(40),
        starting_date timestamp with time zone,
        status smallint,
        created_date timestamp with time zone NOT NULL
        );
    CREATE INDEX call_event_idx_status ON call_event (status);
    --CREATE INDEX call_event_idx_date ON call_event (created_date);
    --CREATE INDEX call_event_idx_uuid ON call_event (call_uuid);
    """
    debug_query(20)

    cursor = connection.cursor()

    #TODO (Areski)
    #Replace this for ORM with select_for_update or transaction

    sql_statement = "SELECT id, event_name, body, job_uuid, call_uuid, used_gateway_id, "\
        "callrequest_id, callerid, phonenumber, duration, billsec, hangup_cause, "\
        "hangup_cause_q850, starting_date, status, created_date, amd_status, leg "\
        "FROM call_event WHERE status=1 LIMIT 1000 OFFSET 0"

    cursor.execute(sql_statement)
    row = cursor.fetchall()

    debug_query(21)
    # buff_voipcall = BufferVoIPCall()

    for record in row:
        call_event_id = record[0]
        event_name = record[1]
        #Update Call Event
        sql_statement = "UPDATE call_event SET status=2 WHERE id=%d" % call_event_id
        cursor.execute(sql_statement)

        logger.info("Processing Event : %s" % event_name)
        process_callevent.delay(record)

    debug_query(30)
    # buff_voipcall.commit()
    # debug_query(31)
    logger.debug('End Loop : check_callevent')
示例#13
0
def handle_callevent(record):
    """
    Handle the callevent, create the voipcall, and save different data
    """
    event_name = record[1]
    body = record[2]
    job_uuid = record[3]
    call_uuid = record[4]
    #used_gateway_id = record[5]
    callrequest_id = record[6]
    callerid = record[7]
    phonenumber = record[8]
    duration = record[9]
    billsec = record[10]
    hangup_cause = record[11]
    hangup_cause_q850 = record[12]
    starting_date = record[13]
    amd_status = record[16]
    leg = record[17]

    if event_name == 'BACKGROUND_JOB':
        #hangup cause come from body
        hangup_cause = body[5:]

    # if event_name == 'CHANNEL_HANGUP_COMPLETE':
    #     #hangup cause come from body
    #     print(event_name)

    if hangup_cause == '':
        hangup_cause = body[5:]

    request_uuid = job_uuid
    opt_hangup_cause = hangup_cause

    debug_query(22)

    try:
        if callrequest_id == 0:
            callrequest = Callrequest.objects\
                .select_related('aleg_gateway', 'subscriber', 'campaign')\
                .get(request_uuid=request_uuid.strip(' \t\n\r'))
        else:
            #mainly coming here
            callrequest = Callrequest.objects\
                .select_related('aleg_gateway', 'subscriber', 'campaign')\
                .get(id=callrequest_id)
    except:
        logger.error("Cannot find Callrequest job_uuid : %s" % job_uuid)
        return True

    logger.debug("Find Callrequest id : %d" % callrequest.id)
    debug_query(23)

    if leg == 'aleg':
        #Update callrequest
        #update_callrequest.delay(callrequest, opt_hangup_cause)
        #Disabled above tasks to reduce amount of tasks

        #Only the aleg will update the subscriber status / Bleg is only recorded
        #Update Callrequest Status
        if opt_hangup_cause == 'NORMAL_CLEARING':
            callrequest.status = CALLREQUEST_STATUS.SUCCESS
            if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
                callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
        else:
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
        callrequest.hangup_cause = opt_hangup_cause

        callrequest.save()
        callrequest.subscriber.save()
        debug_query(24)

    if call_uuid == '':
        call_uuid = job_uuid
    if callerid == '':
        callerid = callrequest.callerid
    if phonenumber == '':
        phonenumber = callrequest.phone_number

    #Create those in Bulk - add in a buffer until reach certain number
    # buff_voipcall.save(
    #     obj_callrequest=callrequest,
    #     request_uuid=request_uuid,
    #     leg=leg,
    #     hangup_cause=opt_hangup_cause,
    #     hangup_cause_q850=hangup_cause_q850,
    #     callerid=callerid,
    #     phonenumber=phonenumber,
    #     starting_date=starting_date,
    #     call_uuid=call_uuid,
    #     duration=duration,
    #     billsec=billsec,
    #     amd_status=amd_status)

    # debug_query(25)

    voipcall_save.delay(callrequest=callrequest,
                        request_uuid=request_uuid,
                        leg=leg,
                        hangup_cause=opt_hangup_cause,
                        hangup_cause_q850=hangup_cause_q850,
                        callerid=callerid,
                        phonenumber=phonenumber,
                        starting_date=starting_date,
                        call_uuid=call_uuid,
                        duration=duration,
                        billsec=billsec,
                        amd_status=amd_status)

    #TODO: Move this to tasks?

    #If the call failed we will check if we want to make a retry call
    #Add condition to retry when it s machine and we want to reach a human
    if (opt_hangup_cause != 'NORMAL_CLEARING' and callrequest.call_type == CALLREQUEST_TYPE.ALLOW_RETRY) or \
       (amd_status == 'machine' and callrequest.campaign.voicemail
       and callrequest.campaign.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY):
        #Update to Retry Done
        callrequest.call_type = CALLREQUEST_TYPE.RETRY_DONE
        callrequest.save()

        debug_query(26)

        #check if we are allowed to retry on failure
        if ((callrequest.subscriber.count_attempt - 1) >=
                callrequest.campaign.maxretry
                or not callrequest.campaign.maxretry):
            logger.error("Not allowed retry - Maxretry (%d)" %
                         callrequest.campaign.maxretry)
            #Check here if we should try for completion
            check_retrycall_completion(callrequest)
            debug_query(28)
        else:
            #Allowed Retry
            logger.error("Allowed Retry - Maxretry (%d)" %
                         callrequest.campaign.maxretry)

            # Create new callrequest, Assign parent_callrequest,
            # Change callrequest_type & num_attempt
            new_callrequest = Callrequest(
                request_uuid=uuid1(),
                parent_callrequest_id=callrequest.id,
                call_type=CALLREQUEST_TYPE.ALLOW_RETRY,
                num_attempt=callrequest.num_attempt + 1,
                user=callrequest.user,
                campaign_id=callrequest.campaign_id,
                aleg_gateway_id=callrequest.aleg_gateway_id,
                content_type=callrequest.content_type,
                object_id=callrequest.object_id,
                phone_number=callrequest.phone_number,
                timelimit=callrequest.timelimit,
                callerid=callrequest.callerid,
                timeout=callrequest.timeout,
                subscriber_id=callrequest.subscriber_id)
            new_callrequest.save()
            #NOTE : implement a PID algorithm
            second_towait = callrequest.campaign.intervalretry
            debug_query(29)

            logger.debug("Init Retry CallRequest in  %d seconds" %
                         second_towait)
            init_callrequest.apply_async(args=[
                new_callrequest.id, callrequest.campaign.id,
                callrequest.campaign.callmaxduration
            ],
                                         countdown=second_towait)
    else:
        #The Call is Answered
        logger.debug("Check for completion call")

        #Check if we should relaunch a new call to achieve completion
        check_retrycall_completion(callrequest)
示例#14
0
def check_callevent():
    """
    Check callevent

    call_event table is created by listener.lua

    CREATE TABLE if not exists call_event (
        id serial NOT NULL PRIMARY KEY,
        event_name varchar(200) NOT NULL,
        body varchar(200) NOT NULL,
        job_uuid varchar(200),
        call_uuid varchar(200) NOT NULL,
        used_gateway_id integer,
        callrequest_id integer,
        callerid varchar(200),
        phonenumber varchar(200),
        duration integer DEFAULT 0,
        billsec integer DEFAULT 0,
        hangup_cause varchar(40),
        hangup_cause_q850 varchar(10),
        amd_status varchar(40),
        starting_date timestamp with time zone,
        status integer,
        created_date timestamp with time zone NOT NULL
        );
    CREATE INDEX call_event_idx_uuid ON call_event (call_uuid);
    CREATE INDEX call_event_idx_status ON call_event (status);
    CREATE INDEX call_event_idx_date ON call_event (created_date);

    """
    debug_query(20)

    cursor = connection.cursor()

    #TODO (Areski)
    #Replace this for ORM with select_for_update or transaction

    sql_statement = "SELECT id, event_name, body, job_uuid, call_uuid, used_gateway_id, "\
        "callrequest_id, callerid, phonenumber, duration, billsec, hangup_cause, "\
        "hangup_cause_q850, starting_date, status, created_date, amd_status, leg FROM call_event WHERE status=1 LIMIT 2000 OFFSET 0"

    cursor.execute(sql_statement)
    row = cursor.fetchall()

    debug_query(21)
    buff_voipcall = BufferVoIPCall()

    for record in row:
        call_event_id = record[0]
        event_name = record[1]
        body = record[2]
        job_uuid = record[3]
        call_uuid = record[4]
        #used_gateway_id = record[5]
        callrequest_id = record[6]
        callerid = record[7]
        phonenumber = record[8]
        duration = record[9]
        billsec = record[10]
        hangup_cause = record[11]
        hangup_cause_q850 = record[12]
        starting_date = record[13]
        amd_status = record[16]
        leg = record[17]

        #Update Call Event
        sql_statement = "UPDATE call_event SET status=2 WHERE id=%d" % call_event_id
        cursor.execute(sql_statement)
        logger.info("Processing Event : %s" % event_name)

        if event_name == 'BACKGROUND_JOB':
            #hangup cause come from body
            hangup_cause = body[5:]

        # if event_name == 'CHANNEL_HANGUP_COMPLETE':
        #     #hangup cause come from body
        #     print(event_name)

        if hangup_cause == '':
            hangup_cause = body[5:]

        opt_request_uuid = job_uuid
        opt_hangup_cause = hangup_cause

        debug_query(22)

        try:
            if callrequest_id == 0:
                callrequest = Callrequest.objects\
                    .select_related('aleg_gateway', 'subscriber', 'campaign')\
                    .get(request_uuid=opt_request_uuid.strip(' \t\n\r'))
            else:
                #mainly coming here
                callrequest = Callrequest.objects\
                    .select_related('aleg_gateway', 'subscriber', 'campaign')\
                    .get(id=callrequest_id)
        except:
            logger.error("Cannot find Callrequest job_uuid : %s" % job_uuid)
            continue

        logger.debug("Find Callrequest id : %d" % callrequest.id)
        debug_query(23)

        if leg == 'aleg':
            #Only the aleg will update the subscriber status / Bleg is only recorded
            #Update Callrequest Status
            if opt_hangup_cause == 'NORMAL_CLEARING':
                callrequest.status = CALLREQUEST_STATUS.SUCCESS
                if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
                    callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
            else:
                callrequest.status = CALLREQUEST_STATUS.FAILURE
                callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
            callrequest.hangup_cause = opt_hangup_cause

            callrequest.save()
            callrequest.subscriber.save()

        debug_query(24)

        if call_uuid == '':
            call_uuid = job_uuid
        if callerid == '':
            callerid = callrequest.callerid
        if phonenumber == '':
            phonenumber = callrequest.phone_number

        #TODO: Create those in Bulk - add in a buffer until reach certain number
        buff_voipcall.save(
            obj_callrequest=callrequest,
            request_uuid=opt_request_uuid,
            leg=leg,
            hangup_cause=opt_hangup_cause,
            hangup_cause_q850=hangup_cause_q850,
            callerid=callerid,
            phonenumber=phonenumber,
            starting_date=starting_date,
            call_uuid=call_uuid,
            duration=duration,
            billsec=billsec,
            amd_status=amd_status)

        debug_query(25)

        #If the call failed we will check if we want to make a retry call
        #Add condition to retry when it s machine and we want to reach a human
        if (opt_hangup_cause != 'NORMAL_CLEARING' and callrequest.call_type == CALLREQUEST_TYPE.ALLOW_RETRY) or \
           (amd_status == 'machine' and callrequest.campaign.voicemail
           and callrequest.campaign.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY):
            #Update to Retry Done
            callrequest.call_type = CALLREQUEST_TYPE.RETRY_DONE
            callrequest.save()

            debug_query(26)

            #check if we are allowed to retry on failure
            if ((callrequest.subscriber.count_attempt - 1) >= callrequest.campaign.maxretry
               or not callrequest.campaign.maxretry):
                logger.error("Not allowed retry - Maxretry (%d)" %
                             callrequest.campaign.maxretry)
                #Check here if we should try for completion
                check_retrycall_completion(callrequest)
                debug_query(28)
            else:
                #Allowed Retry
                logger.error("Allowed Retry - Maxretry (%d)" % callrequest.campaign.maxretry)

                # Create new callrequest, Assign parent_callrequest,
                # Change callrequest_type & num_attempt
                new_callrequest = Callrequest(
                    request_uuid=uuid1(),
                    parent_callrequest_id=callrequest.id,
                    call_type=CALLREQUEST_TYPE.ALLOW_RETRY,
                    num_attempt=callrequest.num_attempt + 1,
                    user=callrequest.user,
                    campaign_id=callrequest.campaign_id,
                    aleg_gateway_id=callrequest.aleg_gateway_id,
                    content_type=callrequest.content_type,
                    object_id=callrequest.object_id,
                    phone_number=callrequest.phone_number,
                    timelimit=callrequest.timelimit,
                    callerid=callrequest.callerid,
                    timeout=callrequest.timeout,
                    subscriber_id=callrequest.subscriber_id
                )
                new_callrequest.save()
                #NOTE : implement a PID algorithm
                second_towait = callrequest.campaign.intervalretry
                debug_query(29)

                logger.debug("Init Retry CallRequest in  %d seconds" % second_towait)
                init_callrequest.apply_async(
                    args=[new_callrequest.id, callrequest.campaign.id, callrequest.campaign.callmaxduration],
                    countdown=second_towait)
        else:
            #The Call is Answered
            logger.debug("Check for completion call")

            #Check if we should relaunch a new call to achieve completion
            check_retrycall_completion(callrequest)

    debug_query(30)

    buff_voipcall.commit()
    debug_query(31)

    logger.debug('End Loop : check_callevent')
示例#15
0
def callevent_processing():
    """
    Retrieve callevents and process them

    call_event table is created by listener.lua

    CREATE TABLE if not exists call_event (
        id serial NOT NULL PRIMARY KEY,
        event_name varchar(200) NOT NULL,
        body varchar(200) NOT NULL,
        job_uuid varchar(200),
        call_uuid varchar(200) NOT NULL,
        used_gateway_id integer,
        callrequest_id integer,
        alarm_request_id integer,
        callerid varchar(200),
        phonenumber varchar(200),
        duration integer DEFAULT 0,
        billsec integer DEFAULT 0,
        hangup_cause varchar(40),
        hangup_cause_q850 varchar(10),
        amd_status varchar(40),
        starting_date timestamp with time zone,
        status smallint,
        leg smallint,
        created_date timestamp with time zone NOT NULL
        );
    CREATE INDEX call_event_idx_status ON call_event (status);
    --CREATE INDEX call_event_idx_date ON call_event (created_date);
    --CREATE INDEX call_event_idx_uuid ON call_event (call_uuid);
    """
    debug_query(20)

    cursor = connection.cursor()
    # TODO (Areski)
    # Replace this for ORM with select_for_update or transaction

    try:
        sql_statement = "SELECT id, event_name, body, job_uuid, call_uuid, used_gateway_id, " \
            "callrequest_id, alarm_request_id, callerid, phonenumber, duration, billsec, hangup_cause, " \
            "hangup_cause_q850, starting_date, status, created_date, amd_status, leg " \
            "FROM call_event WHERE status=1 LIMIT 1000 OFFSET 0"

        cursor.execute(sql_statement)
        row = cursor.fetchall()
    except:
        # Error on sql / Lua listener might not be on
        logger.error("Error Fetching call_event")
    else:
        debug_query(21)
        # buff_voipcall = BufferVoIPCall()
        call_event_list = []
        for record in row:
            call_event_id = record[0]
            event_name = record[1]
            call_event_list.append(str(call_event_id))
            logger.info("Processing Call_Event : %s" % event_name)
            process_callevent.delay(record)

        if call_event_list:
            # Update Call Event
            sql_statement = "UPDATE call_event SET status=2 WHERE id IN (%s)" % ','.join(
                call_event_list)
            cursor.execute(sql_statement)
            debug_query(30)
        # buff_voipcall.commit()
        # debug_query(31)
        logger.debug('End Loop : callevent_processing')
示例#16
0
def process_callevent(record):
    """
    Process the callevent, this tasks will:
        - Retrieve the callrequest using either callrequest_id or request_uuid
        - create the voipcall, and save different data
    """
    #TODO: add method in utils parse_callevent
    app_type = 'campaign'
    event_name = record[1]
    body = record[2]
    job_uuid = record[3]
    call_uuid = record[4]
    #used_gateway_id = record[5]
    callrequest_id = record[6]
    alarm_request_id = record[7]
    callerid = record[8]
    phonenumber = record[9]
    duration = record[10]
    billsec = record[11]
    hangup_cause = record[12]
    hangup_cause_q850 = record[13]
    starting_date = record[14]
    amd_status = record[17]
    leg = record[18]

    if event_name == 'BACKGROUND_JOB':
        #hangup cause come from body
        hangup_cause = body[5:]

    if hangup_cause == '':
        hangup_cause = body[5:]

    request_uuid = job_uuid
    opt_hangup_cause = hangup_cause
    debug_query(22)

    try:
        if callrequest_id == 0:
            callrequest = Callrequest.objects \
                .select_related('aleg_gateway', 'subscriber', 'campaign') \
                .get(request_uuid=request_uuid.strip(' \t\n\r'))
        else:
            #mainly coming here
            callrequest = Callrequest.objects \
                .select_related('aleg_gateway', 'subscriber', 'campaign') \
                .get(id=callrequest_id)
    except:
        logger.error("Cannot find Callrequest job_uuid : %s" % job_uuid)
        return True

    logger.error(callrequest)
    if callrequest.alarm_request_id:
        app_type = 'alarm'
        alarm_req = AlarmRequest.objects.get(pk=callrequest.alarm_request_id)
        #Overwrite alarm_request_id as this is equal to 0 when call fails
        alarm_request_id = callrequest.alarm_request_id

    logger.debug("Find Callrequest id : %d" % callrequest.id)
    debug_query(23)

    if leg == 'aleg' and app_type == 'campaign':
        #Update callrequest
        #update_callrequest.delay(callrequest, opt_hangup_cause)
        #Disabled above tasks to reduce amount of tasks

        #Only the aleg will update the subscriber status / Bleg is only recorded
        #Update Callrequest Status
        if opt_hangup_cause == 'NORMAL_CLEARING':
            callrequest.status = CALLREQUEST_STATUS.SUCCESS
            if callrequest.subscriber.status != SUBSCRIBER_STATUS.COMPLETED:
                callrequest.subscriber.status = SUBSCRIBER_STATUS.SENT
        else:
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
        callrequest.hangup_cause = opt_hangup_cause
        # ...

        callrequest.save()
        callrequest.subscriber.save()
        debug_query(24)
    elif leg == 'aleg' and app_type == 'alarm':
        if opt_hangup_cause == 'NORMAL_CLEARING':
            callrequest.status = CALLREQUEST_STATUS.SUCCESS
            alarm_req.status = ALARMREQUEST_STATUS.SUCCESS
            alarm_req.duration = duration
            alarm_req.alarm.status = ALARM_STATUS.SUCCESS
        else:
            callrequest.status = CALLREQUEST_STATUS.FAILURE
            alarm_req.status = ALARMREQUEST_STATUS.FAILURE
            alarm_req.alarm.status = ALARM_STATUS.FAILURE
        callrequest.hangup_cause = opt_hangup_cause

        callrequest.save()
        alarm_req.save()
        alarm_req.alarm.save()
        debug_query(24)

    if call_uuid == '':
        call_uuid = job_uuid
    if callerid == '':
        callerid = callrequest.callerid
    if phonenumber == '':
        phonenumber = callrequest.phone_number
    #Create those in Bulk - add in a buffer until reach certain number
    # buff_voipcall.save(
    #     obj_callrequest=callrequest,
    #     request_uuid=request_uuid,
    #     leg=leg,
    #     hangup_cause=opt_hangup_cause,
    #     hangup_cause_q850=hangup_cause_q850,
    #     callerid=callerid,
    #     phonenumber=phonenumber,
    #     starting_date=starting_date,
    #     call_uuid=call_uuid,
    #     duration=duration,
    #     billsec=billsec,
    #     amd_status=amd_status)

    # debug_query(25)

    voipcall_save(
        callrequest=callrequest,
        request_uuid=request_uuid,
        leg=leg,
        hangup_cause=opt_hangup_cause,
        hangup_cause_q850=hangup_cause_q850,
        callerid=callerid,
        phonenumber=phonenumber,
        starting_date=starting_date,
        call_uuid=call_uuid,
        duration=duration,
        billsec=billsec,
        amd_status=amd_status)

    #If the call failed we will check if we want to make a retry call
    #Add condition to retry when it s machine and we want to reach a human
    if (app_type == 'campaign' and opt_hangup_cause != 'NORMAL_CLEARING'
        and callrequest.call_type == CALLREQUEST_TYPE.ALLOW_RETRY) or \
       (amd_status == 'machine' and callrequest.campaign.voicemail and
        callrequest.campaign.amd_behavior == AMD_BEHAVIOR.HUMAN_ONLY):
        #Update to Retry Done
        callrequest.call_type = CALLREQUEST_TYPE.RETRY_DONE
        callrequest.save()

        debug_query(26)

        #check if we are allowed to retry on failure
        if ((callrequest.subscriber.count_attempt - 1) >= callrequest.campaign.maxretry
           or not callrequest.campaign.maxretry):
            logger.error("Not allowed retry - Maxretry (%d)" %
                         callrequest.campaign.maxretry)
            #Check here if we should try for completion
            check_retrycall_completion(callrequest)
            debug_query(28)
        else:
            #Allowed Retry
            logger.error("Allowed Retry - Maxretry (%d)" % callrequest.campaign.maxretry)

            # Create new callrequest, Assign parent_callrequest,
            # Change callrequest_type & num_attempt
            new_callrequest = Callrequest(
                request_uuid=uuid1(),
                parent_callrequest_id=callrequest.id,
                call_type=CALLREQUEST_TYPE.ALLOW_RETRY,
                num_attempt=callrequest.num_attempt + 1,
                user=callrequest.user,
                campaign_id=callrequest.campaign_id,
                aleg_gateway_id=callrequest.aleg_gateway_id,
                content_type=callrequest.content_type,
                object_id=callrequest.object_id,
                phone_number=callrequest.phone_number,
                timelimit=callrequest.timelimit,
                callerid=callrequest.callerid,
                timeout=callrequest.timeout,
                subscriber_id=callrequest.subscriber_id
            )
            new_callrequest.save()
            #NOTE : implement a PID algorithm
            second_towait = callrequest.campaign.intervalretry
            debug_query(29)

            logger.debug("Init Retry CallRequest in  %d seconds" % second_towait)
            init_callrequest.apply_async(
                args=[new_callrequest.id, callrequest.campaign.id, callrequest.campaign.callmaxduration],
                countdown=second_towait)

    elif app_type == 'campaign':
        #The Call is Answered and it's a campaign call
        logger.debug("Check for completion call")

        #Check if we should relaunch a new call to achieve completion
        check_retrycall_completion(callrequest)

    elif opt_hangup_cause != 'NORMAL_CLEARING' and app_type == 'alarm':
        #
        check_retry_alarm(alarm_request_id)
示例#17
0
def init_callrequest(callrequest_id,
                     campaign_id,
                     callmaxduration,
                     ms_addtowait=0,
                     alarm_request_id=None):
    """
    This task read the callrequest, update it as 'In Process'
    then proceed on the call outbound, using the different call engine supported

    **Attributes**:

        * ``callrequest_id`` - Callrequest ID
        * ``campaign_id`` - Campaign ID
        * ``callmaxduration`` - Max duration
        * ``ms_addtowait`` - Milliseconds to wait before outbounding the call

    """
    outbound_failure = False
    subscriber_id = None
    contact_id = None
    debug_query(8)

    if ms_addtowait > 0:
        sleep(ms_addtowait)

    # Survey Call or Alarm Call
    if campaign_id:
        # TODO: use only
        # https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.only
        obj_callrequest = Callrequest.objects\
            .select_related('aleg_gateway', 'user__userprofile', 'subscriber', 'campaign').get(id=callrequest_id)
        subscriber_id = obj_callrequest.subscriber_id
        contact_id = obj_callrequest.subscriber.contact_id
    elif alarm_request_id:
        obj_callrequest = Callrequest.objects.select_related(
            'aleg_gateway', 'user__userprofile').get(id=callrequest_id)
        alarm_request_id = obj_callrequest.alarm_request_id
    else:
        logger.info(
            "TASK :: init_callrequest, wrong campaign_id & alarm_request_id")
        return False

    debug_query(9)
    logger.info("TASK :: init_callrequest - status:%s;cmpg:%s;alarm:%s" %
                (obj_callrequest.status, campaign_id, alarm_request_id))

    # TODO: move method prepare_phonenumber into the model gateway
    # Obj_callrequest.aleg_gatewayprepare_phonenumber()
    dialout_phone_number = prepare_phonenumber(
        obj_callrequest.phone_number, obj_callrequest.aleg_gateway.addprefix,
        obj_callrequest.aleg_gateway.removeprefix,
        obj_callrequest.aleg_gateway.status)
    if not dialout_phone_number:
        logger.info("Error with dialout_phone_number - phone_number:%s" %
                    (obj_callrequest.phone_number))
        return False
    else:
        logger.debug("dialout_phone_number : %s" % dialout_phone_number)

    debug_query(10)

    if settings.DIALERDEBUG:
        dialout_phone_number = settings.DIALERDEBUG_PHONENUMBER

    # Retrieve the Gateway for the A-Leg
    gateways = obj_callrequest.aleg_gateway.gateways
    gateway_id = obj_callrequest.aleg_gateway.id
    # Gateway_codecs / gateway_retries

    dialing_timeout = obj_callrequest.timeout
    # fraud protection on short calls
    try:
        dialing_timeout = int(dialing_timeout)
        if dialing_timeout < 10:
            dialing_timeout = 10
    except ValueError:
        dialing_timeout = 45
    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string

    debug_query(11)

    # Sanitize gateways
    gateways = gateways.strip()
    if gateways[-1] != '/':
        gateways = gateways + '/'

    originate_dial_string = obj_callrequest.aleg_gateway.originate_dial_string
    if obj_callrequest.user.userprofile and obj_callrequest.user.userprofile.accountcode:
        originate_dial_string = originate_dial_string + ',accountcode=' + \
            str(obj_callrequest.user.userprofile.accountcode)

    debug_query(12)

    if settings.NEWFIES_DIALER_ENGINE.lower() == 'esl':
        try:
            args_list = []
            send_digits = False
            time_limit = callmaxduration

            # To wait before sending DTMF to the extension, you can add leading 'w'
            # characters.
            # Each 'w' character waits 0.5 seconds instead of sending a digit.
            # Each 'W' character waits 1.0 seconds instead of sending a digit.
            # You can also add the tone duration in ms by appending @[duration] after string.
            # Eg. 1w2w3@1000
            check_senddigit = dialout_phone_number.partition('w')
            if check_senddigit[1] == 'w':
                send_digits = check_senddigit[1] + check_senddigit[2]
                dialout_phone_number = check_senddigit[0]

            if obj_callrequest.callerid and len(obj_callrequest.callerid) > 0:
                args_list.append("origination_caller_id_number='%s'" %
                                 obj_callrequest.callerid)
            if obj_callrequest.caller_name and len(
                    obj_callrequest.caller_name) > 0:
                args_list.append("origination_caller_id_name='%s'" %
                                 obj_callrequest.caller_name)

            # Add App Vars
            args_list.append(
                "campaign_id=%s,subscriber_id=%s,alarm_request_id=%s,used_gateway_id=%s,callrequest_id=%s,contact_id=%s,dialout_phone_number=%s"
                %
                (campaign_id, subscriber_id, alarm_request_id, gateway_id,
                 obj_callrequest.id, contact_id, obj_callrequest.phone_number))
            args_list.append(originate_dial_string)

            # Call Vars
            callvars = "bridge_early_media=true,originate_timeout=%d,newfiesdialer=true,leg_type=1" % \
                (dialing_timeout, )
            args_list.append(callvars)

            # Default Test
            hangup_on_ring = ''
            send_preanswer = False
            # set hangup_on_ring
            try:
                hangup_on_ring = int(hangup_on_ring)
            except ValueError:
                hangup_on_ring = -1
            exec_on_media = 1
            if hangup_on_ring >= 10:  # 0->10 fraud protection on short calls
                args_list.append(
                    "execute_on_media_%d='sched_hangup +%d ORIGINATOR_CANCEL'"
                    % (exec_on_media, hangup_on_ring))
                exec_on_media += 1

            # TODO: look and test http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_queue_dtmf
            # Send digits
            if send_digits:
                if send_preanswer:
                    args_list.append("execute_on_media_%d='send_dtmf %s'" %
                                     (exec_on_media, send_digits))
                    exec_on_media += 1
                else:
                    args_list.append("execute_on_answer='send_dtmf %s'" %
                                     send_digits)

            # Set time_limit
            try:
                time_limit = int(time_limit)
                if time_limit > 0:
                    args_list.append(
                        "execute_on_answer='sched_hangup +%d ALLOTTED_TIMEOUT'"
                        % time_limit)
            except ValueError:
                logger.error('ValueError time_limit :> %s' % time_limit)

            # build originate string
            args_str = ','.join(args_list)

            # DEBUG
            # settings.ESL_SCRIPT = '&playback(/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-record_greeting.wav)'
            if settings.DIALERDEBUG:
                dial_command = "originate {%s}user/areski '%s'" % (
                    args_str, settings.ESL_SCRIPT)
            else:
                dial_command = "originate {%s}%s%s '%s'" % \
                    (args_str, gateways, dialout_phone_number, settings.ESL_SCRIPT)

            # originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=10}user/areski &playback(/tmp/myfile.wav)
            # dial = "originate {bridge_early_media=true,hangup_after_bridge=true,originate_timeout=,newfiesdialer=true,used_gateway_id=1,callrequest_id=38,leg_type=1,origination_caller_id_number=234234234,origination_caller_id_name=234234,effective_caller_id_number=234234234,effective_caller_id_name=234234,}user//1000 '&lua(/usr/share/newfies-lua/newfies.lua)'"

            # Load balance on testing
            # from random import randint, seed
            # seed()
            # randval = randint(1, 2)
            # if randval == 1:
            #     dial_command = dial_command.replace('88.208.208.244', '88.208.208.209')
            # logger.warn('dial_command (%d): %s' % (randval, dial_command))

            logger.warn('dial_command : %s' % dial_command)
            request_uuid = dial_out(dial_command, obj_callrequest.id)

            debug_query(14)

            if request_uuid and len(
                    request_uuid) > 0 and request_uuid[:5] == 'error':
                outbound_failure = True
            debug_query(13)
        except:
            raise
            logger.error('error : ESL')
            outbound_failure = True
        logger.debug('Received RequestUUID :> %s' % request_uuid)
    else:
        logger.error('No other method supported!')
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
        obj_callrequest.save()
        # ADD if alarm_request_id update AlarmRequest
        return False

    # Survey Call or Alarm Call
    if campaign_id:
        # Update Subscriber
        if not obj_callrequest.subscriber.count_attempt:
            obj_callrequest.subscriber.count_attempt = 1
        else:
            obj_callrequest.subscriber.count_attempt = obj_callrequest.subscriber.count_attempt + 1
        obj_callrequest.subscriber.last_attempt = datetime.utcnow().replace(
            tzinfo=utc)
        # check if the outbound call failed then update Subscriber
        if outbound_failure:
            obj_callrequest.subscriber.status = SUBSCRIBER_STATUS.FAIL
        obj_callrequest.subscriber.save()
    elif alarm_request_id:
        if outbound_failure:
            check_retry_alarm(alarm_request_id)

    # Update CallRequest Object
    obj_callrequest.request_uuid = request_uuid
    # check if the outbound call failed
    if outbound_failure:
        obj_callrequest.status = CALLREQUEST_STATUS.FAILURE
    else:
        obj_callrequest.status = CALLREQUEST_STATUS.CALLING
    obj_callrequest.save()

    debug_query(14)

    return True
示例#18
0
    def run(self, campaign_id):
        """
        This will execute the outbound calls in the campaign

        **Attributes**:

            * ``campaign_id`` - Campaign ID
        """
        logger = self.get_logger()
        logger.info("TASK :: spool_pending_call = %d" % campaign_id)

        debug_query(0)

        try:
            obj_campaign = Campaign.objects.select_related(
                'user__userprofile__dialersetting', 'aleg_gateway',
                'content_type').get(id=campaign_id)
        except:
            logger.error("Can't find this campaign")
            return False

        # TODO : Control the Speed
        # if there is many task pending we should slow down
        frequency = obj_campaign.frequency  # default 10 calls per minutes

        debug_query(1)

        # Default call_type
        call_type = CALLREQUEST_TYPE.ALLOW_RETRY
        # Check campaign's maxretry
        if obj_campaign.maxretry == 0:
            call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        # Check user's dialer setting maxretry
        if obj_campaign.user.userprofile.dialersetting:
            if obj_campaign.user.userprofile.dialersetting.maxretry == 0:
                call_type = CALLREQUEST_TYPE.CANNOT_RETRY

        debug_query(2)

        # Speed
        # Check if the other tasks send for this campaign finished to be ran

        # Get the subscriber of this campaign
        # get_pending_subscriber get Max 1000 records
        if frequency >= 10:
            callfrequency = int(
                frequency / DIV_MIN) + 1  # 1000 per minutes 101
            #callfrequency = int(frequency) + 1  # 1000 per minutes 101
        else:
            callfrequency = frequency
        (list_subscriber,
         no_subscriber) = obj_campaign.get_pending_subscriber_update(
             callfrequency, SUBSCRIBER_STATUS.IN_PROCESS)
        logger.info(
            "##subscriber=%d campaign_id=%d callfrequency=%d frequency=%d" %
            (no_subscriber, campaign_id, callfrequency, frequency))
        debug_query(3)

        if no_subscriber == 0:
            return False

        # Set time to wait for balanced dispatching of calls
        #time_to_wait = int(60 / DIV_MIN) / no_subscriber
        time_to_wait = 6.0 / no_subscriber
        count = 0

        for elem_camp_subscriber in list_subscriber:
            """Loop on Subscriber and start the initcall task"""
            count = count + 1
            second_towait = floor(count * time_to_wait)
            ms_addtowait = (count * time_to_wait) - second_towait
            logger.info(
                "Init CallRequest in %d seconds (cmpg:%d,subscriber:%d)" %
                (second_towait, campaign_id, elem_camp_subscriber.id))

            phone_number = elem_camp_subscriber.duplicate_contact
            debug_query(4)

            #Verify that the contact is authorized
            if not obj_campaign.is_authorized_contact(
                    obj_campaign.user.userprofile.dialersetting, phone_number):
                logger.error("Error : Contact not authorized")
                elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                elem_camp_subscriber.save()
                return True
            #Verify that the contact is not in the DNC list
            if obj_campaign.dnc:
                res_dnc = DNCContact.objects.filter(dnc_id=obj_campaign.dnc_id,
                                                    phone_number=phone_number)
                if res_dnc:
                    logger.error("Contact (%s) in DNC list" % phone_number)
                    elem_camp_subscriber.status = SUBSCRIBER_STATUS.NOT_AUTHORIZED
                    elem_camp_subscriber.save()
                    return True
                else:
                    logger.debug("Contact (%s) not in DNC list" % phone_number)

            debug_query(5)

            #TODO: idea to speed up, create bluck of 10(Y) and then send a list of callrequest_id to init_callrequest

            # Create a Callrequest Instance to track the call task
            new_callrequest = Callrequest(
                status=CALLREQUEST_STATUS.PENDING,
                call_type=call_type,
                call_time=datetime.now(),
                timeout=obj_campaign.calltimeout,
                callerid=obj_campaign.callerid,
                phone_number=phone_number,
                campaign=obj_campaign,
                aleg_gateway=obj_campaign.aleg_gateway,
                content_type=obj_campaign.content_type,
                object_id=obj_campaign.object_id,
                user=obj_campaign.user,
                extra_data=obj_campaign.extra_data,
                timelimit=obj_campaign.callmaxduration,
                subscriber=elem_camp_subscriber)
            new_callrequest.save()

            debug_query(6)

            init_callrequest.apply_async(args=[
                new_callrequest.id, obj_campaign.id,
                obj_campaign.callmaxduration, ms_addtowait
            ],
                                         countdown=second_towait)
            # Shell_plus
            # from dialer_cdr.tasks import init_callrequest
            # from datetime import datetime
            # new_callrequest_id = 112
            # obj_campaign_id = 3
            # countdown = 1
            # init_callrequest.apply_async(args=[new_callrequest_id, obj_campaign_id], countdown=1)

        debug_query(7)
        return True