feat: 알림톡 발송 로그 시스템 + 현영 표시 + 문서화

- 알림톡 발송 로그: alimtalk_logs SQLite 테이블 + DB 자동 기록
- /admin/alimtalk 페이지: 서버 로그, NHN Cloud 내역 조회, 수동 발송 테스트
- 적립일시 포맷 수정: %Y-%m-%d %H:%M (16자 초과) → %m/%d %H:%M (11자)
- POS GUI 현금영수증(현영) 표시: 청록색 볼드
- 결제수납구조.md: CD_SUNAB/PS_main/SALE_MAIN 3테이블 관계 문서
- 실행구조.md: Flask 서버 + Qt GUI 실행 가이드

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
thug0bin
2026-02-26 19:28:29 +09:00
parent 0c52542713
commit a3ff69b67f
10 changed files with 1117 additions and 82 deletions

View File

@@ -1885,6 +1885,97 @@ def admin():
recent_tokens=recent_tokens)
# ============================================================================
# 알림톡 로그
# ============================================================================
@app.route('/admin/alimtalk')
def admin_alimtalk():
"""알림톡 발송 로그 + NHN 발송 내역"""
conn = db_manager.get_sqlite_connection()
cursor = conn.cursor()
# 로컬 발송 로그 (최근 50건)
cursor.execute("""
SELECT a.*, u.nickname, u.phone as user_phone
FROM alimtalk_logs a
LEFT JOIN users u ON a.user_id = u.id
ORDER BY a.created_at DESC
LIMIT 50
""")
local_logs = [dict(row) for row in cursor.fetchall()]
# 통계
cursor.execute("""
SELECT
COUNT(*) as total,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as success_count,
SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as fail_count
FROM alimtalk_logs
""")
stats = dict(cursor.fetchone())
# 오늘 통계
cursor.execute("""
SELECT
COUNT(*) as today_total,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as today_success
FROM alimtalk_logs
WHERE date(created_at) = date('now')
""")
today = dict(cursor.fetchone())
stats.update(today)
return render_template('admin_alimtalk.html', local_logs=local_logs, stats=stats)
@app.route('/api/admin/alimtalk/nhn-history')
def api_admin_alimtalk_nhn_history():
"""NHN Cloud 실제 발송 내역 API"""
from services.nhn_alimtalk import get_nhn_send_history
date_str = request.args.get('date', datetime.now().strftime('%Y-%m-%d'))
start = f"{date_str} 00:00"
end = f"{date_str} 23:59"
messages = get_nhn_send_history(start, end)
result = []
for m in messages:
result.append({
'requestDate': m.get('requestDate', ''),
'recipientNo': m.get('recipientNo', ''),
'templateCode': m.get('templateCode', ''),
'messageStatus': m.get('messageStatus', ''),
'resultCode': m.get('resultCode', ''),
'resultMessage': m.get('resultMessage', ''),
'content': m.get('content', ''),
})
return jsonify({'success': True, 'messages': result})
@app.route('/api/admin/alimtalk/test-send', methods=['POST'])
def api_admin_alimtalk_test_send():
"""관리자 수동 알림톡 발송 테스트"""
from services.nhn_alimtalk import send_mileage_claim_alimtalk
data = request.get_json()
phone = data.get('phone', '').strip().replace('-', '')
name = data.get('name', '테스트')
if len(phone) < 10:
return jsonify({'success': False, 'message': '올바른 전화번호를 입력해주세요.'}), 400
success, msg = send_mileage_claim_alimtalk(
phone, name, 100, 500,
items=[{'name': '테스트 발송', 'qty': 1, 'total': 1000}],
trigger_source='admin_test'
)
return jsonify({'success': success, 'message': msg})
# ============================================================================
# 키오스크 적립
# ============================================================================
@@ -2094,9 +2185,15 @@ def api_kiosk_claim():
user_row = cursor.fetchone()
user_name = user_row['nickname'] if user_row else '고객'
send_mileage_claim_alimtalk(phone, user_name, claimed_points, new_balance, items=sale_items)
logging.warning(f"[알림톡] 발송 시도: phone={phone}, name={user_name}, points={claimed_points}, balance={new_balance}, items={sale_items}")
success, msg = send_mileage_claim_alimtalk(
phone, user_name, claimed_points, new_balance,
items=sale_items, user_id=user_id,
trigger_source='kiosk', transaction_id=transaction_id
)
logging.warning(f"[알림톡] 발송 결과: success={success}, msg={msg}")
except Exception as alimtalk_err:
logging.warning(f"알림톡 발송 실패 (적립은 완료): {alimtalk_err}")
logging.warning(f"[알림톡] 발송 예외 (적립은 완료): {alimtalk_err}")
return jsonify({
'success': True,