delete generated code
This commit is contained in:
@ -46,7 +46,8 @@ const ProtectedRoute = ({ children, allowedRoles, deniedMessage, bypass = false,
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center">
|
||||
<h1 className="text-2xl font-bold mb-4 text-blue-500">{session?.user?.email},</h1>
|
||||
<p className="mb-6">{`Нямате достъп до тази страница. Ако мислите, че това е грешка, моля, свържете се с администраторите`}</p>
|
||||
<p className="mb-6">{`Нямате достъп до тази страница.`}</p>
|
||||
<p className="mb-6">{`Ако мислите, че това е грешка, моля, свържете се с администраторите`}</p>
|
||||
</div>
|
||||
</div>
|
||||
</>);
|
||||
|
@ -871,230 +871,6 @@ async function ImportShiftsFromDocx(axios: Axios) {
|
||||
}
|
||||
|
||||
|
||||
async function GenerateOptimalSchedule(axios, date, copyFromPreviousMonth = false, autoFill = false, forDay) {
|
||||
const prisma = common.getPrismaClient();
|
||||
try {
|
||||
const monthInfo = common.getMonthDatesInfo(new Date(date));
|
||||
const lastMonthInfo = common.getMonthDatesInfo(new Date(monthInfo.date.getFullYear(), monthInfo.date.getMonth() - 1, 1));
|
||||
|
||||
if (forDay) {
|
||||
await DeleteShiftsForDay(monthInfo.date);
|
||||
} else {
|
||||
await DeleteShiftsForMonth(monthInfo);
|
||||
}
|
||||
|
||||
const events = await prisma.cartEvent.findMany({
|
||||
where: {
|
||||
isActive: true
|
||||
}
|
||||
});
|
||||
let shiftsLastMonth = await getShiftsFromLastMonth(lastMonthInfo);
|
||||
let publishers = await data.getAllPublishersWithStatisticsMonth(date, false, false);
|
||||
|
||||
let day = new Date(monthInfo.firstMonday);
|
||||
let endDate = monthInfo.lastSunday;
|
||||
let weekNr = 1;
|
||||
|
||||
if (forDay) {
|
||||
day = monthInfo.date;
|
||||
endDate = new Date(monthInfo.date.getTime() + 86400000); // +1 day
|
||||
weekNr = common.getWeekNumber(monthInfo.date);
|
||||
}
|
||||
|
||||
let allShifts = [];
|
||||
|
||||
// First pass: Generate shifts and copy assignments from the previous month
|
||||
while (day < endDate) {
|
||||
let dayShifts = await generateShiftsForDay(day, events, shiftsLastMonth, weekNr, copyFromPreviousMonth);
|
||||
allShifts = [...allShifts, ...dayShifts];
|
||||
|
||||
day.setDate(day.getDate() + 1);
|
||||
if (common.DaysOfWeekArray[day.getDayEuropean()] === DayOfWeek.Sunday) {
|
||||
weekNr++;
|
||||
}
|
||||
if (forDay) break;
|
||||
}
|
||||
|
||||
// Second pass: Optimize assignments
|
||||
allShifts = await optimizeAssignments(allShifts, publishers, events);
|
||||
|
||||
// Save optimized shifts to the database
|
||||
for (let shift of allShifts) {
|
||||
await saveShiftToDB(shift);
|
||||
}
|
||||
|
||||
return {};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return { error: error };
|
||||
}
|
||||
}
|
||||
|
||||
async function generateShiftsForDay(day, events, shiftsLastMonth, weekNr, copyFromPreviousMonth) {
|
||||
const prisma = common.getPrismaClient();
|
||||
let dayShifts = [];
|
||||
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
|
||||
let dayName = common.DaysOfWeekArray[day.getDayEuropean()];
|
||||
const event = events.find((event) => event.dayofweek == dayName && (event.dayOfMonth == null || event.dayOfMonth == day.getDate()));
|
||||
|
||||
if (!event) return dayShifts;
|
||||
|
||||
let startTime = new Date(day);
|
||||
startTime.setHours(event.startTime.getHours(), event.startTime.getMinutes());
|
||||
let endTime = new Date(day);
|
||||
endTime.setHours(event.endTime.getHours(), event.endTime.getMinutes());
|
||||
|
||||
let shiftStart = new Date(startTime);
|
||||
let shiftEnd = new Date(startTime);
|
||||
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
|
||||
|
||||
let shiftNr = 0;
|
||||
while (shiftEnd <= endTime) {
|
||||
shiftNr++;
|
||||
let isTransportRequired = shiftNr == 1 || shiftEnd.getTime() == endTime.getTime();
|
||||
|
||||
let shift = {
|
||||
startTime: new Date(shiftStart),
|
||||
endTime: new Date(shiftEnd),
|
||||
name: `${event.dayofweek} ${shiftStart.toLocaleTimeString()} - ${shiftEnd.toLocaleTimeString()}`,
|
||||
requiresTransport: isTransportRequired,
|
||||
cartEventId: event.id,
|
||||
assignments: [],
|
||||
};
|
||||
|
||||
if (copyFromPreviousMonth) {
|
||||
const shiftLastMonthSameDay = findTheSameShiftFromLastMonth(shiftsLastMonth, day, weekNr, shiftNr);
|
||||
if (shiftLastMonthSameDay) {
|
||||
shift.assignments = shiftLastMonthSameDay.assignments
|
||||
.map(a => ({
|
||||
publisherId: a.publisher.id,
|
||||
isConfirmed: true,
|
||||
isWithTransport: a.isWithTransport
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
dayShifts.push(shift);
|
||||
|
||||
shiftStart = new Date(shiftEnd);
|
||||
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
|
||||
}
|
||||
|
||||
return dayShifts;
|
||||
}
|
||||
|
||||
async function optimizeAssignments(allShifts, publishers, events) {
|
||||
let scheduledPubsPerDayAndWeek = {};
|
||||
|
||||
for (let shift of allShifts) {
|
||||
const event = events.find(e => e.id === shift.cartEventId);
|
||||
const day = new Date(shift.startTime);
|
||||
const weekNr = common.getWeekNumber(day);
|
||||
|
||||
let availablePubs = await getAvailablePublishersForShiftNew(shift.startTime, shift.endTime, publishers, []);
|
||||
availablePubs = filterPublishersForShift(availablePubs, shift, scheduledPubsPerDayAndWeek, day, weekNr);
|
||||
|
||||
while (shift.assignments.length < event.numberOfPublishers && availablePubs.length > 0) {
|
||||
const rankedPubs = rankPublishersForShift(availablePubs, scheduledPubsPerDayAndWeek, day, weekNr);
|
||||
const selectedPub = rankedPubs[0];
|
||||
|
||||
shift.assignments.push({
|
||||
publisherId: selectedPub.id,
|
||||
isConfirmed: true,
|
||||
isWithTransport: shift.requiresTransport && (selectedPub.isWithTransportIn || selectedPub.isWithTransportOut)
|
||||
});
|
||||
|
||||
updateRegistry(selectedPub.id, day, weekNr, scheduledPubsPerDayAndWeek);
|
||||
selectedPub.currentMonthAssignments++;
|
||||
|
||||
availablePubs = availablePubs.filter(p => p.id !== selectedPub.id);
|
||||
}
|
||||
}
|
||||
|
||||
return allShifts;
|
||||
}
|
||||
|
||||
function filterPublishersForShift(publishers, shift, scheduledPubsPerDayAndWeek, day, weekNr) {
|
||||
const dayKey = common.getISODateOnly(day);
|
||||
return publishers.filter(p => {
|
||||
const isNotAssigned = !shift.assignments.some(a => a.publisherId === p.id);
|
||||
const isNotAssignedToday = !flattenRegistry(scheduledPubsPerDayAndWeek[dayKey]).includes(p.id);
|
||||
const isNotOverAssigned = p.currentMonthAssignments < p.desiredShiftsPerMonth;
|
||||
const isNotAssignedThisWeek = !Object.keys(scheduledPubsPerDayAndWeek)
|
||||
.filter(key => common.getWeekNumber(new Date(key)) === weekNr)
|
||||
.some(key => flattenRegistry(scheduledPubsPerDayAndWeek[key]).includes(p.id));
|
||||
|
||||
return isNotAssigned && isNotAssignedToday && isNotOverAssigned && isNotAssignedThisWeek;
|
||||
});
|
||||
}
|
||||
|
||||
function rankPublishersForShift(publishers, scheduledPubsPerDayAndWeek, currentDay, currentWeekNr) {
|
||||
const weights = {
|
||||
gender: 2,
|
||||
desiredCompletion: 3,
|
||||
availability: 2,
|
||||
lastMonthCompletion: 3,
|
||||
currentAssignments: 1
|
||||
};
|
||||
|
||||
const totalWeight = Object.values(weights).reduce((acc, val) => acc + val, 0);
|
||||
Object.keys(weights).forEach(key => {
|
||||
weights[key] /= totalWeight;
|
||||
});
|
||||
|
||||
publishers.forEach(p => {
|
||||
p.score = calculatePublisherScore(p, weights, scheduledPubsPerDayAndWeek, currentDay, currentWeekNr);
|
||||
});
|
||||
|
||||
return publishers.sort((a, b) => b.score - a.score);
|
||||
}
|
||||
|
||||
function calculatePublisherScore(publisher, weights, scheduledPubsPerDayAndWeek, currentDay, currentWeekNr) {
|
||||
let score = (publisher.isMale ? weights.gender : 0) -
|
||||
((publisher.currentMonthAssignments / publisher.desiredShiftsPerMonth) * weights.desiredCompletion) +
|
||||
((1 - publisher.currentMonthAvailabilityHoursCount / 24) * weights.availability) +
|
||||
((publisher.previousMonthAssignments / publisher.currentMonthAssignments) * weights.lastMonthCompletion) -
|
||||
(publisher.currentMonthAssignments * weights.currentAssignments);
|
||||
|
||||
// Apply penalties for nearby assignments
|
||||
for (let i = 1; i <= 6; i++) {
|
||||
const previousDayKey = common.getISODateOnly(addDays(currentDay, -i));
|
||||
const nextDayKey = common.getISODateOnly(addDays(currentDay, i));
|
||||
const penalty = [0.5, 0.7, 0.8, 0.85, 0.9, 0.95][i - 1];
|
||||
|
||||
if (flattenRegistry(scheduledPubsPerDayAndWeek[previousDayKey]).includes(publisher.id) ||
|
||||
flattenRegistry(scheduledPubsPerDayAndWeek[nextDayKey]).includes(publisher.id)) {
|
||||
score *= penalty;
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
async function saveShiftToDB(shift) {
|
||||
const prisma = common.getPrismaClient();
|
||||
await prisma.shift.create({
|
||||
data: {
|
||||
startTime: shift.startTime,
|
||||
endTime: shift.endTime,
|
||||
name: shift.name,
|
||||
requiresTransport: shift.requiresTransport,
|
||||
cartEvent: {
|
||||
connect: {
|
||||
id: shift.cartEventId,
|
||||
},
|
||||
},
|
||||
assignments: {
|
||||
create: shift.assignments.map(a => ({
|
||||
publisher: {
|
||||
connect: { id: a.publisherId }
|
||||
},
|
||||
isWithTransport: a.isWithTransport,
|
||||
isConfirmed: a.isConfirmed,
|
||||
isBySystem: true,
|
||||
})),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
//region helpers
|
||||
// *********************************************************************************************************************
|
||||
|
Reference in New Issue
Block a user