Auto commit: 2026-01-31T23:58:19.892Z
This commit is contained in:
parent
d49fff7c1d
commit
8b1d207a4e
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|
||||||
const TicketsService = require('../services/tickets');
|
const TicketsService = require('../services/tickets');
|
||||||
@ -54,6 +53,11 @@ router.use(checkCrudPermissions('tickets'));
|
|||||||
* description: The Tickets managing API
|
* description: The Tickets managing API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
router.post('/generate', wrapAsync(async (req, res) => {
|
||||||
|
const payload = await TicketsService.generateAutoTicket(req.body.data, req.currentUser);
|
||||||
|
res.status(200).send(payload);
|
||||||
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /api/tickets:
|
* /api/tickets:
|
||||||
@ -439,4 +443,4 @@ router.get('/:id', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
router.use('/', require('../helpers').commonErrorHandler);
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@ -132,7 +132,76 @@ module.exports = class TicketsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async generateAutoTicket(data, currentUser) {
|
||||||
};
|
const { desired_odds, game_count } = data;
|
||||||
|
const targetOdds = parseFloat(desired_odds) || 2.0;
|
||||||
|
const count = parseInt(game_count) || 3;
|
||||||
|
|
||||||
|
// 1. Get all active selections with their game info
|
||||||
|
const selections = await db.selections.findAll({
|
||||||
|
include: [{
|
||||||
|
model: db.markets,
|
||||||
|
as: 'market',
|
||||||
|
include: [{
|
||||||
|
model: db.games,
|
||||||
|
as: 'game',
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (selections.length === 0) {
|
||||||
|
throw new Error('No selections available in the database');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group selections by game to ensure we pick from different games
|
||||||
|
const gameGroups = {};
|
||||||
|
selections.forEach(s => {
|
||||||
|
if (s.market && s.market.game) {
|
||||||
|
const gameId = s.market.game.id;
|
||||||
|
if (!gameGroups[gameId]) gameGroups[gameId] = [];
|
||||||
|
gameGroups[gameId].push(s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const gameIds = Object.keys(gameGroups);
|
||||||
|
const actualCount = Math.min(count, gameIds.length);
|
||||||
|
|
||||||
|
if (actualCount === 0) {
|
||||||
|
throw new Error('Not enough games available');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try multiple times to find a good combination
|
||||||
|
let bestTicket = null;
|
||||||
|
let minDiff = Infinity;
|
||||||
|
|
||||||
|
for (let i = 0; i < 200; i++) {
|
||||||
|
// Randomly pick actualCount games
|
||||||
|
const shuffledGames = gameIds.sort(() => 0.5 - Math.random());
|
||||||
|
const selectedGameIds = shuffledGames.slice(0, actualCount);
|
||||||
|
|
||||||
|
const currentSelections = [];
|
||||||
|
let currentTotalOdds = 1;
|
||||||
|
|
||||||
|
selectedGameIds.forEach(gid => {
|
||||||
|
const gameSelections = gameGroups[gid];
|
||||||
|
const randomSelection = gameSelections[Math.floor(Math.random() * gameSelections.length)];
|
||||||
|
currentSelections.push(randomSelection);
|
||||||
|
currentTotalOdds *= parseFloat(randomSelection.odds);
|
||||||
|
});
|
||||||
|
|
||||||
|
const diff = Math.abs(currentTotalOdds - targetOdds);
|
||||||
|
if (diff < minDiff) {
|
||||||
|
minDiff = diff;
|
||||||
|
bestTicket = {
|
||||||
|
selections: currentSelections,
|
||||||
|
totalOdds: currentTotalOdds,
|
||||||
|
gameCount: actualCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minDiff < 0.05) break; // Close enough
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestTicket;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -122,6 +122,22 @@ export const update = createAsyncThunk('tickets/updateTickets', async (payload:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const generateAutoTicket = createAsyncThunk('tickets/generateAutoTicket', async (data: any, { rejectWithValue }) => {
|
||||||
|
try {
|
||||||
|
const result = await axios.post(
|
||||||
|
'tickets/generate',
|
||||||
|
{ data }
|
||||||
|
)
|
||||||
|
return result.data
|
||||||
|
} catch (error) {
|
||||||
|
if (!error.response) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rejectWithValue(error.response.data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
export const ticketsSlice = createSlice({
|
export const ticketsSlice = createSlice({
|
||||||
name: 'tickets',
|
name: 'tickets',
|
||||||
@ -221,6 +237,19 @@ export const ticketsSlice = createSlice({
|
|||||||
rejectNotify(state, action);
|
rejectNotify(state, action);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.addCase(generateAutoTicket.pending, (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
resetNotify(state);
|
||||||
|
})
|
||||||
|
builder.addCase(generateAutoTicket.fulfilled, (state) => {
|
||||||
|
state.loading = false;
|
||||||
|
fulfilledNotify(state, 'Ticket generated successfully');
|
||||||
|
})
|
||||||
|
builder.addCase(generateAutoTicket.rejected, (state, action) => {
|
||||||
|
state.loading = false;
|
||||||
|
rejectNotify(state, action);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -228,4 +257,4 @@ export const ticketsSlice = createSlice({
|
|||||||
// Action creators are generated for each case reducer function
|
// Action creators are generated for each case reducer function
|
||||||
export const { setRefetch } = ticketsSlice.actions
|
export const { setRefetch } = ticketsSlice.actions
|
||||||
|
|
||||||
export default ticketsSlice.reducer
|
export default ticketsSlice.reducer
|
||||||
Loading…
x
Reference in New Issue
Block a user