수정중

This commit is contained in:
9700X_PC 2025-04-07 22:33:58 +09:00
parent 359b4fcfaa
commit 3b3e0c9e1c
7 changed files with 296 additions and 105 deletions

20
comma_spinBox.py Normal file
View File

@ -0,0 +1,20 @@
from PySide6.QtWidgets import QSpinBox
from PySide6.QtGui import QFont
class CommaSpinBox(QSpinBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 폰트 설정
font = QFont()
font.setPointSize(10) # 폰트 크기 설정
font.setBold(True) # 폰트 굵게 설정
self.setFont(font)
# 스핀박스 설정
self.setRange(0, 1000000)
self.setSingleStep(10000)
def textFromValue(self, value):
"""숫자를 3자리마다 콤마 추가된 형식으로 표시"""
return f"{value:,}"

View File

@ -23,6 +23,7 @@ class PriceHandler:
self.shipping_config = self.price_config.get("shipping_config", {})
self.optimal_price_config = self.price_config.get("optimal_price_config", {})
self.margin_config = self.price_config.get("margin_config", {})
self.is_margin_add_to_shipping_cost = self.price_config.get("margin_add_to_shipping_cost", False)
self.product_costs = []
self.option_data = []
@ -302,6 +303,11 @@ class PriceHandler:
margin = self.round_to_UP(margin)
shipping_cost = self.round_to_UP(shipping_cost)
if self.is_margin_add_to_shipping_cost:
shipping_cost += margin
margin = 0
self.logger.log(f"더하기 마진을 배송비에 포함하여 재계산된 해외배송비: {shipping_cost}", level=logging.DEBUG)
# 더하기 마진 입력 (4번째 인풋박스)
margin_element = await self.page.wait_for_selector(self.plus_margin_locator, timeout=5000)
await margin_element.fill(str(margin))

View File

@ -473,7 +473,7 @@ class KeywordManager(QDialog):
}
# 공통 금지어 로드 (토글이 켜져 있으면)
if self.toggle_common_banned.isChecked():
common_list = self.db_manager.spManager.fetch_common_banned_words_common()
common_list = self.db_manager.fetch_common_banned_words_common()
for record in common_list:
keyword = record["banned_word"]
grade = record["grade"]

View File

@ -1,7 +1,7 @@
from PySide6.QtWidgets import (
QDialog, QTabWidget, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
QTreeWidget, QTreeWidgetItem, QLabel, QLineEdit, QPushButton, QComboBox,
QGroupBox, QMessageBox, QSpinBox, QFileDialog
QGroupBox, QMessageBox, QFileDialog, QApplication, QSpinBox
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QFont, QColor
@ -10,7 +10,8 @@ import math
# 기존 price_DB_Manager 대신 통합된 DBManager 사용
from src.keyword.db_manager import DBManager
from datetime import datetime, timezone
from toggleSwitch import ToggleSwitch
from comma_spinBox import CommaSpinBox
class PriceSettingManager(QDialog):
def __init__(self, parent=None, logger=None, user_id=None, db_path=None, db_manager=None, debug=False):
@ -88,14 +89,14 @@ class PriceSettingManager(QDialog):
shipping_layout = QGridLayout()
shipping_layout.setSpacing(10)
shipping_layout.addWidget(QLabel("상품가"), 0, 0)
self.product_min_price = QSpinBox()
self.product_min_price = CommaSpinBox()
self.product_min_price.setRange(0, 10000000)
self.product_min_price.setValue(20000)
self.product_min_price.setSuffix("")
self.product_min_price.setFixedWidth(50)
shipping_layout.addWidget(self.product_min_price, 0, 1)
shipping_layout.addWidget(QLabel(" 이하시 기본배송비"), 0, 2)
self.spin_min_shipping = QSpinBox()
self.spin_min_shipping = CommaSpinBox()
self.spin_min_shipping.setRange(0, 10000000)
self.spin_min_shipping.setValue(7000)
self.spin_min_shipping.setSuffix("")
@ -105,19 +106,19 @@ class PriceSettingManager(QDialog):
shipping_layout.addWidget(QLabel("1구간 상품가"), 1, 0)
self.spin_threshold1 = QSpinBox()
self.spin_threshold1 = CommaSpinBox()
self.spin_threshold1.setRange(0, 10000000)
self.spin_threshold1.setValue(20000)
self.spin_threshold1.setSuffix("")
shipping_layout.addWidget(self.spin_threshold1, 1, 1)
shipping_layout.addWidget(QLabel("초과시"), 1, 2)
self.spin_increment_unit = QSpinBox()
self.spin_increment_unit = CommaSpinBox()
self.spin_increment_unit.setRange(0, 10000000)
self.spin_increment_unit.setValue(20000)
self.spin_increment_unit.setSuffix("")
shipping_layout.addWidget(self.spin_increment_unit, 1, 3)
shipping_layout.addWidget(QLabel("마다"), 1, 4)
self.spin_add_cost1 = QSpinBox()
self.spin_add_cost1 = CommaSpinBox()
self.spin_add_cost1.setRange(0, 10000000)
self.spin_add_cost1.setValue(7000)
self.spin_add_cost1.setSuffix("")
@ -126,19 +127,19 @@ class PriceSettingManager(QDialog):
shipping_layout.addWidget(QLabel("2구간 상품가"), 2, 0)
self.spin_threshold2 = QSpinBox()
self.spin_threshold2 = CommaSpinBox()
self.spin_threshold2.setRange(0, 10000000)
self.spin_threshold2.setValue(100000)
self.spin_threshold2.setSuffix("")
shipping_layout.addWidget(self.spin_threshold2, 2, 1)
shipping_layout.addWidget(QLabel("초과시"), 2, 2)
self.spin_increment_unit = QSpinBox()
self.spin_increment_unit = CommaSpinBox()
self.spin_increment_unit.setRange(0, 10000000)
self.spin_increment_unit.setValue(20000)
self.spin_increment_unit.setSuffix("")
shipping_layout.addWidget(self.spin_increment_unit, 2, 3)
shipping_layout.addWidget(QLabel("마다"), 2, 4)
self.spin_add_cost2 = QSpinBox()
self.spin_add_cost2 = CommaSpinBox()
self.spin_add_cost2.setRange(0, 10000000)
self.spin_add_cost2.setValue(9000)
self.spin_add_cost2.setSuffix("")
@ -148,19 +149,19 @@ class PriceSettingManager(QDialog):
shipping_layout.addWidget(QLabel("3구간 상품가"), 3, 0)
self.spin_threshold3 = QSpinBox()
self.spin_threshold3 = CommaSpinBox()
self.spin_threshold3.setRange(0, 10000000)
self.spin_threshold3.setValue(200000)
self.spin_threshold3.setSuffix("")
shipping_layout.addWidget(self.spin_threshold3, 3, 1)
shipping_layout.addWidget(QLabel("초과시"), 3, 2)
self.spin_increment_unit = QSpinBox()
self.spin_increment_unit = CommaSpinBox()
self.spin_increment_unit.setRange(0, 10000000)
self.spin_increment_unit.setValue(20000)
self.spin_increment_unit.setSuffix("")
shipping_layout.addWidget(self.spin_increment_unit, 3, 3)
shipping_layout.addWidget(QLabel("마다"), 3, 4)
self.spin_add_cost3 = QSpinBox()
self.spin_add_cost3 = CommaSpinBox()
self.spin_add_cost3.setRange(0, 10000000)
self.spin_add_cost3.setValue(11000)
self.spin_add_cost3.setSuffix("")
@ -175,42 +176,42 @@ class PriceSettingManager(QDialog):
shipping_layout.addWidget(QLabel(" 최종상품가 120,000 + 44,000 = 164,000이 되도록 더하기마진에서 조정"), 9, 0)
# shipping_layout.addWidget(QLabel("임계값 2:"), 2, 0)
# self.spin_threshold2 = QSpinBox()
# self.spin_threshold2 = CommaSpinBox()
# self.spin_threshold2.setRange(0, 10000000)
# self.spin_threshold2.setValue(100000)
# self.spin_threshold2.setSuffix("₩")
# shipping_layout.addWidget(self.spin_threshold2, 2, 1)
# shipping_layout.addWidget(QLabel("임계값 3:"), 3, 0)
# self.spin_threshold3 = QSpinBox()
# self.spin_threshold3 = CommaSpinBox()
# self.spin_threshold3.setRange(0, 10000000)
# self.spin_threshold3.setValue(200000)
# self.spin_threshold3.setSuffix("₩")
# shipping_layout.addWidget(self.spin_threshold3, 3, 1)
# shipping_layout.addWidget(QLabel("배송 단위:"), 4, 0)
# self.spin_increment_unit = QSpinBox()
# self.spin_increment_unit = CommaSpinBox()
# self.spin_increment_unit.setRange(0, 1000000)
# self.spin_increment_unit.setValue(20000)
# self.spin_increment_unit.setSuffix("₩")
# shipping_layout.addWidget(self.spin_increment_unit, 4, 1)
# shipping_layout.addWidget(QLabel("추가 배송비 1:"), 5, 0)
# self.spin_add_cost1 = QSpinBox()
# self.spin_add_cost1 = CommaSpinBox()
# self.spin_add_cost1.setRange(0, 1000000)
# self.spin_add_cost1.setValue(5000)
# self.spin_add_cost1.setSuffix("₩")
# shipping_layout.addWidget(self.spin_add_cost1, 5, 1)
# shipping_layout.addWidget(QLabel("추가 배송비 2:"), 6, 0)
# self.spin_add_cost2 = QSpinBox()
# self.spin_add_cost2 = CommaSpinBox()
# self.spin_add_cost2.setRange(0, 1000000)
# self.spin_add_cost2.setValue(7000)
# self.spin_add_cost2.setSuffix("₩")
# shipping_layout.addWidget(self.spin_add_cost2, 6, 1)
# shipping_layout.addWidget(QLabel("추가 배송비 3:"), 7, 0)
# self.spin_add_cost3 = QSpinBox()
# self.spin_add_cost3 = CommaSpinBox()
# self.spin_add_cost3.setRange(0, 1000000)
# self.spin_add_cost3.setValue(9000)
# self.spin_add_cost3.setSuffix("₩")
@ -222,48 +223,55 @@ class PriceSettingManager(QDialog):
margin_group = QGroupBox("더하기 마진 설정")
margin_layout = QGridLayout()
margin_layout.setSpacing(10)
margin_layout.addWidget(QLabel("마진 임계값 1:"), 0, 0)
self.spin_margin_threshold1 = QSpinBox()
self.spin_margin_threshold1 = CommaSpinBox()
self.spin_margin_threshold1.setRange(0, 10000000)
self.spin_margin_threshold1.setValue(50000)
self.spin_margin_threshold1.setSuffix("")
margin_layout.addWidget(self.spin_margin_threshold1, 0, 1)
margin_layout.addWidget(QLabel("추가 마진 1:"), 0, 2)
self.spin_add_margin1 = QSpinBox()
self.spin_add_margin1 = CommaSpinBox()
self.spin_add_margin1.setRange(0, 1000000)
self.spin_add_margin1.setValue(5000)
self.spin_add_margin1.setSuffix("")
margin_layout.addWidget(self.spin_add_margin1, 0, 3)
margin_layout.addWidget(QLabel("마진 임계값 2:"), 1, 0)
self.spin_margin_threshold2 = QSpinBox()
self.spin_margin_threshold2 = CommaSpinBox()
self.spin_margin_threshold2.setRange(0, 10000000)
self.spin_margin_threshold2.setValue(100000)
self.spin_margin_threshold2.setSuffix("")
margin_layout.addWidget(self.spin_margin_threshold2, 1, 1)
margin_layout.addWidget(QLabel("추가 마진 2:"), 1, 2)
self.spin_add_margin2 = QSpinBox()
self.spin_add_margin2 = CommaSpinBox()
self.spin_add_margin2.setRange(0, 1000000)
self.spin_add_margin2.setValue(7000)
self.spin_add_margin2.setSuffix("")
margin_layout.addWidget(self.spin_add_margin2, 1, 3)
margin_layout.addWidget(QLabel("마진 임계값 3:"), 2, 0)
self.spin_margin_threshold3 = QSpinBox()
self.spin_margin_threshold3 = CommaSpinBox()
self.spin_margin_threshold3.setRange(0, 10000000)
self.spin_margin_threshold3.setValue(200000)
self.spin_margin_threshold3.setSuffix("")
margin_layout.addWidget(self.spin_margin_threshold3, 2, 1)
margin_layout.addWidget(QLabel("추가 마진 3:"), 2, 2)
self.spin_add_margin3 = QSpinBox()
self.spin_add_margin3 = CommaSpinBox()
self.spin_add_margin3.setRange(0, 1000000)
self.spin_add_margin3.setValue(9000)
self.spin_add_margin3.setSuffix("")
margin_layout.addWidget(self.spin_add_margin3, 2, 3)
self.shippingToggleButtonLabel = QLabel("더하기 마진을 배송비에 포함", self)
self.shippingToggleButton = ToggleSwitch(self)
self.shippingToggleButton.clicked.connect(lambda checked: self.on_clicked_shippingToggleButton(checked))
margin_layout.addWidget(self.shippingToggleButtonLabel, 3, 0)
margin_layout.addWidget(self.shippingToggleButton, 3, 1)
margin_group.setLayout(margin_layout)
# === 적정판매가 설정 그룹 ===
@ -271,40 +279,71 @@ class PriceSettingManager(QDialog):
optimal_layout = QGridLayout()
optimal_layout.setSpacing(10)
optimal_layout.addWidget(QLabel("하한 비율 (%):"), 0, 0)
self.spin_lower_bound = QSpinBox()
self.spin_lower_bound = CommaSpinBox()
self.spin_lower_bound.setRange(0, 100)
self.spin_lower_bound.setValue(85) # 85%
self.spin_lower_bound.setSuffix("%")
optimal_layout.addWidget(self.spin_lower_bound, 0, 1)
optimal_layout.addWidget(QLabel("상한 비율 (%):"), 1, 0)
self.spin_upper_bound = QSpinBox()
self.spin_upper_bound = CommaSpinBox()
self.spin_upper_bound.setRange(0, 100)
self.spin_upper_bound.setValue(115) # 115%
self.spin_upper_bound.setSuffix("%")
optimal_layout.addWidget(self.spin_upper_bound, 1, 1)
optimal_layout.addWidget(QLabel("비율 - 팔린가격 (%):"), 2, 0)
self.spin_ratio_sold = QSpinBox()
self.spin_ratio_sold = CommaSpinBox()
self.spin_ratio_sold.setRange(0, 100)
self.spin_ratio_sold.setValue(50)
self.spin_ratio_sold.setSuffix("%")
self.spin_ratio_sold.valueChanged.connect(self.update_percentage_sum)
optimal_layout.addWidget(self.spin_ratio_sold, 2, 1)
optimal_layout.addWidget(QLabel("비율 - 원가2배 (%):"), 3, 0)
self.spin_ratio_cost = QSpinBox()
self.spin_ratio_cost = CommaSpinBox()
self.spin_ratio_cost.setRange(0, 100)
self.spin_ratio_cost.setValue(30)
self.spin_ratio_cost.setSuffix("%")
self.spin_ratio_cost.valueChanged.connect(self.update_percentage_sum)
optimal_layout.addWidget(self.spin_ratio_cost, 3, 1)
optimal_layout.addWidget(QLabel("비율 - 계산가격 (%):"), 4, 0)
self.spin_ratio_calc = QSpinBox()
self.spin_ratio_calc = CommaSpinBox()
self.spin_ratio_calc.setRange(0, 100)
self.spin_ratio_calc.setValue(20)
self.spin_ratio_calc.setSuffix("%")
self.spin_ratio_calc.valueChanged.connect(self.update_percentage_sum)
optimal_layout.addWidget(self.spin_ratio_calc, 4, 1)
# 비율 합계 표시 레이블 추가
self.label_percentage_sum = QLabel("비율 합계가 100%입니다.")
self.label_percentage_sum.setStyleSheet("color: green;")
optimal_layout.addWidget(self.label_percentage_sum, 5, 0, 1, 2) # 5행, 0열, 1행 높이, 2열 너비
# 원가 배수 설정 위젯 추가
optimal_layout.addWidget(QLabel("원가 배수:"), 6, 0)
self.spin_cost_multiplier = QSpinBox()
self.spin_cost_multiplier.setRange(1, 10)
self.spin_cost_multiplier.setValue(2) # 기본값 2배
self.spin_cost_multiplier.setSingleStep(0.5)
optimal_layout.addWidget(self.spin_cost_multiplier, 6, 1)
# 공식 레이블 추가
self.label_formula = QLabel("팔린가격 (50%) + 원가 배수 (2×30%) + 계산가격 (20%) = 결정가격 (100%)")
optimal_layout.addWidget(self.label_formula, 7, 0, 1, 2) # 7행, 0열, 1행 높이, 2열 너비
optimal_group.setLayout(optimal_layout)
# 비율 변경 시 합계 업데이트 이벤트 연결
self.spin_ratio_sold.valueChanged.connect(self.update_percentage_sum)
self.spin_ratio_cost.valueChanged.connect(self.update_percentage_sum)
self.spin_ratio_calc.valueChanged.connect(self.update_percentage_sum)
self.spin_cost_multiplier.valueChanged.connect(self.update_formula_label)
# 초기 합계 계산
self.update_percentage_sum()
optimal_group.setLayout(optimal_layout)
# 탭 하단 저장 버튼
@ -319,6 +358,14 @@ class PriceSettingManager(QDialog):
return widget
def on_clicked_shippingToggleButton(self, checked):
if checked:
self.shippingToggleButtonLabel.setText("더하기 마진을 배송비에 포함")
self.logger.log("배송비에 포함 토글 버튼 클릭", level=logging.DEBUG)
else:
self.shippingToggleButtonLabel.setText("더하기 마진을 배송비에 포함 안함")
self.logger.log("배송비에 포함 안함 토글 버튼 클릭", level=logging.DEBUG)
def update_percentage_sum(self):
total = self.spin_ratio_sold.value() + self.spin_ratio_cost.value() + self.spin_ratio_calc.value()
if total != 100:
@ -392,6 +439,7 @@ class PriceSettingManager(QDialog):
level3_layout.addWidget(QLabel("레벨 3:"))
self.level3_combo = QComboBox()
self.level3_combo.addItem("모두 보기")
self.level3_combo.currentIndexChanged.connect(self.filter_category_tree)
level3_layout.addWidget(self.level3_combo)
# 필터 레이아웃에 추가
@ -401,9 +449,6 @@ class PriceSettingManager(QDialog):
# 버튼 레이아웃 추가
button_layout = QVBoxLayout()
filter_apply_btn = QPushButton("필터 적용")
filter_apply_btn.clicked.connect(self.filter_category_tree)
button_layout.addWidget(filter_apply_btn)
reset_filter_button = QPushButton("필터 초기화")
reset_filter_button.clicked.connect(self.reset_comboboxes)
@ -432,7 +477,12 @@ class PriceSettingManager(QDialog):
self.stage3_filter_btn = QPushButton("3단계만 보기")
self.stage3_filter_btn.clicked.connect(lambda: self.filter_by_stage(3))
button_layout.addWidget(self.stage3_filter_btn)
# 단계 해제 버튼 추가
stage_clear_btn = QPushButton("선택항목 단계해제")
stage_clear_btn.clicked.connect(lambda: self.apply_crmobi_stage(0)) # 0은 미적용 상태
button_layout.addWidget(stage_clear_btn)
reset_db_layout = QHBoxLayout()
db_create_btn = QPushButton("DB 초기화")
db_create_btn.clicked.connect(self.db_manager.create_tables_for_price)
@ -446,33 +496,63 @@ class PriceSettingManager(QDialog):
tree_group = QGroupBox("카테고리 영역")
tree_layout = QVBoxLayout()
self.select_toggle_button = QPushButton("전체 선택")
self.select_toggle_button.clicked.connect(self.toggle_select_all_filtered_items)
tree_layout.addWidget(self.select_toggle_button)
# 일괄 적용 버튼들을 위한 수평 레이아웃
bulk_actions_layout = QHBoxLayout()
# 단계 적용 버튼들
stage1_btn = QPushButton("선택항목 1단계 적용")
stage1_btn.clicked.connect(lambda: self.apply_crmobi_stage(1))
bulk_actions_layout.addWidget(stage1_btn)
stage2_btn = QPushButton("선택항목 2단계 적용")
stage2_btn.clicked.connect(lambda: self.apply_crmobi_stage(2))
bulk_actions_layout.addWidget(stage2_btn)
stage3_btn = QPushButton("선택항목 3단계 적용")
stage3_btn.clicked.connect(lambda: self.apply_crmobi_stage(3))
bulk_actions_layout.addWidget(stage3_btn)
# 단계 해제 버튼 추가
stage_clear_btn = QPushButton("선택항목 단계해제")
stage_clear_btn.clicked.connect(lambda: self.apply_crmobi_stage(0)) # 0은 미적용 상태
bulk_actions_layout.addWidget(stage_clear_btn)
# 금지 토글 버튼
toggle_ban_btn = QPushButton("선택항목 금지토글")
toggle_ban_btn.clicked.connect(self.toggle_banned_flag)
bulk_actions_layout.addWidget(toggle_ban_btn)
tree_layout.addLayout(bulk_actions_layout)
tree_msg_label = QLabel("* 카테고리에 더블 클릭하여 쉽게 CrMoBi 단계나 금지 여부를 변경할 수 있습니다.")
tree_layout.addWidget(tree_msg_label)
# 트리 위젯 설정
self.category_tree = QTreeWidget()
self.category_tree.setHeaderLabels(["ID", "Level1", "Level2", "Level3", "Level4", "CMB 단계", "금지 여부"])
self.category_tree.setAlternatingRowColors(True)
self.category_tree.setStyleSheet("alternate-background-color: #f0f0f0;")
self.category_tree.setSortingEnabled(True)
self.category_tree.setColumnWidth(0, 80) # ID 열 너비 조정
self.category_tree.setColumnWidth(1, 100) # Level1 열 너비 조정
self.category_tree.setColumnWidth(2, 100) # Level2 열 너비 조정
self.category_tree.setColumnWidth(3, 100) # Level3 열 너비 조정
self.category_tree.setColumnWidth(4, 100) # Level4 열 너비 조정
self.category_tree.setColumnWidth(5, 80) # CMB 단계 열 너비 조정
self.category_tree.setColumnWidth(6, 80) # 금지 여부 열 너비 조정
self.category_tree.setColumnWidth(0, 80)
self.category_tree.setColumnWidth(1, 100)
self.category_tree.setColumnWidth(2, 100)
self.category_tree.setColumnWidth(3, 100)
self.category_tree.setColumnWidth(4, 100)
self.category_tree.setColumnWidth(5, 80)
self.category_tree.setColumnWidth(6, 80)
# 헤더 클릭 시 정렬
self.category_tree.header().sectionClicked.connect(self.on_header_clicked)
# 아이템 더블 클릭 이벤트 연결
self.category_tree.itemDoubleClicked.connect(self.on_category_item_double_clicked)
# 스페이스바 이벤트 처리를 위한 키 프레스 이벤트 연결
self.category_tree.keyPressEvent = self.tree_key_press_event
tree_layout.addWidget(self.category_tree)
# 하단에 전체 선택/해제 버튼 추가
bottom_buttons_layout = QHBoxLayout()
self.select_toggle_button = QPushButton("전체 선택")
self.select_toggle_button.clicked.connect(self.toggle_select_all_filtered_items)
bottom_buttons_layout.addWidget(self.select_toggle_button)
tree_layout.addLayout(bottom_buttons_layout)
tree_group.setLayout(tree_layout)
# 왼쪽 레이아웃에 위젯 추가
@ -502,7 +582,7 @@ class PriceSettingManager(QDialog):
stage_layout = QGridLayout()
stage_layout.addWidget(QLabel("최소금액:"), 0, 0)
min_amount_spin = QSpinBox()
min_amount_spin = CommaSpinBox()
min_amount_spin.setRange(1000, 1000000)
min_amount_spin.setSingleStep(1000)
min_amount_spin.setValue(stage * 10000) # 단계별로 다른 기본값
@ -510,7 +590,7 @@ class PriceSettingManager(QDialog):
stage_layout.addWidget(min_amount_spin, 0, 1)
stage_layout.addWidget(QLabel("구간단위:"), 1, 0)
unit_amount_spin = QSpinBox()
unit_amount_spin = CommaSpinBox()
unit_amount_spin.setRange(500, 100000)
unit_amount_spin.setSingleStep(500)
unit_amount_spin.setValue(2000)
@ -518,7 +598,7 @@ class PriceSettingManager(QDialog):
stage_layout.addWidget(unit_amount_spin, 1, 1)
stage_layout.addWidget(QLabel("추가비용:"), 2, 0)
cost_spin = QSpinBox()
cost_spin = CommaSpinBox()
cost_spin.setRange(500, 100000)
cost_spin.setSingleStep(500)
cost_spin.setValue(1000 + stage * 500) # 단계별로 다른 기본값
@ -786,64 +866,82 @@ class PriceSettingManager(QDialog):
def filter_category_tree(self):
self.logger.log("카테고리 필터링", level=logging.DEBUG)
self.logger.log("카테고리 필터링 시작", level=logging.DEBUG)
try:
selected_level1 = self.level1_combo.currentText()
selected_level2 = self.level2_combo.currentText()
selected_level3 = self.level3_combo.currentText()
self.logger.log(f"선택된 필터: 레벨1={selected_level1}, 레벨2={selected_level2}, 레벨3={selected_level3}", level=logging.DEBUG)
# 기본 쿼리 준비
query = "SELECT p_ss_category_code, category1, category2, category3, category4 FROM base_category WHERE 1=1"
args = {}
if selected_level1 != "모두 보기":
# 선택된 필터에 따라 쿼리 조건 추가 (빈 문자열이거나 "모두 보기"가 아닐 때만)
if selected_level1 and selected_level1 != "모두 보기":
query += " AND category1 = :level1"
args["level1"] = selected_level1
if selected_level2 != "모두 보기":
if selected_level2 and selected_level2 != "모두 보기":
query += " AND category2 = :level2"
args["level2"] = selected_level2
if selected_level3 != "모두 보기":
if selected_level3 and selected_level3 != "모두 보기":
query += " AND category3 = :level3"
args["level3"] = selected_level3
# 쿼리 실행하여 데이터 가져오기
self.logger.log(f"실행 쿼리: {query}, 매개변수: {args}", level=logging.DEBUG)
# 쿼리 실행
rows = self.db_manager.fetchall_for_price(query, args)
# 데이터가 비어있는지 확인하고 로그 출력
self.logger.log(f"쿼리 결과 수: {len(rows) if rows else 0}", level=logging.DEBUG)
if not rows:
self.logger.log("필터링 결과가 없습니다.", level=logging.INFO)
self.category_tree.clear() # 트리 위젯 클리어
QMessageBox.information(self, "검색 결과", "해당 조건에 맞는 카테고리가 없습니다.")
return
self.logger.log(f"필터링된 카테고리 수: {len(rows)}", level=logging.DEBUG)
# 다시 user_settings에서 기존 설정을 가져옴
# 사용자 설정 가져오기
user_settings = self.db_manager.get_user_settings_for_price(self.user_id)
cat_settings = {}
if user_settings and "category_settings" in user_settings:
for cs in user_settings["category_settings"]:
cat_settings[cs["p_ss_category_code"]] = cs
# 트리 위젯 초기화
# 트리 위젯 업데이트 전에 메모리 확보를 위해 명시적으로 클리어
self.category_tree.clear()
self.logger.log("트리 위젯 클리어 완료", level=logging.DEBUG)
# 트리 위젯에 결과 추가
for row in rows:
code, cat1, cat2, cat3, cat4 = row
crmobi_stage = "미적용"
banned_flag = "False"
if code in cat_settings:
mapping = {0:"미적용", 1:"1단계", 2:"2단계", 3:"3단계"}
stage_val = cat_settings[code].get("crmobi_stage", 0)
crmobi_stage = mapping.get(stage_val, "미적용")
banned_flag = "True" if cat_settings[code].get("banned_flag", 0)==1 else "False"
banned_flag = "True" if cat_settings[code].get("banned_flag", 0) == 1 else "False"
item = QTreeWidgetItem([code, cat1 or "", cat2 or "", cat3 or "", cat4 or "", crmobi_stage, banned_flag])
item.setCheckState(0, Qt.Unchecked)
# 스타일 적용
self.apply_item_style(item)
self.category_tree.addTopLevelItem(item)
# 업데이트 강제 호출
# UI 갱신 강제 적용
# self.category_tree.update()
self.category_tree.viewport().update()
QApplication.processEvents() # 이벤트 루프 처리
self.logger.log(f"필터링 완료: {len(rows)}개 항목 표시됨", level=logging.DEBUG)
except Exception as e:
QMessageBox.critical(self, "검색 오류", f"카테고리 검색 중 오류 발생: {e}")
self.logger.log(f"카테고리 검색 오류: {e}", level=logging.ERROR, exc_info=True)
QMessageBox.critical(self, "필터링 오류", f"카테고리 필터링 중 오류 발생: {e}")
self.logger.log(f"카테고리 필터링 오류: {e}", level=logging.ERROR, exc_info=True)
import traceback
self.logger.log(f"상세 오류: {traceback.format_exc()}", level=logging.ERROR)
def filter_by_stage(self, stage):
try:
@ -1041,7 +1139,8 @@ class PriceSettingManager(QDialog):
config = {
"shipping_config": shipping_config,
"margin_config": margin_config,
"optimal_price_config": optimal_price_config
"optimal_price_config": optimal_price_config,
"margin_add_to_shipping_cost": self.shippingToggleButton.isChecked()
}
# self.logger.log(f"Price settings retrieved: {config}", level=logging.DEBUG)
return config
@ -1217,11 +1316,28 @@ class PriceSettingManager(QDialog):
"""선택된 항목의 CMB 단계를 변경한 후 전체 설정 저장"""
try:
mapping = {0:"미적용", 1:"1단계", 2:"2단계", 3:"3단계"}
changed_count = 0
for i in range(self.category_tree.topLevelItemCount()):
item = self.category_tree.topLevelItem(i)
if item.checkState(0) == Qt.Checked:
item.setText(5, mapping.get(stage, "미적용"))
self.save_settings()
self.apply_item_style(item)
item.setCheckState(0, Qt.Unchecked)
changed_count += 1
# 전체선택 버튼 텍스트 초기화
self.select_toggle_button.setText("전체 선택")
if changed_count > 0:
self.save_settings()
if stage == 0:
QMessageBox.information(self, "적용 완료", f"{changed_count}개 항목의 CMB 단계가 해제되었습니다.")
else:
QMessageBox.information(self, "적용 완료", f"{changed_count}개 항목에 {mapping.get(stage, '미적용')}이 적용되었습니다.")
else:
QMessageBox.information(self, "알림", "선택된 항목이 없습니다.")
except Exception as e:
QMessageBox.critical(self, "적용 오류", f"CMB 단계 적용 중 오류 발생: {e}")
self.logger.log(f"CMB 단계 적용 오류: {e}", level=logging.ERROR, exc_info=True)
@ -1253,7 +1369,7 @@ class PriceSettingManager(QDialog):
def sync_from_supabase(self):
"""Supabase에서 설정을 가져와 로컬 DB에 저장하고 UI에 반영합니다."""
try:
if self.db_manager and hasattr(self.db_manager, 'spManager') and self.db_manager.spManager:
if self.db_manager:
# Supabase에서 사용자 설정 가져오기
success = self.db_manager.sync_price_settings_from_supabase(self.user_id)
if success:
@ -1352,7 +1468,7 @@ class PriceSettingManager(QDialog):
self.logger.log("설정이 저장되었습니다.", level=logging.INFO)
# Supabase 동기화가 요청된 경우
if sync_to_supabase and self.db_manager and hasattr(self.db_manager, 'spManager') and self.db_manager.spManager:
if sync_to_supabase and self.db_manager:
success = self.db_manager.sync_price_settings_to_supabase(self.user_id)
if success:
self.logger.log("설정이 Supabase에 성공적으로 동기화되었습니다.", level=logging.INFO)
@ -1424,45 +1540,106 @@ class PriceSettingManager(QDialog):
QMessageBox.critical(self, "정렬 오류", f"카테고리 정렬 중 오류가 발생했습니다: {e}")
def on_level1_changed(self, index):
"""레벨 1 콤보박스 변경 시 레벨 2 콤보박스 업데이트"""
"""레벨 1 콤보박스 변경 시 레벨 2 콤보박스 업데이트하고 필터링"""
self.logger.log("레벨 1 콤보박스 변경", level=logging.DEBUG)
try:
# 초기 로딩 시에는 필터링 하지 않음
current_text = self.level1_combo.currentText()
if not current_text: # 빈 문자열이면 초기 로딩으로 간주
return
self.update_level2_combo()
# 레벨 1이 변경되면 레벨 3도 초기화
self.level3_combo.clear()
self.level3_combo.addItem("모두 보기")
# 필터링 즉시 적용 (모두 보기일 때는 전체 데이터 표시)
if current_text != "모두 보기":
self.filter_category_tree()
else:
self.load_category_tree() # 전체 데이터 다시 로드
except Exception as e:
self.logger.log(f"레벨 1 콤보박스 변경 처리 중 오류: {e}", level=logging.ERROR, exc_info=True)
def on_level2_changed(self, index):
"""레벨 2 콤보박스 변경 시 레벨 3 콤보박스 업데이트"""
"""레벨 2 콤보박스 변경 시 레벨 3 콤보박스 업데이트하고 필터링"""
self.logger.log("레벨 2 콤보박스 변경", level=logging.DEBUG)
try:
# 초기 로딩 시에는 필터링 하지 않음
current_text = self.level2_combo.currentText()
if not current_text: # 빈 문자열이면 초기 로딩으로 간주
return
self.update_level3_combo()
# 필터링 즉시 적용 (모두 보기일 때는 상위 레벨의 필터만 적용)
self.filter_category_tree()
except Exception as e:
self.logger.log(f"레벨 2 콤보박스 변경 처리 중 오류: {e}", level=logging.ERROR, exc_info=True)
def tree_key_press_event(self, event):
"""트리 위젯의 키 프레스 이벤트를 처리합니다."""
try:
if event.key() == Qt.Key_Space:
# 현재 선택된 항목들에 대해 체크 상태를 토글
selected_items = self.category_tree.selectedItems()
for item in selected_items:
current_state = item.checkState(0)
new_state = Qt.Checked if current_state == Qt.Unchecked else Qt.Unchecked
item.setCheckState(0, new_state)
else:
# 다른 키 이벤트는 기본 처리로 전달
super(QTreeWidget, self.category_tree).keyPressEvent(event)
except Exception as e:
self.logger.log(f"키 프레스 이벤트 처리 중 오류: {e}", level=logging.ERROR, exc_info=True)
def toggle_banned_flag(self):
"""선택된 항목들의 금지 여부를 토글합니다."""
try:
changed_count = 0
for i in range(self.category_tree.topLevelItemCount()):
item = self.category_tree.topLevelItem(i)
if item.checkState(0) == Qt.Checked:
current_banned = item.text(6)
new_banned = "True" if current_banned == "False" else "False"
item.setText(6, new_banned)
self.apply_item_style(item)
# 체크 상태 해제
item.setCheckState(0, Qt.Unchecked)
changed_count += 1
# 전체선택 버튼 텍스트 초기화
self.select_toggle_button.setText("전체 선택")
if changed_count > 0:
self.save_settings()
QMessageBox.information(self, "적용 완료", f"{changed_count}개 항목의 금지 여부가 변경되었습니다.")
else:
QMessageBox.information(self, "알림", "선택된 항목이 없습니다.")
except Exception as e:
QMessageBox.critical(self, "적용 오류", f"금지 여부 변경 중 오류 발생: {e}")
self.logger.log(f"금지 여부 토글 중 오류: {e}", level=logging.ERROR, exc_info=True)
class CustomSpinBox(QSpinBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# class CustomSpinBox(CommaSpinBox):
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# 폰트 설정
font = QFont()
font.setPointSize(10) # 폰트 크기 설정
font.setBold(True) # 폰트 굵게 설정
self.setFont(font)
# # 폰트 설정
# font = QFont()
# font.setPointSize(10) # 폰트 크기 설정
# font.setBold(True) # 폰트 굵게 설정
# self.setFont(font)
# 스핀박스 설정
self.setRange(0, 1000000)
self.setSingleStep(10000)
# # 스핀박스 설정
# self.setRange(0, 1000000)
# self.setSingleStep(10000)
def textFromValue(self, value):
"""숫자를 3자리마다 콤마 추가된 형식으로 표시"""
return f"{value:,}"
# def textFromValue(self, value):
# """숫자를 3자리마다 콤마 추가된 형식으로 표시"""
# return f"{value:,}"
# if __name__ == "__main__":

View File

@ -93,18 +93,6 @@ class SupabaseManager:
self.logger.log(f"Supabase Kipris 결과 가져오기 실패: {e}", level=logging.ERROR, exc_info=True)
return []
# def fetch_common_banned_words_common(self) -> List[Dict[str, Any]]:
# """
# 공통 금지어 목록을 가져옵니다.
# :return: 공통 금지어 데이터 리스트.
# """
# try:
# response = self.client.table("common_banned_words").select("*").execute()
# return response.data if response.data else []
# except Exception as e:
# self.logger.log(f"fetch_common_banned_words_common 실패: {e}", level=logging.ERROR, exc_info=True)
# return []
def fetch_common_banned_words_common(self) -> List[Dict[str, Any]]:
"""
공통 금지어 목록을 가져오며, 금지어에 대해 관련된 common_banned_words_for_kipris 레코드를 함께 포함합니다.
@ -1048,7 +1036,7 @@ class SupabaseManager:
self.logger.log(f"Push: Found {len(user_banned_words)} user_banned_words to push.", level=logging.INFO)
# 중복 검사를 위해 Supabase에서 기존 금지어 가져오기
response = self.spManager.client.table("user_banned_words").select("word_id,banned_word,user_id").eq("user_id", self.user_id).execute()
response = self.client.table("user_banned_words").select("word_id,banned_word,user_id").eq("user_id", self.user_id).execute()
existing_words = {}
if response.data:
@ -1073,13 +1061,13 @@ class SupabaseManager:
# 새로운 금지어 추가
if new_words:
new_response = self.spManager.client.table("user_banned_words").insert(new_words).execute()
new_response = self.client.table("user_banned_words").insert(new_words).execute()
new_count = len(new_response.data) if new_response.data else 0
self.logger.log(f"Push: Added {new_count} new banned words.", level=logging.INFO)
# 기존 금지어 업데이트
if updated_words:
update_response = self.spManager.client.table("user_banned_words").upsert(updated_words).execute()
update_response = self.client.table("user_banned_words").upsert(updated_words).execute()
update_count = len(update_response.data) if update_response.data else 0
self.logger.log(f"Push: Updated {update_count} existing banned words.", level=logging.INFO)
@ -1120,7 +1108,7 @@ class SupabaseManager:
self.logger.log(f"{len(kipris_data)}개의 Kipris 결과를 Supabase에 동기화합니다", level=logging.INFO)
# Supabase로 동기화
success = self.spManager.sync_kipris_results(kipris_data)
success = self.sync_kipris_results(kipris_data)
if success:
self.logger.log(f"Kipris 결과 {len(kipris_data)}개 동기화 성공", level=logging.INFO)