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
Hide 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
This diff is collapsed.
Click to expand it.
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