parent
000867653b
commit
5cfdf6e87a
@ -1,386 +0,0 @@
|
|||||||
import type { Session } from 'next-auth';
|
|
||||||
import type {
|
|
||||||
City,
|
|
||||||
Company,
|
|
||||||
Country,
|
|
||||||
OffersBackground,
|
|
||||||
OffersCurrency,
|
|
||||||
OffersFullTime,
|
|
||||||
OffersIntern,
|
|
||||||
OffersOffer,
|
|
||||||
OffersProfile,
|
|
||||||
Prisma,
|
|
||||||
PrismaClient,
|
|
||||||
State,
|
|
||||||
} from '@prisma/client';
|
|
||||||
import { TRPCError } from '@trpc/server';
|
|
||||||
|
|
||||||
import { profileAnalysisDtoMapper } from '../../mappers/offers-mappers';
|
|
||||||
|
|
||||||
const searchOfferPercentile = (
|
|
||||||
offer: OffersOffer & {
|
|
||||||
company: Company;
|
|
||||||
offersFullTime:
|
|
||||||
| (OffersFullTime & {
|
|
||||||
baseSalary: OffersCurrency;
|
|
||||||
bonus: OffersCurrency;
|
|
||||||
stocks: OffersCurrency;
|
|
||||||
totalCompensation: OffersCurrency;
|
|
||||||
})
|
|
||||||
| null;
|
|
||||||
offersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
|
|
||||||
profile: OffersProfile & { background: OffersBackground | null };
|
|
||||||
},
|
|
||||||
similarOffers: Array<
|
|
||||||
OffersOffer & {
|
|
||||||
company: Company;
|
|
||||||
offersFullTime:
|
|
||||||
| (OffersFullTime & {
|
|
||||||
totalCompensation: OffersCurrency;
|
|
||||||
})
|
|
||||||
| null;
|
|
||||||
offersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
|
|
||||||
profile: OffersProfile & { background: OffersBackground | null };
|
|
||||||
}
|
|
||||||
>,
|
|
||||||
) => {
|
|
||||||
for (let i = 0; i < similarOffers.length; i++) {
|
|
||||||
if (similarOffers[i].id === offer.id) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const generateAnalysis = async (params: {
|
|
||||||
ctx: {
|
|
||||||
prisma: PrismaClient<
|
|
||||||
Prisma.PrismaClientOptions,
|
|
||||||
never,
|
|
||||||
Prisma.RejectOnNotFound | Prisma.RejectPerOperation | undefined
|
|
||||||
>;
|
|
||||||
session: Session | null;
|
|
||||||
};
|
|
||||||
input: { profileId: string };
|
|
||||||
}) => {
|
|
||||||
const { ctx, input } = params;
|
|
||||||
await ctx.prisma.offersAnalysis.deleteMany({
|
|
||||||
where: {
|
|
||||||
profileId: input.profileId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const offers = await ctx.prisma.offersOffer.findMany({
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
offersFullTime: {
|
|
||||||
include: {
|
|
||||||
baseSalary: true,
|
|
||||||
bonus: true,
|
|
||||||
stocks: true,
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
offersFullTime: {
|
|
||||||
totalCompensation: {
|
|
||||||
baseValue: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offersIntern: {
|
|
||||||
monthlySalary: {
|
|
||||||
baseValue: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
where: {
|
|
||||||
profileId: input.profileId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!offers || offers.length === 0) {
|
|
||||||
throw new TRPCError({
|
|
||||||
code: 'NOT_FOUND',
|
|
||||||
message: 'No offers found on this profile',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const overallHighestOffer = offers[0];
|
|
||||||
|
|
||||||
// TODO: Shift yoe out of background to make it mandatory
|
|
||||||
if (
|
|
||||||
!overallHighestOffer.profile.background ||
|
|
||||||
overallHighestOffer.profile.background.totalYoe == null
|
|
||||||
) {
|
|
||||||
throw new TRPCError({
|
|
||||||
code: 'NOT_FOUND',
|
|
||||||
message: 'YOE not found',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const yoe = overallHighestOffer.profile.background.totalYoe as number;
|
|
||||||
const monthYearReceived = new Date(overallHighestOffer.monthYearReceived);
|
|
||||||
monthYearReceived.setFullYear(monthYearReceived.getFullYear() - 1);
|
|
||||||
|
|
||||||
let similarOffers = await ctx.prisma.offersOffer.findMany({
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
offersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: {
|
|
||||||
include: {
|
|
||||||
experiences: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
offersFullTime: {
|
|
||||||
totalCompensation: {
|
|
||||||
baseValue: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offersIntern: {
|
|
||||||
monthlySalary: {
|
|
||||||
baseValue: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
where: {
|
|
||||||
AND: [
|
|
||||||
{
|
|
||||||
location: overallHighestOffer.location,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
monthYearReceived: {
|
|
||||||
gte: monthYearReceived,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
offersFullTime: {
|
|
||||||
title: overallHighestOffer.offersFullTime?.title,
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
title: overallHighestOffer.offersIntern?.title,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: {
|
|
||||||
background: {
|
|
||||||
AND: [
|
|
||||||
{
|
|
||||||
totalYoe: {
|
|
||||||
gte: Math.max(yoe - 1, 0),
|
|
||||||
lte: yoe + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let similarCompanyOffers = similarOffers.filter(
|
|
||||||
(offer) => offer.companyId === overallHighestOffer.companyId,
|
|
||||||
);
|
|
||||||
|
|
||||||
// CALCULATE PERCENTILES
|
|
||||||
const overallIndex = searchOfferPercentile(
|
|
||||||
overallHighestOffer,
|
|
||||||
similarOffers,
|
|
||||||
);
|
|
||||||
const overallPercentile =
|
|
||||||
similarOffers.length === 0
|
|
||||||
? 100
|
|
||||||
: (100 * overallIndex) / similarOffers.length;
|
|
||||||
|
|
||||||
const companyIndex = searchOfferPercentile(
|
|
||||||
overallHighestOffer,
|
|
||||||
similarCompanyOffers,
|
|
||||||
);
|
|
||||||
const companyPercentile =
|
|
||||||
similarCompanyOffers.length === 0
|
|
||||||
? 100
|
|
||||||
: (100 * companyIndex) / similarCompanyOffers.length;
|
|
||||||
|
|
||||||
// FIND TOP >=90 PERCENTILE OFFERS, DOESN'T GIVE 100th PERCENTILE
|
|
||||||
// e.g. If there only 4 offers, it gives the 2nd and 3rd offer
|
|
||||||
similarOffers = similarOffers.filter(
|
|
||||||
(offer) => offer.id !== overallHighestOffer.id,
|
|
||||||
);
|
|
||||||
similarCompanyOffers = similarCompanyOffers.filter(
|
|
||||||
(offer) => offer.id !== overallHighestOffer.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const noOfSimilarOffers = similarOffers.length;
|
|
||||||
const similarOffers90PercentileIndex = Math.ceil(noOfSimilarOffers * 0.1);
|
|
||||||
const topPercentileOffers =
|
|
||||||
noOfSimilarOffers > 2
|
|
||||||
? similarOffers.slice(
|
|
||||||
similarOffers90PercentileIndex,
|
|
||||||
similarOffers90PercentileIndex + 2,
|
|
||||||
)
|
|
||||||
: similarOffers;
|
|
||||||
|
|
||||||
const noOfSimilarCompanyOffers = similarCompanyOffers.length;
|
|
||||||
const similarCompanyOffers90PercentileIndex = Math.ceil(
|
|
||||||
noOfSimilarCompanyOffers * 0.1,
|
|
||||||
);
|
|
||||||
const topPercentileCompanyOffers =
|
|
||||||
noOfSimilarCompanyOffers > 2
|
|
||||||
? similarCompanyOffers.slice(
|
|
||||||
similarCompanyOffers90PercentileIndex,
|
|
||||||
similarCompanyOffers90PercentileIndex + 2,
|
|
||||||
)
|
|
||||||
: similarCompanyOffers;
|
|
||||||
|
|
||||||
const analysis = await ctx.prisma.offersAnalysis.create({
|
|
||||||
data: {
|
|
||||||
companyPercentile,
|
|
||||||
noOfSimilarCompanyOffers,
|
|
||||||
noOfSimilarOffers,
|
|
||||||
overallHighestOffer: {
|
|
||||||
connect: {
|
|
||||||
id: overallHighestOffer.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
overallPercentile,
|
|
||||||
profile: {
|
|
||||||
connect: {
|
|
||||||
id: input.profileId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
topCompanyOffers: {
|
|
||||||
connect: topPercentileCompanyOffers.map((offer) => {
|
|
||||||
return { id: offer.id };
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
topOverallOffers: {
|
|
||||||
connect: topPercentileOffers.map((offer) => {
|
|
||||||
return { id: offer.id };
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
overallHighestOffer: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
offersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
topCompanyOffers: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
offersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: {
|
|
||||||
include: {
|
|
||||||
experiences: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
topOverallOffers: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
offersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: {
|
|
||||||
include: {
|
|
||||||
experiences: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return profileAnalysisDtoMapper(analysis);
|
|
||||||
};
|
|
Loading…
Reference in new issue