Cách xây dựng công cụ theo dõi chi phí bằng Python

Công cụ theo dõi chi phí thực sự cần thiết với doanh nghiệp và cá nhân trong việc quản lý tài chính. Sau đây là cách làm app theo dõi chi phí dễ dàng nhất bằng Python.

Lập trình app quản lý chi phí bằng Python

Mô đun Tikinter, CSV, Matplotlib

Để xây dựng công cụ theo dõi chi phí, bạn cần mô đun Tkinter, CSV và Matplotlib. Tkinter cho phép bạn tạo các ứng dụng desktop. Nó cung cấp một loạt widget như nút bấm, nhãn dán và hộp văn bản giúp cho việc phát triển ứng dụng dễ dàng.

Mô đun CSV là một thư viện Python có sẵn, cung cấp tính năng đọc và viết file CSV.

Với Matplotlib, bạn có thể xây dựng các hình ảnh trực quan hóa tương tác như đồ thị, sơ đồ và biểu đồ. Sử dụng nó với các mô đun như OpenCV có thể giúp bạn nắm vững những kỹ thật cải tiến hình ảnh.

Để cài những mô đun này, chạy:

pip install tk matplotlib

Xác định cấu trúc của ứng dụng theo dõi chi tiêu

Bắt đầu bằng cách nhập những mô đun cần thiết. Xác định một class, ExpenseTrackerApp. Đặt tiêu đề và kích thước. Xác định một danh sách lưu chi phí và danh sách khác cho thư mục. Khởi tạo StringVar tên category và đặt giá trị ban đầu của nó thành danh mục đầu tiên trong danh sách. Hoàn tất bằng cách gọi phương thức create_widgets.

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import csv
import matplotlib.pyplot as plt

class ExpenseTrackerApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Expense Tracker")
        self.geometry("1300x600")
        self.expenses = []
        self.categories = [
            "Food",
            "Transportation",
            "Utilities",
            "Entertainment",
            "Other",
        ]
        self.category_var = tk.StringVar(self)
        self.category_var.set(self.categories[0])
        self.create_widgets()

Phương thức create_widgets chịu trách nhiệm thêm các thành phần UI vào ứng dụng. Tạo một khung cho các nhãn và mục của bản ghi chi phí. Tạo 6 nhãn: một cho tiêu đề, số lượng chi phí, mô tả mục, danh mục, ngày tháng và tổng chi phí. Đặt từng thành phần cha của mỗi phần tử, nội dung sẽ hiển thị và kiểu font của nó.

Tạo 3 widget mục nhập và Combobox để lấy đầu vào tương ứng. Đối với widget đầu vào, đặt thành phần cha, kiểu font và chiều rộng. Xác định thành phần cha, danh sách giá trị, kiểu font và chiều rộng cho Combobox. Liên kết category_var với nó, nhờ vậy, giá trị được chọn tự động được cập nhật.

    def create_widgets(self):
        self.label = tk.Label(
            self, text="Expense Tracker", font=("Helvetica", 20, "bold")
        )
        self.label.pack(pady=10)
        self.frame_input = tk.Frame(self)
        self.frame_input.pack(pady=10)
        self.expense_label = tk.Label(
            self.frame_input, text="Expense Amount:", font=("Helvetica", 12)
        )
        self.expense_label.grid(row=0, column=0, padx=5)
        self.expense_entry = tk.Entry(
            self.frame_input, font=("Helvetica", 12), width=15
        )
        self.expense_entry.grid(row=0, column=1, padx=5)
        self.item_label = tk.Label(
            self.frame_input, text="Item Description:", font=("Helvetica", 12)
        )
        self.item_label.grid(row=0, column=2, padx=5)
        self.item_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=20)
        self.item_entry.grid(row=0, column=3, padx=5)
        self.category_label = tk.Label(
            self.frame_input, text="Category:", font=("Helvetica", 12)
        )
        self.category_label.grid(row=0, column=4, padx=5)
        self.category_dropdown = ttk.Combobox(
            self.frame_input,
            textvariable=self.category_var,
            values=self.categories,
            font=("Helvetica", 12),
            width=15,
        )
        self.category_dropdown.grid(row=0, column=5, padx=5)
        self.date_label = tk.Label(
            self.frame_input, text="Date (YYYY-MM-DD):", font=("Helvetica", 12)
        )
        self.date_label.grid(row=0, column=6, padx=5)
        self.date_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=15)
        self.date_entry.grid(row=0, column=7, padx=5)

Xác định 5 nút bấm: Add Expense, Edit Expense, Delete Expense, Save Expenses, và Show Expenses Chart. Đặt phần tử gốc cho mỗi nút bấm, nội dung nó sẽ hiển thị và lệnh nó sẽ chạy khi bạn click vào. Tạo một khung cho listbox. Đặt phần tử gốc, kiểu font và chiều rộng.

Tạo thanh cuộn theo chiều dọc và đặt nó ở bên phải của khung hình. Dùng nó để cuộn qua nội dung của listbox. Sắp xếp toàn bộ phần tử với phần padding cần thiết và gọi update_total_label().

        self.add_button = tk.Button(self, text="Add Expense", command=self.add_expense)
        self.add_button.pack(pady=5)
        self.frame_list = tk.Frame(self)
        self.frame_list.pack(pady=10)
        self.scrollbar = tk.Scrollbar(self.frame_list)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.expense_listbox = tk.Listbox(
            self.frame_list,
            font=("Helvetica", 12),
            width=70,
            yscrollcommand=self.scrollbar.set,
        )
        self.expense_listbox.pack(pady=5)
        self.scrollbar.config(command=self.expense_listbox.yview)
        self.edit_button = tk.Button(
            self, text="Edit Expense", command=self.edit_expense
        )
        self.edit_button.pack(pady=5)
        self.delete_button = tk.Button(
            self, text="Delete Expense", command=self.delete_expense
        )
        self.delete_button.pack(pady=5)
        self.save_button = tk.Button(
            self, text="Save Expenses", command=self.save_expenses
        )
        self.save_button.pack(pady=5)
        self.total_label = tk.Label(
            self, text="Total Expenses:", font=("Helvetica", 12)
        )
        self.total_label.pack(pady=5)
        self.show_chart_button = tk.Button(
            self, text="Show Expenses Chart", command=self.show_expenses_chart
        )
        self.show_chart_button.pack(pady=5)
        self.update_total_label()

Xác định chức năng của công cụ theo dõi chi phí

Xác định phương thức, add_expense. Truy xuất giá trị của chi phí, mục, danh mục và ngày tháng. Nếu giá trị của chi phí và ngày tháng hợp lệ, thêm chi phí vào danh sách expenses. Chèn bản ghi này thành listbox và định dạng nó phù hợp. Sau khi được chèn, xóa đầu vào người dùng trong các box nhập cho input mới.

Nếu không, hiện một cảnh báo giá trị của chi phí và ngày tháng không thể để trống. Gọi update_total_label.

    def add_expense(self):
        expense = self.expense_entry.get()
        item = self.item_entry.get()
        category = self.category_var.get()
        date = self.date_entry.get()
        if expense and date:
            self.expenses.append((expense, item, category, date))
            self.expense_listbox.insert(
                tk.END, f"{expense} - {item} - {category} ({date})"
            )
            self.expense_entry.delete(0, tk.END)
            self.item_entry.delete(0, tk.END)
            self.date_entry.delete(0, tk.END)
        else:
            messagebox.showwarning("Warning", "Expense and Date cannot be empty.")
        self.update_total_label()

Xác định phương thức, edit_expense. Truy xuất chỉ mục của bản ghi được chọn và lấy chi phí. Mở hộp thoại yêu cầu nhập chi phí. Nếu người dùng đã cung cấp chi phí mới, thay đổi danh sách chi phí cho phù hợp. Gọi refresh_listupdate_total_label.

    def edit_expense(self):
        selected_index = self.expense_listbox.curselection()
        if selected_index:
            selected_index = selected_index[0]
            selected_expense = self.expenses[selected_index]
            new_expense = simpledialog.askstring(
                "Edit Expense", "Enter new expense:", initialvalue=selected_expense[0]
            )
            if new_expense:
                self.expenses[selected_index] = (
                    new_expense,
                    selected_expense[1],
                    selected_expense[2],
                    selected_expense[3],
                )
                self.refresh_list()
                self.update_total_label()

Xác định phương thức, delete_expense. Truy xuất chỉ mục của bản ghi đã chọn và lấy chi phí. Chuyển chỉ mục của entry bạn muốn xóa. Xóa mục nhập đó từ listbox và gọi update_total_label.

    def delete_expense(self):
        selected_index = self.expense_listbox.curselection()
        if selected_index:
            selected_index = selected_index[0]
            del self.expenses[selected_index]
            self.expense_listbox.delete(selected_index)
            self.update_total_label()

Xác định phương thức, refresh_list. Xóa bản ghi hiện tại và thêm bản ghi mới bằng các giá trị đã được update.

    def refresh_list(self):
        self.expense_listbox.delete(0, tk.END)
        for expense, item, category, date in self.expenses:
            self.expense_listbox.insert(
                tk.END, f"{expense} - {item} - {category} ({date})"
            )

Định nghĩa phương thức update_total_label. Tính tổng toàn bộ chi phí trong danh sách và update nó trên nhãn. Xác định phương thức khác, save_expenses. Tạo và mở một file CSV tên expenses.csv ở chế độ ghi. Thêm các tiêu đề cột cho fie CSV vào hàng đầu tiên. Lặp lại từng bản ghi chi phí và viết nó thành một hàng.

    def update_total_label(self):
        total_expenses = sum(float(expense[0]) for expense in self.expenses)
        self.total_label.config(text=f"Total Expenses: USD {total_expenses:.2f}")

    def save_expenses(self):
        with open("expenses.csv", "w", newline="") as csvfile:
            writer = csv.writer(csvfile)
            column_headers = ["Expense Amount", "Item Description", "Category", "Date"]
            writer.writerow(column_headers)
            for expense in self.expenses:
                writer.writerow(expense))

Xác định một phương thức, show_expenses_chart. Định nghĩa một từ điển, category_totals. Lặp qua danh sách expenses và chuyển đổi số tiền chi phí sang float. Lưu trữ tổng chi phí cho từng danh mục. Nếu danh mục đã tồn tại trong từ điển, hãy tăng tổng số lên số tiền chi phí hiện tại. Nếu không, tạo một mục mới với tổng chi phí hiện tại.

    def show_expenses_chart(self):
        category_totals = {}
        for expense, _, category, _ in self.expenses:
            try:
                amount = float(expense)
            except ValueError:
                continue
            category_totals[category] = category_totals.get(category, 0) + amount

Truy xuất danh mục và chi phí trong hai danh sách khác nhau. Tạo kiểu mới cho bản đồ với kích thước cụ thể. Tạo biểu đồ hình tròn, dùng danh sách chi phí làm dữ liệu và danh mục làm nhãn. Tham số autopct xác định định dạng để hiển thị các giá trị phần trăm trên các phần biểu đồ. Chuyển equal sang plt.axis để đảm bảo dữ liệu bạn vẽ là hình tròn. Đặt tiêu đề cho biểu đồ hình tròn và hiển thị nó.

        categories = list(category_totals.keys())
        expenses = list(category_totals.values())
        plt.figure(figsize=(8, 6))
        plt.pie(
            expenses, labels=categories, autopct="%1.1f%%", startangle=140, shadow=True
        )
        plt.axis("equal")
        plt.title(f"Expense Categories Distribution (USD)")
        plt.show()

Tạo một phiên bản của ExpenseTrackerApp. Hàm mainloop() báo cho Python chạy lặp sự kiện Tkinter và lắng nghe sự kiện cho tới khi bạn đóng của sổ.

if __name__ == "__main__":
    app = ExpenseTrackerApp()
    app.mainloop()

Kiểm tra các tính năng khác nhau của ứng dụng quản lý chi tiêu bằng Python

Khi chạy chương trình này, nó sẽ mở một cửa sổ ứng dụng. Bên trong chứa các trường đầu vào để ghi chi phí, mô tả mục, danh mục và ngày tháng. Nhập một số dữ liệu và click nút Add Expense. Bạn sẽ thấy bản ghi được thêm vào box danh sách. Chương trình này cũng update chi phí tổng.

Expense Tracker

Chọn bản ghi và click nút Edit Expenses. Một hộp thoại hiện ra, cho phép bạn update từng bản ghi.

Kiểm tra ứng dụng quản lý chi tiêu

Click nút Delete Expenses để loại bỏ bản ghi đã chọn.

Xóa chi tiêu

Khi nhấn nút Show Expenses Chart, chương trình này hiện một biểu đồ hình tròn. Biểu đồ hình tròn hiện chi phí cho từng danh mục cùng với tên và phần trăm của nó.

Biểu đồ phân bổ chi tiêu

Bạn có thể thêm chức năng tìm kiếm để cho phép người dùng tìm chi phí cụ thể dựa trên mô tả, số lượng, thư mục hoặc ngày tháng. Bạn có thể thêm lựa chọn phân loại và lọc bản ghi. Bản địa hóa ứng dụng với nhiều ngôn ngữ và định dạng tiền tệ khác nhau.

Hi vọng bài viết hữu ích với các bạn.

Thứ Ba, 12/09/2023 16:44
53 👨 403
0 Bình luận
Sắp xếp theo
    ❖ Python