def post(self): target_year = int(self.request.get("year")) s = tools.getKey(self.request.get("skey")) mode = self.request.get("mode") td1 = datetime(target_year, 1, 1, 0, 0) td2 = datetime(target_year, 12, 31, 0, 0) annual_donations = models.Donation.query(models.Donation.settings == s, models.Donation.donation_date >= td1, models.Donation.donation_date <= td2) all_contacts = set([d.contact for d in annual_donations]) with_email = [] without_email = [] missing_contacts = [] for c_key in all_contacts: c = c_key.get() if not c: missing_contacts.append(c_key) else: if c.email != ['']: with_email.append(c) else: donation_total = c.data.donation_total if donation_total >= tools.toDecimal("250"): without_email.append(c) elif c.data.number_donations == 1 and donation_total >= tools.toDecimal("100"): without_email.append(c) body = "" body += "\n" + "#### " + str(len(with_email)) + " Donors with Email Addresses ####" for c in with_email: body += "\n" + c.websafe body += "\n" + "\n\n\n#### " + str(len(without_email)) + " Donors WITHOUT Email Addresses ####" for c in without_email: body += "\n" + "https://ghidonations.appspot.com/reports/donor?c=" + c.websafe + "&y=2013" body += "\n" + "\n\n\n#### " + str(len(missing_contacts)) + " Missing Contacts ####" for c in missing_contacts: body += "\n" + str(c) # Writing text file gcs_file_key, gcs_file = tools.newFile("text/plain", "GHI_Donations_" + str(target_year) + ".txt") gcs_file.write(body) gcs_file.close()
def task(self, isAdmin, s): try: contact_key = self.request.get("c") year = int(self.request.get("y")) if contact_key == "" or year == "" or len(str(year)) != 4: # Throw an error if you don't have those two pieces of info or if the year isn't a number raise Exception("Don't know contact key or year.") c = tools.getKey(contact_key).get() s = c.settings.get() donations = c.data.annual_donations(year) donation_total = tools.toDecimal(0) for d in donations: donation_total += d.confirmation_amount donation_total = "${:,.2f}".format(donation_total) template_variables = {"s": s, "c": c, "donations": donations, "year": str(year), "donation_total": str(donation_total), "street": c.address[0], "city": c.address[1], "state": c.address[2], "zip": c.address[3]} self.response.write( template.render("pages/letters/donor_report_print.html", template_variables)) except: # If there's a malformed URL, give a 500 error self.error(500) self.response.write( template.render('pages/letters/thankyou_error.html', {}))
def new_offline_donation(self, req): message = "Offline donation created" success = True isAdmin, s = tools.checkAuthentication(self, True, from_endpoints=True) # Make req variables local name, email, amount_donated, notes, address, team_key, individual_key, \ add_deposit = req.name, req.email, tools.toDecimal(req.amount_donated), req.notes, \ req.address, req.team_key, req.individual_key, req.add_deposit # Check for null value in individual field if individual_key == "none": individual_key = None if address: address = [address.street, address.city, address.state, address.zipcode] if team_key: team_key = tools.getKey(team_key) if individual_key: individual_key = tools.getKey(individual_key) s.create.donation(name, email, amount_donated, "offline", address=address, team_key=team_key, individual_key=individual_key, add_deposit=add_deposit, special_notes=notes) return SuccessMessage_Out(success=success, message=message)
def _run(self): # Scheduled cron job to update analytics for all settings accounts every hour all_settings = models.Settings.query() for s in all_settings: ## Update one_week_history last_week = datetime.today() - timedelta(days=7) # Get donations made in the last week donations = models.Donation.gql( "WHERE settings = :s AND donation_date > :last_week ORDER BY donation_date DESC", s=s.key, last_week=last_week) donation_count = 0 total_money = tools.toDecimal(0) for d in donations: # Counting total money total_money += d.amount_donated # Counting number of donations donation_count += 1 one_week_history = [donation_count, str(total_money)] s.one_week_history = json.dumps(one_week_history) ##################################################################################################### ## Update one_month_history last_week = datetime.today() - timedelta(days=30) # Get donations made in the last week donations = models.Donation.gql( "WHERE settings = :s AND donation_date > :last_week ORDER BY donation_date DESC", s=s.key, last_week=last_week) one_month_history = [["Date", "Amount Donated ($)"]] donations_dict = {} for d in donations: d_date = tools.convertTime(d.donation_date) day = str(d_date.month).zfill(2) + "/" + str(d_date.day).zfill(2) if day in donations_dict: donations_dict[day] += d.amount_donated else: donations_dict[day] = d.amount_donated for date in sorted(donations_dict.iterkeys()): one_month_history.append([date, float(donations_dict[date])]) s.one_month_history = json.dumps(one_month_history) s.put()
def post(self): contact_key = self.request.get("contact_key") year = self.request.get("year") c = tools.getKey(contact_key).get() logging.info("AnnualReport handler hit with contact key " + contact_key + " and year " + year) if c.email: message = mail.EmailMessage() try: email = c.email[0] except: email = c.email message.to = email message.sender = "Global Hope India <*****@*****.**>" message.subject = str(year) + " Global Hope India Donations" donations = c.data.annual_donations(year) donation_total = tools.toDecimal(0) for d in donations: donation_total += d.confirmation_amount donation_total = "${:,.2f}".format(donation_total) template_variables = {"s": c.settings.get(), "c": c, "donations": donations, "year": year, "donation_total": str(donation_total)} message.html = template.render("pages/letters/donor_report.html", template_variables) message.send() logging.info("Annual report sent to:" + c.name) else: logging.info("Annual report not sent sent because " + c.name + "doesn't have an email.")
def update(self, name, email, team_list, description, change_image, password, show_donation_page, show_progress_bar): name_changed = False show_donation_changed = False if name != self.name: self.name = name name_changed = True if email: if email != self.email: self.email = email if password != None and password != "" and self.password != password: self.password = password else: self.email = None self.password = None if show_donation_page != self.show_donation_page: self.show_donation_page = show_donation_page show_donation_changed = True if show_progress_bar != self.show_progress_bar: self.show_progress_bar = show_progress_bar show_donation_changed = True # Initializes DictDiffer object to tell differences from current dictionary to server-side one team = json.loads(team_list) dd = tools.DictDiffer(team, self.data.team_list) for key in dd.added(): new_tl = TeamList() new_tl.individual = self.key new_tl.team = tools.getKey(key) new_tl.fundraise_amt = tools.toDecimal(team[key][1]) new_tl.put() for key in dd.removed(): query = TeamList.gql("WHERE team = :t AND individual = :i", t=tools.getKey(key), i=self.key) tl = query.fetch(1)[0] for d in tl.data.donations: d.team = None d.put() tl.key.delete() for key in dd.changed(): query = TeamList.gql("WHERE team = :t AND individual = :i", t=tools.getKey(key), i=self.key) tl = query.fetch(1)[0] tl.fundraise_amt = tools.toDecimal(team[key][1]) tl.put() if description != self.description: self.description = description if change_image != None: # If change_image = None, there isn't any change. If it isn't, it # contains a if self.photo != None: # Delete old blob to keep it from orphaning old_blobkey = self.photo old_blob = blobstore.BlobInfo.get(old_blobkey) old_blob.delete() self.photo = change_image try: if name_changed or show_donation_changed: for tl in self.teamlist_entities: if name_changed == True: tl.sort_name = name if show_donation_changed: tl.show_donation_page = show_donation_page tl.show_progress_bar = show_progress_bar tl.put() except: pass self.put() if name_changed: # Reindexing donations on name change taskqueue.add(url="/tasks/reindex", params={'mode': 'team', 'key': self.websafe}, countdown=1, queue_name="backend")
def _from_base_type(self, value): return tools.toDecimal(value)
def post(self): # Below URL used for the live version. PP_URL = "https://www.paypal.com/cgi-bin/webscr" # Below URL used for testing with the sandbox - if this is uncommented, all real # donations will not be authenticated. ONLY use with dev versions. # PP_URL = "https://www.sandbox.paypal.com/cgi-bin/webscr" # Gets all account emails from Settings data models # to authenticate PayPal (don't accept payment from unknown) all_account_emails = tools.getAccountEmails() parameters = None if self.request.POST: parameters = self.request.POST.copy() if self.request.GET: parameters = self.request.GET.copy() payment_status = self.request.get("payment_status") logging.info("Payment status: " + payment_status) # Check payment is completed, not Pending or Failed. if payment_status == "Failed" or payment_status == "Pending": logging.error("Payment status is " + payment_status + ", so not continuing.") else: logging.info("All parameters: " + str(parameters)) # Check the IPN POST request came from real PayPal, not from a fraudster. if parameters: parameters['cmd'] = '_notify-validate' # Encode the parameters in UTF-8 out of Unicode str_parameters = {} for k, v in parameters.iteritems(): str_parameters[k] = unicode(v).encode('utf-8') params = urllib.urlencode(str_parameters) status = urlfetch.fetch( url=PP_URL, method=urlfetch.POST, payload=params, ).content if not status == "VERIFIED": logging.debug("PayPal returned status:" + str(status)) logging.debug('Error. The request could not be verified, check for fraud.') parameters['homemadeParameterValidity'] = False # Comparing receiver email to list of allowed email addresses try: receiver_email = parameters['receiver_email'] authenticated = False settings = None # If the receiver_email isn't in the database, this will fail settings = all_account_emails[receiver_email] authenticated = True logging.info("Getting payment to account: " + receiver_email + ", #: " + settings) except: authenticated = False logging.info("No match for incoming payment email address. Not continuing.") # Make sure money is going to the correct account - otherwise fraudulent if authenticated == True: # Currency of the donation # currency = parameters['mc_currency'] s = tools.getKey(settings).get() ipn_data = str(parameters) # Email and payer ID numbers try: email = parameters['payer_email'] except: email = None try: name = parameters['first_name'] + " " + parameters['last_name'] except: name = "Anonymous Donor" # Check if an address was given by the donor try: # Stich all the address stuff together address = [parameters['address_street'], parameters['address_city'], parameters['address_state'], parameters['address_zip']] except: address = None # Reading designation and notes values encoded in JSON from # donate form decoded_custom = None try: decoded_custom = json.loads(parameters["custom"]) team_key = tools.getKeyIfExists(decoded_custom[0]) individual_key = tools.getKeyIfExists(decoded_custom[1]) special_notes = decoded_custom[2] if s.exists.entity(team_key) == False: team_key = None if s.exists.entity(individual_key) == False: individual_key = None except: logging.error("Excepted on designation.") team_key = None individual_key = None special_notes = None try: cover_trans = decoded_custom[3] email_subscr = decoded_custom[4] except: cover_trans = False email_subscr = False try: phone = parameters['contact_phone'] if len(phone) > 10: special_notes += "\nContact phone: " + phone phone = None except: logging.info("Excepted on phone number.") phone = None confirmation_amount = tools.toDecimal(0) amount_donated = tools.toDecimal(0) try: confirmation_amount = parameters['mc_gross'] amount_donated = float(parameters['mc_gross']) - float(parameters['mc_fee']) except: pass # Find out what kind of payment this was - recurring, one-time, etc. try: payment_type = parameters['txn_type'] except: logging.info("Txn_type not available, so continuing with payment status") payment_type = payment_status if payment_type == "recurring_payment_profile_created" or payment_type == "subscr_signup": logging.info("This is the start of a recurring payment. Create info object.") payment_id = parameters['subscr_id'] # Duration between payments duration = "recurring" # s.create.recurring_donation(payment_id, duration, ipn_data) elif payment_type == "recurring_payment" or payment_type == "subscr_payment": logging.info("This is a recurring donation payment.") payment_id = parameters['subscr_id'] payment_type = "recurring" # Create a new donation s.create.donation(name, email, amount_donated, payment_type, confirmation_amount=confirmation_amount, phone=phone, address=address, team_key=team_key, individual_key=individual_key, payment_id=payment_id, special_notes=special_notes, email_subscr=email_subscr, ipn_data=ipn_data) elif payment_type == "web_accept": logging.info("This is a one-time donation.") if payment_status == "Completed": payment_id = parameters['txn_id'] # Create a new donation s.create.donation(name, email, amount_donated, "one-time", confirmation_amount=confirmation_amount, address=address, team_key=team_key, individual_key=individual_key, payment_id=payment_id, special_notes=special_notes, email_subscr=email_subscr, ipn_data=ipn_data) else: logging.info("Payment status not complete. Not logging the donation.") elif payment_type == "subscr_cancel": logging.info("A subscriber has cancelled.") amount_donated = "N/A" elif payment_type == "subscr_failed": logging.info("A subscriber payment has failed.") amount_donated = "N/A" elif payment_type == "Refunded": try: donation = models.Donation.gql("WHERE payment_id = :t", t=parameters["txn_id"]) donation_key = donation[0].key() donation_key.delete() logging.info("Refund detected and donation deleted. (" + donation_key.urlsafe() + ")") except: logging.info("Donation tried to be deleted, but failed. Most likely already deleted.") try: logging.info("Recording IPN") logging.info("Payment type: " + payment_type) logging.info("Name: " + name) logging.info("Email: " + email) logging.info("Amount donated: " + str(amount_donated)) except: logging.error("Failed somewhere in the logs.")
def task(self, isAdmin, s): # WARNING - this is a complicated and kind of a hacked-together # solution. I didn't understand it the day after I wrote it. # ... But it works. deposit_key = self.request.get("d") deposit = tools.getKey(deposit_key).get() entity_keys = deposit.entity_keys gross_amount = tools.toDecimal(0) net_amount = tools.toDecimal(0) general_fund = tools.toDecimal(0) donations = [] team_breakout = {} for k in entity_keys: d = k.get() if d != None: donations.append(d) gross_amount += d.confirmation_amount net_amount += d.amount_donated if d.team: t = d.team.get() try: team_breakout[t.name] except: team_breakout[t.name] = [tools.toDecimal(0), []] team_breakout[t.name][0] += d.amount_donated if d.individual: i = d.individual.get() array = [i.name, d.amount_donated] team_breakout[t.name][1].append(array) else: # Add count to general fund general_fund += d.amount_donated team_breakout["General Fund"] = [tools.toDecimal(general_fund), []] new_team_breakout = {} for k, v in team_breakout.items(): name = k amount_donated = v[0] array = v[1] new_array = [] for a in array: string = a[0] + " ($" + str(a[1]) + ")" new_array.append(string) new_team_breakout[unicode(name) + " ($" + str(amount_donated) + ")"] = new_array template_variables = {"d": deposit, "donations": donations, "team_breakout": new_team_breakout, "gross_amount": gross_amount, "net_amount": net_amount} self.response.write( template.render('pages/deposit.html', template_variables))