class Donor: ''' Information about the individual donors ''' name = jsd.String() donations = jsd.List() def __init__(self, name, donations=None): self.name = name self.donations = donations @property def total_given(self): return sum(self.donations) @property def num_gifts(self): return len(self.donations) @property def average_gift(self): return self.total_given / self.num_gifts def append_donation(self, donor, current_donor, current_donation): ''' appends a new donation to an existing donor ''' self.donations.append(float(current_donation)) def send_thanks(self, current_donation): print("\nDear", self.name, ":") print("Thank you very much for your generous donation.") print("Your gift of $" + current_donation, "will help our efforts greatly.\n") print("Sincerely - ACME Charity")
class Donor: first = jsd.String() last = jsd.String() donations = jsd.List() def __init__(self, first_name, last_name, donations=None): self.first = first_name self.last = last_name self.donations = donations @property def full_name(self): return "{} {}".format(self.first, self.last) def add_donation(self, amount): return self.donations.append(amount) def mult_donations(self, factor, donation_list): return list(map(lambda x: x * factor, donation_list)) def list_min_donations(self, min_donation=10): return list(filter(lambda x: x > min_donation, self.donations)) def donations_less_than_value(self, value): return list(filter(lambda x: x < value, self.donations)) def donations_more_than_value(self, value): return list(filter(lambda x: x > value, self.donations)) def total_donation(self): return sum(self.donations)
class MyClass: x = js.Int() y = js.Float() lst = js.List() def __init__(self, x, lst): self.x = x self.lst = lst
class Donor(object): first_name = js.String() last_name = js.String() amount_list = js.List() def __init__(self, name, amount_list=(500, 100, 1000, 20)): try: name.split()[1] except IndexError as e: print('The first and last name of donor must be provided\n') raise else: self.first_name = name.split()[0] self.last_name = name.split()[1] self.amount_list = list(amount_list) @property def donation_total(self): return sum(int(v) for v in self.amount_list) @property def donation_count(self): return len(self.amount_list) @property def donation_average(self): return round(self.donation_total / self.donation_count, 2) def __repr__(self): return f"{self.first_name} {self.last_name}" def save_data(self): with open(f"data/{self.first_name}_{self.last_name}.json", 'w') as infile: infile.write(json.dumps(self.to_json_compat())) def load_data(self, json_file): """ reads in json file and loads to json dict """ with open(json_file, 'r') as infile: donor_data = json.loads(infile.read()) print(donor_data) return self.from_json_dict(donor_data)
class Donor(): firstname = jsd.String() lastname = jsd.String() donations = jsd.List() def __init__(self, firstname, lastname, donations=None): self.firstname = firstname self.lastname = lastname self.donations = donations if donations else [] @property def fullname(self): """returns string with fullname of donor""" return f"{self.firstname} {self.lastname}" def donations_total(self): """returns the total donations""" try: return sum(self.donations) except TypeError: return self.donations def last_donation(self): """ returns the last donation""" return self.donations[-1] def add_donation(self, donation): """adds the new donation amount to donations""" return self.donations.append(donation) def donation_count(self): """returns number of donations""" return len(self.donations) def average_donation(self): try: return self.donations_total() / self.donation_count() except TypeError: return self.donations
class Donor: """ Information about single donors. """ # Saveables objects setup name = jsd.String() donations = jsd.List() def __init__(self, name, donations=None): self.name = name self.donations = donations @property def donor_totals(self): # Takes in a list --> use sum this time return sum(self.donations) @property def num_donations(self): return len(self.donations) @property def average_donations(self): return self.donor_totals / self.num_donations def add_donation(self, donation): self.donations.append(donation) """ OO Sorting. """ def __lt__(self, other): return self.donor_totals < other.donor_totals def __gt__(self, other): return self.donor_totals > other.donor_totals
class Donor: first = js.String() last = js.String() donations = js.List() def __init__(self, first_name, surname, donations=None): self.first = first_name self.last = surname if isinstance(donations, int): donations = [donations] self.donations = list(donations) @property def full_name(self): return f"{self.first} {self.last}" @property def total_donation(self): return sum(self.donations) def add_donation(self, new_donation): self.donations.append(new_donation)
class DonorCollection: ''' Information on the entire group of donors ''' def __init__(self, donors=None): self.donors = donors donors = jsd.List() def create_report(self): print("\nDonor Name\t\t| Total Given | Num Gifts | Average Gift") print("-" * 64) everyone = [] for donor in self.donors: everyone.append([donor]) for info in everyone: for donor in info: print("{:<22}".format(donor.name).title(), " $", "{:11.2f}".format(donor.total_given), "\t\t{:<2}".format(donor.num_gifts), "{:2}".format("$"), "{:10.2f}".format(donor.average_gift)) def send_letters(self): everyone = [] for donor in self.donors: everyone.append([donor]) for info in everyone: for donor in info: with open('/Users/toddschultz/Projects/' + donor.name + ".txt", 'w') as f: f.write( "\n\n" + donor.name + ":\n\tThank you very much for your generous donations. " ) f.write( f"your donation total of ${donor.total_given:.2f} is awesome! " ) f.write( "Our charity would not exist without your support.\\n") f.write("Sincerely:\n\nLeadership Team at Charity X.\n\n") print("Letters Complete!\n") def does_donor_exist(self, current_donor, current_donation): ''' determines if the donor is already in the collection ''' for donor in self.donors: if donor.name == current_donor: donor.append_donation(donor, current_donor, current_donation) donor.send_thanks(current_donation) break else: self.new_donor(current_donor, current_donation) def new_donor(self, current_donor, current_donation): ''' adds a new donor to the collection ''' new_donor = Donor(current_donor, [int(current_donation)]) self.donors.append(new_donor) new_donor.send_thanks(current_donation) def threshold_direction(self, num): return num >= 1100 def above(self, value, threshold): return value > float(threshold) def below(self, value, threshold): return value < float(threshold) def challenge(self, donors, factor, threshold, direction): ''' The challenge multiplys all the donations in a given direction (above or below) a certain threshold amount by a factor entered by the user. ''' print("\nHere are the current donations", direction, "$", threshold, ":") total_a = 0 for d in self.donors: gifts = filter( lambda x: self.above(x, threshold) if direction == 'above' else self.below(x, threshold), d.donations) for i in gifts: total_a = total_a + i print("%.2f" % i) print("For a total of: $", total_a) print("\nHere are all the donations", direction, "$", threshold, "multiplied by", factor, ":") total_b = 0 for d in self.donors: gifts = map( lambda x: x * float(factor), filter( lambda x: self.above(x, threshold) if direction == 'above' else self.below(x, threshold), d.donations)) for i in gifts: total_b = total_b + i print("%.2f" % i) print("For a new total of: $", ("%.2f" % total_b)) print("\nThis challenge would make you: $", ("%.2f" % (total_b - total_a)), "more monies!") def save_json(self): """ Saves donor info in JSON """ info = jsd._to_json_compat(self) with open('donors.json', 'w+') as outfile: json.dump(info, outfile) def load_json(self): """ Loads donor info from JSON """ with open('donors.json', 'r') as infile: loaded = jsd.from_json(infile) self.donors = loaded.donors
class DonorFunctions: """ Class to hold the functions done on/with Donors""" donorslist = jsd.List() def __init__(self, donors=None): self.donorslist = donors if donors else [] def save_json(self): """ JSON Donor list""" donorsave = jsd._to_json_compat(self) with open('donorList_updated.json', 'w+') as fileout: json.dump(donorsave, fileout) print('Donors Saved to File') def load_json(self): """Loads JSON file to program""" global donorslist with open('donorList.json', 'r') as infile: donor_dict = json.load(infile) donorslist = self.from_json_dict(donor_dict) self.mailroom_donors = donorslist print('Data successfully loaded from file') return donorslist def add_donor(self, donor): self.donorslist.append(donor) def get_all_donors(self): return [d.fullname for d in self.donorslist] def list_all_donors(self): return "\n".join(self.get_all_donors()) def send_single_thank_you(self): """function for sending thank you message-gets/ adds single donation and prints thank you""" donor_name = get_name_input(self.get_all_donors()) if donor_name == "quit": print("No donor name entered, exiting to menu") else: donor_amount = check_number_input() if donor_name not in self.get_all_donors(): firstname, lastname = donor_name.split(" ") self.add_donor(Donor(firstname, lastname, [donor_amount])) else: for donor in self.donorslist: if donor.fullname == donor_name: donor.add_donation(donor_amount) print('\nDear {},'.format(donor_name)) print('''\tThank you for your generous donation of ${:,.2f}\n Sincerely, \nThe ChickTech Donations Department\n'''.format( donor_amount)) def print_report(self): """Print report to match example from assignment for donor list """ print() title = [ 'Donor Name', '| Total Given ', '| Num Gifts', ' | Average Gift' ] print('{:<20}{:>14}{:^14}{:>14}'.format(title[0], title[1], title[2], title[3])) print('-' * 65) print() # # Creating list to hold donors info for printing for donor in self.donorslist: print('{:<22}{}{:>12.2f}{:>10}{:>8}{:>12.2f}'.format( donor.fullname, '$', donor.donations_total(), donor.donation_count(), '$', donor.average_donation())) print() def send_letters_everyone(self): """Creates a letter for everyone in the database, and writes them to file.""" letters_count = 0 date = datetime.datetime.now() new_folder = date.strftime("%Y-%m-%d_%H-%M") try: os.mkdir(new_folder) except OSError: print( "\nError with directory creation.Something must have gone wrong!\n" ) return for donor in self.donorslist: # create file in date folder titled with donor name filename = "./{}/{}_{}.txt".format(new_folder, donor.firstname, donor.lastname) with open(filename, 'w') as donor_thanks: letter_output = print_thank_you_total(donor) donor_thanks.write(letter_output) letters_count += 1 print("Created {} Thank You letters in this folder: {}".format( letters_count, new_folder)) def print_letters_to_everyone(self): '''test print all function''' print() for donor in self.donorslist: print(print_thank_you_total(donor)) def print_donors(self): print(self.print_report()) def print_donors_names(self): """ prints list of donors""" print("\nDonors") print("-" * 20) print(self.list_all_donors()) def print_donors_and_donations(self): """Prints all letters to screen - for view and testing""" print("\nDonors and donations") print("-" * 30, "\n") [ print(donor.fullname, "=>", donor.donations, '\n') for donor in self.donorslist ] def print_donors_and_donation_totals(self): """Prints all letters to screen - for view and testing""" print("\nDonors and donations") print("-" * 30, "\n") [ print(donor.fullname, "=>", donor.donations_total(), '\n') for donor in self.donorslist ] def new_donors_list(self, factor, min_don=None, max_don=None): """Calls the challenge function and returns new database. **Attempted to do this in challenge - but kept encountering an error.**""" updated_donor_list = self.challenge(factor, min_don, max_don) return DonorFunctions(updated_donor_list) def challenge(self, factor, min_don=None, max_don=None): """Returns a new db of donors multiplied by the factor provided. Creates new db calling the filter_factor_map""" new_d_list = [] for donor in self.donorslist: new_d_list.append( Donor( donor.firstname, donor.lastname, self.filter_factor_map(factor, donor.donations, min_don, max_don))) # return list of donors return new_d_list def projection(self, factor, min_donation=None, max_donation=None): """Return projection value for donations. a feature that could show them, based on past contributions, what their total contribution would become under different scenarios """ projected_contribution = 0 for donor in self.donorslist: projected_contribution += sum( self.filter_factor_map(factor, donor.donations, min_donation, max_donation)) # returns the projection return projected_contribution def filter_factor_map(self, factor, donations, min_donation=None, max_donation=None): """Uses filter, map and the factor to provide the new list of filtered donations""" if min_donation and max_donation: if min_donation > max_donation: raise ValueError( 'Minimum Donation listed is larger than Maximum Donation. Try Again!' ) else: # for donation in donations: return list( map( lambda x: x * factor, filter(lambda y: min_donation <= y <= max_donation, donations))) elif min_donation: # for donation in donations: return list( map(lambda x: x * factor, filter(lambda y: y >= min_donation, donations))) elif max_donation: # for donation in donations: return list( map(lambda x: x * factor, filter(lambda y: y <= max_donation, donations))) else: # for donation in donations: return list(map(lambda x: x * factor, donations))
class DonorHistory: donors = jsd.List() def __init__(self, donors=None): if donors is None: self.donors = [] else: self.donors = donors def save_json(self): donor_save = jsd._to_json_compat(self) with open('donors.json', 'w+') as file: json.dump(donor_save, file) print('Saved to JSON') def load_json(self): global donors with open('donors.json', 'r') as file: donor_load = json.load(file) donors = self.from_json_dict(donor_load) #self.dh = donors print('JSON loaded') return donors def add_donor(self, donor): self.donors.append(donor) def get_all_donor_names(self): return [donor.full_name for donor in self.donors] def thank_you(self): donor_name = None while not donor_name: donor_name = name_input() if donor_name.lower() == "list": print(self.get_all_donor_names()) donor_name = None donation = None while not donation: try: donation = donation_input() except ValueError: print("Invalid input! Please enter a number:\n") if donor_name not in self.get_all_donor_names(): try: first, last = donor_name.split(" ") self.add_donor(Donor(first, last, [donation])) except ValueError: print("Please enter the full name") else: for donor in self.donors: if donor.full_name == donor_name: donor.add_donation(donation) print("Thank you for the donation!\n") def donation_reports(self): reports = [] for donor in self.donors: reports.append( [donor.full_name, sum(donor.donations), len(donor.donations)]) return reports def report(self): print( "\nDonor Name | Total Given | Num Gifts | Average Gift") print( "---------------------------------------------------------------\n" ) for donor_report in self.donation_reports(): print("{:23}${:12.2f}{:10} ${:12.2f}".format( donor_report[0], donor_report[1], donor_report[2], donor_report[1] / donor_report[2])) print("\n") def send_all(self): for donor in self.donors: file_name = donor.full_name + '.txt' with open(file_name, "w") as donor_file: donor_file.write( "Thank you {}, for your generous donation of {}!".format( donor.full_name, donor.donations)) def challenge(self): multiplier = factor_input() try: min_donation = min_donation_input() except ValueError: min_donation = 10 print("Challenge: \n") for donor in self.donors: new_dh.append( Donor( donor.full_name, donor.mult_donations( multiplier, donor.list_min_donations(min_donation)))) print("{}: {}".format( donor.full_name, donor.mult_donations(multiplier, donor.list_min_donations(min_donation)))) def projections(self): for donor in self.donors: d_double = donor.donations_less_than_value(100) * 2 d_triple = donor.donations_more_than_value(50) * 3 print("{}'s current donations are {}".format( donor.full_name, donor.donations)) print( "(a) what {}'s total contribution would come to if they were to double contributions under $100: {}" .format(donor.full_name, sum(d_double))) print( "(b) what {}'s total contribution would come to if they were to triple contributions over $50: {}\n" .format(donor.full_name, sum(d_triple)))
class DonorChart: donors = js.List() def __init__(self, donors=None): self.donors = [] if donors: self.donors = donors def add_donor(self, donor): self.donors.append(donor) @property def donor_list(self): return [donor.full_name for donor in self.donors] @property def total_raised(self): return (sum([sum(donor.donations) for donor in self.donors])) @property def total_donations(self): return (sum([len(donor.donations) for donor in self.donors])) def sort_by_first(self): return (sorted(self.donors, key=first_key, reverse=False)) def sort_by_last(self): return (sorted(self.donors, key=last_key, reverse=False)) def sort_by_total(self): return (sorted(self.donors, key=total_key, reverse=True)) def mult_donations(self, factor): """multiply donations for each donor and return new class""" dc_dub = DonorChart() for donor in self.donors: person = Donor(donor.first, donor.last, list(map(lambda x: x * factor, donor.donations))) dc_dub.add_donor(person) return dc_dub def min_filter(self, min_donation=10): """filter by min donation for each donor and return new class""" dc_min_filt = DonorChart() for donor in self.donors: person = Donor( donor.first, donor.last, list(filter(lambda x: x >= min_donation, donor.donations))) dc_min_filt.add_donor(person) return dc_min_filt def max_filter(self, max_donation=1000): """filter by max donation for each donor and return new class""" dc_max_filt = DonorChart() for donor in self.donors: person = Donor( donor.first, donor.last, list(filter(lambda x: x <= max_donation, donor.donations))) dc_max_filt.add_donor(person) return dc_max_filt def create_report(self): """ Create Report """ report = [] page_break() new_list = [sum(donor.donations) for donor in self.donors] col_lab = ["Donor Name", "Total Given", "Num Gifts", "Average Gift"] max_name = max([len(x) for x in self.donor_list]) max_don = [max(donor.donations) for donor in self.donors] float_max = (f"{max(max_don):,.2f}") max_donl = len(str(float_max)) max_gift = len(col_lab[2]) if max_donl < len(col_lab[1]): max_donl = len(col_lab[1]) format_col = "\n{:<" + "{}".format(max_name + 5) + "}|{:^" format_col += "{}".format(max_donl + 5) format_col += "}|{:^" + "{}".format(max_gift + 5) format_col += "}|{:>" + "{}".format(max_donl + 5) + "}" print(format_col.format(*col_lab)) print("-" * len(format_col.format(*col_lab))) sorted_list = self.sort_by_total() for donor in sorted_list: num_gifts = len(donor.donations) avg_gift = sum(donor.donations) / num_gifts format_item = "{:<" + "{}".format(max_name + 5) + "}${:>" format_item += "{}".format(max_donl + 5) + ",.2f}{:>" format_item += "{}".format(max_gift + 5) + "d} ${:>" format_item += "{}".format(max_donl + 5) + ",.2f}" report.append( format_item.format(donor.full_name, donor.total_donation, num_gifts, avg_gift)) report.append(f"Total raised = $ {self.total_raised:,.2f} " f"from {self.total_donations:d} donations") print('\n'.join(report)) return ('\n'.join(report)) def save_json(self, filename=donors): """ save donor list to .json file """ save_file = js._to_json_compat(self) with open(f"{filename}.json", 'w+') as file: json.dump(save_file, file) print('Saved file to JSON') def load_json(self, filename=donors): """load donor list from .json file""" with open(f"{filename}.json", 'r') as file: load_file = json.load(file) donor_list = self.from_json_dict(load_file) print('JSON file loaded') return donor_list
class DonorList: """ Holds a list of donor objects. Performs following after user inputs a donor: 'list' input --> shows a list of donor names and reprompts adds donor if they do not exist or uses existing user prompts for a donation amd adds to donor prints thank you note """ donors = jsd.List() def __init__(self, donors=None): # Accepts only a list of donors now self.donors = donors def list_donor_names(self): donor_names = [donor.name for donor in self.donors] return ('\n'.join(donor_names)) def add_donation(self, target_donor, new_donation): target_donor.add_donation(new_donation) def add_donor_and_donation(self, target_donor, new_donation): """ Called for a brand new donor only. Creates new donor object """ new_donor = Donor(target_donor, [new_donation]) self.donors.append(new_donor) # self.add_donor(new_donor) --> deprecated print(f"{new_donor.name} has given {new_donor.donor_totals}") def send_thanks(self): """ Determines if the donor exists and gets the donation amount. """ # Get donor target_donor = input("Please enter the donor's full name. ") # Get donation try: new_donation = float( input("Please enter the donation amount for {}. ".format( target_donor))) except ValueError: print("Please enter a number. ") # Find donor or create and add new donor object. if target_donor in self.donors: self.add_donation(target_donor, new_donation) else: self.add_donor_and_donation(target_donor, new_donation) self.print_thanks(target_donor, new_donation) def print_thanks(self, target_donor, new_donation): message = f"""Dear {target_donor}, Thank you for you generous donation of ${new_donation:.2f}. It will truly help the children. Sincerely, Donation Recievers""" print(message) def order_donors(self): """ Orders the donors based on the sum of their total donations. """ ordered_donors = [] for donor in self.donors: ordered_donors.append([donor]) # Sorts on class default donor totals ordered_donors.sort(reverse=True) return ordered_donors def create_report(self): """ Prints a report based ordered by total donations. """ # Base setup line_out = '' line_out += "Donor: | $ Total | Donations | $ Average |\n" line_out += ("-" * 76) + '\n' # Setup line format to recieve ordered donor info line_in = "{:<26}| ${:>14,.2f}|{:>15}| ${:>13,.2f}\n" ordered_donors = self.order_donors() # Donor object itself is contained in a list. [[donor1], [donor2]]. Peel that away to access properties. for info in ordered_donors: for donor in info: line_out += line_in.format(donor.name, donor.donor_totals, donor.num_donations, donor.average_donations) print(line_out) def create_letters(self): """ Creates text files for each donor in the list. """ for donor in self.donors: outletter = os.path.join(os.getcwd(), f'{donor.name}_ty_letter.txt') with open(outletter, 'w+') as f: message = f"""Dear {donor.name[0]}, Thank you for you generous donation of ${donor.donor_totals:.2f}. It will truly help the children. Sincerely, Donation Receivers """ f.write(message) def save_json(self): """ JSON formatted donor information. """ # Convert to json compatible and use json built in to convert to str and write info = jsd._to_json_compat(self) with open('donors.json', 'w+') as outfile: json.dump(info, outfile) # @classmethod # def load_json(cls): # """ Loads a JSON donor dictionary. """ # with open('donors.json', 'r') as infile: # info = json.load(infile) # formatted_info = jsd.from_json_dict(info) # return formatted_info # print(formatted_info) # return formatted_info def load_json(self): """ Loads a JSON donor dictionary. """ with open('donors.json', 'r') as infile: info = json.load(infile) formatted_info = jsd.from_json_dict(info) self.donors = formatted_info def quitter(self): print("Quitting.") quit()