- 바코드 스캔 → 제품 조회 → 장바구니 → 결제 흐름의 더미 POS GUI 추가 - ESC/POS 영수증 프린터 설정 다이얼로그 추가 - barcode_reader_gui.py dbsetup import 경로 수정 - POS 프린터 config.json 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
223 lines
7.3 KiB
Python
223 lines
7.3 KiB
Python
# pos_settings_dialog.py
|
|
# POS 영수증 프린터 설정 다이얼로그
|
|
|
|
from PyQt5.QtWidgets import (
|
|
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
|
|
QLineEdit, QFormLayout, QMessageBox
|
|
)
|
|
from PyQt5.QtCore import Qt
|
|
import json
|
|
import os
|
|
import socket
|
|
import time
|
|
|
|
|
|
class POSSettingsDialog(QDialog):
|
|
"""POS 영수증 프린터 설정"""
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.config_path = os.path.join(os.path.dirname(__file__), '..', 'config.json')
|
|
self.setWindowTitle("POS 영수증 프린터 설정")
|
|
self.setMinimumSize(500, 300)
|
|
self.init_ui()
|
|
self.load_settings()
|
|
|
|
def init_ui(self):
|
|
layout = QVBoxLayout()
|
|
|
|
# 제목
|
|
title = QLabel("POS 영수증 프린터 설정")
|
|
title.setStyleSheet("font-size: 16px; font-weight: bold; margin-bottom: 10px;")
|
|
layout.addWidget(title)
|
|
|
|
# 설명
|
|
desc = QLabel("ESC/POS 프로토콜을 지원하는 영수증 프린터 설정\n올댓포스 AGENT가 설치된 PC IP를 입력하세요")
|
|
desc.setStyleSheet("color: gray; margin-bottom: 20px;")
|
|
layout.addWidget(desc)
|
|
|
|
# 폼 레이아웃
|
|
form_layout = QFormLayout()
|
|
|
|
# IP 주소
|
|
self.ip_input = QLineEdit()
|
|
self.ip_input.setPlaceholderText("예: 192.168.0.174")
|
|
form_layout.addRow("IP 주소 *", self.ip_input)
|
|
|
|
# 포트
|
|
self.port_input = QLineEdit()
|
|
self.port_input.setText("9100")
|
|
form_layout.addRow("포트", self.port_input)
|
|
|
|
# 프린터 이름
|
|
self.name_input = QLineEdit()
|
|
self.name_input.setPlaceholderText("예: 메인 POS 프린터")
|
|
form_layout.addRow("프린터 이름", self.name_input)
|
|
|
|
layout.addLayout(form_layout)
|
|
|
|
layout.addStretch()
|
|
|
|
# 버튼들
|
|
button_layout = QHBoxLayout()
|
|
|
|
self.test_button = QPushButton("테스트 인쇄")
|
|
self.test_button.clicked.connect(self.test_print)
|
|
self.test_button.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #2196F3;
|
|
color: white;
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #1976D2;
|
|
}
|
|
""")
|
|
button_layout.addWidget(self.test_button)
|
|
|
|
button_layout.addStretch()
|
|
|
|
self.cancel_button = QPushButton("취소")
|
|
self.cancel_button.clicked.connect(self.reject)
|
|
button_layout.addWidget(self.cancel_button)
|
|
|
|
self.save_button = QPushButton("저장")
|
|
self.save_button.clicked.connect(self.save_settings)
|
|
self.save_button.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #45a049;
|
|
}
|
|
""")
|
|
button_layout.addWidget(self.save_button)
|
|
|
|
layout.addLayout(button_layout)
|
|
self.setLayout(layout)
|
|
|
|
def load_settings(self):
|
|
"""설정 불러오기"""
|
|
try:
|
|
if os.path.exists(self.config_path):
|
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
config = json.load(f)
|
|
|
|
pos_config = config.get('pos_printer', {})
|
|
self.ip_input.setText(pos_config.get('ip', ''))
|
|
self.port_input.setText(str(pos_config.get('port', 9100)))
|
|
self.name_input.setText(pos_config.get('name', ''))
|
|
except Exception as e:
|
|
print(f"[POS Settings] 설정 로드 오류: {e}")
|
|
|
|
def save_settings(self):
|
|
"""설정 저장"""
|
|
ip = self.ip_input.text().strip()
|
|
port = self.port_input.text().strip()
|
|
name = self.name_input.text().strip()
|
|
|
|
# 유효성 검사
|
|
if not ip:
|
|
QMessageBox.warning(self, "입력 오류", "IP 주소를 입력해주세요.")
|
|
return
|
|
|
|
try:
|
|
port_num = int(port)
|
|
except ValueError:
|
|
QMessageBox.warning(self, "입력 오류", "포트는 숫자여야 합니다.")
|
|
return
|
|
|
|
# 설정 저장
|
|
try:
|
|
config = {}
|
|
if os.path.exists(self.config_path):
|
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
config = json.load(f)
|
|
|
|
config['pos_printer'] = {
|
|
'ip': ip,
|
|
'port': port_num,
|
|
'name': name if name else f"POS Printer ({ip})"
|
|
}
|
|
|
|
with open(self.config_path, 'w', encoding='utf-8') as f:
|
|
json.dump(config, f, indent=4, ensure_ascii=False)
|
|
|
|
QMessageBox.information(self, "성공", "POS 프린터 설정이 저장되었습니다.")
|
|
self.accept()
|
|
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "오류", f"설정 저장 실패: {str(e)}")
|
|
|
|
def test_print(self):
|
|
"""테스트 인쇄"""
|
|
ip = self.ip_input.text().strip()
|
|
port = self.port_input.text().strip()
|
|
|
|
if not ip:
|
|
QMessageBox.warning(self, "입력 오류", "IP 주소를 입력해주세요.")
|
|
return
|
|
|
|
try:
|
|
port_num = int(port)
|
|
except ValueError:
|
|
QMessageBox.warning(self, "입력 오류", "포트는 숫자여야 합니다.")
|
|
return
|
|
|
|
# ESC/POS 테스트 인쇄
|
|
try:
|
|
# ESC/POS 명령어
|
|
ESC = b'\x1b'
|
|
INIT = ESC + b'@' # 프린터 초기화
|
|
CUT = ESC + b'd\x03' # 용지 커트
|
|
|
|
# 테스트 메시지
|
|
message = f"""
|
|
================================
|
|
POS 프린터 테스트!
|
|
================================
|
|
|
|
IP: {ip}
|
|
Port: {port_num}
|
|
Time: {time.strftime('%Y-%m-%d %H:%M:%S')}
|
|
|
|
ESC/POS 명령으로 인쇄됨
|
|
정상 작동 확인!
|
|
================================
|
|
"""
|
|
|
|
# EUC-KR 인코딩 (한글 지원)
|
|
message_bytes = message.encode('euc-kr')
|
|
command = INIT + message_bytes + b'\n\n\n' + CUT
|
|
|
|
# TCP 소켓으로 전송
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.settimeout(5)
|
|
sock.connect((ip, port_num))
|
|
sock.sendall(command)
|
|
sock.close()
|
|
|
|
QMessageBox.information(
|
|
self, "성공",
|
|
f"테스트 인쇄 명령을 전송했습니다!\n\n"
|
|
f"IP: {ip}:{port_num}\n\n"
|
|
f"POS 프린터에서 영수증 출력을 확인하세요."
|
|
)
|
|
|
|
except socket.timeout:
|
|
QMessageBox.warning(self, "실패", f"연결 시간 초과\n\n프린터가 켜져있는지 확인하세요.")
|
|
except ConnectionRefusedError:
|
|
QMessageBox.warning(self, "실패", f"연결 거부됨\n\nIP 주소와 포트를 확인하세요.")
|
|
except UnicodeEncodeError:
|
|
QMessageBox.warning(self, "인코딩 오류", "EUC-KR로 인코딩할 수 없는 문자가 있습니다.")
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "실패", f"테스트 인쇄 실패\n\n{type(e).__name__}: {str(e)}")
|