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)
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)
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)
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
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)
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
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)
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
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)
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
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()
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
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
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")
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
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)
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)
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()
def __temp__001__(): import datetime d = datetime.datetime.now() from libs.dateutil.relativedelta import relativedelta d = d + relativedelta(hour=8)
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
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")
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
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")
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
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")
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()
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)