parent
d0af7f87e7
commit
c865897673
@ -1,378 +0,0 @@
|
|||||||
import reader from 'xlsx';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import crypto from 'crypto';
|
|
||||||
import { baseCurrencyString } from '../src/utils/offers/currency';
|
|
||||||
import { convert } from '../src/utils/offers/currency/currencyExchange';
|
|
||||||
import { generateAnalysis } from '../src/utils/offers/analysisGeneration';
|
|
||||||
import {
|
|
||||||
generateRandomName,
|
|
||||||
generateRandomStringForToken,
|
|
||||||
} from '../src/utils/offers/randomGenerator';
|
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
// Reading our test file
|
|
||||||
const file = reader.readFile('prisma/salaries.xlsx');
|
|
||||||
|
|
||||||
let data: Array<ExcelData> = [];
|
|
||||||
|
|
||||||
type ExcelData = {
|
|
||||||
Timestamp: Date;
|
|
||||||
Type: string;
|
|
||||||
Company: string;
|
|
||||||
Role: string;
|
|
||||||
Income?: number | string;
|
|
||||||
Stocks?: number | string;
|
|
||||||
SignOn?: number | string;
|
|
||||||
TC?: number | string;
|
|
||||||
Bonus?: number | string;
|
|
||||||
Comments?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sheets = file.SheetNames;
|
|
||||||
|
|
||||||
for (let i = 0; i < 1; i++) {
|
|
||||||
const temp = reader.utils.sheet_to_json(file.Sheets[file.SheetNames[i]]);
|
|
||||||
temp.forEach((res: ExcelData) => {
|
|
||||||
data.push(res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function xlSerialToJsDate(xlSerial) {
|
|
||||||
return new Date(Date.UTC(0, 0, xlSerial - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
const getJobTitle = (role: string) => {
|
|
||||||
const processedRole = role.toUpperCase().trim();
|
|
||||||
|
|
||||||
if (processedRole.includes('ML ENGINEER')) {
|
|
||||||
return 'ai-ml-engineer';
|
|
||||||
} else if (processedRole.includes('BACKEND')) {
|
|
||||||
return 'back-end-engineer';
|
|
||||||
} else if (processedRole.includes('DATA')) {
|
|
||||||
return 'data-engineer';
|
|
||||||
} else if (processedRole.includes('DEVOPS')) {
|
|
||||||
return 'devops-engineer';
|
|
||||||
} else if (processedRole.includes('ENTERPRISE')) {
|
|
||||||
return 'enterprise-engineer';
|
|
||||||
} else if (processedRole.includes('RESEARCH')) {
|
|
||||||
return 'research-engineer';
|
|
||||||
} else if (
|
|
||||||
processedRole.includes('CYBER') ||
|
|
||||||
processedRole.includes('SECURITY')
|
|
||||||
) {
|
|
||||||
return 'security-engineer';
|
|
||||||
} else if (processedRole.includes('QA')) {
|
|
||||||
return 'test-engineer';
|
|
||||||
} else if (processedRole.includes('SYSTEM')) {
|
|
||||||
return 'systems-engineer';
|
|
||||||
} else {
|
|
||||||
return 'software-engineer'; // Assume default SWE
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getYoe = (type: string) => {
|
|
||||||
const processedType = type.toUpperCase().trim();
|
|
||||||
|
|
||||||
if (
|
|
||||||
processedType.includes('FRESH GRAD') ||
|
|
||||||
processedType.includes('JUNIOR')
|
|
||||||
) {
|
|
||||||
return Math.floor(Math.random() * 3);
|
|
||||||
} else if (processedType.includes('MID')) {
|
|
||||||
return Math.floor(Math.random() * 3) + 3;
|
|
||||||
} else if (processedType.includes('SENIOR')) {
|
|
||||||
return Math.floor(Math.random() * 5) + 6;
|
|
||||||
} else {
|
|
||||||
return 0; // INTERNSHIP OR ERROR -> 0 YOE
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLevel = (type: string) => {
|
|
||||||
const processedType = type.toUpperCase().trim();
|
|
||||||
|
|
||||||
if (
|
|
||||||
processedType.includes('FRESH GRAD') ||
|
|
||||||
processedType.includes('JUNIOR')
|
|
||||||
) {
|
|
||||||
return 'L1';
|
|
||||||
} else if (processedType.includes('MID')) {
|
|
||||||
return 'L2';
|
|
||||||
} else if (processedType.includes('SENIOR')) {
|
|
||||||
return 'L4';
|
|
||||||
} else {
|
|
||||||
return 'L0';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createdProfileIds: Array<string> = [];
|
|
||||||
|
|
||||||
const seedSalaries = async () => {
|
|
||||||
console.log('Seeding from salaries sheet...');
|
|
||||||
|
|
||||||
const companyIdMappings = {};
|
|
||||||
(await prisma.company.findMany()).forEach((company) => {
|
|
||||||
companyIdMappings[company.slug] = company.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
// get countryId of Singapore
|
|
||||||
const singapore = (await prisma.city.findFirst({
|
|
||||||
where: {
|
|
||||||
name: "Singapore"
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
console.log("Singapore ID: " + singapore)
|
|
||||||
// break;
|
|
||||||
// seed here
|
|
||||||
|
|
||||||
if (singapore) {
|
|
||||||
return await Promise.all(
|
|
||||||
data.map(async (data: ExcelData) => {
|
|
||||||
if (data.TC && typeof data.TC === 'number') {
|
|
||||||
// Generate random name until unique
|
|
||||||
let uniqueName: string = await generateRandomName();
|
|
||||||
|
|
||||||
const jobTitle = getJobTitle(data.Role);
|
|
||||||
const yoe = getYoe(data.Type);
|
|
||||||
const level = getLevel(data.Type);
|
|
||||||
|
|
||||||
// check if we have company id
|
|
||||||
if (companyIdMappings[data.Company]) {
|
|
||||||
const token = crypto
|
|
||||||
.createHash('sha256')
|
|
||||||
.update(
|
|
||||||
xlSerialToJsDate(data.Timestamp).toString() +
|
|
||||||
generateRandomStringForToken(),
|
|
||||||
)
|
|
||||||
.digest('hex');
|
|
||||||
|
|
||||||
if (data.Type.toUpperCase() === 'INTERNSHIP') {
|
|
||||||
// create profile
|
|
||||||
const dataAdded = await prisma.offersProfile.create({
|
|
||||||
data: {
|
|
||||||
profileName: uniqueName,
|
|
||||||
createdAt: xlSerialToJsDate(data.Timestamp),
|
|
||||||
editToken: token,
|
|
||||||
background: {
|
|
||||||
create: {
|
|
||||||
totalYoe: yoe,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offers: {
|
|
||||||
create: {
|
|
||||||
comments: data.Comments ?? '',
|
|
||||||
company: {
|
|
||||||
connect: {
|
|
||||||
id: companyIdMappings[data.Company],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
jobType: 'INTERN',
|
|
||||||
location: {
|
|
||||||
connect: {
|
|
||||||
id: singapore.id
|
|
||||||
}
|
|
||||||
}, // TODO: DEFAULT AS SG
|
|
||||||
monthYearReceived: xlSerialToJsDate(data.Timestamp),
|
|
||||||
negotiationStrategy: '',
|
|
||||||
offersIntern: {
|
|
||||||
create: {
|
|
||||||
internshipCycle: 'Summer',
|
|
||||||
monthlySalary: {
|
|
||||||
create: {
|
|
||||||
baseCurrency: baseCurrencyString,
|
|
||||||
baseValue: await convert(
|
|
||||||
data.Income
|
|
||||||
? typeof data.Income === 'number'
|
|
||||||
? data.Income
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
'SGD', // assume sgd
|
|
||||||
baseCurrencyString,
|
|
||||||
),
|
|
||||||
currency: 'SGD', // assume sgd
|
|
||||||
value: data.Income
|
|
||||||
? typeof data.Income === 'number'
|
|
||||||
? data.Income
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
startYear: xlSerialToJsDate(
|
|
||||||
data.Timestamp,
|
|
||||||
).getFullYear(),
|
|
||||||
title: jobTitle,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Profile created:', dataAdded.id);
|
|
||||||
createdProfileIds.push(dataAdded.id);
|
|
||||||
} else {
|
|
||||||
// assume rest full time
|
|
||||||
const dataAdded = await prisma.offersProfile.create({
|
|
||||||
data: {
|
|
||||||
profileName: uniqueName,
|
|
||||||
createdAt: xlSerialToJsDate(data.Timestamp),
|
|
||||||
editToken: token,
|
|
||||||
background: {
|
|
||||||
create: {
|
|
||||||
totalYoe: yoe,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offers: {
|
|
||||||
create: {
|
|
||||||
comments: data.Comments ?? '',
|
|
||||||
company: {
|
|
||||||
connect: {
|
|
||||||
id: companyIdMappings[data.Company],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
jobType: 'FULLTIME',
|
|
||||||
location: {
|
|
||||||
connect: {
|
|
||||||
id: singapore.id
|
|
||||||
}
|
|
||||||
}, // TODO: DEFAULT AS SG
|
|
||||||
monthYearReceived: xlSerialToJsDate(data.Timestamp),
|
|
||||||
negotiationStrategy: '',
|
|
||||||
offersFullTime: {
|
|
||||||
create: {
|
|
||||||
baseSalary: {
|
|
||||||
create: {
|
|
||||||
baseCurrency: baseCurrencyString,
|
|
||||||
baseValue: await convert(
|
|
||||||
data.Income
|
|
||||||
? typeof data.Income === 'number'
|
|
||||||
? data.Income
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
'SGD', // assume sgd
|
|
||||||
baseCurrencyString,
|
|
||||||
),
|
|
||||||
currency: 'SGD', // assume sgd
|
|
||||||
value: data.Income
|
|
||||||
? typeof data.Income === 'number'
|
|
||||||
? data.Income
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
bonus: {
|
|
||||||
create: {
|
|
||||||
baseCurrency: baseCurrencyString,
|
|
||||||
baseValue: await convert(
|
|
||||||
data.Bonus
|
|
||||||
? typeof data.Bonus === 'number'
|
|
||||||
? data.Bonus
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
'SGD',
|
|
||||||
baseCurrencyString,
|
|
||||||
),
|
|
||||||
currency: 'SGD',
|
|
||||||
value: data.Bonus
|
|
||||||
? typeof data.Bonus === 'number'
|
|
||||||
? data.Bonus
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
level: level,
|
|
||||||
stocks: {
|
|
||||||
create: {
|
|
||||||
baseCurrency: baseCurrencyString,
|
|
||||||
baseValue: await convert(
|
|
||||||
data.Stocks
|
|
||||||
? typeof data.Stocks === 'number'
|
|
||||||
? data.Stocks
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
'SGD',
|
|
||||||
baseCurrencyString,
|
|
||||||
),
|
|
||||||
currency: 'SGD',
|
|
||||||
value: data.Stocks
|
|
||||||
? typeof data.Stocks === 'number'
|
|
||||||
? data.Stocks
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
title: jobTitle,
|
|
||||||
totalCompensation: {
|
|
||||||
create: {
|
|
||||||
baseCurrency: baseCurrencyString,
|
|
||||||
baseValue: await convert(
|
|
||||||
data.TC
|
|
||||||
? typeof data.TC === 'number'
|
|
||||||
? data.TC
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
'SGD',
|
|
||||||
baseCurrencyString,
|
|
||||||
),
|
|
||||||
currency: 'SGD',
|
|
||||||
value: data.TC
|
|
||||||
? typeof data.TC === 'number'
|
|
||||||
? data.TC
|
|
||||||
: 0
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log('Profile created:', dataAdded.id);
|
|
||||||
createdProfileIds.push(dataAdded.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('Invalid Company: ' + data.Company);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('Invalid TC not a number: ' + data.TC);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateAllAnalysis = async () => {
|
|
||||||
return await Promise.all(
|
|
||||||
createdProfileIds.map(async (profileId) => {
|
|
||||||
await generateAnalysis({
|
|
||||||
ctx: { prisma, session: null },
|
|
||||||
input: { profileId },
|
|
||||||
});
|
|
||||||
console.log('Analysis generated for profile with id:', profileId);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Promise.all([seedSalaries()])
|
|
||||||
.then(() => {
|
|
||||||
console.log(createdProfileIds.length + " profiles created")
|
|
||||||
console.log("Busy crunching analysis.....")
|
|
||||||
})
|
|
||||||
.then(() => generateAllAnalysis())
|
|
||||||
.then((_data) => {
|
|
||||||
console.log('Seeding from salaries sheet complete');
|
|
||||||
})
|
|
||||||
.then(async () => {
|
|
||||||
await prisma.$disconnect();
|
|
||||||
})
|
|
||||||
.catch(async (e) => {
|
|
||||||
console.error(e);
|
|
||||||
await prisma.$disconnect();
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(xlSerialToJsDate(data[0].Timestamp));
|
|
||||||
|
|
||||||
export {};
|
|
Loading…
Reference in new issue