Files
mwitnessing/pages/api/shiftgenerate.ts
2024-04-02 02:04:45 +03:00

691 lines
32 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//import { getToken } from "next-auth/jwt";
import axiosServer from '../../src/axiosServer';
import { getToken } from "next-auth/jwt";
import type { NextApiRequest, NextApiResponse } from "next";
import { Prisma, PrismaClient, DayOfWeek, Publisher, Shift } from "@prisma/client";
import { levenshteinEditDistance } from "levenshtein-edit-distance";
import { filterPublishers, /* other functions */ } from './index';
import CAL from "../../src/helpers/calendar";
//const common = require("@common");
import common from "../../src/helpers/common";
import { Axios } from 'axios';
export default handler;
async function handler(req: NextApiRequest, res: NextApiResponse) {
console.log(req.url);
console.log(req.query);
const prisma = common.getPrismaClient();
// If you don't have the NEXTAUTH_SECRET environment variable set,
// you will have to pass your secret as `secret` to `getToken`
const axios = await axiosServer({ req: req, res: res });
const token = await getToken({ req: req });
if (!token) {
// If no token or invalid token, return unauthorized status
return res.status(401).json({ message: "Unauthorized" });
}
// const token = req.headers.authorization.split('Bearer ')[1]
// const { user } = await verify(token, process.env.NEXTAUTH_SECRET, {
// maxAge: 30 * 24 * 60 * 60, // 30 days
// })
// if (!user.roles.includes('admin')) {
// res.status(401).json({ message: 'Unauthorized' })
// return
// }
// // if (!user.role == "adminer") {
// if (token?.userRole !== "adminer") {
// res.status(401).json({ message: "Unauthorized" });
// console.log("not authorized");
// return;
// }
// var result = { error: "Not authorized" };
var action = req.query.action;
switch (action) {
case "generate":
var result = await GenerateSchedule(axios,
req.query.date?.toString() || common.getISODateOnly(new Date()),
common.parseBool(req.query.copyFromPreviousMonth),
common.parseBool(req.query.autoFill),
common.parseBool(req.query.forDay));
res.send(JSON.stringify(result.error?.toString()));
break;
case "delete":
result = await DeleteSchedule(axios, req.query.date, common.parseBool(req.query.forDay));
res.send("deleted"); // JSON.stringify(result, null, 2)
break;
case "createcalendarevent":
//CAL.GenerateICS();
result = await CreateCalendarForUser(req.query.id);
res.send(result); // JSON.stringify(result, null, 2)
break;
case "test":
var data = prisma.shift.findMany({
where: {
isActive: true
}
});
res.send({
action: "OK",
shifts: data,
locations: prisma.location.findMany({
take: 10, // Limit the number of records to 10
orderBy: {
name: 'asc' // Replace 'someField' with a field you want to sort by
},
})
});
break;
default:
res.send("Invalid action");
break;
}
}
// handle /api/data/schedule?date=2021-08-01&time=08:00:00&duration=60&service=1&provider=1
//Fix bugs in this code:
async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMonth: boolean = false, autoFill: boolean = false, forDay: Boolean) {
let missingPublishers: any[] = [];
let publishersWithChangedPref: any[] = [];
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));
//delete all shifts for this month
if (forDay) {
// Delete shifts only for the specific day
await DeleteShiftsForDay(monthInfo.date);
} else {
// Delete all shifts for the entire month
await DeleteShiftsForMonth(monthInfo);
}
console.log("finding shifts for previous 3 months for statistics (between " + new Date(monthInfo.date.getFullYear(), monthInfo.date.getMonth() - 3, 1).toISOString() + " and " + monthInfo.firstDay.toISOString() + ")");
const { data: events } = await axios.get(`/api/data/cartevents?where={"isActive":{"$eq":true}}`);
//// let [shiftsLastMonth, publishers] = await getShiftsAndPublishersForPreviousMonths(lastMonthInfo);
//use filterPublishers from /pages/api/data/index.ts to get publishers with stats
let shiftsLastMonth = await getShiftsFromLastMonth(lastMonthInfo);
let publishers = await filterPublishers("id,firstName,lastName", null, lastMonthInfo.firstMonday, true, true, false);
//let publishersWithStatsNew = await filterPublishers("id,firstName,lastName", null, monthInfo.firstMonday, true, true, false);
//foreach day of the month check if there is an event for this day
//if there is an event, then generate shifts for this day based on shiftduration and event start and end time
//####################################################GPT###########################################################
let shiftAssignments = [];
let day = monthInfo.firstMonday; // Start from forDay if provided, otherwise start from first Monday
let endDate = monthInfo.lastSunday; // End at forDay + 1 day if provided, otherwise end at last Sunday
let dayNr = 1; // Start from the day number of forDay, or 1 for the entire month
let weekNr = 1; // Start from the week number of forDay, or 1 for the entire month
if (forDay) {
day = monthInfo.date;
endDate.setDate(monthInfo.date.getDate() + 1);
dayNr = monthInfo.date.getDate();
weekNr = common.getWeekNumber(monthInfo.date);
}
let publishersThisWeek: any[] = [];
console.log("\r\n");
console.log("###############################################");
console.log(" SHIFT GENERATION STARTED for " + common.getISODateOnly(monthInfo.date));
console.log("###############################################");
while (day < endDate) {
const dayOfM = day.getDate();
let dayName = common.DaysOfWeekArray[day.getDayEuropean()];
console.log("[day " + dayNr + "] " + dayName + " " + dayOfM);
//ToDo: rename event to cartEvent
const event = events.find((event: { dayofweek: string }) => {
return event.dayofweek == dayName;
});
if (!event) {
console.log("no event for " + dayName);
day.setDate(day.getDate() + 1);
continue;
}
event.startTime = new Date(event.startTime);
event.endTime = new Date(event.endTime);
var startTime = new Date(day);
startTime.setHours(event.startTime.getHours());
startTime.setMinutes(event.startTime.getMinutes());
var endTime = new Date(day);
endTime.setHours(event.endTime.getHours());
endTime.setMinutes(event.endTime.getMinutes());
var shiftStart = new Date(startTime);
var shiftEnd = new Date(startTime);
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
var shiftNr = 0;
while (shiftEnd <= endTime) {
shiftNr++;
const __shiftName = String(shiftStart.getHours()).padStart(2, "0") + ":" + String(shiftStart.getMinutes()).padStart(2, "0") + " - " + String(shiftEnd.getHours()).padStart(2, "0") + ":" + String(shiftEnd.getMinutes()).padStart(2, "0");
shiftAssignments = [];
let isTransportRequired = shiftNr == 1 || shiftEnd.getTime() == endTime.getTime();
console.log("[shift " + shiftNr + "] " + __shiftName + ", transport: " + (isTransportRequired ? "yes" : "no") + ", " + shiftStart.toLocaleTimeString() + " - " + shiftEnd.toLocaleTimeString() + " (end time: " + endTime.toLocaleTimeString() + ", " + event.shiftDuration + " min)");
if (autoFill || copyFromPreviousMonth) {
// ###########################################
// shift cache !!!
// ###########################################
// get last month attendance for this shift for each week, same day of the week and same shift
const shiftLastMonthSameDay = getShiftFromLastMonth(shiftsLastMonth, day, weekNr, shiftNr);
if (shiftLastMonthSameDay) {
console.log("shiftCache: loaded shifts from '" + shiftLastMonthSameDay.startTime + "' for: " + day);
//log shiftLastMonthSameDay.assignments.publisher names
console.log("last month attendance for shift " + shiftNr + " (" + __shiftName + ") : " + shiftLastMonthSameDay.assignments.map((a: { publisher: { firstName: string; lastName: string; }; }) => a.publisher.firstName + " " + a.publisher.lastName).join(", "));
for (var i = 0; i < shiftLastMonthSameDay.assignments.length; i++) {
let sameP = shiftLastMonthSameDay.assignments[i].publisher;
let name = sameP.firstName + " " + sameP.lastName;
console.log("shiftCache: considerig publisher: " + sameP.firstName + " " + sameP.lastName + ". Checking if he is available for this shift...");
//get availability for the same dayofweek and time (< startTime, > endTime) OR exact date (< startTime, > endTime)
// Query for exact date match
let availability = (await prisma.availability.findMany({
where: {
publisherId: sameP.id,
dayOfMonth: dayOfM,
startTime: {
lte: shiftStart,
},
endTime: {
gte: shiftEnd,
},
},
}))[0] || null;
if (copyFromPreviousMonth) {
//copy from previous month without checking availability
console.log("shiftCache: copy from previous month. Аvailability is " + (availability ? "available" : "not available")
+ ". Adding him to the new scedule as " + (availability ? "confirmed" : "tentative") + ".");
shiftAssignments.push({ publisherId: sameP.id, isConfirmed: availability ? false : true });
} else {
// check if the person filled the form this month
const allAvailabilities = await prisma.availability.findMany({
where: {
publisherId: sameP.id,
isFromPreviousAssignment: false,
},
});
// // ?? get the date on the same weeknr and dayofweek last month, and check if there is an availability for the same day of the week and required time
// if (!availability) {
// // check if there is an availability for the same day of the week and required time
// availability = allAvailabilities.filter((a: { dayofweek: any; startTime: Date; endTime: Date; }) => {
// return a.dayofweek === event.dayofweek && a.startTime <= startTime && a.endTime >= endTime;
// })[0] || null;
// }
// var availability = allAvailabilities.find((a) => {
// return (a.dayofweek === event.dayofweek && a.dayOfMonth == null) || a.dayOfMonth == dayOfM;
// });
//publishers not filled the form will not have an email with @, but rather as 'firstname.lastname'.
//We will add them to the schedule as manual override until they fill the form
//ToDo this logic is not valid in all cases.
if (!availability && sameP.email.includes("@")) {
if (!publishersWithChangedPref.includes(name)) {
//publishersWithChangedPref.push(name);
}
console.log("shiftCache: publisher is not available for this shift. Available days: " + allAvailabilities.filter((a: { dayOfMonth: any; }) => a.dayOfMonth === dayOfM).map((a) => a.dayofweek + " " + a.dayOfMonth).join(", "));
//continue;
}
if (availability) {
console.log("shiftCache: publisher is available for this shift. Available days: " + availability.dayofweek + " " + availability.dayOfMonth + " " + availability.startTime + " - " + availability.endTime);
console.log("shiftCache: publisher is available for this shift OR manual override is set. Adding him to the new scedule.");
shiftAssignments.push({ publisherId: sameP.id });
}
else {
// skip publishers without availability now
// console.warn("NO publisher availability found! for previous assignment for " + name + ". Assuming he does not have changes in his availability. !!! ADD !!! him to the new scedule but mark him as missing.");
// if (!missingPublishers.includes(name)) {
// missingPublishers.push(name);
// }
// try {
// console.log("shiftCache: publisher was last month assigned to this shift but he is not in the system. Adding him to the system with id: " + sameP.id);
// shiftAssignments.push({ publisherId: sameP.id, });
// } catch (e) {
// console.error(`shiftCache: error adding MANUAL publisher to the system(${sameP.email} ${sameP.firstName} ${sameP.lastName}): ` + e);
// }
}
}
}
// ###########################################
// shift CACHE END
// ###########################################
console.log("searching available publisher for " + dayName + " " + __shiftName);
if (!copyFromPreviousMonth) {
/* We chave the following data:
availabilities:(6) [{…}, {…}, {…}, {…}, {…}, {…}]
currentDayAssignments:0
currentMonthAssignments:2
currentMonthAvailability:(2) [{…}, {…}]
currentMonthAvailabilityDaysCount:2
currentMonthAvailabilityHoursCount:3
currentWeekAssignments:0
firstName:'Алесия'
id:'clqjtcrqj0008oio8kan5lkjn'
lastName:'Сейз'
previousMonthAssignments:2
*/
// until we reach event.numberOfPublishers, we will try to fill the shift with publishers from allAvailablePublishers with the following priority:
// do multiple passes, reecalculating availabilityIndex for each publisher after each pass.
// !!! Never assign the same publisher twice to the same day! (currentDayAssignments > 0)
// PASS 1: Prioritize publishers with little currentMonthAvailabilityHoursCount ( < 5 ), as they may not have another opportunity to serve this month
// PASS 2: try to fill normally based on availabilityIndex, excluding those who were assigned this week
// PASS 3: try to fill normally based on availabilityIndex, including those who were assigned this week and weighting the desiredShiftsPerMonth
// PASS 4: include those without availability this month - based on old availabilities and assignments for this day of the week.
// push found publisers to shiftAssignments with: .push({ publisherId: publisher.id }); and update publisher stats in new function: addAssignmentToPublisher(shiftAssignments, publisher)
// ---------------------------------- new code ---------------------------------- //
// get all publishers who are available for this SPECIFIC day and WEEKDAY
const queryParams = new URLSearchParams({
action: 'filterPublishers',
assignments: 'true',
availabilities: 'true',
date: common.getISODateOnly(shiftStart),
select: 'id,firstName,lastName,isActive,desiredShiftsPerMonth'
});
let allAvailablePublishers = (await axios.get(`/api/?${queryParams.toString()}`)).data;
let availablePublishers = allAvailablePublishers;
let publishersNeeded = Math.max(0, event.numberOfPublishers - shiftAssignments.length);
// LEVEL 1: Prioritize publishers with little currentMonthAvailabilityHoursCount ( < 5 ), as they may not have another opportunity to serve this month
// get publishers with little currentMonthAvailabilityHoursCount ( < 5 )
// let availablePublishers = allAvailablePublishers.filter((p: { currentMonthAvailabilityHoursCount: number; }) => p.currentMonthAvailabilityHoursCount < 5);
// // log all available publishers with their currentMonthAvailabilityHoursCount
// console.info("PASS 1: availablePublishers for this shift with currentMonthAvailabilityHoursCount < 5: " + availablePublishers.length + " (" + publishersNeeded + " needed)");
// availablePublishers.slice(0, publishersNeeded).forEach((p: { id: any; }) => { addAssignmentToPublisher(shiftAssignments, p); });
// publishersNeeded = Math.max(0, event.numberOfPublishers - shiftAssignments.length);
// LEVEL 2+3: try to fill normally based on availabilityIndex, excluding those who were assigned this week
// get candidates that are not assigned this week, and which have not been assigned this month as mutch as the last month.
// calculate availabilityIndex for each publisher based on various factors:
// 1. currentMonthAssignments - lastMonth (weight 50%)
// 2. desiredShiftsPerMonth (weight 30%)
// 3. publisher type (weight 20%) - regular, auxiliary, pioneer, special, bethel, etc.. (see publisherType in publisher model). exclude betelites who were assigned this month. (index =)
//calculate availabilityIndex:
allAvailablePublishers.forEach((p: { currentMonthAssignments: number; desiredShiftsPerMonth: number; publisherType: string; }) => {
// 1. currentMonthAssignments - lastMonth (weight 50%)
// 2. desiredShiftsPerMonth (weight 30%)
// 3. publisher type (weight 20%) - regular, auxiliary, pioneer, special, bethel, etc.. (see publisherType in publisher model). exclude betelites who were assigned this month. (index =)
p.availabilityIndex = Math.round(((p.currentMonthAssignments - p.previousMonthAssignments) * 0.5 + p.desiredShiftsPerMonth * 0.3 + (p.publisherType === "bethelite" ? 0 : 1) * 0.2) * 100) / 100;
});
// use the availabilityIndex to sort the publishers
// LEVEL 2: remove those who are already assigned this week (currentWeekAssignments > 0), order by !availabilityIndex
availablePublishers = allAvailablePublishers.filter((p: { currentWeekAssignments: number; }) => p.currentWeekAssignments === 0)
.sort((a: { availabilityIndex: number; }, b: { availabilityIndex: number; }) => a.availabilityIndex - b.availabilityIndex);
console.warn("PASS 2: availablePublishers for this shift after removing already assigned this week: " + availablePublishers.length + " (" + publishersNeeded + " needed)");
availablePublishers.slice(0, publishersNeeded).forEach((p: { id: any; }) => { addAssignmentToPublisher(shiftAssignments, p); });
publishersNeeded = Math.max(0, event.numberOfPublishers - shiftAssignments.length);
// LEVEL 3: order by !availabilityIndex
availablePublishers = allAvailablePublishers.sort((a: { availabilityIndex: number; }, b: { availabilityIndex: number; }) => a.availabilityIndex - b.availabilityIndex);
console.warn("PASS 3: availablePublishers for this shift including already assigned this week: " + availablePublishers.length + " (" + publishersNeeded + " needed)");
availablePublishers.slice(0, publishersNeeded).forEach((p: { id: any; }) => { addAssignmentToPublisher(shiftAssignments, p); });
publishersNeeded = Math.max(0, event.numberOfPublishers - shiftAssignments.length);
// LEVEL 4: include those without availability this month - based on old availabilities and assignments for this day of the week.
// get candidates that are not assigned this week, and which have not been assigned this month as mutch as the last month.
//query the api again for all publishers with assignments and availabilities for this day of the week including from old assignments (set filterPublishers to false)
availablePublishers = await filterPublishers("id,firstName,lastName", null, shiftStart, false, true, true);
console.warn("PASS 4: availablePublishers for this shift including weekly and old assignments: " + availablePublishers.length + " (" + publishersNeeded + " needed)");
function oldCode() {
// ---------------------------------- old code ---------------------------------- //
// console.warn("allAvailablePublishers: " + allAvailablePublishers.length);
// // remove those who are already assigned this week (currentWeekAssignments > 0)//, # OLD: order by !availabilityIndex
// let availablePublishers = allAvailablePublishers.filter((p: { currentWeekAssignments: number; }) => p.currentWeekAssignments === 0);
// console.warn("availablePublishers for this shift after removing already assigned this week: " + availablePublishers.length + " (" + (event.numberOfPublishers - shiftAssignments.length) + " needed)");
// if (availablePublishers.length === 0) {
// console.error(`------------------- no available publishers for ${dayName} ${dayOfM}!!! -------------------`);
// // Skipping the rest of the code execution
// //return;
// }
// let msg = `FOUND ${availablePublishers.length} publishers for ${dayName} ${dayOfM}, ${__shiftName} . ${event.numberOfPublishers - shiftAssignments.length} needed\r\n: `;
// msg += availablePublishers.map((p: { firstName: any; lastName: any; asignmentsThisMonth: any; availabilityIndex: any; }) => `${p.firstName} ${p.lastName} (${p.asignmentsThisMonth}:${p.availabilityIndex})`).join(", ");
// console.log(msg);
// // ---------------------------------- old code ---------------------------------- //
} // end of old code
}
}
}
//###############################################################################################################
// create shift assignmens
//###############################################################################################################
// using prisma client:
// https://stackoverflow.com/questions/65950407/prisma-many-to-many-relations-create-and-connect
// connect publishers to shift
const createdShift = await prisma.shift.create({
data: {
startTime: shiftStart,
endTime: shiftEnd,
name: event.dayofweek + " " + shiftStart.toLocaleTimeString() + " - " + shiftEnd.toLocaleTimeString(),
requiresTransport: isTransportRequired,
cartEvent: {
connect: {
id: event.id,
},
},
assignments: {
create: shiftAssignments.map((a) => {
return { publisher: { connect: { id: a.publisherId } }, isConfirmed: a.isConfirmed };
}),
},
},
});
shiftStart = new Date(shiftEnd);
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
}
day.setDate(day.getDate() + 1);
dayNr++;
let weekDay = common.DaysOfWeekArray[day.getDayEuropean()]
if (weekDay == DayOfWeek.Sunday) {
weekNr++;
publishersThisWeek = [];
publishers.forEach((p: { currentWeekAssignments: number; }) => {
p.currentWeekAssignments = 0;
});
}
//the whole day is done, go to next day. break if we are generating for a specific day
if (forDay) {
break;
}
}
//###################################################GPT############################################################
if (!forDay) {
const fs = require("fs");
//fs.writeFileSync("./content/publisherShiftStats.json", JSON.stringify(publishers, null, 2));
//fs.writeFileSync("./content/publishersWithChangedPref.json", JSON.stringify(publishersWithChangedPref, null, 2));
//fs.writeFileSync("./content/missingPublishers.json", JSON.stringify(missingPublishers, null, 2));
console.log("###############################################");
console.log(" DONE CREATING SCHEDULE FOR " + monthInfo.monthName + " " + monthInfo.year);
console.log("###############################################");
}
//create shifts using API
// const { data: createdShifts } = await axios.post(`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/shifts`, shiftsToCreate);
//const { data: allshifts } = await axios.get(`/api/data/shifts`);
return {}; //allshifts;
}
catch (error) {
console.log(error);
return { error: error };
}
}
function addAssignmentToPublisher(shiftAssignments: any[], publisher: Publisher) {
shiftAssignments.push({ publisherId: publisher.id });
publisher.currentWeekAssignments++ || 1;
publisher.currentDayAssignments++ || 1;
publisher.currentMonthAssignments++ || 1;
//console.log(`manual assignment: ${dayName} ${dayOfM} ${shiftStart}:${shiftEnd} ${p.firstName} ${p.lastName} ${p.availabilityIndex} ${p.currentMonthAssignments}`);
console.log(`manual assignment: ${publisher.firstName} ${publisher.lastName} ${publisher.currentMonthAssignments}`);
return publisher;
}
async function DeleteShiftsForMonth(monthInfo: any) {
try {
const prisma = common.getPrismaClient();
await prisma.shift.deleteMany({
where: {
startTime: {
gte: monthInfo.firstMonday,
lt: monthInfo.lastSunday,
},
},
});
} catch (e) {
console.log(e);
}
}
async function DeleteShiftsForDay(date: Date) {
const prisma = common.getPrismaClient();
try {
// Assuming shifts do not span multiple days, so equality comparison is used
await prisma.shift.deleteMany({
where: {
startTime: {
gte: date,
lt: new Date(date.getTime() + 86400000), // +1 day in milliseconds
},
},
});
} catch (e) {
console.log(e);
}
}
async function getShiftsFromLastMonth(monthInfo) {
const prisma = common.getPrismaClient();
// Fetch shifts for the month
const rawShifts = await prisma.shift.findMany({
where: {
startTime: {
gte: monthInfo.firstMonday,
lte: monthInfo.lastSunday,
},
},
include: {
assignments: {
include: {
publisher: true,
},
},
},
});
// Process shifts to add weekNr and shiftNr
return rawShifts.map(shift => ({
...shift,
weekNr: common.getWeekNumber(new Date(shift.startTime)),
shiftNr: rawShifts.filter(s => common.getISODateOnly(s.startTime) === common.getISODateOnly(shift.startTime)).indexOf(shift) + 1,
weekDay: common.DaysOfWeekArray[new Date(shift.startTime).getDayEuropean()],
}));
}
function getShiftFromLastMonth(shiftsLastMonth, day, weekNr, shiftNr) {
let weekDay = common.DaysOfWeekArray[day.getDayEuropean()];
return shiftsLastMonth.find(s => {
return s.weekNr === weekNr &&
s.shiftNr === shiftNr &&
s.weekDay === weekDay;
});
}
/**
* Dangerous function that deletes all shifts and publishers.
* @param date
* @returns
*/
async function DeleteSchedule(axios: Axios, date: Date, forDay: Boolean | undefined) {
try {
let monthInfo = common.getMonthDatesInfo(new Date(date));
if (forDay) {
// Delete shifts only for the specific day
await DeleteShiftsForDay(monthInfo.date);
} else {
// Delete all shifts for the entire month
await DeleteShiftsForMonth(monthInfo);
}
} catch (error) {
console.log(error);
return { error: error };
}
}
async function CreateCalendarForUser(eventId: string | string[] | undefined) {
try {
//CAL.authorizeNew();
CAL.createEvent(eventId);
} catch (error) {
console.log(error);
return { error: error };
}
}
/*
obsolete?
*/
async function ImportShiftsFromDocx(axios: Axios) {
try {
const { data: shifts } = await axios.get(`/api/data/shifts`);
shifts.forEach(async (shift: { id: any; }) => {
await axios.delete(`/api/data/shifts/${shift.id}`);
});
const { data: shiftsToCreate } = await axios.get(`/api/data/shiftsToCreate`);
shiftsToCreate.forEach(async (shift: any) => {
await axios.post(`/api/data/shifts`, shift);
});
} catch (error) {
console.log(error);
return { error: error };
}
}
/**
* Retrieves shifts and publishers for the previous months based on the given month information.
* @deprecated This function is deprecated and will be removed in future versions. Use `filterPublishers` from `/pages/api/data/index.ts` instead.
* @param monthInfo - An object containing information about the last month, including its first day and last Sunday.
* @returns A Promise that resolves to an array containing the publishers for the previous months.
*/
// async function getShiftsAndPublishersForPreviousMonths(monthInfo: { firstDay: any; lastSunday: any; firstMonday: any; nrOfWeeks: number; }) {
// const prisma = common.getPrismaClient(); //old: (global as any).prisma;
// const [shiftsLastMonth, initialPublishers] = await Promise.all([
// prisma.shift.findMany({
// where: {
// startTime: {
// gte: monthInfo.firstDay,
// lte: monthInfo.lastSunday,
// },
// },
// include: {
// assignments: {
// include: {
// publisher: true,
// },
// },
// },
// }),
// prisma.publisher.findMany({
// where: {
// isActive: true,
// },
// include: {
// availabilities: {
// where: {
// isActive: true,
// },
// },
// assignments: {
// include: {
// shift: true,
// },
// },
// },
// }),
// ]);
// // Group shifts by day
// function getDayFromDate(date: Date) {
// return date.toISO String().split('T')[0];
// }
// const groupedShifts = shiftsLastMonth.reduce((acc: { [x: string]: any[]; }, shift: { startTime: string | number | Date; }) => {
// const day = getDayFromDate(new Date(shift.startTime));
// if (!acc[day]) {
// acc[day] = [];
// }
// acc[day].push(shift);
// return acc;
// }, {});
// //temp fix - calculate shift.weekNr
// const updatedShiftsLastMonth = [];
// for (const day in groupedShifts) {
// const shifts = groupedShifts[day];
// for (let i = 0; i < shifts.length; i++) {
// const shift = shifts[i];
// updatedShiftsLastMonth.push({
// ...shift,
// weekNr: common.getWeekNumber(shift.startTime) + 1,
// shiftNr: i + 1 // The shift number for the day starts from 1
// });
// }
// }
// const publishers = initialPublishers.map((publisher: { assignments: any[]; desiredShiftsPerMonth: number; }) => {
// // const lastMonthStartDate = new Date(date.getFullYear(), date.getMonth() - 1, 1);
// // const last2MonthsStartDate = new Date(date.getFullYear(), date.getMonth() - 2, 1);
// const filterAssignmentsByDate = (startDate: any, endDate: any) =>
// publisher.assignments.filter((assignment: { shift: { startTime: string | number | Date; }; }) => isDateBetween(new Date(assignment.shift.startTime), startDate, endDate));
// const lastMonthAssignments = filterAssignmentsByDate(monthInfo.firstMonday, monthInfo.lastSunday);
// //const last2MonthsAssignments = filterAssignmentsByDate(last2MonthsStartDate, monthInfo.firstMonday);
// const desiredShifts = publisher.desiredShiftsPerMonth * (monthInfo.nrOfWeeks / 4);
// const availabilityIndex = Math.round((lastMonthAssignments.length / desiredShifts) * 100) / 100;
// return {
// ...publisher,
// availabilityIndex,
// currentWeekAssignments: 0,
// currentMonthAssignments: 0,
// assignmentsLastMonth: lastMonthAssignments.length,
// //assignmentsLast2Months: last2MonthsAssignments.length,
// };
// });
// return [updatedShiftsLastMonth, publishers];
// }
// *********************************************************************************************************************
//region helpers
// *********************************************************************************************************************