diff --git a/pages/api/shiftgenerate.ts b/pages/api/shiftgenerate.ts
index 214ad13..2a35b75 100644
--- a/pages/api/shiftgenerate.ts
+++ b/pages/api/shiftgenerate.ts
@@ -123,25 +123,65 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
// ### COPIED TO shift api (++) ###
-
-let scheduledPubsPerDayAndWeek = {};
+let publisherMonthlyAssignments = new Map();
+let scheduledPubsCacheStatistics = {};
// Function to flatten the registry
// Function to update the registry
function updateRegistry(publisherId, day, weekNr) {
// Registry schema: {day: {weekNr: [publisherIds]}}
const dayKey = common.getISODateOnly(day);
- if (!scheduledPubsPerDayAndWeek[dayKey]) {
- scheduledPubsPerDayAndWeek[dayKey] = {};
+ if (!scheduledPubsCacheStatistics[dayKey]) {
+ scheduledPubsCacheStatistics[dayKey] = {};
}
- if (!scheduledPubsPerDayAndWeek[dayKey][weekNr]) {
- scheduledPubsPerDayAndWeek[dayKey][weekNr] = [];
+ if (!scheduledPubsCacheStatistics[dayKey][weekNr]) {
+ scheduledPubsCacheStatistics[dayKey][weekNr] = [];
}
- scheduledPubsPerDayAndWeek[dayKey][weekNr].push(publisherId);
+ scheduledPubsCacheStatistics[dayKey][weekNr].push(publisherId);
+ // Update monthly assignments
+ const currentCount = publisherMonthlyAssignments.get(publisherId) || 0;
+ publisherMonthlyAssignments.set(publisherId, currentCount + 1);
}
function flattenRegistry(dayKey) {
- const weekEntries = scheduledPubsPerDayAndWeek[dayKey] || {};
+ const weekEntries = scheduledPubsCacheStatistics[dayKey] || {};
return Object.values(weekEntries).flat();
}
+// Function to initialize monthly counts from database
+async function initializeMonthlyAssignments(prisma, startOfMonth, endOfMonth) {
+ const monthlyAssignments = await prisma.assignment.groupBy({
+ by: ['publisherId'],
+ where: {
+ shift: {
+ startTime: {
+ gte: startOfMonth,
+ lte: endOfMonth
+ }
+ }
+ },
+ _count: {
+ publisherId: true
+ }
+ });
+
+ publisherMonthlyAssignments = new Map(
+ monthlyAssignments.map(count => [
+ count.publisherId,
+ count._count.publisherId
+ ])
+ );
+}
+// Function to get current assignment count for a publisher
+function getPublisherAssignmentCount(publisherId) {
+ return publisherMonthlyAssignments.get(publisherId) || 0;
+}
+
+// Function to update publishers with their current counts
+function updatePublishersWithCurrentCounts(publishers) {
+ return publishers.map(pub => ({
+ ...pub,
+ currentMonthAssignments: getPublisherAssignmentCount(pub.id)
+ }));
+}
+
async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, autoFill = false, forDay, algType = 0, until) {
@@ -167,7 +207,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
let shiftsLastMonth = await getShiftsFromLastMonth(lastMonthInfo);
let publishers = await data.getAllPublishersWithStatisticsMonth(date, false, false);
- let shiftAssignments = [];
+ let shiftAssignments: any[] = [];
let day = new Date(monthInfo.firstMonday);
let endDate = monthInfo.lastSunday;
let dayNr = 1;
@@ -188,7 +228,12 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
weekNr = common.getWeekNumber(monthInfo.date);
}
- let publishersThisWeek = [];
+ /**
+ * An array to store the publishers for the current week.
+ *
+ * @type {never[]}
+ */
+ let publishersThisWeek: never[] = [];
// # # # # # # # # # # #
@@ -242,25 +287,25 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
//---------------------------------------------------
// // COMMENT TO DISABLE COPY FROM LAST MONTH
- if (availability && copyFromPreviousMonth && !publishersThisWeek.includes(publisher.id)) {
- const transportCount = shiftAssignments.filter(a => a.isWithTransport).length;
- const isWithTransport = availability.isWithTransportIn || availability.isWithTransportOut;
+ // if (availability && copyFromPreviousMonth && !publishersThisWeek.includes(publisher.id)) {
+ // const transportCount = shiftAssignments.filter(a => a.isWithTransport).length;
+ // const isWithTransport = availability.isWithTransportIn || availability.isWithTransportOut;
- if (!isWithTransport || transportCount < 2) {
- shiftAssignments.push({
- publisherId: publisher.id,
- isConfirmed: true,
- isBySystem: true,
- isWithTransport: isWithTransport
- });
- publishersThisWeek.push(publisher.id);
- updateRegistry(publisher.id, day, weekNr);
- publisher.currentMonthAssignments += 1;
- }
- else {
- console.log(" " + publisher.firstName + " " + publisher.lastName + " skipped (transport already assigned)");
- }
- }
+ // if (!isWithTransport || transportCount < 2) {
+ // shiftAssignments.push({
+ // publisherId: publisher.id,
+ // isConfirmed: true,
+ // isBySystem: true,
+ // isWithTransport: isWithTransport
+ // });
+ // publishersThisWeek.push(publisher.id);
+ // updateRegistry(publisher.id, day, weekNr);
+ // publisher.currentMonthAssignments += 1;
+ // }
+ // else {
+ // console.log(" " + publisher.firstName + " " + publisher.lastName + " skipped (transport already assigned)");
+ // }
+ // }
//---------------------------------------------------
}
@@ -359,7 +404,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
if (event) {
- let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
+ // let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
let shifts = allShifts.filter(s => common.getISODateOnly(s.startTime) === common.getISODateOnly(day));
let publishersToday = await prisma.assignment.findMany({
@@ -395,20 +440,22 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
else if (publishersNeeded > 0) {
console.log("shift " + shift.name + " requires transport (" + transportCapable.length + " transport capable)");
- let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type,familyHeadId', shift.startTime, true, false, false, true, false);
+ const availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type,familyHeadId', shift.startTime, true, false, false, true, false);
+ const availablePubsWithCounts = updatePublishersWithCurrentCounts(availablePubsForTheShift);
- let availablePublishers = availablePubsForTheShift.filter(p => {
+
+ const availablePublishers = availablePubsWithCounts.filter(p => {
const hasTransportInAvailability = shift.transportIn && p.availabilities.some(avail => avail.isWithTransportIn);
const hasTransportOutAvailability = shift.transportOut && p.availabilities.some(avail => avail.isWithTransportOut);
return (hasTransportInAvailability || hasTransportOutAvailability);
});
- availablePublishers = await FilterInappropriatePublishers([...availablePublishers], publishersToday, shift);
+ const appropriatePublishers = await FilterInappropriatePublishers([...availablePublishers], publishersToday, shift, 10);
if (algType == 0) {
- rankedPublishers = await RankPublishersForShiftOld([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
+ rankedPublishers = await RankPublishersForShiftOld([...appropriatePublishers], scheduledPubsCacheStatistics, day);
} else if (algType == 1) {
- rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
+ rankedPublishers = await RankPublishersForShiftWeighted([...appropriatePublishers], scheduledPubsCacheStatistics, day, weekNr);
}
AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
@@ -443,7 +490,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
if (event) {
- let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
+ //let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
let shifts = allShifts.filter(s => common.getISODateOnly(s.startTime) === common.getISODateOnly(day));
let publishersToday = await prisma.assignment.findMany({
where: {
@@ -468,11 +515,11 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
if (publishersNeeded > 0 && shift.assignments.length < goal) {
let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type,familyHeadId', shift.startTime, true, false, false, true, false);
- let availablePublishers = await FilterInappropriatePublishers([...availablePubsForTheShift], publishersToday, shift);
+ let availablePublishers = await FilterInappropriatePublishers([...availablePubsForTheShift], publishersToday, shift, 10);
if (algType == 0) {
- rankedPublishers = await RankPublishersForShiftOld([...availablePublishers], scheduledPubsPerDayAndWeek, day);
+ rankedPublishers = await RankPublishersForShiftOld([...availablePublishers], scheduledPubsCacheStatistics, day);
} else if (algType == 1) {
- rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
+ rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsCacheStatistics, day, weekNr);
}
await AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
@@ -509,10 +556,16 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
} else {
for (let i = 0; i < rankedPublishers.length; i++) {
let mainPublisher = rankedPublishers[i];
- let familyMembers = availablePubsForTheShift.filter(p => (p.id !== mainPublisher.id && (p.id === mainPublisher.familyHeadId) || (p.familyHeadId === mainPublisher.id)));
+ let familyMembers = availablePubsForTheShift.filter(p => {
+ const isNotSelf = p.id !== mainPublisher.id;
+ const isMyFamilyHead = p.id === mainPublisher.familyHeadId;
+ const isMyFamilyMember = p.familyHeadId === mainPublisher.id;
+
+ return isNotSelf && (isMyFamilyHead || isMyFamilyMember);
+ });
if (familyMembers.length > 0 && (shift.assignments.length + familyMembers.length + 1) <= event.numberOfPublishers) {
- console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " and " + familyMembers.length + " available family members to " + new Date(shift.startTime).getDate() + " " + shift.name);
+ console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " and family members: '" + familyMembers.map(fm => `${fm.firstName} ${fm.lastName}`).join(", ") + `' to ${new Date(shift.startTime).getDate()} ${shift.name}`);
const hasTransportInAvailability = shift.transportIn && mainPublisher.availabilities.some(avail => avail.isWithTransportIn);
const hasTransportOutAvailability = shift.transportOut && mainPublisher.availabilities.some(avail => avail.isWithTransportOut);
@@ -537,7 +590,6 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
shift.assignments.push(newAssignment);
publishersToday.push(mainPublisher.id);
updateRegistry(mainPublisher.id, day, weekNr);
- mainPublisher.currentMonthAssignments += 1;
for (const familyMember of familyMembers) {
const newFamilyAssignment = await prisma.assignment.create({
@@ -560,7 +612,6 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
shift.assignments.push(newFamilyAssignment);
publishersToday.push(familyMember.id);
updateRegistry(familyMember.id, day, weekNr);
- familyMember.currentMonthAssignments += 1;
}
break;
@@ -590,7 +641,6 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
shift.assignments.push(newAssignment);
publishersToday.push(mainPublisher.id);
updateRegistry(mainPublisher.id, day, weekNr);
- mainPublisher.currentMonthAssignments += 1;
break;
}
}
@@ -619,7 +669,7 @@ async function FilterInappropriatePublishers(availablePublishers, pubsToExclude,
// 6. Idealy noone should be more than once a week. disqualify publishers already on a shift this week. only assign them if there are no other options and we have less than 3 publishers on a specific shift.
//sort publishers to rank the best option for the current shift assignment
-async function RankPublishersForShiftOld(publishers, scheduledPubsPerDayAndWeek, currentDay: Date) {
+async function RankPublishersForShiftOld(publishers, stats, currentDay: Date) {
publishers.forEach(p => {
p.DesiredMinusCurrent = p.desiredShiftsPerMonth - p.currentMonthAssignments;
});
@@ -672,7 +722,7 @@ async function RankPublishersForShiftOld(publishers, scheduledPubsPerDayAndWeek,
// ToDo: add negative weights for currentweekAssignments, so we avoid assigning the same publishers multiple times in a week. having in mind the days difference between shifts.
-async function RankPublishersForShiftWeighted(publishers, scheduledPubsPerDayAndWeek, currentDay, currentWeekNr) {
+async function RankPublishersForShiftWeighted(publishers, stats, currentDay, currentWeekNr) {
// Define weights for each criterion
const weights = {
gender: 2,
@@ -694,6 +744,9 @@ async function RankPublishersForShiftWeighted(publishers, scheduledPubsPerDayAnd
});
const calculateScoreAndPenalties = (p) => {
+
+ // apply for reaching desired shifts per month
+
let score = (p.isMale ? weights.gender : 0) -
(p.desiredCompletion * weights.desiredCompletion) +
((1 - p.currentMonthAvailabilityHoursCount / 24) * weights.availability) +
diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx
index b0d2df0..70fb116 100644
--- a/pages/cart/calendar/index.tsx
+++ b/pages/cart/calendar/index.tsx
@@ -730,10 +730,12 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
Генерирай смени
-
+ {/* ✧✨ */}
+ {/*
+ Генерирай смени 3 */}
+