2025-09-04 10:10:24 +09:00
|
|
|
|
"""
|
|
|
|
|
|
QRコードサービスポイント処理API
|
|
|
|
|
|
|
|
|
|
|
|
このモジュールは、QRコードを使用したサービスポイントの登録・処理を行います。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from rest_framework.decorators import api_view
|
|
|
|
|
|
from rest_framework.response import Response
|
|
|
|
|
|
from rest_framework import status
|
|
|
|
|
|
from rog.models import NewEvent2, Entry, Location2025, GpsCheckin
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
from django.utils import timezone
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import json
|
|
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
|
def submit_qr_points(request):
|
|
|
|
|
|
"""
|
|
|
|
|
|
QRコードサービスポイント登録API
|
|
|
|
|
|
|
|
|
|
|
|
パラメータ:
|
|
|
|
|
|
- event_code: イベントコード
|
|
|
|
|
|
- team_name: チーム名
|
|
|
|
|
|
- qr_code_data: QRコードデータ
|
|
|
|
|
|
- latitude: 緯度(オプション)
|
|
|
|
|
|
- longitude: 経度(オプション)
|
|
|
|
|
|
- image: 画像データ(オプション)
|
|
|
|
|
|
- cp_number: チェックポイント番号(オプション)
|
|
|
|
|
|
"""
|
|
|
|
|
|
# リクエストIDを生成してログで追跡できるようにする
|
|
|
|
|
|
request_id = str(uuid.uuid4())[:8]
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🚀 Starting QR points submission - ID: {request_id}")
|
|
|
|
|
|
|
|
|
|
|
|
# クライアント情報を取得
|
|
|
|
|
|
user_agent = request.META.get('HTTP_USER_AGENT', 'Unknown')
|
|
|
|
|
|
client_ip = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get('REMOTE_ADDR', 'Unknown')
|
|
|
|
|
|
user_info = str(request.user) if request.user.is_authenticated else 'Anonymous'
|
|
|
|
|
|
|
|
|
|
|
|
# リクエストからパラメータを取得
|
|
|
|
|
|
event_code = request.data.get('event_code')
|
|
|
|
|
|
team_name = request.data.get('team_name')
|
|
|
|
|
|
qr_code_data = request.data.get('qr_code_data')
|
|
|
|
|
|
latitude = request.data.get('latitude')
|
|
|
|
|
|
longitude = request.data.get('longitude')
|
|
|
|
|
|
image_data = request.data.get('image')
|
|
|
|
|
|
cp_number = request.data.get('cp_number')
|
2025-09-04 19:25:14 +09:00
|
|
|
|
point_value = request.data.get('point_value')
|
|
|
|
|
|
location_id = request.data.get('location_id')
|
|
|
|
|
|
timestamp = request.data.get('timestamp')
|
|
|
|
|
|
qr_scan = request.data.get('qr_scan')
|
2025-09-04 10:10:24 +09:00
|
|
|
|
|
2025-09-04 10:34:48 +09:00
|
|
|
|
# 📋 パラメータをログ出力(デバッグ用)
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📋 Request Parameters:")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 🏷️ Event Code: '{event_code}'")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 👥 Team Name: '{team_name}'")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📱 QR Code Data: '{qr_code_data}'")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📍 Latitude: {latitude}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 🌍 Longitude: {longitude}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 🏁 CP Number: {cp_number}")
|
2025-09-04 19:25:14 +09:00
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - <20> Point Value: {point_value}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📍 Location ID: {location_id}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - ⏰ Timestamp: {timestamp}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📱 QR Scan: {qr_scan}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - <20>📸 Has Image: {image_data is not None}")
|
2025-09-04 10:34:48 +09:00
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 🌐 Client IP: {client_ip}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 👤 User: {user_info}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 🔧 User Agent: {user_agent[:100]}...")
|
|
|
|
|
|
|
|
|
|
|
|
# 全リクエストデータをログ出力(セキュリティ上重要でないデータのみ)
|
|
|
|
|
|
safe_data = {k: v for k, v in request.data.items() if k not in ['image', 'password']}
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ID: {request_id} - 📊 Full Request Data: {json.dumps(safe_data, ensure_ascii=False, indent=2)}")
|
|
|
|
|
|
cp_number = request.data.get('cp_number')
|
|
|
|
|
|
|
2025-09-04 10:10:24 +09:00
|
|
|
|
# 📊 詳細なパラメータログ
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📊 DETAILED PARAMS - ID: {request_id}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🏷️ Basic params: event_code='{event_code}', team_name='{team_name}'")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📱 QR params: qr_code_data='{qr_code_data}', cp_number={cp_number}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🌍 Location params: lat={latitude}, lng={longitude}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🖼️ Image params: has_image={bool(image_data)}, image_size={len(str(image_data)) if image_data else 0}")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📱 Client params: user_agent='{user_agent[:100]}...', client_ip='{client_ip}'")
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🔐 Auth params: user_authenticated={request.user.is_authenticated}, user='{user_info}'")
|
|
|
|
|
|
|
|
|
|
|
|
# 全リクエストデータをダンプ(デバッグ用)
|
|
|
|
|
|
try:
|
|
|
|
|
|
request_data_safe = {}
|
|
|
|
|
|
for key, value in request.data.items():
|
|
|
|
|
|
if key == 'image' and value:
|
|
|
|
|
|
request_data_safe[key] = f"[IMAGE_DATA:{len(str(value))}chars]"
|
|
|
|
|
|
else:
|
|
|
|
|
|
request_data_safe[key] = value
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📥 FULL REQUEST DATA: {json.dumps(request_data_safe, ensure_ascii=False, indent=2)}")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] Failed to log request data: {e}")
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# パラメータ検証 - 実際のリクエストデータに基づく
|
|
|
|
|
|
# 基本的な必須パラメータ: event_code, team_name
|
|
|
|
|
|
# オプション: qr_code_data, cp_number, point_value, location_id, qr_scan
|
|
|
|
|
|
if not all([event_code, team_name]):
|
|
|
|
|
|
missing_params = []
|
|
|
|
|
|
if not event_code:
|
|
|
|
|
|
missing_params.append('event_code')
|
|
|
|
|
|
if not team_name:
|
|
|
|
|
|
missing_params.append('team_name')
|
|
|
|
|
|
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ❌ Missing required parameters: {missing_params} - ID: {request_id}")
|
2025-09-04 10:10:24 +09:00
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
2025-09-04 19:25:14 +09:00
|
|
|
|
"message": f"必須パラメータが不足しています: {', '.join(missing_params)}",
|
|
|
|
|
|
"missing_parameters": missing_params,
|
2025-09-04 10:10:24 +09:00
|
|
|
|
"request_id": request_id
|
|
|
|
|
|
}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
with transaction.atomic():
|
|
|
|
|
|
# イベントの存在確認
|
|
|
|
|
|
event = NewEvent2.objects.filter(event_name=event_code).first()
|
|
|
|
|
|
if not event:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ❌ Event not found: {event_code} - ID: {request_id}")
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": f"指定されたイベント '{event_code}' が見つかりません",
|
|
|
|
|
|
"request_id": request_id
|
|
|
|
|
|
}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
|
|
|
|
|
|
# チームの存在確認
|
|
|
|
|
|
entry = Entry.objects.filter(
|
|
|
|
|
|
event=event,
|
|
|
|
|
|
team__team_name=team_name
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if not entry:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ❌ Team not found: {team_name} in event: {event_code} - ID: {request_id}")
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": f"指定されたチーム '{team_name}' がイベント '{event_code}' に見つかりません",
|
|
|
|
|
|
"request_id": request_id
|
|
|
|
|
|
}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# QRコードデータの解析(オプション)
|
|
|
|
|
|
qr_data = None
|
|
|
|
|
|
if qr_code_data:
|
|
|
|
|
|
try:
|
|
|
|
|
|
if isinstance(qr_code_data, str):
|
|
|
|
|
|
# JSON文字列の場合はパース
|
|
|
|
|
|
if qr_code_data.startswith('{'):
|
|
|
|
|
|
qr_data = json.loads(qr_code_data)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 単純な文字列の場合
|
|
|
|
|
|
qr_data = {"code": qr_code_data}
|
2025-09-04 10:10:24 +09:00
|
|
|
|
else:
|
2025-09-04 19:25:14 +09:00
|
|
|
|
qr_data = qr_code_data
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📱 Parsed QR data: {qr_data} - ID: {request_id}")
|
|
|
|
|
|
|
|
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ⚠️ Invalid QR code data format: {e}, using as string - ID: {request_id}")
|
|
|
|
|
|
qr_data = {"code": str(qr_code_data)}
|
2025-09-04 10:10:24 +09:00
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# チェックポイント情報の取得
|
2025-09-04 10:10:24 +09:00
|
|
|
|
location = None
|
2025-09-04 19:25:14 +09:00
|
|
|
|
calculated_point_value = 0
|
|
|
|
|
|
|
|
|
|
|
|
# location_idが指定されている場合、それを優先
|
|
|
|
|
|
if location_id:
|
|
|
|
|
|
location = Location2025.objects.filter(
|
|
|
|
|
|
id=location_id,
|
|
|
|
|
|
event_id=event.id
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if location:
|
|
|
|
|
|
calculated_point_value = location.cp_point or 0
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📍 Found location by ID: {location_id} - CP{location.cp_number} - {location.cp_name} - Points: {calculated_point_value} - ID: {request_id}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ⚠️ Location not found for location_id: {location_id} - ID: {request_id}")
|
|
|
|
|
|
|
|
|
|
|
|
# cp_numberが指定されている場合も確認
|
|
|
|
|
|
elif cp_number:
|
2025-09-04 10:10:24 +09:00
|
|
|
|
location = Location2025.objects.filter(
|
|
|
|
|
|
event_id=event.id,
|
|
|
|
|
|
cp_number=cp_number
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if location:
|
2025-09-04 19:25:14 +09:00
|
|
|
|
calculated_point_value = location.cp_point or 0
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 📍 Found location by CP: CP{cp_number} - {location.cp_name} - Points: {calculated_point_value} - ID: {request_id}")
|
2025-09-04 10:10:24 +09:00
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ⚠️ Location not found for CP{cp_number} - ID: {request_id}")
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# point_valueが明示的に指定されている場合、それを使用
|
|
|
|
|
|
final_point_value = point_value if point_value is not None else calculated_point_value
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 💯 Point calculation: provided={point_value}, calculated={calculated_point_value}, final={final_point_value} - ID: {request_id}")
|
|
|
|
|
|
|
2025-09-04 10:10:24 +09:00
|
|
|
|
# QRポイント登録処理
|
|
|
|
|
|
current_time = timezone.now()
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# timestampが提供されている場合は使用、そうでなければ現在時刻
|
|
|
|
|
|
if timestamp:
|
|
|
|
|
|
try:
|
|
|
|
|
|
# ISO形式のタイムスタンプをパース
|
|
|
|
|
|
checkin_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
|
|
|
|
|
|
if checkin_time.tzinfo is None:
|
|
|
|
|
|
checkin_time = timezone.make_aware(checkin_time)
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] ⏰ Using provided timestamp: {checkin_time} - ID: {request_id}")
|
|
|
|
|
|
except (ValueError, AttributeError) as e:
|
|
|
|
|
|
logger.warning(f"[QR_SUBMIT] ⚠️ Invalid timestamp format, using current time: {e} - ID: {request_id}")
|
|
|
|
|
|
checkin_time = current_time
|
|
|
|
|
|
else:
|
|
|
|
|
|
checkin_time = current_time
|
|
|
|
|
|
|
|
|
|
|
|
# GpsCheckinレコードを作成
|
2025-09-04 10:10:24 +09:00
|
|
|
|
checkin_data = {
|
|
|
|
|
|
'event': event,
|
|
|
|
|
|
'entry': entry,
|
|
|
|
|
|
'zekken_number': entry.zekken_number,
|
2025-09-04 19:25:14 +09:00
|
|
|
|
'cp_number': cp_number or (location.cp_number if location else 0),
|
|
|
|
|
|
'checkin_time': checkin_time,
|
2025-09-04 10:10:24 +09:00
|
|
|
|
'is_service_checked': True, # QRコードはサービスポイントとして扱う
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 位置情報が提供されている場合は追加
|
|
|
|
|
|
if latitude and longitude:
|
|
|
|
|
|
checkin_data['latitude'] = float(latitude)
|
|
|
|
|
|
checkin_data['longitude'] = float(longitude)
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🌍 GPS coordinates recorded: {latitude}, {longitude} - ID: {request_id}")
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
# QRコードデータを格納(qr_scanフラグも含む)
|
|
|
|
|
|
qr_metadata = {
|
|
|
|
|
|
'qr_scan': qr_scan,
|
|
|
|
|
|
'location_id': location_id,
|
|
|
|
|
|
'point_value': final_point_value,
|
|
|
|
|
|
'original_qr_data': qr_data,
|
|
|
|
|
|
'timestamp': timestamp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-04 10:10:24 +09:00
|
|
|
|
if hasattr(GpsCheckin, 'qr_code_data'):
|
2025-09-04 19:25:14 +09:00
|
|
|
|
checkin_data['qr_code_data'] = qr_metadata
|
2025-09-04 10:10:24 +09:00
|
|
|
|
|
|
|
|
|
|
# 画像データを格納(URLまたはパスの場合)
|
|
|
|
|
|
if image_data:
|
|
|
|
|
|
if hasattr(GpsCheckin, 'image_url'):
|
|
|
|
|
|
checkin_data['image_url'] = image_data
|
|
|
|
|
|
logger.info(f"[QR_SUBMIT] 🖼️ Image data recorded - ID: {request_id}")
|
|
|
|
|
|
|
|
|
|
|
|
# レコードを作成
|
|
|
|
|
|
gps_checkin = GpsCheckin.objects.create(**checkin_data)
|
|
|
|
|
|
|
|
|
|
|
|
# 成功レスポンス
|
|
|
|
|
|
response_data = {
|
|
|
|
|
|
"status": "OK",
|
|
|
|
|
|
"message": "QRコードサービスポイントが正常に登録されました",
|
|
|
|
|
|
"request_id": request_id,
|
|
|
|
|
|
"data": {
|
|
|
|
|
|
"event_code": event_code,
|
|
|
|
|
|
"team_name": team_name,
|
|
|
|
|
|
"zekken_number": entry.zekken_number,
|
2025-09-04 19:25:14 +09:00
|
|
|
|
"cp_number": cp_number or (location.cp_number if location else 0),
|
|
|
|
|
|
"point_value": final_point_value,
|
|
|
|
|
|
"location_id": location_id,
|
|
|
|
|
|
"checkin_time": checkin_time.isoformat(),
|
|
|
|
|
|
"qr_scan": qr_scan,
|
2025-09-04 10:10:24 +09:00
|
|
|
|
"qr_code_processed": True,
|
|
|
|
|
|
"has_location": bool(latitude and longitude),
|
|
|
|
|
|
"has_image": bool(image_data),
|
|
|
|
|
|
"checkin_id": gps_checkin.id if gps_checkin else None
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-04 19:25:14 +09:00
|
|
|
|
logger.info(f"[QR_SUBMIT] ✅ SUCCESS - Team: {team_name}, Zekken: {entry.zekken_number}, CP: {cp_number or (location.cp_number if location else 0)}, Points: {final_point_value}, QR: {qr_scan}, Location ID: {location_id}, Client IP: {client_ip}, User: {user_info} - ID: {request_id}")
|
2025-09-04 10:10:24 +09:00
|
|
|
|
|
|
|
|
|
|
return Response(response_data, status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"[QR_SUBMIT] ❌ EXCEPTION - ID: {request_id}, Error: {str(e)}", exc_info=True)
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": "QRコードサービスポイント処理中にエラーが発生しました",
|
|
|
|
|
|
"request_id": request_id,
|
|
|
|
|
|
"error_detail": str(e) if logger.getEffectiveLevel() <= logging.DEBUG else None
|
|
|
|
|
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['GET'])
|
|
|
|
|
|
def qr_points_status(request):
|
|
|
|
|
|
"""
|
|
|
|
|
|
QRポイント処理状況確認API
|
|
|
|
|
|
|
|
|
|
|
|
パラメータ:
|
|
|
|
|
|
- event_code: イベントコード
|
|
|
|
|
|
- team_name: チーム名(オプション)
|
|
|
|
|
|
"""
|
|
|
|
|
|
event_code = request.query_params.get('event_code')
|
|
|
|
|
|
team_name = request.query_params.get('team_name')
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"[QR_STATUS] QR points status check - event: {event_code}, team: {team_name}")
|
|
|
|
|
|
|
|
|
|
|
|
if not event_code:
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": "イベントコードが必要です"
|
|
|
|
|
|
}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# イベントの存在確認
|
|
|
|
|
|
event = NewEvent2.objects.filter(event_name=event_code).first()
|
|
|
|
|
|
if not event:
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": f"指定されたイベント '{event_code}' が見つかりません"
|
|
|
|
|
|
}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
|
|
|
|
|
|
# QRコード関連のチェックイン状況を取得
|
|
|
|
|
|
query = GpsCheckin.objects.filter(event=event, is_service_checked=True)
|
|
|
|
|
|
|
|
|
|
|
|
if team_name:
|
|
|
|
|
|
query = query.filter(entry__team__team_name=team_name)
|
|
|
|
|
|
|
|
|
|
|
|
qr_checkins = query.order_by('-checkin_time')[:50] # 最新50件
|
|
|
|
|
|
|
|
|
|
|
|
checkin_list = []
|
|
|
|
|
|
for checkin in qr_checkins:
|
|
|
|
|
|
checkin_list.append({
|
|
|
|
|
|
"checkin_id": checkin.id,
|
|
|
|
|
|
"team_name": checkin.entry.team.team_name,
|
|
|
|
|
|
"zekken_number": checkin.zekken_number,
|
|
|
|
|
|
"cp_number": checkin.cp_number,
|
|
|
|
|
|
"checkin_time": checkin.checkin_time.isoformat(),
|
|
|
|
|
|
"has_qr_data": hasattr(checkin, 'qr_code_data') and bool(checkin.qr_code_data),
|
|
|
|
|
|
"has_location": bool(checkin.latitude and checkin.longitude),
|
|
|
|
|
|
"is_service_checked": checkin.is_service_checked
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "OK",
|
|
|
|
|
|
"message": "QRポイント状況を取得しました",
|
|
|
|
|
|
"data": {
|
|
|
|
|
|
"event_code": event_code,
|
|
|
|
|
|
"total_count": len(checkin_list),
|
|
|
|
|
|
"checkins": checkin_list
|
|
|
|
|
|
}
|
|
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"[QR_STATUS] Error getting QR points status: {str(e)}", exc_info=True)
|
|
|
|
|
|
return Response({
|
|
|
|
|
|
"status": "ERROR",
|
|
|
|
|
|
"message": "QRポイント状況取得中にエラーが発生しました",
|
|
|
|
|
|
"error_detail": str(e) if logger.getEffectiveLevel() <= logging.DEBUG else None
|
|
|
|
|
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|