class ClassWithDict: x = js.Int() d = js.Dict() def __init__(self, x, d): self.x = x self.d = d
class Donors: dic = js.Dict() def __init__(self, dic={}): self.dic = dic def add_donor(self, name, lst): self.dic.update({name: lst})
class donor_DB(): dict = js.Dict() def __init__(self, dict= {}): self._donors = dict def find_donor(self, name): if name.lower() in self._donors: return self._donors[name.lower()] return None def add_donor(self, name): if self.find_donor(name): pass else: donor = Donor(name) self._donors[donor.name.lower()] = donor def search_donor(self,name): return self._donors.get(name.lower()) def donor_list(self): return list(self._donors) def _letter(self, d): letter = f'''Dear {d.name} Thank you for your generous donation of ${d.last:.2f}. We appreciate your contribution. Team R ''' return letter def report(self): head = '{:20}|{:20}|{:10}|{:20}|'.format('Donor Name','Total Given', 'Num Gifts','Average Gifts') result = [head] result.append('-'*len(head)) for donor in self._donors: result.append(f"{donor.name:20}|${donor.total:19,.2f}|{donor.times:10}|${donor.ave:19,.2f}|") return result def file_letters(self): for donor in self._donors: f_name = donor.name+'.txt' with open(f_name, 'wt') as f: print(f'''Dear {donor.name}, Thank you for your generous donation ${donor.total:.2f}. We appreciate your contribution. Team R ''', file = f) def quit(self): sys.exit()
class DonorDB(object): #Dictionary: keys are donors and values are lists of donations donor_data = { "Allen, Paul": [1000000.00, 50000.00, 300000.00], "Gates, Bill": [5000000.00, 80000.00, 700000.00], "Bezos, Jeff": [30000.00], "Musk, Elon": [1000000.00, 30000.00], "Zuckerberg, Mark": [10000.00, 50000.00, 2000.00, 400000.00] } donor_db = js.Dict() def __init__(self): try: with open('mailroom.json', 'r') as db_handle: file_contents = db_handle.read() except IOError: self.donor_db = self.initial_db if file_contents: self.donor_db = js.from_json(file_contents)
class DonorDB(object): initial_db = { "Aristotle": [384.0, 322.0], "Kant": [1724.0, 1804.0, 1785.0], "Locke": [1632.0], "Russell": [1872.0, 1970.0, 1950.0], "Dennett": [1942.0], } donor_db = js.Dict() def __init__(self): try: with open('mailroom.json', 'r') as db_handle: file_contents = db_handle.read() except IOError: self.donor_db = self.initial_db if file_contents: self.donor_db = js.from_json(file_contents)
class DonorCollection: donor_dict = js.Dict() def __init__(self, donors): self.donor_dict = donors def generate_name_list(self): """Creates a list of all the distinct donors, returns a list helper method for print_names""" return list(self.donor_dict) def print_names(self): """Prints out all the names in the name list, references generate_name_list""" for name in self.generate_name_list(): print(name) def send_thanks(self): """Prompts the user to type a name of a donor, enter a donation amount, prints an email thanking the donor If the user types exit, it would return to the main prompt""" temp_list = [] donor_name = get_new_donor_name() if (donor_name != 'exit'): temp_list = donor_name.split() donation_amt = get_new_donor_amount() if (donation_amt != 'exit'): temp_list.append(float(donation_amt)) if donor_name in self.donor_dict: self.donor_dict[donor_name].add_donation(temp_list[2]) else: self.donor_dict[donor_name] = Donor( temp_list[0], temp_list[1], [temp_list[2]]) print(self.donor_dict[donor_name].get_email_text(temp_list)) def send_letters(self): """Goes through all the previous donators, gets their total donated, sends a thank you letter that is output on a .txt file""" for name, vals in self.donor_dict.items(): message = vals.get_letter_text() with open(name + ".txt", 'w') as output: output.write(message) print("Letters have been generated.") def generate_report(self): """Generates a report of all the previous donators Report includes name, total donated, count of donations, average gift Report is also formatted with a certain spacing returns the report as a string""" donation_total = [[ k, v.get_donation_total, v.get_donation_count, v.get_avg_donation ] for k, v in self.donor_dict.items()] donation_total.sort(key=lambda l: l[1], reverse=True) s1 = "Donor Name | Total Given | Num Gifts | Average Gift\n" s2 = "-----------------------------------------------------------------\n" final_string = s1 + s2 for z in range(0, len(donation_total)): s3 = '{:20} ${:13,.2f}{:14} ${:13,.2f}\n'.format( *donation_total[z]) final_string += s3 return final_string def print_report(self): """Prints a report of all the previous donators references generate_report""" print(self.generate_report()) def challenge(self): """Prompts the user whether they want to get an estimate or match, enter a number to multiply all the donations by an amount, enter a min and max threshold on the donation amount to filter""" projection = get_projection() factor = get_multip_factor() lower = get_min_donation() upper = get_max_donation() temp_sum = 0 for donor, val in self.donor_dict.items(): filtered_list = list( filter(lambda x: lower <= x <= upper, val._donations)) challenge_list = list(map(lambda x: x * factor, filtered_list)) if projection == '1': # Get estimate if challenge_list: temp_sum += reduce(lambda x, y: x + y, challenge_list) else: # Get match self.donor_dict[donor]._donations = challenge_list if projection == '1': print("Estimated match contribution is ${:.2f}.".format(temp_sum)) else: # projection == '2' print("Donations have been multiplied by a factor of {}.".format( factor)) return self.donor_dict def save_json(self): """Saves the donor dictionary into a json file""" json_string = json.dumps(self.to_json_compat()) with open('Data.json', 'w') as file: file.write(json_string) print("Your file has been generated.") def load_json(self): #global donor_dict """Loads donor information from a json file""" with open('Data1.json', 'r') as data_load: json_data = json.load(data_load) self.donor_dict = self.from_json_dict(json_data).donor_dict print("Donors have been loaded.")
class DonorList(): donors = js.Dict() def __init__(self, donors): self.donors = donors @property def donor_list(self): return (list(self.donors.keys())) # define a function to prompt the user for their desired action def prompt_user(self): print("Choose an action. ") print() print("1 - Send a thank you ") print("2 - Create a report ") print("3 - Send letters to everyone ") print("4 - Quit") while True: try: response = int(input(" > ")) except ValueError: print("You must enter an *integer* value. ") continue else: return response def add_donor(self, new_donor): self.donors[new_donor.name] = new_donor def receive_thank_you_card_recepient_input(self): recipient = str( input("To whom would you like to send a thank you? > ")) while recipient == "list": print(self.donor_list) print("\n") recipient = str( input("To whom would you like to send a thank you? > ")) return (recipient) def receive_donation_amount(self): while True: donation_amount = input("How much would you like to donate? > ") try: donation_amount = float(donation_amount) if donation_amount < 0.00: print("You must enter a positive number to donate. ") continue break except ValueError: print("You must enter a numeric value. > ") return (donation_amount) def send_a_thank_you(self, out=sys.stdout): recipient = self.receive_thank_you_card_recepient_input() donation_amount = self.receive_donation_amount() self.donors.setdefault(recipient, Donor(recipient)).add_donation(donation_amount) out.write("Dear {:s}, \n".format(recipient)) out.write("Thank you for your generous donations totaling ${:.2f}. \n". format(*[ x.total_donations for i, x in enumerate(self.donors.values()) if x.name == recipient ])) out.write("Best, The Donation Foundation") def create_a_report(self, out=sys.stdout): header_tuple = ("Donor Name", "Total Given", "Num Gifts", "Average Gift Size") out.write("{:20s} | {:10s} | {:10s} | {:15s}\n".format(*header_tuple)) out.write("-" * 70) out.write("\n") for donor in self.donors.values(): out.write("{:20s} ${:10.2f} {:10d} ${:15.2f}\n".format( donor.name, donor.total_donations, donor.number_of_donations, donor.average_donation_size)) def send_letters_to_everyone(self): for donor in self.donors.values(): file = open( "thank_you_{name:{width}}.txt".format(name=donor.name, width=len(donor.name)), "w") file.write("Dear {:s}, \n".format(donor.name)) file.write( "Thank you for your generous donations totaling ${:.2f}. \n". format(donor.total_donations)) file.write("Best, The Donation Foundation") file.close()
class DonorDB: """ Encapsulation of the entire database of donors and data associated with them. """ # specify a json_save dict as the data structure for the data. donor_data = js.Dict() _frozen = False def __init__(self, donors=None, db_file=None): """ Initialize a new donor database :param donors=None: iterable of Donor objects :param db_file=None: path to file to store the datbase in. if None, the data will be stored in the package data_dir """ if db_file is None: self.db_file = data_dir / "mailroom_data.json" else: self.db_file = Path(db_file) self.donor_data = {} if donors is not None: # you can set _frozen so that it won't save on every change. self._frozen = True for d in donors: self.add_donor(d) self.save # save resets _frozen def mutating(method): """ Decorator that saves the DB when a change is made It should be applied to all mutating methods, so the data will be saved whenever it's been changed. NOTE: This is not very efficient -- it will re-write the entire file each time. """ # note that this is expecting to decorate a method # so self will be the first argument def wrapped(self, *args, **kwargs): res = method(self, *args, **kwargs) if not self._frozen: self.save() return res return wrapped @classmethod def load_from_file(cls, filename): """ loads a donor database from a raw json file NOTE: This is not a json_save format file! -- it is a simpler, less flexible format. """ with open(filename) as infile: donors = json.load(infile) db = cls([Donor(*d) for d in donors]) return db @classmethod def load(cls, filepath): """ loads a donor database from a json_save format file. """ with open(filepath) as jsfile: db = js.from_json(jsfile) db.db_file = filepath def save(self): """ Save the data to a json_save file """ # if explicitly called, you want to do it! self._frozen = False with open(self.db_file, 'w') as db_file: self.to_json(db_file) @property def donors(self): """ an iterable of all the donors """ return self.donor_data.values() def list_donors(self): """ creates a list of the donors as a string, so they can be printed Not calling print from here makes it more flexible and easier to test """ listing = ["Donor list:"] for donor in self.donors: listing.append(donor.name) return "\n".join(listing) def find_donor(self, name): """ find a donor in the donor db :param: the name of the donor :returns: The donor data structure -- None if not in the self.donor_data """ return self.donor_data.get(Donor.normalize_name(name)) @mutating def add_donor(self, donor): """ Add a new donor to the donor db :param donor: A Donor instance, or the name of the donor :returns: The new or existing Donor object """ if not isinstance(donor, Donor): donor = Donor(donor) self.donor_data[donor.norm_name] = donor donor._donor_db = self return donor @staticmethod def sort_key(item): # used to sort on name in self.donor_data return item[1] def generate_donor_report(self): """ Generate the report of the donors and amounts donated. :returns: the donor report as a string. """ # First, reduce the raw data into a summary list view report_rows = [] for donor in self.donor_data.values(): name = donor.name gifts = donor.donations total_gifts = donor.total_donations num_gifts = len(gifts) avg_gift = donor.average_donation report_rows.append((name, total_gifts, num_gifts, avg_gift)) # sort the report data report_rows.sort(key=self.sort_key) report = [] report.append("{:25s} | {:11s} | {:9s} | {:12s}".format( "Donor Name", "Total Given", "Num Gifts", "Average Gift")) report.append("-" * 66) for row in report_rows: report.append( "{:25s} ${:10.2f} {:9d} ${:11.2f}".format(*row)) return "\n".join(report) def save_letters_to_disk(self): """ make a letter for each donor, and save it to disk. """ print("Saving letters:") for donor in self.donor_data.values(): print("donor:", donor.name) letter = donor.gen_letter() # I don't like spaces in filenames... filename = donor.name.replace(" ", "_") + ".txt" open(filename, 'w').write(letter)
class Donor_Save(js.JsonSaveable): donors = js.Dict() def __init__(self, donors): self.donors = donors
class Mailroom(object): # Initial donor table with the donation values. donor_table_dict = js.Dict() def __init__(self, donor_table_dict): self.donor_table_dict = donor_table_dict def thank_you(self, thank_you_dict, full_name, donation_value_str): output_string = "" while True: if full_name.lower() == "quit": return thank_you_dict, "" if full_name.lower() == "list": output_string = "Donor list:\n" for i in (list(thank_you_dict.keys())): output_string = output_string + i + "\n" return thank_you_dict, output_string else: if donation_value_str.lower() == "quit": return thank_you_dict, "" try: donation_value_flt = float(donation_value_str) if donation_value_flt <= 0: raise ValueError if full_name in thank_you_dict: thank_you_dict[full_name].append(donation_value_flt) else: thank_you_dict[full_name] = [donation_value_flt] print() output_string = (""" Dear {}: Thank you for your generous donation of ${:.2f} to Save the Kids. ------------- Save the Kids [email protected] """.format(full_name, donation_value_flt)) return (thank_you_dict, output_string) except ValueError: output_string = "Not entered. Please enter a positive number value for the donation amount." return thank_you_dict, output_string def create_report(self, create_report_dict): output_string = "{:<20} | {:<10} | {:<10} | {:<10}\n".format( "Donor Name", "Total Given", "Num Gifts", "Average Gift") output_string += "----------------------------------------------------------------------------\n" order_dict = OrderedDict(sorted(create_report_dict.items())) for key in order_dict: output_string += ( "{:<20} ${:>10.2f} {:>10d} ${:>10.2f}\n".format( key, sum(order_dict[key]), len(order_dict[key]), sum(order_dict[key]) / len(order_dict[key]))) return create_report_dict, output_string def send_letters(self, send_letters_dict): for key in send_letters_dict: with open(key + ".txt", "w") as writefile: letter = """ Dear {}: Thank you for your recent donation of ${:.2f} to Save the Kids. We are grateful for your total donations of ${:.2f} to our organization. ------------- Save the Kids [email protected] """.format(key, send_letters_dict[key][-1], sum(send_letters_dict[key])) writefile.write(letter) print("Letters have been created.\n")
class DonorCollection: #convert list to json donorsdict = js.Dict() def __init__(self, donors): self.donorsdict = donors def add_donor(self, donor): return self.donorsdict.update({donor.full_name: donor.donation_lis}) #Returns sorted list of all donors def get_all_donors(self): donor_lis = list(self.donorsdict.keys()) return sorted(donor_lis) def search_for_donor(self): reply = input("Enter first and last name of donor>> ") donor = reply.title() if donor not in self.donorsdict: print("{} is not a previous donor.".format(donor)) else: for key, val in self.donorsdict.items(): if donor == key: print("Name: {}\nDonations: {}\n".format(donor, val)) def sort_donors_by_total_amount(self): donor_total_amount = { key: sum(value) for key, value in self.donorsdict.items() } return OrderedDict( sorted(donor_total_amount.items(), key=itemgetter(1), reverse=True)) def thank_you(self): try: self.name = donor_name_prompt() if self.name.lower() == 'list': print(self.get_all_donors()) elif self.name.upper() == 'Q': main_menu(self) first, last = self.name.split(' ') except ValueError: print("Invalid input.") self.thank_you() else: success = False while not success: try: self.donation = donation_prompt() success = True except ValueError: print('Please enter a valid number.') success = False self.donor = Donor(first.title(), last.title(), [self.donation]) if self.donor.full_name not in self.donorsdict: print(f"{self.name.title()} is a new donor.") print(self.thank_you_message(self.name, self.donation, 0)) self.add_donor(self.donor) else: print(f"{self.name.title()} is a previous donor.\n>> ") print(self.thank_you_message(self.name, self.donation, 1)) self.donorsdict[f"{first.title()} {last.title()}"].append( self.donation) def thank_you_message(self, name, donation, type): #New donor message if type == 0: return f"Thank you {name.title()} for becoming a new donor to our charity! Your genereous donation of ${float(donation):.2f} is much appreciated." # previous donor message elif type == 1: return f"Thank you {name.title()} for your loyal support to our charity! Your genereous donation of ${float(donation):.2f} is much appreciated." def match_contributions(self, projection=-1): while projection not in [0, 1]: try: projection = projection_prompt() except ValueError: print('invalid input') success = False while not success or min_amount > max_amount: try: factor = factor_prompt() min_amount = min_amount_prompt() max_amount = max_amount_prompt() if min_amount > max_amount: print( 'The minimum donation amount must be less than the maximum donation amount' ) else: success = True except ValueError: print('Please enter a valid number.') success = False self.challenge(projection, min_amount, max_amount, factor) def challenge(self, projection=0, min=0, max=99999999, factor=1): #Multiplies total donation amount of each donor by factor. total = 0 for donor in self.donorsdict: filtered_list1 = list( filter(lambda x: x >= min and x <= max, self.donorsdict[donor])) filtered_list2 = list( filter(lambda x: x < min and x > max, self.donorsdict[donor])) challenge_list = list(map(lambda x: x * factor, filtered_list1)) if projection == 1: self.donorsdict[donor] = challenge_list + filtered_list2 else: if challenge_list: total = total + functools.reduce(lambda x, y: x + y, challenge_list) if projection == 1: print( f"All donations have been multiplied by a factor of {factor}") return self.donorsdict else: if total == 0: print( 'There were no donation amounts that fit into the range of minimum and maximum donations. Please re-adjust minimum and maximum donations.' ) else: print(f'Total estimated donation: ${total:.2f}') def create_report(self): print( "Donor Name | Total Given | Num Gifts | Average Gift" ) print( "-----------------------------------------------------------------------" ) for donor in self.sort_donors_by_total_amount(): print( f"{donor:20} ${sum(self.donorsdict.get(donor)):>17.2f} {len(self.donorsdict.get(donor)):>6} ${sum(self.donorsdict.get(donor))/ len(self.donorsdict.get(donor)):>16.2f}" ) def create_thank_you_letters(self): # Creates a letter for each donor that gets a file in the working dir based on donor's name. for donor in self.donorsdict: letter = self.letter_template(donor) with open(donor + ".txt", 'w') as output: output.write(letter) print("Letters have been generated.") def letter_template(self, donor): letter = "Dear {},\n Thank you for donating ${:,.2f}. Your donation makes a positive impact on your community.\n\nSincerely,\nThe Team".format( donor, sum(self.donorsdict.get(donor))) return letter def thank_you_email_template(self, dk): if len(self.donorsdict.get(dk)) > 1: return "Dear {},\nThank you for your {} generous donations of ${:.2f}. Your support helps our charity stay in business.\n\nSincerely,\n-The Team".format( dk, len(self.donorsdict.get(dk)), sum(self.donorsdict.get(dk))) else: return "Dear {},\nThank you for your generous donation of ${:.2f}. Your support helps our charity stay in business.\n\nSincerely,\n-The Team".format( dk, sum(self.donorsdict.get(dk))) def save_json(self): """Saves the donor dictionary into a json file""" json_string = json.dumps(self.to_json_compat()) with open('Donor_DB.json', 'w') as file: file.write(json_string) print("Your file has been generated.") def load_json(self): """Loads donor information from a json file""" with open('Donor_DB.json', 'r') as data_load: json_data = json.load(data_load) self.donorsdict = self.from_json_dict(json_data).donorsdict print("Donors have been loaded.")
class DonorsCollection(): _donors = js.Dict() rep = js.String() def __init__(self, val=None): self._donors = {} self.donors = val self.rep = "" @property def donors(self): return self._donors @donors.setter def donors(self, val): if val is not None: if isinstance(val, Donor): self._donors[val.name] = val else: raise ValueError("Must be instance od Donor class") return def add_donor(self): name = input("Type donor first and last name: ") donor_name = tuple(name.split()) if donor_name in self.donors: self.donors[donor_name].donations = float( input(" Donation in USD: ")) else: d = Donor(name) try: d.donations = float(input("Donation in USD: ")) except ValueError: print(""" Donation must be in USD... Donor not added """) del (d) return self.donors = d self.donors[donor_name].print_greetings def display_key(self, a): return a[-1] def display(self): for donor in sorted(self.donors, key=self.display_key): print("".join(["{} "] * len(donor)).format(*donor)) def custom_key(self, a): return (a[1].total) # 2nd arg => dict value => Donor instance def challenge(self, factor, min_donation=None, max_donation=None): for donor in self.donors: self.donors[donor] = \ self.donors[donor].multiply_donations(factor, min_donation, max_donation) @property def report(self): self.rep = "" self.rep += "{:<40}| {:<18}| {:<8}| {:<18}\n".format( 'Donor Name', 'Total Given', 'Num Gifts', 'Average Gift') self.rep += "{:-<90}\n".format('') for k, v in sorted(self.donors.items(), key=self.custom_key, reverse=True): name = " ".join(["{} "] * len(k)).format(*k) self.rep += "{:<40}{}{:>18.2f}{:>11}{}{:>17.2f}\n" \ .format(name, ' $', v.total, v.number, ' $', v.average) return (self.rep) def print_report(self): print(self.report) def write_letters(self): print("Sending letters to all donors...") for k, d in self.donors.items(): d.write_letter() def projections(self, factor, min_donation=None, max_donation=None): for donor in self.donors.values(): temp = cp.deepcopy(donor) # projection done on donor copy print("Donor: {} Current total of dination: {} \ Total after factor applied: {}".format( donor.name, donor.total, temp.multiply_donations(factor=factor, min_donation=min_donation, max_donation=max_donation).total)) del (temp) answer = None while answer not in ['Yes', 'No']: answer = input("Whould you like to multiply " + "(above min, below max) donations: [Yes, No]:") if answer == "Yes": self.challenge(factor, min_donation=min_donation, max_donation=max_donation) print("Changes applied...") else: print("No changes applied...") def save(self, backup_file=None): if not backup_file: backup_file = input( "Name of json backup file(without extension): ") bkp = self.to_json() name = "{}.json".format(backup_file) with open(name, 'w') as f: f.write(bkp) print("Database save in {}".format(name)) @classmethod def load(self, backup_file=None): if not backup_file: backup_file = input("Name of json backup file to load:\n") bkp_f = backup_file + ".json" with open(bkp_f, 'r') as f: bkp = json.load(f) return self.from_json_dict(bkp)
class Donor(object): """ Encapsulation of the entire database of donors and data associated with them. """ # Class attributes # Will be using a dictionary here to work with it db = None donor_records = js.Dict() initial_state = False def __init__(self, donors=None, donor_data=None): """Initialize a new donor database.""" # Database # Does it exist? if donor_data is None: self.donor_data = os.path.abspath("data/donor_records.json") else: self.donor_data = Path(donor_data) self.donor_records = {} # Donors if donors is not None: self.initial_state = True for i in donors: self.add_donor(i) @property def donors(self): """Method to get the donor values.""" return self.donor_records.values() def add_donor(self, donor): """Add a donor.""" if not isinstance(donor, DonorDonations): donor = DonorDonations(donor) self.donor_records[donor] = donor donor.db = self return donor def list_donors(self): """Method to create a list of the donors as a string, so they can be printed.""" donor_list = ["Donor list:"] for donor in self.donors: donor_list.append(donor.donor_name) return "\n".join(donor_list) def donor_lookup(self, name): """Method for looking up a donor.""" return self.donor_records.get(DonorDonations(name)) def donor_save_records(self): """Save donor and information related to donor.""" # Open donor_records.json in write mode an save to the file. with open(self.donor_data, 'w') as donor_data: self.to_json(donor_data) @classmethod def load_donor_records_js(cls, file): """Class method for working with the json_save library.""" # Open donor_records.json using context manager with open(file) as f_obj: temp_donors = js.from_json(f_obj) temp_donors.donor_data = file def create_donor_report(self): """Create a report of the donors and donation amounts.""" # Set an empty list for donations to append donations to as they are iterated over. donations = [] print("{:26s} | {:13s} | {:9s} | {:13s}".format( "Donor name", "Total Donation", "Number of Gifts", "Average Gifts")) print("-" * 80) # print(self.donor_records.values()) for donor in self.donor_records.values(): full_name = donor.name gifts = donor.donor_donation total_given = donor.total_donations number_gifts = len(gifts) average_gift = donor.average_donation donations.append( (full_name, total_given, number_gifts, average_gift)) for amount in donations: print("{:26s} | {:14.2f} | {:15d} | {:13.2f}".format(*amount)) print() return donations def gen_letter(self, donor): """Generate a thank you letter for the donor.""" """Template for writing a letter to a donor, thanking them for their donation.""" return """Dear {0:s},\nThank you for your very kind donation of ${1:.2f}.\n\nIt will be put to very good use.\n\n \t\tSincerely,\n\t\t\t-The Team""".format( donor, donor.last_donation) def send_letter_file(self): """Write a thank you letter and save to file.""" for k, v in donor_data.values(): letter = gen_letter(donor) file_name = donor.name.replace(" ", "_") + ".txt" with open(file_name, 'w') as f: f.write(letter) print('Completed creating letters to send out to donors.')
class DonorList: donors = js.Dict() def __init__(self, donors): self.donors = Donor(donors)
class Donors: donors = js.Dict() def __init__(self, donors_dict): self.donors = donors_dict def __iter__(self): return iter(self.donors) def __contains__(self, donor_str): return donor_str in self.donors.keys() def report_gen(self): header = ('Donor Name', 'Total Given', 'Num Gifts', 'Average Gift') row_format, row_format0 = '{:<14}', '{:<14}' for item in header[1:]: row_format += f' | {{:>{len(item)}}}' row_format0 += f' {{}}{{:>{len(item)}}}' print(row_format.format(*header)) print('-' * len(row_format.format(*header))) for item in self.donors.keys(): print( row_format0.format( item, '$', sum(self.donors[item]), ' ', len(self.donors[item]), '$', round(sum(self.donors[item]) / len(self.donors[item]), 1))) def letters(self): for names in self.donors.keys(): with open(f'{names}.txt', 'w') as text_file: print( f'Dear {names},\nThank you for your very kind donation of ${sum(self.donors[names])}.\nIt will be put to very good use.\nSincerely,\n-The Team', file=text_file) def see_list(self): for item in self.donors.keys(): print(item) def add_donor(self, name_str, amount): try: if name_str in self.donors: self.donors[name_str].append(int(amount)) else: self.donors[name_str] = [int(amount)] except ValueError: print("Please Enter a number.") def challenge(self, name_str, factor, min_donation=0, max_donation=None): temp = list( set(self.filter_min(min_donation)).intersection( self.filter_max(max_donation))) amount0 = sum(map(lambda x: sum(self.donors[x]) * factor, temp)) self.add_donor(name_str, amount0) def filter_min(self, min_donation): return list( filter(lambda x: sum(donors[x]) > min_donation, self.donors.keys())) def filter_max(self, max_donation): if max_donation == None: return self.donors.keys() else: return list( filter(lambda x: sum(donors[x]) < max_donation, self.donors.keys())) def load_json(self): with open("save_file.json") as file_in: temp = js.from_json(file_in) self.donors = temp.donors def save_json(self): json_dlist = self.to_json() with open("save_file.json", 'w') as file_out: file_out.write(json_dlist)
class Donorlist: """ Instance of a list of donors, implemented as a dictionary. Implements methods used in mailroom5. """ _donor_objects = js.Dict() def __init__(self, init_list=None): """Takes dictionary value using format {'donor1', ['donations1']} """ self._donor_objects = {} self._short_template = "Dear {}, thank you for your generous donation of ${:.2f}\n" self._long_template = ( 'Dear {},\n' '\n' ' Thank you for your kind donations totaling ${:.2f}\n' '\n' ' Your gifts will be put to very good use.\n\n' ' Sincerely\n' ' -The Team\n') if init_list: for d in init_list: self._donor_objects[d[0]] = Donor(*d) def __contains__(self, val): """ Returns if a name is in the list of donors""" return val in self._donor_objects.keys() pass def get_donor(self, val): """Returns a single donor object. Not using in mailroom""" if val in self._donor_objects.keys(): return self._donor_objects[val] def list_donors(self): """Returns a list of donors sorted by name""" return sorted(self._donor_objects.keys()) def list_by_total(self): """Returns a list of donors sorted by total donations""" return tuple( sorted(self._donor_objects.values(), key=Donor.sort_by_total, reverse=True)) def list_donations(self, name): """Returns list of donations for a donor""" if name in self._donor_objects.keys(): return self._donor_objects[name].donations else: raise ValueError('Donor not in list') def add_donor(self, name): """Adds a new donor to the list with a blank donation history""" if name not in self._donor_objects.keys(): self._donor_objects[name] = Donor(name, []) else: raise ValueError(f"Duplicate name in {type(self)}") def add_donation(self, name, amt): self._donor_objects[name].add_donation(amt) def send_thankyou(self, name, amt, template='short'): """ Sends thank you note after donation. Can pass an alternate template if desired. """ if template == 'short': template = self._short_template elif template == 'long': template = self._long_template return template.format(name, amt) def create_report(self, file_out): """Prints report of all donors""" categories = ['Donor Name', 'Total Given', 'Num Gifts', 'Average Gift'] spacing = "{:<20} $ {:>10.2f} {:>10} $ {:>10.2f}\n" sorted_tuple = self.list_by_total() header = "{:<20}| {:>10} | {:>10} | {:>10}\n" file_out.write(header.format(*categories)) for dn in sorted_tuple: ft = spacing.format(dn.name, dn.total, dn.count, dn.average) file_out.write(ft) def get_total(self, name): """Returns total donations for donor""" return self._donor_objects[name].total def save_list(self, file_out): """Writes Donor List object to open file handle in JSON format""" file_out.write(self.to_json()) @classmethod def load_file(cls, file_in): """"Creates Donorlist object from JSON file""" input_dict = json.loads(file_in.getvalue()) return Donorlist.from_json_dict(input_dict)