简易的家庭财务管理系统,提供大家参考。


# 用json的形式保存学生信息
import json


def show_menu():
    print("请选择功能: ")
    print("1. 添加收入")
    print("2. 添加支出")
    print("3. 删除收入")
    print("4. 删除支出")
    print("5. 修改收入")
    print("6. 修改支出")
    print("7. 查询总收入和总支出")
    print("8. 查询收入明细")
    print("9. 查询支出明细")
    print("10. 保存数据到本地磁盘")
    print("11. 退出系统")
    print("=" * 30)


# 添加收入信息
def add_income(money):
    amount = float(input("请输入收入金额:"))
    date = input("请输入收入日期(格式为YYYY-MM-DD):")
    desc = input("请输入收入描述:")
    income = {"amount": amount, "date": date, "desc": desc}
    money["incomes"].append(income)
    print("成功添加一条收入记录!")


# 添加支出信息
def add_expense(money):
    amount = float(input("请输入支出金额:"))
    date = input("请输入支出日期(格式为YYYY-MM-DD):")
    desc = input("请输入支出描述:")
    expense = {"amount": amount, "date": date, "desc": desc}
    data["expenses"].append(expense)
    print("成功添加一条支出记录!")


# 删除一条收入信息
def remove_income(money):
    index = int(input("请输入要删除的收入编号:"))
    try:
        income = data["incomes"].pop(index - 1)
        print("成功删除一条收入记录!")
        return income
    except IndexError:
        print("收入编号不存在!")


# 移除一条支出信息
def remove_expense(money):
    index = int(input("请输入要删除的支出编号:"))
    try:
        expense = data["expenses"].pop(index - 1)
        print("成功删除一条支出记录!")
        return expense
    except IndexError:
        print("支出编号不存在!")


# 修改一条收入信息
def update_income(money):
    index = int(input("请输入要修改的收入编号:"))
    try:
        income = data["incomes"][index - 1]
        amount = float(input(f"当前收入为{income['amount']}, 请输入新的收入金额:"))
        date = input(f"当前日期为{income['date']}, 请输入新的收入日期(格式为YYYY-MM-DD):")
        desc = input(f"当前描述为{income['desc']}, 请输入新的收入描述:")
        income["amount"] = amount
        income["date"] = date
        income["desc"] = desc
        print("成功修改一条收入记录!")
    except IndexError:
        print("收入编号不存在!")


# 修改一条支出信息
def update_expense(money):
    index = int(input("请输入要修改的支出编号:"))
    try:
        expense = data["expenses"][index - 1]
        amount = float(input(f"当前支出为{expense['amount']}, 请输入新的支出金额:"))
        date = input(f"当前日期为{expense['date']}, 请输入新的支出日期(格式为YYYY-MM-DD):")
        desc = input(f"当前描述为{expense['desc']}, 请输入新的支出描述:")
        expense["amount"] = amount
        expense["date"] = date
        expense["desc"] = desc
        print("成功修改一条支出记录!")
    except IndexError:
        print("支出编号不存在!")


# 查询总收入和总支出
def show_total(money):
    incomes = sum([income["amount"] for income in data["incomes"]])
    expenses = sum([expense["amount"] for expense in data["expenses"]])
    print("=" * 30)
    print(f"总收入:{incomes:.2f} 元")
    print(f"总支出:{expenses:.2f} 元")
    print(f"净收入:{(incomes - expenses):.2f} 元")


# 查询收入明细
"""
    incomes = [income for income in data["incomes"] if income["data"].startswith(data)]
遍历"data"字典中的"expenses"列表中的所有元素
对于每个元素,检查它的"date"属性是否以指定日期开头
如果是,就将该元素添加到一个新的列表中
最终,这个新列表中包含了所有符合条件的元素,赋值给了名为"expenses"的变量
"""


def show_income_details(money):
    date = input("请输入要查询的年月(格式为YYYY-MM):")
    incomes = [income for income in data["incomes"] if income["date"].startswith(date)]
    if incomes:
        print("=" * 30)
        for index, income in enumerate(incomes, start=1):
            print(f"收入编号:{index}")
            print(f"收入金额:{income['amount']:.2f} 元")
            print(f"收入日期:{income['date']}")
            print(f"收入描述:{income['desc']}")
            print("-" * 30)
    else:
        print("没有找到收入明细!")


# 查询支出明细
"""
    expenses = [expense for expense in data["expenses"] if expense["date"].startswith(date)]
这段代码的含义是:从“data”字典的“expenses”键对应的值中,筛选出所有“date”属性以指定日期开头的元素,并将它们存储在“expenses”列表中。
具体来说,这个代码中的for循环遍历了“expenses”列表的每一个元素,判断每个元素的“date”属性是否以指定日期开头。如果是,就将这个元素添加到“expenses”列表中。
一个简单的例子来帮助理解列表推导式的语法:[x**2 for x in range(5)] 的结果为 [0, 1, 4, 9, 16],
它的作用是将 0 到 4 中的每个数字做平方,然后将结果放入一个新的列表中。
因此,{expense for expense in data["expenses"] if expense["date"].startswith(date)} 的作用就是选出所有符合条件的元素,最后将它们存储在一个新的列表中。
"""


def show_expense_details(money):
    date = input("请输入要查询的年月(格式为YYYY-MM):")
    expenses = [expense for expense in data["expenses"] if expense["date"].startswith(date)]
    if expenses:
        print("=" * 30)
        for index, expense in enumerate(expenses, start=1):
            print(f"支出编号:{index}")
            print(f"支出金额:{expense['amount']:.2f} 元")
            print(f"支出日期:{expense['date']}")
            print(f"支出描述:{expense['desc']}")
            print("-" * 30)
    else:
        print("没有找到支出明细!")


# 保存数据到本地磁盘
def save_to_disk(money):
    with open("data.json", "w", encoding="utf-8") as f:
        # ensure_ascii=False,输出中文
        json.dump(data, f, ensure_ascii=False)
    print("成功保存家庭财务信息到本地磁盘!")


# 将存盘的数据提取出来
def load_from_disk():
    try:
        with open("data.json", "r", encoding="utf-8") as f:
            return json.load(f)
    # 排除错误的文件名
    except FileNotFoundError:
        return {"incomes": [], "expenses": []}


if __name__ == '__main__':
    data = load_from_disk()
    while True:
        show_menu()
        choice = input("请输入选项编号:")
        if choice == "1":
            add_income(data)
        elif choice == "2":
            add_expense(data)
        elif choice == "3":
            remove_income(data)
        elif choice == "4":
            remove_expense(data)
        elif choice == "5":
            update_income(data)
        elif choice == "6":
            update_expense(data)
        elif choice == "7":
            show_total(data)
        elif choice == "8":
            show_income_details(data)
        elif choice == "9":
            show_expense_details(data)
        elif choice == "10":
            save_to_disk(data)
        elif choice == "11":
            print("欢迎下次使用!")
            break
        else:
            print("无效选项,请重新选择!")