Example #1
0
 def _wrapper():
     # need to activate the store's timezone for template rendering!
     timezone.activate(pytz.timezone(store.store_timezone))
     with open(FS_SITE_DIR +\
         "/templates/manage/notification-receipt-monthly-failed.html", 'r') as f:
         template = Template(f.read())
     # variable names are misleading here ><
     date_now = subscription.date_last_billed +\
         relativedelta(days=30)
     #########
     # the 14 day sequence just like passed user limit
     date_disable = date_now + relativedelta(days=14)
     subject = "Repunch Inc. important service notice."
     ctx = get_notification_ctx()
     ctx.update({'store': store, "date_disable":date_disable,
         "date_now":date_now,
         "account_disabled": account_disabled,
         "sub_type":sub_type, "subscription":subscription})
     body = template.render(Context(ctx)).__str__()
             
     email = mail.EmailMultiAlternatives(subject,
                 strip_tags(body), EMAIL_FROM,
                 [account.get('email')])
     email.attach_alternative(body, 'text/html')
         
     _send_emails([email], connection)
Example #2
0
def calculate_daterange(type):
    start = datetime.now()
    end = datetime.now()
    
    #default to today
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    
    if type == 'month-to-date':
        start = start.replace(day=1, hour=0, minute=0, second=0)
    elif type == 'week-to-date':
        # from monday to sunday!
        start = start + relativedelta(days=-1*start.weekday())
    elif type == 'last-week':
        start = start + relativedelta(days=-1*start.weekday() - 7)
        end = start + relativedelta(days=7)
    elif type == 'last-month':
        start = start + relativedelta(days=-1*start.day)
        month_maxday = start.day
        # get first day of the month
        start = start + relativedelta(days=-1*start.day + 1)
        end = start.replace(day=month_maxday,
            hour=23, minute=59, second=59)
    
    return (start, end)
Example #3
0
def _refresh_access_token():
    """
    Must be called after every x seconds. x is acquired from the 
    reponse's expires_in field.
    
    returns a dictionary containing the results.
    """
    url = 'https://' + PAYPAL_ENDPOINT + '/v1/oauth2/token'
    res = StringIO()

    c = pycurl.Curl()
    c.setopt(pycurl.URL, url)
    c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])
    c.setopt(pycurl.HTTPHEADER, ['Accept-Language: en_US'])
    c.setopt(pycurl.USERPWD, PAYPAL_CLIENT_ID + ':' +\
                PAYPAL_CLIENT_SECRET)
    c.setopt(c.WRITEFUNCTION, res.write)
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, 'grant_type=client_credentials')
    # perform automatically returns a value and exits this method
    c.perform()
    res = json.loads(res.getvalue())
    
    global ACCESS_TOKEN, ACCESS_TOKEN_EXPIRES_IN
    # update 
    ACCESS_TOKEN = res['access_token']
    # subtract 5 mins (300 seconds) to be safe
    ACCESS_TOKEN_EXPIRES_IN = timezone.now() +\
                    relativedelta(seconds=res['expires_in']-300)
Example #4
0
    def has_unicodedecodeerror(self, subset):
        """
        we may encounter an infinite loop if a UnicodeDecodeError
        occurs so we check the datetime of the last tag in the
        in the current subset and start fresh if LOGJOB_FAIL has passed
        """
        tags = TAG_RE.findall(subset)
        if len(tags) == 0:
            # This shouldn't happen but just in case
            return True
        
        last_log_tag = tags[-1]
        # get 16:23:32 from "I2013-11-18T16:23:32.026Z]"
        last_log_time = TAG_TIME_RE.search(last_log_tag).group(1)
        hour, minute, second = last_log_time.split(":")
        last_log_time = timezone.now().replace(hour=int(hour),
            minute=int(minute), second=int(second)) +\
            relativedelta(seconds=LOGJOB_FAIL)

        if timezone.now() > last_log_time:
            self.last_log_tag = None
            self.last_log_time = timezone.now()
            self.n = LogJob.START_N
            return True
            
        return False
Example #5
0
def index(request):
    """
    Renders the first 20 most recent pending and approved/denied
    redemptions.
    """
    # do not just use timezone.now(). that will just get the current
    # utc time. We need the local time and then convert it to utc
    today = timezone.make_aware(datetime.now(),
                                SESSION.get_store_timezone(request.session))
    today = today + relativedelta(days=-1)
    today = today.replace(hour=23, minute=59, second=59)  # midnight

    data = {"workbench_nav":True, "settings":\
        SESSION.get_settings(request.session), "today":today}

    redemps = SESSION.get_redemptions_pending(request.session)
    past_redemps = SESSION.get_redemptions_past(request.session)

    # initially display the first 20 pending/history chronologically
    redemps.sort(key=lambda r: r.createdAt, reverse=True)
    past_redemps.sort(key=lambda r: r.updatedAt, reverse=True)

    data['pending_redemptions'] = redemps[:PAGINATION_THRESHOLD]
    data['past_redemptions'] = past_redemps[:PAGINATION_THRESHOLD]

    data["pag_threshold"] = PAGINATION_THRESHOLD
    data["pag_page"] = 1
    data["pending_redemptions_count"] = len(redemps)
    data["history_redemptions_count"] = len(past_redemps)

    return render(request, 'manage/workbench.djhtml', data)
Example #6
0
def index(request):
    """
    Renders the first 20 most recent pending and approved/denied
    redemptions.
    """
    # do not just use timezone.now(). that will just get the current
    # utc time. We need the local time and then convert it to utc
    today = timezone.make_aware(datetime.now(), 
                    SESSION.get_store_timezone(request.session))
    today = today + relativedelta(days=-1)
    today = today.replace(hour=23, minute=59, second=59) # midnight
    
    data = {"workbench_nav":True, "settings":\
        SESSION.get_settings(request.session), "today":today}
    
    redemps = SESSION.get_redemptions_pending(request.session)
    past_redemps = SESSION.get_redemptions_past(request.session)
    
    # initially display the first 20 pending/history chronologically
    redemps.sort(key=lambda r: r.createdAt, reverse=True)
    past_redemps.sort(key=lambda r: r.updatedAt, reverse=True)
    
    data['pending_redemptions'] = redemps[:PAGINATION_THRESHOLD]
    data['past_redemptions'] = past_redemps[:PAGINATION_THRESHOLD]
    
    data["pag_threshold"] = PAGINATION_THRESHOLD
    data["pag_page"] = 1
    data["pending_redemptions_count"] = len(redemps)
    data["history_redemptions_count"] = len(past_redemps)
    
    return render(request, 'manage/workbench.djhtml', data)
Example #7
0
    def has_unicodedecodeerror(self, subset):
        """
        we may encounter an infinite loop if a UnicodeDecodeError
        occurs so we check the datetime of the last tag in the
        in the current subset and start fresh if LOGJOB_FAIL has passed
        """
        tags = TAG_RE.findall(subset)
        if len(tags) == 0:
            # This shouldn't happen but just in case
            return True

        last_log_tag = tags[-1]
        # get 16:23:32 from "I2013-11-18T16:23:32.026Z]"
        last_log_time = TAG_TIME_RE.search(last_log_tag).group(1)
        hour, minute, second = last_log_time.split(":")
        last_log_time = timezone.now().replace(hour=int(hour),
            minute=int(minute), second=int(second)) +\
            relativedelta(seconds=LOGJOB_FAIL)

        if timezone.now() > last_log_time:
            self.last_log_tag = None
            self.last_log_time = timezone.now()
            self.n = LogJob.START_N
            return True

        return False
Example #8
0
def retailer_message(store_id, message_type):
    rand_str = str(randint(0,9999))
    if message_type == "offer":
        print _retailer_message(store_id, "Test Message #"+rand_str,
            "This is a test message", 
            timezone.now() + relativedelta(days=10),
            message_type, "Offer #"+rand_str, None,
            None, sender_name="Test Store")
    
    elif message_type == "basic":
        pass
Example #9
0
 def _wrapper():
     with open(FS_SITE_DIR +\
         "/templates/manage/notification-receipt-monthly.html", 'r') as f:
         template = Template(f.read())
     emails = []
     # for accounts
     for asis in asiss:
         invoice = asis[2]
         if not invoice: # failed to charge user
             continue
         subscription = asis[3]
         account = asis[0]
         store = asis[1]
         timezone.activate(pytz.timezone(store.store_timezone))
         # assumes that subscription's date_last_billed has been 
         # updated prior to this
         # variable names are misleading here ><
         date_30_ago = subscription.date_last_billed +\
             relativedelta(days=-30)
         date_now = subscription.date_last_billed.replace()
         #############
         subject = EMAIL_MONTHLY_SUBJECT
         ctx = get_notification_ctx()
         ctx.update({'store': store, 'invoice': invoice,
             "date_30_ago":date_30_ago, "date_now":date_now,
             "sub_type":sub_type, "subscription":subscription})
         body = template.render(Context(ctx)).__str__()
         timezone.deactivate()
                 
         email = mail.EmailMultiAlternatives(subject,
                     strip_tags(body), EMAIL_FROM,
                     [account.get('email')])
         email.attach_alternative(body, 'text/html')
         emails.append(email)
     # for ORDER_PLACED_EMAILS
     with open(FS_SITE_DIR +\
         "/templates/manage/notification-receipt-monthly-admin.html", 'r') as f:
         template = Template(f.read())
     date = timezone.localtime(timezone.now(),pytz.timezone(TIME_ZONE))
     subject = "Monthly billing results : " + date.strftime("%b %d %Y")
     ctx = get_notification_ctx()
     ctx.update({'asiss': asiss, "date":date, "sub_type":sub_type})
     timezone.activate(pytz.timezone(TIME_ZONE))
     body = template.render(Context(ctx)).__str__()
     timezone.deactivate()
     email = mail.EmailMultiAlternatives(subject,
                 strip_tags(body), EMAIL_FROM,
                 ORDER_PLACED_EMAILS)
     email.attach_alternative(body, 'text/html')
     emails.append(email)
     
     _send_emails(emails, connection)
Example #10
0
 def is_mail_sent(self, value, search_by="SUBJECT"):
     self.select_sent_mailbox()
     mail_ids = self.search(value)
     if len(mail_ids) > 0:
         sent = self.fetch_date(str(mail_ids[-1]))
         now = timezone.now()
         lb = now + relativedelta(seconds=-20)
         # make sure that this is the correct email 
         if now.year == sent.year and now.month == sent.month and\
             now.day == sent.day and now.hour == sent.hour and\
             (sent.minute == now.minute or\
             sent.minute == lb.minute):
             return True
     return False
Example #11
0
def calculate_daterange(type):
    start = datetime.now()
    end = datetime.now()

    #default to today
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)

    if type == 'month-to-date':
        start = start.replace(day=1, hour=0, minute=0, second=0)
    elif type == 'week-to-date':
        # from monday to sunday!
        start = start + relativedelta(days=-1 * start.weekday())
    elif type == 'last-week':
        start = start + relativedelta(days=-1 * start.weekday() - 7)
        end = start + relativedelta(days=7)
    elif type == 'last-month':
        start = start + relativedelta(days=-1 * start.day)
        month_maxday = start.day
        # get first day of the month
        start = start + relativedelta(days=-1 * start.day + 1)
        end = start.replace(day=month_maxday, hour=23, minute=59, second=59)

    return (start, end)
Example #12
0
def retailer_message(store_id, message_type):
    rand_str = str(randint(0, 9999))
    if message_type == "offer":
        print _retailer_message(store_id,
                                "Test Message #" + rand_str,
                                "This is a test message",
                                timezone.now() + relativedelta(days=10),
                                message_type,
                                "Offer #" + rand_str,
                                None,
                                None,
                                sender_name="Test Store")

    elif message_type == "basic":
        pass
Example #13
0
 def _wrapper():
     # need to activate the store's timezone for template rendering!
     timezone.activate(pytz.timezone(store.store_timezone))
     with open(FS_SITE_DIR +\
         "/templates/manage/notification-receipt-monthly.html", 'r') as f:
         template = Template(f.read())
     # assumes that subscription's date_last_billed has been 
     # updated prior to this
     # variable names are misleading here ><
     date_30_ago = subscription.date_last_billed +\
         relativedelta(days=-30)
     date_now = subscription.date_last_billed.replace()
     ##########
     emails = []
     subject = EMAIL_MONTHLY_SUBJECT
     ctx = get_notification_ctx()
     ctx.update({'store': store, 'invoice': invoice,
         "account": account, "subscription":subscription,
         "date_30_ago":date_30_ago, "date_now":date_now,
         "sub_type":sub_type, "subscription":subscription})
     body = template.render(Context(ctx)).__str__()
     timezone.deactivate()
             
     email = mail.EmailMultiAlternatives(subject,
                 strip_tags(body), EMAIL_FROM,
                 [account.get('email')])
     email.attach_alternative(body, 'text/html')
     emails.append(email)
     
     # for ORDER_PLACED_EMAILS
     subject = "Monthly billing payment by " +\
         store.get_owner_fullname() + "."
     timezone.activate(pytz.timezone(TIME_ZONE))
     ctx.update({"for_admin": True})
     body = template.render(Context(ctx)).__str__()
     timezone.deactivate()
     email = mail.EmailMultiAlternatives(subject,
                 strip_tags(body), EMAIL_FROM,
                 ORDER_PLACED_EMAILS)
     email.attach_alternative(body, 'text/html')
     emails.append(email)
     
     _send_emails(emails, connection)
 def handle(self, *args, **options):
     """
     posible values in args:
         - force : terminate ALL sessions - even active ones
     """
     # for logging when ran by CRON
     print "Running clean_comet_session: " + str(timezone.now())
     
     force = "force" in args
 
     now = timezone.now()
     timedout_time = now + relativedelta(hours=\
         -1*LAST_UPDATED_THRESHOLD)
     to_del = []
     
     for cometi in  CometSessionIndex.objects.all():
         if cometi.last_updated < timedout_time or force:
             session = SessionStore(cometi.session_key)
             flush(session)
             to_del.append(cometi)
             # delete associated cometsessions 
             for comet in CometSession.objects.filter(\
                 session_key=cometi.session_key):
                 to_del.append(comet)    
                 if force:
                      comet.modified = True
                      comet.save()
    
     # wait for the threads in the server to detect modified
     if force:
         sleep(COMET_PULL_RATE + 3)
         
     # now actually delete the objects
     for c in to_del:
         c.delete()
         
     # check for dangling cometsessions that did not get terminated
     for comet in CometSession.objects.all():
         # delete if no associated cometsessionindex exists
         cs = CometSession.objects.filter(\
             session_key=comet.session_key)
         for c in cs:
             c.delete()
Example #15
0
    def handle(self, *args, **options):
        """
        posible values in args:
            - force : terminate ALL sessions - even active ones
        """
        # for logging when ran by CRON
        print "Running clean_comet_session: " + str(timezone.now())

        force = "force" in args

        now = timezone.now()
        timedout_time = now + relativedelta(hours=\
            -1*LAST_UPDATED_THRESHOLD)
        to_del = []

        for cometi in CometSessionIndex.objects.all():
            if cometi.last_updated < timedout_time or force:
                session = SessionStore(cometi.session_key)
                flush(session)
                to_del.append(cometi)
                # delete associated cometsessions
                for comet in CometSession.objects.filter(\
                    session_key=cometi.session_key):
                    to_del.append(comet)
                    if force:
                        comet.modified = True
                        comet.save()

        # wait for the threads in the server to detect modified
        if force:
            sleep(COMET_PULL_RATE + 3)

        # now actually delete the objects
        for c in to_del:
            c.delete()

        # check for dangling cometsessions that did not get terminated
        for comet in CometSession.objects.all():
            # delete if no associated cometsessionindex exists
            cs = CometSession.objects.filter(\
                session_key=comet.session_key)
            for c in cs:
                c.delete()
Example #16
0
    def clean_date_offer_expiration(self):
        exp = self.cleaned_data['date_offer_expiration']

        if self.cleaned_data['attach_offer']:
            if exp == None:
                raise forms.ValidationError('Please enter an expiration date.')
            else:
                # make sure the expiration is in the future
                now = timezone.now()
                if now >= exp:
                    raise forms.ValidationError('Please enter an'+\
                        ' expiration date that is later than today.')
                # max is 1 year
                year_later = now + relativedelta(days=365)
                if exp >= year_later:
                    raise forms.ValidationError('Please enter an'+\
                        ' expiration date that is less than a year.')

        else:
            exp = None

        return exp
Example #17
0
 def clean_date_offer_expiration(self):
     exp = self.cleaned_data['date_offer_expiration']
     
     if self.cleaned_data['attach_offer']:
         if exp == None:
             raise forms.ValidationError('Please enter an expiration date.')
         else:
             # make sure the expiration is in the future
             now = timezone.now()
             if now >= exp:
                 raise forms.ValidationError('Please enter an'+\
                     ' expiration date that is later than today.')
             # max is 1 year
             year_later = now + relativedelta(days=365)
             if exp >= year_later:
                 raise forms.ValidationError('Please enter an'+\
                     ' expiration date that is less than a year.')
                 
     else:
         exp = None
             
     return exp
 def create_offer(self):
     offer = Message.objects().create(**{
         'subject': u'test_request_validate_redeem script message offer',
         'body': u'test_request_validate_redeem script generate offer', 
         'sender_name': u'test_request_validate_redeem', 
         'store_id': self.store.objectId, 
         'is_read': False, 
         'offer_redeemed': False, 
         'date_offer_expiration': timezone.now()+relativedelta(days=1), 
         'filter': u'all', 
         'offer_title': u'test_request_validate_redeem script offer', 
         'message_type': 'offer', 
     })
     
     cloud_call("retailer_message", {
         "filter": offer.filter,
         "store_name": self.store.store_name,
         "message_id": offer.objectId,
         "store_id": self.store.objectId,
         "subject": offer.subject,
     })
     
     return offer
Example #19
0
def pull(request):
    """
    This is where the comet approach is put into play.
    This handles ajax requests from clients, holding on to the 
    request while checking Parse for new activity.
    
    IMPORTANT! The order in which the session cache is checked is very
    critical. Take for example and employee that registers.
    Dashboard A receives the pending employee and immediately 
    approves it. Now Dashboard B will run pull with the pending
    employee and the approved employee. We must first add the pending 
    then check for the approved!
    """
    def comet(session_copy):
        # used by more than 1 (note that it is ok to retrieve all of 
        # the lists since they are all pointers - not the actual list!
        employees_pending_list_copy =\
            SESSION.get_employees_pending_list(session_copy)
        employees_approved_list_copy =\
            SESSION.get_employees_approved_list(session_copy)
        messages_received_list_copy =\
            SESSION.get_messages_received_list(session_copy)
        redemptions_pending_copy =\
            SESSION.get_redemptions_pending(session_copy)
        redemptions_past_copy =\
            SESSION.get_redemptions_past(session_copy)
        
        # this is the latest session data
        session = SessionStore(request.session.session_key)
        employees_pending_list =\
            SESSION.get_employees_pending_list(session)
        employees_approved_list =\
            SESSION.get_employees_approved_list(session)
        messages_received_list =\
            SESSION.get_messages_received_list(session)
        redemptions_pending =\
            SESSION.get_redemptions_pending(session)
        redemptions_past =\
            SESSION.get_redemptions_past(session)
        
        # put the diffs between session_copy and session here
        data = {}
        
        #############################################################
        # FEEDBACKS_UNREAD ##################################
        fbs_unread_copy = [ fb.objectId for fb in\
            messages_received_list_copy if not fb.is_read ]
        fbs_unread = [ fb.objectId for fb in\
            messages_received_list if not fb.is_read ]
            
        # get the difference between the two
        feedbacks_unread =\
            tuple(set(fbs_unread) - set(fbs_unread_copy))
        if feedbacks_unread:
            fb_unread = []
            messages_received_ids =\
                [ fb.objectId for fb in messages_received_list ]
            for feedback_id in feedbacks_unread:
                for fb in messages_received_list:
                    if fb.objectId == feedback_id:
                        fb_unread.append(fb.jsonify())
                        break
                
            if len(fb_unread) > 0:
                fb_count = 0
                for fb in messages_received_list:
                    if not fb.get("is_read"):
                        fb_count += 1
                data['feedbacks_unread'] = fb_unread
                data['feedback_unread_count'] = fb_count
          
        #############################################################
        # EMPLOYEES_PENDING ##################################
        # must also check if employee is already approved!
        emps_pending_copy = [ emp.objectId for emp in
            employees_pending_list_copy ]
        emps_pending = [ emp.objectId for emp in
            employees_pending_list ]
            
        employees_pending =\
            tuple(set(emps_pending) - set(emps_pending_copy))
            
        if employees_pending:
            pending = []
            for emp_id in employees_pending:
                for emp in employees_pending_list:
                    if emp.objectId == emp_id:
                        pending.append(emp.jsonify())
                        break
                    
            if len(pending) > 0:   
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_pending'] = pending
        
        #############################################################
        # EMPLOYEES APPROVED (pending to approved) #################
        emps_approved_copy = [ emp.objectId for emp in\
            employees_approved_list_copy]
        emps_approved = [ emp.objectId for emp in\
            employees_approved_list]
            
        appr_emps =\
            tuple(set(emps_approved) - set(emps_approved_copy))
        
        if appr_emps:
            approved = []
            for appr_emp_id in appr_emps:
                for emp in employees_approved_list:
                    if emp.objectId == appr_emp_id:
                        approved.append(emp.jsonify())
                        break
                        
            if len(approved) > 0:
                data['employees_approved'] = approved
                data['employees_pending_count'] =\
                    len(employees_pending_list)
            
        #############################################################
        # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)!
        # need to compare approved and pending!
        emps_copy = emps_approved_copy[:]
        emps_copy.extend(emps_pending_copy)
        emps = emps_approved[:]
        emps.extend(emps_pending)
        
        # emps_copy has the same or more items that emps
        del_emps = tuple(set(emps_copy) - set(emps))
        
        if del_emps:
            deleted = []
            for demp_id in del_emps:
                if demp_id in emps_approved_copy:
                    emps_list = employees_approved_list_copy
                else:
                    emps_list = employees_pending_list_copy
                    
                for emp in emps_list:
                    if emp.objectId == demp_id:
                        deleted.append(emp.jsonify())
                        break  
                        
            if len(deleted) > 0:   
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_deleted'] = deleted
           
        #############################################################
        # REDEMPTIONS PENDING
        reds_pending_copy = [ r.objectId for r in\
            redemptions_pending_copy ]
        reds_pending = [ r.objectId for r in redemptions_pending ]
        
        reds = tuple(set(reds_pending) - set(reds_pending_copy))
        
        if reds:
            redemps = []
            for r_id in reds:
                for redemp in redemptions_pending:
                    if redemp.objectId == r_id:
                        redemps.append(redemp.jsonify())
                        break
                        
            if len(redemps) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_pending'] = redemps
                
        #############################################################
        # REDEMPTIONS APPROVED (pending to history)
        reds_past_copy = [ r.objectId for r in\
            redemptions_past_copy ]
        reds_past = [ r.objectId for r in redemptions_past ]
        
        appr_redemps =\
            tuple(set(reds_past) - set(reds_past_copy))
            
        if appr_redemps:   
            redemp_js = []
            for red_id in appr_redemps:
                for redemp in redemptions_past:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break
            
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_approved'] = redemp_js
            
        #############################################################
        # REDEMPTIONS DELETED ##############################
        # remove from pending (should not be in history!)
        reds_copy = reds_past_copy[:]
        reds_copy.extend(reds_pending_copy)
        reds = reds_past[:]
        reds.extend(reds_pending)
        
        # reds_copy has the same or more items that reds
        del_redemps = tuple(set(reds_copy) - set(reds))
        if del_redemps:
            redemp_js = []
            for red_id in del_redemps:
                reds_list = []
                if red_id in reds_past_copy:
                    reds_list = redemptions_past_copy
                elif red_id in reds_pending_copy:
                    reds_list = redemptions_pending_copy
                    
                for redemp in reds_list:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break               
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_deleted'] = redemp_js
            
        #############################################################
        # SETTINGS UPDATED ##############################
        settings_copy = session_copy.get("settings")
        settings = session.get("settings")
        if settings_copy.get("retailer_pin") !=\
            settings.get("retailer_pin"):
            data['retailer_pin'] = settings.get("retailer_pin")
        
        #############################################################
        # REWARDS UPDATED ##############################
        rewards_copy = session_copy.get("store").get("rewards")
        rewards_copy =\
            { reward['reward_id']:reward for reward in rewards_copy }
            
        rewards = session.get("store").get("rewards")
        rewards = { reward['reward_id']:reward for reward in rewards }
        updated_rewards = []
        
        for reward_id, rew_copy in rewards_copy.iteritems():
            # Note that some rewards may have been deleted!
            rew = rewards.get(reward_id)
            if rew and rew_copy['redemption_count'] !=\
                rew['redemption_count']:
                # only the redemtpion_count and reward_id are used
                # in the client side
                updated_rewards.append({
                    "reward_id": reward_id,
                    "redemption_count": rew['redemption_count'],
                })
        
        if updated_rewards:
            data['rewards'] = updated_rewards
           
        #############################################################
        # PATRONSTORE_COUNT ##################################
        patronStore_count_copy =int(session_copy["patronStore_count"])
        patronStore_count = int(session["patronStore_count"])
        if patronStore_count_copy != patronStore_count:
            data['patronStore_count'] = patronStore_count
            
            
        #############################################################
        # ACTIVE_STORE_LOCATION_ID ############################
        if session['active_store_location_id'] !=\
            session_copy['active_store_location_id']:
            data['active_store_location_id'] =\
                session['active_store_location_id']
            

        # IMPORTANT! The request.session is the same as the 
        # SessionStore(session_key)! so we must use the 
        # request.session because it is automatically saved at the end
        # of each request- thereby overriding/undoing any changes made
        # to the SessionStore(session_key) key!
        # need to check if we are still logged in
        session = SessionStore(request.session.session_key)
        if 'account' in session and SESSION_KEY in session:
            request.session.clear()
            request.session.update(session)
        else:
            flush(request.session)
        
        ############################################################
        # Respond ###########################################
        try: 
            return HttpResponse(json.dumps(data), 
                        content_type="application/json")
        except (IOError, socket.error) as e: # broken pipe/socket. 
            thread.exit() # exit silently
            
            
    ##################################################################
    ##### ENTRY POINT
    ######################################################
    # get the timestamp and uid
    t = parser.parse(request.GET["timestamp"])
    timestamp = str(t.hour).zfill(2) + ":" +\
        str(t.minute).zfill(2) + ":" + str(t.second).zfill(2)
    uid = request.GET['uid']
    
    # update the last_updated field of the CometSessionIndex
    try:
        csi = CometSessionIndex.objects.get(session_key=\
            request.session.session_key)
        csi.last_updated = timezone.now()
        csi.save()
    except CometSessionIndex.DoesNotExist:
        # should never go here but just in case.
        CometSessionIndex.objects.create(session_key=\
            request.session.session_key, 
            store_id=SESSION.get_store(request.session).objectId,
            last_updated=timezone.now())
        
        
    # register the CometSession
    CometSession.objects.update()
    CometSession.objects.create(session_key=\
        request.session.session_key, timestamp=timestamp, uid=uid)
    
    # cache the current session at this state
    session_copy = dict(request.session)
    timeout_time = timezone.now() + relativedelta(seconds=REQUEST_TIMEOUT)
    
    # keep going until its time to return a response forcibly
    while timezone.now() < timeout_time:  
        # need to update he objects manager to get the latest objects
        CometSession.objects.update() 
        try:     
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
        except CometSession.DoesNotExist:
            # cometsession was deleted - time to go
            try:
                # make sure that the latest session is saved!
                # need to check if we are still logged in
                session = SessionStore(request.session.session_key)
                if 'account' in session and SESSION_KEY in session:
                    request.session.clear()
                    request.session.update(session)
                else:
                    flush(request.session)
                return HttpResponse(json.dumps({"result":-1}), 
                            content_type="application/json")
            except (IOError, socket.error) as e: 
                thread.exit() 
                
        if scomet.modified:
            # delete the registered comet session object
            CometSession.objects.update()
            try:
                scomet = CometSession.objects.get(session_key=\
                    request.session.session_key,
                    timestamp=timestamp, uid=uid)
                scomet.delete()
            except CometSession.DoesNotExist:
                pass # do nothing
            try:
                return comet(session_copy)
            except KeyError:
                # if a key error occurs then that probably means that
                # the session has been flushed- was logged out by user
                # or forcefully by server =)
                # now time to flag existing tabs.
                request.session.clear()
                try: 
                    return HttpResponse(json.dumps({"result": -3}), 
                                content_type="application/json")
                except (IOError, socket.error) as e: # broken pipe/socket. 
                    thread.exit() # exit silently
        else: # nothing new, sleep for a bit
            sleep(COMET_PULL_RATE)
            
            
    # TIME IS UP - return a response result 0 means no change 
    # try 1 last time
    if scomet.modified:
        # delete the registered comet session object
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
            scomet.delete()
        except CometSession.DoesNotExist:
            pass # do nothing
        return comet(session_copy)
            
    # make sure that request.session is the most up to date
    session = SessionStore(request.session.session_key)
    # need to check if we are still logged in
    if 'account' in session and SESSION_KEY in session:
        request.session.clear()
        request.session.update(session)
    else:
        flush(request.session)
    
    # attempt to delete registered comet session if not yet deleted
    try:
        scomet = CometSession.objects.get(session_key=\
            request.session.session_key,
            timestamp=timestamp, uid=uid)
        scomet.delete()
    except CometSession.DoesNotExist:
        pass # do nothing
    
    try:
        return HttpResponse(json.dumps({"result":0}), 
                        content_type="application/json")
    except (IOError, socket.error) as e:
        thread.exit() # exit silently
Example #20
0
def get_page(request):
    """
    Returns a generated html to plug in the tables.
    """
    if request.method == "GET":
        type = request.GET.get("type")
        page = int(request.GET.get("page")) - 1
        if type == "pending-redemptions":
            template = "manage/redemptions_pending_chunk.djhtml" 
            pending_redemps =\
                SESSION.get_redemptions_pending(request.session)
            # sort
            header_map = {
                "redemption_time":"createdAt", # IMPORTANT DIFF!
                "redemption_customer_name": "customer_name",
                "redemption_title": "title",
                "redemption_punches": "num_punches",
            }
            header = request.GET.get("header")
            if header: # header can only be date
                reverse = request.GET.get("order") == "desc"
                pending_redemps.sort(key=lambda r:\
                    r.__dict__[header_map[header]], reverse=reverse)
            
            # set the chunk
            start = page * PAGINATION_THRESHOLD
            end = start + PAGINATION_THRESHOLD
            data = {"pending_redemptions":pending_redemps[start:end]}
            
            request.session["redemptions_pending"] = pending_redemps
            
        elif type == "history-redemptions":
            template = "manage/redemptions_history_chunk.djhtml"
            past_redemps =\
                SESSION.get_redemptions_past(request.session)
            # sort
            header_map = {
                "redemption_time-past":"updatedAt", # IMPORTANT DIFF!
                "redemption_customer_name-past": "customer_name",
                "redemption_title-past": "title",
                "redemption_punches-past": "num_punches", 
            }
            header = request.GET.get("header")
            if header:
                reverse = request.GET.get("order") == "desc"
                past_redemps.sort(key=lambda r:\
                    r.__dict__[header_map[header]], reverse=reverse)
                    
            request.session["redemptions_past"] = past_redemps
            # set the chunk
            start = page * PAGINATION_THRESHOLD 
            end = start + PAGINATION_THRESHOLD
            data = {"past_redemptions":past_redemps[start:end]}
       
        # don't forget the today for comparison!
        today = timezone.make_aware(datetime.now(), 
                    SESSION.get_store_timezone(request.session))
        today = today + relativedelta(days=-1)
        today = today.replace(hour=23, minute=59, second=59)
        
        data["today"] = today
        return render(request, template, data)
        
    return HttpResponse("Bad request")
Example #21
0
    def handle(self, *args, **options):
        # for logging when ran by CRON
        print "Running detect_suspicious_activity: " + str(timezone.now())

        # first count the number of active stores
        store_count = Store.objects().count(active=True)
        # store_count = Store.objects().count(objectId="o72LmDy0YK")

        end = timezone.now()
        start = end + relativedelta(hours=-24)
        conn = mail.get_connection(fail_silently=(not DEBUG))
        conn.open()

        # to send to the admins
        admin_chunks = []

        # get 500 stores at a time
        LIMIT, skip = 500, 0
        while store_count > 0:
            for store in Store.objects().filter(active=True,
                                                include="store_locations",
                                                limit=LIMIT,
                                                skip=skip,
                                                order="createdAt"):
                # for store in Store.objects().filter(\
                #     objectId="o72LmDy0YK", include="store_locations"):

                ### CHUNK1 ####################################
                chunk1, account_patron, patron_punch = {}, {}, {}
                total_punches = []

                # check approved EMPLOYEES
                employees = store.get("employees", status=APPROVED, limit=900)
                employee_punches = []

                def add_to_patron_punch(punch, employee=None):
                    if punch.Patron not in patron_punch:
                        patron_punch[punch.Patron] =\
                            [{"punch":punch, "employee": employee}]
                    else:
                        patron_punch[punch.Patron].append({"punch":\
                            punch, "employee":employee})

                def get_location(location_id):
                    for loc in store.store_locations:
                        if loc.objectId == location_id:
                            return loc

                if employees and len(employees) > 0:
                    # check all the punches of each employee
                    for employee in employees:
                        # get all the punches for today
                        punches = employee.get("punches",
                                               limit=900,
                                               createdAt__lte=end,
                                               createdAt__gte=start)
                        if not punches:
                            continue

                        # for querying the dashboard punches
                        employee_punches.extend([p.objectId for p in\
                            punches])

                        # group the punches by patron
                        for punch in punches:
                            add_to_patron_punch(punch, employee)

                # now check DASHBOARD
                punches = store.get("punches",
                                    limit=900,
                                    createdAt__lte=end,
                                    createdAt__gte=start,
                                    objectId__nin=employee_punches)

                # group the punches by patron
                if punches:
                    for punch in punches:
                        add_to_patron_punch(punch, None)

                # check for a group with a list >= 6
                for key, val in patron_punch.iteritems():
                    suspicious_punches = []
                    if val and len(val) >= 6:
                        for punch in val:
                            suspicious_punches.append({
                                "store_location":\
                                    get_location(punch["punch"].store_location_id),
                                "punch": punch["punch"],
                                "employee": punch["employee"]
                            })

                        # cache the account and patron
                        if key not in account_patron:
                            acc = Account.objects().get(Patron=key,
                                                        include="Patron")
                            account_patron[key] = {
                                "account": acc,
                                "patron": acc.patron,
                            }

                        if key not in chunk1:
                            chunk1[key] = {
                                "account":\
                                   account_patron[key]['account'],
                                "patron":\
                                   account_patron[key]['patron'],
                                "punches": suspicious_punches
                            }
                        else:
                            chunk1[key]['punches'].extend(suspicious_punches)

                ### CHUNK2 ####################################
                # hours per location
                # punches are still grouped per patron
                chunk2 = {}
                for loc in store.store_locations:
                    if loc.hours and len(loc.hours) > 0 and\
                        loc.hours[0]['day'] != 0: # 24/7
                        # check for punches out of hours
                        tz = pytz.timezone(loc.store_timezone)
                        start = timezone.localtime(start, tz)
                        end = timezone.localtime(end, tz)
                        # isoweekday is from 1-7 monday to sunday
                        # convert to 1-7 sunday to saturday
                        day1_weekday = (start.isoweekday()) % 7 + 1
                        day2_weekday = (end.isoweekday()) % 7 + 1

                        # get the hours for day1 and day2
                        def get_hours_range(weekday, d):
                            for hr in loc.hours:
                                if hr["day"] == weekday:
                                    hr_start_hour =\
                                        int(hr["open_time"][:2])
                                    hr_start_minute =\
                                        int(hr["open_time"][2:])
                                    hr_end_hour =\
                                        int(hr["close_time"][:2])
                                    hr_end_minute =\
                                        int(hr["close_time"][2:])
                                    return d.replace(hour=hr_start_hour,
                                        minute=hr_start_minute),\
                                        d.replace(hour=hr_end_hour,
                                        minute=hr_end_minute)
                            return None, None

                        (hours1_start, hours1_end) =\
                            get_hours_range(day1_weekday, start)
                        (hours2_start, hours2_end) =\
                            get_hours_range(day2_weekday, end)

                        # now convert to utc since punch times are in utc
                        if hours1_start:
                            hours1_start =\
                                timezone.localtime(hours1_start, tzutc())
                            hours1_end =\
                                timezone.localtime(hours1_end, tzutc())
                        if hours2_start:
                            hours2_start =\
                                timezone.localtime(hours2_start, tzutc())
                            hours2_end =\
                                timezone.localtime(hours2_end, tzutc())

                        for key, val in patron_punch.iteritems():
                            if not val:
                                continue

                            suspicious_punches = []

                            # process only those punches that are in this location
                            for p in [
                                    x for x in val
                                    if x["punch"].store_location_id ==
                                    loc.objectId
                            ]:
                                punch = p["punch"]
                                # suspicious if not in hours1 and 2
                                if not (hours1_start and\
                                    punch.createdAt>hours1_start and\
                                    punch.createdAt<hours1_end) and\
                                    not (hours2_start and\
                                    punch.createdAt>hours2_start and\
                                    punch.createdAt<hours2_end):
                                    # not in hours1 or 2 so suspicious!
                                    suspicious_punches.append({
                                        "store_location":
                                        loc,
                                        "punch":
                                        punch,
                                        "employee":
                                        p["employee"],
                                    })

                            if len(suspicious_punches) == 0:
                                continue

                            # cache the account and patron
                            if key not in account_patron:
                                acc = Account.objects().get(Patron=key,
                                                            include="Patron")
                                account_patron[key] = {
                                    "account": acc,
                                    "patron": acc.patron,
                                }

                            if key not in chunk2:
                                chunk2[key] = {
                                    "account":\
                                       account_patron[key]['account'],
                                    "patron":\
                                       account_patron[key]['patron'],
                                    "punches": suspicious_punches
                                }
                            else:
                                chunk2[key]['punches'].extend(
                                    suspicious_punches)

                # all tasks are done for this store - send email
                if len(chunk1) > 0 or len(chunk2) > 0:
                    store_acc = Account.objects().get(Store=store.objectId)
                    admin_chunks.append({
                        "store_acc": store_acc,
                        "store": store,
                        "data": (chunk1, chunk2),
                    })

                    try:
                        send_email_suspicious_activity(store_acc, store,
                                                       chunk1, chunk2, conn)
                    except SMTPServerDisconnected:
                        conn = mail.get_connection(fail_silently=(not DEBUG))
                        conn.open()
                        send_email_suspicious_activity(store_acc, store,
                                                       chunk1, chunk2, conn)

            # end of while loop
            store_count -= LIMIT
            skip += LIMIT

        if len(admin_chunks) > 0:
            send_email_suspicious_activity_admin(admin_chunks, start, end,
                                                 conn)

        # everything is done. close the connection
        try:
            conn.close()
        except Exception:
            pass
Example #22
0
def edit(request, message_id):
    """
    Render the message edit template for a new message and handles
    send message forms.
    """
    data = {'messages_nav': True, 'message_id': message_id, "filters": FILTERS}

    store = SESSION.get_store(request.session)
    # number of patron stores
    mp = SESSION.get_patronStore_count(request.session)
    # make sure cache attr is None for future queries!
    store.patronStores = None

    data['mp_slider_value'] = int(ceil(float(mp) * 0.50))
    data['mp_slider_min'] = 1
    data['mp_slider_max'] = mp

    # redirect if no patrons
    if not store.get("patronStores", count=1, limit=0):
        return redirect(reverse("messages_index"))

    # user submitted a form by form submission through POST request
    # or user is coming from an upgrade sequence from subscription_update
    if request.method == 'POST' or (request.method == "GET" and\
        request.GET.get("send_message") and "message_b4_upgrade" in\
        request.session):

        if request.method == "GET":
            # user is coming from an upgrade sequence from subscription_update
            postDict = request.session['message_b4_upgrade'].copy()
            # cleanup temp vars in session
            del request.session['message_b4_upgrade']
            del request.session['from_limit_reached']

        else:
            # user submitted a form by form submission through POST request
            postDict = request.POST.dict().copy()

        # populate a message form with the POST data for validation
        form = MessageForm(postDict)

        if form.is_valid():
            # form is valid so continue to send the message
            subscription = SESSION.get_subscription(request.session)
            subType = subscription.get('subscriptionType')

            # refresh the message count - make sure we get the one in the cloud
            if 'message_count' in request.session:
                del request.session['message_count']
            message_count = SESSION.get_message_count(request.session)

            # get the max_messages from the user's subscriptionType
            # or the highest level if god_mode is on
            if subscription.god_mode:
                max_messages = sub_type[2]['max_messages']
            else:
                max_messages = sub_type[subType]['max_messages']

            # limit is reached if the amount of messages sent this
            # billing cycle passed the amount for that subscription type
            limit_reached = message_count >= max_messages

            # We always enforce the limit when we are in production
            # otherwise, we ignore it if we have message_limit_off in our session
            if limit_reached and (PRODUCTION_SERVER or\
                (not PRODUCTION_SERVER and "message_limit_off" not in request.session)):

                data['limit_reached'] = limit_reached

                # not the highest level of subscription so an upgrade
                # is still possible
                if subType != 2:
                    # save the dict to the session
                    request.session['message_b4_upgrade'] =\
                        request.POST.dict().copy()

                # the highest level of subscription so no more
                # upgrades can occur - therefore maxed_out
                elif subType == 2:
                    data['maxed_out'] = True

            else:
                # limit has not yet been reached - send the message
                # build the message from session and POST data
                message = Message(\
                    sender_name=store.get('store_name'),
                    store_id=store.objectId
                )
                message.update_locally(postDict, False)

                # check if attach offer is selected
                if 'attach_offer' in postDict:
                    # message has an offer - extract it from the post
                    # post data ensuring proper datetime format
                    d = parser.parse(postDict['date_offer_expiration'])
                    d = make_aware_to_utc(
                        d, SESSION.get_store_timezone(request.session))
                    message.set('date_offer_expiration', d)
                    message.set('message_type', OFFER)

                else:
                    # make sure to delete offer information in the case
                    # that attach offer is not checked but the form
                    # submitted still contained offer information
                    message.set('offer_title', None)
                    message.set('date_offer_expiration', None)
                    message.set('message_type', BASIC)

                # actually create the message to Parse
                message.create()

                # put the message in the template context for rendering
                data['message'] = message
                # add to the store's relation
                store.add_relation("SentMessages_", [message.objectId])

                # prepare the parameters for the cloud call
                params = {
                    "store_id": store.objectId,
                    "store_name": store.get('store_name'),
                    "subject": message.get('subject'),
                    "message_id": message.objectId,
                    "filter": message.filter,
                }

                # process the filter option
                if message.filter == "idle":
                    # pass in the correct idle_date which is today
                    # minus the days specified by idle_latency
                    idle_days = postDict['idle_latency']
                    d = timezone.now() + relativedelta(days=\
                        -1*int(idle_days))
                    params.update({"idle_date": d.isoformat()})

                elif message.filter == "most_loyal":
                    # pass in the number of patrons
                    params.update({"num_patrons": postDict['num_patrons']})

                # update store and message_count in session cache
                request.session['message_count'] = message_count
                request.session['store'] = store
                # save session- cloud_call may take a while!
                request.session.save()

                # make the cloud call
                res = cloud_call("retailer_message", params)
                if "error" not in res and res.get("result"):
                    message.set("receiver_count",
                                res.get("result").get("receiver_count"))

                # notify other tabs and windows that are logged into
                # this store about the new message sent.
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "newMessage": message.jsonify()
                }
                comet_receive(store.objectId, payload)

                # Note that the new message is saved in comet_receive
                # make sure we have the latest session to save!
                request.session.clear()
                request.session.update(
                    SessionStore(request.session.session_key))

                return HttpResponseRedirect(message.get_absolute_url())

        elif 'num_patrons' in form.errors:
            # form is invalid due to the number of patrons input
            # for most_loyal filter
            data['error'] = "Number of customers must be a "+\
                                "whole number and greater than 0."

        else:
            # form has some errors
            data['error'] = "The form you submitted has errors."

    else:
        # check if the incoming request is for an account upgrade
        if request.GET.get("do_upgrade"):
            # flag the upgrade view
            request.session["from_limit_reached"] = True
            # redirect to upgrade account
            return HttpResponseRedirect(reverse("subscription_update") +\
                "?do_upgrade=1")

        if message_id in (0, '0'):
            # this is a new message so just instantiate a new form
            form = MessageForm()

        else:
            # this is an existing message that the user wants to view

            # inserting this success and error message into the template
            # should be done in a cleaner way - this was done by the
            # first guy. I just didn't bother changing it.
            if request.GET.get("error"):
                data['error'] = request.GET.get("error")
            if request.GET.get("success"):
                data['success'] = request.GET.get("success")

            # get from the messages_sent_list in session cache
            messages_sent_list = SESSION.get_messages_sent_list(\
                request.session)
            for m in messages_sent_list:
                if m.objectId == message_id:
                    data['message'] = m

            if data['message']:
                # message is found so fill up the form with its data
                form = MessageForm(data['message'].__dict__.copy())

            else:
                # message not found so just instantiate a new form
                form = MessageForm()

    # update store session cache
    request.session['store'] = store

    # inject the form in the template context for rendering
    data['form'] = form

    return render(request, 'manage/message_edit.djhtml', data)
Example #23
0
def update_subscription(request):
    """
    This view is also used for explicit upgrades.
    """
    do_upgrade = request.GET.get("do_upgrade") is not None

    if do_upgrade:
        data = {'account_nav': True, 'upgrade': True}
    else:
        data = {'account_nav': True, 'update': True}

    store = SESSION.get_store(request.session)
    subscription = SESSION.get_subscription(request.session)

    if request.method == 'POST':
        form = SubscriptionForm(request.POST)
        form.subscription = subscription  # to validate cc_number
        all_forms_valid = form.is_valid()

        if all_forms_valid:
            # upgrade account if date_passed_user_limit is on
            # should fetch the most up-to-date subscription first
            subscription = Subscription.objects().get(objectId=\
                subscription.objectId)
            upgraded = False
            if subscription.date_passed_user_limit or do_upgrade:
                level = subscription.get("subscriptionType")
                if level == 0:
                    subscription.set("subscriptionType", 1)
                    subscription.date_passed_user_limit = None
                    upgraded = True
                elif level == 1:
                    subscription.date_passed_user_limit = None
                    subscription.set("subscriptionType", 2)
                    upgraded = True

            # subscription.update() called in store_cc
            subscription.update_locally(request.POST.dict(), False)

            d = datetime(int(request.POST['date_cc_expiration_year']),
                         int(request.POST['date_cc_expiration_month']), 1)
            subscription.set(
                "date_cc_expiration",
                make_aware_to_utc(d,
                                  SESSION.get_store_timezone(request.session)))

            def invalid_card():
                # add some asterisk to cc_number
                if form.initial.get("cc_number"):
                    form.initial['cc_number'] = "*" * 12 +\
                        form.initial.get('cc_number')[-4:]
                errs = form._errors.setdefault(\
                    "cc_number", ErrorList())
                errs.append("Invalid credit " +\
                    "card. Please make sure that you provide " +\
                    "correct credit card information and that you " +\
                    "have sufficient funds, then try again.")
                data['form'] = form
                return render(request, 'manage/subscription_update.djhtml',
                              data)

            res = True
            # only store_cc if it is a digit (new)
            if str(form.data['cc_number']).isdigit():
                res = subscription.store_cc(form.data['cc_number'],
                                            form.data['cc_cvv'], False)
            if not res:
                return invalid_card()

            # if monthly billing failed
            if subscription.date_charge_failed:
                sub_cost = sub_type[subscription.get(\
                            "subscriptionType")]["monthly_cost"]
                invoice = subscription.charge_cc(\
                        sub_cost, EMAIL_MONTHLY_SUBJECT, MONTHLY)
                if invoice:
                    subscription.date_last_billed =\
                        subscription.date_last_billed +\
                        relativedelta(days=30)
                    subscription.date_charge_failed = None
                    subscription.update()
                    send_email_receipt_monthly_success(\
                        request.session['account'],
                        store, subscription, invoice)
                else:
                    return invalid_card()
            ###########

            if upgraded:
                max_users = sub_type[\
                        subscription.subscriptionType]["max_users"]
                if max_users == UNLIMITED:
                    max_users = "Unlimited"
                package = {
                    "sub_type": sub_type[\
                        subscription.subscriptionType-1]["name"],
                    "new_sub_type": sub_type[\
                        subscription.subscriptionType]["name"],
                    "new_sub_type_cost": sub_type[\
                        subscription.subscriptionType]["monthly_cost"],
                    "new_max_patronStore_count": max_users,
                }
                send_email_account_upgrade(request.session['account'], store,
                                           package)

            # Important that this is last since invalid_card may be
            # returned!
            subscription.update()

            # update the session cache
            request.session['store'] = store
            request.session['subscription'] = subscription

            # notify other dashboards of these changes
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSubscription": subscription.jsonify()
            }
            comet_receive(store.objectId, payload)

            # if coming from the message edit limit reached
            if do_upgrade:
                if request.session.get('from_limit_reached') and\
                    request.session.get('message_b4_upgrade'):
                    # redirect back to message_edit view to process
                    return redirect(reverse('message_edit',
                            args=(0,)) + "?%s" %\
                            urllib.urlencode({'send_message': '1'}))

            if do_upgrade:
                return redirect(reverse('store_index')+ "?%s" %\
                        urllib.urlencode({'success':\
                            'Your subscription has been upgraded.'}))
            else:
                return redirect(reverse('store_index')+ "?%s" %\
                            urllib.urlencode({'success':\
                                'Your subscription has been updated.'}))
    else:
        form = SubscriptionForm()
        form.initial = subscription.__dict__.copy()
        # add some asterisk to cc_number
        if form.initial.get("cc_number"):
            form.initial['cc_number'] = "*" * 12 +\
                form.initial.get('cc_number')[-4:]

        if do_upgrade:
            from_limit_reached =\
                request.session.get("from_limit_reached")
            if from_limit_reached:
                data['from_limit_reached'] = from_limit_reached

    # update the session cache
    request.session['store'] = store
    request.session['subscription'] = subscription

    data['form'] = form
    return render(request, 'manage/subscription_update.djhtml', data)
Example #24
0
def test_messages():
    # TODO test that patrons are getting the messages!!!
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    # set subscriptionType to free
    subscription.subscriptionType = 0
    subscription.update()

    # clear the sent messages relation
    sent_messages = store.get("sentMessages", keys="")
    if sent_messages:
        store.remove_relation("SentMessages_",
            [m.objectId for m in sent_messages])
            
    store.set("sentMessages", None)
            
    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        
        # FIRST
        {'test_name': "Send message. Filter all. No offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SECOND
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # THIRD    
        {'test_name': "Send message. Filter idle. No offer. " +\
            "Message limit passed (free) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the " +\
            "message and upgrades the account to middle"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FOURTH
        {'test_name': "Send message. Filter idle. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FIFTH
        {'test_name': "Send message. Filter most_loyal. No offer. " +\
            "Message limit passed (middle) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the" +\
            " message and upgrades the account to heavy"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SIXTH
        {'test_name': "Send message. Filter most_loyal. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SEVENTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # EIGHTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # NINTH
        {'test_name': "Send message. Filter all. No offer. " +\
            "Message limit passed (heavy) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Account can no longer be upgraded." +\
            "Message cannot be sent. Clicking okay redirects "+\
            "user to messages index."},
        #
            
        {'test_name': "Subject is required"},
        {'test_name': "Body is required"},
        {'test_name': "Offer title not required if attach offer off"},
        {'test_name': "Expiration not required if attach offer off"},
        {'test_name': "Offer title is required if attach offer on"},
        {'test_name': "Expiration date required if attach offer on"},
        {'test_name': "Expiration date must be at a later date"},
        {'test_name': "Expiration date must be at most 1 year later"},
    ]
    section = {
        "section_name": "Sending messages works?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(5) 
    
    def send_message(filter, subject, body,
            attach_offer=False, offer_title=None, exp_date=None,):
        """ Must be called at messages index page """
        test.find("#create_message").click()
        sleep(1)
        # set the filter
        test.find("//select[@id='filter']/option[@value='%s']" %\
            (filter,), type="xpath").click()
        # subject
        test.find("#id_subject").send_keys(subject)
        # body
        test.find("#id_body").send_keys(body)
        # attach_offer
        if attach_offer:
            test.find("#id_attach_offer").click()
            # offer title
            if offer_title:
                test.find("#id_offer_title").send_keys(offer_title)
            # exp_date
            if exp_date:
                test.find("#id_date_offer_expiration").send_keys(exp_date)
            
        # submit
        test.find("#send-now").click()
        sleep(5)
        
    def message_in_relation(message_id, test_number):
        if not message_id:
            return
            
        store.sentMessages = None
        parts[test_number]['success'] = store.get("sentMessages", 
            objectId=message_id, count=1, limit=0) == 1
            
    def message_in_page(message_id, test_number):
        if not message_id:
            return
            
        try:
            rows = test.find("#tab-body-sent div.tr a", multiple=True)
            for row in rows:
                if row.get_attribute("href").split("/")[5] ==\
                    message_id:
                    parts[test_number]['success'] = True
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        
    def message_viewable(message_id, test_number):
        if not message_id:
            return
        href = reverse("message_details", args=(message_id,))
        try:
            test.find("#tab-body-sent div.tr a[href='%s']" %\
                (href,)).click()
            sleep(2)
            parts[test_number]['success'] = test.is_current_url(href)
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        finally:
            # must go back to messages index for the other tests
            test.open(reverse("messages_index"))
                
    # FIRST
    ##########  Send message. Filter all. No offer. 
    message_id = None
    try:
        send_message("all", "msg #1", "body #1")
        parts[1]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
        
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 2)
    ##########  Message is visible in page. 
    message_in_page(message_id, 3)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 4)

    # SECOND
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #2", "body #2", True, "offer#2",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[5]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 6)
    ##########  Message is visible in page. 
    message_in_page(message_id, 7)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 8) 
        
    # THIRD
    ##########  Send message. Filter idle. No offer. 
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("idle", "msg #3", "body #3")
        parts[9]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the 
    ###         message and upgrades the account to middle.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[10]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 1
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
        
    # open the mail connection
    if SeleniumTest.CHECK_SENT_MAIL:
        mail = Mail()
        ##########  Email is sent notifying user the upgrade.
        try:
            parts[11]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[11]['test_message'] = str(e)
    else:
        parts[11]['success'] = parts[10]['success']
        
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 12)
    ##########  Message is visible in page. 
    message_in_page(message_id, 13)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 14) 

    # FOURTH
    ##########  Send message. Filter idle. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("idle", "msg #4", "body #4", True, "offer#4",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[15]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 16)
    ##########  Message is visible in page. 
    message_in_page(message_id, 17)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 18) 
        
    # FIFTH
    ##########  Send message. Filter most_loyal. No offer. 
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("most_loyal", "msg #5", "body #5")
        parts[19]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the 
    ###         message and upgrades the account to heavy.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[20]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 2
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Email is sent notifying user the upgrade.
    if SeleniumTest.CHECK_SENT_MAIL:
        try:
            parts[21]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[21]['test_message'] = str(e)
    else:
        parts[21]['success'] = parts[20]['success']
            
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 22)
    ##########  Message is visible in page. 
    message_in_page(message_id, 23)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 24) 

    # SIXTH
    ##########  Send message. Filter most_loyal. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("most_loyal", "msg #6", "body #6",
            True, "offer#6", exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[25]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 26)
    ##########  Message is visible in page. 
    message_in_page(message_id, 27)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 28) 

    # SEVENTH
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #7", "body #7", True, "offer#7",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[29]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 30)
    ##########  Message is visible in page. 
    message_in_page(message_id, 31)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 32) 

    # EIGHTH
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #8", "body #8", True, "offer#8",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[33]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 34)
    ##########  Message is visible in page. 
    message_in_page(message_id, 35)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 36) 

    # NINTH
    ##########  Send message. Filter all. With offer. 
    ###         Message limit passed (heavy) dialog appears. 
    message_id = None
    try:
        send_message("all", "msg #9", "body #9")
        parts[37]['success'] = test.element_exists("#maxed_out")
    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Account can no longer be upgraded. Msg cannot be sent.
    ###         Clicking Okay redirects user to messages index.
    try:
        test.find("#maxed_out").click()
        sleep(1)
        parts[38]['success'] =\
            test.is_current_url(reverse("messages_index"))
    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # 
    
    # goto edit message page
    test.find("#create_message").click()
    sleep(2)
        
    selectors = (
        ("#id_subject", "   "),
        ("#id_body", "   "),
    )
    test.action_chain(0, selectors, action="send_keys")
    test.find("#send-now").click()
    sleep(1)
    ##########  Subject is required.
    try:
        parts[39]['success'] = test.find("#subject_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[39]['test_message']= str(e)
    ##########  Body is required. 
    try:
        parts[40]['success'] = test.find("#body_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    ##########  Offer title not required if attach offer off. 
    try:
        parts[41]['success'] = not test.element_exists(\
            "#offer_title_e ul li")
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)
    ##########  Expiration not required if attach offer off. 
    try:
        parts[42]['success'] = not test.element_exists(\
            "#date_offer_expiration_e ul li")
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)
        
    test.find("#id_attach_offer").click()
    test.find("#send-now").click()
    sleep(1)
    ##########  Offer title is required if attach offer on. 
    try:
        parts[43]['success'] =\
            test.find("#offer_title_e ul li").text ==\
            "Please enter a title."
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)
    ##########  Expiration date required if attach offer on. 
    try:
        parts[44]['success'] =\
            test.find("#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date."
    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)
        
    ##########  Expiration date must be at a later date. 
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=-1)
        test.find("#id_date_offer_expiration").send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(1)
        parts[45]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is later than today."
    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)
    
    ##########  Expiration date must be at most 1 year later. 
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=367)
        date_offer = test.find("#id_date_offer_expiration")
        date_offer.clear()
        date_offer.send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(2)
        parts[46]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is less than a year."
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)
    
    
    # END OF ALL TESTS - cleanup
    if SeleniumTest.CHECK_SENT_MAIL:
        mail.logout()
        
    return test.tear_down() 
Example #25
0
def __temp__001__():
    import datetime
    d = datetime.datetime.now()
    from libs.dateutil.relativedelta import relativedelta
    d = d + relativedelta(hour=8)
Example #26
0
 def handle(self, *args, **options):
     # for logging when ran by CRON
     print "Running passed_user_limit: " + str(timezone.now())
     
     now = timezone.now()
     b4_now = now + relativedelta(hours=-1)
     
     # get 500 subscriptions at a time
     LIMIT = 500
     
     # first scan though all the stores and set their
     # date_passed_user_limit if so
     # TODO optimize with a relational query? possible with Parse?
     #### SUB_TYPE 0
     skip = 0
     sub_count = Subscription.objects().count(\
         date_passed_user_limit=None, subscriptionType=0)
     max_users = sub_type[0]['max_users']
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit=None, god_mode=False,
             limit=LIMIT, skip=skip, order="createdAt"):
             store = sub.store
             if store.get("patronStores", count=1, limit=0) >\
                 max_users:
                 sub.date_passed_user_limit = b4_now
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
     # TODO optimize with a relational query? possible with Parse?
     #### SUB_TYPE 1
     skip = 0
     sub_count = Subscription.objects().count(\
         date_passed_user_limit=None, subscriptionType=1)
     max_users = sub_type[1]['max_users']
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit=None, god_mode=False,
             limit=LIMIT, skip=skip, order="createdAt"):
             store = sub.store
             if store.get("patronStores", count=1, limit=0) >\
                 max_users:
                 sub.date_passed_user_limit = b4_now
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
     
     ################
     conn = mail.get_connection(fail_silently=(not DEBUG))
     conn.open()
     # 1st day time range
     day1_end = now.replace()
     day1_start = day1_end + relativedelta(hours=-24)
     # 4th day time range
     day4_end = now + relativedelta(days=-4)
     day4_start = day4_end + relativedelta(hours=-24)
     # 8th day time range
     day8_end = now + relativedelta(days=-8)
     day8_start = day8_end + relativedelta(hours=-24)
     # 14th day time range
     day14_end = now + relativedelta(days=-14)
     day14_start = day14_end + relativedelta(hours=-24)
     
     
     #### SUB_TYPE 0
     ## 1st day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day1_end,
         date_passed_user_limit__gte=day1_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day1_end,
             date_passed_user_limit__gte=day1_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             # with pp_cc_id
             if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                 sub.subscriptionType = 1
                 sub.date_passed_user_limit = None
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 package = {
                     "status": "upgraded",
                     "sub_type": sub_type[0]["name"],
                     "new_sub_type": sub_type[1]["name"],
                     "new_sub_type_cost": sub_type[1]["monthly_cost"],
                     "new_max_patronStore_count":\
                         sub_type[1]["max_users"], 
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                 }
                     
             # no pp_cc_id
             else:
                 package = {
                     "sub_type": sub_type[0]["name"],
                     "max_patronStore_count": sub_type[0]["max_users"],
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                     "disable_date": sub.date_passed_user_limit + 
                         relativedelta(days=\
                             USER_LIMIT_PASSED_DISABLE_DAYS),
                 }
                 
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
   
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
     
     ## 4th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day4_end,
         date_passed_user_limit__gte=day4_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day4_end,
             date_passed_user_limit__gte=day4_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[0]["name"],
                 "max_patronStore_count": sub_type[0]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
                 
     ## 8th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day8_end,
         date_passed_user_limit__gte=day8_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day8_end,
             date_passed_user_limit__gte=day8_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[0]["name"],
                 "max_patronStore_count": sub_type[0]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
         
             
     ## 14th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day14_end,
         date_passed_user_limit__gte=day14_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day14_end,
             date_passed_user_limit__gte=day14_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = { "status": "disabled" }
             
             # deactivate the store
             sub.store.active = False
             sub.store.update()
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedStore":sub.store.jsonify(),
             }
             comet_receive(sub.Store, payload)
             
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
     
     
     #### SUB_TYPE 1
     ## 1st day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day1_end,
         date_passed_user_limit__gte=day1_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day1_end,
             date_passed_user_limit__gte=day1_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             # with pp_cc_id
             if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                 sub.subscriptionType = 2
                 sub.date_passed_user_limit = None
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 package = {
                     "status": "upgraded",
                     "sub_type": sub_type[1]["name"],
                     "new_sub_type": sub_type[2]["name"],
                     "new_sub_type_cost": sub_type[2]["monthly_cost"],
                     "new_max_patronStore_count": "Unlimited",
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                 }
                 
             # no pp_cc_id
             else:
                 package = {
                     "sub_type": sub_type[1]["name"],
                     "max_patronStore_count": sub_type[1]["max_users"],
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                     "disable_date": sub.date_passed_user_limit + 
                         relativedelta(days=\
                             USER_LIMIT_PASSED_DISABLE_DAYS),
                 }
                 
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
     
     ## 4th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day4_end,
         date_passed_user_limit__gte=day4_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day4_end,
             date_passed_user_limit__gte=day4_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[1]["name"],
                 "max_patronStore_count": sub_type[1]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
         
         
     ## 8th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day8_end,
         date_passed_user_limit__gte=day8_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day8_end,
             date_passed_user_limit__gte=day8_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[1]["name"],
                 "max_patronStore_count": sub_type[1]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
          
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT         
          
     ## 14th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day14_end,
         date_passed_user_limit__gte=day14_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day14_end,
             date_passed_user_limit__gte=day14_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = { "status": "disabled" }
             
             # deactivate the store
             sub.store.active = False
             sub.store.update()
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedStore":sub.store.jsonify(),
             }
             comet_receive(sub.Store, payload)
             
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT       
     
     try:
         conn.close()
     except Exception:
         pass
Example #27
0
def breakdown_graph(request, data_type=None, filter=None, range=None):
    """
    handles requests for the breakdown graph.
    """
    store = SESSION.get_store(request.session)
    store_timezone = SESSION.get_store_timezone(request.session)
    (start, end) = rputils.calculate_daterange(range)
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    # need to make aware and then convert to utc for querying
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)

    results = []
    if data_type == 'punches':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])

            # WARNING! max punches returned is 1000!
            unknown, male, female = 0, 0, 0
            male_punches = relational_query(store.objectId, "Store", "Punches",
                                            "Punch", "Patron", "Patron",
                                            {"gender": "male"}, {
                                                'createdAt__lte': end_aware,
                                                'createdAt__gte': start_aware
                                            })
            female_punches = relational_query(store.objectId, "Store",
                                              "Punches", "Punch", "Patron",
                                              "Patron", {"gender": "female"}, {
                                                  'createdAt__lte': end_aware,
                                                  'createdAt__gte': start_aware
                                              })

            if male_punches:
                male_punches = male_punches['results']
                # aggregate the punches
                for p in male_punches:
                    male += p.get('punches')

            if female_punches:
                female_punches = female_punches['results']
                for p in female_punches:
                    female += p.get('punches')

            rows = [start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    unknown, male, female]
            results.append(rows)

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                punches = relational_query(
                    store.objectId, "Store", "Punches", "Punch", "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    })
                punch_count = 0
                if punches:
                    punches = punches['results']
                    for punch in punches:
                        punch_count += punch['punches']
                rows[idx] = punch_count
            results.append(rows)

    elif data_type == 'facebook':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0,
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost",
                        "Patron", "Patron",
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost",
                        "Patron", "Patron",
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
            ])

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                rows[idx] = relational_query(
                    store.objectId,
                    "Store",
                    "FacebookPosts",
                    "FacebookPost",
                    "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    },
                    count=True)

            results.append(rows)

    else:  # patrons
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0,
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore",
                        "Patron", "Patron",
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore",
                        "Patron", "Patron",
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
            ])

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                rows[idx] = relational_query(
                    store.objectId,
                    "Store",
                    "PatronStores",
                    "PatronStore",
                    "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    },
                    count=True)
            results.append(rows)

    return HttpResponse(json.dumps(results), content_type="application/json")
Example #28
0
def pull(request):
    """
    This is where the comet approach is put into play.
    This handles ajax requests from clients, holding on to the 
    request while checking Parse for new activity.
    
    IMPORTANT! The order in which the session cache is checked is very
    critical. Take for example and employee that registers.
    Dashboard A receives the pending employee and immediately 
    approves it. Now Dashboard B will run pull with the pending
    employee and the approved employee. We must first add the pending 
    then check for the approved!
    """
    def comet(session_copy):
        # used by more than 1 (note that it is ok to retrieve all of
        # the lists since they are all pointers - not the actual list!
        employees_pending_list_copy =\
            SESSION.get_employees_pending_list(session_copy)
        employees_approved_list_copy =\
            SESSION.get_employees_approved_list(session_copy)
        messages_received_list_copy =\
            SESSION.get_messages_received_list(session_copy)
        redemptions_pending_copy =\
            SESSION.get_redemptions_pending(session_copy)
        redemptions_past_copy =\
            SESSION.get_redemptions_past(session_copy)

        # this is the latest session data
        session = SessionStore(request.session.session_key)
        employees_pending_list =\
            SESSION.get_employees_pending_list(session)
        employees_approved_list =\
            SESSION.get_employees_approved_list(session)
        messages_received_list =\
            SESSION.get_messages_received_list(session)
        redemptions_pending =\
            SESSION.get_redemptions_pending(session)
        redemptions_past =\
            SESSION.get_redemptions_past(session)

        # put the diffs between session_copy and session here
        data = {}

        #############################################################
        # FEEDBACKS_UNREAD ##################################
        fbs_unread_copy = [ fb.objectId for fb in\
            messages_received_list_copy if not fb.is_read ]
        fbs_unread = [ fb.objectId for fb in\
            messages_received_list if not fb.is_read ]

        # get the difference between the two
        feedbacks_unread =\
            tuple(set(fbs_unread) - set(fbs_unread_copy))
        if feedbacks_unread:
            fb_unread = []
            messages_received_ids =\
                [ fb.objectId for fb in messages_received_list ]
            for feedback_id in feedbacks_unread:
                for fb in messages_received_list:
                    if fb.objectId == feedback_id:
                        fb_unread.append(fb.jsonify())
                        break

            if len(fb_unread) > 0:
                fb_count = 0
                for fb in messages_received_list:
                    if not fb.get("is_read"):
                        fb_count += 1
                data['feedbacks_unread'] = fb_unread
                data['feedback_unread_count'] = fb_count

        #############################################################
        # EMPLOYEES_PENDING ##################################
        # must also check if employee is already approved!
        emps_pending_copy = [
            emp.objectId for emp in employees_pending_list_copy
        ]
        emps_pending = [emp.objectId for emp in employees_pending_list]

        employees_pending =\
            tuple(set(emps_pending) - set(emps_pending_copy))

        if employees_pending:
            pending = []
            for emp_id in employees_pending:
                for emp in employees_pending_list:
                    if emp.objectId == emp_id:
                        pending.append(emp.jsonify())
                        break

            if len(pending) > 0:
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_pending'] = pending

        #############################################################
        # EMPLOYEES APPROVED (pending to approved) #################
        emps_approved_copy = [ emp.objectId for emp in\
            employees_approved_list_copy]
        emps_approved = [ emp.objectId for emp in\
            employees_approved_list]

        appr_emps =\
            tuple(set(emps_approved) - set(emps_approved_copy))

        if appr_emps:
            approved = []
            for appr_emp_id in appr_emps:
                for emp in employees_approved_list:
                    if emp.objectId == appr_emp_id:
                        approved.append(emp.jsonify())
                        break

            if len(approved) > 0:
                data['employees_approved'] = approved
                data['employees_pending_count'] =\
                    len(employees_pending_list)

        #############################################################
        # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)!
        # need to compare approved and pending!
        emps_copy = emps_approved_copy[:]
        emps_copy.extend(emps_pending_copy)
        emps = emps_approved[:]
        emps.extend(emps_pending)

        # emps_copy has the same or more items that emps
        del_emps = tuple(set(emps_copy) - set(emps))

        if del_emps:
            deleted = []
            for demp_id in del_emps:
                if demp_id in emps_approved_copy:
                    emps_list = employees_approved_list_copy
                else:
                    emps_list = employees_pending_list_copy

                for emp in emps_list:
                    if emp.objectId == demp_id:
                        deleted.append(emp.jsonify())
                        break

            if len(deleted) > 0:
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_deleted'] = deleted

        #############################################################
        # REDEMPTIONS PENDING
        reds_pending_copy = [ r.objectId for r in\
            redemptions_pending_copy ]
        reds_pending = [r.objectId for r in redemptions_pending]

        reds = tuple(set(reds_pending) - set(reds_pending_copy))

        if reds:
            redemps = []
            for r_id in reds:
                for redemp in redemptions_pending:
                    if redemp.objectId == r_id:
                        redemps.append(redemp.jsonify())
                        break

            if len(redemps) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_pending'] = redemps

        #############################################################
        # REDEMPTIONS APPROVED (pending to history)
        reds_past_copy = [ r.objectId for r in\
            redemptions_past_copy ]
        reds_past = [r.objectId for r in redemptions_past]

        appr_redemps =\
            tuple(set(reds_past) - set(reds_past_copy))

        if appr_redemps:
            redemp_js = []
            for red_id in appr_redemps:
                for redemp in redemptions_past:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break

            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_approved'] = redemp_js

        #############################################################
        # REDEMPTIONS DELETED ##############################
        # remove from pending (should not be in history!)
        reds_copy = reds_past_copy[:]
        reds_copy.extend(reds_pending_copy)
        reds = reds_past[:]
        reds.extend(reds_pending)

        # reds_copy has the same or more items that reds
        del_redemps = tuple(set(reds_copy) - set(reds))
        if del_redemps:
            redemp_js = []
            for red_id in del_redemps:
                reds_list = []
                if red_id in reds_past_copy:
                    reds_list = redemptions_past_copy
                elif red_id in reds_pending_copy:
                    reds_list = redemptions_pending_copy

                for redemp in reds_list:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_deleted'] = redemp_js

        #############################################################
        # SETTINGS UPDATED ##############################
        settings_copy = session_copy.get("settings")
        settings = session.get("settings")
        if settings_copy.get("retailer_pin") !=\
            settings.get("retailer_pin"):
            data['retailer_pin'] = settings.get("retailer_pin")

        #############################################################
        # REWARDS UPDATED ##############################
        rewards_copy = session_copy.get("store").get("rewards")
        rewards_copy =\
            { reward['reward_id']:reward for reward in rewards_copy }

        rewards = session.get("store").get("rewards")
        rewards = {reward['reward_id']: reward for reward in rewards}
        updated_rewards = []

        for reward_id, rew_copy in rewards_copy.iteritems():
            # Note that some rewards may have been deleted!
            rew = rewards.get(reward_id)
            if rew and rew_copy['redemption_count'] !=\
                rew['redemption_count']:
                # only the redemtpion_count and reward_id are used
                # in the client side
                updated_rewards.append({
                    "reward_id":
                    reward_id,
                    "redemption_count":
                    rew['redemption_count'],
                })

        if updated_rewards:
            data['rewards'] = updated_rewards

        #############################################################
        # PATRONSTORE_COUNT ##################################
        patronStore_count_copy = int(session_copy["patronStore_count"])
        patronStore_count = int(session["patronStore_count"])
        if patronStore_count_copy != patronStore_count:
            data['patronStore_count'] = patronStore_count

        #############################################################
        # ACTIVE_STORE_LOCATION_ID ############################
        if session['active_store_location_id'] !=\
            session_copy['active_store_location_id']:
            data['active_store_location_id'] =\
                session['active_store_location_id']

        # IMPORTANT! The request.session is the same as the
        # SessionStore(session_key)! so we must use the
        # request.session because it is automatically saved at the end
        # of each request- thereby overriding/undoing any changes made
        # to the SessionStore(session_key) key!
        # need to check if we are still logged in
        session = SessionStore(request.session.session_key)
        if 'account' in session and SESSION_KEY in session:
            request.session.clear()
            request.session.update(session)
        else:
            flush(request.session)

        ############################################################
        # Respond ###########################################
        try:
            return HttpResponse(json.dumps(data),
                                content_type="application/json")
        except (IOError, socket.error) as e:  # broken pipe/socket.
            thread.exit()  # exit silently

    ##################################################################
    ##### ENTRY POINT
    ######################################################
    # get the timestamp and uid
    t = parser.parse(request.GET["timestamp"])
    timestamp = str(t.hour).zfill(2) + ":" +\
        str(t.minute).zfill(2) + ":" + str(t.second).zfill(2)
    uid = request.GET['uid']

    # update the last_updated field of the CometSessionIndex
    try:
        csi = CometSessionIndex.objects.get(session_key=\
            request.session.session_key)
        csi.last_updated = timezone.now()
        csi.save()
    except CometSessionIndex.DoesNotExist:
        # should never go here but just in case.
        CometSessionIndex.objects.create(session_key=\
            request.session.session_key,
            store_id=SESSION.get_store(request.session).objectId,
            last_updated=timezone.now())

    # register the CometSession
    CometSession.objects.update()
    CometSession.objects.create(session_key=\
        request.session.session_key, timestamp=timestamp, uid=uid)

    # cache the current session at this state
    session_copy = dict(request.session)
    timeout_time = timezone.now() + relativedelta(seconds=REQUEST_TIMEOUT)

    # keep going until its time to return a response forcibly
    while timezone.now() < timeout_time:
        # need to update he objects manager to get the latest objects
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
        except CometSession.DoesNotExist:
            # cometsession was deleted - time to go
            try:
                # make sure that the latest session is saved!
                # need to check if we are still logged in
                session = SessionStore(request.session.session_key)
                if 'account' in session and SESSION_KEY in session:
                    request.session.clear()
                    request.session.update(session)
                else:
                    flush(request.session)
                return HttpResponse(json.dumps({"result": -1}),
                                    content_type="application/json")
            except (IOError, socket.error) as e:
                thread.exit()

        if scomet.modified:
            # delete the registered comet session object
            CometSession.objects.update()
            try:
                scomet = CometSession.objects.get(session_key=\
                    request.session.session_key,
                    timestamp=timestamp, uid=uid)
                scomet.delete()
            except CometSession.DoesNotExist:
                pass  # do nothing
            try:
                return comet(session_copy)
            except KeyError:
                # if a key error occurs then that probably means that
                # the session has been flushed- was logged out by user
                # or forcefully by server =)
                # now time to flag existing tabs.
                request.session.clear()
                try:
                    return HttpResponse(json.dumps({"result": -3}),
                                        content_type="application/json")
                except (IOError, socket.error) as e:  # broken pipe/socket.
                    thread.exit()  # exit silently
        else:  # nothing new, sleep for a bit
            sleep(COMET_PULL_RATE)

    # TIME IS UP - return a response result 0 means no change
    # try 1 last time
    if scomet.modified:
        # delete the registered comet session object
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
            scomet.delete()
        except CometSession.DoesNotExist:
            pass  # do nothing
        return comet(session_copy)

    # make sure that request.session is the most up to date
    session = SessionStore(request.session.session_key)
    # need to check if we are still logged in
    if 'account' in session and SESSION_KEY in session:
        request.session.clear()
        request.session.update(session)
    else:
        flush(request.session)

    # attempt to delete registered comet session if not yet deleted
    try:
        scomet = CometSession.objects.get(session_key=\
            request.session.session_key,
            timestamp=timestamp, uid=uid)
        scomet.delete()
    except CometSession.DoesNotExist:
        pass  # do nothing

    try:
        return HttpResponse(json.dumps({"result": 0}),
                            content_type="application/json")
    except (IOError, socket.error) as e:
        thread.exit()  # exit silently
Example #29
0
def get_page(request):
    """
    Returns a generated html to plug in the tables.
    """
    if request.method == "GET":
        type = request.GET.get("type")
        page = int(request.GET.get("page")) - 1
        if type == "pending-redemptions":
            template = "manage/redemptions_pending_chunk.djhtml"
            pending_redemps =\
                SESSION.get_redemptions_pending(request.session)
            # sort
            header_map = {
                "redemption_time": "createdAt",  # IMPORTANT DIFF!
                "redemption_customer_name": "customer_name",
                "redemption_title": "title",
                "redemption_punches": "num_punches",
            }
            header = request.GET.get("header")
            if header:  # header can only be date
                reverse = request.GET.get("order") == "desc"
                pending_redemps.sort(key=lambda r:\
                    r.__dict__[header_map[header]], reverse=reverse)

            # set the chunk
            start = page * PAGINATION_THRESHOLD
            end = start + PAGINATION_THRESHOLD
            data = {"pending_redemptions": pending_redemps[start:end]}

            request.session["redemptions_pending"] = pending_redemps

        elif type == "history-redemptions":
            template = "manage/redemptions_history_chunk.djhtml"
            past_redemps =\
                SESSION.get_redemptions_past(request.session)
            # sort
            header_map = {
                "redemption_time-past": "updatedAt",  # IMPORTANT DIFF!
                "redemption_customer_name-past": "customer_name",
                "redemption_title-past": "title",
                "redemption_punches-past": "num_punches",
            }
            header = request.GET.get("header")
            if header:
                reverse = request.GET.get("order") == "desc"
                past_redemps.sort(key=lambda r:\
                    r.__dict__[header_map[header]], reverse=reverse)

            request.session["redemptions_past"] = past_redemps
            # set the chunk
            start = page * PAGINATION_THRESHOLD
            end = start + PAGINATION_THRESHOLD
            data = {"past_redemptions": past_redemps[start:end]}

        # don't forget the today for comparison!
        today = timezone.make_aware(
            datetime.now(), SESSION.get_store_timezone(request.session))
        today = today + relativedelta(days=-1)
        today = today.replace(hour=23, minute=59, second=59)

        data["today"] = today
        return render(request, template, data)

    return HttpResponse("Bad request")
Example #30
0
    def handle(self, *args, **options):
        # for logging when ran by CRON
        print "Running passed_user_limit: " + str(timezone.now())

        now = timezone.now()
        b4_now = now + relativedelta(hours=-1)

        # get 500 subscriptions at a time
        LIMIT = 500

        # first scan though all the stores and set their
        # date_passed_user_limit if so
        # TODO optimize with a relational query? possible with Parse?
        #### SUB_TYPE 0
        skip = 0
        sub_count = Subscription.objects().count(\
            date_passed_user_limit=None, subscriptionType=0)
        max_users = sub_type[0]['max_users']
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit=None, god_mode=False,
                limit=LIMIT, skip=skip, order="createdAt"):
                store = sub.store
                if store.get("patronStores", count=1, limit=0) >\
                    max_users:
                    sub.date_passed_user_limit = b4_now
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        # TODO optimize with a relational query? possible with Parse?
        #### SUB_TYPE 1
        skip = 0
        sub_count = Subscription.objects().count(\
            date_passed_user_limit=None, subscriptionType=1)
        max_users = sub_type[1]['max_users']
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit=None, god_mode=False,
                limit=LIMIT, skip=skip, order="createdAt"):
                store = sub.store
                if store.get("patronStores", count=1, limit=0) >\
                    max_users:
                    sub.date_passed_user_limit = b4_now
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ################
        conn = mail.get_connection(fail_silently=(not DEBUG))
        conn.open()
        # 1st day time range
        day1_end = now.replace()
        day1_start = day1_end + relativedelta(hours=-24)
        # 4th day time range
        day4_end = now + relativedelta(days=-4)
        day4_start = day4_end + relativedelta(hours=-24)
        # 8th day time range
        day8_end = now + relativedelta(days=-8)
        day8_start = day8_end + relativedelta(hours=-24)
        # 14th day time range
        day14_end = now + relativedelta(days=-14)
        day14_start = day14_end + relativedelta(hours=-24)

        #### SUB_TYPE 0
        ## 1st day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day1_end,
            date_passed_user_limit__gte=day1_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day1_end,
                date_passed_user_limit__gte=day1_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                # with pp_cc_id
                if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                    sub.subscriptionType = 1
                    sub.date_passed_user_limit = None
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)
                    package = {
                        "status": "upgraded",
                        "sub_type": sub_type[0]["name"],
                        "new_sub_type": sub_type[1]["name"],
                        "new_sub_type_cost": sub_type[1]["monthly_cost"],
                        "new_max_patronStore_count":\
                            sub_type[1]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                    }

                # no pp_cc_id
                else:
                    package = {
                        "sub_type": sub_type[0]["name"],
                        "max_patronStore_count": sub_type[0]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                        "disable_date": sub.date_passed_user_limit +
                            relativedelta(days=\
                                USER_LIMIT_PASSED_DISABLE_DAYS),
                    }

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 4th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day4_end,
            date_passed_user_limit__gte=day4_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day4_end,
                date_passed_user_limit__gte=day4_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[0]["name"],
                    "max_patronStore_count": sub_type[0]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 8th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day8_end,
            date_passed_user_limit__gte=day8_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day8_end,
                date_passed_user_limit__gte=day8_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[0]["name"],
                    "max_patronStore_count": sub_type[0]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 14th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day14_end,
            date_passed_user_limit__gte=day14_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day14_end,
                date_passed_user_limit__gte=day14_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {"status": "disabled"}

                # deactivate the store
                sub.store.active = False
                sub.store.update()
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": sub.store.jsonify(),
                }
                comet_receive(sub.Store, payload)

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        #### SUB_TYPE 1
        ## 1st day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day1_end,
            date_passed_user_limit__gte=day1_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day1_end,
                date_passed_user_limit__gte=day1_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                # with pp_cc_id
                if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                    sub.subscriptionType = 2
                    sub.date_passed_user_limit = None
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)
                    package = {
                        "status": "upgraded",
                        "sub_type": sub_type[1]["name"],
                        "new_sub_type": sub_type[2]["name"],
                        "new_sub_type_cost": sub_type[2]["monthly_cost"],
                        "new_max_patronStore_count": "Unlimited",
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                    }

                # no pp_cc_id
                else:
                    package = {
                        "sub_type": sub_type[1]["name"],
                        "max_patronStore_count": sub_type[1]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                        "disable_date": sub.date_passed_user_limit +
                            relativedelta(days=\
                                USER_LIMIT_PASSED_DISABLE_DAYS),
                    }

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 4th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day4_end,
            date_passed_user_limit__gte=day4_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day4_end,
                date_passed_user_limit__gte=day4_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[1]["name"],
                    "max_patronStore_count": sub_type[1]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 8th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day8_end,
            date_passed_user_limit__gte=day8_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day8_end,
                date_passed_user_limit__gte=day8_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[1]["name"],
                    "max_patronStore_count": sub_type[1]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 14th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day14_end,
            date_passed_user_limit__gte=day14_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day14_end,
                date_passed_user_limit__gte=day14_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {"status": "disabled"}

                # deactivate the store
                sub.store.active = False
                sub.store.update()
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": sub.store.jsonify(),
                }
                comet_receive(sub.Store, payload)

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        try:
            conn.close()
        except Exception:
            pass
Example #31
0
def breakdown_graph(request, data_type=None, filter=None, range=None):
    """
    handles requests for the breakdown graph.
    """
    store = SESSION.get_store(request.session)
    store_timezone = SESSION.get_store_timezone(request.session)
    (start, end) = rputils.calculate_daterange(range)
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    # need to make aware and then convert to utc for querying
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)
    
    results = [] 
    if data_type == 'punches':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            
            # WARNING! max punches returned is 1000!
            unknown, male, female = 0, 0, 0 
            male_punches = relational_query(store.objectId, "Store",
                "Punches", "Punch", "Patron", "Patron", 
                {"gender": "male"}, {'createdAt__lte':end_aware,
                    'createdAt__gte':start_aware})
            female_punches = relational_query(store.objectId, "Store",
                "Punches", "Punch", "Patron", "Patron", 
                {"gender": "female"}, {'createdAt__lte':end_aware,
                    'createdAt__gte':start_aware})
                    
            if male_punches:
                male_punches = male_punches['results']
                # aggregate the punches
                for p in male_punches:
                    male += p.get('punches')
            
            if female_punches:
                female_punches = female_punches['results']
                for p in female_punches:
                    female += p.get('punches')

            rows = [start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    unknown, male, female]
            results.append(rows)
        
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
           
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                punches = relational_query(store.objectId, "Store",
                    "Punches", "Punch", "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware})
                punch_count = 0
                if punches: 
                    punches = punches['results']
                    for punch in punches:
                        punch_count += punch['punches']
                rows[idx] = punch_count
            results.append(rows)
            
    elif data_type == 'facebook':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0, 
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost", 
                        "Patron", "Patron", 
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost", 
                        "Patron", "Patron", 
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
            ])
        
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
           
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                                        
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                rows[idx] = relational_query(store.objectId, "Store",
                    "FacebookPosts", "FacebookPost", 
                    "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware}, count=True)
                    
            results.append(rows)
            
    else: # patrons
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0, 
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore", 
                        "Patron", "Patron", 
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore", 
                        "Patron", "Patron", 
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
            ])
            
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
            
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                                        
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                rows[idx] = relational_query(store.objectId, "Store",
                    "PatronStores", "PatronStore", 
                    "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware}, count=True)
            results.append(rows)
        
    return HttpResponse(json.dumps(results), content_type="application/json")
Example #32
0
def test_messages():
    # TODO test that patrons are getting the messages!!!
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    # set subscriptionType to free
    subscription.subscriptionType = 0
    subscription.update()

    # clear the sent messages relation
    sent_messages = store.get("sentMessages", keys="")
    if sent_messages:
        store.remove_relation("SentMessages_",
                              [m.objectId for m in sent_messages])

    store.set("sentMessages", None)

    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},

        # FIRST
        {'test_name': "Send message. Filter all. No offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SECOND
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # THIRD
        {'test_name': "Send message. Filter idle. No offer. " +\
            "Message limit passed (free) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the " +\
            "message and upgrades the account to middle"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FOURTH
        {'test_name': "Send message. Filter idle. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FIFTH
        {'test_name': "Send message. Filter most_loyal. No offer. " +\
            "Message limit passed (middle) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the" +\
            " message and upgrades the account to heavy"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SIXTH
        {'test_name': "Send message. Filter most_loyal. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SEVENTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # EIGHTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # NINTH
        {'test_name': "Send message. Filter all. No offer. " +\
            "Message limit passed (heavy) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Account can no longer be upgraded." +\
            "Message cannot be sent. Clicking okay redirects "+\
            "user to messages index."},
        #

        {'test_name': "Subject is required"},
        {'test_name': "Body is required"},
        {'test_name': "Offer title not required if attach offer off"},
        {'test_name': "Expiration not required if attach offer off"},
        {'test_name': "Offer title is required if attach offer on"},
        {'test_name': "Expiration date required if attach offer on"},
        {'test_name': "Expiration date must be at a later date"},
        {'test_name': "Expiration date must be at most 1 year later"},
    ]
    section = {
        "section_name": "Sending messages works?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(5)

    def send_message(
        filter,
        subject,
        body,
        attach_offer=False,
        offer_title=None,
        exp_date=None,
    ):
        """ Must be called at messages index page """
        test.find("#create_message").click()
        sleep(1)
        # set the filter
        test.find("//select[@id='filter']/option[@value='%s']" %\
            (filter,), type="xpath").click()
        # subject
        test.find("#id_subject").send_keys(subject)
        # body
        test.find("#id_body").send_keys(body)
        # attach_offer
        if attach_offer:
            test.find("#id_attach_offer").click()
            # offer title
            if offer_title:
                test.find("#id_offer_title").send_keys(offer_title)
            # exp_date
            if exp_date:
                test.find("#id_date_offer_expiration").send_keys(exp_date)

        # submit
        test.find("#send-now").click()
        sleep(5)

    def message_in_relation(message_id, test_number):
        if not message_id:
            return

        store.sentMessages = None
        parts[test_number]['success'] = store.get("sentMessages",
                                                  objectId=message_id,
                                                  count=1,
                                                  limit=0) == 1

    def message_in_page(message_id, test_number):
        if not message_id:
            return

        try:
            rows = test.find("#tab-body-sent div.tr a", multiple=True)
            for row in rows:
                if row.get_attribute("href").split("/")[5] ==\
                    message_id:
                    parts[test_number]['success'] = True
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)

    def message_viewable(message_id, test_number):
        if not message_id:
            return
        href = reverse("message_details", args=(message_id, ))
        try:
            test.find("#tab-body-sent div.tr a[href='%s']" %\
                (href,)).click()
            sleep(2)
            parts[test_number]['success'] = test.is_current_url(href)
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        finally:
            # must go back to messages index for the other tests
            test.open(reverse("messages_index"))

    # FIRST
    ##########  Send message. Filter all. No offer.
    message_id = None
    try:
        send_message("all", "msg #1", "body #1")
        parts[1]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 2)
    ##########  Message is visible in page.
    message_in_page(message_id, 3)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 4)

    # SECOND
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #2", "body #2", True, "offer#2",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[5]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 6)
    ##########  Message is visible in page.
    message_in_page(message_id, 7)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 8)

    # THIRD
    ##########  Send message. Filter idle. No offer.
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("idle", "msg #3", "body #3")
        parts[9]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the
    ###         message and upgrades the account to middle.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[10]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 1
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))

    # open the mail connection
    if SeleniumTest.CHECK_SENT_MAIL:
        mail = Mail()
        ##########  Email is sent notifying user the upgrade.
        try:
            parts[11]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[11]['test_message'] = str(e)
    else:
        parts[11]['success'] = parts[10]['success']

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 12)
    ##########  Message is visible in page.
    message_in_page(message_id, 13)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 14)

    # FOURTH
    ##########  Send message. Filter idle. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("idle", "msg #4", "body #4", True, "offer#4",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[15]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 16)
    ##########  Message is visible in page.
    message_in_page(message_id, 17)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 18)

    # FIFTH
    ##########  Send message. Filter most_loyal. No offer.
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("most_loyal", "msg #5", "body #5")
        parts[19]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the
    ###         message and upgrades the account to heavy.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[20]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 2
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Email is sent notifying user the upgrade.
    if SeleniumTest.CHECK_SENT_MAIL:
        try:
            parts[21]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[21]['test_message'] = str(e)
    else:
        parts[21]['success'] = parts[20]['success']

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 22)
    ##########  Message is visible in page.
    message_in_page(message_id, 23)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 24)

    # SIXTH
    ##########  Send message. Filter most_loyal. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("most_loyal", "msg #6", "body #6", True, "offer#6",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[25]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 26)
    ##########  Message is visible in page.
    message_in_page(message_id, 27)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 28)

    # SEVENTH
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #7", "body #7", True, "offer#7",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[29]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 30)
    ##########  Message is visible in page.
    message_in_page(message_id, 31)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 32)

    # EIGHTH
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #8", "body #8", True, "offer#8",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[33]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 34)
    ##########  Message is visible in page.
    message_in_page(message_id, 35)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 36)

    # NINTH
    ##########  Send message. Filter all. With offer.
    ###         Message limit passed (heavy) dialog appears.
    message_id = None
    try:
        send_message("all", "msg #9", "body #9")
        parts[37]['success'] = test.element_exists("#maxed_out")
    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Account can no longer be upgraded. Msg cannot be sent.
    ###         Clicking Okay redirects user to messages index.
    try:
        test.find("#maxed_out").click()
        sleep(1)
        parts[38]['success'] =\
            test.is_current_url(reverse("messages_index"))
    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    #

    # goto edit message page
    test.find("#create_message").click()
    sleep(2)

    selectors = (
        ("#id_subject", "   "),
        ("#id_body", "   "),
    )
    test.action_chain(0, selectors, action="send_keys")
    test.find("#send-now").click()
    sleep(1)
    ##########  Subject is required.
    try:
        parts[39]['success'] = test.find("#subject_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[39]['test_message'] = str(e)
    ##########  Body is required.
    try:
        parts[40]['success'] = test.find("#body_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    ##########  Offer title not required if attach offer off.
    try:
        parts[41]['success'] = not test.element_exists(\
            "#offer_title_e ul li")
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)
    ##########  Expiration not required if attach offer off.
    try:
        parts[42]['success'] = not test.element_exists(\
            "#date_offer_expiration_e ul li")
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)

    test.find("#id_attach_offer").click()
    test.find("#send-now").click()
    sleep(1)
    ##########  Offer title is required if attach offer on.
    try:
        parts[43]['success'] =\
            test.find("#offer_title_e ul li").text ==\
            "Please enter a title."
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)
    ##########  Expiration date required if attach offer on.
    try:
        parts[44]['success'] =\
            test.find("#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date."
    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)

    ##########  Expiration date must be at a later date.
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=-1)
        test.find("#id_date_offer_expiration").send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(1)
        parts[45]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is later than today."
    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)

    ##########  Expiration date must be at most 1 year later.
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=367)
        date_offer = test.find("#id_date_offer_expiration")
        date_offer.clear()
        date_offer.send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(2)
        parts[46]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is less than a year."
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    if SeleniumTest.CHECK_SENT_MAIL:
        mail.logout()

    return test.tear_down()
Example #33
0
 def handle(self, *args, **options):
     """
     get all of the subscriptions whose stores are active & who
     have been last billed 30+ days ago.
     IMPORTANT! This includes accounts of type FREE, which are
     not charged or included in the email notifications
     """
     # for logging when ran by CRON
     print "Running monthly_billing: " + str(timezone.now())
     
     date_30_ago = timezone.now() + relativedelta(days=-30)
     date_now = timezone.now()
     sub_count = pointer_query("Subscription",
         {"date_last_billed__lte":date_30_ago},
             "Store", "Store", {"active":True}, count=True)
             
     asiss = []
     # get 500 subscriptions at a time
     LIMIT, skip = 500, 0
     while sub_count > 0:
         for each in pointer_query("Subscription",
             {"date_last_billed__lte":date_30_ago}, "Store",
                 "Store", {"active":True}, limit=LIMIT,
                 skip=skip, order="createdAt")['results']:
             subscription = Subscription(**each)
             sub_cost = sub_type[subscription.get(\
                         "subscriptionType")]["monthly_cost"]
             store = None # prevent UnboundLocalError
             update_store = False
             if sub_cost == 0: # FREE account
                 subscription.date_last_billed =\
                     subscription.date_last_billed +\
                     relativedelta(days=30)
                 subscription.update()
             else: # PAID account
                 account = Account.objects().get(Store=\
                             subscription.get("Store"),
                             include="Store")
                 store = account.get("store")
                 invoice = subscription.charge_cc(\
                         sub_cost, "Repunch Inc. Recurring " +\
                         "monthly subscription charge", MONTHLY)
                 send_user_email = True
                 if invoice:
                     subscription.date_last_billed =\
                         subscription.date_last_billed +\
                         relativedelta(days=30)
                     subscription.date_charge_failed = None
                     subscription.update()
                 else:
                     subscription.date_charge_failed = date_now
                     # force entering new credit card!
                     subscription.cc_number = None
                     subscription.date_cc_expiration = None
                     subscription.update()
                 
                     # notify user via email- payment is done via 
                     # dashboard to also validate cc realtime
                     # 1st day time range
                     day0_end = date_30_ago.replace()
                     day0_start = day0_end + relativedelta(hours=-24)
                     # 4th day time range
                     day4_end = date_30_ago + relativedelta(days=-4)
                     day4_start = day4_end + relativedelta(hours=-24)
                     # 8th day time range
                     day8_end = date_30_ago + relativedelta(days=-8)
                     day8_start = day8_end + relativedelta(hours=-24)
                     # 14th day time range
                     day14_end = date_30_ago + relativedelta(days=-14)
                     day14_start = day14_end + relativedelta(hours=-24)
                     # only send email after 1, 4, and 8 days
                     last_billed = subscription.date_last_billed
                     if (last_billed >= day0_start and\
                         last_billed <= day0_end) or\
                         (last_billed >= day4_start and\
                         last_billed <= day4_end) or\
                         (last_billed >= day8_start and\
                         last_billed <= day8_end):
                         send_email_receipt_monthly_failed(account, store,
                             subscription)
                     elif last_billed >= day14_start and\
                         last_billed <= day14_end:
                         # send final notification
                         send_email_receipt_monthly_failed(account,
                             store, subscription, account_disabled=True)
                     else:
                         send_user_email = False
                             
                     # make sure that the store is deactivated after the 14th day
                     if last_billed <= day14_end:
                         store.active = False
                         store.update()
                         update_store = True
                     
                 # do not send email after account deactivation
                 if send_user_email:
                     asiss.append((account, store, invoice,
                         subscription))
                     
             # update the logged in users' subscription and store
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedSubscription":subscription.jsonify()
             }
             if store and update_store:
                 payload.update({"updatedStore":store.jsonify()})
             comet_receive(subscription.Store, payload)
                     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT
         
     # everything is done - send the emails
     send_email_receipt_monthly_batch(asiss)