Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterc
Commits
c00f9cdb
Commit
c00f9cdb
authored
Jan 27, 2026
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Balabce globalized
parent
a1afa146
Changes
10
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
361 additions
and
139 deletions
+361
-139
client.py
mbetterclient/api_client/client.py
+143
-26
games_thread.py
mbetterclient/core/games_thread.py
+81
-64
match_timer.py
mbetterclient/core/match_timer.py
+7
-5
migrations.py
mbetterclient/database/migrations.py
+50
-0
models.py
mbetterclient/database/models.py
+1
-0
routes.py
mbetterclient/web_dashboard/routes.py
+70
-38
bet_details.html
...client/web_dashboard/templates/dashboard/bet_details.html
+3
-3
bets.html
mbetterclient/web_dashboard/templates/dashboard/bets.html
+2
-2
fixtures.html
...terclient/web_dashboard/templates/dashboard/fixtures.html
+2
-1
index.html
mbetterclient/web_dashboard/templates/dashboard/index.html
+2
-0
No files found.
mbetterclient/api_client/client.py
View file @
c00f9cdb
This diff is collapsed.
Click to expand it.
mbetterclient/core/games_thread.py
View file @
c00f9cdb
This diff is collapsed.
Click to expand it.
mbetterclient/core/match_timer.py
View file @
c00f9cdb
...
@@ -745,23 +745,25 @@ class MatchTimerComponent(ThreadedComponent):
...
@@ -745,23 +745,25 @@ class MatchTimerComponent(ThreadedComponent):
return
'all_bets_on_start'
return
'all_bets_on_start'
def
_select_random_match_templates
(
self
,
count
:
int
,
session
)
->
List
[
Any
]:
def
_select_random_match_templates
(
self
,
count
:
int
,
session
)
->
List
[
Any
]:
"""Select random match templates from the database"""
"""Select random match templates from the database
that have validated ZIP files
"""
try
:
try
:
from
..database.models
import
MatchTemplateModel
from
..database.models
import
MatchTemplateModel
from
sqlalchemy.orm
import
joinedload
from
sqlalchemy.orm
import
joinedload
# Get all active match templates
# Get all active match templates
with validated ZIP files
match_templates
=
session
.
query
(
MatchTemplateModel
)
.
options
(
joinedload
(
MatchTemplateModel
.
outcomes
))
.
filter
(
match_templates
=
session
.
query
(
MatchTemplateModel
)
.
options
(
joinedload
(
MatchTemplateModel
.
outcomes
))
.
filter
(
MatchTemplateModel
.
active_status
==
True
MatchTemplateModel
.
active_status
==
True
,
MatchTemplateModel
.
zip_upload_status
==
'completed'
,
MatchTemplateModel
.
zip_validation_status
==
'valid'
)
.
all
()
)
.
all
()
if
len
(
match_templates
)
<
count
:
if
len
(
match_templates
)
<
count
:
logger
.
warning
(
f
"Only {len(match_templates)} match templates found, requested {count}"
)
logger
.
warning
(
f
"Only {len(match_templates)}
validated
match templates found, requested {count}"
)
return
match_templates
return
match_templates
# Select random templates
# Select random templates
selected_templates
=
random
.
sample
(
match_templates
,
count
)
selected_templates
=
random
.
sample
(
match_templates
,
count
)
logger
.
info
(
f
"Selected {len(selected_templates)} random match templates"
)
logger
.
info
(
f
"Selected {len(selected_templates)} random
validated
match templates"
)
return
selected_templates
return
selected_templates
except
Exception
as
e
:
except
Exception
as
e
:
...
...
mbetterclient/database/migrations.py
View file @
c00f9cdb
...
@@ -2890,6 +2890,55 @@ class Migration_038_AddWin1Win2Associations(DatabaseMigration):
...
@@ -2890,6 +2890,55 @@ class Migration_038_AddWin1Win2Associations(DatabaseMigration):
return
False
return
False
class
Migration_039_AddMatchNumberToBetDetails
(
DatabaseMigration
):
"""Add match_number column to bets_details table for storing match numbers directly"""
def
__init__
(
self
):
super
()
.
__init__
(
"039"
,
"Add match_number column to bets_details table"
)
def
up
(
self
,
db_manager
)
->
bool
:
"""Add match_number column to bets_details table"""
try
:
with
db_manager
.
engine
.
connect
()
as
conn
:
# Check if match_number column already exists
result
=
conn
.
execute
(
text
(
"PRAGMA table_info(bets_details)"
))
columns
=
[
row
[
1
]
for
row
in
result
.
fetchall
()]
if
'match_number'
not
in
columns
:
# Add match_number column
conn
.
execute
(
text
(
"""
ALTER TABLE bets_details
ADD COLUMN match_number INTEGER
"""
))
# Populate existing records with match numbers from matches table
conn
.
execute
(
text
(
"""
UPDATE bets_details
SET match_number = (
SELECT m.match_number
FROM matches m
WHERE m.id = bets_details.match_id
)
WHERE match_number IS NULL
"""
))
conn
.
commit
()
logger
.
info
(
"match_number column added to bets_details table"
)
else
:
logger
.
info
(
"match_number column already exists in bets_details table"
)
return
True
except
Exception
as
e
:
logger
.
error
(
f
"Failed to add match_number column to bets_details: {e}"
)
return
False
def
down
(
self
,
db_manager
)
->
bool
:
"""Remove match_number column - SQLite doesn't support DROP COLUMN easily"""
logger
.
warning
(
"SQLite doesn't support DROP COLUMN - match_number column will remain"
)
return
True
class
Migration_036_AddMatchTemplatesTables
(
DatabaseMigration
):
class
Migration_036_AddMatchTemplatesTables
(
DatabaseMigration
):
"""Add matches_templates and match_outcomes_templates tables for storing match templates"""
"""Add matches_templates and match_outcomes_templates tables for storing match templates"""
...
@@ -3047,6 +3096,7 @@ MIGRATIONS: List[DatabaseMigration] = [
...
@@ -3047,6 +3096,7 @@ MIGRATIONS: List[DatabaseMigration] = [
Migration_036_AddMatchTemplatesTables
(),
Migration_036_AddMatchTemplatesTables
(),
Migration_037_RenameDailyRedistributionShortfallTable
(),
Migration_037_RenameDailyRedistributionShortfallTable
(),
Migration_038_AddWin1Win2Associations
(),
Migration_038_AddWin1Win2Associations
(),
Migration_039_AddMatchNumberToBetDetails
(),
]
]
...
...
mbetterclient/database/models.py
View file @
c00f9cdb
...
@@ -772,6 +772,7 @@ class BetDetailModel(BaseModel):
...
@@ -772,6 +772,7 @@ class BetDetailModel(BaseModel):
bet_id
=
Column
(
String
(
1024
),
ForeignKey
(
'bets.uuid'
),
nullable
=
False
,
comment
=
'Foreign key to bets table uuid field'
)
bet_id
=
Column
(
String
(
1024
),
ForeignKey
(
'bets.uuid'
),
nullable
=
False
,
comment
=
'Foreign key to bets table uuid field'
)
match_id
=
Column
(
Integer
,
ForeignKey
(
'matches.id'
),
nullable
=
False
,
comment
=
'Foreign key to matches table'
)
match_id
=
Column
(
Integer
,
ForeignKey
(
'matches.id'
),
nullable
=
False
,
comment
=
'Foreign key to matches table'
)
match_number
=
Column
(
Integer
,
comment
=
'Match number for display purposes'
)
outcome
=
Column
(
String
(
255
),
nullable
=
False
,
comment
=
'Bet outcome/prediction'
)
outcome
=
Column
(
String
(
255
),
nullable
=
False
,
comment
=
'Bet outcome/prediction'
)
amount
=
Column
(
Float
(
precision
=
2
),
nullable
=
False
,
comment
=
'Bet amount with 2 decimal precision'
)
amount
=
Column
(
Float
(
precision
=
2
),
nullable
=
False
,
comment
=
'Bet amount with 2 decimal precision'
)
win_amount
=
Column
(
Float
(
precision
=
2
),
default
=
0.0
,
nullable
=
False
,
comment
=
'Winning amount (calculated when result is win)'
)
win_amount
=
Column
(
Float
(
precision
=
2
),
default
=
0.0
,
nullable
=
False
,
comment
=
'Winning amount (calculated when result is win)'
)
...
...
mbetterclient/web_dashboard/routes.py
View file @
c00f9cdb
...
@@ -2592,9 +2592,9 @@ def get_fixture_details(fixture_id):
...
@@ -2592,9 +2592,9 @@ def get_fixture_details(fixture_id):
@
get_api_auth_decorator
()
@
get_api_auth_decorator
()
@
get_api_auth_decorator
(
require_admin
=
True
)
@
get_api_auth_decorator
(
require_admin
=
True
)
def
reset_fixtures
():
def
reset_fixtures
():
"""Reset all fixtures data (admin only) - clear matches, match_outcomes, and ZIP files"""
"""Reset all fixtures data (admin only) - clear matches, match_outcomes,
matches_templates, match_outcomes_templates, bets, extraction_stats,
and ZIP files"""
try
:
try
:
from
..database.models
import
MatchModel
,
MatchOutcomeModel
from
..database.models
import
MatchModel
,
MatchOutcomeModel
,
MatchTemplateModel
,
MatchOutcomeTemplateModel
,
BetModel
,
BetDetailModel
,
ExtractionStatsModel
from
..config.settings
import
get_user_data_dir
from
..config.settings
import
get_user_data_dir
from
pathlib
import
Path
from
pathlib
import
Path
import
shutil
import
shutil
...
@@ -2604,13 +2604,27 @@ def reset_fixtures():
...
@@ -2604,13 +2604,27 @@ def reset_fixtures():
# Count existing data before reset
# Count existing data before reset
matches_count
=
session
.
query
(
MatchModel
)
.
count
()
matches_count
=
session
.
query
(
MatchModel
)
.
count
()
outcomes_count
=
session
.
query
(
MatchOutcomeModel
)
.
count
()
outcomes_count
=
session
.
query
(
MatchOutcomeModel
)
.
count
()
templates_count
=
session
.
query
(
MatchTemplateModel
)
.
count
()
template_outcomes_count
=
session
.
query
(
MatchOutcomeTemplateModel
)
.
count
()
bets_count
=
session
.
query
(
BetModel
)
.
count
()
bet_details_count
=
session
.
query
(
BetDetailModel
)
.
count
()
extraction_stats_count
=
session
.
query
(
ExtractionStatsModel
)
.
count
()
# Delete in correct order to handle foreign key constraints
# 1. Delete extraction_stats first (references matches)
deleted_extraction_stats
=
session
.
query
(
ExtractionStatsModel
)
.
delete
()
session
.
commit
()
# 2. Delete bets (will cascade to bet_details due to CASCADE constraint)
deleted_bets
=
session
.
query
(
BetModel
)
.
delete
()
session
.
commit
()
#
Clear all match outcomes first (due to foreign key constraints
)
#
3. Delete matches (will cascade to match_outcomes due to CASCADE constraint
)
session
.
query
(
MatchOutcome
Model
)
.
delete
()
deleted_matches
=
session
.
query
(
Match
Model
)
.
delete
()
session
.
commit
()
session
.
commit
()
#
Clear all matches
#
4. Delete match templates (will cascade to match_outcomes_templates due to CASCADE constraint)
session
.
query
(
Match
Model
)
.
delete
()
deleted_templates
=
session
.
query
(
MatchTemplate
Model
)
.
delete
()
session
.
commit
()
session
.
commit
()
# Clear ZIP files from persistent storage
# Clear ZIP files from persistent storage
...
@@ -2630,7 +2644,7 @@ def reset_fixtures():
...
@@ -2630,7 +2644,7 @@ def reset_fixtures():
logger
.
info
(
f
"Removed {zip_files_removed} ZIP files from {zip_storage_dir}"
)
logger
.
info
(
f
"Removed {zip_files_removed} ZIP files from {zip_storage_dir}"
)
logger
.
info
(
f
"Fixtures reset completed - Removed {matches_count} matches, {outcomes_count} outcomes, {zip_files_removed} ZIP files"
)
logger
.
info
(
f
"Fixtures reset completed - Removed {matches_count} matches, {outcomes_count} outcomes, {
templates_count} templates, {template_outcomes_count} template outcomes, {bets_count} bets, {bet_details_count} bet details, {extraction_stats_count} extraction stats, {
zip_files_removed} ZIP files"
)
return
jsonify
({
return
jsonify
({
"success"
:
True
,
"success"
:
True
,
...
@@ -2638,6 +2652,11 @@ def reset_fixtures():
...
@@ -2638,6 +2652,11 @@ def reset_fixtures():
"removed"
:
{
"removed"
:
{
"matches"
:
matches_count
,
"matches"
:
matches_count
,
"outcomes"
:
outcomes_count
,
"outcomes"
:
outcomes_count
,
"templates"
:
templates_count
,
"template_outcomes"
:
template_outcomes_count
,
"bets"
:
bets_count
,
"bet_details"
:
bet_details_count
,
"extraction_stats"
:
extraction_stats_count
,
"zip_files"
:
zip_files_removed
"zip_files"
:
zip_files_removed
}
}
})
})
...
@@ -4120,19 +4139,20 @@ def get_redistribution_balance():
...
@@ -4120,19 +4139,20 @@ def get_redistribution_balance():
session
=
api_bp
.
db_manager
.
get_session
()
session
=
api_bp
.
db_manager
.
get_session
()
try
:
try
:
# Get the latest redistribution adjustment record
# Get the global redistribution adjustment record (fixed date 1970-01-01)
latest_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
\
global_date
=
date
(
1970
,
1
,
1
)
.
order_by
(
PersistentRedistributionAdjustmentModel
.
date
.
desc
())
\
global_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
\
.
filter_by
(
date
=
global_date
)
\
.
first
()
.
first
()
current_balance
=
0.0
current_balance
=
0.0
if
latest
_record
:
if
global
_record
:
current_balance
=
float
(
latest
_record
.
accumulated_shortfall
)
current_balance
=
float
(
global
_record
.
accumulated_shortfall
)
return
jsonify
({
return
jsonify
({
"success"
:
True
,
"success"
:
True
,
"redistribution_balance"
:
current_balance
,
"redistribution_balance"
:
current_balance
,
"last_updated"
:
latest_record
.
date
.
isoformat
()
if
latest
_record
else
None
"last_updated"
:
global_record
.
updated_at
.
isoformat
()
if
global
_record
else
None
})
})
finally
:
finally
:
...
@@ -4154,19 +4174,20 @@ def reset_redistribution_balance():
...
@@ -4154,19 +4174,20 @@ def reset_redistribution_balance():
session
=
api_bp
.
db_manager
.
get_session
()
session
=
api_bp
.
db_manager
.
get_session
()
try
:
try
:
# Get the latest redistribution adjustment record
# Get the global redistribution adjustment record (fixed date 1970-01-01)
latest_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
\
global_date
=
date
(
1970
,
1
,
1
)
.
order_by
(
PersistentRedistributionAdjustmentModel
.
date
.
desc
())
\
global_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
\
.
filter_by
(
date
=
global_date
)
\
.
first
()
.
first
()
if
latest
_record
:
if
global
_record
:
# Reset the accumulated shortfall to zero
# Reset the accumulated shortfall to zero
old_balance
=
float
(
latest
_record
.
accumulated_shortfall
)
old_balance
=
float
(
global
_record
.
accumulated_shortfall
)
latest
_record
.
accumulated_shortfall
=
0.0
global
_record
.
accumulated_shortfall
=
0.0
latest
_record
.
updated_at
=
datetime
.
utcnow
()
global
_record
.
updated_at
=
datetime
.
utcnow
()
session
.
commit
()
session
.
commit
()
logger
.
info
(
f
"
R
edistribution balance reset from {old_balance} to 0.0"
)
logger
.
info
(
f
"
Global r
edistribution balance reset from {old_balance} to 0.0"
)
return
jsonify
({
return
jsonify
({
"success"
:
True
,
"success"
:
True
,
...
@@ -4175,21 +4196,20 @@ def reset_redistribution_balance():
...
@@ -4175,21 +4196,20 @@ def reset_redistribution_balance():
"new_balance"
:
0.0
"new_balance"
:
0.0
})
})
else
:
else
:
# No record exists, create one with zero balance
# No global record exists, create one with zero balance
today
=
date
.
today
()
new_record
=
PersistentRedistributionAdjustmentModel
(
new_record
=
PersistentRedistributionAdjustmentModel
(
date
=
today
,
date
=
global_date
,
accumulated_shortfall
=
0.0
,
accumulated_shortfall
=
0.0
,
cap_percentage
=
70.0
# Default cap
cap_percentage
=
70.0
# Default cap
)
)
session
.
add
(
new_record
)
session
.
add
(
new_record
)
session
.
commit
()
session
.
commit
()
logger
.
info
(
"Created
new
redistribution adjustment record with zero balance"
)
logger
.
info
(
"Created
global
redistribution adjustment record with zero balance"
)
return
jsonify
({
return
jsonify
({
"success"
:
True
,
"success"
:
True
,
"message"
:
"Redistribution balance set to 0.00 (
new
record created)"
,
"message"
:
"Redistribution balance set to 0.00 (
global
record created)"
,
"old_balance"
:
None
,
"old_balance"
:
None
,
"new_balance"
:
0.0
"new_balance"
:
0.0
})
})
...
@@ -4626,6 +4646,8 @@ def create_cashier_bet():
...
@@ -4626,6 +4646,8 @@ def create_cashier_bet():
existing_match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
match_id
)
.
first
()
existing_match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
match_id
)
.
first
()
if
not
existing_match
:
if
not
existing_match
:
return
jsonify
({
"error"
:
f
"Match {match_id} not found"
}),
404
return
jsonify
({
"error"
:
f
"Match {match_id} not found"
}),
404
# Store match_number for later use
detail
[
'_match_number'
]
=
existing_match
.
match_number
# Generate UUID for the bet
# Generate UUID for the bet
bet_uuid
=
str
(
uuid_lib
.
uuid4
())
bet_uuid
=
str
(
uuid_lib
.
uuid4
())
...
@@ -4702,6 +4724,7 @@ def create_cashier_bet():
...
@@ -4702,6 +4724,7 @@ def create_cashier_bet():
bet_detail
=
BetDetailModel
(
bet_detail
=
BetDetailModel
(
bet_id
=
bet_uuid
,
bet_id
=
bet_uuid
,
match_id
=
detail_data
[
'match_id'
],
match_id
=
detail_data
[
'match_id'
],
match_number
=
detail_data
[
'_match_number'
],
outcome
=
detail_data
[
'outcome'
],
outcome
=
detail_data
[
'outcome'
],
amount
=
float
(
detail_data
[
'amount'
]),
amount
=
float
(
detail_data
[
'amount'
]),
result
=
'pending'
result
=
'pending'
...
@@ -4774,6 +4797,9 @@ def get_cashier_bet_details(bet_id):
...
@@ -4774,6 +4797,9 @@ def get_cashier_bet_details(bet_id):
for
detail
in
bet_details
:
for
detail
in
bet_details
:
detail_data
=
detail
.
to_dict
()
detail_data
=
detail
.
to_dict
()
# Include stored match_number
detail_data
[
'match_number'
]
=
detail
.
match_number
# Get match information
# Get match information
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
if
match
:
if
match
:
...
@@ -5179,6 +5205,9 @@ def verify_bet_details(bet_id):
...
@@ -5179,6 +5205,9 @@ def verify_bet_details(bet_id):
for
detail
in
bet_details
:
for
detail
in
bet_details
:
detail_data
=
detail
.
to_dict
()
detail_data
=
detail
.
to_dict
()
# Include stored match_number
detail_data
[
'match_number'
]
=
detail
.
match_number
# Get match information
# Get match information
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
if
match
:
if
match
:
...
@@ -5255,6 +5284,9 @@ def verify_barcode():
...
@@ -5255,6 +5284,9 @@ def verify_barcode():
detail_data
=
detail
.
to_dict
()
detail_data
=
detail
.
to_dict
()
total_amount
+=
float
(
detail
.
amount
)
total_amount
+=
float
(
detail
.
amount
)
# Include stored match_number
detail_data
[
'match_number'
]
=
detail
.
match_number
# Get match information
# Get match information
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
match
=
session
.
query
(
MatchModel
)
.
filter_by
(
id
=
detail
.
match_id
)
.
first
()
if
match
:
if
match
:
...
...
mbetterclient/web_dashboard/templates/dashboard/bet_details.html
View file @
c00f9cdb
...
@@ -89,9 +89,9 @@
...
@@ -89,9 +89,9 @@
{% for detail in bet.bet_details %}
{% for detail in bet.bet_details %}
<tr>
<tr>
<td>
<td>
<strong>
Match #{{ detail.match
.match
_number }}
</strong><br>
<strong>
Match #{{ detail.match_number }}
</strong><br>
<small
class=
"text-muted"
>
<small
class=
"text-muted"
>
{{ detail.match.fighter1_township
}} vs {{ detail.match.fighter2_township
}}
{{ detail.match.fighter1_township
if detail.match else 'Unknown' }} vs {{ detail.match.fighter2_township if detail.match else 'Unknown'
}}
</small>
</small>
</td>
</td>
<td>
<td>
...
@@ -450,7 +450,7 @@
...
@@ -450,7 +450,7 @@
"bet_details"
:
[
"bet_details"
:
[
{
%
for
detail
in
bet
.
bet_details
%
}
{
%
for
detail
in
bet
.
bet_details
%
}
{
{
"match_number"
:
"{{ detail.match
.match_number if detail.match else 'Unknown'
}}"
,
"match_number"
:
"{{ detail.match
_number
}}"
,
"fighter1"
:
"{{ detail.match.fighter1_township if detail.match else 'Unknown' }}"
,
"fighter1"
:
"{{ detail.match.fighter1_township if detail.match else 'Unknown' }}"
,
"fighter2"
:
"{{ detail.match.fighter2_township if detail.match else 'Unknown' }}"
,
"fighter2"
:
"{{ detail.match.fighter2_township if detail.match else 'Unknown' }}"
,
"venue"
:
"{{ detail.match.venue_kampala_township if detail.match else 'Unknown' }}"
,
"venue"
:
"{{ detail.match.venue_kampala_township if detail.match else 'Unknown' }}"
,
...
...
mbetterclient/web_dashboard/templates/dashboard/bets.html
View file @
c00f9cdb
...
@@ -533,7 +533,7 @@ function updateBetsTable(data, container) {
...
@@ -533,7 +533,7 @@ function updateBetsTable(data, container) {
const
totalAmount
=
parseFloat
(
bet
.
total_amount
).
toFixed
(
2
);
const
totalAmount
=
parseFloat
(
bet
.
total_amount
).
toFixed
(
2
);
// Collect unique match numbers
// Collect unique match numbers
const
matchNumbers
=
[...
new
Set
(
bet
.
details
?
bet
.
details
.
map
(
detail
=>
detail
.
match
?
detail
.
match
.
match_number
:
'Unknown'
).
filter
(
n
=>
n
!==
'Unknown'
)
:
[])];
const
matchNumbers
=
[...
new
Set
(
bet
.
details
?
bet
.
details
.
map
(
detail
=>
detail
.
match
_number
||
'Unknown'
).
filter
(
n
=>
n
!==
'Unknown'
)
:
[])];
// Determine overall bet status based on details
// Determine overall bet status based on details
let
overallStatus
=
'pending'
;
let
overallStatus
=
'pending'
;
...
@@ -719,7 +719,7 @@ function transformBetDataForReceipt(betData) {
...
@@ -719,7 +719,7 @@ function transformBetDataForReceipt(betData) {
total_amount
:
betData
.
total_amount
,
total_amount
:
betData
.
total_amount
,
bet_count
:
betData
.
details_count
||
betData
.
details
.
length
,
bet_count
:
betData
.
details_count
||
betData
.
details
.
length
,
bet_details
:
betData
.
details
.
map
(
detail
=>
({
bet_details
:
betData
.
details
.
map
(
detail
=>
({
match_number
:
detail
.
match
?
detail
.
match
.
match_number
:
'Unknown'
,
match_number
:
detail
.
match
_number
||
'Unknown'
,
fighter1
:
detail
.
match
?
detail
.
match
.
fighter1_township
:
'Unknown'
,
fighter1
:
detail
.
match
?
detail
.
match
.
fighter1_township
:
'Unknown'
,
fighter2
:
detail
.
match
?
detail
.
match
.
fighter2_township
:
'Unknown'
,
fighter2
:
detail
.
match
?
detail
.
match
.
fighter2_township
:
'Unknown'
,
venue
:
detail
.
match
?
detail
.
match
.
venue_kampala_township
:
'Unknown'
,
venue
:
detail
.
match
?
detail
.
match
.
venue_kampala_township
:
'Unknown'
,
...
...
mbetterclient/web_dashboard/templates/dashboard/fixtures.html
View file @
c00f9cdb
...
@@ -477,6 +477,7 @@ function getUploadStatusBadge(fixture) {
...
@@ -477,6 +477,7 @@ function getUploadStatusBadge(fixture) {
function
resetFixtures
()
{
function
resetFixtures
()
{
const
confirmMessage
=
'WARNING: This will permanently delete ALL fixture data including:
\
n
\
n'
+
const
confirmMessage
=
'WARNING: This will permanently delete ALL fixture data including:
\
n
\
n'
+
'• All synchronized matches and outcomes
\
n'
+
'• All synchronized matches and outcomes
\
n'
+
'• All match templates and template outcomes
\
n'
+
'• All downloaded ZIP files
\
n'
+
'• All downloaded ZIP files
\
n'
+
'• This action cannot be undone!
\
n
\
n'
+
'• This action cannot be undone!
\
n
\
n'
+
'Are you sure you want to reset all fixtures data?'
;
'Are you sure you want to reset all fixtures data?'
;
...
@@ -500,7 +501,7 @@ function resetFixtures() {
...
@@ -500,7 +501,7 @@ function resetFixtures() {
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
.
then
(
data
=>
{
if
(
data
.
success
)
{
if
(
data
.
success
)
{
alert
(
`Fixtures reset successfully!\n\nRemoved:\n•
${
data
.
removed
.
matches
}
matches\n•
${
data
.
removed
.
outcomes
}
outcomes\n•
${
data
.
removed
.
zip_files
}
ZIP files`
);
alert
(
`Fixtures reset successfully!\n\nRemoved:\n•
${
data
.
removed
.
matches
}
matches\n•
${
data
.
removed
.
outcomes
}
outcomes\n•
${
data
.
removed
.
templates
}
match templates\n•
${
data
.
removed
.
template_outcomes
}
template outcomes\n•
${
data
.
removed
.
zip_files
}
ZIP files`
);
// Reload fixtures to show empty state
// Reload fixtures to show empty state
loadFixtures
();
loadFixtures
();
}
else
{
}
else
{
...
...
mbetterclient/web_dashboard/templates/dashboard/index.html
View file @
c00f9cdb
...
@@ -499,6 +499,8 @@ document.addEventListener('DOMContentLoaded', function() {
...
@@ -499,6 +499,8 @@ document.addEventListener('DOMContentLoaded', function() {
// Load redistribution balance (admin only)
// Load redistribution balance (admin only)
if
(
document
.
getElementById
(
'redistribution-balance'
))
{
if
(
document
.
getElementById
(
'redistribution-balance'
))
{
loadRedistributionBalance
();
loadRedistributionBalance
();
// Periodic update of redistribution balance
setInterval
(
loadRedistributionBalance
,
5000
);
// Update every 5 seconds
}
}
// Quick action buttons
// Quick action buttons
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment