Files

152 lines
5.4 KiB
TypeScript
Raw Permalink 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.
/**
* seed-vacations.ts
* Populates 15 vacation days per resource per year (2025, 2026, 2027-partial).
* Spread across 3 blocks:
* Spring/Easter (5 days, fixed)
* Summer (5 days, staggered by resource index so teams don't all leave at once)
* Christmas/NYE (5 days, fixed)
*/
import { PrismaClient } from "@prisma/client";
import { loadWorkspaceEnv } from "./load-workspace-env.js";
import { assertSafeSeedTarget } from "./safe-destructive-env.js";
loadWorkspaceEnv();
const prisma = new PrismaClient();
// ─── Helpers ──────────────────────────────────────────────────────────────────
/** ISO date string → Date at midnight UTC */
function d(iso: string): Date {
return new Date(iso + "T00:00:00.000Z");
}
/** Add calendar days to a Date */
function addDays(date: Date, n: number): Date {
const r = new Date(date);
r.setUTCDate(r.getUTCDate() + n);
return r;
}
// ─── Vacation blocks per year ─────────────────────────────────────────────────
// Each block is { start, end } of a MonFri week (5 working days).
// Summer has multiple offsets so resources are staggered (offset chosen by index % 4).
const BLOCKS: Record<
number,
{
spring: { start: string; end: string };
summer: { start: string; end: string }[];
christmas: { start: string; end: string };
}
> = {
2025: {
spring: { start: "2025-04-14", end: "2025-04-18" }, // MonFri Easter week
summer: [
{ start: "2025-07-07", end: "2025-07-11" },
{ start: "2025-07-21", end: "2025-07-25" },
{ start: "2025-08-04", end: "2025-08-08" },
{ start: "2025-08-18", end: "2025-08-22" },
],
christmas: { start: "2025-12-22", end: "2025-12-26" }, // MonFri
},
2026: {
spring: { start: "2026-03-30", end: "2026-04-03" }, // MonFri Easter week
summer: [
{ start: "2026-07-06", end: "2026-07-10" },
{ start: "2026-07-20", end: "2026-07-24" },
{ start: "2026-08-03", end: "2026-08-07" },
{ start: "2026-08-17", end: "2026-08-21" },
],
christmas: { start: "2026-12-21", end: "2026-12-25" }, // MonFri
},
2027: {
// Partial year — spring only (for future view context)
spring: { start: "2027-03-29", end: "2027-04-02" },
summer: [
{ start: "2027-07-05", end: "2027-07-09" },
{ start: "2027-07-19", end: "2027-07-23" },
{ start: "2027-08-02", end: "2027-08-06" },
{ start: "2027-08-16", end: "2027-08-20" },
],
christmas: { start: "2027-12-20", end: "2027-12-24" },
},
};
const YEARS = [2025, 2026, 2027];
// ─── Main ─────────────────────────────────────────────────────────────────────
async function main() {
assertSafeSeedTarget("db:seed:vacations");
// Get admin user to act as approver (fall back to manager, then any user)
const admin =
(await prisma.user.findFirst({ where: { systemRole: "ADMIN" }, select: { id: true } })) ??
(await prisma.user.findFirst({ where: { systemRole: "MANAGER" }, select: { id: true } })) ??
(await prisma.user.findFirst({ select: { id: true } }));
if (!admin) {
throw new Error("No users found — run the main seed first.");
}
// Get all resources ordered by eid for stable staggering
const resources = await prisma.resource.findMany({
where: { isActive: true },
select: { id: true, eid: true },
orderBy: { eid: "asc" },
});
console.log(`Found ${resources.length} active resources. Admin id: ${admin.id}`);
// Delete existing vacations to allow re-running
const deleted = await prisma.vacation.deleteMany({});
console.log(`Deleted ${deleted.count} existing vacation records.`);
let created = 0;
for (let i = 0; i < resources.length; i++) {
const resource = resources[i]!;
const summerOffset = i % 4; // 0-3 → pick one of the 4 staggered summer weeks
for (const year of YEARS) {
const blocks = BLOCKS[year]!;
const summerBlock = blocks.summer[summerOffset]!;
const vacationBlocks = [
{ type: "ANNUAL" as const, ...blocks.spring },
{ type: "ANNUAL" as const, ...summerBlock },
{ type: "ANNUAL" as const, ...blocks.christmas },
];
for (const block of vacationBlocks) {
await prisma.vacation.create({
data: {
resourceId: resource.id,
type: block.type,
status: "APPROVED",
startDate: d(block.start),
endDate: d(block.end),
requestedById: admin.id,
approvedById: admin.id,
approvedAt: new Date(),
note: `${year} annual leave`,
},
});
created++;
}
}
console.log(`${resource.eid}${YEARS.length * 3} vacation blocks`);
}
console.log(`\nDone! Created ${created} vacation records.`);
console.log(` ${resources.length} resources × ${YEARS.length} years × 3 blocks = ${resources.length * YEARS.length * 3} expected`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(() => void prisma.$disconnect());