291 lines
12 KiB
Python
291 lines
12 KiB
Python
# gui/main_window.py
|
|
|
|
import asyncio
|
|
from datetime import datetime
|
|
from PySide6.QtWidgets import (
|
|
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
QPushButton, QTextEdit, QMenuBar, QMenu, QLabel,
|
|
QTableWidget, QTableWidgetItem, QMessageBox
|
|
)
|
|
from PySide6.QtGui import QAction
|
|
from PySide6.QtCore import Qt, Slot, QSettings, QTimer
|
|
from gui.order_input_dialog import OrderInputDialog
|
|
from gui.template_management_dialog import TemplateManagementDialog
|
|
from gui.help_dialog import HelpDialog
|
|
from gui.settings_dialog import SettingsDialog
|
|
from src.database_module import DatabaseManager
|
|
from src.sms_module import SMSMessenger # SMS 전송 모듈
|
|
|
|
class MainWindow(QMainWindow):
|
|
def __init__(self, logger):
|
|
super().__init__()
|
|
self.logger = logger
|
|
|
|
self.settings = QSettings("When_Ride_Mycar", "SMS_Sender")
|
|
self.db_manager = DatabaseManager() # SQLite, SQLAlchemy 기반 DB 관리자
|
|
|
|
self.setWindowTitle("주문 알림 SMS 전송 프로그램")
|
|
self.resize(900, 700)
|
|
self.setup_menu()
|
|
self.setup_ui()
|
|
self.apply_styles()
|
|
|
|
# SMSMessenger를 생성합니다.
|
|
self.sms_messenger = SMSMessenger(self.logger, headless=False, delay=1)
|
|
# 이벤트 루프가 실행된 후 (0ms 후) connect()를 실행하도록 예약합니다.
|
|
QTimer.singleShot(0, self.start_sms_connection)
|
|
|
|
# 매달 1일(또는 저장된 월과 현재 월이 다르면) SMS 카운트 초기화
|
|
self.check_and_reset_sms_count()
|
|
self.update_sms_count_label()
|
|
|
|
self.refresh_order_list()
|
|
|
|
def start_sms_connection(self):
|
|
asyncio.create_task(self.sms_messenger.connect())
|
|
|
|
def setup_menu(self):
|
|
menu_bar = self.menuBar()
|
|
file_menu = menu_bar.addMenu("파일")
|
|
settings_action = QAction("사용자 설정", self)
|
|
settings_action.triggered.connect(self.open_settings_dialog)
|
|
file_menu.addAction(settings_action)
|
|
exit_action = QAction("종료", self)
|
|
exit_action.triggered.connect(self.close)
|
|
file_menu.addAction(exit_action)
|
|
|
|
help_menu = menu_bar.addMenu("도움말")
|
|
usage_action = QAction("프로그램 사용설명서", self)
|
|
usage_action.triggered.connect(self.show_help)
|
|
help_menu.addAction(usage_action)
|
|
|
|
def setup_ui(self):
|
|
central_widget = QWidget(self)
|
|
self.setCentralWidget(central_widget)
|
|
main_layout = QVBoxLayout(central_widget)
|
|
|
|
# 상단 버튼 영역
|
|
button_layout = QHBoxLayout()
|
|
self.order_input_button = QPushButton("주문정보 입력")
|
|
self.order_input_button.setToolTip("주문 정보를 입력하여 문자 전송 준비")
|
|
self.order_input_button.clicked.connect(self.open_order_input_dialog)
|
|
button_layout.addWidget(self.order_input_button)
|
|
|
|
self.template_button = QPushButton("템플릿 관리")
|
|
self.template_button.setToolTip("문자 템플릿을 저장, 불러오기 및 수정")
|
|
self.template_button.clicked.connect(self.open_template_management_dialog)
|
|
button_layout.addWidget(self.template_button)
|
|
|
|
main_layout.addLayout(button_layout)
|
|
|
|
# SMS 발송 건수 표시 (예: "이번달 총 발송건수: X 건")
|
|
self.sms_count_label = QLabel()
|
|
self.sms_count_label.setToolTip("이번달 총 SMS 발송 건수")
|
|
main_layout.addWidget(self.sms_count_label)
|
|
|
|
# 주문 목록 테이블 (열 수를 8로 설정)
|
|
self.order_table = QTableWidget()
|
|
self.order_table.setColumnCount(8)
|
|
self.order_table.setHorizontalHeaderLabels([
|
|
"ID", "상품명", "고객명", "전화번호", "현재단계", "SMS발송여부", "지금발송", "최종 업데이트"
|
|
])
|
|
self.order_table.setToolTip("현재 진행 중인 주문 목록을 표시합니다.")
|
|
main_layout.addWidget(QLabel("주문 목록:"))
|
|
main_layout.addWidget(self.order_table)
|
|
|
|
# 로그 출력 영역
|
|
self.log_display = QTextEdit()
|
|
self.log_display.setReadOnly(True)
|
|
self.log_display.setToolTip("프로그램 로그가 표시됩니다.")
|
|
main_layout.addWidget(QLabel("로그:"))
|
|
main_layout.addWidget(self.log_display)
|
|
|
|
self.logger.log_signal.connect(self.append_log)
|
|
self.order_table.itemChanged.connect(self.item_changed_slot)
|
|
|
|
@Slot(str)
|
|
def append_log(self, message: str):
|
|
self.log_display.append(message)
|
|
|
|
def open_order_input_dialog(self):
|
|
dialog = OrderInputDialog(self.logger, self.db_manager, parent=self)
|
|
if dialog.exec():
|
|
self.refresh_order_list()
|
|
|
|
def open_template_management_dialog(self):
|
|
dialog = TemplateManagementDialog(self.logger, self.db_manager, parent=self)
|
|
dialog.exec()
|
|
|
|
def open_settings_dialog(self):
|
|
dialog = SettingsDialog(self.logger, self.db_manager)
|
|
dialog.exec()
|
|
|
|
def show_help(self):
|
|
dialog = HelpDialog(parent=self)
|
|
dialog.exec()
|
|
|
|
def check_and_reset_sms_count(self):
|
|
"""현재 월과 저장된 월을 비교하여, 달이 변경되었으면 SMS 카운트를 초기화"""
|
|
current_month = datetime.now().strftime("%Y-%m")
|
|
stored_month = self.settings.value("sms_count_month", "")
|
|
if stored_month != current_month:
|
|
# 새로운 달이 시작되었으므로 카운트를 0으로 초기화하고 저장
|
|
self.settings.setValue("sms_count", 0)
|
|
self.settings.setValue("sms_count_month", current_month)
|
|
|
|
def update_sms_count_label(self):
|
|
"""SMS 카운트 라벨 업데이트"""
|
|
count = self.settings.value("sms_count", 0, type=int)
|
|
self.sms_count_label.setText(f"이번달 총 발송건수: {count} 건")
|
|
|
|
def increment_sms_count(self):
|
|
"""SMS 전송 성공 시 카운트를 1 증가시키고 라벨 업데이트"""
|
|
count = self.settings.value("sms_count", 0, type=int)
|
|
count += 1
|
|
self.settings.setValue("sms_count", count)
|
|
self.update_sms_count_label()
|
|
|
|
def refresh_order_list(self):
|
|
orders = self.db_manager.get_all_orders()
|
|
self.order_table.blockSignals(True) # 초기화 시 itemChanged 시그널 방지
|
|
self.order_table.setRowCount(len(orders))
|
|
for row, order in enumerate(orders):
|
|
# ID (편집 불가)
|
|
id_item = QTableWidgetItem(str(order.id))
|
|
id_item.setFlags(id_item.flags() & ~Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 0, id_item)
|
|
|
|
# 상품명 (편집 가능)
|
|
product_item = QTableWidgetItem(order.product_name or "")
|
|
product_item.setFlags(product_item.flags() | Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 1, product_item)
|
|
|
|
# 고객명 (편집 가능)
|
|
name_item = QTableWidgetItem(order.customer_name or "")
|
|
name_item.setFlags(name_item.flags() | Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 2, name_item)
|
|
|
|
# 전화번호 (편집 가능)
|
|
phone_item = QTableWidgetItem(order.customer_phone)
|
|
phone_item.setFlags(phone_item.flags() | Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 3, phone_item)
|
|
|
|
# 현재단계 (편집 가능)
|
|
step_item = QTableWidgetItem(str(order.order_step))
|
|
step_item.setFlags(step_item.flags() | Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 4, step_item)
|
|
|
|
# SMS발송여부 (편집 불가)
|
|
sms_status = "전송 완료" if order.domestic_tracking else "미전송"
|
|
sms_item = QTableWidgetItem(sms_status)
|
|
sms_item.setFlags(sms_item.flags() & ~Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 5, sms_item)
|
|
|
|
# "지금발송" 버튼 (셀 위젯)
|
|
send_btn = QPushButton("지금발송")
|
|
send_btn.setToolTip("SMS를 즉시 전송합니다.")
|
|
# SMS 미전송인 경우에만 버튼 활성화
|
|
send_btn.setEnabled(False if order.domestic_tracking else True)
|
|
# 버튼 클릭 시 해당 주문의 SMS를 전송하는 비동기 함수 호출
|
|
send_btn.clicked.connect(lambda _, o=order: asyncio.create_task(self.send_sms_for_order(o)))
|
|
self.order_table.setCellWidget(row, 6, send_btn)
|
|
|
|
# 최종 업데이트 (편집 불가)
|
|
updated_at_str = order.updated_at.strftime("%Y-%m-%d %H:%M:%S") if order.updated_at else ""
|
|
update_item = QTableWidgetItem(updated_at_str)
|
|
update_item.setFlags(update_item.flags() & ~Qt.ItemIsEditable)
|
|
self.order_table.setItem(row, 7, update_item)
|
|
self.order_table.blockSignals(False)
|
|
|
|
async def send_sms_for_order(self, order):
|
|
"""주문 객체를 인자로 받아 SMS를 전송하는 비동기 함수"""
|
|
recipient = order.customer_phone
|
|
# 실제 템플릿과 주문 데이터를 결합하여 메시지 작성 (여기서는 예시 메시지 사용)
|
|
message = "주문 접수 메시지 예시"
|
|
self.logger.log(f"Order {order.id}: SMS 전송 시도 (받는 사람: {recipient})", level=1)
|
|
result = await self.sms_messenger.send_sms(recipient, message)
|
|
self.logger.log(f"Order {order.id}: SMS 전송 결과: {result}", level=1)
|
|
if result.get("success"):
|
|
# 전송 성공 시 DB 업데이트 및 SMS 발송 카운트 증가
|
|
self.db_manager.update_order(order.id, domestic_tracking="전송 완료")
|
|
self.increment_sms_count()
|
|
self.refresh_order_list()
|
|
|
|
@Slot()
|
|
def item_changed_slot(self, item):
|
|
# 사용자가 셀을 수정한 경우, 수정 내용을 DB에 업데이트합니다.
|
|
row = self.order_table.currentRow()
|
|
if row < 0:
|
|
return
|
|
try:
|
|
order_id = int(self.order_table.item(row, 0).text())
|
|
except Exception:
|
|
return
|
|
customer_name = self.order_table.item(row, 2).text()
|
|
product_name = self.order_table.item(row, 1).text()
|
|
customer_phone = self.order_table.item(row, 3).text()
|
|
order_step_text = self.order_table.item(row, 4).text()
|
|
try:
|
|
order_step = int(order_step_text)
|
|
except ValueError:
|
|
QMessageBox.warning(self, "입력 오류", "진행 단계는 정수 값으로 입력해주세요.")
|
|
return
|
|
updated_order = self.db_manager.update_order(
|
|
order_id,
|
|
customer_name=customer_name,
|
|
product_name=product_name,
|
|
customer_phone=customer_phone,
|
|
order_step=order_step
|
|
)
|
|
QMessageBox.information(self, "저장 확인", f"주문서(ID {order_id})가 수정되었습니다.")
|
|
self.logger.log(
|
|
f"주문서(ID {order_id}) 수정: 고객명={customer_name}, 상품명={product_name}, 전화번호={customer_phone}, 진행단계={order_step}",
|
|
level=1
|
|
)
|
|
|
|
def apply_styles(self):
|
|
style = """
|
|
QMainWindow {
|
|
background-color: #f7f7f7;
|
|
}
|
|
QPushButton {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
border-radius: 6px;
|
|
padding: 8px 16px;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #45a049;
|
|
}
|
|
QTextEdit {
|
|
background-color: white;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
}
|
|
QTableWidget {
|
|
background-color: white;
|
|
border: 1px solid #ccc;
|
|
}
|
|
QMenuBar {
|
|
background-color: #333;
|
|
color: white;
|
|
}
|
|
QMenuBar::item {
|
|
background-color: #333;
|
|
padding: 4px 10px;
|
|
}
|
|
QMenuBar::item:selected {
|
|
background-color: #555;
|
|
}
|
|
QMenu {
|
|
background-color: #444;
|
|
color: white;
|
|
}
|
|
QMenu::item:selected {
|
|
background-color: #666;
|
|
}
|
|
"""
|
|
self.setStyleSheet(style)
|