Skip to content

Commit 70ff0ee

Browse files
committed
fix workday to use soap api
1 parent 734f4ee commit 70ff0ee

File tree

26 files changed

+1135
-494
lines changed

26 files changed

+1135
-494
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { createLogger } from '@sim/logger'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { z } from 'zod'
4+
import { checkInternalAuth } from '@/lib/auth/hybrid'
5+
import { generateRequestId } from '@/lib/core/utils/request'
6+
import { createWorkdaySoapClient, extractRefId, wdRef } from '@/tools/workday/soap'
7+
8+
export const dynamic = 'force-dynamic'
9+
10+
const logger = createLogger('WorkdayAssignOnboardingAPI')
11+
12+
const RequestSchema = z.object({
13+
tenantUrl: z.string().min(1),
14+
tenant: z.string().min(1),
15+
username: z.string().min(1),
16+
password: z.string().min(1),
17+
workerId: z.string().min(1),
18+
onboardingPlanId: z.string().min(1),
19+
actionEventId: z.string().min(1),
20+
stages: z.string().optional(),
21+
})
22+
23+
export async function POST(request: NextRequest) {
24+
const requestId = generateRequestId()
25+
26+
try {
27+
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
28+
if (!authResult.success) {
29+
return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
30+
}
31+
32+
const body = await request.json()
33+
const data = RequestSchema.parse(body)
34+
35+
const client = await createWorkdaySoapClient(
36+
data.tenantUrl,
37+
data.tenant,
38+
'humanResources',
39+
data.username,
40+
data.password
41+
)
42+
43+
const [result] = await client.Put_Onboarding_Plan_AssignmentAsync({
44+
Onboarding_Plan_Assignment_Data: {
45+
Onboarding_Plan_Reference: wdRef('Onboarding_Plan_ID', data.onboardingPlanId),
46+
Person_Reference: wdRef('Employee_ID', data.workerId),
47+
Action_Event_Reference: wdRef('Background_Check_ID', data.actionEventId),
48+
Assignment_Effective_Moment: new Date().toISOString(),
49+
Active: true,
50+
},
51+
})
52+
53+
return NextResponse.json({
54+
success: true,
55+
output: {
56+
assignmentId: extractRefId(result?.Onboarding_Plan_Assignment_Reference),
57+
workerId: data.workerId,
58+
planId: data.onboardingPlanId,
59+
},
60+
})
61+
} catch (error) {
62+
logger.error(`[${requestId}] Workday assign onboarding failed`, { error })
63+
return NextResponse.json(
64+
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
65+
{ status: 500 }
66+
)
67+
}
68+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { createLogger } from '@sim/logger'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { z } from 'zod'
4+
import { checkInternalAuth } from '@/lib/auth/hybrid'
5+
import { generateRequestId } from '@/lib/core/utils/request'
6+
import { createWorkdaySoapClient, extractRefId, wdRef } from '@/tools/workday/soap'
7+
8+
export const dynamic = 'force-dynamic'
9+
10+
const logger = createLogger('WorkdayChangeJobAPI')
11+
12+
const RequestSchema = z.object({
13+
tenantUrl: z.string().min(1),
14+
tenant: z.string().min(1),
15+
username: z.string().min(1),
16+
password: z.string().min(1),
17+
workerId: z.string().min(1),
18+
effectiveDate: z.string().min(1),
19+
newPositionId: z.string().optional(),
20+
newJobProfileId: z.string().optional(),
21+
newLocationId: z.string().optional(),
22+
newManagerId: z.string().optional(),
23+
reason: z.string().min(1, 'Reason is required for job changes'),
24+
})
25+
26+
export async function POST(request: NextRequest) {
27+
const requestId = generateRequestId()
28+
29+
try {
30+
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
31+
if (!authResult.success) {
32+
return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
33+
}
34+
35+
const body = await request.json()
36+
const data = RequestSchema.parse(body)
37+
38+
const changeJobDetailData: Record<string, unknown> = {
39+
Reason_Reference: wdRef('Change_Job_Subcategory_ID', data.reason),
40+
}
41+
if (data.newPositionId) {
42+
changeJobDetailData.Position_Reference = wdRef('Position_ID', data.newPositionId)
43+
}
44+
if (data.newJobProfileId) {
45+
changeJobDetailData.Job_Profile_Reference = wdRef('Job_Profile_ID', data.newJobProfileId)
46+
}
47+
if (data.newLocationId) {
48+
changeJobDetailData.Location_Reference = wdRef('Location_ID', data.newLocationId)
49+
}
50+
if (data.newManagerId) {
51+
changeJobDetailData.Supervisory_Organization_Reference = wdRef(
52+
'Supervisory_Organization_ID',
53+
data.newManagerId
54+
)
55+
}
56+
57+
const client = await createWorkdaySoapClient(
58+
data.tenantUrl,
59+
data.tenant,
60+
'staffing',
61+
data.username,
62+
data.password
63+
)
64+
65+
const [result] = await client.Change_JobAsync({
66+
Business_Process_Parameters: {
67+
Auto_Complete: true,
68+
Run_Now: true,
69+
},
70+
Change_Job_Data: {
71+
Worker_Reference: wdRef('Employee_ID', data.workerId),
72+
Effective_Date: data.effectiveDate,
73+
Change_Job_Detail_Data: changeJobDetailData,
74+
},
75+
})
76+
77+
const eventRef = result?.Event_Reference
78+
79+
return NextResponse.json({
80+
success: true,
81+
output: {
82+
eventId: extractRefId(eventRef),
83+
workerId: data.workerId,
84+
effectiveDate: data.effectiveDate,
85+
},
86+
})
87+
} catch (error) {
88+
logger.error(`[${requestId}] Workday change job failed`, { error })
89+
return NextResponse.json(
90+
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
91+
{ status: 500 }
92+
)
93+
}
94+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { createLogger } from '@sim/logger'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { z } from 'zod'
4+
import { checkInternalAuth } from '@/lib/auth/hybrid'
5+
import { generateRequestId } from '@/lib/core/utils/request'
6+
import { createWorkdaySoapClient, extractRefId, wdRef } from '@/tools/workday/soap'
7+
8+
export const dynamic = 'force-dynamic'
9+
10+
const logger = createLogger('WorkdayCreatePrehireAPI')
11+
12+
const RequestSchema = z.object({
13+
tenantUrl: z.string().min(1),
14+
tenant: z.string().min(1),
15+
username: z.string().min(1),
16+
password: z.string().min(1),
17+
legalName: z.string().min(1),
18+
email: z.string().optional(),
19+
phoneNumber: z.string().optional(),
20+
address: z.string().optional(),
21+
sourceId: z.string().optional(),
22+
})
23+
24+
export async function POST(request: NextRequest) {
25+
const requestId = generateRequestId()
26+
27+
try {
28+
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
29+
if (!authResult.success) {
30+
return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
31+
}
32+
33+
const body = await request.json()
34+
const data = RequestSchema.parse(body)
35+
36+
const parts = data.legalName.trim().split(/\s+/)
37+
const firstName = parts[0] ?? ''
38+
const lastName = parts.length > 1 ? parts.slice(1).join(' ') : (parts[0] ?? '')
39+
40+
const client = await createWorkdaySoapClient(
41+
data.tenantUrl,
42+
data.tenant,
43+
'staffing',
44+
data.username,
45+
data.password
46+
)
47+
48+
if (!data.email && !data.phoneNumber && !data.address) {
49+
return NextResponse.json(
50+
{
51+
success: false,
52+
error: 'At least one contact method (email, phone, or address) is required',
53+
},
54+
{ status: 400 }
55+
)
56+
}
57+
58+
const contactData: Record<string, unknown> = {}
59+
if (data.email) {
60+
contactData.Email_Address_Data = [
61+
{
62+
Email_Address: data.email,
63+
Usage_Data: {
64+
Type_Data: { Type_Reference: wdRef('Communication_Usage_Type_ID', 'WORK') },
65+
Public: true,
66+
},
67+
},
68+
]
69+
}
70+
if (data.phoneNumber) {
71+
contactData.Phone_Data = [
72+
{
73+
Phone_Number: data.phoneNumber,
74+
Phone_Device_Type_Reference: wdRef('Phone_Device_Type_ID', 'Landline'),
75+
Usage_Data: {
76+
Type_Data: { Type_Reference: wdRef('Communication_Usage_Type_ID', 'WORK') },
77+
Public: true,
78+
},
79+
},
80+
]
81+
}
82+
if (data.address) {
83+
contactData.Address_Data = [
84+
{
85+
Formatted_Address: data.address,
86+
Usage_Data: {
87+
Type_Data: { Type_Reference: wdRef('Communication_Usage_Type_ID', 'WORK') },
88+
Public: true,
89+
},
90+
},
91+
]
92+
}
93+
94+
const [result] = await client.Put_ApplicantAsync({
95+
Applicant_Data: {
96+
Personal_Data: {
97+
Name_Data: {
98+
Legal_Name_Data: {
99+
Name_Detail_Data: {
100+
Country_Reference: wdRef('ISO_3166-1_Alpha-2_Code', 'US'),
101+
First_Name: firstName,
102+
Last_Name: lastName,
103+
},
104+
},
105+
},
106+
Contact_Information_Data: contactData,
107+
},
108+
},
109+
})
110+
111+
const applicantRef = result?.Applicant_Reference
112+
113+
return NextResponse.json({
114+
success: true,
115+
output: {
116+
preHireId: extractRefId(applicantRef),
117+
descriptor: applicantRef?.attributes?.Descriptor ?? null,
118+
},
119+
})
120+
} catch (error) {
121+
logger.error(`[${requestId}] Workday create prehire failed`, { error })
122+
return NextResponse.json(
123+
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
124+
{ status: 500 }
125+
)
126+
}
127+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { createLogger } from '@sim/logger'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { z } from 'zod'
4+
import { checkInternalAuth } from '@/lib/auth/hybrid'
5+
import { generateRequestId } from '@/lib/core/utils/request'
6+
import { createWorkdaySoapClient } from '@/tools/workday/soap'
7+
8+
export const dynamic = 'force-dynamic'
9+
10+
const logger = createLogger('WorkdayGetCompensationAPI')
11+
12+
const RequestSchema = z.object({
13+
tenantUrl: z.string().min(1),
14+
tenant: z.string().min(1),
15+
username: z.string().min(1),
16+
password: z.string().min(1),
17+
workerId: z.string().min(1),
18+
})
19+
20+
export async function POST(request: NextRequest) {
21+
const requestId = generateRequestId()
22+
23+
try {
24+
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
25+
if (!authResult.success) {
26+
return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
27+
}
28+
29+
const body = await request.json()
30+
const data = RequestSchema.parse(body)
31+
32+
const client = await createWorkdaySoapClient(
33+
data.tenantUrl,
34+
data.tenant,
35+
'humanResources',
36+
data.username,
37+
data.password
38+
)
39+
40+
const [result] = await client.Get_WorkersAsync({
41+
Request_References: {
42+
Worker_Reference: {
43+
ID: { attributes: { 'wd:type': 'Employee_ID' }, $value: data.workerId },
44+
},
45+
},
46+
Response_Group: {
47+
Include_Reference: true,
48+
Include_Compensation: true,
49+
},
50+
})
51+
52+
const rawWorker = result?.Response_Data?.Worker
53+
const workerData = (Array.isArray(rawWorker) ? rawWorker[0] : (rawWorker ?? null)) as Record<
54+
string,
55+
unknown
56+
> | null
57+
const workerInner = workerData?.Worker_Data as Record<string, unknown> | undefined
58+
const compensationData = workerInner?.Compensation_Data as Record<string, unknown> | undefined
59+
60+
const rawPlans = compensationData?.Compensation_Plan_Assignment
61+
const plansArray = (Array.isArray(rawPlans) ? rawPlans : rawPlans ? [rawPlans] : []) as Record<
62+
string,
63+
unknown
64+
>[]
65+
66+
const compensationPlans = plansArray.map((p) => ({
67+
...p,
68+
}))
69+
70+
return NextResponse.json({
71+
success: true,
72+
output: { compensationPlans },
73+
})
74+
} catch (error) {
75+
logger.error(`[${requestId}] Workday get compensation failed`, { error })
76+
return NextResponse.json(
77+
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
78+
{ status: 500 }
79+
)
80+
}
81+
}

0 commit comments

Comments
 (0)