def __init__(self, user, *args, **kwargs): super(DuplicateCampaignForm, self).__init__(*args, **kwargs) self.fields['campaign_code'].initial = get_unique_code(length=5) for i in self.fields.keyOrder: self.fields[i].widget.attrs['class'] = "form-control" if user: phonebook_list = get_phonebook_list(user) self.fields['phonebook'].choices = phonebook_list self.fields['phonebook'].initial = str(phonebook_list[0][0])
def __init__(self, user, *args, **kwargs): super(DuplicateCampaignForm, self).__init__(*args, **kwargs) self.fields['campaign_code'].initial = get_unique_code(length=5) if user: list_pb = [] list_pb.append((0, '---')) list = Phonebook.objects.values_list('id', 'name')\ .filter(user=user).order_by('id') for l in list: list_pb.append((l[0], l[1])) self.fields['phonebook'].choices = list_pb
def __init__(self, user, *args, **kwargs): super(CampaignForm, self).__init__(*args, **kwargs) instance = getattr(self, 'instance', None) self.fields['campaign_code'].initial = get_unique_code(length=5) self.fields['description'].widget.attrs['class'] = "input-xlarge" if user: self.fields['ds_user'].initial = user list_gw = [] list_pb = [] dnc_list = [] list_pb.append((0, '---')) list = Phonebook.objects.values_list('id', 'name')\ .filter(user=user).order_by('id') for l in list: list_pb.append((l[0], l[1])) self.fields['phonebook'].choices = list_pb list = user.get_profile().userprofile_gateway.all() gw_list = ((l.id, l.name) for l in list) dnc_list.append(('', '---')) list = DNC.objects.values_list('id', 'name')\ .filter(user=user).order_by('id') for l in list: dnc_list.append((l[0], l[1])) self.fields['dnc'].choices = dnc_list for i in gw_list: list_gw.append((i[0], i[1])) self.fields['aleg_gateway'].choices = list_gw if instance.has_been_duplicated: from survey.models import Survey available_objects = Survey.objects.filter(user=user, campaign=instance) object_choices = get_object_choices(available_objects) self.fields['content_object'].widget.attrs['readonly'] = True else: from survey.models import Survey_template available_objects = Survey_template.objects.filter(user=user) object_choices = get_object_choices(available_objects) self.fields['content_object'].choices = object_choices # Voicemail setting is not enabled by default if settings.AMD: from survey.forms import get_audiofile_list self.fields['voicemail_audiofile'].choices = get_audiofile_list(user) # if campaign is running if instance.status == CAMPAIGN_STATUS.START: self.fields['name'].widget.attrs['readonly'] = True self.fields['caller_name'].widget.attrs['readonly'] = True self.fields['callerid'].widget.attrs['readonly'] = True self.fields['extra_data'].widget.attrs['readonly'] = True self.fields['phonebook'].widget.attrs['disabled'] = 'disabled' selected_phonebook = '' if instance.phonebook.all(): selected_phonebook = \ ",".join(["%s" % (i.id) for i in instance.phonebook.all()]) self.fields['selected_phonebook'].initial = selected_phonebook self.fields['content_object'].widget.attrs['disabled'] = 'disabled' self.fields['content_object'].required = False self.fields['selected_content_object'].initial = "type:%s-id:%s" \ % (instance.content_type.id, instance.object_id)
def __init__(self, *args, **kwargs): super(CampaignAdminForm, self).__init__(*args, **kwargs) self.fields['campaign_code'].widget.attrs['readonly'] = True self.fields['campaign_code'].initial = get_unique_code(length=5)
class Campaign(Model): """This defines the Campaign **Attributes**: * ``campaign_code`` - Auto-generated campaign code to identify the campaign * ``name`` - Campaign name * ``description`` - Description about the Campaign * ``status`` - Campaign status * ``callerid`` - Caller ID * ``startingdate`` - Starting date of the Campaign * ``expirationdate`` - Expiry date of the Campaign * ``daily_start_time`` - Start time * ``daily_stop_time`` - End time * ``week_day_setting`` (monday, tuesday, wednesday, thursday, friday, \ saturday, sunday) * ``frequency`` - Frequency, speed of the campaign. number of calls/min * ``callmaxduration`` - Max retry allowed per user * ``maxretry`` - Max retry allowed per user * ``intervalretry`` - Time to wait between retries in seconds * ``completion_maxretry`` - Amount of retries until a contact is completed * ``completion_intervalretry`` - Time delay in seconds before retrying \ contact for completion * ``calltimeout`` - Number of seconds to timeout on calls * ``aleg_gateway`` - Gateway to use to reach the contact * ``extra_data`` - Additional data to pass to the application * ``totalcontact`` - Total Contact for this campaign * ``completed`` - Total Contact that completed Call / Survey * ``has_been_started`` - campaign started flag * ``has_been_duplicated`` - campaign duplicated flag * ``voicemail`` - Enable Voicemail Detection * ``amd_behavior`` - Detection Behaviour **Relationships**: * ``content_type`` - Defines the application (``survey``) \ to use when the call is established on the A-Leg * ``object_id`` - Defines the object of content_type application * ``content_object`` - Used to define the Voice App or the Survey with generic ForeignKey * ``phonebook`` - Many-To-Many relationship to the Phonebook model. * ``user`` - Foreign key relationship to the a User model. \ Each campaign assigned to a User * ``voicemail_audiofile`` - Foreign key relationship to the a AudioFile model. * ``dnc`` - Foreign key relationship to the a DNC model. **Name of DB table**: dialer_campaign """ campaign_code = models.CharField( unique=True, max_length=20, blank=True, verbose_name=_("campaign code"), help_text= _('this code is auto-generated by the platform, this is used to identify the campaign' ), default=(lambda: get_unique_code(length=5))) name = models.CharField(max_length=100, verbose_name=_('name')) description = models.TextField(verbose_name=_('description'), blank=True, null=True, help_text=_("campaign description")) user = models.ForeignKey('auth.User', related_name='Campaign owner') status = models.IntegerField(choices=list(CAMPAIGN_STATUS), default=CAMPAIGN_STATUS.PAUSE, verbose_name=_("status"), blank=True, null=True) callerid = models.CharField(max_length=80, blank=True, verbose_name=_("callerID"), help_text=_("outbound caller-ID")) caller_name = models.CharField(max_length=80, blank=True, verbose_name=_("caller name"), help_text=_("outbound caller-Name")) #General Starting & Stopping date startingdate = models.DateTimeField( default=(lambda: datetime.now()), verbose_name=_('start'), help_text=_("date format: YYYY-mm-DD HH:MM:SS")) expirationdate = models.DateTimeField( default=(lambda: datetime.now() + relativedelta(days=+1)), verbose_name=_('finish'), help_text=_("date format: YYYY-mm-DD HH:MM:SS")) #Per Day Starting & Stopping Time daily_start_time = models.TimeField(default='00:00:00', verbose_name=_('daily start time'), help_text=_("time format: HH:MM:SS")) daily_stop_time = models.TimeField(default='23:59:59', verbose_name=_('daily stop time'), help_text=_("time format: HH:MM:SS")) monday = models.BooleanField(default=True, verbose_name=_('monday')) tuesday = models.BooleanField(default=True, verbose_name=_('tuesday')) wednesday = models.BooleanField(default=True, verbose_name=_('wednesday')) thursday = models.BooleanField(default=True, verbose_name=_('thursday')) friday = models.BooleanField(default=True, verbose_name=_('friday')) saturday = models.BooleanField(default=True, verbose_name=_('saturday')) sunday = models.BooleanField(default=True, verbose_name=_('sunday')) #Campaign Settings frequency = models.IntegerField(default='10', blank=True, null=True, verbose_name=_('frequency'), help_text=_("calls per minute")) callmaxduration = models.IntegerField( default='1800', blank=True, null=True, verbose_name=_('max call duration'), help_text=_("maximum call duration in seconds")) #max retry on failure - Note that the answered call not completed are counted maxretry = models.IntegerField(default='0', blank=True, null=True, verbose_name=_('max retries'), help_text=_("maximum retries per contact")) intervalretry = models.IntegerField( default='300', blank=True, null=True, verbose_name=_('time between retries'), help_text=_("time delay in seconds before retrying contact")) completion_maxretry = models.IntegerField( default='0', blank=True, null=True, verbose_name=_('completion max retries'), help_text=_("amount of retries until a contact is completed")) completion_intervalretry = models.IntegerField( default='900', blank=True, null=True, verbose_name=_('completion time between retries'), help_text=_( "time delay in seconds before retrying contact for completion")) calltimeout = models.IntegerField( default='45', blank=True, null=True, verbose_name=_('timeout on call'), help_text=_("connection timeout in seconds")) aleg_gateway = models.ForeignKey(Gateway, verbose_name=_("A-Leg gateway"), related_name="A-Leg Gateway", help_text=_("select outbound gateway")) content_type = models.ForeignKey( ContentType, verbose_name=_("type"), limit_choices_to={"model__in": ["survey_template"]}) object_id = models.PositiveIntegerField(verbose_name=_("application")) content_object = generic.GenericForeignKey('content_type', 'object_id') extra_data = models.CharField( max_length=120, blank=True, verbose_name=_("extra parameters"), help_text=_("additional application parameters.")) phonebook = models.ManyToManyField(Phonebook, blank=True, null=True) imported_phonebook = models.CharField(max_length=500, default='', blank=True, verbose_name=_('imported phonebook')) totalcontact = models.IntegerField( default=0, blank=True, null=True, verbose_name=_('total contact'), help_text=_("total contact for this campaign")) completed = models.IntegerField( default=0, blank=True, null=True, verbose_name=_('completed'), help_text=_("total contact that completed call / survey")) #Flags has_been_started = models.BooleanField(default=False, verbose_name=_('has been started')) has_been_duplicated = models.BooleanField( default=False, verbose_name=_('has been duplicated')) dnc = models.ForeignKey(DNC, null=True, blank=True, verbose_name=_("DNC"), help_text=_("do not call list"), related_name='DNC') #Voicemail voicemail = models.BooleanField( default=False, verbose_name=_('enable voicemail detection')) amd_behavior = models.IntegerField(choices=list(AMD_BEHAVIOR), default=AMD_BEHAVIOR.ALWAYS, verbose_name=_("detection behaviour"), blank=True, null=True) voicemail_audiofile = models.ForeignKey( AudioFile, null=True, blank=True, verbose_name=_("voicemail audio file")) created_date = models.DateTimeField(auto_now_add=True, verbose_name=_('date')) updated_date = models.DateTimeField(auto_now=True) objects = CampaignManager() def __unicode__(self): return u"%s" % (self.name) class Meta: permissions = (("view_campaign", _('can see campaign')), ("view_dashboard", _('can see campaign dashboard'))) db_table = u'dialer_campaign' verbose_name = _("campaign") verbose_name_plural = _("campaigns") def update_campaign_status(self): """Update the campaign's status For example, If campaign is active, you can change status to 'Pause' or 'Stop' """ if self.status == CAMPAIGN_STATUS.START: return "<a href='%s'>Pause</a> | <a href='%s'>Abort</a> | <a href='%s'>Stop</a>" % \ (reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.PAUSE]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.ABORT]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.END])) if self.status == CAMPAIGN_STATUS.PAUSE: return "<a href='%s'>Start</a> | <a href='%s'>Abort</a> | <a href='%s'>Stop</a>" % \ (reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.START]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.ABORT]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.END])) if self.status == CAMPAIGN_STATUS.ABORT: return "<a href='%s'>Start</a> | <a href='%s'>Pause</a> | <a href='%s'>Stop</a>" % \ (reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.START]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.PAUSE]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.END])) if self.status == CAMPAIGN_STATUS.END: return "<a href='%s'>Start</a> | <a href='%s'>Pause</a> | <a href='%s'>Abort</a>" % \ (reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.START]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.PAUSE]), reverse('dialer_campaign.views.update_campaign_status_admin', args=[self.pk, CAMPAIGN_STATUS.ABORT])) update_campaign_status.allow_tags = True update_campaign_status.short_description = _('action') def is_authorized_contact(self, dialersetting, str_contact): """Check if a contact is authorized""" return common_contact_authorization(dialersetting, str_contact) def get_campaign_type(self): """Get campaign type""" if self.content_type.name[0:6] == 'Survey': return ugettext('survey') return ugettext('voice app') def get_active_max_frequency(self): """Get the active max frequency""" try: obj_userprofile = self.user.get_profile() except UserProfile.DoesNotExist: return self.frequency max_frequency = obj_userprofile.dialersetting.max_frequency if max_frequency < self.frequency: return max_frequency return self.frequency def get_active_callmaxduration(self): """Get the active call max duration""" try: obj_userprofile = self.user.get_profile() except UserProfile.DoesNotExist: return self.frequency callmaxduration = obj_userprofile.dialersetting.callmaxduration if callmaxduration < self.callmaxduration: return callmaxduration return self.callmaxduration def get_active_contact(self): """Get all the active Contacts from the phonebook""" list_contact =\ Contact.objects.filter(phonebook__campaign=self.id, status=CONTACT_STATUS.ACTIVE).all() if not list_contact: return False return list_contact def progress_bar(self): """Progress bar generated based on no of contacts""" # Cache subscriber_count count_contact = \ Contact.objects.filter(phonebook__campaign=self.id).count() # Cache need to be set per campaign # subscriber_count_key_campaign_id_1 subscriber_count = cache.get('subscriber_count_key_campaign_id_' + str(self.id)) if subscriber_count is None: list_contact = Contact.objects.values_list('id', flat=True)\ .filter(phonebook__campaign=self.id) subscriber_count = 0 try: subscriber_count += Subscriber.objects\ .filter(contact__in=list_contact, campaign=self.id, status=SUBSCRIBER_STATUS.SENT)\ .count() except: pass cache.set("subscriber_count_key_campaign_id_%s" % str(self.id), subscriber_count, 5) subscriber_count = int(subscriber_count) count_contact = int(count_contact) if count_contact > 0: percentage_pixel = \ (float(subscriber_count) / count_contact) * 100 percentage_pixel = int(percentage_pixel) else: percentage_pixel = 0 subscriber_count_string = "subscribers (" + str(subscriber_count) + ")" return "<div title='%s' style='width: 100px; border: 1px solid #ccc;'><div style='height: 4px; width: %dpx; background: #555; '></div></div>" % \ (subscriber_count_string, percentage_pixel) progress_bar.allow_tags = True progress_bar.short_description = _('progress') def subscriber_detail(self): """This will link to subscribers who are associated with the campaign""" model_name = Subscriber._meta.object_name.lower() app_label = self._meta.app_label link = '/admin/%s/%s/' % (app_label, model_name) link += '?campaign__id=%d' % self.id display_link = _("<a href='%(link)s'>%(name)s</a>") % \ {'link': link, 'name': _('details')} return display_link subscriber_detail.allow_tags = True subscriber_detail.short_description = _('subscriber') # OPTIMIZATION - GOOD def get_pending_subscriber_update(self, limit, status): """Get all the pending subscribers from the campaign""" #TODO: Improve this part with a PL/SQL #We cannot use select_related here as it's not compliant with locking the rows list_subscriber = Subscriber.objects.select_for_update()\ .filter(campaign=self.id, status=SUBSCRIBER_STATUS.PENDING)\ .all()[:limit] if not list_subscriber: return (False, 0) id_list_sb = [] count = 0 for elem_subscriber in list_subscriber: count = count + 1 id_list_sb.append(elem_subscriber.id) #Update in bulk Subscriber.objects.filter(id__in=id_list_sb).update(status=status) return (list_subscriber, count)
def __init__(self, user, *args, **kwargs): super(CampaignForm, self).__init__(*args, **kwargs) instance = getattr(self, 'instance', None) self.fields['campaign_code'].initial = get_unique_code(length=5) self.fields['description'].widget.attrs['class'] = "input-xlarge" if user: self.fields['ds_user'].initial = user list_gw = [] list_pb = [] dnc_list = [] list_pb.append((0, '---')) list = Phonebook.objects.values_list('id', 'name')\ .filter(user=user).order_by('id') for l in list: list_pb.append((l[0], l[1])) self.fields['phonebook'].choices = list_pb list = user.get_profile().userprofile_gateway.all() gw_list = ((l.id, l.name) for l in list) dnc_list.append(('', '---')) list = DNC.objects.values_list('id', 'name')\ .filter(user=user).order_by('id') for l in list: dnc_list.append((l[0], l[1])) self.fields['dnc'].choices = dnc_list for i in gw_list: list_gw.append((i[0], i[1])) self.fields['aleg_gateway'].choices = list_gw if instance.has_been_duplicated: from survey.models import Survey available_objects = Survey.objects.filter(user=user, campaign=instance) object_choices = get_object_choices(available_objects) self.fields['content_object'].widget.attrs['readonly'] = True else: from survey.models import Survey_template available_objects = Survey_template.objects.filter(user=user) object_choices = get_object_choices(available_objects) self.fields['content_object'].choices = object_choices # Voicemail setting is not enabled by default if settings.AMD: from survey.forms import get_audiofile_list self.fields[ 'voicemail_audiofile'].choices = get_audiofile_list(user) # if campaign is running if instance.status == CAMPAIGN_STATUS.START: self.fields['name'].widget.attrs['readonly'] = True self.fields['caller_name'].widget.attrs['readonly'] = True self.fields['callerid'].widget.attrs['readonly'] = True self.fields['extra_data'].widget.attrs['readonly'] = True self.fields['phonebook'].widget.attrs['disabled'] = 'disabled' selected_phonebook = '' if instance.phonebook.all(): selected_phonebook = \ ",".join(["%s" % (i.id) for i in instance.phonebook.all()]) self.fields['selected_phonebook'].initial = selected_phonebook self.fields['content_object'].widget.attrs['disabled'] = 'disabled' self.fields['content_object'].required = False self.fields['selected_content_object'].initial = "type:%s-id:%s" \ % (instance.content_type.id, instance.object_id)