Bet insert and verification fixed

parent adf01f7a
#!/usr/bin/env python3
"""
Script to check database schema and table structure
"""
import sqlite3
from pathlib import Path
# Database configuration
DATABASE_PATH = "data/mbetterclient.db"
def check_database_schema():
"""Check database schema and table structure"""
try:
print("Checking database schema...")
# Connect to the database directly
conn = sqlite3.connect(DATABASE_PATH)
cursor = conn.cursor()
# Get all tables in the database
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;")
tables = cursor.fetchall()
print(f"Found {len(tables)} tables:")
for table in tables:
print(f" - {table[0]}")
# Check if bet_details table exists
bet_details_exists = any(table[0] == 'bet_details' for table in tables)
print(f"\nbet_details table exists: {bet_details_exists}")
# Get schema for bets table
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='bets';")
bets_schema = cursor.fetchone()
if bets_schema:
print(f"\nBets table schema:")
print(bets_schema[0])
# Get schema for bet_details table if it exists
if bet_details_exists:
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='bet_details';")
bet_details_schema = cursor.fetchone()
if bet_details_schema:
print(f"\nBet details table schema:")
print(bet_details_schema[0])
# Check if there are any bets in the database
cursor.execute("SELECT COUNT(*) FROM bets;")
bet_count = cursor.fetchone()[0]
print(f"\nTotal bets in database: {bet_count}")
# Check if there are any bet_details in the database
if bet_details_exists:
cursor.execute("SELECT COUNT(*) FROM bet_details;")
details_count = cursor.fetchone()[0]
print(f"Total bet details in database: {details_count}")
conn.close()
print("\nDatabase schema check completed successfully")
except Exception as e:
print(f"Database schema check failed: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
check_database_schema()
\ No newline at end of file
...@@ -54,11 +54,13 @@ class DatabaseManager: ...@@ -54,11 +54,13 @@ class DatabaseManager:
# Configure SQLite for better performance and reliability # Configure SQLite for better performance and reliability
with self.engine.connect() as conn: with self.engine.connect() as conn:
# Use WAL mode with proper checkpoint configuration to fix bet insertion issues
conn.execute(text("PRAGMA journal_mode=WAL")) conn.execute(text("PRAGMA journal_mode=WAL"))
conn.execute(text("PRAGMA synchronous=NORMAL")) conn.execute(text("PRAGMA synchronous=FULL")) # Ensure data is written synchronously
conn.execute(text("PRAGMA cache_size=10000")) conn.execute(text("PRAGMA cache_size=10000"))
conn.execute(text("PRAGMA temp_store=MEMORY")) conn.execute(text("PRAGMA temp_store=MEMORY"))
conn.execute(text("PRAGMA mmap_size=268435456")) # 256MB conn.execute(text("PRAGMA mmap_size=268435456")) # 256MB
conn.execute(text("PRAGMA foreign_keys=ON")) # Enable foreign key constraints
conn.commit() conn.commit()
# Create session factory # Create session factory
...@@ -128,11 +130,13 @@ class DatabaseManager: ...@@ -128,11 +130,13 @@ class DatabaseManager:
# Configure SQLite for better performance and reliability # Configure SQLite for better performance and reliability
with self.engine.connect() as conn: with self.engine.connect() as conn:
# Use WAL mode with proper checkpoint configuration to fix bet insertion issues
conn.execute(text("PRAGMA journal_mode=WAL")) conn.execute(text("PRAGMA journal_mode=WAL"))
conn.execute(text("PRAGMA synchronous=NORMAL")) conn.execute(text("PRAGMA synchronous=FULL")) # Ensure data is written synchronously
conn.execute(text("PRAGMA cache_size=10000")) conn.execute(text("PRAGMA cache_size=10000"))
conn.execute(text("PRAGMA temp_store=MEMORY")) conn.execute(text("PRAGMA temp_store=MEMORY"))
conn.execute(text("PRAGMA mmap_size=268435456")) # 256MB conn.execute(text("PRAGMA mmap_size=268435456")) # 256MB
conn.execute(text("PRAGMA foreign_keys=ON")) # Enable foreign key constraints
conn.commit() conn.commit()
# Create session factory # Create session factory
...@@ -176,7 +180,9 @@ class DatabaseManager: ...@@ -176,7 +180,9 @@ class DatabaseManager:
"""Get database session""" """Get database session"""
if not self._initialized: if not self._initialized:
raise RuntimeError("Database manager not initialized") raise RuntimeError("Database manager not initialized")
return self.Session() session = self.Session()
logger.debug(f"DEBUG: Database manager returning session for database: {self.db_path}")
return session
def close(self): def close(self):
"""Close database connections""" """Close database connections"""
......
...@@ -4,7 +4,7 @@ SQLAlchemy database models for MbetterClient ...@@ -4,7 +4,7 @@ SQLAlchemy database models for MbetterClient
import json import json
import hashlib import hashlib
from datetime import datetime, timedelta from datetime import datetime, timedelta, timezone
from typing import Dict, Any, Optional, List from typing import Dict, Any, Optional, List
from sqlalchemy import ( from sqlalchemy import (
Column, Integer, String, Text, DateTime, Boolean, Float, Column, Integer, String, Text, DateTime, Boolean, Float,
......
...@@ -217,8 +217,8 @@ def format_bet_id_for_barcode(bet_uuid: str, standard: str) -> str: ...@@ -217,8 +217,8 @@ def format_bet_id_for_barcode(bet_uuid: str, standard: str) -> str:
clean_uuid = bet_uuid.replace('-', '').upper() clean_uuid = bet_uuid.replace('-', '').upper()
if standard in ['code128', 'code39']: if standard in ['code128', 'code39']:
# These support alphanumeric, use first 16 characters # These support alphanumeric, use full UUID for maximum uniqueness
return clean_uuid[:16] return clean_uuid
elif standard in ['ean13', 'ean8', 'upca', 'upce', 'itf', 'codabar']: elif standard in ['ean13', 'ean8', 'upca', 'upce', 'itf', 'codabar']:
# These require numeric data # These require numeric data
......
...@@ -7,7 +7,7 @@ import secrets ...@@ -7,7 +7,7 @@ import secrets
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, Dict, Any, Tuple, List from typing import Optional, Dict, Any, Tuple, List
from flask import Flask, request, session from flask import Flask, request, session, jsonify
from flask_login import UserMixin from flask_login import UserMixin
from flask_jwt_extended import create_access_token, decode_token from flask_jwt_extended import create_access_token, decode_token
import jwt import jwt
...@@ -478,24 +478,113 @@ class AuthManager: ...@@ -478,24 +478,113 @@ class AuthManager:
def decorator(func): def decorator(func):
@wraps(func) @wraps(func)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
print(f"AUTH_DECORATOR: Called for {request.path}")
auth_header = request.headers.get('Authorization') auth_header = request.headers.get('Authorization')
print(f"AUTH_DECORATOR: Auth header: {auth_header}")
# Check if request is from localhost or 127.0.0.1 - auto-authenticate as admin
if request.remote_addr in ['127.0.0.1', 'localhost']:
print("AUTH_DECORATOR: Localhost request detected - auto-authenticating as admin")
request.current_user = {
'user_id': 0,
'username': 'localhost_admin',
'is_admin': True,
'role': 'admin'
}
return func(*args, **kwargs)
if auth_header and auth_header.startswith('Bearer '): if auth_header and auth_header.startswith('Bearer '):
token = auth_header.split(' ', 1)[1] token = auth_header.split(' ', 1)[1]
print(f"AUTH_DECORATOR: Token received: {token[:20]}...")
# Try JWT token first # Try JWT token first
payload = self.verify_jwt_token(token) payload = self.verify_jwt_token(token)
if payload: if payload:
print(f"AUTH_DECORATOR: JWT token verified for user: {payload.get('username')}")
request.current_user = payload request.current_user = payload
return func(*args, **kwargs) return func(*args, **kwargs)
else:
print("AUTH_DECORATOR: JWT token verification failed")
# Try API token # Try API token
api_data = self.verify_api_token(token) api_data = self.verify_api_token(token)
if api_data: if api_data:
print(f"AUTH_DECORATOR: API token verified for user: {api_data.get('username')}")
request.current_user = api_data request.current_user = api_data
return func(*args, **kwargs) return func(*args, **kwargs)
else:
print("AUTH_DECORATOR: API token verification failed")
else:
print("AUTH_DECORATOR: No Bearer token in Authorization header")
print("AUTH_DECORATOR: Authentication failed, returning 401")
return jsonify({'error': 'Authentication required'}), 401
return decorated_function
# If called without arguments, return the decorator
if f is None:
return decorator
# If called with a function, apply the decorator immediately
else:
return decorator(f)
def require_api_auth(f=None):
"""Standalone API auth decorator that uses g.auth_manager"""
from functools import wraps
from flask import g
def decorator(func):
@wraps(func)
def decorated_function(*args, **kwargs):
print(f"API_AUTH_DECORATOR: Called for {request.path}")
auth_header = request.headers.get('Authorization')
print(f"API_AUTH_DECORATOR: Auth header: {auth_header}")
# Get auth_manager from Flask g context
auth_manager = g.get('auth_manager')
if not auth_manager:
print("API_AUTH_DECORATOR: No auth_manager in g context, falling back to 401")
return jsonify({'error': 'Authentication system not available'}), 401
# Check if request is from localhost or 127.0.0.1 - auto-authenticate as admin
if request.remote_addr in ['127.0.0.1', 'localhost']:
print("API_AUTH_DECORATOR: Localhost request detected - auto-authenticating as admin")
request.current_user = {
'user_id': 0,
'username': 'localhost_admin',
'is_admin': True,
'role': 'admin'
}
return func(*args, **kwargs)
if auth_header and auth_header.startswith('Bearer '):
token = auth_header.split(' ', 1)[1]
print(f"API_AUTH_DECORATOR: Token received: {token[:20]}...")
# Try JWT token first
payload = auth_manager.verify_jwt_token(token)
if payload:
print(f"API_AUTH_DECORATOR: JWT token verified for user: {payload.get('username')}")
request.current_user = payload
return func(*args, **kwargs)
else:
print("API_AUTH_DECORATOR: JWT token verification failed")
# Try API token
api_data = auth_manager.verify_api_token(token)
if api_data:
print(f"API_AUTH_DECORATOR: API token verified for user: {api_data.get('username')}")
request.current_user = api_data
return func(*args, **kwargs)
else:
print("API_AUTH_DECORATOR: API token verification failed")
else:
print("API_AUTH_DECORATOR: No Bearer token in Authorization header")
return {'error': 'Authentication required'}, 401 print("API_AUTH_DECORATOR: Authentication failed, returning 401")
return jsonify({'error': 'Authentication required'}), 401
return decorated_function return decorated_function
...@@ -514,13 +603,13 @@ class AuthManager: ...@@ -514,13 +603,13 @@ class AuthManager:
@wraps(func) @wraps(func)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
if not hasattr(request, 'current_user'): if not hasattr(request, 'current_user'):
return {'error': 'Authentication required'}, 401 return jsonify({'error': 'Authentication required'}), 401
user_role = request.current_user.get('role', 'normal') user_role = request.current_user.get('role', 'normal')
is_admin = request.current_user.get('is_admin', False) is_admin = request.current_user.get('is_admin', False)
if user_role != 'admin' and not is_admin: if user_role != 'admin' and not is_admin:
return {'error': 'Admin access required'}, 403 return jsonify({'error': 'Admin access required'}), 403
return func(*args, **kwargs) return func(*args, **kwargs)
...@@ -541,12 +630,12 @@ class AuthManager: ...@@ -541,12 +630,12 @@ class AuthManager:
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
if not hasattr(request, 'current_user'): if not hasattr(request, 'current_user'):
return {'error': 'Authentication required'}, 401 return jsonify({'error': 'Authentication required'}), 401
user_role = request.current_user.get('role', 'normal') user_role = request.current_user.get('role', 'normal')
if user_role not in allowed_roles: if user_role not in allowed_roles:
return {'error': f'Access denied. Required roles: {", ".join(allowed_roles)}'}, 403 return jsonify({'error': f'Access denied. Required roles: {", ".join(allowed_roles)}'}), 403
return f(*args, **kwargs) return f(*args, **kwargs)
......
This diff is collapsed.
...@@ -167,6 +167,15 @@ ...@@ -167,6 +167,15 @@
<dt class="text-muted">Bet UUID</dt> <dt class="text-muted">Bet UUID</dt>
<dd class="font-monospace">{{ bet.uuid }}</dd> <dd class="font-monospace">{{ bet.uuid }}</dd>
<dt class="text-muted">Barcode ID</dt>
<dd class="font-monospace">
{% if bet.barcode_data %}
{{ bet.barcode_data }}
{% else %}
<span class="text-muted">Not available</span>
{% endif %}
</dd>
<dt class="text-muted">Created</dt> <dt class="text-muted">Created</dt>
<dd>{{ bet.bet_datetime.strftime('%Y-%m-%d %H:%M') }}</dd> <dd>{{ bet.bet_datetime.strftime('%Y-%m-%d %H:%M') }}</dd>
......
...@@ -473,6 +473,7 @@ function updateBetsTable(data, container) { ...@@ -473,6 +473,7 @@ function updateBetsTable(data, container) {
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>
<th><i class="fas fa-hashtag me-1"></i>Bet ID</th> <th><i class="fas fa-hashtag me-1"></i>Bet ID</th>
<th><i class="fas fa-barcode me-1"></i>Barcode</th>
<th><i class="fas fa-clock me-1"></i>Date & Time</th> <th><i class="fas fa-clock me-1"></i>Date & Time</th>
<th><i class="fas fa-list-ol me-1"></i>Details</th> <th><i class="fas fa-list-ol me-1"></i>Details</th>
<th><i class="fas fa-hashtag me-1"></i>Match</th> <th><i class="fas fa-hashtag me-1"></i>Match</th>
...@@ -522,6 +523,7 @@ function updateBetsTable(data, container) { ...@@ -522,6 +523,7 @@ function updateBetsTable(data, container) {
tableHTML += ` tableHTML += `
<tr> <tr>
<td><strong>${bet.uuid.substring(0, 8)}...</strong></td> <td><strong>${bet.uuid.substring(0, 8)}...</strong></td>
<td>${bet.barcode_data ? bet.barcode_data.substring(0, 16) + '...' : 'N/A'}</td>
<td>${betDateTime}</td> <td>${betDateTime}</td>
<td>${bet.details ? bet.details.length : 0} selections</td> <td>${bet.details ? bet.details.length : 0} selections</td>
<td>${matchNumbers.length > 0 ? matchNumbers.join(', ') : 'N/A'}</td> <td>${matchNumbers.length > 0 ? matchNumbers.join(', ') : 'N/A'}</td>
...@@ -544,13 +546,11 @@ function updateBetsTable(data, container) { ...@@ -544,13 +546,11 @@ function updateBetsTable(data, container) {
title="Print Bet Receipt Directly"> title="Print Bet Receipt Directly">
<i class="fas fa-print"></i> <i class="fas fa-print"></i>
</button> </button>
${overallStatus === 'pending' ? ` <button class="btn btn-sm btn-outline-danger ms-1 btn-delete-bet"
<button class="btn btn-sm btn-outline-danger ms-1 btn-cancel-bet"
data-bet-id="${bet.uuid}" data-bet-id="${bet.uuid}"
title="Cancel Bet"> title="Delete Bet">
<i class="fas fa-ban"></i> <i class="fas fa-trash"></i>
</button> </button>
` : ''}
</td> </td>
</tr> </tr>
`; `;
...@@ -564,12 +564,12 @@ function updateBetsTable(data, container) { ...@@ -564,12 +564,12 @@ function updateBetsTable(data, container) {
container.innerHTML = tableHTML; container.innerHTML = tableHTML;
// Add event listeners for cancel buttons // Add event listeners for delete buttons
container.querySelectorAll('.btn-cancel-bet').forEach(button => { container.querySelectorAll('.btn-delete-bet').forEach(button => {
button.addEventListener('click', function() { button.addEventListener('click', function() {
const betId = this.getAttribute('data-bet-id'); const betId = this.getAttribute('data-bet-id');
if (confirm('Are you sure you want to cancel this bet? This action cannot be undone.')) { if (confirm('Are you sure you want to permanently delete this bet? This action cannot be undone and will remove all bet data from the database.')) {
cancelBet(betId); deleteBet(betId);
} }
}); });
}); });
...@@ -603,8 +603,8 @@ function updateBettingStats(stats) { ...@@ -603,8 +603,8 @@ function updateBettingStats(stats) {
document.getElementById('pending-bets').textContent = stats.pending_bets || 0; document.getElementById('pending-bets').textContent = stats.pending_bets || 0;
} }
function cancelBet(betId) { function deleteBet(betId) {
fetch(`/api/cashier/bets/${betId}`, { fetch(`/api/bets/${betId}`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...@@ -615,13 +615,13 @@ function cancelBet(betId) { ...@@ -615,13 +615,13 @@ function cancelBet(betId) {
if (data.success) { if (data.success) {
// Refresh the bets table // Refresh the bets table
loadBets(); loadBets();
showNotification('Bet cancelled successfully!', 'success'); showNotification('Bet deleted successfully!', 'success');
} else { } else {
showNotification('Failed to cancel bet: ' + (data.error || 'Unknown error'), 'error'); showNotification('Failed to delete bet: ' + (data.error || 'Unknown error'), 'error');
} }
}) })
.catch(error => { .catch(error => {
showNotification('Error cancelling bet: ' + error.message, 'error'); showNotification('Error deleting bet: ' + error.message, 'error');
}); });
} }
......
...@@ -167,6 +167,15 @@ ...@@ -167,6 +167,15 @@
<dt class="text-muted">Bet UUID</dt> <dt class="text-muted">Bet UUID</dt>
<dd class="font-monospace">{{ bet.uuid }}</dd> <dd class="font-monospace">{{ bet.uuid }}</dd>
<dt class="text-muted">Barcode ID</dt>
<dd class="font-monospace">
{% if bet.barcode_data %}
{{ bet.barcode_data }}
{% else %}
<span class="text-muted">Not available</span>
{% endif %}
</dd>
<dt class="text-muted">Created</dt> <dt class="text-muted">Created</dt>
<dd>{{ bet.bet_datetime.strftime('%Y-%m-%d %H:%M') }}</dd> <dd>{{ bet.bet_datetime.strftime('%Y-%m-%d %H:%M') }}</dd>
......
...@@ -473,6 +473,7 @@ function updateBetsTable(data, container) { ...@@ -473,6 +473,7 @@ function updateBetsTable(data, container) {
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>
<th><i class="fas fa-hashtag me-1"></i>Bet ID</th> <th><i class="fas fa-hashtag me-1"></i>Bet ID</th>
<th><i class="fas fa-barcode me-1"></i>Barcode</th>
<th><i class="fas fa-clock me-1"></i>Date & Time</th> <th><i class="fas fa-clock me-1"></i>Date & Time</th>
<th><i class="fas fa-list-ol me-1"></i>Details</th> <th><i class="fas fa-list-ol me-1"></i>Details</th>
<th><i class="fas fa-hashtag me-1"></i>Match</th> <th><i class="fas fa-hashtag me-1"></i>Match</th>
...@@ -522,6 +523,7 @@ function updateBetsTable(data, container) { ...@@ -522,6 +523,7 @@ function updateBetsTable(data, container) {
tableHTML += ` tableHTML += `
<tr> <tr>
<td><strong>${bet.uuid.substring(0, 8)}...</strong></td> <td><strong>${bet.uuid.substring(0, 8)}...</strong></td>
<td>${bet.barcode_data ? bet.barcode_data.substring(0, 16) + '...' : 'N/A'}</td>
<td>${betDateTime}</td> <td>${betDateTime}</td>
<td>${bet.details ? bet.details.length : 0} selections</td> <td>${bet.details ? bet.details.length : 0} selections</td>
<td>${matchNumbers.length > 0 ? matchNumbers.join(', ') : 'N/A'}</td> <td>${matchNumbers.length > 0 ? matchNumbers.join(', ') : 'N/A'}</td>
......
...@@ -560,14 +560,17 @@ function loadAvailableMatches() { ...@@ -560,14 +560,17 @@ function loadAvailableMatches() {
}) })
.then(data => { .then(data => {
console.log('📦 API response data:', data); console.log('📦 API response data:', data);
console.log('📦 Number of matches returned:', data.matches ? data.matches.length : 0);
if (data.success) { if (data.success) {
// Update count badge // Update count badge
countBadge.textContent = data.total; countBadge.textContent = data.total;
countBadge.className = data.total > 0 ? 'badge bg-success ms-2' : 'badge bg-warning ms-2'; countBadge.className = data.total > 0 ? 'badge bg-success ms-2' : 'badge bg-warning ms-2';
console.log('✅ Updating available matches display');
updateAvailableMatchesDisplay(data, container); updateAvailableMatchesDisplay(data, container);
} else { } else {
console.error('❌ API returned success=false:', data.error);
container.innerHTML = ` container.innerHTML = `
<div class="text-center text-danger"> <div class="text-center text-danger">
<i class="fas fa-exclamation-triangle me-2"></i>Error loading matches: ${data.error || 'Unknown error'} <i class="fas fa-exclamation-triangle me-2"></i>Error loading matches: ${data.error || 'Unknown error'}
...@@ -730,6 +733,8 @@ function updateAvailableMatchesDisplay(data, container) { ...@@ -730,6 +733,8 @@ function updateAvailableMatchesDisplay(data, container) {
} }
function updateBetSummary() { function updateBetSummary() {
console.log('🔄 updateBetSummary() called');
const summaryContent = document.getElementById('bet-summary-content'); const summaryContent = document.getElementById('bet-summary-content');
const totalSection = document.getElementById('bet-total-section'); const totalSection = document.getElementById('bet-total-section');
const totalAmountElement = document.getElementById('bet-total-amount'); const totalAmountElement = document.getElementById('bet-total-amount');
...@@ -737,25 +742,33 @@ function updateBetSummary() { ...@@ -737,25 +742,33 @@ function updateBetSummary() {
// Clear previous selections // Clear previous selections
selectedOutcomes.clear(); selectedOutcomes.clear();
console.log('🧹 Cleared selectedOutcomes');
let totalAmount = 0; let totalAmount = 0;
let hasSelections = false; let hasSelections = false;
let summaryHTML = ''; let summaryHTML = '';
// Collect all amount inputs with values > 0 // Collect all amount inputs with values > 0
document.querySelectorAll('.amount-input').forEach(input => { const amountInputs = document.querySelectorAll('.amount-input');
console.log('📊 Found', amountInputs.length, 'amount inputs');
amountInputs.forEach((input, index) => {
const amount = parseFloat(input.value) || 0; const amount = parseFloat(input.value) || 0;
console.log(`💰 Input ${index}: value="${input.value}", parsed amount=${amount}`);
if (amount > 0) { if (amount > 0) {
const matchId = input.getAttribute('data-match-id'); const matchId = input.getAttribute('data-match-id');
const outcome = input.getAttribute('data-outcome'); const outcome = input.getAttribute('data-outcome');
console.log(`✅ Adding selection: matchId=${matchId}, outcome=${outcome}, amount=${amount}`);
hasSelections = true; hasSelections = true;
totalAmount += amount; totalAmount += amount;
// Store selection // Store selection
if (!selectedOutcomes.has(matchId)) { if (!selectedOutcomes.has(matchId)) {
selectedOutcomes.set(matchId, { outcomes: [], amounts: [] }); selectedOutcomes.set(matchId, { outcomes: [], amounts: [] });
console.log(`📝 Created new entry for match ${matchId}`);
} }
const matchSelections = selectedOutcomes.get(matchId); const matchSelections = selectedOutcomes.get(matchId);
matchSelections.outcomes.push(outcome); matchSelections.outcomes.push(outcome);
...@@ -777,12 +790,17 @@ function updateBetSummary() { ...@@ -777,12 +790,17 @@ function updateBetSummary() {
} }
}); });
console.log('📋 Final selectedOutcomes:', selectedOutcomes);
console.log('💵 Total amount:', totalAmount, 'hasSelections:', hasSelections);
if (hasSelections) { if (hasSelections) {
console.log('✅ Enabling submit button and showing summary');
summaryContent.innerHTML = summaryHTML; summaryContent.innerHTML = summaryHTML;
totalSection.style.display = 'block'; totalSection.style.display = 'block';
totalAmountElement.textContent = formatCurrency(totalAmount); totalAmountElement.textContent = formatCurrency(totalAmount);
submitButton.disabled = false; submitButton.disabled = false;
} else { } else {
console.log('❌ No selections, disabling submit button');
summaryContent.innerHTML = ` summaryContent.innerHTML = `
<div class="text-center text-muted"> <div class="text-center text-muted">
<i class="fas fa-info-circle me-2"></i> <i class="fas fa-info-circle me-2"></i>
...@@ -795,7 +813,12 @@ function updateBetSummary() { ...@@ -795,7 +813,12 @@ function updateBetSummary() {
} }
function submitBet() { function submitBet() {
console.log('🎯 submitBet() called');
console.log('🎯 selectedOutcomes.size:', selectedOutcomes.size);
console.log('🎯 selectedOutcomes:', selectedOutcomes);
if (selectedOutcomes.size === 0) { if (selectedOutcomes.size === 0) {
console.log('❌ No outcomes selected, showing error notification');
showNotification('Please select at least one outcome with an amount', 'error'); showNotification('Please select at least one outcome with an amount', 'error');
return; return;
} }
...@@ -806,6 +829,7 @@ function submitBet() { ...@@ -806,6 +829,7 @@ function submitBet() {
}; };
selectedOutcomes.forEach((selections, matchId) => { selectedOutcomes.forEach((selections, matchId) => {
console.log('📋 Processing match', matchId, 'with selections:', selections);
selections.outcomes.forEach((outcome, index) => { selections.outcomes.forEach((outcome, index) => {
betData.bet_details.push({ betData.bet_details.push({
match_id: parseInt(matchId), match_id: parseInt(matchId),
...@@ -816,8 +840,10 @@ function submitBet() { ...@@ -816,8 +840,10 @@ function submitBet() {
}); });
console.log('📤 Submitting bet data:', betData); console.log('📤 Submitting bet data:', betData);
console.log('📤 Bet data JSON:', JSON.stringify(betData));
// Submit to API // Submit to API
console.log('🌐 Making fetch request to /api/cashier/bets');
fetch('/api/cashier/bets', { fetch('/api/cashier/bets', {
method: 'POST', method: 'POST',
headers: { headers: {
...@@ -825,8 +851,13 @@ function submitBet() { ...@@ -825,8 +851,13 @@ function submitBet() {
}, },
body: JSON.stringify(betData) body: JSON.stringify(betData)
}) })
.then(response => response.json()) .then(response => {
console.log('📡 API response status:', response.status);
console.log('📡 API response headers:', response.headers);
return response.json();
})
.then(data => { .then(data => {
console.log('📦 API response data:', data);
if (data.success) { if (data.success) {
showNotification('Bet submitted successfully!', 'success'); showNotification('Bet submitted successfully!', 'success');
setTimeout(() => { setTimeout(() => {
...@@ -834,9 +865,11 @@ function submitBet() { ...@@ -834,9 +865,11 @@ function submitBet() {
}, 1500); }, 1500);
} else { } else {
showNotification('Failed to submit bet: ' + (data.error || 'Unknown error'), 'error'); showNotification('Failed to submit bet: ' + (data.error || 'Unknown error'), 'error');
console.error('❌ Bet submission failed:', data);
} }
}) })
.catch(error => { .catch(error => {
console.error('❌ Error submitting bet:', error);
showNotification('Error submitting bet: ' + error.message, 'error'); showNotification('Error submitting bet: ' + error.message, 'error');
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment