diff --git a/app.py b/app.py index 1f68d66..c07fa26 100644 --- a/app.py +++ b/app.py @@ -1,3 +1,4 @@ + import os import mysql.connector from mysql.connector import pooling @@ -6,8 +7,6 @@ from flask_cors import CORS from datetime import datetime # --- 從環境變數讀取資料庫連線資訊 --- -# os.environ.get() 會嘗試讀取環境變數,如果找不到,則使用後面的預設值 -# 這讓程式碼在本地 (使用預設值) 和 Zeabur (使用環境變數) 都能運作 DB_CONFIG = { 'user': os.environ.get('DB_USER', 'A023'), 'password': os.environ.get('DB_PASSWORD', 'UkrHhx76kCCM'), @@ -33,7 +32,8 @@ except mysql.connector.Error as err: print(f"資料庫連線池建立失敗: {err}") # --- 統一回應格式的輔助函式 --- -def create_response(status, data, message, code): +def create_standard_response(status, data, message, code): + """建立標準的 JSON 回應,包含 data 欄位""" return jsonify({ "status": status, "code": code, @@ -41,10 +41,23 @@ def create_response(status, data, message, code): "data": data }), code -def create_error_response(message, code): - return create_response("error", None, message, code) +def create_order_success_response(message, order_id, code): + """建立符合訂單成功需求的特殊 JSON 回應""" + return jsonify({ + "status": "success", + "message": message, + "order_id": order_id + }), code -# --- API Endpoint: /menu --- +def create_error_response(message, code): + """建立標準的錯誤 JSON 回應""" + return jsonify({ + "status": "error", + "code": code, + "message": message + }), code + +# --- API Endpoint: /menu (GET) --- @app.route('/menu', methods=['GET']) def get_menu_by_date(): menu_date_str = request.args.get('date') @@ -73,9 +86,9 @@ def get_menu_by_date(): menu_items = cursor.fetchall() if not menu_items: - return create_response("success", [], "no menu found", 200) + return create_standard_response("success", [], "no menu found", 200) - return create_response("success", menu_items, "Menu retrieved successfully.", 200) + return create_standard_response("success", menu_items, "Menu retrieved successfully.", 200) except mysql.connector.Error as err: return create_error_response(f"Database error: {err}", 500) @@ -87,6 +100,83 @@ def get_menu_by_date(): if conn and conn.is_connected(): conn.close() +# --- API Endpoint: /order (POST) --- +@app.route('/order', methods=['POST']) +def create_order(): + """建立一筆新的訂單""" + if not request.is_json: + return create_error_response("Invalid content type, must be application/json", 415) + + data = request.get_json() + + required_fields = ['employee_id', 'employee_name', 'order_date', 'quantity'] + missing_fields = [field for field in required_fields if field not in data] + if missing_fields: + return create_error_response(f"Missing required fields: {', '.join(missing_fields)}", 400) + + try: + order_date = data['order_date'] + quantity = int(data['quantity']) + datetime.strptime(order_date, '%Y-%m-%d') + if quantity <= 0: + raise ValueError("Quantity must be a positive integer.") + except (ValueError, TypeError): + return create_error_response("Invalid data format for date or quantity.", 400) + + if not connection_pool: + return create_error_response("Database connection not available.", 503) + + conn = None + cursor = None + try: + conn = connection_pool.get_connection() + cursor = conn.cursor() + + # 設定當前連線的時區為 UTC+8 + cursor.execute("SET time_zone = '+8:00'") + + # 1. 根據 order_date 查詢 menu_item_id + query_menu = "SELECT id FROM menu_items WHERE menu_date = %s LIMIT 1" + cursor.execute(query_menu, (order_date,)) + menu_item = cursor.fetchone() + + if not menu_item: + return create_error_response(f"No menu found for date {order_date}", 404) + + menu_item_id = menu_item[0] + + # 2. 將訂單資料寫入資料庫 + # 使用 NOW() 函數,因為連線時區已設定 + add_order_query = ("INSERT INTO employee_order " + "(emp_id, name, order_date, menu_item_id, order_qty, update_by, update_at) " + "VALUES (%s, %s, %s, %s, %s, %s, NOW())") + order_data = ( + data['employee_id'], + data['employee_name'], + order_date, + menu_item_id, + quantity, + data['employee_id'] + ) + cursor.execute(add_order_query, order_data) + new_order_id = cursor.lastrowid + + conn.commit() + + return create_order_success_response("新增成功", new_order_id, 201) + + except mysql.connector.Error as err: + if conn: conn.rollback() + return create_error_response(f"Database error: {err}", 500) + except Exception as e: + if conn: conn.rollback() + return create_error_response(f"An unexpected error occurred: {e}", 500) + finally: + if cursor: + cursor.close() + if conn and conn.is_connected(): + conn.close() + # --- 全域錯誤處理 --- @app.errorhandler(404) def not_found(error): @@ -98,7 +188,5 @@ def method_not_allowed(error): # --- 啟動應用程式 --- if __name__ == '__main__': - # Zeabur 會透過 Gunicorn 啟動,這段主要用於本地測試 - # Zeabur 會自動注入 PORT 環境變數 port = int(os.environ.get('PORT', 5000)) - app.run(host='0.0.0.0', port=port, debug=False) # 正式環境 debug 應為 False \ No newline at end of file + app.run(host='0.0.0.0', port=port, debug=False)