first commit
This commit is contained in:
commit
a2e3b46cdf
|
|
@ -0,0 +1,12 @@
|
|||
Lib/
|
||||
libs/
|
||||
Scripts/
|
||||
build/
|
||||
dist/
|
||||
Include/
|
||||
__pycache__/
|
||||
*.log
|
||||
*.log.*
|
||||
*.xlsx
|
||||
pyvenv.cfg
|
||||
.ssh/
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
[DEFAULT]
|
||||
max_businesses = 5
|
||||
log_level = DEBUG
|
||||
business_count = 0
|
||||
encryption_key = UDHoVlNcjDeR7ABRyDVr349RAtEUBNMZH5w4cq8g2IM=
|
||||
|
||||
[USER]
|
||||
user_id = leensoo1nt@gmail.com
|
||||
password = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
|
||||
[BUSINESS_1]
|
||||
사업자별칭 = sample_alias_1
|
||||
사업자등록번호 = 123-45-67890
|
||||
상호명 = sample_name_1
|
||||
등록날짜 = 2023-01-01
|
||||
응대전화번호 = 010-1234-5678
|
||||
쿠팡_쿠팡id = gAAAAABmRvruHmgHV1k6kuaWXu_abhE5WcPZxMjW3QKK7jY9Ms3UT1nD0BgpH_ujpnThATcfc4QNhlOTcYpa7PB8psJIr1_BsnTQ4HGUI45VbBPnEoWGglU=
|
||||
쿠팡_업체 코드 = gAAAAABmRvruW5eBP4UAE126L4DRScX9lgspb7ANxG-tdJOYNOg4gXo7F-4Xe-9LnIbjvxjITK0rqoCjJfAK8AaZRrzFohmXpX8MwM44XzMuyayC4WKsTu4=
|
||||
쿠팡_access key = gAAAAABmRvruIlRrsIgwTSsR3fCYMM6G-hYerYMnFkSD050WM9WArprzDJvAjVjxmiLYh6xXDHUxu31wFhJjiFwdcjOcwSvYkx55pAJRN7Crk0Pw80e_Spw=
|
||||
쿠팡_secret key = gAAAAABmRvru_QY05u0XIShzeLHiUWbdbRbW_5ruEPOl-7adaxjQZXOewnOaODi9wDdR2aLQ9dp0UNkIAVWZzq-BYc8ovEQ6I5keVA9mCzCxx8SWbIvst7M=
|
||||
스마트스토어_업로드항 스마트스토어 계정 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
스마트스토어_애플리케이션 id = gAAAAABmRvruEqawY-NssQNcQwEeOcRiGsiV0_QABw0IUhn-su02wAcyQ2X-At2sRla6tBK0HSDVZyGdCrrEIhlvTq_EbFE-HeNi8zaKdbGoPmnMhV5i9OE=
|
||||
스마트스토어_애플리케이션 시크릿 = gAAAAABmRvruf3WXP0dWq9b-ykEu_e2h7V2D9xcDfSyYtXb19u57STPmnabKSrUJeDnCaq23oBBM89vXnGPyIuWSTX5wajNnYLjYY0e_J5Gp-Jon5wv0ICU=
|
||||
옥션지마켓_옥션id = gAAAAABmRvruDCrmyG3EyInh86KIHrZt5JQK0rF8jvt6a3EOMfQCsUxfk7pZkY6xF34DvQmBLmqCcgifH8oBpFqUixE1_OHhQ6RwMcLAnk8ympBbEctGD4g=
|
||||
옥션지마켓_g마켓 id = gAAAAABmRvruJgJvYqzSfSg0YIAAb5h3HQOBUbheMqUYGiNU1fSxVgCCyODezPe-Ejgn4yLNOqmsxLkolyMWJNd5v0QCuqz_SbJPebff9I3tQaXC7pMqO6w=
|
||||
11번가-일반_api key = gAAAAABmRvrurEqGJf086Qs6TJYxIQXuiOV5gytNZ5Z6u7pRjFY9JY2IEMzxG-cg1cGTAv1XF_ilgDCEJmZHYxrlSRfkUdMtrA_uk8u0zjXcnKuoI85S2aE=
|
||||
11번가-글로벌_api key = gAAAAABmRvruI-bQL9A7rB1Z-JzqSQYaXm--wll9GMW-ke0cGLdD5iy_3VatzNGSy9JhOI2He_dF6srQ7EGbre-zfZReeaI1XLJEk-Ze6SL5EKcJ6j7IsLA=
|
||||
롯데온_api key = gAAAAABmRvrumkOok8QyAX4caHgkJDiifOmEpYCGG6zsqysBunDZFzmTd6Zbk_6tWWlyqxdXIQbqCbDPwHSPpM4yF_y8f9QB8gxrTg6bbF3rBzAFChPH-iU=
|
||||
인터파크_상품상태재고수정 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품상태재고수정 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품재고조회 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품재고조회 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품정보조회 인증 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품정보조회 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품수정 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품수정 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품등록 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품등록 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_반품배송지조회 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_반품배송지조회 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_반품배송지등록 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_반품배송지등록 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품qna등록 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품qna등록 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품qna조회 인증키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_상품qna조회 비밀키 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_인터파크 업체번호 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
인터파크_공급계약 일련번호 = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
위메프_api key = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
옥션1.0_api key = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
옥션1.0_멤버 id = gAAAAABmRrpwomEeVDrsgzi7afYKMZg0-B3eS3eZJrZGMTQ_FOebl-Uq2KkY6XByMAtr0hbGX0_ZiOgcIVSrEOf-9q7_Et38mA==
|
||||
alias = 설정사업자없음
|
||||
register_number = 000-00-00000
|
||||
name = 설정사업자없음
|
||||
date = 0000-00-00
|
||||
call = 000-000-0000
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
|
||||
from asyncqt import QEventLoop
|
||||
from ui.main_window import MainWindow
|
||||
from ui.license_dialog import LicenseDialog
|
||||
from utils.config import ConfigManager
|
||||
from utils.logger import setup_logger
|
||||
import asyncio
|
||||
|
||||
def main():
|
||||
config = ConfigManager()
|
||||
log_level = config.get('DEFAULT', 'log_level', fallback='DEBUG')
|
||||
logger = setup_logger(log_level)
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
loop = QEventLoop(app)
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
license_dialog = LicenseDialog()
|
||||
if license_dialog.exec_() == QDialog.Accepted:
|
||||
main_window = MainWindow(config, logger)
|
||||
main_window.show()
|
||||
|
||||
with loop:
|
||||
loop.run_forever()
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
# main.py
|
||||
import sys
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QTextBrowser, QLineEdit, QLabel, QCheckBox,
|
||||
QComboBox, QProgressBar, QWidget, QMessageBox, QTabWidget)
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal
|
||||
from playwright.async_api import async_playwright
|
||||
import configparser
|
||||
import logging
|
||||
import json
|
||||
from cryptography.fernet import Fernet
|
||||
import asyncio
|
||||
|
||||
# 설정 로드 및 저장
|
||||
def load_config():
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
return config
|
||||
|
||||
def save_config(config):
|
||||
with open('config.ini', 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
# 암호화 키 생성 및 로드
|
||||
def generate_key():
|
||||
return Fernet.generate_key()
|
||||
|
||||
def load_key():
|
||||
try:
|
||||
with open("secret.key", "rb") as key_file:
|
||||
return key_file.read()
|
||||
except FileNotFoundError:
|
||||
key = generate_key()
|
||||
with open("secret.key", "wb") as key_file:
|
||||
key_file.write(key)
|
||||
return key
|
||||
|
||||
# 암호화 및 복호화 함수
|
||||
def encrypt_data(data, key):
|
||||
fernet = Fernet(key)
|
||||
return fernet.encrypt(data.encode())
|
||||
|
||||
def decrypt_data(data, key):
|
||||
fernet = Fernet(key)
|
||||
return fernet.decrypt(data).decode()
|
||||
|
||||
# 로그 설정
|
||||
def setup_logging():
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logging.info("Logging setup complete.")
|
||||
|
||||
class LicenseAgreement(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
|
||||
def initUI(self):
|
||||
self.setWindowTitle('License Agreement')
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.licenseText = QTextBrowser()
|
||||
self.licenseText.setPlainText("License Agreement Text Here...")
|
||||
layout.addWidget(self.licenseText)
|
||||
|
||||
self.acceptCheckbox = QCheckBox("I accept the terms and conditions.")
|
||||
self.acceptCheckbox.stateChanged.connect(self.toggleAcceptButton)
|
||||
layout.addWidget(self.acceptCheckbox)
|
||||
|
||||
self.acceptButton = QPushButton("Accept")
|
||||
self.acceptButton.setEnabled(False)
|
||||
self.acceptButton.clicked.connect(self.accept)
|
||||
layout.addWidget(self.acceptButton)
|
||||
|
||||
self.cancelButton = QPushButton("Cancel")
|
||||
self.cancelButton.clicked.connect(self.cancel)
|
||||
layout.addWidget(self.cancelButton)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def toggleAcceptButton(self, state):
|
||||
self.acceptButton.setEnabled(state == Qt.Checked)
|
||||
|
||||
def accept(self):
|
||||
self.accepted = True
|
||||
self.close()
|
||||
|
||||
def cancel(self):
|
||||
self.accepted = False
|
||||
self.close()
|
||||
|
||||
class FetchSettingsThread(QThread):
|
||||
result_ready = pyqtSignal(dict)
|
||||
|
||||
def run(self):
|
||||
asyncio.run(self.fetch_market_settings())
|
||||
|
||||
async def fetch_market_settings(self):
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=False)
|
||||
page = await browser.new_page()
|
||||
await page.goto("https://percenty.co.kr")
|
||||
await page.click(".signList > .ant-btn-default > span")
|
||||
await page.fill(".ant-input:nth-child(4)", "your_username")
|
||||
await page.fill(".ant-input:nth-child(1)", "your_password")
|
||||
await page.click(".ant-btn-primary")
|
||||
|
||||
# 팝업 다이얼로그 닫기
|
||||
try:
|
||||
await page.click('xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary')
|
||||
except:
|
||||
pass
|
||||
|
||||
await page.click('xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]')
|
||||
|
||||
market_data = {}
|
||||
# 각 마켓의 API key를 가져오는 로직
|
||||
markets = {
|
||||
"쿠팡": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[1]",
|
||||
"스마트스토어": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[2]",
|
||||
"옥션지마켓": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[3]",
|
||||
"11번가-일반": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[4]",
|
||||
"11번가-글로벌": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[5]",
|
||||
"롯데온": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[6]",
|
||||
}
|
||||
|
||||
for market, xpath in markets.items():
|
||||
await page.click(f'xpath={xpath}')
|
||||
if market == "쿠팡":
|
||||
market_data[market] = {
|
||||
"쿠팡ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[1]/input', 'value'),
|
||||
"업체코드": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[2]/input', 'value'),
|
||||
"Access Key": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[3]/input', 'value'),
|
||||
"Secret Key": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[4]/input', 'value')
|
||||
}
|
||||
elif market == "스마트스토어":
|
||||
market_data[market] = {
|
||||
"애플리케이션 ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[2]/input', 'value'),
|
||||
"애플리케이션 시크릿": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[3]/input', 'value')
|
||||
}
|
||||
elif market == "옥션지마켓":
|
||||
market_data[market] = {
|
||||
"옥션ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value'),
|
||||
"G마켓ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[2]/input', 'value')
|
||||
}
|
||||
elif market == "11번가-일반":
|
||||
market_data[market] = {
|
||||
"API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[4]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value')
|
||||
}
|
||||
elif market == "11번가-글로벌":
|
||||
market_data[market] = {
|
||||
"API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[5]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value')
|
||||
}
|
||||
elif market == "롯데온":
|
||||
market_data[market] = {
|
||||
"API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[6]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value')
|
||||
}
|
||||
|
||||
await browser.close()
|
||||
self.result_ready.emit(market_data)
|
||||
|
||||
class ChangeBusinessThread(QThread):
|
||||
progress_update = pyqtSignal(int)
|
||||
def __init__(self, market_data):
|
||||
super().__init__()
|
||||
self.market_data = market_data
|
||||
|
||||
def run(self):
|
||||
asyncio.run(self.change_business())
|
||||
|
||||
async def change_business(self):
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=False)
|
||||
page = await browser.new_page()
|
||||
await page.goto("https://percenty.co.kr")
|
||||
await page.click(".signList > .ant-btn-default > span")
|
||||
await page.fill(".ant-input:nth-child(4)", "your_username")
|
||||
await page.fill(".ant-input:nth-child(1)", "your_password")
|
||||
await page.click(".ant-btn-primary")
|
||||
|
||||
# 팝업 다이얼로그 닫기
|
||||
try:
|
||||
await page.click('xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary')
|
||||
except:
|
||||
pass
|
||||
|
||||
await page.click('xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]')
|
||||
|
||||
markets = self.market_data.keys()
|
||||
progress_step = 100 // len(markets)
|
||||
progress = 0
|
||||
|
||||
for market in markets:
|
||||
market_xpath = {
|
||||
"쿠팡": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[1]",
|
||||
"스마트스토어": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[2]",
|
||||
"옥션지마켓": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[3]",
|
||||
"11번가-일반": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[4]",
|
||||
"11번가-글로벌": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[5]",
|
||||
"롯데온": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[6]"
|
||||
}[market]
|
||||
|
||||
await page.click(f'xpath={market_xpath}')
|
||||
data = self.market_data[market]
|
||||
if market == "쿠팡":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[1]/input', data["쿠팡ID"])
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[2]/input', data["업체코드"])
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[3]/input', data["Access Key"])
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[4]/input', data["Secret Key"])
|
||||
elif market == "스마트스토어":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[2]/input', data["애플리케이션 ID"])
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[3]/input', data["애플리케이션 시크릿"])
|
||||
elif market == "옥션지마켓":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[1]/input', data["옥션ID"])
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[2]/input', data["G마켓ID"])
|
||||
elif market == "11번가-일반":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[4]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"])
|
||||
elif market == "11번가-글로벌":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[5]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"])
|
||||
elif market == "롯데온":
|
||||
await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[6]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"])
|
||||
|
||||
progress += progress_step
|
||||
self.progress_update.emit(progress)
|
||||
|
||||
await browser.close()
|
||||
self.progress_update.emit(100)
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
self.config = load_config()
|
||||
self.key = load_key()
|
||||
self.fetch_thread = FetchSettingsThread()
|
||||
self.fetch_thread.result_ready.connect(self.updateStatus)
|
||||
self.load_business_data()
|
||||
|
||||
def initUI(self):
|
||||
self.setWindowTitle('Percenty API Manager')
|
||||
|
||||
mainLayout = QVBoxLayout()
|
||||
|
||||
self.settingButtonLayout = QHBoxLayout()
|
||||
self.currentSettingButton = QPushButton("현재 설정 가져오기")
|
||||
self.saveSettingButton = QPushButton("현재 설정 저장하기")
|
||||
self.currentSettingButton.clicked.connect(self.fetch_current_settings)
|
||||
self.saveSettingButton.clicked.connect(self.save_current_settings)
|
||||
self.settingButtonLayout.addWidget(self.currentSettingButton)
|
||||
self.settingButtonLayout.addWidget(self.saveSettingButton)
|
||||
mainLayout.addLayout(self.settingButtonLayout)
|
||||
|
||||
self.currentStatusLayout = QHBoxLayout()
|
||||
self.statusBox1 = QLabel("사업자 현황")
|
||||
self.statusBox2 = QLabel("마켓 현황")
|
||||
self.statusBox3 = QLabel("빈 박스")
|
||||
self.currentStatusLayout.addWidget(self.statusBox1)
|
||||
self.currentStatusLayout.addWidget(self.statusBox2)
|
||||
self.currentStatusLayout.addWidget(self.statusBox3)
|
||||
mainLayout.addLayout(self.currentStatusLayout)
|
||||
|
||||
self.selectSettingLayout = QVBoxLayout()
|
||||
self.businessDropdown = QComboBox()
|
||||
self.businessDropdown.currentIndexChanged.connect(self.update_market_checkboxes)
|
||||
self.marketCheckboxLayout = QVBoxLayout()
|
||||
self.changeBusinessButton = QPushButton("사업자 바꾸기")
|
||||
self.changeBusinessButton.clicked.connect(self.change_business)
|
||||
self.progressBar = QProgressBar()
|
||||
self.selectSettingLayout.addWidget(self.businessDropdown)
|
||||
self.selectSettingLayout.addLayout(self.marketCheckboxLayout)
|
||||
self.selectSettingLayout.addWidget(self.changeBusinessButton)
|
||||
self.selectSettingLayout.addWidget(self.progressBar)
|
||||
mainLayout.addLayout(self.selectSettingLayout)
|
||||
|
||||
widget = QWidget()
|
||||
widget.setLayout(mainLayout)
|
||||
self.setCentralWidget(widget)
|
||||
|
||||
def load_business_data(self):
|
||||
try:
|
||||
loaded_data = self.config['BUSINESS_DATA']['data']
|
||||
decrypted_data = decrypt_data(loaded_data, self.key)
|
||||
self.business_data = json.loads(decrypted_data)
|
||||
self.update_business_dropdown()
|
||||
except KeyError:
|
||||
self.business_data = {}
|
||||
|
||||
def update_business_dropdown(self):
|
||||
self.businessDropdown.clear()
|
||||
for business_name in self.business_data.keys():
|
||||
self.businessDropdown.addItem(business_name)
|
||||
self.update_market_checkboxes()
|
||||
|
||||
def fetch_current_settings(self):
|
||||
self.fetch_thread.start()
|
||||
|
||||
def save_current_settings(self):
|
||||
encrypted_data = encrypt_data(json.dumps(self.business_data), self.key)
|
||||
self.config['BUSINESS_DATA'] = {'data': encrypted_data}
|
||||
save_config(self.config)
|
||||
QMessageBox.information(self, "Success", "Current settings have been saved.")
|
||||
|
||||
def updateStatus(self, market_data):
|
||||
business_name = self.businessDropdown.currentText()
|
||||
if business_name:
|
||||
self.business_data[business_name]["markets"] = market_data
|
||||
self.update_market_checkboxes()
|
||||
self.statusBox1.setText(f"사업자 현황: {business_name}")
|
||||
self.statusBox2.setText(json.dumps(market_data, indent=4, ensure_ascii=False))
|
||||
|
||||
def update_market_checkboxes(self):
|
||||
business_name = self.businessDropdown.currentText()
|
||||
if not business_name:
|
||||
return
|
||||
|
||||
self.clear_layout(self.marketCheckboxLayout)
|
||||
|
||||
markets = self.business_data[business_name]["markets"]
|
||||
for market, details in markets.items():
|
||||
market_checkbox = QCheckBox(market)
|
||||
market_checkbox.setChecked(details["api_key"] != "")
|
||||
self.marketCheckboxLayout.addWidget(market_checkbox)
|
||||
|
||||
def clear_layout(self, layout):
|
||||
while layout.count():
|
||||
child = layout.takeAt(0)
|
||||
if child.widget():
|
||||
child.widget().deleteLater()
|
||||
|
||||
def change_business(self):
|
||||
business_name = self.businessDropdown.currentText()
|
||||
selected_markets = [checkbox.text() for checkbox in self.findChildren(QCheckBox) if checkbox.isChecked()]
|
||||
|
||||
if business_name:
|
||||
market_data = {market: self.business_data[business_name]["markets"][market] for market in selected_markets}
|
||||
self.change_thread = ChangeBusinessThread(market_data)
|
||||
self.change_thread.progress_update.connect(self.update_progress)
|
||||
self.change_thread.start()
|
||||
|
||||
def update_progress(self, value):
|
||||
self.progressBar.setValue(value)
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_logging()
|
||||
app = QApplication(sys.argv)
|
||||
licenseWindow = LicenseAgreement()
|
||||
licenseWindow.show()
|
||||
app.exec_()
|
||||
|
||||
if licenseWindow.accepted:
|
||||
mainWindow = MainWindow()
|
||||
mainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
@ -0,0 +1 @@
|
|||
-RX8kOGCLzoZz9xxvqB4mh_VULiqV7KLMbdokG7npes=
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTabWidget, QWidget, QFormLayout, QLineEdit, QPushButton, QHBoxLayout, QLabel
|
||||
from utils.config import ConfigManager
|
||||
|
||||
class BusinessSettingsDialog(QDialog):
|
||||
def __init__(self, config: ConfigManager):
|
||||
super().__init__()
|
||||
self.config = config
|
||||
self.setWindowTitle('사업자 설정')
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
self.tab_widget = QTabWidget()
|
||||
|
||||
business_count = int(self.config.get('DEFAULT', 'business_count', fallback='0'))
|
||||
for i in range(business_count):
|
||||
self.add_business_tab(i, load=True)
|
||||
|
||||
layout.addWidget(self.tab_widget)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
add_button = QPushButton('사업자 추가')
|
||||
add_button.clicked.connect(self.add_new_business_tab)
|
||||
save_button = QPushButton('저장')
|
||||
save_button.clicked.connect(self.save_settings)
|
||||
cancel_button = QPushButton('취소')
|
||||
cancel_button.clicked.connect(self.reject)
|
||||
button_layout.addWidget(add_button)
|
||||
button_layout.addWidget(save_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def add_business_tab(self, index, load=False):
|
||||
tab = QWidget()
|
||||
form_layout = QFormLayout()
|
||||
tab.setLayout(form_layout)
|
||||
|
||||
alias = QLineEdit(self)
|
||||
business_number = QLineEdit(self)
|
||||
business_name = QLineEdit(self)
|
||||
registration_date = QLineEdit(self)
|
||||
contact_number = QLineEdit(self)
|
||||
|
||||
if load:
|
||||
alias.setText(self.config.get(f'BUSINESS_{index}', 'alias', fallback=''))
|
||||
business_number.setText(self.config.get(f'BUSINESS_{index}', 'business_number', fallback=''))
|
||||
business_name.setText(self.config.get(f'BUSINESS_{index}', 'business_name', fallback=''))
|
||||
registration_date.setText(self.config.get(f'BUSINESS_{index}', 'registration_date', fallback=''))
|
||||
contact_number.setText(self.config.get(f'BUSINESS_{index}', 'contact_number', fallback=''))
|
||||
|
||||
form_layout.addRow('사업자 별칭:', alias)
|
||||
form_layout.addRow('사업자 등록번호:', business_number)
|
||||
form_layout.addRow('상호명:', business_name)
|
||||
form_layout.addRow('등록 날짜:', registration_date)
|
||||
form_layout.addRow('응대 전화번호:', contact_number)
|
||||
|
||||
self.tab_widget.addTab(tab, f'사업자 {index + 1}')
|
||||
|
||||
def add_new_business_tab(self):
|
||||
business_count = self.tab_widget.count()
|
||||
max_businesses = int(self.config.get('DEFAULT', 'max_businesses', fallback='5'))
|
||||
|
||||
if business_count >= max_businesses:
|
||||
self.show_error_message(f'최대 {max_businesses}개의 사업자만 추가할 수 있습니다.')
|
||||
return
|
||||
|
||||
self.add_business_tab(business_count)
|
||||
|
||||
def show_error_message(self, message):
|
||||
error_dialog = QDialog(self)
|
||||
error_dialog.setWindowTitle('에러')
|
||||
error_layout = QVBoxLayout()
|
||||
error_label = QLabel(message)
|
||||
error_layout.addWidget(error_label)
|
||||
error_button = QPushButton('확인')
|
||||
error_button.clicked.connect(error_dialog.accept)
|
||||
error_layout.addWidget(error_button)
|
||||
error_dialog.setLayout(error_layout)
|
||||
error_dialog.exec_()
|
||||
|
||||
def save_settings(self):
|
||||
business_count = self.tab_widget.count()
|
||||
self.config.set('DEFAULT', 'business_count', str(business_count))
|
||||
|
||||
for i in range(business_count):
|
||||
tab = self.tab_widget.widget(i)
|
||||
form_layout = tab.layout()
|
||||
alias = form_layout.itemAt(0, QFormLayout.FieldRole).widget().text()
|
||||
business_number = form_layout.itemAt(1, QFormLayout.FieldRole).widget().text()
|
||||
business_name = form_layout.itemAt(2, QFormLayout.FieldRole).widget().text()
|
||||
registration_date = form_layout.itemAt(3, QFormLayout.FieldRole).widget().text()
|
||||
contact_number = form_layout.itemAt(4, QFormLayout.FieldRole).widget().text()
|
||||
|
||||
self.config.set(f'BUSINESS_{i}', 'alias', alias)
|
||||
self.config.set(f'BUSINESS_{i}', 'business_number', business_number)
|
||||
self.config.set(f'BUSINESS_{i}', 'business_name', business_name)
|
||||
self.config.set(f'BUSINESS_{i}', 'registration_date', registration_date)
|
||||
self.config.set(f'BUSINESS_{i}', 'contact_number', contact_number)
|
||||
|
||||
self.accept()
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTextBrowser, QPushButton, QHBoxLayout
|
||||
|
||||
class HelpDialog(QDialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle('도움말')
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
help_text = QTextBrowser()
|
||||
help_text.setPlainText('도움말 내용을 여기에 작성합니다.')
|
||||
layout.addWidget(help_text)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
close_button = QPushButton('닫기')
|
||||
close_button.clicked.connect(self.accept)
|
||||
button_layout.addWidget(close_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
self.setLayout(layout)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QCheckBox, QPushButton, QHBoxLayout
|
||||
|
||||
class LicenseDialog(QDialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle('라이센스 동의')
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
license_text = QLabel('라이센스 동의 내용을 여기에 작성합니다.')
|
||||
layout.addWidget(license_text)
|
||||
|
||||
self.agree_checkbox = QCheckBox('동의합니다.')
|
||||
self.agree_checkbox.stateChanged.connect(self.toggle_accept_button)
|
||||
layout.addWidget(self.agree_checkbox)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
self.accept_button = QPushButton('Accept')
|
||||
self.accept_button.setEnabled(False)
|
||||
self.accept_button.clicked.connect(self.accept)
|
||||
cancel_button = QPushButton('Cancel')
|
||||
cancel_button.clicked.connect(self.reject)
|
||||
button_layout.addWidget(self.accept_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def toggle_accept_button(self):
|
||||
self.accept_button.setEnabled(self.agree_checkbox.isChecked())
|
||||
|
|
@ -0,0 +1,509 @@
|
|||
from PyQt5.QtWidgets import (QMainWindow, QAction, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QLabel, QProgressBar, QComboBox, QCheckBox, QTextBrowser, QPlainTextEdit, QDialog, QFrame, QLineEdit,QGridLayout)
|
||||
from PyQt5.QtCore import Qt
|
||||
from ui.percenty_settings import PercentySettingsDialog
|
||||
from ui.business_settings import BusinessSettingsDialog
|
||||
from ui.help_dialog import HelpDialog
|
||||
from utils.playwright_helpers import PlaywrightHelper
|
||||
from utils.config import ConfigManager
|
||||
import asyncio
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, config, logger):
|
||||
super().__init__()
|
||||
self.config = config
|
||||
self.logger = logger
|
||||
self.playwright_helper = PlaywrightHelper()
|
||||
|
||||
self.setWindowTitle('Change-Percenty2')
|
||||
self.setGeometry(100, 100, 450, 800)
|
||||
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
main_layout = QVBoxLayout()
|
||||
|
||||
# 상단의 도움말, 퍼센티 설정, 사업자 설정 메뉴
|
||||
self.create_menu()
|
||||
|
||||
# 메인 레이아웃 설정
|
||||
main_layout.addLayout(self.create_main_layout())
|
||||
|
||||
# 상태 라벨 추가
|
||||
self.status_label = QLabel('현재 상태: 준비 완료')
|
||||
main_layout.addWidget(self.status_label)
|
||||
|
||||
container = QWidget()
|
||||
container.setLayout(main_layout)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
def create_menu(self):
|
||||
menubar = self.menuBar()
|
||||
|
||||
# 도움말 메뉴
|
||||
help_menu = menubar.addMenu('도움말')
|
||||
help_action = QAction('도움말 보기', self)
|
||||
help_action.triggered.connect(self.show_help)
|
||||
help_menu.addAction(help_action)
|
||||
|
||||
# 퍼센티 설정 메뉴
|
||||
percenty_menu = menubar.addMenu('퍼센티 설정')
|
||||
percenty_action = QAction('퍼센티 설정', self)
|
||||
percenty_action.triggered.connect(self.show_percenty_settings)
|
||||
percenty_menu.addAction(percenty_action)
|
||||
|
||||
# 사업자 설정 메뉴
|
||||
business_menu = menubar.addMenu('사업자 설정')
|
||||
business_action = QAction('사업자 설정', self)
|
||||
business_action.triggered.connect(self.show_business_settings)
|
||||
business_menu.addAction(business_action)
|
||||
|
||||
def create_main_layout(self):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# self.top_frame = QFrame(self)
|
||||
# self.top_frame.setFrameShape(QFrame.StyledPanel)
|
||||
# self.top_frame.setFrameShadow(QFrame.Raised)
|
||||
# self.top_layout = QHBoxLayout(self.top_frame)
|
||||
|
||||
# self.middle_frame = QFrame(self)
|
||||
# self.middle_frame.setFrameShape(QFrame.StyledPanel)
|
||||
# self.middle_frame.setFrameShadow(QFrame.Raised)
|
||||
# self.middle_layout = QHBoxLayout(self.middle_frame)
|
||||
|
||||
# self.bottom_frame = QFrame(self)
|
||||
# self.bottom_frame.setFrameShape(QFrame.StyledPanel)
|
||||
# self.bottom_frame.setFrameShadow(QFrame.Raised)
|
||||
# self.bottom_layout = QVBoxLayout(self.bottom_frame)
|
||||
|
||||
|
||||
top_layout = QHBoxLayout()
|
||||
middle_layout = QVBoxLayout()
|
||||
bottom_layout = QVBoxLayout()
|
||||
|
||||
# 상단 레이아웃
|
||||
self.create_top_layout(top_layout)
|
||||
|
||||
# 중단 레이아웃
|
||||
self.create_middle_layout(middle_layout)
|
||||
|
||||
# 하단 레이아웃
|
||||
self.create_bottom_layout(bottom_layout)
|
||||
|
||||
# QFrame으로 감싸고 테두리 설정
|
||||
top_frame = QFrame()
|
||||
top_frame.setLayout(top_layout)
|
||||
top_frame.setFrameShape(QFrame.Box)
|
||||
top_frame.setFrameShadow(QFrame.Raised)
|
||||
|
||||
middle_frame = QFrame()
|
||||
middle_frame.setLayout(middle_layout)
|
||||
middle_frame.setFrameShape(QFrame.Box)
|
||||
middle_frame.setFrameShadow(QFrame.Raised)
|
||||
|
||||
bottom_frame = QFrame()
|
||||
bottom_frame.setLayout(bottom_layout)
|
||||
bottom_frame.setFrameShape(QFrame.Box)
|
||||
bottom_frame.setFrameShadow(QFrame.Raised)
|
||||
|
||||
layout.addWidget(top_frame, 10)
|
||||
layout.addWidget(middle_frame, 60)
|
||||
layout.addWidget(bottom_frame, 30)
|
||||
|
||||
return layout
|
||||
|
||||
|
||||
def create_top_layout(self, layout):
|
||||
self.fetch_button = QPushButton('현재설정 가져오기')
|
||||
self.fetch_button.setMinimumSize(150,50)
|
||||
self.fetch_button.clicked.connect(lambda: asyncio.ensure_future(self.fetch_settings()))
|
||||
layout.addWidget(self.fetch_button)
|
||||
|
||||
self.save_button = QPushButton('현재설정 저장하기')
|
||||
self.save_button.setMinimumSize(150,50)
|
||||
self.save_button.clicked.connect(lambda: asyncio.ensure_future(self.save_settings()))
|
||||
layout.addWidget(self.save_button)
|
||||
|
||||
def create_middle_layout(self, layout):
|
||||
# currentStatusLayout 추가
|
||||
current_status_layout = QVBoxLayout()
|
||||
|
||||
# 첫 번째 박스 (사업자 현황)
|
||||
self.business_info_box = QGridLayout()
|
||||
self.business_info_label = QLabel('현재 사업자 정보(별칭)')
|
||||
self.business_info_label_context = QLineEdit('------')
|
||||
self.business_register_number_label = QLabel('사업자등록번호')
|
||||
self.business_register_number_label_context = QLineEdit('------')
|
||||
self.business_name_label = QLabel('상호명')
|
||||
self.business_name_label_context = QLineEdit('------')
|
||||
self.business_date_label = QLabel('등록날짜')
|
||||
self.business_date_label_context = QLineEdit('------')
|
||||
self.business_call_label = QLabel('전화번호')
|
||||
self.business_call_label_context = QLineEdit('------')
|
||||
self.business_info_box.addWidget(self.business_info_label,1,1,1,2)
|
||||
self.business_info_box.addWidget(self.business_info_label_context,1,3,1,2)
|
||||
self.business_info_box.addWidget(self.business_register_number_label,2,1)
|
||||
self.business_info_box.addWidget(self.business_register_number_label_context,3,1)
|
||||
self.business_info_box.addWidget(self.business_name_label,2,2)
|
||||
self.business_info_box.addWidget(self.business_name_label_context,3,2)
|
||||
self.business_info_box.addWidget(self.business_date_label,2,3)
|
||||
self.business_info_box.addWidget(self.business_date_label_context,3,3)
|
||||
self.business_info_box.addWidget(self.business_call_label,2,4)
|
||||
self.business_info_box.addWidget(self.business_call_label_context,3,4)
|
||||
self.business_info_box.setContentsMargins(10,10,10,10)
|
||||
self.business_info_box.setSpacing(10)
|
||||
|
||||
|
||||
business_frame = QFrame()
|
||||
business_frame.setLayout(self.business_info_box)
|
||||
self.business_call_label.setStyleSheet
|
||||
business_frame.setFrameShape(QFrame.Box)
|
||||
# business_frame.setFrameShadow(QFrame.Plain)
|
||||
# business_frame.setStyleSheet("border: 1px dashed black;")
|
||||
|
||||
current_status_layout.addWidget(business_frame, 30)
|
||||
|
||||
# 두 번째 박스 (마켓 현황)
|
||||
self.market_info_box = QGridLayout()
|
||||
|
||||
self.market_info_label = QLabel('마켓 정보')
|
||||
self.market_info_cc_btn = QPushButton('쿠팡')
|
||||
self.market_info_cc_label = QLabel('------')
|
||||
self.market_info_ss_btn = QPushButton('스스')
|
||||
self.market_info_ss_label = QLabel('------')
|
||||
self.market_info_dm11_btn = QPushButton('11국내')
|
||||
self.market_info_dm11_label = QLabel('------')
|
||||
self.market_info_gb11_btn = QPushButton('11해외')
|
||||
self.market_info_gb11_label = QLabel('------')
|
||||
self.market_info_esm_btn = QPushButton('ESM')
|
||||
self.market_info_esm_label = QLabel('------')
|
||||
self.market_info_lton_btn = QPushButton('롯데온')
|
||||
self.market_info_lton_label = QLabel('------')
|
||||
self.market_info_ip_btn = QPushButton('인터파크')
|
||||
self.market_info_ip_label = QLabel('------')
|
||||
self.market_info_wmp_btn = QPushButton('위메프')
|
||||
self.market_info_wmp_label = QLabel('------')
|
||||
self.market_info_at_btn = QPushButton('옥션1.0')
|
||||
self.market_info_at_label = QLabel('------')
|
||||
|
||||
# self.market_info_cc_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_ss_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_dm11_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_gb11_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_esm_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_lton_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_ip_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_wmp_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
# self.market_info_at_btn.clicked.connect(self.market_info_cc_btn_clicked)
|
||||
|
||||
# def market_info_cc_btn_clicked(self)
|
||||
# pass
|
||||
|
||||
self.market_info_box.addWidget(self.market_info_label,1,1,1,2)
|
||||
self.market_info_box.addWidget(self.market_info_cc_btn,2,1)
|
||||
self.market_info_box.addWidget(self.market_info_cc_label,2,2)
|
||||
self.market_info_box.addWidget(self.market_info_ss_btn,2,3)
|
||||
self.market_info_box.addWidget(self.market_info_ss_label,2,4)
|
||||
self.market_info_box.addWidget(self.market_info_dm11_btn,3,1)
|
||||
self.market_info_box.addWidget(self.market_info_dm11_label,3,2)
|
||||
self.market_info_box.addWidget(self.market_info_gb11_btn,3,3)
|
||||
self.market_info_box.addWidget(self.market_info_gb11_label,3,4)
|
||||
self.market_info_box.addWidget(self.market_info_esm_btn,4,1)
|
||||
self.market_info_box.addWidget(self.market_info_esm_label,4,2)
|
||||
self.market_info_box.addWidget(self.market_info_lton_btn,4,3)
|
||||
self.market_info_box.addWidget(self.market_info_lton_label,4,4)
|
||||
self.market_info_box.addWidget(self.market_info_ip_btn,5,1)
|
||||
self.market_info_box.addWidget(self.market_info_ip_label,5,2)
|
||||
self.market_info_box.addWidget(self.market_info_wmp_btn,5,3)
|
||||
self.market_info_box.addWidget(self.market_info_wmp_label,5,4)
|
||||
self.market_info_box.addWidget(self.market_info_at_btn,6,1)
|
||||
self.market_info_box.addWidget(self.market_info_at_label,6,2)
|
||||
|
||||
market_frame = QFrame()
|
||||
market_frame.setLayout(self.market_info_box)
|
||||
market_frame.setFrameShape(QFrame.Box)
|
||||
|
||||
current_status_layout.addWidget(market_frame, 40)
|
||||
|
||||
# 세 번째 박스 (비어 있음)
|
||||
self.empty_box = QVBoxLayout()
|
||||
|
||||
empty_frame = QFrame()
|
||||
empty_frame.setLayout(self.empty_box)
|
||||
empty_frame.setFrameShape(QFrame.Box)
|
||||
empty_frame.setFrameShadow(QFrame.Plain)
|
||||
empty_frame.setStyleSheet("border: 1px dashed black;")
|
||||
|
||||
current_status_layout.addWidget(empty_frame, 30)
|
||||
|
||||
layout.addLayout(current_status_layout)
|
||||
|
||||
def create_bottom_layout(self, layout):
|
||||
self.business_dropdown = QComboBox()
|
||||
layout.addWidget(self.business_dropdown)
|
||||
|
||||
self.market_checkbox_layout = QGridLayout()
|
||||
layout.addLayout(self.market_checkbox_layout)
|
||||
|
||||
# 체크박스만 추가
|
||||
self.all_checkbox = QCheckBox("전체 체크")
|
||||
self.cp_checkbox = QCheckBox("쿠팡")
|
||||
self.ss_checkbox = QCheckBox("스스")
|
||||
self.st11_dm_checkbox = QCheckBox("11번가-국내")
|
||||
self.st11_gb_checkbox = QCheckBox("11번가-해외")
|
||||
self.esm_checkbox = QCheckBox("ESM")
|
||||
self.lton_checkbox = QCheckBox("롯데온")
|
||||
self.ip_checkbox = QCheckBox("인터파크")
|
||||
self.wmp_checkbox = QCheckBox("위메프")
|
||||
self.at_checkbox = QCheckBox("옥션1.0")
|
||||
self.all_checkbox.stateChanged.connect(self.handle_all_checked)
|
||||
self.market_checkbox_layout.addWidget(self.all_checkbox,1,1)
|
||||
self.market_checkbox_layout.addWidget(self.cp_checkbox,2,1)
|
||||
self.market_checkbox_layout.addWidget(self.ss_checkbox,2,2)
|
||||
self.market_checkbox_layout.addWidget(self.st11_dm_checkbox,2,3)
|
||||
self.market_checkbox_layout.addWidget(self.st11_gb_checkbox,3,1)
|
||||
self.market_checkbox_layout.addWidget(self.esm_checkbox,3,2)
|
||||
self.market_checkbox_layout.addWidget(self.lton_checkbox,3,3)
|
||||
self.market_checkbox_layout.addWidget(self.ip_checkbox,4,1)
|
||||
self.market_checkbox_layout.addWidget(self.wmp_checkbox,4,2)
|
||||
self.market_checkbox_layout.addWidget(self.at_checkbox,4,3)
|
||||
|
||||
self.change_business_button = QPushButton('사업자 바꾸기')
|
||||
self.change_business_button.clicked.connect(lambda: asyncio.ensure_future(self.change_business()))
|
||||
layout.addWidget(self.change_business_button)
|
||||
|
||||
self.progress_bar = QProgressBar(self)
|
||||
self.progress_bar.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
|
||||
def handle_all_checked(self, state):
|
||||
if state == Qt.Checked:
|
||||
self.cp_checkbox.setChecked(True)
|
||||
self.ss_checkbox.setChecked(True)
|
||||
self.st11_dm_checkbox.setChecked(True)
|
||||
self.st11_gb_checkbox.setChecked(True)
|
||||
self.esm_checkbox.setChecked(True)
|
||||
self.lton_checkbox.setChecked(True)
|
||||
self.ip_checkbox.setChecked(True)
|
||||
self.wmp_checkbox.setChecked(True)
|
||||
self.at_checkbox.setChecked(True)
|
||||
|
||||
elif state == Qt.Unchecked:
|
||||
self.cp_checkbox.setChecked(False)
|
||||
self.ss_checkbox.setChecked(False)
|
||||
self.st11_dm_checkbox.setChecked(False)
|
||||
self.st11_gb_checkbox.setChecked(False)
|
||||
self.esm_checkbox.setChecked(False)
|
||||
self.lton_checkbox.setChecked(False)
|
||||
self.ip_checkbox.setChecked(False)
|
||||
self.wmp_checkbox.setChecked(False)
|
||||
self.at_checkbox.setChecked(False)
|
||||
|
||||
async def fetch_settings(self):
|
||||
self.logger.debug("Fetching settings...")
|
||||
self.status_label.setText('현재 상태: 설정 가져오는 중...')
|
||||
self.progress_bar.setValue(0)
|
||||
|
||||
await self.playwright_helper.init_browser()
|
||||
self.progress_bar.setValue(5)
|
||||
user_id = self.config.get('USER', 'user_id')
|
||||
password = self.config.decrypt(self.config.get('USER', 'password'))
|
||||
|
||||
api_keys = await self.playwright_helper.login_and_fetch_api_keys('https://percenty.co.kr', user_id, password, self.status_label, self.progress_bar)
|
||||
print(f"가져온 apikeys\n{api_keys}")
|
||||
|
||||
business_info = self.search_apikeys(api_keys)
|
||||
|
||||
# 가져온 API 키를 UI에 업데이트하는 로직 추가
|
||||
self.update_market_info(api_keys, business_info)
|
||||
self.progress_bar.setValue(100)
|
||||
self.status_label.setText('현재 상태: 설정 가져오기 완료')
|
||||
await self.playwright_helper.close_browser()
|
||||
|
||||
def search_apikeys(self, api_keys):
|
||||
self.status_label.setText('현재 상태: 키 검증하기')
|
||||
|
||||
business_info = {
|
||||
'사업자별칭': '설정사업자없음',
|
||||
'사업자등록번호': '000-00-00000',
|
||||
'상호명': '설정사업자없음',
|
||||
'등록날짜': '0000-00-00',
|
||||
'응대전화번호': '000-000-0000'
|
||||
}
|
||||
|
||||
# max_business = int(self.config.get('DEFAULT', 'max_businesses'))
|
||||
|
||||
all = self.config.get_all_businesses()
|
||||
print(f"사업자 수 : {len(all)}")
|
||||
print(f"all : {all}")
|
||||
|
||||
progress_step = 15 / len(all)
|
||||
|
||||
print(f"progress_step : {progress_step}")
|
||||
|
||||
try:
|
||||
# 저장된 모든 사업자 정보 가져오기
|
||||
|
||||
for business_section in all:
|
||||
print(f"키검증 business_section : {business_section}")
|
||||
stored_api_keys = self.config.get_api_keys(business_section)
|
||||
print(f"키검증 stored_api_keys : {stored_api_keys}")
|
||||
if stored_api_keys and stored_api_keys == api_keys:
|
||||
print("stored_api_keys 존재함")
|
||||
business_info = self.config.get_business_info(business_section)
|
||||
print(f"business_info : {business_info}")
|
||||
break
|
||||
else:
|
||||
print("else")
|
||||
|
||||
print("progress_bar")
|
||||
self.progress_bar.setValue(80 + int(progress_step))
|
||||
self.status_label.setText(f'현재 상태: {business_section} 사업자 가져오기 완료')
|
||||
except Exception as e:
|
||||
print(f"{e}")
|
||||
|
||||
print(f"business_info{business_info}")
|
||||
return business_info
|
||||
|
||||
|
||||
def update_market_info(self, api_keys, business_info):
|
||||
print(f"update_market_info : {api_keys}, {business_info}")
|
||||
|
||||
# 사업자 정보 업데이트
|
||||
self.business_info_label_context.setText(business_info['사업자별칭'])
|
||||
self.business_register_number_label_context.setText(business_info['사업자등록번호'])
|
||||
self.business_name_label_context.setText(business_info['상호명'])
|
||||
self.business_date_label_context.setText(business_info['등록날짜'])
|
||||
self.business_call_label_context.setText(business_info['응대전화번호'])
|
||||
|
||||
# 마켓 정보 업데이트
|
||||
market_buttons = [
|
||||
(self.market_info_cc_btn, '쿠팡', self.market_info_cc_label),
|
||||
(self.market_info_ss_btn, '스스', self.market_info_ss_label),
|
||||
(self.market_info_dm11_btn, '11번가-국내', self.market_info_dm11_label),
|
||||
(self.market_info_gb11_btn, '11번가-해외', self.market_info_gb11_label),
|
||||
(self.market_info_esm_btn, 'ESM', self.market_info_esm_label),
|
||||
(self.market_info_lton_btn, '롯데온', self.market_info_lton_label),
|
||||
(self.market_info_ip_btn, '인터파크', self.market_info_ip_label),
|
||||
(self.market_info_wmp_btn, '위메프', self.market_info_wmp_label),
|
||||
(self.market_info_at_btn, '옥션1.0', self.market_info_at_label),
|
||||
]
|
||||
|
||||
for button, market, label in market_buttons:
|
||||
market_info = api_keys.get(market, None)
|
||||
if market_info:
|
||||
button.setStyleSheet("background-color: lightgreen;")
|
||||
label.setText(business_info['사업자별칭'])
|
||||
else:
|
||||
button.setStyleSheet("background-color: darkgray;")
|
||||
label.setText("NoMatch")
|
||||
|
||||
async def save_settings(self):
|
||||
self.logger.debug("Saving settings...")
|
||||
self.status_label.setText('현재 상태: 설정 저장하는 중...')
|
||||
self.progress_bar.setValue(0)
|
||||
|
||||
# 현재 QLineEdit 값들을 가져와서 사업자 정보 업데이트
|
||||
business_info = {
|
||||
'사업자별칭': self.business_info_label_context.text(),
|
||||
'사업자등록번호': self.business_register_number_label_context.text(),
|
||||
'상호명': self.business_name_label_context.text(),
|
||||
'등록날짜': self.business_date_label_context.text(),
|
||||
'응대전화번호': self.business_call_label_context.text()
|
||||
}
|
||||
|
||||
self.config.set_business_info(1, business_info)
|
||||
|
||||
# 예시 API 키 설정
|
||||
api_keys = {
|
||||
'쿠팡': {
|
||||
'쿠팡ID': 'example_coupang_id',
|
||||
'업체 코드': 'example_company_code',
|
||||
'Access Key': 'example_access_key',
|
||||
'Secret Key': 'example_secret_key'
|
||||
},
|
||||
'스마트스토어': {
|
||||
'애플리케이션 ID': 'example_application_id',
|
||||
'애플리케이션 시크릿': 'example_application_secret'
|
||||
},
|
||||
'옥션지마켓': {
|
||||
'옥션ID': 'example_auction_id',
|
||||
'G마켓 ID': 'example_gmarket_id'
|
||||
},
|
||||
'11번가-일반': {
|
||||
'API KEY': 'example_11st_api_key'
|
||||
},
|
||||
'11번가-글로벌': {
|
||||
'API KEY': 'example_11st_global_api_key'
|
||||
},
|
||||
'롯데온': {
|
||||
'API KEY': 'example_lotteon_api_key'
|
||||
},
|
||||
}
|
||||
|
||||
self.config.set_api_keys(1, api_keys)
|
||||
|
||||
self.progress_bar.setValue(100)
|
||||
self.status_label.setText('현재 상태: 설정 저장 완료')
|
||||
await self.playwright_helper.close_browser()
|
||||
|
||||
async def change_business(self):
|
||||
self.logger.debug("Changing business...")
|
||||
self.status_label.setText('현재 상태: 사업자 변경 중...')
|
||||
self.progress_bar.setValue(0)
|
||||
|
||||
# 사업자 드롭박스에서 선택된 사업자와 마켓 체크박스에서 선택된 마켓 가져오기
|
||||
selected_business = self.business_dropdown.currentText()
|
||||
selected_markets = [checkbox.text() for checkbox in self.market_checkbox_layout.children() if checkbox.isChecked()]
|
||||
|
||||
# 선택된 사업자와 마켓에 따라 API 키 변경 작업 수행
|
||||
await self.playwright_helper.init_browser()
|
||||
user_id = self.config.get('USER', 'user_id')
|
||||
password = self.config.decrypt(self.config.get('USER', 'password'))
|
||||
api_keys = {} # 여기에 새로운 API 키를 설정하는 로직 추가
|
||||
|
||||
await self.playwright_helper.update_api_keys('https://percenty.co.kr', user_id, password, api_keys, self.status_label, self.progress_bar)
|
||||
|
||||
self.progress_bar.setValue(100)
|
||||
self.status_label.setText('현재 상태: 사업자 변경 완료')
|
||||
await self.playwright_helper.close_browser()
|
||||
|
||||
# 작업 완료 창 띄우기
|
||||
self.show_completion_dialog()
|
||||
|
||||
def show_completion_dialog(self):
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle('작업 완료')
|
||||
|
||||
layout = QVBoxLayout()
|
||||
completion_label = QLabel('사업자 변경 작업이 완료되었습니다.')
|
||||
layout.addWidget(completion_label)
|
||||
|
||||
browser_button = QPushButton('브라우저 실행')
|
||||
browser_button.clicked.connect(lambda: asyncio.ensure_future(self.run_browser()))
|
||||
layout.addWidget(browser_button)
|
||||
|
||||
close_button = QPushButton('확인')
|
||||
close_button.clicked.connect(dialog.accept)
|
||||
layout.addWidget(close_button)
|
||||
|
||||
dialog.setLayout(layout)
|
||||
dialog.exec_()
|
||||
|
||||
async def run_browser(self):
|
||||
await self.playwright_helper.init_browser(headless=False)
|
||||
user_id = self.config.get('USER', 'user_id')
|
||||
password = self.config.decrypt(self.config.get('USER', 'password'))
|
||||
await self.playwright_helper.login_and_fetch_api_keys('https://percenty.co.kr', user_id, password)
|
||||
|
||||
def show_help(self):
|
||||
dialog = HelpDialog()
|
||||
dialog.exec_()
|
||||
|
||||
def show_percenty_settings(self):
|
||||
dialog = PercentySettingsDialog(self.config)
|
||||
dialog.exec_()
|
||||
|
||||
def show_business_settings(self):
|
||||
dialog = BusinessSettingsDialog(self.config)
|
||||
dialog.exec_()
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton, QHBoxLayout
|
||||
from utils.config import ConfigManager
|
||||
|
||||
class PercentySettingsDialog(QDialog):
|
||||
def __init__(self, config: ConfigManager):
|
||||
super().__init__()
|
||||
self.config = config
|
||||
self.setWindowTitle('퍼센티 설정')
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.user_id_label = QLabel('사용자 아이디:')
|
||||
self.user_id_input = QLineEdit(self)
|
||||
layout.addWidget(self.user_id_label)
|
||||
layout.addWidget(self.user_id_input)
|
||||
|
||||
self.password_label = QLabel('비밀번호:')
|
||||
self.password_input = QLineEdit(self)
|
||||
self.password_input.setEchoMode(QLineEdit.Password)
|
||||
layout.addWidget(self.password_label)
|
||||
layout.addWidget(self.password_input)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
save_button = QPushButton('저장')
|
||||
save_button.clicked.connect(self.save_settings)
|
||||
cancel_button = QPushButton('취소')
|
||||
cancel_button.clicked.connect(self.reject)
|
||||
button_layout.addWidget(save_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
# 기존 설정 불러오기
|
||||
self.load_settings()
|
||||
|
||||
def load_settings(self):
|
||||
user_id = self.config.get('USER', 'user_id', fallback='')
|
||||
encrypted_password = self.config.get('USER', 'password', fallback='')
|
||||
password = self.config.decrypt(encrypted_password) if encrypted_password else ''
|
||||
|
||||
self.user_id_input.setText(user_id)
|
||||
self.password_input.setText(password)
|
||||
|
||||
def save_settings(self):
|
||||
user_id = self.user_id_input.text()
|
||||
password = self.password_input.text()
|
||||
|
||||
self.config.set('USER', 'user_id', user_id)
|
||||
self.config.set('USER', 'password', self.config.encrypt(password))
|
||||
|
||||
self.accept()
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
import configparser
|
||||
from cryptography.fernet import Fernet, InvalidToken
|
||||
import os
|
||||
|
||||
class ConfigManager:
|
||||
def __init__(self, config_file='config.ini'):
|
||||
self.config_file = config_file
|
||||
self.config = configparser.ConfigParser()
|
||||
self.valid_markets = ['쿠팡', '스마트스토어','옥션지마켓', '11번가-일반','11번가-글로벌', '롯데온','인터파크', '위메프', '옥션1.0'] # 여기에 원하는 마켓 이름을 추가하세요
|
||||
|
||||
if not os.path.exists(config_file):
|
||||
self._create_default_config()
|
||||
|
||||
self.config.read(config_file, encoding='utf-8')
|
||||
|
||||
if 'DEFAULT' not in self.config or 'encryption_key' not in self.config['DEFAULT']:
|
||||
self.key = Fernet.generate_key()
|
||||
self.config['DEFAULT']['encryption_key'] = self.key.decode()
|
||||
with open(self.config_file, 'w') as configfile:
|
||||
self.config.write(configfile)
|
||||
else:
|
||||
self.key = self.config['DEFAULT']['encryption_key'].encode()
|
||||
|
||||
self.cipher_suite = Fernet(self.key)
|
||||
|
||||
def _create_default_config(self):
|
||||
self.config['DEFAULT'] = {
|
||||
'max_businesses': '5',
|
||||
'log_level': 'DEBUG',
|
||||
'business_count': '0',
|
||||
'encryption_key': Fernet.generate_key().decode()
|
||||
}
|
||||
with open(self.config_file, 'w') as configfile:
|
||||
self.config.write(configfile)
|
||||
|
||||
def get(self, section, option, fallback=None):
|
||||
return self.config.get(section, option, fallback=fallback)
|
||||
|
||||
def set(self, section, option, value):
|
||||
if not self.config.has_section(section):
|
||||
self.config.add_section(section)
|
||||
self.config.set(section, option, value)
|
||||
with open(self.config_file, 'w') as configfile:
|
||||
self.config.write(configfile)
|
||||
|
||||
def encrypt(self, data):
|
||||
return self.cipher_suite.encrypt(data.encode()).decode()
|
||||
|
||||
def decrypt(self, encrypted_data):
|
||||
print(f"encrypted_data : {encrypted_data} ")
|
||||
try:
|
||||
print("decrypt Try")
|
||||
result = self.cipher_suite.decrypt(encrypted_data.encode()).decode()
|
||||
print(f"result : {result}")
|
||||
return result
|
||||
except InvalidToken:
|
||||
raise ValueError("Invalid encryption key or corrupted data.")
|
||||
|
||||
def get_business_info(self, business_section):
|
||||
|
||||
if not self.config.has_section(business_section):
|
||||
print(f"{business_section} : 해당 섹션이 없음")
|
||||
return None
|
||||
print(f"business_section : {business_section}")
|
||||
print(f"self.config.get(business_section, '사업자별칭', fallback='설정사업자없음') \n {self.config.get(business_section, '사업자별칭', fallback='설정사업자없음')}")
|
||||
|
||||
business_info = {
|
||||
'사업자별칭': self.config.get(business_section, '사업자별칭', fallback='설정사업자없음'),
|
||||
'사업자등록번호': self.config.get(business_section, '사업자등록번호', fallback='000-00-00000'),
|
||||
'상호명': self.config.get(business_section, '상호명', fallback='설정사업자없음'),
|
||||
'등록날짜': self.config.get(business_section, '등록날짜', fallback='0000-00-00'),
|
||||
'응대전화번호': self.config.get(business_section, '응대전화번호', fallback='000-000-0000')
|
||||
}
|
||||
return business_info
|
||||
|
||||
def set_business_info(self, business_id, business_info):
|
||||
business_section = f'BUSINESS_{business_id}'
|
||||
self.set(business_section, 'alias', business_info['사업자별칭'])
|
||||
self.set(business_section, 'register_number', business_info['사업자등록번호'])
|
||||
self.set(business_section, 'name', business_info['상호명'])
|
||||
self.set(business_section, 'date', business_info['등록날짜'])
|
||||
self.set(business_section, 'call', business_info['응대전화번호'])
|
||||
|
||||
def get_all_businesses(self):
|
||||
businesses = []
|
||||
for section in self.config.sections():
|
||||
if section.startswith('BUSINESS_'):
|
||||
businesses.append(section)
|
||||
return businesses
|
||||
|
||||
def get_api_keys(self, business_section):
|
||||
print("get_api_keys")
|
||||
print(f"business_section : {business_section}")
|
||||
if not self.config.has_section(business_section):
|
||||
print("business_section이 존재하지 않음")
|
||||
return {}
|
||||
|
||||
api_keys = {}
|
||||
for key in self.config.options(business_section):
|
||||
print(f"key : {key}")
|
||||
market_name = key.split('_', 1)[0]
|
||||
print(f"market_name : {market_name}")
|
||||
if market_name in self.valid_markets and '_' in key:
|
||||
market, key_name = key.split('_', 1)
|
||||
print(f"market : {market}")
|
||||
print(f"key_name : {key_name}")
|
||||
if market not in api_keys:
|
||||
api_keys[market] = {}
|
||||
print("market not in api_keys, 마켓생성")
|
||||
encrypted_value = self.config.get(business_section, key)
|
||||
print(f"encrypted_value : {encrypted_value}")
|
||||
if encrypted_value:
|
||||
try:
|
||||
decrypted_value = self.decrypt(encrypted_value)
|
||||
print(f"decrypted_value : {decrypted_value}")
|
||||
api_keys[market][key_name] = decrypted_value
|
||||
except Exception as e:
|
||||
print(f"Decryption failed for key {key}: {e}")
|
||||
api_keys[market][key_name] = ''
|
||||
else:
|
||||
api_keys[market][key_name] = ''
|
||||
print(f"Empty value for key {key}, setting as empty string")
|
||||
|
||||
print(f"최종 api_keys: {api_keys}")
|
||||
return api_keys
|
||||
|
||||
|
||||
def get_api_keys_2(self, business_id):
|
||||
section = f'API_KEYS_{business_id}'
|
||||
if not self.config.has_section(section):
|
||||
return None
|
||||
return {
|
||||
'쿠팡': {
|
||||
'쿠팡ID': self.get(section, 'coupang_coupangid', ''),
|
||||
'업체 코드': self.get(section, 'coupang_업체_코드', ''),
|
||||
'Access Key': self.get(section, 'coupang_access_key', ''),
|
||||
'Secret Key': self.get(section, 'coupang_secret_key', '')
|
||||
},
|
||||
'스마트스토어': {
|
||||
'업로드항 스마트스토어 계정': self.get(section, 'ss_업로드항_스마트스토어_계정', ''),
|
||||
'애플리케이션 ID': self.get(section, 'ss_application_id', ''),
|
||||
'애플리케이션 시크릿': self.get(section, 'ss_application_secret', '')
|
||||
},
|
||||
'옥션지마켓': {
|
||||
'옥션ID': self.get(section, 'esm_auction_id', ''),
|
||||
'G마켓 ID': self.get(section, 'esm_gmarket_id', '')
|
||||
},
|
||||
'11번가-일반': {
|
||||
'API KEY': self.get(section, 'est_api_key', '')
|
||||
},
|
||||
'11번가-글로벌': {
|
||||
'API KEY': self.get(section, 'est_global_api_key', '')
|
||||
},
|
||||
'롯데온': {
|
||||
'API KEY': self.get(section, 'lotteon_api_key', '')
|
||||
},
|
||||
'인터파크': {
|
||||
'상품상태재고수정 인증키': self.get(section, 'ip_product_status_inventory_update_auth_key', ''),
|
||||
'상품상태재고수정 비밀키': self.get(section, 'ip_product_status_inventory_update_secret_key', ''),
|
||||
'상품재고조회 인증키': self.get(section, 'ip_product_inventory_check_auth_key', ''),
|
||||
'상품재고조회 비밀키': self.get(section, 'ip_product_inventory_check_secret_key', ''),
|
||||
'상품정보조회 인증': self.get(section, 'ip_product_info_check_auth_key', ''),
|
||||
'상품정보조회 비밀키': self.get(section, 'ip_product_info_check_secret_key', ''),
|
||||
'상품수정 인증키': self.get(section, 'ip_product_update_auth_key', ''),
|
||||
'상품수정 비밀키': self.get(section, 'ip_product_update_secret_key', ''),
|
||||
'상품등록 인증키': self.get(section, 'ip_product_register_auth_key', ''),
|
||||
'상품등록 비밀키': self.get(section, 'ip_product_register_secret_key', ''),
|
||||
'반품배송지조회 인증키': self.get(section, 'ip_return_address_check_auth_key', ''),
|
||||
'반품배송지조회 비밀키': self.get(section, 'ip_return_address_check_secret_key', ''),
|
||||
'반품배송지등록 인증키': self.get(section, 'ip_return_address_register_auth_key', ''),
|
||||
'반품배송지등록 비밀키': self.get(section, 'ip_return_address_register_secret_key', ''),
|
||||
'상품QnA등록 인증키': self.get(section, 'ip_product_qna_register_auth_key', ''),
|
||||
'상품QnA등록 비밀키': self.get(section, 'ip_product_qna_register_secret_key', ''),
|
||||
'상품QnA조회 인증키': self.get(section, 'ip_product_qna_check_auth_key', ''),
|
||||
'상품QnA조회 비밀키': self.get(section, 'ip_product_qna_check_secret_key', ''),
|
||||
'인터파크 업체번호': self.get(section, 'ip_interpark_company_number', ''),
|
||||
'공급계약 일련번호': self.get(section, 'ip_supply_contract_serial_number', '')
|
||||
},
|
||||
'위메프': {
|
||||
'API KEY': self.get(section, 'wmp_api_key', '')
|
||||
},
|
||||
'옥션1.0': {
|
||||
'API KEY': self.get(section, 'at_api_key', ''),
|
||||
'멤버 ID': self.get(section, 'at_member_id', '')
|
||||
}
|
||||
}
|
||||
|
||||
def set_api_keys(self, business_id, api_keys):
|
||||
business_section = f'BUSINESS_{business_id}'
|
||||
if not self.config.has_section(business_section):
|
||||
self.config.add_section(business_section)
|
||||
|
||||
for market, keys in api_keys.items():
|
||||
for key_name, key_value in keys.items():
|
||||
encrypted_value = self.encrypt(key_value)
|
||||
self.config.set(business_section, f'{market}_{key_name}', encrypted_value)
|
||||
|
||||
with open(self.config_file, 'w') as configfile:
|
||||
self.config.write(configfile)
|
||||
|
||||
|
||||
def reset_settings(self):
|
||||
if os.path.exists(self.config_file):
|
||||
os.remove(self.config_file)
|
||||
self._create_default_config()
|
||||
self.config.read(self.config_file)
|
||||
|
||||
def get_user_info(self):
|
||||
user_id = self.get('USER', 'user_id', fallback='')
|
||||
encrypted_password = self.get('USER', 'password', fallback='')
|
||||
password = self.decrypt(encrypted_password) if encrypted_password else ''
|
||||
return user_id, password
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from loguru import logger
|
||||
import sys
|
||||
|
||||
def setup_logger(log_level="DEBUG"):
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level=log_level)
|
||||
logger.add("app.log", level=log_level, rotation="10 MB", retention="10 days")
|
||||
return logger
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
from playwright.async_api import async_playwright
|
||||
|
||||
class PlaywrightHelper:
|
||||
def __init__(self):
|
||||
self.browser = None
|
||||
|
||||
async def init_browser(self):
|
||||
playwright = await async_playwright().start()
|
||||
self.browser = await playwright.chromium.launch(headless=False)
|
||||
|
||||
async def close_browser(self):
|
||||
if self.browser:
|
||||
await self.browser.close()
|
||||
|
||||
async def login_and_fetch_api_keys(self, url, username, password, status_label, progress_bar):
|
||||
context = await self.browser.new_context()
|
||||
page = await context.new_page()
|
||||
await page.goto(url)
|
||||
progress_bar.setValue(10)
|
||||
status_label.setText('현재 상태: 웹페이지 접속완료')
|
||||
|
||||
# 홈 페이지에서 로그인 버튼 클릭
|
||||
await page.click(".signList > .ant-btn-default > span")
|
||||
|
||||
# 로그인 페이지에서 로그인 수행
|
||||
await page.fill(".ant-input:nth-child(4)", username)
|
||||
await page.fill(".ant-input:nth-child(1)", password)
|
||||
await page.click(".ant-btn-primary")
|
||||
|
||||
progress_bar.setValue(20)
|
||||
status_label.setText('현재 상태: 퍼센티 로그인 완료')
|
||||
|
||||
|
||||
# 팝업 다이얼로그 닫기 (있는 경우)
|
||||
try:
|
||||
await page.click("xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary")
|
||||
except:
|
||||
pass
|
||||
|
||||
# 마켓 설정 페이지로 이동
|
||||
await page.click("xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]")
|
||||
# await page.click("div#root li.ant-menu-item.ant-menu-item-selected.ant-menu-item-only-child > span")
|
||||
|
||||
progress_bar.setValue(30)
|
||||
status_label.setText('현재 상태: 마켓 설정')
|
||||
|
||||
api_keys = {}
|
||||
|
||||
# 각 마켓별 API 키 가져오기
|
||||
async def fetch_market_api_keys(market_xpath, api_key_xpaths):
|
||||
await page.click(market_xpath)
|
||||
await page.wait_for_timeout(1000) # 잠시 대기
|
||||
return {key: await page.get_attribute(xpath, 'value') for key, xpath in api_key_xpaths.items()}
|
||||
|
||||
api_key_xpaths = {
|
||||
'쿠팡': {
|
||||
'쿠팡ID': "div#rc-tabs-0-panel-cp div:nth-child(1) > input",
|
||||
'업체 코드': "div#rc-tabs-0-panel-cp div:nth-child(2) > input",
|
||||
'Access Key': "div#rc-tabs-0-panel-cp div:nth-child(3) > input",
|
||||
'Secret Key': "div#rc-tabs-0-panel-cp div:nth-child(4) > input",
|
||||
},
|
||||
'스마트스토어': {
|
||||
'업로드항 스마트스토어 계정' : "div#rc-tabs-0-panel-ss div:nth-child(1) > input",
|
||||
'애플리케이션 ID': "div#rc-tabs-0-panel-ss div:nth-child(3) > input",
|
||||
'애플리케이션 시크릿': "div#rc-tabs-0-panel-ss div:nth-child(3) > input",
|
||||
},
|
||||
'옥션지마켓': {
|
||||
'옥션ID': "div#rc-tabs-0-panel-esm div:nth-child(1) > input",
|
||||
'G마켓 ID': "div#rc-tabs-0-panel-esm div:nth-child(2) > input",
|
||||
},
|
||||
'11번가-일반': {
|
||||
'API KEY': "div#rc-tabs-0-panel-est input",
|
||||
},
|
||||
'11번가-글로벌': {
|
||||
'API KEY': "div#rc-tabs-0-panel-est_global input",
|
||||
},
|
||||
'롯데온': {
|
||||
'API KEY': "div#rc-tabs-0-panel-lotteon input",
|
||||
},
|
||||
'인터파크': {
|
||||
'상품상태재고수정 인증키': "div#rc-tabs-0-panel-ip div:nth-child(1) > input",
|
||||
'상품상태재고수정 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(2) > input",
|
||||
'상품재고조회 인증키':"div#rc-tabs-0-panel-ip div:nth-child(3) > input",
|
||||
'상품재고조회 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(4) > input",
|
||||
'상품정보조회 인증':"div#rc-tabs-0-panel-ip div:nth-child(6) > input",
|
||||
'상품정보조회 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(7) > input",
|
||||
'상품수정 인증키':"div#rc-tabs-0-panel-ip div:nth-child(8) > input",
|
||||
'상품수정 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(9) > input",
|
||||
'상품등록 인증키':"div#rc-tabs-0-panel-ip div:nth-child(11) > input",
|
||||
'상품등록 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(12) > input",
|
||||
'반품배송지조회 인증키':"div#rc-tabs-0-panel-ip div:nth-child(13) > input",
|
||||
'반품배송지조회 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(14) > input",
|
||||
'반품배송지등록 인증키':"div#rc-tabs-0-panel-ip div:nth-child(16) > input",
|
||||
'반품배송지등록 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(17) > input",
|
||||
'상품QnA등록 인증키':"div#rc-tabs-0-panel-ip div:nth-child(18) > input",
|
||||
'상품QnA등록 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(19) > input",
|
||||
'상품QnA조회 인증키':"div#rc-tabs-0-panel-ip div:nth-child(21) > input",
|
||||
'상품QnA조회 비밀키':"div#rc-tabs-0-panel-ip div:nth-child(22) > input",
|
||||
'인터파크 업체번호':"div#rc-tabs-0-panel-ip div:nth-child(23) > input",
|
||||
'공급계약 일련번호':"div#rc-tabs-0-panel-ip div:nth-child(24) > input",
|
||||
},
|
||||
'위메프': {
|
||||
'API KEY': "div#rc-tabs-0-panel-wmp input",
|
||||
},
|
||||
'옥션1.0': {
|
||||
'API KEY': "div#rc-tabs-0-panel-at div:nth-child(1) > input",
|
||||
'멤버 ID': "div#rc-tabs-0-panel-at div:nth-child(2) > input",
|
||||
},
|
||||
}
|
||||
|
||||
api_keys['쿠팡'] = await fetch_market_api_keys("div#rc-tabs-0-tab-cp", api_key_xpaths['쿠팡'])
|
||||
# print(f"api_keys['쿠팡'] \n {api_keys['쿠팡']}")
|
||||
progress_bar.setValue(35)
|
||||
status_label.setText('현재 상태: 쿠팡 가져오기 완료')
|
||||
api_keys['스마트스토어'] = await fetch_market_api_keys("div#rc-tabs-0-tab-ss", api_key_xpaths['스마트스토어'])
|
||||
# print(f"api_keys['스마트스토어'] \n {api_keys['스마트스토어']}")
|
||||
progress_bar.setValue(40)
|
||||
status_label.setText('현재 상태: 스마트스토어 가져오기 완료')
|
||||
api_keys['옥션지마켓'] = await fetch_market_api_keys("div#rc-tabs-0-tab-esm", api_key_xpaths['옥션지마켓'])
|
||||
# print(f"api_keys['옥션지마켓'] \n {api_keys['옥션지마켓']}")
|
||||
progress_bar.setValue(45)
|
||||
status_label.setText('현재 상태: ESM 가져오기 완료')
|
||||
api_keys['11번가-일반'] = await fetch_market_api_keys("div#rc-tabs-0-tab-est", api_key_xpaths['11번가-일반'])
|
||||
# print(f"api_keys['11번가-일반'] \n {api_keys['11번가-일반']}")
|
||||
progress_bar.setValue(50)
|
||||
status_label.setText('현재 상태: 11번가 국내 가져오기 완료')
|
||||
api_keys['11번가-글로벌'] = await fetch_market_api_keys("div#rc-tabs-0-tab-est_global", api_key_xpaths['11번가-글로벌'])
|
||||
# print(f"api_keys['11번가-글로벌'] \n {api_keys['11번가-글로벌']}")
|
||||
progress_bar.setValue(55)
|
||||
status_label.setText('현재 상태: 11번가 글로벌 가져오기 완료')
|
||||
api_keys['롯데온'] = await fetch_market_api_keys("div#rc-tabs-0-tab-lotteon", api_key_xpaths['롯데온'])
|
||||
# print(f"api_keys['롯데온'] \n {api_keys['롯데온']}")
|
||||
progress_bar.setValue(60)
|
||||
status_label.setText('현재 상태: 롯데온 가져오기 완료')
|
||||
api_keys['인터파크'] = await fetch_market_api_keys("div#rc-tabs-0-tab-ip", api_key_xpaths['인터파크'])
|
||||
# print(f"api_keys['인터파크'] \n {api_keys['인터파크']}")
|
||||
progress_bar.setValue(65)
|
||||
status_label.setText('현재 상태: 인터파크 가져오기 완료')
|
||||
api_keys['위메프'] = await fetch_market_api_keys("div#rc-tabs-0-tab-wmp", api_key_xpaths['위메프'])
|
||||
# print(f"api_keys['위메프'] \n {api_keys['위메프']}")
|
||||
progress_bar.setValue(70)
|
||||
status_label.setText('현재 상태: 위메프 가져오기 완료')
|
||||
api_keys['옥션1.0'] = await fetch_market_api_keys("div#rc-tabs-0-tab-at", api_key_xpaths['옥션1.0'])
|
||||
# print(f"api_keys['옥션1.0'] \n {api_keys['옥션1.0']}")
|
||||
progress_bar.setValue(75)
|
||||
status_label.setText('현재 상태: 옥션1.0 가져오기 완료')
|
||||
|
||||
await context.close()
|
||||
return api_keys
|
||||
|
||||
async def update_api_keys(self, url, username, password, api_keys, status_label, progress_bar):
|
||||
context = await self.browser.new_context()
|
||||
page = await context.new_page()
|
||||
await page.goto(url)
|
||||
|
||||
# 홈 페이지에서 로그인 버튼 클릭
|
||||
await page.click(".signList > .ant-btn-default > span")
|
||||
|
||||
# 로그인 페이지에서 로그인 수행
|
||||
await page.fill(".ant-input:nth-child(4)", username)
|
||||
await page.fill(".ant-input:nth-child(1)", password)
|
||||
await page.click(".ant-btn-primary")
|
||||
|
||||
# 팝업 다이얼로그 닫기 (있는 경우)
|
||||
try:
|
||||
await page.click("xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary")
|
||||
except:
|
||||
pass
|
||||
|
||||
# 마켓 설정 페이지로 이동
|
||||
await page.click("xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]")
|
||||
# await page.click("div#root li.ant-menu-item.ant-menu-item-selected.ant-menu-item-only-child > span")
|
||||
|
||||
# 각 마켓별 API 키 업데이트
|
||||
async def update_market_api_keys(market_xpath, api_key_xpaths):
|
||||
await page.click(market_xpath)
|
||||
await page.wait_for_timeout(1000) # 잠시 대기
|
||||
for key, value in api_key_xpaths.items():
|
||||
await page.fill(value, api_keys.get(key, ''))
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-cp", api_keys['쿠팡'])
|
||||
progress_bar.setValue(35)
|
||||
status_label.setText('현재 상태: 쿠팡 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-ss", api_keys['스마트스토어'])
|
||||
progress_bar.setValue(40)
|
||||
status_label.setText('현재 상태: 스마트스토어 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-esm", api_keys['옥션지마켓'])
|
||||
progress_bar.setValue(45)
|
||||
status_label.setText('현재 상태: ESM 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-est", api_keys['11번가-일반'])
|
||||
progress_bar.setValue(50)
|
||||
status_label.setText('현재 상태: 11번가 국내 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-est_global", api_keys['11번가-글로벌'])
|
||||
progress_bar.setValue(55)
|
||||
status_label.setText('현재 상태: 11번가 글로벌 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-lotteon", api_keys['롯데온'])
|
||||
progress_bar.setValue(60)
|
||||
status_label.setText('현재 상태: 롯데온 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-ip", api_keys['인터파크'])
|
||||
progress_bar.setValue(65)
|
||||
status_label.setText('현재 상태: 인터파크 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-wmp", api_keys['위메프'])
|
||||
progress_bar.setValue(70)
|
||||
status_label.setText('현재 상태: 위메프 업데이트 완료')
|
||||
|
||||
await update_market_api_keys("div#rc-tabs-0-tab-at", api_keys['옥션1.0'])
|
||||
progress_bar.setValue(75)
|
||||
status_label.setText('현재 상태: 옥션1.0 업데이트 완료')
|
||||
|
||||
await context.close()
|
||||
Loading…
Reference in New Issue