177 lines
5.3 KiB
Python
177 lines
5.3 KiB
Python
import flet as ft
|
|
import sqlite3
|
|
import signal
|
|
import sys
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
def init_db():
|
|
conn = sqlite3.connect('sales.db')
|
|
cursor = conn.cursor()
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS sales (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
customer TEXT NOT NULL,
|
|
product TEXT NOT NULL,
|
|
amount REAL NOT NULL,
|
|
date TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
conn.commit()
|
|
conn.close()
|
|
return True
|
|
|
|
def load_sales():
|
|
conn = sqlite3.connect('sales.db')
|
|
cursor = conn.cursor()
|
|
cursor.execute('''
|
|
SELECT customer, product, amount, date
|
|
FROM sales
|
|
ORDER BY created_at DESC
|
|
LIMIT 20
|
|
''')
|
|
sales = cursor.fetchall()
|
|
conn.close()
|
|
return sales
|
|
|
|
def add_sale(customer, product, amount):
|
|
conn = sqlite3.connect('sales.db')
|
|
cursor = conn.cursor()
|
|
cursor.execute('''
|
|
INSERT INTO sales (customer, product, amount, date)
|
|
VALUES (?, ?, ?, ?)
|
|
''', (customer, product, float(amount), datetime.now().strftime("%Y-%m-%d")))
|
|
conn.commit()
|
|
conn.close()
|
|
return True
|
|
|
|
def cleanup_resources():
|
|
"""リソースをクリーンアップ"""
|
|
try:
|
|
logging.info("アプリケーション終了処理開始")
|
|
print("✅ 正常終了処理完了")
|
|
logging.info("アプリケーション正常終了")
|
|
except Exception as e:
|
|
logging.error(f"クリーンアップエラー: {e}")
|
|
print(f"❌ クリーンアップエラー: {e}")
|
|
|
|
def signal_handler(signum, frame):
|
|
"""シグナルハンドラ"""
|
|
print(f"\nシグナル {signum} を受信しました")
|
|
cleanup_resources()
|
|
sys.exit(0)
|
|
|
|
def main(page: ft.Page):
|
|
# ログ設定
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.FileHandler('app.log'),
|
|
logging.StreamHandler()
|
|
]
|
|
)
|
|
|
|
# シグナルハンドラ設定
|
|
signal.signal(signal.SIGINT, signal_handler)
|
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
|
|
logging.info("アプリケーション起動")
|
|
|
|
# データベース初期化
|
|
try:
|
|
init_db()
|
|
logging.info("データベース初期化完了")
|
|
except Exception as e:
|
|
logging.error(f"データベース初期化エラー: {e}")
|
|
print(f"❌ データベース初期化エラー: {e}")
|
|
|
|
page.title = "販売アシスト"
|
|
page.window_width = 400
|
|
page.window_height = 600
|
|
|
|
# ウィンドウクローズイベント
|
|
def on_window_close(e):
|
|
logging.info("ウィンドウクローズイベント")
|
|
cleanup_resources()
|
|
|
|
page.on_window_close = on_window_close
|
|
|
|
# UI要素定義
|
|
customer = ft.TextField(label="顧客名")
|
|
product = ft.TextField(label="商品名")
|
|
amount = ft.TextField(label="金額")
|
|
list_view = ft.Column()
|
|
|
|
def add_sale_clicked(e):
|
|
if customer.value and product.value and amount.value:
|
|
try:
|
|
# 保存前に値を取得
|
|
customer_val = customer.value
|
|
product_val = product.value
|
|
amount_val = amount.value
|
|
|
|
# データベースに保存
|
|
add_sale(customer_val, product_val, amount_val)
|
|
|
|
# フィールドをクリア
|
|
customer.value = ""
|
|
product.value = ""
|
|
amount.value = ""
|
|
|
|
# リスト更新
|
|
update_list()
|
|
|
|
# 成功メッセージ
|
|
page.snack_bar = ft.SnackBar(
|
|
content=ft.Text("保存しました"),
|
|
bgcolor=ft.Colors.GREEN
|
|
)
|
|
page.snack_bar.open = True
|
|
page.update()
|
|
|
|
logging.info(f"売上データ追加: {customer_val} {product_val} {amount_val}")
|
|
except Exception as ex:
|
|
logging.error(f"保存エラー: {ex}")
|
|
page.snack_bar = ft.SnackBar(
|
|
content=ft.Text("エラーが発生しました"),
|
|
bgcolor=ft.Colors.RED
|
|
)
|
|
page.snack_bar.open = True
|
|
page.update()
|
|
|
|
def update_list():
|
|
try:
|
|
list_view.controls.clear()
|
|
sales = load_sales()
|
|
for sale in sales:
|
|
customer, product, amount, date = sale
|
|
list_view.controls.append(
|
|
ft.Text(f"{date}: {customer} - {product}: ¥{amount:,.0f}")
|
|
)
|
|
except Exception as e:
|
|
logging.error(f"リスト更新エラー: {e}")
|
|
|
|
# ボタン定義(関数定義後)
|
|
add_btn = ft.Button("追加", on_click=add_sale_clicked)
|
|
|
|
# 初期データ読み込み
|
|
update_list()
|
|
|
|
logging.info("UI初期化完了")
|
|
print("🚀 アプリケーション起動完了")
|
|
|
|
page.add(
|
|
ft.Text("売上管理", size=20),
|
|
customer,
|
|
product,
|
|
amount,
|
|
add_btn,
|
|
ft.Divider(),
|
|
ft.Text("売上一覧", size=16),
|
|
list_view
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
ft.app(target=main)
|