feat: 키오스크 마일리지 적립 시스템 추가
- 키오스크 전체화면 웹 UI (/kiosk) - QR 표시 + 전화번호 숫자패드 입력 - 키오스크 API 4개 (trigger, current, claim, kiosk 페이지) - POS GUI에 "키오스크 적립" 버튼 추가 (Flask 서버로 HTTP 트리거) - NHN Cloud 알림톡 발송 모듈 (적립 완료 시 자동 발송) - Qt 플랫폼 플러그인 경로 자동 설정 (no Qt platform plugin 에러 해결) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
111
backend/services/nhn_alimtalk.py
Normal file
111
backend/services/nhn_alimtalk.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
NHN Cloud 알림톡 발송 서비스
|
||||
마일리지 적립 완료 등 알림톡 발송
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# NHN Cloud 알림톡 설정
|
||||
APPKEY = os.getenv('NHN_ALIMTALK_APPKEY', 'u0TLUaXXY9bfQFkY')
|
||||
SECRET_KEY = os.getenv('NHN_ALIMTALK_SECRET', 'naraGEUJfpkRu1fgirKewJtwADqWQ5gY')
|
||||
SENDER_KEY = os.getenv('NHN_ALIMTALK_SENDER', '341352077bce225195ccc2697fb449f723e70982')
|
||||
|
||||
API_BASE = f'https://api-alimtalk.cloud.toast.com/alimtalk/v2.3/appkeys/{APPKEY}'
|
||||
|
||||
# KST 타임존
|
||||
KST = timezone(timedelta(hours=9))
|
||||
|
||||
|
||||
def _send_alimtalk(template_code, recipient_no, template_params):
|
||||
"""
|
||||
알림톡 발송 공통 함수
|
||||
|
||||
Args:
|
||||
template_code: 템플릿 코드
|
||||
recipient_no: 수신 번호 (01012345678)
|
||||
template_params: 템플릿 변수 딕셔너리
|
||||
|
||||
Returns:
|
||||
tuple: (성공 여부, 메시지)
|
||||
"""
|
||||
url = f'{API_BASE}/messages'
|
||||
headers = {
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
'X-Secret-Key': SECRET_KEY
|
||||
}
|
||||
data = {
|
||||
'senderKey': SENDER_KEY,
|
||||
'templateCode': template_code,
|
||||
'recipientList': [
|
||||
{
|
||||
'recipientNo': recipient_no,
|
||||
'templateParameter': template_params
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
try:
|
||||
resp = requests.post(url, headers=headers, json=data, timeout=10)
|
||||
result = resp.json()
|
||||
|
||||
if resp.status_code == 200 and result.get('header', {}).get('isSuccessful'):
|
||||
logger.info(f"알림톡 발송 성공: {template_code} → {recipient_no}")
|
||||
return (True, "발송 성공")
|
||||
else:
|
||||
error_msg = result.get('header', {}).get('resultMessage', str(result))
|
||||
logger.warning(f"알림톡 발송 실패: {template_code} → {recipient_no}: {error_msg}")
|
||||
return (False, error_msg)
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.warning(f"알림톡 발송 타임아웃: {template_code} → {recipient_no}")
|
||||
return (False, "타임아웃")
|
||||
except Exception as e:
|
||||
logger.warning(f"알림톡 발송 오류: {template_code} → {recipient_no}: {e}")
|
||||
return (False, str(e))
|
||||
|
||||
|
||||
def send_mileage_claim_alimtalk(phone, name, points, balance):
|
||||
"""
|
||||
마일리지 적립 완료 알림톡 발송
|
||||
|
||||
Args:
|
||||
phone: 수신 전화번호 (01012345678)
|
||||
name: 고객명
|
||||
points: 적립 포인트
|
||||
balance: 적립 후 총 잔액
|
||||
|
||||
Returns:
|
||||
tuple: (성공 여부, 메시지)
|
||||
"""
|
||||
now_kst = datetime.now(KST).strftime('%Y-%m-%d %H:%M')
|
||||
|
||||
# MILEAGE_CLAIM_V2 (버튼 포함 버전) 우선 시도
|
||||
template_code = 'MILEAGE_CLAIM_V2'
|
||||
params = {
|
||||
'고객명': name,
|
||||
'적립포인트': f'{points:,}',
|
||||
'총잔액': f'{balance:,}',
|
||||
'적립일시': now_kst,
|
||||
'전화번호': phone
|
||||
}
|
||||
|
||||
success, msg = _send_alimtalk(template_code, phone, params)
|
||||
|
||||
if not success:
|
||||
# V2 실패 시 V1 (버튼 없는 버전) 시도
|
||||
template_code = 'MILEAGE_CLAIM'
|
||||
params_v1 = {
|
||||
'고객명': name,
|
||||
'적립포인트': f'{points:,}',
|
||||
'총잔액': f'{balance:,}',
|
||||
'적립일시': now_kst
|
||||
}
|
||||
success, msg = _send_alimtalk(template_code, phone, params_v1)
|
||||
|
||||
return (success, msg)
|
||||
Reference in New Issue
Block a user