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 TicketsService = require('../services/tickets');
|
||||
@ -54,6 +53,11 @@ router.use(checkCrudPermissions('tickets'));
|
||||
* 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
|
||||
* /api/tickets:
|
||||
@ -439,4 +443,4 @@ router.get('/:id', wrapAsync(async (req, res) => {
|
||||
|
||||
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({
|
||||
name: 'tickets',
|
||||
@ -221,6 +237,19 @@ export const ticketsSlice = createSlice({
|
||||
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
|
||||
export const { setRefetch } = ticketsSlice.actions
|
||||
|
||||
export default ticketsSlice.reducer
|
||||
export default ticketsSlice.reducer
|
||||
Loading…
x
Reference in New Issue
Block a user