Skip to content

Instantly share code, notes, and snippets.

@thinkphp
Last active June 21, 2025 20:56
Show Gist options
  • Save thinkphp/13d9a9d0546e4477c230f5a8a5482e23 to your computer and use it in GitHub Desktop.
Save thinkphp/13d9a9d0546e4477c230f5a8a5482e23 to your computer and use it in GitHub Desktop.
#global data structures for property Management
#hardcoded property details from Table 1 (Task 2 requirement)
PROPERTIES = {
"B12-3AB": {"original_cost": 153450,"residual_mortgage": 112345},
"B13-4CD": {"original_cost": 212130,"residual_mortgage": 180234},
"B14-5GH": {"original_cost": 120100,"residual_mortgage": 85980},
"B15-6JK": {"original_cost": 135230,"residual_mortgage": 101321},
"B16-7MO": {"original_cost": 183230,"residual_mortgage": 130234}
}
# Glbobal list to store all transactions (accessible by both Task 2 and Task 3)
TRANSACTIONS = []
def reset_transactions():
"""
Remove all transactions
"""
TRANSACTIONS.clear()
#print("OK All transactions have been cleared.")
def read_data():
reset_transactions()
#print("\nLoading test data from Table 2....")
test_entries = [
("B12-3AB", "Rent received", 760),
("B13-4CD", "Replaced radiator in kitchen", -150),
("B13-4CD", "Rent received", 1060),
("B14-5GH", "Repaired water leak in bathroom", -70),
("B14-5GH", "Rent received", 600),
("B12-3AB", "Boiler serviced", -80),
("B15-6JK", "Rent received", 600),
("B16-7MO", "Repaired washing machine", -120),
("B16-7MO", "Rent received", 920),
("B14-5GH", "Replaced bathroom flooring", -210),
("B15-6JK", "Boiler serviced", -80),
("B12-3AB", "Rent received", 760)
]
for code, desc, amount in test_entries:
transaction = {
"property_code": code,
"description": desc,
"amount": amount
}
TRANSACTIONS.append(transaction)
print(f"OK {len(test_entries)} transactions loaded successfully!")
def display_menu():
"""
This is the subroutine for Main menu which will display to users 3 options to choose from, 3rd one being the Exit option.
The program should only terminate when option 3 is chosen.
"""
print("\n" + "="*40)
print(" RENTAL Management MENU")
print("="*40)
print("1. Enter rental property details")
print("2. Display summary data for rentals")
print("3. Exit")
print("=" * 40)
def property_data():
"""
This is the subroutine option created for option 1 - Enter rental property details
For task 1, only an info mesage will be displayed. Further functionality will be added in next tasks, as per assignment instructions.
Task 2 Implementation : Subroutine for option 1 -- Enter rental property details
Allows user to input rent and expense transactions for properties
"""
#print("\n --- Enter Property Details ---")
#print("This function will be implemented in Task2")
#input("Press Enter to continue...")
print("\n" + "=" * 50)
print(" ENTER PROPERTY DETAILS")
print("=" * 50)
while True:
#Display available properties
print("\nAvailable Properties:")
print("-" * 20)
for property_code in PROPERTIES.keys():
print(f"*{property_code}")
#get property code input
print("\nEnter property code (or type 'quit' to return to main manu")
property_code = input("Property Code: ").strip() # remove spaces at the beginning and at the end of the string
if property_code.lower() == 'quit':
print("Returning to main manu...")
break
#validate property code
if property_code not in PROPERTIES:
print(f"Error: '{property_code}' is not a valid property code.")
print("Please choose from the available properties listed above.")
continue
description = ""
while description.strip() == "":
description = input("Enter description: ").strip() # remove spaces at the beginning and at the end of the string
if description == "":
print("Error: DEscription cannot be empty. Please enter a description")
#get amount input with validation
while True:
try:
amount_str = input("Enter amount (positive for rent , negative for expenses): Β£")
amount = float( amount_str ) #converteste de la siruri de caractere adica stringuri la float
if amount == 0:
print("Error: Amount cannot be zero. Please enter a valid amount.")
continue
break #valid amount entered
except ValueError:
print("Error: Please enter a valid numeric amount (e.g. 101 or -101)")
transaction = {
"property_code": property_code,
"description": description,
"amount": amount
}
TRANSACTIONS.append( transaction )
#if amount is positive then we assume this is rent
if amount > 0:
print(f"OK Rent entry of Β£{amount: .2f} added successfully for {property_code}")
# otherwise we assume an expense
else:
print(f"OK Expense entry of Β£{abs(amount): .2f} added successfully for {property_code}")
while True:
continue_choice = input("\nDo you want to add another entry? (y/n): ").strip().lower()
if continue_choice in ['y', 'yes','oui','o']: #the use can enter or 'y' or 'yes'
break
elif continue_choice in ['n','no','nope']:
print("Return to main menu...")
return #exit subroutine
else:
print("Error: Please enter 'y' for yes or 'n' for no")
def summary_data():
"""
Task 3 Implementation: Subroutine for option 2 - Display summary for rentals
Processes stored transaction data and displays summary table
"""
#read_data()
print("\n" + "="*80)
print(" PROPERTY SUMMARY REPORT")
print("="*80)
#check if there are any transactions
if not TRANSACTIONS:
print("No transaction data available.")
print("Please enter some property details first using option 1.")
input("\nPress Enter to continue...")
return
#initialize summary data structure
summary = {}
#initialize summary for each property with default values
for prop_code in PROPERTIES:
summary[ prop_code ] = {
'original_cost': PROPERTIES[ prop_code ]['original_cost'],
'residual_mortgage': PROPERTIES[ prop_code ]['residual_mortgage'],
'total_repairs': 0,
'total_rents': 0
}
#Process all transactions
for transaction in TRANSACTIONS:
prop_code = transaction['property_code']
amount = transaction['amount']
# add to appropriate category based on amount sign
if amount > 0:
summary[ prop_code ]['total_rents'] += amount
#positive amount = RENT received
else:
#negative amount = expense / repair (store as posive value)
summary[ prop_code ]['total_repairs'] += abs(amount)
print("\nProperty Summary:")
print("-"*80)
print(f"{'Post':<10} {'Original':<10} {'Repairs':<10} {'Amended':<10} {'Residual':<10} {'Rents':<10} {'Rent as %':<10}")
print(f"{'Code':<10} {'Cost':<10} {'$':<8} {'Cost':<8} {'Mortgage':<10} {'$':<10} {'of Mortgage':<8}")
print("-"*80)
#initialize totals
total_original = 0
total_repairs = 0
total_amended = 0
total_mortgage = 0
total_rents = 0
#display each property's summary
for prop_code in sorted(PROPERTIES.keys()):
original_cost = summary[prop_code]['original_cost']
repairs = summary[prop_code]['total_repairs']
amended_cost = original_cost + repairs
residual_mortgage = summary[prop_code]['residual_mortgage']
rents = summary[prop_code]['total_rents']
#calculate rent as percentage of mortgage
if residual_mortgage > 0:
rent_percentage = (rents / residual_mortgage) * 100
else:
rent_percentage = 0
#display property row
print(f"{prop_code:>10} {original_cost:>10.0f} {repairs:>8.0f} {amended_cost:>10.0f} "
f"{residual_mortgage:>10.0f} {rents:>8.0f} {rent_percentage:>9.2f}%")
total_original += original_cost
total_repairs += repairs
total_amended += amended_cost
total_mortgage += residual_mortgage
total_rents += rents
#display total row
print("-" * 80)
total_rent_percentage = (total_rents / total_mortgage) * 100 if total_mortgage > 0 else 0
print(f"{'Total':<10} {total_original:<10.0f} {total_repairs:<8.0f} {total_amended:<10.0f} "
f"{total_mortgage:<10.0f} {total_rents:<8.0f} {total_rent_percentage:<2.2f}%")
print("-" * 80)
print(f"\nFormula used: π΄π‘šπ‘’π‘›π‘‘π‘’π‘‘ π‘π‘œπ‘ π‘‘ = π‘‚π‘Ÿπ‘–π‘”π‘–π‘›π‘Žπ‘™ π‘π‘œπ‘ π‘‘ + π‘…π‘’π‘π‘Žπ‘–π‘Ÿπ‘ ")
print(f"Example: for any property, if original cost = $120,100 and repairs = $280")
print(f" then amended cost = $120,100 + $280,380")
print(f"\nTotal transactions processed: {len(TRANSACTIONS)}")
input("\nPress Enter to continue...")
def exit_program():
"""
This is the subroutine for option 3 - Exit
It is intended to display a polite goodby message and to terminate the program
"""
print("\n --- EXIT Program ----")
print("Thank you for using the Property REntal Management System!")
def get_user_choice():
"""
Obtains and validate the user choice
Returns: int - valid option chosen by user (1, 2, or 3)
"""
while True:
try:
"""
Prompt the user to select the correct option which will then be analized and transmited to the corresponding variable of choice.
An intiger will be required here.
"""
choice = input("Please enter your choice (1-3): ")
#set the data type to intiger to build up on the program's functionality and integrity
choice_int = int(choice)
#validate if the option chosen by the user is in the correct range
if choice_int in [1,2,3]:
return choice_int
#inform the user of what are the valid options to navigate through the program and prompt for the correct value to be chosen
else:
print("Error: Please enter a valid option (1,2, or 3)")
except ValueError:
#manage any situation where the user might input text or any other characters, considered invalid - through an error message together with guidance on what the valid options are
print("Error: Please enter a valid intiger (1,2, or 3)")
def main():
"""
This is the main function which is controlling the program
Implementing the main menu's functionality as per flowchart attached for Task 1
"""
print("Welcome to the Rental Property Management System")
#main loop here
while True:
#here display the main menu
display_menu()
#Obtain the user's valid choice
user_choice = get_user_choice()
#Execute the correcponding action as per user's choice
if user_choice == 1:
#call the function
property_data()
elif user_choice == 2:
summary_data()
elif user_choice == 3:
exit_program()
break #exit the main loop
print("\nReturning to main menu...")
#Point of entry in the program, the main menu being called
if __name__ == "__main__":
main()
# {'property':<10} inseamna sirul property aliniat la stanga < intr-un spatiu de 10 caractere
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment